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.

How exactly are messages passed between cores using MessageQ (IPC sample proj)

Good day to all,

I'm currently trying out the IPC MessageQ sample project, and as i am looking through the code, i'm filled with questions as i don't really understand how this works.

DSP: TMDXEVM6678LE
CCS: v5.5
Proj: IPC Single Image MessageQ sample project

"MessageQ_put(remoteQueueID, msg)" puts the msg in queue, and "MessageQ_get(messageQ, &msg, MessageQ_FOREVER)" gets the message from the queue? But then again, what exactly is the 'message' being passed? I understand 'msg' is actually a struct(below), but then all i see being passed are IDs etc, so what is the 'message' being passed? So if i want CORE0 to send the text "Hello World" to CORE1, how is this actually done?

typedef struct {
Bits 32  msgSize
Bits 32  flags
Bits 32  msgId
Bits 16  dstId
Bits 16  dstProc
Bits 16  replyId
Bits 16  replyProc
Bits 16  srsProc
Bits 16  heapId
Bits 16  seqNum
Bits 16  reserved
}MessageQ_MsgHeader;

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

Also, which exactly is the code that calls the next core to print? There is a message "System_printf("Sending a message #%d to %s\n", MessageQ_getMsgId(msg), nextQueueName);" which prints as shown:

[C66xx_0] Sending a message #1 to CORE1
[C66xx_1] Sending a message #1 to CORE2

And in main, "nextProcId = (multiProc_Seld() + 1) % MultiProc_getNumProcessors();" tells, for example core0, that its next core is 1, but if i modify the code to "nextProcId = (multiProc_Seld() + 2) % MultiProc_getNumProcessors();", the output changes to:

[C66xx_0] Sending a message #1 to CORE2
[C66xx_2] Sending a message #1 to CORE4

From this i understand that core0 now knows its next processor is core 2, but which is the code in the sample proj which actually 'calls' CORE2? I understand 'why' its core2, but i don't understand 'how' core2 is being called to print instead of core 1. What is the code that actually says "Hey core2, you're my next processors, time for u to take over!"?

Thank you so much for your precious  time and patience.

