This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

IPC Notify Event not responding

Hi , 

MCSDK version : 2.2.1.03

IPC Version: ipc_1_25_03_15

Bios Version : bios_6_35_04_50 

XDC version : xdctools_3_25_03_72 

We are trying out interrupt based Message_get() .  Since Message_put() and Message_get() uses signal() and wait() functions which are more like polling . 

So we thought of using notify to send an interrupt as soon as the put happens to the remote proc . But unfortunately the code is not calling the callback function.

In ROV we saw Notify event registration is successful for both the cores. 

Core 0 : Puts the message and send the event 

Core1:  Is in indefinite run state .

Core 0 code snippet : 

               status = MessageQ_put(remoteQueueId, msgTx);

               if (status < 0) {
                  System_abort("MessageQ_put had a failure/error\n");
               }
               System_printf("Msg Core1 put \n");
               status = Notify_sendEvent(nextProcId, LINEID, eventId, NULL, TRUE);

core 1 code snippet : 

attachAll(Num_Processor) ;

    status = Notify_registerEventSingle(nextProcId, LINEID, eventId,(Notify_FnNotifyCbck)Core0_Interrupt,
                                        NULL);

void Core0_Interrupt(UInt16 procId, UInt16 lineId,UInt32 eventId, UArg arg, UInt32 payload)
{


	          int status ;
			 status = MessageQ_get(messageQ, &msgRX, MessageQ_FOREVER);
		     if (status < 0)
		     {
			  // System_abort("This should not happen since timeout is forever\n");
			 }
		     core1msg = (Core1Struct*)msgRX;
		    // System_printf("Msg Core1 Got :: %d\n" ,core1msg->test_val1);
			 status = MessageQ_free(msgRX);
	         if(status == MessageQ_E_FAIL )
			 {
			    // System_printf("Msg free failed\n");
			 }



}

.cfg file :
/* --COPYRIGHT--,BSD
 * Copyright (c) 2011, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/

/* Benchmark Task */
var Task = xdc.useModule('ti.sysbios.knl.Task'); 



var Semaphore     = xdc.useModule('ti.sysbios.knl.Semaphore');
Semaphore.supportsEvents = false;

//var Agent = xdc.useModule('ti.sysbios.rta.Agent');
//Agent.transport = Agent.Transport_STOP_MODE_ONLY;
 
//var Load = xdc.useModule('ti.sysbios.utils.Load');
//Load.hwiEnabled = false;
//Load.swiEnabled = false; 
//Load.taskEnabled = false;

var System   = xdc.useModule('xdc.runtime.System');
var Startup   =   xdc.useModule('xdc.runtime.Startup');
var SysStd   = xdc.useModule('xdc.runtime.SysStd');
System.SupportProxy = SysStd;

System.extendedFormats = "%f";

var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.clockEnabled = false;
BIOS.heapSize = 0x8000;

var Timestamp = xdc.useModule("xdc.runtime.Timestamp");



var PlatformLib = xdc.loadPackage('ti.platform.evmtci6614');

/* 
** Register an EVM Init handler with BIOS. This will initialize the hardware. BIOS calls before it starts. 
**
** If debugging with CCS, then this function will execute as CCS loads it if the option in your 
** Target Configuration file (.ccxml) has the option set to execute all code before Main. That is the 
** default.
*/

var cslSettings = xdc.useModule ('ti.csl.Settings');

var cacheEnabled = true;  
var cacheLineSize = 128;
var procName = null;
var procNameList = [];

var Settings                = xdc.module('ti.sdo.ipc.family.Settings');
var Cache                   = xdc.useModule('ti.sysbios.family.c66.Cache');
var MessageQ                = xdc.module('ti.sdo.ipc.MessageQ');
var Notify                  = xdc.module('ti.sdo.ipc.Notify');
var Ipc                     = xdc.useModule('ti.sdo.ipc.Ipc');
var HeapBufMP               = xdc.useModule('ti.sdo.ipc.heaps.HeapBufMP');


Notify.SetupProxy           = xdc.module(Settings.getNotifySetupDelegate());
MessageQ.SetupTransportProxy= xdc.module(Settings.getMessageQSetupDelegate());

/* Use shared memory IPC */
Notify.SetupProxy           = xdc.module('ti.sdo.ipc.family.c647x.NotifyCircSetup');
MessageQ.SetupTransportProxy = xdc.module('ti.sdo.ipc.transports.TransportShmNotifySetup');

/* Synchronize all processors (this will be done in Ipc_start) */
Ipc.procSync = Ipc.ProcSync_ALL;

/* Set to disable error printouts */
/* var Error = xdc.useModule('xdc.runtime.Error'); */
/* Error.raiseHook = null; */

Program.global.NOTIFYSETUP = Notify.SetupProxy.delegate$.$name;
Program.global.TRANSPORTSETUP = MessageQ.SetupTransportProxy.delegate$.$name;

//switch (Program.platformName) {                                                                   
   // case "ti.platforms.evm6614":    
       // Program.global.USING_TCI6614 = 1;    
        //procNameList = ["CORE0", "CORE1"];
        //Program.global.shmBase = 0x0C000000;
        //Program.global.shmSize = 0x00050000; /* Sized for greater than 2000 128 byte messageQ messages */
      //  break;
    //default:
  //      throw("Unsupported platform: " + Program.platformName);
//}
		// procName = "CORE1";
        procNameList = ["CORE0","CORE1"];

var MultiProc = xdc.useModule('ti.sdo.utils.MultiProc');
MultiProc.setConfig(null, procNameList);

Program.global.DEVICENAME = Program.cpu.deviceName;
Program.global.PROCNAMES = procNameList.join(",");
Program.global.BUILDPROFILE = Program.build.profile;

