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: IPC message queue communication between CPU1 and CM and IPC communication issues

Part Number: TMS320F28388D

Hi Team,

1) CPU1 can enter an IPC interrupt when CM sends data to CPU1 through the message queue when communicating between CPU1 and CM using IPC message queues in customer-built project code. however, the GetWriteIndex for CPU1 is not updated: 

CPU1:

CM:

The CPU1 codes are as follows:

CM:

2) Is it required to call IPC_waitForAck to wait for a response after the sending side calls the IPC_sendCommand function when communicating with IPC non-message queues?

Because the customer has tried to send by calling only the IPC_sendCommand function, interrupts can be entered normally on the receiving side. However, there is a chance that the IPC_readCommand function will not be read out when called, and the receiving side will call the IPC_ackFlagRtoL function normally. 

Could you help check this case? Thanks.

Best Regards,

Cherry

  • Hi Cherry,

    Please allow me a day to look into the first issue.

    For issue 2: 

    The IPC_waitForAck() function is simply waiting for the IPC flag that is passed as an argument to be cleared. If the IPC_sendCommand() function is used multiple times with the same flag without the IPC_waitForAck() function, there is a possibility that the flag is already high, so the remote CPU will not see the flag go high again.

    The IPC_readCommand() function returns true(1) or false(0) when called. Could you check what your customer is seeing when the IPC_readCommand() function is not reading the expected data? 

    Best Regards,

    Ben Collier

  • Cherry,

    Apologies for the delay, but I will need another day or two to look into the first issue. 

    Best Regards,

    Ben Collier

  • Hi Ben Collier,

    Thank you for the support.

    Apologies for the delay, but I will need another day or two to look into the first issue. 

    Thanks and expect your response.

    The IPC_waitForAck() function is simply waiting for the IPC flag that is passed as an argument to be cleared. If the IPC_sendCommand() function is used multiple times with the same flag without the IPC_waitForAck() function, there is a possibility that the flag is already high, so the remote CPU will not see the flag go high again.

    Understood and since the IPC_sendCommand function is called once every 1ms in the code, it is not repeated at all. 

    The IPC_readCommand() function returns true(1) or false(0) when called. Could you check what your customer is seeing when the IPC_readCommand() function is not reading the expected data? 

    The value read back is 1, but the value of command read back is not correct.

    Because the customer uses ECAT and Enet for communication in CM, ECAT sends data to CPU1 via IPC0, Enet sends data to CPU1 via IPC1, and IPC0's sendCommand function is called in the while loop. the IPC1 transmit function is called in the receive interrupt of Enet, so the customer guesses that the receive interrupt from Enet is interrupting the IPC0 wait while the IPC_waitForAck() function is executing. And the transmit function for IPC1 of Enet is executed.

    The command value read back in the IPC0 interrupt for CPU1 is the value that IPC1 sends to the command for CPU1, but IPC0 and IPC1 are two different interrupts.

    Why was the command value for IPC1 read back in IPC0? And that happens at a certain probability. 
    Thanks and regards,
    Cherry
  • Cherry,

    I apologize again, I will look into the GetWriteIndex not incrementing tomorrow. I suspect that it is an issue with the register view in CCS and that it may actually be incrementing.

    Are both IPC0 and IPC1 using messageQueue? Are they using the same message queue address? 

    Best Regards,

    Ben Collier

  • Cherry,

    I am not able to replicate the customer issue where the GetWriteIndex and GetReadIndex are not incrementing. The GetWriteIndex should increment when the IPC_sendMessageToQueue() function is called and the GetReadIndex should increment when the IPC_readMessageFromQueue() function is called. 

    Does the customer not see this? 

    Best Regards,

    Ben Collier

  • Hi Ben Collier,

    1) CPU1 can enter an IPC interrupt when CM sends data to CPU1 through the message queue when communicating between CPU1 and CM using IPC message queues in customer-built project code. however, the GetWriteIndex for CPU1 is not updated: 

    The issue is due to different variables mapped to the Message RAM for CM and CPU1. 

    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];		

    IPC_CPU_to_CM_GetBuffer for CPU1 is in a different location in MSGRAM and IPC_CM_to_CPU1_PutBuffer for CM, so it does not work properly.

    Then there 's a new question, if the user would like to define variables in MSGRAM, is there a way to avoid the above issue?

    Are both IPC0 and IPC1 using messageQueue? Are they using the same message queue address? 

    Message queues are not used, the IPC_sendCommand and IPC_readCommand functions are used here.

    Thanks and regards,

    Cherry

  • Cherry,

    Are you able to share all of the customer's code related to IPC? I am having a hard time understanding what they are trying to do.

    Has the customer looked at the ipc_ex2_msgqueue example to see how this issue of different addresses is handled? The below screenshot is from the IPC_sendMessageToQueue() function.

    Could the customer modify the address correction part of the function to work for their specific address locations? 

    Best Regards,

    Ben Collier

  • Hi Ben Collier,

    CM Core transmit IPC0 function: 

    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 kernel while loop send call send function: 

        while(1)
        {
    //    	testcount++;
    //    	if(testcount >= 64)
        	if(EcatRev_Flag == 1)
        	{
        		SYNC0_Update_Send();
        		EcatRev_Flag = 0;
    //    		testcount = 0;
        	}
        }

    CM: ENET receive function, IPC1 sends data received by Enet to 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);
    }

    Interrupt IPC0 and IPC1 receive function for CPU1: 

    __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;
    }

    Could the customer modify the address correction part of the function to work for their specific address locations? 

    The customer uses the cmd file to store user-defined arrays by re-dividing the IPCMSGRAM address into a region, dose this make sense?

    Thanks and regards,

    Cherry

  • Cherry,

    Please allow me to get back to you about this tomorrow. Apologies again for the delay. 

    Best Regards,

    Ben Collier

  • Cherry,

    I apologize again for the delays, but please allow me to get back to you about this next Monday when I am back in office. I will try to find some time to look into this before Monday, but I am not sure if I will be able.

    Best Regards,

    Ben Collier

  • Hi Ben Collier,

    Thank you and feel free to give any updates.

    Best Regards,

    Cherry

  • Cherry,

    I will need another day to look into this, I am very sorry again about the delays. 

    Best Regards,

    Ben Collier

  • Cherry,

    I am finally getting some more time to look into this issue. Just to confirm, the issues that the customer needs help with are the following:

    1) Buffer indexes are not incrementing for their message queue (using IPC2)

    2) Reading command on CPU1 for IPC0 returns the command passed for IPC1

    Is issue 2 something that happens intermittently, or does it happen every time the command is read for IPC0? 

    Best Regards,

    Ben Collier

  • Hi Ben Collier,

    1) Buffer indexes are not incrementing for their message queue (using IPC2)

    Issue 1 has been resolved.

    2) Reading command on CPU1 for IPC0 returns the command passed for IPC1

    Is issue 2 something that happens intermittently, or does it happen every time the command is read for IPC0? 

    It happens intermittently, IPC0 is sent to CPU1 on the while loop in CM and IPC1 is sent in an interrupt in CM. The customer is wondering if it's because that while IPC0 is performing a sending and waiting for a reply from CPU1, the interrupt from CM triggers the sending of IPC1 and then receives the command from IPC1 in the IPC0 interrupt of CPU1. But it's strange so they would like to figure it out.

    Thanks and regards,

    Cherry

  • Hi Cherry,

    This is an interesting issue, and I can see how it is happening by looking at the IPC_sendCommand() function. I think this is the expected behavior when the IPC_sendCommand() function is interrupted, and then another IPC_sendCommand() function is used before the first one can be completed.

    I will need to talk with a coworker about how to work around this. Would it be acceptable in the customer system to delay the ethernet interrupt until the IPC0 sendCommand function is complete? I think that would be one of the options. 

    Best Regards,

    Ben Collier

  • Hi Cherry,

    I've had a lot of conversations with coworkers about this issue over the last week. The general consensus is that the customer should not need to disable interrupts during their first IPC_sendCommand() function, but instead it may be better for them to use message Queues for these messages as well. 

    It is possible to set up multiple message queues so that the customer can keep messages from different origins separated. I'll try to leave some instructions about how to do this.

    Best Regards,

    Ben Collier

  • Hi Cherry,

    I was curious if you've had any recent communication with the customer about this? Would they be ok with stopping interrupts during the IPC_sendCommand() function in their while loop? I think the other alternative would be to use multiple messageQueues instead of using the IPC_sendCommand() function.

    Best Regards,

    Ben Collier

  • Hi Ben,

    Thanks for your help and response, the customer just updated with the message that the above workaround does work!

    Thank you again!

    Best Regards,

    Cherry