[Edit] I think I understand the second part of my ans. Correct me if I'm wrong. Its not that core0 is 'calling' core1 to print, but instead all the core are actively listening to message received.. MessageQ_get waits forever till message received end, only then will the code following the get be RU. Thus printing the following messages.

  • Hi,

    Your understanding is correct about the messageQ write/read (put/get).
    Yes, this module supports the structured sending and receiving of variable length messages. Messages are sent and received through a message queue.

    • A reader is a thread that gets (reads) messages from a message queue.
    • A writer is a thread that puts (writes) a message to a message queue.

    Each message queue has one reader and can have many writers. A thread may read from or write to multiple message queues.

    Go through the IPC user guide to get the detailed information for messageQ.
    C:\ti\ipc_1_xx_xx_xx\docs\IPC_Users_Guide
    http://processors.wiki.ti.com/index.php/IPC_Users_Guide/MessageQ_Module
    http://processors.wiki.ti.com/index.php/BIOS_MCSDK_2.0_User_Guide#Inter-Processor_Communication_.28IPC.29

  • Hi pubesh, I understand slightly better on the sending n receiving now. But I don't really get what is being sent over.. I see that 'msg' which is sent over is a struct, and the struct contains all IDs and such, then what exactly am I sending over? What if I have core0 doing some function and I want core0 to send the output to core1? Like maybe a text or something?

    Because right now all I see if IDs and msg size etc being sent over, what about actual useful data?

  • Hi,

    Find the test code at mcsdk: C:\ti\mcsdk_2_01_02_06\demos\image_processing\ipc

    Before test this, check the image processing user guide.

    http://processors.wiki.ti.com/index.php/MCSDK_Image_Processing_Demonstration_Guide

    This test code is based on messageQ transport. In addition that, see the multicore based examples at: C:\ti\ipc_1_xx_xx_xx\packages\ti\sdo\ipc\examples\multicore\evm667x

  • Take a look at the recently posted training slides for IPC. They contain references to a few labs to help better understand the IPC communication..

    http://processors.wiki.ti.com/index.php/IPC_3.x#IPC_Training

  • Jing,

    For MessageQ, the transport determines how the message is passed from the local processor to the remote processor. The typical setup is to use TransportShm which is a zero-copy based transport. This transport relies on shared memory which is visible to both processors. Calling MessageQ_alloc will acquire a buffer in the shared memory. The local processor fills the buffer with data.

    When the local processor calls MessageQ_put, only the pointer to this buffer is passed to the remote processor. When the remote processor returns from MessageQ_get, it has the pointer to this buffer. So, no data is copied. When the remote processor calls MessageQ_free, the buffer is released back into the pool.

    In all cases, the local processor cannot use the message buffer once it has sent it to the remote processor. It has to acquire a new message using MessageQ_alloc.

    In the following image, the arrows show the logical data flow, but the physical data is written to and read from the shared memory between the two processors.

     

    When shared memory is not available, then a copy-based transport is used. In this case, when the local processor calls MessageQ_alloc, a buffer is returned from a local pool. When calling MessageQ_put, the transport will read the data in the message and send it to the remote processor using some physical transport (e.g. SRIO, SPI, etc). After the data has been sent, the transport will free the buffer back to the local pool. On the remote processor, the transport will acquire a buffer from the local pool and fill it as the data is received. When all data has been received, the pointer to this local buffer is returned from MessageQ_get.

     

    Re: the message structure. The following image illustrates the message layout in memory. When you call MessageQ_alloc, you must make the message size large enough to contain both the embedded MessageQ_MsgHeader structure as well as your payload. A typical way to do this is to define your own message structure as illustrated.

    ~Ramsey

  • Hi, thank you for the detailed explaination, i understood most of it already but your explanation further improved my understanding. Based on the comments section in the MessageQ header file and ur example:

    typedef struct{
      MessageQ_MsgHeader header;
      int num;
    } MyMsg;

    Correct me if i'm wrong. Because MessageQ_put only allows the passing of MessageQ_Header type, my understanding is that i'm supposed to initialize a MyMsg struct which will initialize a MessageQ_Header. This will ensure that the header and my 'int num' will be within the same block of memory. Thus when i pass the pointer of my header over to another core, the receiving core just needs to offset the size of the header to retrieve my 'int num'. Is this how it's supposed to be?

    If so, i seem to be having some problems initializing the structs. I'm currently working on the sample project from TI on MessageQ(single image). 

    typedef MessageQ_Header *MessageQ (in header)
    MessageQ msg;

    How should i modify my codes then? Changing the 'MessageQ msg' to 'MyMsg.header msg'? Or should i just initialize the struct MyMsg and it will initialize MessageQ_Header as header on it's own?

    Thank you so much for ur patience and sry for my lack of knowledge.

    PS: I'm currently working on a PC not connected to the internet thus i'm unable to copy n paste the codes etc. I'm posting from home so its all based on my memory.

  • Jing,

    Your understanding regarding the message structure is correct. Your message definition above looks correct.

    When you call MessageQ_alloc(), you specify the requested size of the message. The size would be the size of your message which includes the embedded message queue header.

    typedef struct {
        MessageQ_MsgHeader reserved;
        int num;
    } MyMsg;

    MyMsg *msg;

    msg = (MyMsg *)MessageQ_alloc(heapId, sizeof(MyMsg));
    msg->num = 4;

    MessageQ_put(qid, (MessageQ_Msg)msg);

    In the call to MessageQ_alloc(), the embedded message queue header is initialized for you. You do not need to initialize the header yourself. One of the fields in the header contains the message size. This is how MessageQ_put knows how much data to "send" to the remote processor.

    When you receive the message, you would cast the return pointer to your own message type. Then you can dereference your data objects.

    MyMsg *msg;

    MessageQ_get(que, (MessageQ_Msg *)&msg, MessageQ_FOREVER);
    num = msg->num;

    MessageQ_free((MessageQ_Msg)msg);

    I hope this answers your question.

    ~Ramsey

  • Oh! Awesome! It worked.. Thanks a lot! It seems I got confused by what is being sent over. I kept thinking only MessageQ_MsgHeader is able to be sent over, didn't think I could send my whole stuct over. Forgot that its just a pointer after all. Thank you all! :)