• Join
  • Sign In with my.TI Login
Texas Instruments
  • Products
  • Applications
  • Tools & Software
  • Support & Community
  • Sample & Buy
  • About TI
Sample & Purchase Cart Sample & Purchase Cart
  • Search
  • Advanced
TI E2E™ Community
  • Support Forums
  • Blogs
  • Groups
  • Videos
  • 简体中文
  • More ...
TI Home » TI E2E Community » Support Forums » Embedded Software » BIOS » BIOS forum » IPC correct management
Share
BIOS
  • Forum
  • Announcements
Options
  • Subscribe via RSS

IPC correct management

IPC correct management

This question is answered
Alla Shnaider
Posted by Alla Shnaider
on Aug 09 2012 04:06 AM
Prodigy190 points

Hi Jodah,

I would like to manage my application on Concerto the following way:

I'm using messageQ and Notify module of IPC.

The scenarion of my application shall go like this:

Two cores M3 and C28.....

I don't want it be managed as polling.

I would like that each core will get messages out of the qeue on interrupt when another core calls MessageQ_put

For urgent message such as inform another core for error on another core, I'll use Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, payload, TRUE);

Jodah I have two questions:

1.  Notify_sendEvent-  Can it be called from HWI? The TRUE flag .....how shall my application behave if  Notify_sendEvent suqentually one after another without another core got previous event.

I've implemented Notify function as following, please review

void SendNotifyEvent (UInt32 payload)
{
 Int  status;

    // Send an event to the remote processor
    status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, payload, TRUE);
    if (status < 0) {
        System_abort("sendEvent failed\n");
    }
}

what shall be application behaviour if status is Notify_E_TIMEOUT......specially if SendNotifyEvent () is called from HWI ?

2. How to manage MessageQ_put as interrupt driven.....

Please confirm that my implementation today does it according to the bellow code:

.cfg file IPC configuration is as following:

var MessageQ = xdc.useModule('ti.sdo.ipc.MessageQ');
var Notify = xdc.useModule('ti.sdo.ipc.Notify');

BIOS.heapSize = 0x4000;

/* IPC */
/* Use the f28m35x IpcMgr to configure the shared buffers used by IPC */
var IpcMgr = xdc.useModule('ti.sdo.ipc.family.f28m35x.IpcMgr');
IpcMgr.readAddr  = 0x20016000;
IpcMgr.writeAddr = 0x20014000;

-----------------------------------------------------

Initialization of MessageQ in the code:

void IPC_init (void)
{
 Int  status;
    UInt numProcs = MultiProc_getNumProcessors(); // Number of processors, in the Concerto case = 2

    // Generate queue names based on own proc ID and total number of procs
    System_sprintf(localQueueName, "%s_queue",
            MultiProc_getName(MultiProc_self()));
    System_sprintf(remoteQueueName, "%s_queue", 
            MultiProc_getName(1 - MultiProc_self()));

    // Determine which processors Notify will communicate with based on the local MultiProc id.
    srcProc = ((MultiProc_self() - 1 + numProcs) % numProcs);
    dstProc = ((MultiProc_self() + 1) % numProcs);

    // Register call back with Notify. It will be called when the processor
    // with id = srcProc sends event number EVENTID to this processor.
    status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID,
                                  (Notify_FnNotifyCbck)NotifycallBackFxn, NULL);
    if (status < 0) {
        System_abort("Notify_registerEvent failed\n");
    }

    // Register default system heap with MessageQ
    MessageQ_registerHeap((IHeap_Handle)(MsgQHeapBuf0), HEAPID);

    // Create the local message queue
    messageQ = MessageQ_create(localQueueName, NULL);
    if (messageQ == NULL) {
        System_abort("MessageQ_create failed\n" );
    }

    // Open the remote message queue. Spin until it is ready.
    do {
        status = MessageQ_open(remoteQueueName, &remoteQueueId);
        // Sleep for 1 clock tick to avoid inundating remote processor
        // with interrupts if open failed
        if (status < 0) {
            Task_sleep(1);
        }
    } while (status < 0);

}

////Add message to Qeue

void IPC_sendMsg ( MY_M3_C28_Msg *Message )
{
 Int              status;

    // Increment the msgID and set it
    msgId++;
    MessageQ_setMsgId(Message, msgId);

    System_printf("Sending a message #%d to %s\n", msgId, remoteQueueName);

    // send the message to the remote processor
    status = MessageQ_put(remoteQueueId, (MessageQ_Msg)Message);
    if (status < 0) {
         System_abort("MessageQ_put had a failure/error\n");
    }

}

 

