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.

AM2634-Q1: IPC communication corrupted by ISR

Part Number: AM2634-Q1


Dear Champs,

My customer faced IPC communication was corrupted when ISR was executed.

e.g. My customer is trying to communicate with other cores through IPC while PWM interrupt was occurred at every 5us and there will be control operation in this ISR, but faced an issue in their IPC communication after this ISR like Data Overwrite, Delay and so on.

How customer can resolve this issue? Can they solve it by controlling priorities of IPC and PWM interrupt ISR? or should they use HWIP_disable() API?

If they can solve it by priority control, could you please provide some guide how they can control priority?

If they should use HWIP_disable() API, is there any method to make PWM interrupt ISR to be pending? 

Thanks and Best Regards,

SI.

  • I found there is while loop in the main and IPC function is executed in this while loop of main function when there is updated data.

    e.g. their IPC function is executed in the main function when there is new data received from ISR.

    Thanks and Best Regards,

    SI.

  • Hello SI,

    Can you confirm if it is MCAL IPC or MCU_PLUS_SDK IPC?

    Thanks,
    Gunjan

  • Hi Gunjan,

    it is MCU_PLUS_SDK_IPC.

    They are using MCU_PLUS_SDK v8.6.0.

    Thanks and Best Regards,

    SI.

  • Hello SI,

    I am working on reproducing this issue. Please expect a reply by Wednesday.

    Best Regards,
    Gunjan

  • Hello SI,

    Can you tell which cores customer using for IPC? And which core is generating PWM interrupt? Also what is priority of PWM and IPC ISR?

    Regards,
    Gunjan

  • Hi Gunjan,

    In Core0/1, there are AutoSAR platform working with IPC, and PWM based on MCU+SDK is working on Core2/3 with IPC.

    In Core 2/3, there is no IPC ISR, and IPC is executed in the main while loop when there is data received from PWM ISR like below.

    main()

    {

        do {

              if (data !=0) IPC_to_core0_and_1(data);

        } while ();

    Thanks and Best Regards,

    SI.

  • Hello SI,

    Apologies for delay in response. I have tried to add pwm interupt in core1 for ipc_notify example of mcu_plus_sdk.
    And whenever there is pwm interrupt in core1 it will do 'IpcNotify_sendMsg(0, 4, itr_interrupts, 1);' to core0.
    For me it is working fine and it is passing ipc_notify_echo successfully.

    Best Regards,
    Gunjan

  • Hi Gunjan,

    Thanks for your response and test.

    Are you using HwiP_disable() and HwiP_restore() API in your test?

    Without these APIs, they found some issues like Data Overwrite, Delay, and so on.

    If you can still success in your test without these APIs, could you please share your test files?

    Thanks and Best Regards,

    SI.

  • Hello SI,

    I have not used HwiP_disable() and HwiP_restore() in my tests. I am attaching updated ipc_notify_echo.c and example.syscfg used in Core1. For remaining cores code is same as given in ipc_notify example of MCU_PLUS_SDK .

    /*
     *  Copyright (C) 2021 Texas Instruments Incorporated
     *
     *  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.
     */
    #include <stdio.h>
    #include <inttypes.h>
    #include <kernel/dpl/ClockP.h>
    #include <kernel/dpl/SemaphoreP.h>
    #include <drivers/ipc_notify.h>
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    #include <kernel/dpl/HwiP.h>
    #include <drivers/epwm.h>
    
    /* This example shows message exchange between multiple cores.
     *
     * One of the core is designated as the 'main' core
     * and other cores are desginated as `remote` cores.
     *
     * The main core initiates IPC with remote core's by sending it a message.
     * The remote cores echo the same message to the main core.
     *
     * The main core repeats this for gMsgEchoCount iterations.
     *
     * In each iteration of message exchange, the message value is incremented.
     *
     * When iteration count reaches gMsgEchoCount, a semaphore is posted and
     * the pending thread/task on that core is unblocked.
     *
     * When a message or its echo is received, a user registered callback is invoked.
     * The message is echoed from within the user callback itself.
     *
     * This is a example message exchange, in final systems, user can do more
     * sophisticated message exchanges as needed for their applications.
     */
    
    /* Frequency of PWM output signal in Hz - 1 KHz is selected */
    #define APP_EPWM_OUTPUT_FREQ    (1U * 1000U)
    /* APP run time in seconds */
    #define APP_EPWM_RUN_TIME    (60U)
    /* FIXME : To be removed after syscfg integration */
    #define APP_INT_IS_PULSE    (1U)
    
    /* Global variables and objects */
    static HwiP_Object  gEpwmHwiObject;
    static SemaphoreP_Object  gEpwmSyncSemObject;
    
    /* Function Prototypes */
    static void App_epwmIntrISR(void *handle);
    /* variable to hold base address of EPWM that is used */
    uint32_t gEpwmBaseAddr;
    uint32_t itr_interrupts;
    
    
    
    /* number of iterations of message exchange to do */
    uint32_t gMsgEchoCount = 10u;
    /* client ID that is used to send and receive messages */
    uint32_t gClientId = 4u;
    #define max_cores_here (4U)
    
    #if defined(SOC_AM64X)
    /* main core that starts the message exchange */
    uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
    /* remote cores that echo messages from main core, make sure to NOT list main core in this list */
    uint32_t gRemoteCoreId[] = {
        CSL_CORE_ID_R5FSS0_1,
        CSL_CORE_ID_R5FSS1_0,
        CSL_CORE_ID_R5FSS1_1,
        CSL_CORE_ID_M4FSS0_0,
        CSL_CORE_ID_A53SS0_0,
        max_cores_here /* this value indicates the end of the array */
    };
    #endif
    
    #if defined(SOC_AM243X)
    /* main core that starts the message exchange */
    uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
    /* remote cores that echo messages from main core, make sure to NOT list main core in this list */
    uint32_t gRemoteCoreId[] = {
        CSL_CORE_ID_R5FSS0_1,
        CSL_CORE_ID_R5FSS1_0,
        CSL_CORE_ID_R5FSS1_1,
        CSL_CORE_ID_M4FSS0_0,
        max_cores_here /* this value indicates the end of the array */
    };
    #endif
    
    #if defined (SOC_AM263X) || defined (SOC_AM263PX)
    /* main core that starts the message exchange */
    uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
    /* remote cores that echo messages from main core, make sure to NOT list main core in this list */
    uint32_t gRemoteCoreId[] = {
        CSL_CORE_ID_R5FSS0_1,
        CSL_CORE_ID_R5FSS1_0,
        CSL_CORE_ID_R5FSS1_1,
        max_cores_here /* this value indicates the end of the array */
    };
    #endif
    
    #if defined(SOC_AM273X) || defined(SOC_AWR294X)
    /* main core that starts the message exchange */
    uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
    /* remote cores that echo messages from main core, make sure to NOT list main core in this list */
    uint32_t gRemoteCoreId[] = {
        CSL_CORE_ID_R5FSS0_1,
        CSL_CORE_ID_C66SS0,
        max_cores_here /* this value indicates the end of the array */
    };
    #endif
    
    /* semaphore's used to indicate a main core has finished all message exchanges */
    SemaphoreP_Object gMainDoneSem[max_cores_here];
    
    /* semaphore used to indicate a remote core has finished all message xchange */
    SemaphoreP_Object gRemoteDoneSem;
    
    void ipc_notify_msg_handler_main_core(uint32_t remoteCoreId, uint16_t localClientId, uint32_t msgValue, int32_t crcStatus, void *args)
    {
        /* increment msgValue and send it back until gMsgEchoCount iterations are done */
        if(msgValue != (gMsgEchoCount-1))
        {
            /* send new message to remote core, that echod our message */
            msgValue++;
    //        IpcNotify_sendMsg(remoteCoreId, gClientId, msgValue, 1);
        }
        else
        {
            /* there is one semaphore for each core ID, so post the semaphore for the remote core that
             * has finished all message exchange iterations
             */
            SemaphoreP_post(&gMainDoneSem[remoteCoreId]);
        }
    }
    
    void ipc_notify_echo_main_core_start(void)
    {
        int32_t status;
        uint32_t i, numRemoteCores;
    
        /* create completion semaphores for all cores */
        for(i=0; i < max_cores_here; i++)
        {
            SemaphoreP_constructBinary(&gMainDoneSem[i], 0);
        }
    
        /* register a handler to receive messages */
        status = IpcNotify_registerClient(gClientId, ipc_notify_msg_handler_main_core, NULL);
        DebugP_assert(status==SystemP_SUCCESS);
    
        /* wait for all cores to be ready */
        IpcNotify_syncAll(SystemP_WAIT_FOREVER);
    
    
        DebugP_log("[IPC NE core 0-0] Message exchange started by main core !!!\r\n");
    
        for(i=0; gRemoteCoreId[i]!=max_cores_here; i++)
        {
            uint32_t msgValue = 0;
            /* send message's to all participating core's, wait for message to be put in HW FIFO */
            status = IpcNotify_sendMsg(gRemoteCoreId[i], gClientId, msgValue, 1);
            DebugP_assert(status==SystemP_SUCCESS);
        }
    
        /* wait for all messages to be echo'ed back */
        numRemoteCores = 0;
        for(i=0; gRemoteCoreId[i]!=max_cores_here; i++)
        {
            SemaphoreP_pend(&gMainDoneSem[ gRemoteCoreId[i] ], SystemP_WAIT_FOREVER);
            numRemoteCores++;
        }
    
        DebugP_log("[IPC NE core 0-0] All echoed messages received by main core from %d remote cores !!!\r\n", numRemoteCores);
        DebugP_log("[IPC NE core 0-0] Messages sent to each core = %d \r\n", gMsgEchoCount);
        DebugP_log("[IPC NE core 0-0] Number of remote cores = %d \r\n", numRemoteCores);
        DebugP_log("All tests have passed!!\r\n");
    }
    
    void ipc_notify_msg_handler_remote_core(uint32_t remoteCoreId, uint16_t localClientId, uint32_t msgValue, int32_t crcStatus, void *args)
    {
        /* on remote core, we have registered handler on the same client ID and current core client ID */
    //    if(msgValue==0)
    //    IpcNotify_sendMsg(remoteCoreId, localClientId, msgValue, 1);
    
        /* if all messages received then post semaphore to exit */
        if(msgValue == (gMsgEchoCount-1))
        {
            SemaphoreP_post(&gRemoteDoneSem);
        }
    }
    
    void ipc_notify_echo_remote_core_start(void)
    {
        int32_t status;
    
        SemaphoreP_constructBinary(&gRemoteDoneSem, 0);
    
        /* register a handler to receive messages */
        status = IpcNotify_registerClient(gClientId, ipc_notify_msg_handler_remote_core, NULL);
        DebugP_assert(status==SystemP_SUCCESS);
    
        /* wait for all cores to be ready */
        IpcNotify_syncAll(SystemP_WAIT_FOREVER);
    
        DebugP_log("[IPC NE core 0-0] Remote Core waiting for messages from main core ... !!!\r\n");
    
        int32_t  statusepwm;
        uint32_t  numIsrCnt = (APP_EPWM_RUN_TIME * APP_EPWM_OUTPUT_FREQ);
        HwiP_Params  hwiPrms;
    
    /* Get Address of ePWM */
    gEpwmBaseAddr = CONFIG_EPWM_BASE_ADDR;
    statusepwm = SemaphoreP_constructCounting(&gEpwmSyncSemObject, 0, numIsrCnt);
    DebugP_assert(SystemP_SUCCESS == statusepwm);
    
    /* Register & enable interrupt */
        HwiP_Params_init(&hwiPrms);
        /* Integrate with Syscfg */
        hwiPrms.intNum      = CSLR_R5FSS0_CORE0_CONTROLSS_INTRXBAR0_OUT_0;
        hwiPrms.callback    = &App_epwmIntrISR;
        /* Integrate with Syscfg */
        hwiPrms.isPulse     = APP_INT_IS_PULSE;
        statusepwm              = HwiP_construct(&gEpwmHwiObject, &hwiPrms);
        DebugP_assert(statusepwm == SystemP_SUCCESS);
    
        EPWM_clearEventTriggerInterruptFlag(gEpwmBaseAddr);
    
        /* wait for all messages to be echo'ed back */
        SemaphoreP_pend(&gRemoteDoneSem, SystemP_WAIT_FOREVER);
    
        DebugP_log("[IPC NE core 0-0] Remote core has echoed all messages !!!\r\n");
    }
    
    
    
    void ipc_notify_echo_main(void *args)
    {
        Drivers_open();
        Board_driversOpen();
    
        itr_interrupts = 0;
    
        if(IpcNotify_getSelfCoreId()==gMainCoreId)
        {
            ipc_notify_echo_main_core_start();
        }
        else
        {
            ipc_notify_echo_remote_core_start();
        }
    
        Board_driversClose();
        /* We dont close drivers to let the UART driver remain open and flush any pending messages to console */
        /* Drivers_close(); */
    }
    
    static void App_epwmIntrISR(void *handle)
    {
        DebugP_log("[IPC NE core 0-0] PWM ISR !!!\r\n");
        volatile bool status;
    
        /* on remote core, we have registered handler on the same client ID and current core client ID */
        if(itr_interrupts == (gMsgEchoCount-1))
            {
                SemaphoreP_post(&gRemoteDoneSem);
            }
        else
            IpcNotify_sendMsg(0, 4, itr_interrupts, 1);
            itr_interrupts= itr_interrupts + 1;
    
        status = EPWM_getEventTriggerInterruptStatus(gEpwmBaseAddr);
        if(status == true)
        {
            SemaphoreP_post(&gEpwmSyncSemObject);
            EPWM_clearEventTriggerInterruptFlag(gEpwmBaseAddr);
        }
    
        return;
    }
    
    
    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/908/6153.example.syscfg

    Thanks,
    Gunjan

  • Hi Gunjan,

    Thanks for the sharing the code.

    I got more details as below for their structure.

    * PWM ISR at every 5us ISR

    * IPC will be occurred at every

      - read at every 1ms(Core 0/1 -> Core 2/3) in the main while loop.

      - write at every 5ms(Core 2/3 -> Core 0/1) in the main while loop.

    Their target is to get all PWM ISRs without any loss, and they are worrying the PWM interrupts would be lost after HwiP_disable().

    I think HwIP_disable() API would ignore all interrupts and all these interrupts would be lost, right?

    They believe it takes 3~3.5us to execute PWM ISR(60~70% CPU loads).

    Could you please suggest what is robust structure of IPC for their usecase? I think they should make additional tasks for IPC read/write. what is your opinion?

    Thanks and Best Regards,

    SI.

  • Hello SI,

    PWM interrupt in all cores or some specific core?

    When HwiP_disable() is called it will stop receiving interrupts(let's say we disable it for PWM handling:3us) and since ipc are occurring at 1us interval, in between IPC interrupts will be missed.
    They are generating IPC and PWM interrupts, then one of them will be of higher priority. Higher priority interrupt will be serviced first.

    Best Regards,
    Gunjan