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.

RTOS/TMS320C6678: How to use Ipc_attach function in IPC Notify?

Part Number: TMS320C6678
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

The documentation says:

"For BIOS, this function should be called within a 'while' loop within a Task. A Task_sleep() or Task_yield() should be called within the loop to allow other threads in the system to execute. This function needs to be called in a loop because the remote processor may not be in a ready state."

while (Ipc_attach(remoteProcId) < 0) {

Task_sleep(1);
}

I have a simple example:

#include <xdc/std.h>

/*  -----------------------------------XDC.RUNTIME module Headers    */
#include <xdc/runtime/System.h>

/*  ----------------------------------- IPC module Headers           */
#include <ti/ipc/MultiProc.h>
#include <ti/ipc/Notify.h>
#include <ti/ipc/Ipc.h>
/*  ----------------------------------- BIOS6 module Headers         */
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/BIOS.h>

/*  ----------------------------------- To get globals from .cfg Header */
#include <xdc/cfg/global.h>

#define INTERRUPT_LINE  0

/* Notify event number that the app uses */
#define EVENTID         10

#define masterProc 6
#define sloverNum  6


UInt16  received_num = 0;

/*
 *  ======== cbFxn ========
 *  This function was registered with Notify. It is called when any event is
 *  sent to this processor.
 */
Void cbFxn(UInt16 procId, UInt16 lineId,
           UInt32 eventId, UArg arg, UInt32 payload)
{
    if(procId !=masterProc)
    {
        received_num ++;
        if(received_num == sloverNum)
        {
            received_num = 0;
            Semaphore_post(semHandle);
        }
    }
    else{
        Semaphore_post(semHandle);
    }
}


/*
 *  ======== tsk0_func ========
 *  Sends an event to the next processor then pends on a semaphore.
 *  The semaphore is posted by the callback function.
 */
Void tsk0_func(UArg arg0, UArg arg1)
{
    Int i = 0;
    Int status;

    if(MultiProc_self() == masterProc){
        while(i <sloverNum){
            status = Notify_sendEvent(i,INTERRUPT_LINE,EVENTID,i,TRUE);

            if(status <0){
                continue;
            }

            System_printf("materCore has sent event to slaveCore %d\n",i);
            i++;
        }

        System_printf("all event has been sent\n");

        Semaphore_pend(semHandle,BIOS_WAIT_FOREVER);

        System_printf("all slave core has received event from master\n");

    }
    else{
        Semaphore_pend(semHandle,BIOS_WAIT_FOREVER);

        status = Notify_sendEvent(masterProc,INTERRUPT_LINE, EVENTID, 2,TRUE);

        if(status < 0){
            System_abort("sendEvent to MasterCore failed\n");
        }

        System_printf("slaveCore %d has sent event to master core",MultiProc_self());
    }
}

/*
 *  ======== main ========
 *  Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers
 *  for an incoming event
 */
Int main(Int argc, Char* argv[])
{
    Int status;
    Int procId = 0;

    status = Ipc_start();
    if (status < 0) {
        System_abort("Ipc_start failed\n");
    }
    if(MultiProc_self() == masterProc){
        while(procId < sloverNum)
        {
            while(Ipc_attach(procId)){
                Task_sleep(1);
            }
            status = Notify_registerEvent(procId,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);

            if (status < 0)
            {
                System_abort("Notify_registerEvent for sloverCore1 failed\n");
            }
            procId++;
        }
    }
    else{
        while(Ipc_attach(masterProc)){
            Task_sleep(1);
        }
        status = Notify_registerEvent(masterProc,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);

        if(status <0){
            System_abort("Notify_registerEvent for sloverCore1 failed\n");
        }
    }
    BIOS_start();

    return (0);
}

My cfg-file is

/* 
 * Copyright (c) 2012, 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.
 * */
var MultiProc = xdc.useModule('ti.sdo.utils.MultiProc');

/* 
 *  Get the list of names that the build device supports.
 *  I.e. ["CORE0", "CORE1", "CORE2" ... ]
 */
var nameList = MultiProc.getDeviceProcNames();

/* 
 *  Since this is a single-image example, we don't (at build-time) which 
 *  processor we're building for.  We therefore supply 'null' 
 *  as the local procName and use MultiProc_setLocalId to set the procId
 *  at runtime.
 */
MultiProc.setConfig(null, nameList);

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