Get Message from the qeue:

MY_M3_C28_Msg * IPC_recMsg (void)
{
 Int              status;
 MessageQ_Msg     msg;

    // Get a message
    status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);
    if (status < 0) {
       System_abort("This should not happen since timeout is forever\n");
    }

    System_printf("Received message #%d from %s\n", MessageQ_getMsgId(msg),
        remoteQueueName);
    return ((MY_M3_C28_Msg *)msg);
}

Void IPC_Task(UArg arg0, UArg arg1)
{

    // Init the IPC, M3 <-> C28x communication
 IPC_init ();

    // Check the WD timer "0" interrupt
    while (1)
    {
     // receive a message
     myRcvMessage = IPC_recMsg ();

     switch (myRcvMessage->MsgType)
     {
      case 1:
           Semaphore_post(SEM_BB_WaitOnDataReceived);
       break;

      default:
       break;
     }

     //Free the received message
     IPC_freeMsg (myRcvMessage);
    }

}

 

How shall I change my code for avoid polling on getting messages from the qeue ?  I know that messageQ can be managed not as polling, please guide what shall I add to my code to do so.....

3. Can MessageQ_put, MessageQ_get be called from HWI, SWI?

 

 Thank you, Alla

 

IPC correct management
Report Abuse
  • Reply
