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.
大家好,
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,
第一个问题工程师正在查看中,预计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:
// .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];
CPU1:
// .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];
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函数:
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); }
CM内核while循环发送调用发送函数:
while(1) { // testcount++; // if(testcount >= 64) if(EcatRev_Flag == 1) { SYNC0_Update_Send(); EcatRev_Flag = 0; // testcount = 0; } }
CM:ENET接收函数,IPC1发送Enet接收的数据至CPU1
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); } enet_remotePort = port; udp_connect(upcb, addr, port); /* connect to the remote host */ } // 释放缓冲区数据 pbuf_free(p); }
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); }
CPU1的中断IPC0和IPC1接收函数:
__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); Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11); } __interrupt void CMTOCPU1IPC0_ISR(void) { uint32_t command; // sig0_updata_send command = CMTOCPU1_ipc0ReadData(cpu1ObjReadBuffer); Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11); } uint32_t CMTOCPU1_ipc0ReadData(uint32_t *dataAddr) { uint32_t command, Addr; uint32_t dataSize; // // Read the command // IPC_readCommand(IPC_CPU1_L_CM_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE, &command, &Addr, &dataSize); if(command == IPC0_CMD_CPU1_ECAT_UPDATE) { int i; for(i=0; i<dataSize; i++) { *(dataAddr + i) = *((uint32_t *)Addr + i); } } IPC_ackFlagRtoL(IPC_CPU1_L_CM_R, IPC_FLAG0); return command; }
您试下修改函数的地址更正部分来适用于特定的地址位置?
这个函数我看了,我不太理解你说的意思,,但 我在cmd文件中通过将IPCMSGRAM的地址重新划分出一个区用来存储用户定义的数组,不知这样可不可行
您好,
我们再确认下您这里的具体问题:
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