/* Modules explicitly used in the application */
var Notify      = xdc.useModule('ti.sdo.ipc.Notify');
var Ipc         = xdc.useModule('ti.sdo.ipc.Ipc');
var BIOS        = xdc.useModule('ti.sysbios.BIOS');
BIOS.heapSize   = 0x8000;
var Task        = xdc.useModule('ti.sysbios.knl.Task');

var tsk0 = Task.create('&tsk0_func');
tsk0.instance.name = "tsk0";

/* To avoid wasting shared memory for MessageQ transports */
for (var i = 0; i < MultiProc.numProcessors; i++) {
    Ipc.setEntryMeta({
        remoteProcId: i,
        setupMessageQ: false,
    });
}

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

/* Shared Memory base address and length */
var SHAREDMEM           = 0x0C000000;
var SHAREDMEMSIZE       = 0x00200000;

/* 
 *  Need to define the shared region. The IPC modules use this
 *  to make portable pointers. All processors need to add this
 *  call with their base address of the shared memory region.
 *  If the processor cannot access the memory, do not add it.
 */ 
var SharedRegion = xdc.useModule('ti.sdo.ipc.SharedRegion');
SharedRegion.setEntryMeta(0,
    { base: SHAREDMEM, 
      len:  SHAREDMEMSIZE,
      ownerProcId: 0,
      isValid: true,
      name: "DDR2_RAM",
    });

/* Create a semaphore with count 0 */
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
Program.global.semHandle = Semaphore.create(0);

I don't use Ipc.ProcSync_ALL specially. 

When debugging, I get the following error:

ti.sysbios.knl.Task: line 565: assertion failure: A_sleepTaskDisabled: Cannot call Task_sleep() while the Task scheduler is disabled.