You have posted to a forum that requires a moderator to approve posts before they are publicly available.
All Replies
  • ToddMullanix
    Posted by ToddMullanix
    on Aug 10 2012 13:00 PM
    Genius15570 points

    1. Yes, you can call Notify_sendEvent from a Hwi. For Concerto, if there is no slot available and you have waitClear set to TRUE, it spins waiting for a slot to become free.

    2. I would use the dedicate MTOC and CTOM memory for the IpcMgr.readAddr and IpcMgr.writeAddr. I scanned the code and it looks like you have the correct idea.

    3. Yes both can be called from a Hwi or Swi. However, for the MessageQ_get, make sure you use a non-blocking synchronizer when you create the queue.

    Todd

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Aug 12 2012 01:33 AM
    Prodigy190 points

    Hi Todd,

    Thank you for reply.......

    1. I don't understand  If Notify_sendEvent can be called from HWI. Usually in HWI not accaptable to use loop (spinning  waiting for a slot to become free.).....so how do you suggest to handle it?

    2. Do you mean to map the shared memory to MTOC and CTOM?

    3. Can you please guide me exactly how to define it .....what exactly changes  in the code shall I do in :

     

    void IPC_init (void)
    {
     Int  status;
        UInt numProcs = MultiProc_getNumProcessors(); // Number of processors, in the Concerto case = 2

        // Generate queue names based on own proc ID and total number of procs
        System_sprintf(localQueueName, "%s_queue",
                MultiProc_getName(MultiProc_self()));
        System_sprintf(remoteQueueName, "%s_queue", 
                MultiProc_getName(1 - MultiProc_self()));

        // Determine which processors Notify will communicate with based on the local MultiProc id.
        srcProc = ((MultiProc_self() - 1 + numProcs) % numProcs);
        dstProc = ((MultiProc_self() + 1) % numProcs);

        // Register call back with Notify. It will be called when the processor
        // with id = srcProc sends event number EVENTID to this processor.
        status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID,
                                      (Notify_FnNotifyCbck)NotifycallBackFxn, NULL);
        if (status < 0) {
            System_abort("Notify_registerEvent failed\n");
        }

        // Register default system heap with MessageQ
        MessageQ_registerHeap((IHeap_Handle)(MsgQHeapBuf0), HEAPID);

        // Create the local message queue
        messageQ = MessageQ_create(localQueueName, NULL);
        if (messageQ == NULL) {
            System_abort("MessageQ_create failed\n" );
        }

     

    // Open the remote message queue. Spin until it is ready.
        do {
            status = MessageQ_open(remoteQueueName, &remoteQueueId);
            // Sleep for 1 clock tick to avoid inundating remote processor
            // with interrupts if open failed
            if (status < 0) {
                Task_sleep(1);
            }
        } while (status < 0);

    }

     

    and what exactly changes shall I do in:

     

     

    MY_M3_C28_Msg * IPC_recMsg (void)
    {
     Int              status;
     MessageQ_Msg     msg;

        // Get a message
        status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);
        if (status < 0) {
           System_abort("This should not happen since timeout is forever\n");
        }

        System_printf("Received message #%d from %s\n", MessageQ_getMsgId(msg),
            remoteQueueName);
        return ((MY_M3_C28_Msg *)msg);
    }

     

    thank you

    A

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • ToddMullanix
    Posted by ToddMullanix
    on Aug 15 2012 11:00 AM
    Verified Answer
    Verified by David Friedland
    Genius15570 points

    Alla Shnaider
    1. I don't understand  If Notify_sendEvent can be called from HWI. Usually in HWI not accaptable to use loop (spinning  waiting for a slot to become free.).....so how do you suggest to handle it?

    It is generally not recommended to spin in an Hwi because of the latency impact. However that is a decision you need to make. Note: you cannot call a blocking API in a Hwi (e.g. Semphore_pend with a non-zero timeout).

    Alla Shnaider
    2. Do you mean to map the shared memory to MTOC and CTOM?

    On the M3 side do:

    var IpcMgr = xdc.useModule('ti.sdo.ipc.family.f28m35x.IpcMgr');
    IpcMgr.readAddr  = 0x2007F000;
    IpcMgr.writeAddr = 0x2007F800;

    On the X28 side do:

    var IpcMgr = xdc.useModule('ti.sdo.ipc.family.f28m35x.IpcMgr');
    IpcMgr.readAddr  = 0x3FC00;
    IpcMgr.writeAddr = 0x3F800;

    Alla Shnaider
    3. Can you please guide me exactly how to define it .....what exactly changes  in the code shall I do in :

    ROV is a useful tool to help debug the issue. Other suggestion is to get MessageQ working on one core (easier to debug) and then move the functionality around as needed.

    Todd

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Aug 24 2012 06:42 AM
    Prodigy190 points

    Hi Todd,

    Thank you for reply.....

    I have two questions  to make sure that I've understand properly........

    Please clarify.........

    Regarding CTOM and MTOM....wanted to clarify

    I'm managing MessageQ when writer does MessageQ_alloc and....... reader does MessageQ_free((MessageQ_Msg)Message);....freeing memoty....... after reading the message from the queue.....(meaning that for reader side its not only "read only" operation) ...

    Ttherfore I would like to understand

    if I'll use CTOM and MTOM shared region......if reader processor can do :

    1. MessageQ_get  >>   2. MessageQ_free   

     3.  MessageQ_open

    Can I still use CTOM and MTOC?...... or shall i better use S7-S8?

     

     

    Additional question:

    I'm using HeapBuf for IPC message allocation.......

    MessageQ_alloc(HEAPID, sizeof(MY_M3_C28_Msg));.......   when HEAPID is my Heap Buffer ID

    I'm looking where actually shall I map HeapBuffer (used for IPC) to shared memory.....

    My question : Is it registration of heap....  MessageQ_registerHeap((IHeap_Handle)(MsgQHeapBuf0), HEAPID);........actually does mapping of heap to the shared region...say to  MTOC?..........

     

     Thank you,

    Alla

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • ToddMullanix
    Posted by ToddMullanix
    on Aug 24 2012 12:02 PM
    Genius15570 points

    Alla,

    For Concerto, this is how a message is passed from one core to another (pseudo-code).

    Assume we are sending the message from the M3 to the C28 and the queue on the C28 has been created on the C28 and opened on the M3. Also assume both sides have a heap registered with MessageQ and the heapId is HEAPID. Also assume we are using MTOC and CTOM.

    M3 side
    msg = MessageQ_alloc(HEAPID, size);

    //fill in msg...

    MessageQ_put(remoteQ, msg);

    //MessageQ sees that this message is for the C28. So it copies the contents on the message into the MTOC memory and sends an interrupt to the C28. It then calls MessageQ_free on the msg...returning it to the heap.

    C28 Side
    When the C28 interrupt runs, it posts a Swi. This Swi looks the msg in the MTOC memory. The Swi notes the size and the heapId of the msg. It calls MessageQ_alloc(heapId, size). It copies the contents of the MTOC msg into the newly allocated message. It then calls MessageQ_put of the message (note it gets the destination queue from the message). The Swi then updates its shared memory to let the M3 that the message has been processed.

    When the application gets the message (via MessageQ_get), it can call MessageQ_free which returns it back to the heap.

    The reverse (C28 to M3) is exactly the same except the CTOM memory would be used.


    Observations

    The registered heaps do not need to be shared memory. However, the heaps that are registered on both sides with the same heapId need to be similar. For example, if you allocate a message from the M3 with a size of 4096 bytes. The heap on the C28 must be able to honor an alloc for 4096 bytes since MessageQ will be internally doing this. 

    For Concerto, this approach is same regardless of which memory you give to the IpcMgr. Please note: other devices support a zero-copy transfer between cores because they have multi-core synchronization mechanisms (HW semaphores, spin-locks, Peterson algorithm, etc.) and have shared memory that all sides can read and write.

    Todd

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Sep 18 2012 05:14 AM
    Prodigy190 points

    Hi Jodah and Todd,

    Thank you for reply.

    Currently I have a new problem. I manage 2   different message queus. One for managing messages received from PC (ARM<->PC) and another for handling messages from other controller (ARM<->Peripherial controller)

    On DSP side  I have two different threads(taks) with same priority. Each listens to coming messages from different message queue.

     

    each thread does the following:

    Task 1:

     while (1)
        {
         // receive a message
         myRcvMessage = IPC_recMsg1 ();

          m_pPCInterface->PCMessageHandle(myRcvMessage->MsgType, myRcvMessage->Data);

         //Free the received message
         IPC_freeMsg (myRcvMessage);
        }

    /////////////////////////////////////////////////////

    Task 2:

     while (1)
        {
         // receive a message
         myRcvMessage = IPC_recMsg2 ();

          m_pPeriphContollerInterface->PeriphContollerMessageHandle(myRcvMessage->MsgType, myRcvMessage->Data);

         //Free the received message
         IPC_freeMsg (myRcvMessage);
        }

     IPC_recMsg1 uses   "status = MessageQ_get(messageQ1, &msg, MessageQ_FOREVER);"

     IPC_recMsg2   uses    "status = MessageQ_get(messageQ2, &msg, MessageQ_FOREVER);"

     

    the problem is that one tasks blocks another one. And I see that only one task listens to received messages.

    In one of your replys you've mentioned that I have to use  MessageQ_get not as blocking. Create MessageQ not as blocking.. (I'm not sure that I understand you clearly and how to do it)...I guess may be this the problem because I'm using:

     // Create the local message queue
        messageQ = MessageQ_create(localQueueName, NULL);

    Can you please advice, guide me stepby step  how shall I create non blocking queus. I would like to manage each queu in different task , theefore both tasks shall be enabled to listen for incoming messages fro its own queue.

    thank you,

    Alla

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Johannes
    Posted by Johannes
    on Sep 18 2012 10:03 AM
    Genius3160 points

    Hi Alla,

    Please, correct me if I'm wrong but I think that you can't have two active threads at the same time in the same core.

    You can go from one to the other and go back and so on, but if both have a while (1) { } it will stay there until a higher priority thread preempts it or there's a termination condition. I think that this is your problem. Maybe using semaphores could "unblock" the tasks.

    About the blocking condition of MessageQ I think that what they mean is: imagine you have a MessageQ_get with a very long timeout value and this MessageQ_get is inside a Hwi (it has high priority), this way you will block your system until the MessageQ_get returns, what might never happen.

    Regards

    Johannes

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Sep 18 2012 14:43 PM
    Prodigy190 points

    Hi Johannes,

    Please correct me if I wrong is it blocking on MessageQ_get is as blocking on semaphore:

    MessageQ_get(messageQ, &msg, MessageQ_FOREVER);

    I have two different queus.  Handling messages from both queus shall be handled by application in the same priority. I though using different tasks, which each one listens for received messages via MessageQ_get(messageQ, &msg, MessageQ_FOREVER);

    How you suggest tohandle it?

     

    thank you in advance

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • judahvang
    Posted by judahvang
    on Sep 20 2012 19:12 PM
    Genius16715 points

    Alla,

    I'm speaking to your second question in this post about 2 threads waiting on 2 different MessageQs.

    If you have a non-blocking Synchronizer then you must be spinning until the first thread gets a message?  After it gets the message it will simply wait for another message because how is it going to yield the processor?  That's the reason why in most cases when a MessgeQ_get is called from a Task, We use SyncSem as the synchronizer so the Task would block and yield the processor to another Task.

    The other way to do this would be to call Task_yield() or Task_sleep() after the Task gets a message to allow the other Task a chance to execute.

    Judah

    If my reply answers your question please mark the thread as answered

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Sep 24 2012 06:43 AM
    Prodigy190 points

     Hi Judah,

    "We use SyncSem as the synchronizer so the Task would block and yeild the processor if a message is not available......"

    Please point me to example using  SyncSem  as the synchronizer so the Task would block and yield the processor to another Task.  Do I have for each queus to use its own SyncSem  as the synchronizer.

    Please guide me how.

    Thank you

    Alla

     

     

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • judahvang
    Posted by judahvang
    on Sep 24 2012 11:34 AM
    Genius16715 points

    Alla,

    The default if you don't specify anything when creating a MessageQ is to use SyncSem as the synchronizer.  Each MessageQ instance would get its own synchronizer object.  So if you do MessageQ_create("Name", NULL), by default your synchronizer is a SyncSem.

    Here is an example of explicitly specifying SyncSem:

        /* Create a message queue. Using SyncSem as the synchronizer */
        syncSemHandle = SyncSem_create(NULL, NULL);
        MessageQ_Params_init(&messageQParams);
        messageQParams.synchronizer = SyncSem_Handle_upCast(syncSemHandle);
        messageQ = MessageQ_create(CORE0_MESSAGEQNAME, &messageQParams);
        if (messageQ == NULL) {
            System_abort("MessageQ_create failed\n" );
        }

    Here is an example of specifying SyncSwi which is non-blocking:

        Swi_Params_init(&swiParams);
        swiParams.priority = 1;
        swiHandle = Swi_create(swi1_func, &swiParams, NULL);

        /* Create a message queue. Using SyncSwi as the synchronizer */
        SyncSwi_Params_init(&syncSwiParams);
        syncSwiParams.swi = swiHandle;
        syncSwiHandle = SyncSwi_create(&syncSwiParams, NULL);   

        MessageQ_Params_init(&messageQParams);
        messageQParams.synchronizer = SyncSwi_Handle_upCast(syncSwiHandle);
        messageQ = MessageQ_create(CORE0_MESSAGEQNAME, &messageQParams);
        if (messageQ == NULL) {
            System_abort("MessageQ_create failed\n" );
        }

    Judah

    If my reply answers your question please mark the thread as answered

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • Alla Shnaider
    Posted by Alla Shnaider
    on Dec 13 2012 09:58 AM
    Prodigy190 points

    Hi Judah,

    Please advice for correct management  IPC and Etherenet. I'm using messageQ  via IPC and Etherent which is much faster then IPC messageQ.

    I find my self to end of heap buffer (no free heap buffers) used for message allocation fail (even when there are used 4 messages in messageQ). Please advice for mutual management. How can I achieve the same (or almost the same) speed for passing received message from Ethernet and move it via IPC from M3 to C28?

     

    I'm limmited in resorces (RAM)

    My message size is 100 bytes. I've allocated HeapBuffer.  I've defined on both cores:

    MsgQHeapBuf0, block size 256, number of blocks 4, aligment 8 ,

    MessageQSize 256, NumMessageQMessage 4

     What is optimal size of  HepBuf shall be?

     

    thank you

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
  • judahvang
    Posted by judahvang
    on Dec 13 2012 10:47 AM
    Genius16715 points

    Alla,

    I think this thread is marked answer so you aren't going to get any new response.

    My recommendation would be to post your question on a new thread.

    I'm don't know this for sure but I think TI has an MCUSDK which may have some examples using ethernet along with IPC on the Concerto board.

    Judah

    If my reply answers your question please mark the thread as answered

    Report Abuse
    • Reply
    You have posted to a forum that requires a moderator to approve posts before they are publicly available.
