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.

TMS320F28388D: 关于CPU1和CM之间IPC消息队列通信以及IPC通信问题

Part Number: TMS320F28388D

大家好,

1、我在自建工程代码中在CPU1和CM之间使用IPC消息队列进行通信时遇到一些问题,就是CM通过消息队列发送数据给CPU1时,CPU1能进入IPC中断,但CPU1的GetWriteIndex没有更新

CPU1:

CM是已经发送消息队列了

CM:

CPU1相关代码:

CM:

2、我想问一下,使用IPC非消息队列通信时,在发送端调用IPC_sendCommand函数后是一定要调用IPC_waitForAck等待响应吗?

因为我尝试只调用IPC_sendCommand函数来发送,在接收端能正常进入中断,但会有几率在调用IPC_readCommand函数时无法读出数据,接收端也正常调用了IPC_ackFlagRtoL函数。

  • Hi,

    我们向工程师确认后给到您答复。

  • Hi,

    第一个问题工程师正在查看中,预计1-2天给到您答复。

    关于第二个问题,

    2、我想问一下,使用IPC非消息队列通信时,在发送端调用IPC_sendCommand函数后是一定要调用IPC_waitForAck等待响应吗?

    因为我尝试只调用IPC_sendCommand函数来发送,在接收端能正常进入中断,但会有几率在调用IPC_readCommand函数时无法读出数据,接收端也正常调用了IPC_ackFlagRtoL函数。

    IPC_waitForAck()函数只是等待作为参数传递的 IPC  flag被清除。 如果在没有 IPC_waitForAck ()函数的情况下多次使用 IPC_sendCommand ()函数,那么这个flag可能已经是高电平,因此远程 CPU 并不会看到flag再次变为高电平。

    IPC_readCommand()函数在调用时返回 true (1)或 false (0)。 在 IPC_readCommand ()函数未读取预期数据时,您会看到什么?

  • 第一个问题工程师正在查看中,预计1-2天给到您答复。

    好的,感谢。

    IPC_waitForAck()函数只是等待作为参数传递的 IPC  flag被清除。 如果在没有 IPC_waitForAck ()函数的情况下多次使用 IPC_sendCommand ()函数,那么这个flag可能已经是高电平,因此远程 CPU 并不会看到flag再次变为高电平。

    这个我明白,因为代码中是间隔1ms调用IPC_sendCommand函数一次,所以基本不会重复调用。 

    IPC_readCommand()函数在调用时返回 true (1)或 false (0)。 在 IPC_readCommand ()函数未读取预期数据时,您会看到什么?

    这边读回来的值是1,但读回来的command的值不对。

    因为我在CM中使用ECAT和Enet通信,ECAT通过IPC0将数据发送至CPU1,Enet通过IPC1将数据发送至CPU1,IPC0的sendCommand函数是在while循环中调用,IPC1发送函数是在Enet的接收中断中调用,所以我猜测是在执行IPC0发送函数,并在IPC_waitForAck()函数等待时,有Enet的接收中断打断了IPC0的等待,并执行了Enet的IPC1的发送函数,我在CPU1的IPC0中断中读回来的command值是IPC1发送给CPU1的command的值,但IPC0和IPC1是两个不同的中断。

    所以不知道为什么会在IPC0中读回来了IPC1的command值,而且这种情况是有概率出现的。

  • 您好,

    很抱歉问题1工程师还在查看中,尽快给到您答复。

    工程师怀疑是 CCS 中的寄存器视图的问题,并且实际上可能会递增。

    请问IPC0和 IPC1都使用 messageQueue 吗? 是否使用了相同的消息队列地址?

  • 很抱歉问题1工程师还在查看中,尽快给到您答复。

    你好,我已经找到问题了,是CM和CPU1映射到消息RAM的变量不一样导致的。

    CM:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // .map
    20080000 IPC_CM_To_CPU1_GetBuffer
    20082000 cmSend2CPUBuffer
    20082400 cmDatSendBuffer
    20082414 cmObjSendBuffer
    20082514 IPC_CM_To_CPU1_PutBuffer
    20084000 IPC_CM_To_CPU2_GetBuffer
    20086000 IPC_CM_To_CPU2_PutBuffer
    // .c
    #pragma DATA_SECTION(cmDatSendBuffer,"MSGRAM_CM_TO_CPU1")
    #pragma DATA_SECTION(cmObjSendBuffer,"MSGRAM_CM_TO_CPU1")
    #pragma DATA_SECTION(cmSend2CPUBuffer,"MSGRAM_CM_TO_CPU1")
    uint16_t cmDatSendBuffer[10];
    uint32_t cmObjSendBuffer[64];
    uint16_t cmSend2CPUBuffer[512];
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    CPU1:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // .map
    0 00038000 IPC_CPU_To_CM_GetBuffer
    0 00039000 ipcTxBuffer
    0 00039180 ipcSampleTxBuffer
    0 00039300 cpu1DatSendBuffer
    0 0003930a cpu1MonitSendBuffer
    0 00039440 IPC_CPU_To_CM_PutBuffer
    0 0003a000 IPC_CPU1_To_CPU2_PutBuffer
    0 0003b000 IPC_CPU1_To_CPU2_GetBuffer
    // .c
    #pragma DATA_SECTION(cpu1DatSendBuffer,"MSGRAM_CPU_TO_CM")
    #pragma DATA_SECTION(ipcTxBuffer,"MSGRAM_CPU_TO_CM")
    #pragma DATA_SECTION(cpu1MonitSendBuffer,"MSGRAM_CPU_TO_CM")
    #pragma DATA_SECTION(ipcSampleTxBuffer,"MSGRAM_CPU_TO_CM")
    uint16_t ipcTxBuffer[384] = {0};
    uint16_t ipcSampleTxBuffer[384];
    int32_t cpu1MonitSendBuffer[128];
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    CPU1的IPC_CPU_To_CM_GetBuffer所在MSGRAM的位置和CM的IPC_CM_To_CPU1_PutBuffer所在位置不一样,所以没法正常使用。

    所以现在有一个新的问题,如果自己想要在MSGRAM定义变量,怎样才能避免上述这个问题呢?

    请问IPC0和 IPC1都使用 messageQueue 吗? 是否使用了相同的消息队列地址?

    第二个问题没有使用消息队列,使用的是IPC_sendCommand和IPC_readCommand函数

  • Hi,

    能否分享下所有与 IPC 相关的代码?

    您是否查看过 ipc_ex2_msgqueue 示例来了解如何处理不同地址的这一问题? 以下屏幕截图来自 IPC_sendMessageToQueue()函数。

    您试下修改函数的地址更正部分来适用于特定的地址位置? 

  • 能否分享下所有与 IPC 相关的代码?

    CM内核发送IPC0函数:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    void CMTOCPU1_ipc0SendData(uint32_t dataAddr, uint32_t dataSize, uint32_t command)
    {
    //
    // Send a message without message queue
    // Since C28x and CM does not share the same address space for shared RAM,
    // ADDRESS_CORRECTION is enabled
    // Length of the data to be read is passed as data.
    //
    IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,
    command, (uint32_t)dataAddr, dataSize);
    // GPIO_togglePin(mGPIO_PIN_LED5);
    //
    // Wait for acknowledgment
    //
    IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG0);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    CM内核while循环发送调用发送函数:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    while(1)
    {
    // testcount++;
    // if(testcount >= 64)
    if(EcatRev_Flag == 1)
    {
    SYNC0_Update_Send();
    EcatRev_Flag = 0;
    // testcount = 0;
    }
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    CM:ENET接收函数,IPC1发送Enet接收的数据至CPU1

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void udp_rx_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p,
    struct ip_addr *addr, u16_t port)
    {
    int i;
    enet_actualCnt = p->len;
    enet_totalCnt = p->tot_len;
    struct pbuf *ptmp = p;
    if (p != NULL)
    {
    {
    for (i = 0; i < enet_actualCnt; i++)
    {
    cmSend2CPUBuffer[i]=(*((uint8_t *)p->payload + i));
    }
    ptmp = p->next;
    CMTOCPU1_ipc1SendData(cmSend2CPUBuffer, enet_totalCnt, IPC1_CMD_CPU1_READ_MEM);
    // memset(&cmDatSendBuffer[0], 0, enet_totalCnt);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void CMTOCPU1_ipc1SendData(uint32_t dataAddr, uint32_t dataSize, uint32_t command)
    {
    //
    // Send a message without message queue
    // Since C28x and CM does not share the same address space for shared RAM,
    // ADDRESS_CORRECTION is enabled
    // Length of the data to be read is passed as data.
    //
    IPC_sendCommand(IPC_CM_L_CPU1_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,
    command, (uint32_t)dataAddr, dataSize);
    //
    // Wait for acknowledgment
    //
    IPC_waitForAck(IPC_CM_L_CPU1_R, IPC_FLAG1);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    CPU1的中断IPC0和IPC1接收函数:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    __interrupt void CMTOCPU1IPC1_ISR(void)
    {
    uint32_t enet_totalRvCnt;
    uint32_t command;
    uint32_t Addr;
    int i = 0;
    IPC_readCommand(IPC_CPU1_L_CM_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,
    &command, &Addr, &enet_totalRvCnt);
    if(command == IPC1_CMD_CPU1_READ_MEM || command == IPC1_CMD_CM_READ_ARRAY ||
    command == IPC1_CMD_CM_READ_MONITOR)
    {
    for(i=0; i<enet_totalRvCnt; i++)
    {
    *(RevBuffer + i) = *((uint16_t *)Addr + i);
    }
    }
    IPC_ackFlagRtoL(IPC_CPU1_L_CM_R, IPC_FLAG1);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    您试下修改函数的地址更正部分来适用于特定的地址位置? 

    这个函数我看了,我不太理解你说的意思,,但 我在cmd文件中通过将IPCMSGRAM的地址重新划分出一个区用来存储用户定义的数组,不知这样可不可行

  • 好的,感谢您提供的信息。

    工程师正在查看中,预计1-2天内给到您答复。给您带来的不便敬请谅解!

  • 您好,

    我们再确认下您这里的具体问题:

    1) 缓冲区索引不会因其消息队列而递增(使用 IPC2)

    2) 在 CPU1上读取 IPC0的命令但返回了 IPC1传递的命令

    请问问题2)是间歇性发生的,还是每次为 IPC0读取命令时都会发生?

  • 1) 缓冲区索引不会因其消息队列而递增(使用 IPC2)

    该问题已经找到原因了。

    请问问题2)是间歇性发生的,还是每次为 IPC0读取命令时都会发生?

    是间歇性发生的,IPC0是在CM的while循环上发送至CPU1的,而IPC1是在CM的一个中断中发送的,所以我猜测是IPC0在执行发送并等待CPU1应答过程中,CM的中断触发了IPC1的发送,所以在CPU1的IPC0中断中接收到了IPC1传递的命令,但不清楚为什么会这样。

  • 好的感谢您提供的信息,我们看下给到您答复。

  • 您好,

    是间歇性发生的,IPC0是在CM的while循环上发送至CPU1的,而IPC1是在CM的一个中断中发送的,所以我猜测是IPC0在执行发送并等待CPU1应答过程中,CM的中断触发了IPC1的发送,所以在CPU1的IPC0中断中接收到了IPC1传递的命令,但不清楚为什么会这样。

    通过查看 IPC_sendCommand()函数来我们可以了解这是如何发生的。 该行为应该是在 IPC_sendCommand()函数中断后,在第一个函数完成前使用另一个 IPC_sendCommand()函数时的预期行为。

    我们需要再和其他团队讨论下您的问题,看下如何解决。您的系统这边是否可以将以太网中断延迟到 IPC0 sendCommand 功能完成? 您可以先试下。

    Thanks

  • 好的,谢谢

  • 您好,

    我们讨论过后,认为您在您的第一个 IPC_sendCommand ()函数中不需要禁用中断,最好为这些消息使用消息队列。

    可以设置多个消息队列,这样您可以将来自不同来源的消息分开。 

    您可以试下在 while 循环中的 ipc_sendCommand()函数中停止中断是否可行? 另一种方法是使用多个 messageQueues,而不是使用 IPC_sendCommand()函数。 

    Thanks

  • 好的,明白