Part Number:TMS320F28388D
大家好,
我在使用IPC进行CM4到CPU1通信时遇到一些问题,我使用下面帖子回答的用例进行修改
https://e2echina.ti.com/support/microcontrollers/c2000/f/c2000-microcontrollers-forum/272839/tms320f28388d-c28xcpu1-cm4-ipc
原代码内容:
//############################################################################# // // FILE:ipc_ex2_msgqueue_cm.c // // TITLE: IPC example with interrupt and message queue // //! \addtogroup driver_cm_c28x_dual_example_list //! <h1> IPC message passing example with interrupt and message queue </h1> //! //! This example demonstrates how to configure IPC and pass information from //! C28x to CM core with message queues. //! It is recommended to run the C28x1 core first, followed by the CM core. //! //! \b External \b Connections \n //! - None. //! //! \b Watch \b Variables \n //! - None. //! // //############################################################################# // $Copyright: // Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com // // 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. // $ //########################################################################### // // Included Files // #include "cm.h" #include "ipc.h" // // Defines // #define IPC_CMD_READ_MEM0x1001 #define IPC_CMD_RESP0x2001 #define TEST_PASS0x5555 #define TEST_FAIL0xAAAA IPC_MessageQueue_t messageQueue; #pragma DATA_SECTION(CMData, "MSGRAM_CM_TO_CPU1") uint32_t CMData[10]; // // IPC ISR for Flag 1 // C28x core sends data with message queue using Flag 0 // __interrupt void IPC_ISR1() {int i;IPC_Message_t TxMsg, RxMsg;bool status = false;//// Read the message from the message queue//IPC_readMessageFromQueue(IPC_CM_L_CPU1_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&RxMsg, IPC_NONBLOCKING_CALL);if(RxMsg.command == IPC_CMD_READ_MEM){status = true;//// Read and compare data//for(i=0; i<RxMsg.dataw1; i++){if((*(uint32_t *)RxMsg.address + i) != i)status = false;}}//// Send response message//TxMsg.command = IPC_CMD_RESP;TxMsg.address = (uint32_t)CMData;TxMsg.dataw1 = 10;TxMsg.dataw2 = 1;IPC_sendMessageToQueue(IPC_CM_L_CPU1_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&TxMsg, IPC_NONBLOCKING_CALL);//// Acknowledge the flag//IPC_ackFlagRtoL(IPC_CM_L_CPU1_R, IPC_FLAG1); } // // Main // void main(void) {//// Initialize device clock and peripherals//CM_init();//// Clear any IPC flags if set already//IPC_clearFlagLtoR(IPC_CM_L_CPU1_R, IPC_FLAG_ALL);//// Enable IPC interrupts//IPC_registerInterrupt(IPC_CM_L_CPU1_R, IPC_INT1, IPC_ISR1);//// Initialize message queue//IPC_initMessageQueue(IPC_CM_L_CPU1_R, &messageQueue, IPC_INT1, IPC_INT1);//// Synchronize both the cores.//IPC_sync(IPC_CM_L_CPU1_R, IPC_FLAG31);int i;for(i=0; i<10; i++){CMData[i] = i+11;}//// Loop forever. Wait for IPC interrupt//while(1); } // // End of File //
//############################################################################# // // FILE:ipc_ex2_msgqueue_c28x1.c // // TITLE: IPC example with interrupt and message queue // //! \addtogroup driver_cm_c28x_dual_example_list //! <h1> IPC message passing example with interrupt and message queue </h1> //! //! This example demonstrates how to configure IPC and pass information from //! C28x to CM core with message queues. //! It is recommended to run the C28x1 core first, followed by the CM core. //! //! \b External \b Connections \n //! - None. //! //! \b Watch \b Variables \n //! - pass //! // //############################################################################# // $Copyright: // Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com // // 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. // $ //########################################################################### // // Included Files // #include "driverlib.h" #include "device.h" // // Defines // #define IPC_CMD_READ_MEM0x1001 #define IPC_CMD_RESP0x2001 #define TEST_PASS0x5555 #define TEST_FAIL0xAAAA #pragma DATA_SECTION(CPU1Data, "MSGRAM_CPU_TO_CM") uint32_t CPU1Data[10]; IPC_MessageQueue_t messageQueue; IPC_Message_tTxMsg, RxMsg; uint32_t pass; __interrupt void IPC_ISR1() {int i;bool status = false;//// Read the message from the message queue//IPC_readMessageFromQueue(IPC_CPU1_L_CM_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&RxMsg, IPC_NONBLOCKING_CALL);if(RxMsg.command == IPC_CMD_RESP){status = true;for(i=0; i<RxMsg.dataw1; i++){if((*(uint32_t *)RxMsg.address + i) != i+11)status = false;}}//// Send response message//TxMsg.command = IPC_CMD_READ_MEM;TxMsg.address = (uint32_t)CPU1Data;TxMsg.dataw1 = 10; // Using dataw1 as data lengthTxMsg.dataw2 = 1;// Message identifierIPC_sendMessageToQueue(IPC_CPU1_L_CM_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&TxMsg, IPC_NONBLOCKING_CALL);//// Acknowledge the flag//IPC_ackFlagRtoL(IPC_CPU1_L_CM_R, IPC_FLAG1);Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11); } // // Main // void main(void) {int i;//// Initialize device clock and peripherals//Device_init();//// Boot CM core// #ifdef _FLASHDevice_bootCM(BOOTMODE_BOOT_TO_FLASH_SECTOR0); #elseDevice_bootCM(BOOTMODE_BOOT_TO_S0RAM); #endif//// Initialize PIE and clear PIE registers. Disables CPU interrupts.//Interrupt_initModule();//// Initialize the PIE vector table with pointers to the shell Interrupt// Service Routines (ISR).//Interrupt_initVectorTable();//// Clear any IPC flags if set already//IPC_clearFlagLtoR(IPC_CPU1_L_CM_R, IPC_FLAG_ALL);//// Enable IPC interrupts//IPC_registerInterrupt(IPC_CPU1_L_CM_R, IPC_INT1, IPC_ISR1);//// Initialize message queue//IPC_initMessageQueue(IPC_CPU1_L_CM_R, &messageQueue, IPC_INT1, IPC_INT1);//// Synchronize both the cores//IPC_sync(IPC_CPU1_L_CM_R, IPC_FLAG31);//// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)//EINT;ERTM;//// Fill in the data to be sent//for(i=0; i<10; i++){CPU1Data[i] = i;}//// Update the message//TxMsg.command = IPC_CMD_READ_MEM;TxMsg.address = (uint32_t)CPU1Data;TxMsg.dataw1 = 10; // Using dataw1 as data lengthTxMsg.dataw2 = 1;// Message identifier//// Send message to the queue// Since C28x and CM does not share the same address space for shared RAM,// ADDRESS_CORRECTION is enabled//IPC_sendMessageToQueue(IPC_CPU1_L_CM_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&TxMsg, IPC_NONBLOCKING_CALL);//// End of example. Loop forever//while(1); } // // End of File //
修改内容:
1、我在CM4核的while循环上不断发送消息至CPU1,发现CPU1无法重复进入中断,请问是什么原因造成的?
ipc_ex2_msgqueue_cm.c
//// End of example. Loop forever//while(1){//// Send response message//TxMsg.command = IPC_CMD_RESP;TxMsg.address = (uint32_t)CMData;TxMsg.dataw1 = 10;TxMsg.dataw2 = 1;IPC_sendMessageToQueue(IPC_CM_L_CPU1_R, &messageQueue, IPC_ADDR_CORRECTION_ENABLE,&TxMsg, IPC_NONBLOCKING_CALL);}
2、想问下消息队列的阻塞方式和非阻塞方式该如何理解?
Ben Qin:
你好,
TFTMing said:1、我在CM4核的while循环上不断发送消息至CPU1,发现CPU1无法重复进入中断,请问是什么原因造成的?
可能是中断标志位没有清除。
TFTMing said:2、想问下消息队列的阻塞方式和非阻塞方式该如何理解?
你是说IPC吗?方便举个例子说明一下吗?
,
TFTMing:
Ben Qin said:可能是中断标志位没有清除。
我是直接根据原代码内容进行修改的,只是将发送ipc消息队列放在while循环里了,然后就无法重复进入中断了,原代码中是有执行Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);这个函数的。
Ben Qin said:你是说IPC吗?方便举个例子说明一下吗?
是的,就是说我不理解IPC_NONBLOCKING_CALL和IPC_BLOCKING_CALL这两种方式根据什么情况下进行选择?
,
Ben Qin:
我查看下相关资料后回复您。
,
TFTMing:
你好,请问有进展了吗?
,
Ben Qin:
抱歉忘记回复您了。这边我已经咨询了相关工程师,但由于工程师出差了,需要等到这周三才能回来。一旦工程师有回复我会立即回复您。
,
TFTMing:
好的
,
Ben Qin:
您是否能最少进入一次ISR?
关于“block”参数,我认为理解它的最好方法是阅读 ipc.c 中的 IPC_sendMessageToQueue() 和 IPC_readMessageFromQueue() 函数:
如果放置缓冲区已满,看起来非阻塞调用将使 IPC_sendMessageToQueue() 函数立即失败。阻塞参数将使函数等待,直到放置缓冲区槽空闲。
我认为这在实践中意味着如果 没有 IPC_readMessageFromQueue() 就不能多次使用 IPC_sendMessageToQueue(),否则队列将满。阻塞调用将等待(可能永远)队列有空间,而非阻塞调用在看到队列已满时将立即失败。
,
TFTMing:
Ben Qin said:您是否能最少进入一次ISR?
是 的,只有第一次能进来。
Ben Qin said:
如果放置缓冲区已满,看起来非阻塞调用将使 IPC_sendMessageToQueue() 函数立即失败。阻塞参数将使函数等待,直到放置缓冲区槽空闲。
我认为这在实践中意味着如果 没有 IPC_readMessageFromQueue() 就不能多次使用 IPC_sendMessageToQueue(),否则队列将满。阻塞调用将等待(可能永远)队列有空间,而非阻塞调用在看到队列已满时将立即失败。
明白,非常感谢!
,
Ben Qin:
已向相关工程师跟进。
,
Ben Qin:
在 ISR 被触发一次之后,您是否能够在其内存浏览器中检查 cm 消息队列的放置缓冲区的内容 ?是否能够进入 IPC_sendMessageToQueue() 函数来查看函数内部发生了什么?是否通过了上面截图中的 while 循环?函数第一次运行和后续运行有什么不同吗?
,
TFTMing:
好的,我需要去测试看一下。
,
Ben Qin:
好的
,
Ben Qin:
你好,有结果了吗?问题是否已解决?
,
TFTMing:
你好,这几天在出差,回来后会尽快验证给答复
,
Ben Qin:
好的
,
TFTMing:
你好,经过验证找到问题了
我现在只进行cm发送ipc消息,cpu1中断读取消息,通过对两个core一起打断点来查看writeIndex和readIndex。
验证过程:
1、cm第一次执行完IPC_sendMessageToQueue() 函数,CPU1进入ipc中断但未IPC_readMessageToQueue()
上面两个图可以看到,cm的PutWriteIndex和cpu1的GetWriteIndex都加1。
2、cm第一次执行完IPC_sendMessageToQueue() 函数,CPU1进入ipc中断执行了IPC_readMessageToQueue()
当cpu1执行了IPC_readMessageToQueue() 后,cm的PutReadIndex和cpu1的GetReadIndex都加1
从上面两个验证结果来看,ipc的消息队列是能重复执行的,代码也没有问题。
我之前不能重复中断的原因就是只在cpu1的ipc中断中设置断点,cm没有设置断点,也就导致cm不断发送ipc消息,而cpu1没有去读取,直到PutBuffer已满一直在IPC_sendMessageToQueue() 函数的while循环中执行,所以cpu1就没法重复进入中断读取消息了。
对于阻塞和非阻塞调用,如果发送端采用阻塞调用不断发送数据而接收端采用阻塞接收,当发送端的PutBuffer已满,那发送端和接收端都会进入While循环导致两者都不能正常工作,这种情况如果其中一端采用非阻塞调用的话则这一端就能继续执行其他任务。请问我这样理解是对的吗?
,
Ben Qin:
您的理解是正确的。