var SharedRegion = xdc.useModule('ti.sdo.ipc.SharedRegion');
SharedRegion.translate = false;
SharedRegion.setEntryMeta(0,
    { base: 0x0c000000,
      len: 0x00100000,
      ownerProcId: 0,
      isValid: true,
      cacheEnable: cacheEnabled,
      cacheLineSize: cacheLineSize,  /* Aligns allocated messages to a cache line */
      createHeap: true,
      name: "internal_shared_mem",
    });


/* Optimization stuff */
Diags = xdc.useModule("xdc.runtime.Diags");
var Defaults = xdc.useModule('xdc.runtime.Defaults');

//Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
Defaults.common$.logger = null;


//Semaphore.supportsEvents = false;
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
Program.global.semHandle = Semaphore.create(0);

#   We tried semaphore_pend and post to handle the interrupt flow : but both core was getting into an indefinite run state (Deadlock) .

PS : WIthout the notify functionality the code was working fine with MessageQ_get in BLOCKING mode. 

1# Can MessageQ_get() can be called inside the Callback function ?

2# Is default value for EventId and LineId is 0 or any values can be assigned ?

Regards , 

Vinodh

  • Hi Vinodh,

    It looks like you are using TransportShmNotify for MessageQ, which uses Notify internally in the transport layer to notify the remote core upon sending a message. So I am a little confused as to why you feel the need to use Notify in the application. Is it because you do not want your Task to block on MessageQ_get()? If so, you can try passing it a zero timeout value, and only call MessageQ_get when the Task has nothing else to do

    MessageQ_get should normally be called in Task context due to its use of Semaphore. So it shouldn't be used in the user-registered function Core0_Interrupt(), given the latter runs within Hwi context. Your approach *may* be able to get away with it if it ensures there is always a message pending in the queue, but it is still best to just call Semaphore_post() and defer the MessageQ_get() call to a Task to reduce interrupt latency. In general you want to keep your Notify callback functions lean.

    I think for 'ti.sdo.ipc.family.c647x.NotifyCircSetup', line id 0 needs to be used since there is only one interrupt line. Event id usually can be anything from 0 to 31, and you can use Notify_eventAvailable() to verify if an event id is available. See IPC documentation for more details.

    Best regards,

    Vincent

  • Hi , 

    Thanks Vincent .

    We are trying to built a interrupt based MessageQ_Get(), Where MessageQ_get will run as background process on receiving the interrupt from the Tx side. 

    now our doubt is :

    # When MessageQ_get() with timeout 0 is called and message is not yet received - the core will continue with the code execution . Will the MessageQ_get() will automatically retrieve the data in the shared memory when data arrives or will it wait till the messageQ_get() function call ?? 

    # When ever a message arrives - we need to immediately fetch the information on interrupt basis , thats the reason we deployed NotifyEvent . Since NotifyEvent is by IPCGRx value , the callback function will be automatically called when there is an interrupt . 

    Is our understanding is correct ?

  • Hi vinodh,

    If MessageQ_get is called with timeout 0, it will not block. However, it is up to the user application to call it again eventually to retrieve the data.

    When a message arrives, a Notify Event is internally received in ti.sdo.ipc.transports.TransportShmNotify. This transport will queue up the message onto the MessageQ, and unblock any on-going MessageQ_get call. If you use the scheme you have described, what you are doing is sending an additional Notify event over on top of the default behavior. The latter will call your callback in the interrupt context.

    That said, if ultimately your intent is to have MessageQ_get to run in a "background process", you really should remove it from the ISR context and move it into a Task. You can consider creating a high-priority Task that simply processes the messages as they come in, if the messages need to be processed asap.

    Best regards,

    Vincent

  • Hi Vincent , 

    How the high-priority task get the notification that a packet is received ?  Will internal notify_Event trigger this high priority task as soon as the packet arrives?

    regards , 

    vinodh 

  • Vinodh,

    Please go through the section "3.3.8 Message Priorities" in the IPC user guide. This will help you to better understand.

  • Hi Pubesh,

    We went through the user guide and created the task. It only talks about setting priorities. Also, every task runs only once. But we want to create a task where MessageQ_get is called. This task should run multiple times, may be with some fixed periodicity in the background (as the other core will send multiple messages).

    We tried creating a task, with a priority of 30. It ran only once. Is there any way to configure the SYS-BIOS to execute this task everytime the core receives a message?

  • Tasks work the same as threads in a PC application.  Usually you would use a "while" loop to run until the application exits (or to run forever).  In the "while" loop, there will be something - maybe MessageQ_get, maybe a semaphore - which blocks the task until conditions are correct to run it.

    As with threads, it takes a long time to set up a task, but only a very short time to switch between task contexts when something blocks/unblocks.  This is why you use blocking and keep the task around, instead of letting the task run to completion.

  • Hi vinodh,

    When the Task calls MessageQ_get, it internally blocks on a Semaphore. The next message is received internally as a Notify event within the 'TransportShmNotify' transport, which immediately triggers a call in interrupt context to its registered Notify function. The latter calls MessageQ_put 'locally' which puts the message onto the local MessageQ and posts the Semaphore, thereby unblocking the Task. The Task then resumes execution of MessageQ_get, and returns the message to the application.

    As long as there are no higher-priority interrupts being serviced, the Notify function will run and will post the Semaphore as soon as the message arrives. And the Task will run after all interrupts are serviced if there are no other higher-priority Tasks ready to run.


    Your Task function would look similar to this:

    while(1) {

            /* wait for inbound message */
            status = MessageQ_get(localMsgQue, (MessageQ_Msg *)&msg,
                MessageQ_FOREVER);

            ... process the message

    }

    Best regards,

    Vincent