TI E2E™ Community
  • Support Forums
  • Blogs
  • Videos
  • Groups
  • Site Support & Feedback
  • Settings
TI E2E™ Community Groups
  • TI University Program
  • Make the Switch
  • Microcontroller Projects
  • Motor Drive & Control
Other Communities
  • Deyisupport
  • Designsomething.org
  • beagleboard.org
  • TI on Element 14
  • TI on TechXchangeSM
Other Technical & Support Resources
  • WEBENCH® Design Center
  • Product Information Centers
  • Technical Documents
  • TI Design Network
  • TI Technical Articles
  • TI Training

All content and materials on this site are provided "as is". TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with regard to these materials, including but not limited to all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with respect to these materials. No license, either express or implied, by estoppel or otherwise, is granted by TI. Use of the information on this site may require a license from a third party, or a license from TI.

Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms of Use of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms of Use of this site. TI, its suppliers and providers of content reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.

Follow Us Texas Instruments on Facebook Texas Instruments on Twitter Texas Instruments on LinkedIn Texas Instruments on Google+
TI Worldwide | Contact Us | my.TI Login | Site Map | Corporate Citizenship | mobile m.ti.com (Mobile Version)

TI is a global semiconductor design and manufacturing company. Innovate with 100,000+ analog ICs and
embedded processors, along with software, tools and the industry’s largest sales/support staff.

© Copyright 1995-2013 Texas Instruments Incorporated. All rights reserved.
Trademarks | Privacy Policy | Terms of Use