How to use Ipc_attach function with Task_sleep in IPC Notify?

  • I am using:

    • CCSv7.3
    • Processor SDK RTOS v04.02.00
    • Compiler TI v8.1.4
    • IPC v 3.46.2.04.
  • Hi Michael,

    Swi_disable() and Task_disable() will cause this assertion failure and both Semaphore_pend() and Semaphore_post() call Task_disable(). However it doesn't look like you are using either before Ipc_attach.

    I've attached one of our examples that uses Ipc_attach with the Ipc.ProcSync_PAIR configuration. It calls Ipc_attach in a do-while loop and doesn't use task_sleep, I recommend trying this out and seeing if it works for you as well.

    1715.ex02_messageq.zip

    Also, in case you haven't already, I recommend taking a look at our IPC User's Guide: 

     

  • Hi Sahin!

    I think I understood how to use Ipc_attach() function with Task_sleep() in IPC Notify.

    If you use synchronization, then initialization must be performed in the task:

    #include <xdc/std.h>
    
    /*  -----------------------------------XDC.RUNTIME module Headers    */
    #include <xdc/runtime/System.h>
    
    /*  ----------------------------------- IPC module Headers           */
    #include <ti/ipc/MultiProc.h>
    #include <ti/ipc/Notify.h>
    #include <ti/ipc/Ipc.h>
    /*  ----------------------------------- BIOS6 module Headers         */
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/BIOS.h>
    
    /*  ----------------------------------- To get globals from .cfg Header */
    #include <xdc/cfg/global.h>
    
    #define INTERRUPT_LINE  0
    
    /* Notify event number that the app uses */
    #define EVENTID         10
    
    #define masterProc 6
    #define sloverNum  6
    
    
    UInt16  received_num = 0;
    
    /*
     *  ======== cbFxn ========
     *  This function was registered with Notify. It is called when any event is
     *  sent to this processor.
     */
    Void cbFxn(UInt16 procId, UInt16 lineId,
               UInt32 eventId, UArg arg, UInt32 payload)
    {
        if(procId !=masterProc)
        {
            received_num ++;
            if(received_num == sloverNum)
            {
                received_num = 0;
                Semaphore_post(semHandle);
            }
        }
        else{
            Semaphore_post(semHandle);
        }
    }
    
    
    /*
     *  ======== tsk0_func ========
     *  Sends an event to the next processor then pends on a semaphore.
     *  The semaphore is posted by the callback function.
     */
    Void tsk0_func(UArg arg0, UArg arg1)
    {
        Int i = 0;
        Int status;
        Int procId = 0;
    
        status = Ipc_start();
        if (status < 0) {
            System_abort("Ipc_start failed\n");
        }
        if(MultiProc_self() == masterProc){
            while(procId < sloverNum)
            {
                while(Ipc_attach(procId)){
                    Task_sleep(1);
                }
                status = Notify_registerEvent(procId,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
                if (status < 0)
                {
                    System_abort("Notify_registerEvent for sloverCore1 failed\n");
                }
                procId++;
            }
        }
        else{
            while(Ipc_attach(masterProc)){
                Task_sleep(1);
            }
            status = Notify_registerEvent(masterProc,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
            if(status <0){
                System_abort("Notify_registerEvent for sloverCore1 failed\n");
            }
        }
    
        if(MultiProc_self() == masterProc){
            while(i <sloverNum){
                status = Notify_sendEvent(i,INTERRUPT_LINE,EVENTID,i,TRUE);
    
                if(status <0){
                    continue;
                }
    
                System_printf("materCore has sent event to slaveCore %d\n",i);
                i++;
            }
    
            System_printf("all event has been sent\n");
    
            Semaphore_pend(semHandle,BIOS_WAIT_FOREVER);
    
            System_printf("all slave core has received event from master\n");
    
        }
        else{
            Semaphore_pend(semHandle,BIOS_WAIT_FOREVER);
    
            status = Notify_sendEvent(masterProc,INTERRUPT_LINE, EVENTID, 2,TRUE);
    
            if(status < 0){
                System_abort("sendEvent to MasterCore failed\n");
            }
    
            System_printf("slaveCore %d has sent event to master core",MultiProc_self());
        }
    }
    
    /*
     *  ======== main ========
     *  Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers
     *  for an incoming event
     */
    Int main(Int argc, Char* argv[])
    {
        Int status;
        Int procId = 0;
    
        status = Ipc_start();
        if (status < 0) {
            System_abort("Ipc_start failed\n");
        }
        if(MultiProc_self() == masterProc){
            while(procId < sloverNum)
            {
                while(Ipc_attach(procId)){
                    Task_sleep(1);
                }
                status = Notify_registerEvent(procId,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
                if (status < 0)
                {
                    System_abort("Notify_registerEvent for sloverCore1 failed\n");
                }
                procId++;
            }
        }
        else{
            while(Ipc_attach(masterProc)){
                Task_sleep(1);
            }
            status = Notify_registerEvent(masterProc,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
            if(status <0){
                System_abort("Notify_registerEvent for sloverCore1 failed\n");
            }
        }
        BIOS_start();
    
        return (0);
    }

    You can not use the function at all and do the initialization in main:

    Int main(Int argc, Char* argv[])
    {
        Int status;
        Int procId = 0;
    
        status = Ipc_start();
        if (status < 0) {
            System_abort("Ipc_start failed\n");
        }
        if(MultiProc_self() == masterProc){
            while(procId < sloverNum)
            {
                // wait attaching
    			do {
    				status = Ipc_attach(procId);
    			} while (status < 0);
    		
                status = Notify_registerEvent(procId,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
                if (status < 0)
                {
                    System_abort("Notify_registerEvent for sloverCore1 failed\n");
                }
                procId++;
            }
        }
        else{
    		// wait attaching
    		do {
    			status = Ipc_attach(masterProc);
    		} while (status < 0);
    		
            status = Notify_registerEvent(masterProc,INTERRUPT_LINE, EVENTID,(Notify_FnNotifyCbck)cbFxn, NULL);
    
            if(status <0){
                System_abort("Notify_registerEvent for sloverCore1 failed\n");
            }
        }
        BIOS_start();
    
        return (0);
    }

    If you use synchronization of all processors (Ipc.procSync = Ipc.ProcSync_ALL) in the cfg-file, then the function

    Ipc_attach() is not needed: it is automatically called in the function Ipc_start(). An example for this case can be the following:

    #include <xdc/std.h>
    
    /*  -----------------------------------XDC.RUNTIME module Headers    */
    #include <xdc/runtime/System.h>
    
    /*  ----------------------------------- IPC module Headers           */
    #include <ti/ipc/MultiProc.h>
    #include <ti/ipc/Notify.h>
    #include <ti/ipc/Ipc.h>
    /*  ----------------------------------- BIOS6 module Headers         */
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/BIOS.h>
    
    /*  ----------------------------------- To get globals from .cfg Header */
    #include <xdc/cfg/global.h>
    
    #define INTERRUPT_LINE  0
    
    /* Notify event number that the app uses */
    #define EVENTID         10
    
    /* Number of times to run the loop */
    #define NUMLOOPS        5
    
    UInt32 times = 0;
    UInt16 recvnumes = 0;
    
    #define masterProc 0
    #define sloverProc1 1
    #define sloverProc2 2
    #define sloverNum 2
    
    /*
     *  ======== cbFxn ========
     *  This function was registered with Notify. It is called when any event is
     *  sent to this processor.
     */
    Void cbFxn(UInt16 procId, UInt16 lineId,
               UInt32 eventId, UArg arg, UInt32 payload)
    {
        /* The payload is a sequence number. */
    
    	if(procId!=masterProc)
    	{
    		recvnumes++;
        	if(recvnumes==sloverNum)
        	{
        		recvnumes=0;
        		Semaphore_post(semHandle);
        	}
    	}
    	else{
    		times = payload;
    		Semaphore_post(semHandle);
    	}
    }
    
    
    /*
     *  ======== tsk0_func ========
     *  Sends an event to the next processor then pends on a semaphore.
     *  The semaphore is posted by the callback function.
     */
    Void tsk0_func(UArg arg0, UArg arg1)
    {
        Int i = 1;
        Int status;
        status = Ipc_start();
        if (status < 0) {
            System_abort("Ipc_start failed\n");
        }
    
        if(MultiProc_self()==masterProc)
        {
            while(Ipc_attach(sloverProc1)){
                Task_sleep(1);
            }
            while(Ipc_attach(sloverProc2)){
                Task_sleep(1);
            }
    
            status = Notify_registerEvent(sloverProc1, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for sloverCore1 failed\n");
            }
    
            status = Notify_registerEvent(sloverProc2, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for sloverCore2 failed \n");
            }
    
        }
        else{
    
            while(Ipc_attach(masterProc)){
                Task_sleep(1);
            }
    
            status = Notify_registerEvent(masterProc, INTERRUPT_LINE, EVENTID,
                                          (Notify_FnNotifyCbck)cbFxn, NULL);
            if (status < 0) {
                System_abort("Notify_registerEvent for masterCore0 failed\n");
            }
    
        }
        
        if (MultiProc_self() == masterProc) {
            while (i <= NUMLOOPS) {
    
                /* Send an event to the next processor */
                status = Notify_sendEvent(sloverProc1, INTERRUPT_LINE, EVENTID, i,
                        TRUE);
                status = Notify_sendEvent(sloverProc2, INTERRUPT_LINE, EVENTID, i,
                                    TRUE);
    
                /* Continue until remote side is up */
                if (status < 0) {
                    continue;
                }
    
                System_printf("MasterCore Sent Event to SloverCores in %d\n", i);
    
                /* Wait to be released by the cbFxn posting the semaphore */
                Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    
                System_printf("MasterCore Received Event from All SloverCores in %d\n",i);
    
                /* increment for next iteration */
                i++;
            }
        }
        else {
            while (times < NUMLOOPS) {
    
                /* wait forever on a semaphore, semaphore is posted in callback */
                Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    
                System_printf("SloverCore%d Received Event from MasterCore in %d\n", MultiProc_self(),times);
    
    
                /* Send an event to the next processor */
                status = Notify_sendEvent(masterProc, INTERRUPT_LINE, EVENTID, times,
                        TRUE);
                if (status < 0) {
                    System_abort("sendEvent to MasterCore failed\n");
                }
    
                System_printf("SloverCore%d sent Event from MasterCore in %d\n", MultiProc_self(),times);
            }
        }
    
        System_printf("Test completed\n");
        BIOS_exit(0);
    }
    
    /*
     *  ======== main ========
     *  Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers 
     *  for an incoming event
     */
    Int main(Int argc, Char* argv[])
    {
    
        BIOS_start();
        
        return (0);
    }

    Tell me please, are my arguments correct?

  • Hi Michael,

    That is correct! And if you do Ipc.ProcSync_ALL you can specify in the cfg file the cores you want to attach to.

    Also, I didn't realize it at the time, but the reason you were getting the assertion failure is because the task scheduler is disabled until it's enabled by BIOS_start() at the end of main. See: