TDA4VH-Q1: Adapated drivers from R5F to C7x receive duplicate IT

Part Number: TDA4VH-Q1


Hello,

Using J784S4 EVM with SDK 10.01.00.04.

I had to adapt a few drivers written for R5F cores to work with C7x cores. To adapt the SPI driver for the C7x, I mapped the CLEC IT number in the SPI driver configuration structure and configured the CLEC event at the driver init.
I found that the C7x received 2 IT instead of 1. For example, with the SPI driver. The C7x was interrupted once with the flag 0x00000001 (TX FIFO empty) and then just after a second one with flag 0x00000000 meaning nothing (no IT flag in the SPI reg).

With GPIO driver, I have also seen this IT duplication on C7x. Therefore, I do not think that it comes from our SPI driver adaptation.

I tried clearing the CLEC event during the first IT (the meaningfull one) however to no avail.

For us this is an issue as the "remanant" IT introduces unexpected latency that I cannot afford.
Do you have any insights on what happens ?

  • Hi,

    Can you please clear the SPI interrupt flag first, then clear the CLEC event. After changing the order, check if the duplicate interrupt still occurs.

    Regards,
    SIvadeep

  • Hi,

    Thank you very much for your quick answer.
    In the MCSPI_v1_hwiFxn(), I did as you said and cleared the CLEC event (CSL_clecClearEvent) after the SPI IT flag (McSPIIntStatusClear).
    However I still see the duplication. This screenshot shows the duplication via prints in MCSPI_v1_hwiFxn():

    The order of the clears do not seem to alleviate the issue.

    Regards,
    Nathan

  • Hi,

    Is R5F triggering the event again? Can you please check if that's the case.

    Regards,
    Sivadeep

  • Hi,

    The R5F does not trigger twice, only the C7x sees this remanent IT.

    Regards,
    Nathan

  • HI Nathan,

    Let me check this and get back to you. 

    Regards,
    Sivadeep

  • Hi Nathan,

    Could you please provide more details about this interrupt scenario?

    • What modifications were made on the R5F core for interrupt handling?

    • Are there any other interrupts routed to the same destination or CLEC event?

    • What is the ISR associated with this interrupt ?

    Regards,
    Sivadeep

  • Hi Sivadeep,

    Most certainly, here is what I did:

    • Regarding the R5F, I did not touch anything. My only modifications are for the C7x.
    • Regarding the C7x there are mainly 2 changes in spi/soc/j784s4/SPI_soc.c and spi/src/v1/SPI_v1.c
    • Regarding my test case, I make one call to MCSPI_transfer() after initialising SPI. The data I see is correct so no issues on that side.

    Here is a diff of my modifications to adapt for the C7x:

    diff --git a/soc/j784s4/SPI_soc.c b/soc/j784s4/SPI_soc.c
    index 3c03a7b..d6ec237 100644
    --- a/soc/j784s4/SPI_soc.c
    +++ b/soc/j784s4/SPI_soc.c
    @@ -1458,6 +1458,72 @@ int32_t MCSPI_socInit(void)
         {
             ret = -1;
         }
    +// !ADDED
    +#elif defined(BUILD_C7X)
    +	uint32_t cpu_id	= 0;
    +
    +    cpu_id = CSL_clecGetC7xRtmapCpuId();
    +
    +    if((uint32_t)CSL_CLEC_RTMAP_CPU_4 == cpu_id)			/* MAIN C7X_1 */
    +    {
    +		spiInitCfg[0][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[0][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[0][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[1][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[1][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][3].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI3_INTR_SPI_0;
    +		spiInitCfg[1][4].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI4_INTR_SPI_0;
    +		spiInitCfg[1][5].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI5_INTR_SPI_0;
    +		spiInitCfg[1][6].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI6_INTR_SPI_0;
    +		spiInitCfg[1][7].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI7_INTR_SPI_0;
    +    }
    +    else if((uint32_t)CSL_CLEC_RTMAP_CPU_5 == cpu_id)		/* MAIN C7X_2 */
    +    {
    +		spiInitCfg[0][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[0][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[0][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[1][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[1][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][3].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI3_INTR_SPI_0;
    +		spiInitCfg[1][4].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI4_INTR_SPI_0;
    +		spiInitCfg[1][5].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI5_INTR_SPI_0;
    +		spiInitCfg[1][6].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI6_INTR_SPI_0;
    +		spiInitCfg[1][7].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI7_INTR_SPI_0;
    +    }
    +    else if((uint32_t)CSL_CLEC_RTMAP_CPU_6 == cpu_id)		/* MAIN C7X_3 */
    +    {
    +		spiInitCfg[0][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[0][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[0][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[1][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[1][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][3].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI3_INTR_SPI_0;
    +		spiInitCfg[1][4].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI4_INTR_SPI_0;
    +		spiInitCfg[1][5].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI5_INTR_SPI_0;
    +		spiInitCfg[1][6].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI6_INTR_SPI_0;
    +		spiInitCfg[1][7].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI7_INTR_SPI_0;
    +    }
    +	else if((uint32_t)CSL_CLEC_RTMAP_CPU_7 == cpu_id)		/* MAIN C7X_4 */
    +    {
    +		spiInitCfg[0][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[0][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[0][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCU_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][0].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI0_INTR_SPI_0;
    +		spiInitCfg[1][1].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI1_INTR_SPI_0;
    +		spiInitCfg[1][2].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI2_INTR_SPI_0;
    +		spiInitCfg[1][3].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI3_INTR_SPI_0;
    +		spiInitCfg[1][4].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI4_INTR_SPI_0;
    +		spiInitCfg[1][5].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI5_INTR_SPI_0;
    +		spiInitCfg[1][6].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI6_INTR_SPI_0;
    +		spiInitCfg[1][7].intNum = CSLR_COMPUTE_CLUSTER0_CLEC_SOC_EVENTS_IN_MCSPI7_INTR_SPI_0;
    +    }
    +    else
    +    {
    +        ret = -1;
    +    }
     #endif
         return (ret);
     }
    diff --git a/spi_component.mk b/spi_component.mk
    index 8ac5301..fad6584 100755
    --- a/spi_component.mk
    +++ b/spi_component.mk
    @@ -81,7 +81,7 @@ drvspi_j721s2_CORELIST             = mpu1_0 mcu1_0 mcu1_1 mcu2_0 mcu2_1 mcu3_0 m
     drvspi_j721s2_CORELIST_CACHE       = mcu1_0 mcu1_1 mcu2_0 mcu2_1 mcu3_0 mcu3_1
     drvspi_j721s2_CORELIST_DMA         = mpu1_0 mcu1_0 mcu2_0 mcu2_1 mcu3_0 mcu3_1
     drvspi_j721s2_CORELIST_DMA_CACHE   = mcu1_0 mcu2_0 mcu2_1 mcu3_0 mcu3_1
    -drvspi_j784s4_CORELIST             = mpu1_0 mcu1_0 mcu1_1 mcu2_0 mcu2_1 mcu3_0 mcu3_1 mcu4_0 mcu4_1
    +drvspi_j784s4_CORELIST             = mpu1_0 mcu1_0 mcu1_1 mcu2_0 mcu2_1 mcu3_0 mcu3_1 mcu4_0 mcu4_1 c7x_1 c7x_2
     drvspi_j784s4_CORELIST_CACHE       = mcu1_0 mcu1_1 mcu2_0 mcu2_1 mcu3_0 mcu3_1 mcu4_0 mcu4_1
     drvspi_j784s4_CORELIST_DMA         = mpu1_0 mcu1_0 mcu2_0 mcu2_1 mcu3_0 mcu3_1 mcu4_0 mcu4_1
     drvspi_j784s4_CORELIST_DMA_CACHE   = mcu1_0 mcu2_0 mcu2_1 mcu3_0 mcu3_1 mcu4_0 mcu4_1
    diff --git a/src/v1/SPI_v1.c b/src/v1/SPI_v1.c
    index 7bc1e6c..ca42c82 100755
    --- a/src/v1/SPI_v1.c
    +++ b/src/v1/SPI_v1.c
    @@ -47,6 +47,17 @@
     #include <ti/csl/src/ip/mcspi/V0/hw_mcspi.h>
     #include <ti/drv/spi/src/SPI_osal.h>
     
    +// !ADDED
    +#if defined(BUILD_C7X)
    +#include <ti/csl/arch/c7x/cslr_C7X_CPU.h>
    +#include <ti/csl/arch/c7x/Hwi.h>
    +#include <ti/csl/arch/c7x/src/clec/cslr_clec.h>
    +#include <ti/csl/arch/c7x/src/clec/csl_clec.h>
    +#include "FreeRTOS.h"
    +
    +Hwi_Handle oc_spi_set_interrupt(uint32_t cpu_event_id, uintptr_t mcHandle, uint32_t int_num);
    +#endif
    +
     #ifdef __GNUC__
     #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
     #endif
    @@ -186,10 +197,12 @@ static void SPI_init_v1(SPI_Handle handle)
      */
     static SPI_Handle SPI_open_v1(SPI_Handle handle, const SPI_Params *params)
     {
    +	DRV_PRINT_LOG("SPI_open_v1\n");
         MCSPI_Handle          mcHandle;
         MCSPI_Params          mcParams;
         SPI_v1_Object        *object;
     
    +	DRV_PRINT_LOG("SPI handle at @: %p\n", handle);
         /* Input parameter validation */
         if (NULL != handle)
         {
    @@ -198,6 +211,7 @@ static SPI_Handle SPI_open_v1(SPI_Handle handle, const SPI_Params *params)
     
             /* Get multi-channel handle */
             mcHandle = MCSPI_get_handle(handle);
    +		DRV_PRINT_LOG("Retrived MCSPI handle at @: %p\n", mcHandle);
             if (NULL != mcHandle)
             {
                 if (NULL != params)
    @@ -347,7 +361,14 @@ static void MCSPI_close_v1(MCSPI_Handle mcHandle)
             if(NULL != object->hwi)
             {
                 /* Destruct the Hwi */
    +#if defined(BUILD_MCU)
                 (void)SPI_osalHardwareIntDestruct(object->hwi, hwAttrs->eventId);
    +	// !ADDED
    +#elif defined(BUILD_C7X)
    +			(void)hwAttrs->eventId; // Disable unused warning
    +			Hwi_destruct((Hwi_Handle)object->hwi);
    +			vPortFree(object->hwi);
    +#endif
                 object->hwi = NULL;
             }
     
    @@ -1148,6 +1169,7 @@ static void MCSPI_init_v1(MCSPI_Handle mcHandle)
     static MCSPI_Handle MCSPI_open_v1(MCSPI_Handle        mcHandle,
                                       const MCSPI_Params *params)
     {
    +	DRV_PRINT_LOG("MCSPI_open_v1\n");
         SPI_Handle            handle;
         MCSPI_Handle          retMcHandle = mcHandle;
         const MCSPI_Params   *pParams = params;
    @@ -1157,7 +1179,10 @@ static MCSPI_Handle MCSPI_open_v1(MCSPI_Handle        mcHandle,
         uint32_t              chNum;
         SPI_v1_HWAttrs const *hwAttrs;
         SPI_v1_ChnCfg const  *chnCfg;
    +// !ADDED
    +#if defined(BUILD_MCU)
         OsalRegisterIntrParams_t interruptRegParams;
    +#endif
         uint32_t              ret_flag = UFALSE;
     
         /* Input parameter validation */
    @@ -1252,6 +1277,8 @@ static MCSPI_Handle MCSPI_open_v1(MCSPI_Handle        mcHandle,
                 {
                     /* register interrrupt when the 1st
                     channel of the instance is opened */
    +// !ADDED
    +#if defined(BUILD_MCU)
                     Osal_RegisterInterrupt_initParams(&interruptRegParams);             
     
                     interruptRegParams.corepacConfig.name = NULL;
    @@ -1266,7 +1293,9 @@ static MCSPI_Handle MCSPI_open_v1(MCSPI_Handle        mcHandle,
                     interruptRegParams.corepacConfig.arg         = (uintptr_t)mcHandle;
     
                     (void)SPI_osalRegisterInterrupt(&interruptRegParams,&(object->hwi));
    -
    +#elif defined(BUILD_C7X)
    +				object->hwi = (void *)oc_spi_set_interrupt(40U, (uintptr_t)mcHandle, hwAttrs->intNum);
    +#endif
                     if(NULL == object->hwi)
                     {
                         MCSPI_close_v1(mcHandle);
    @@ -1838,3 +1867,83 @@ void MCSPI_clearIntErrStatus(MCSPI_Handle mcHandle, uint32_t intStatus)
                 break;
         }
     }
    +
    +// !ADDED
    +#if defined(BUILD_C7X)
    +#define OC_C_INTERRUPT_CLEC_OFFSET	(992)
    +
    +/* pas besoin de toucher à cette fct */
    +Hwi_Handle oc_config_core_interrupt(uint32_t core_interrupt_num, void (*isr_function), uintptr_t arg)
    +{
    +	Hwi_Params hwiParams;
    +	Hwi_FuncPtr HwiFuncPtr = NULL;
    +	int32_t iStat = 0;
    +
    +	Hwi_Handle hwiHandle = (Hwi_Handle) pvPortMalloc(sizeof(HwiC7x_Struct));
    +
    +	Hwi_Params_init(&hwiParams);
    +	hwiParams.arg		= arg;
    +	hwiParams.priority	= 2;		/* doesn't work, the real priority is the core interrupt num, 1 is highest prio */
    +	hwiParams.eventId	= core_interrupt_num;
    +	hwiParams.enableInt	= true;
    +	HwiFuncPtr			= (Hwi_FuncPtr) isr_function;
    +
    +	iStat = Hwi_construct(hwiHandle, core_interrupt_num, HwiFuncPtr, &hwiParams);
    +
    +	if(iStat != 0) 
    +	{
    +		DRV_PRINT_LOG("failed config core interrupt %d : ret value is %d\n", core_interrupt_num, iStat);
    +	}
    +
    +	return hwiHandle;
    +}
    +
    +/* pas besoin de toucher à cette fct */
    +void oc_interrupt_config_CLEC(uint32_t CLEC_event_id, uint32_t core_interrupt_num)
    +{
    +	int32_t ret = CSL_PASS;
    +	CSL_ClecEventConfig cfgClec;
    +	CSL_CLEC_EVTRegs *clecBaseAddr = (CSL_CLEC_EVTRegs *) CSL_COMPUTE_CLUSTER0_CLEC_REGS_BASE;
    +
    +	/* needs an offset to reach CLEC events */
    +	CLEC_event_id += OC_C_INTERRUPT_CLEC_OFFSET;
    +
    +	/* Configure CLEC event */
    +	cfgClec.secureClaimEnable	= FALSE;
    +	cfgClec.evtSendEnable		= TRUE;
    +	cfgClec.rtMap				= CSL_clecGetC7xRtmapCpuId();
    +	cfgClec.extEvtNum			= 0;
    +	cfgClec.c7xEvtNum			= core_interrupt_num;
    +
    +	CSL_clecClearEvent(clecBaseAddr, CLEC_event_id);
    +	ret = CSL_clecConfigEvent(clecBaseAddr,CLEC_event_id, &cfgClec);
    +	
    +	if(ret != CSL_PASS)
    +	{
    +		DRV_PRINT_LOG("Interrutp Error : failed to config CLEC event %d\n", CLEC_event_id - OC_C_INTERRUPT_CLEC_OFFSET);
    +	}
    +}
    +
    +/* fonction principale qui setup l'interruption */
    +/* cpu event ID est le vecteur d'IT de ton spi sur le c7x (de 0 à 64. En général j'utilise le 40 pour mes tests)*/
    +Hwi_Handle oc_spi_set_interrupt(uint32_t cpu_event_id, uintptr_t mcHandle, uint32_t int_num)
    +{
    +	/* tu peux mettre l'event en param stv */
    +	uint32_t clec_event_id = int_num;
    +	Hwi_Handle hwi_handle = NULL;
    +
    +	/* every spi interrupt are managed by the same fct */
    +	/* the fct should identify the interrupt from its flag in the reg */
    +	oc_interrupt_config_CLEC(clec_event_id, cpu_event_id);
    +
    +	hwi_handle = oc_config_core_interrupt(	cpu_event_id, 
    +											&MCSPI_v1_hwiFxn, 
    +											mcHandle);
    +	
    +	/* enable tes IT spi via CSL ? (peut nécessiter de faire un hwi_desable/restor) */
    +	// csl_spi_enable_interrupt(id_de_ton_it);
    +
    +	return hwi_handle;
    +}
    +
    +#endif
    

    If you need any more information feel free to ask.

    Regards,
    Nathan

  • HI,

    Can you also provide a test case to replicate this issue, also could you please share the build process also for the same.

    Regards,
    Sivadeep

  • Hi,

    Could you please print MCSPI interrupt enable and status register , while these interrupts are generated , including the duplicate interrupt.

    Also clear the interrupt from the c7x side. 

    API to do the same is  HwiP_clearInterrupt could you look into PDK on its usage and parameters.

    in the duplicate interrupt i could see that it is mapped to Index 0, what interrupt to that index.

    Regards,

    Manojna

  • I created a component in the PDK with an example containing my test code. All you need to do is to require the spi component to be built as a dependency (in doubt build all_libs).
    Here is my simplified test code:

    #include <ti/drv/spi/MCSPI.h>
    #include <ti/drv/spi/soc/SPI_soc.h>
    #include <ti/board/board.h>
    #include <ti/csl/soc.h>
    #include <ti/board/src/j784s4_evm/J784S4_pinmux.h>
    #include <ti/board/src/j784s4_evm/include/board_utils.h>
    #include <ti/drv/sciclient/sciclient.h>
    #include <stdbool.h>
    #include <stdio.h>
    
    #define __BOOT_LINUX__
    #define PERF_TEST_IS_CCS_WAIT					false
    /**
     * The default channel number in multichannel case
     */
    #define MCSPI_DEFAULT_CHN			(0U)
    
    extern int tracePrintf(const char *fmt, ...); // Adjust to use remoteproc or UART
    static char s_print_buffer[1024U];
    #if defined(__clang__) || defined(__GNUC__)
      /* For the linter/host compiler, use its builtin */
      #undef va_start
      #define va_start(ap, last) __builtin_va_start(ap, last)
    #endif
    /**
     * @brief Print log with prefix
     */
    void print_with_prefix(const char* prefix, const char* pcString, ...)
    {
      
      va_list arguments;
    
      /* Start the varargs processing */
      va_start(arguments, pcString);
      vsnprintf(s_print_buffer, sizeof(s_print_buffer), pcString, arguments);
    
      tracePrintf("[%s] %s\n", prefix, s_print_buffer);
    
      /* End the varargs processing */
      va_end(arguments);
    }
    #define PRINT_LOG(debug_string, ...) print_with_prefix("C7X_1 ", debug_string, ##__VA_ARGS__)
    
    static char s_master_rx_buffer[128] __attribute__ ((aligned (128))) = {1U};
    static uint32_t s_master_tx_buffer[16] = {0x82149900, 0x82149901, 0x82149902, 0x82149903, 0x82149904, 0x82149905, 0x82149900, 0x82149907, 0x82149908, 0x82149909, 0x8214990A, 0x8214990B, 0x8214990C, 0x8214990D, 0x8214990E, 0x8214990F};
    #ifdef __BOOT_LINUX__
    TaskHandle_t xShutDownTaskHandle = NULL;
    #endif
    TaskHandle_t xTestSPITaskHandle = NULL;
    
    /**
     * Callback semaphores (1 per SPI channel)
     */
    SemaphoreHandle_t t_cb_semaphores[CSL_MCSPI_CHAN_CNT] = {NULL, NULL, NULL, NULL};
    
    /**
     * Counter of callback function passes
     */
    static uint64_t s_cb_cnt = 0;
    
    /** 
     * @brief Callback mode function for single channel with perf mode
     */
    void MCSPI_callback0(MCSPI_Handle handle, SPI_Transaction *transaction)
    {
    	BaseType_t xHigherPriorityTaskWoken = 0;
    	s_cb_cnt++;
    	(void)xSemaphoreGiveFromISR(t_cb_semaphores[0], &xHigherPriorityTaskWoken);
    	portYIELD_FROM_ISR((uint32_t)xHigherPriorityTaskWoken);
    }
    
    
    /**
     * @brief SPI init configuration for multichannel
     */
    static void SPI_initConfigDefault(SPI_HWAttrs *cfg, uint32_t chn)
    {
    	cfg->chNum							= chn;
    	cfg->chnCfg[chn].tcs				= MCSPI_CS_TCS_0PNT5_CLK;
    	/* SPIDAT[1] for TX and SPIDAT[0] for RX */
    	cfg->chnCfg[chn].dataLineCommMode	= MCSPI_DATA_LINE_COMM_MODE_1;
    	cfg->chnCfg[chn].trMode				= MCSPI_TX_RX_MODE;
    	cfg->initDelay						= MCSPI_INITDLY_0;
    	cfg->rxTrigLvl						= MCSPI_RX_TX_FIFO_SIZE;
    	cfg->txTrigLvl						= MCSPI_RX_TX_FIFO_SIZE;
    }
    
    int32_t App_test_peripheral_mcspi_api(void)
    {
    	volatile int16_t CCS_wait		= 1;
    	int32_t retVal 					= 0;
    	SPI_HWAttrs spi_cfg				= {};
    	uint32_t domain					= SPI_MCSPI_DOMAIN_MAIN;
    	uint32_t instance				= 5U;
    	MCSPI_Handle mcspi_handle		= NULL;
    	MCSPI_Params mcspi_params		= {};
    	SPI_Transaction spi_transaction	= {};
    	uint32_t transfer_size			= 64U; // In bytes
    	uint32_t trigger_lvl			= 32U; // In bytes
    	uint32_t word_size				= 32U; // In bits
    	uint32_t nb_frames_in_transfer	= 0;
    	uint32_t terminate_transfer		= 1;
    	bool transfer_success			= false;
    	uint32_t clk_freq				= 50000000U;
    	uint32_t i_nb_tests				= 0U;
    	uint32_t isSemTaken				= pdFALSE;
    
    	/* Init the MCSPI */
    	SPI_init();
    
    	/* Change interrupt number for the core */
    	MCSPI_socInit();
    
    	/* Get the default SPI init configurations */
    	retVal += SPI_socGetInitCfg(domain, instance, &spi_cfg);
    	SPI_initConfigDefault(&spi_cfg, MCSPI_DEFAULT_CHN);
    	t_cb_semaphores[0] = xSemaphoreCreateBinary();
    	configASSERT(t_cb_semaphores[0] != NULL);
    	spi_cfg.dmaMode = false;
    	spi_cfg.enableIntr = true;
    	spi_cfg.edmaHandle = NULL;
    	spi_cfg.chnCfg[MCSPI_DEFAULT_CHN].csPolarity = MCSPI_CH0CONF_EPOL_ACTIVEHIGH;
    	spi_cfg.txTrigLvl = trigger_lvl;
    	spi_cfg.rxTrigLvl = trigger_lvl;
    	spi_cfg.chnCfg[MCSPI_DEFAULT_CHN].tcs = MCSPI_CH0CONF_TCS0_ZEROCYCLEDLY;
    	spi_cfg.initDelay = MCSPI_INITDLY_0;
    	spi_cfg.pinMode = SPI_PINMODE_4_PIN;
    	
    	/* Set the SPI init configurations */
    	retVal += SPI_socSetInitCfg(domain, instance, &spi_cfg);
    	if(retVal < 0)
    	{
    		PRINT_LOG("[Error] SPI config init failed !");
    		return retVal;
    	}
    	PRINT_LOG("SPI config init success !");
    
    	/* Initialize SPI handle */
    	MCSPI_Params_init(&mcspi_params);
    	mcspi_params.mode = SPI_MASTER;
    	mcspi_params.transferTimeout = 5000U;
    	mcspi_params.bitRate = clk_freq;
    	mcspi_params.dataSize = word_size;
    	PRINT_LOG("MCSPI callback mode");
    	mcspi_params.transferMode = SPI_MODE_CALLBACK;
    	mcspi_params.transferCallbackFxn = MCSPI_callback0;
    	/* Open SPI driver */
    	PRINT_LOG("MCSPI instance opening (DOM %d, INST %d)!", domain, instance);
    	mcspi_handle = MCSPI_open(domain, instance, MCSPI_DEFAULT_CHN, &mcspi_params);
    	McSPITurboModeEnable(spi_cfg.baseAddr, MCSPI_DEFAULT_CHN);
    	while (i_nb_tests < 1U)
    	{
    		i_nb_tests++;
    		CCS_wait = 1;
    		if(PERF_TEST_IS_CCS_WAIT == true)
    		{
    			while (CCS_wait);
    		}
    		/* Wait */
    		vTaskDelay(1);
    		/* Clear buffers */
    		memset(s_master_rx_buffer, 0, sizeof(s_master_rx_buffer));
    		CacheP_wbInv(s_master_tx_buffer, sizeof(s_master_tx_buffer));
    		CacheP_wbInv(s_master_rx_buffer, sizeof(s_master_rx_buffer));
    		if (transfer_size > trigger_lvl)
    		{
    			/* always transfer data bytes of multiple trigger level */
    			transfer_size = (transfer_size / trigger_lvl) * trigger_lvl;
    		}
    		else
    		{
    			/* transfer data bytes of 1 trigger level */
    			transfer_size = trigger_lvl;
    		}
    		/* Compute the number of words and bytes for this transfer */
    		nb_frames_in_transfer = transfer_size / (word_size / 8);
    		if(nb_frames_in_transfer * (word_size / 8) < transfer_size)
    		{
    			nb_frames_in_transfer++;
    		}
    		PRINT_LOG("Word size of %u bits for a transfer of %u bytes will result in %u frames", word_size, transfer_size, nb_frames_in_transfer);
    		/* Setup the SPI transaction structure */
    		spi_transaction.count = nb_frames_in_transfer;
    		spi_transaction.arg = (void *)&terminate_transfer;
    		spi_transaction.txBuf = s_master_tx_buffer;
    		spi_transaction.rxBuf = s_master_rx_buffer;
    		/* Initiate SPI transfer */
    		transfer_success = MCSPI_transfer(mcspi_handle, &spi_transaction);
    		PRINT_LOG("SPI transfer completed!");
    
    		/* Check transfer */
    		if (transfer_success == true)
    		{
    			/* Check that the callback did happen */
    			isSemTaken = (uint32_t)xSemaphoreTake(t_cb_semaphores[0], portMAX_DELAY);
    
    			if(isSemTaken != pdTRUE)
    			{
    				PRINT_LOG("[Error] Callback semaphore could not be taken");
    				retVal = -1;
    			}
    		}
    		else
    		{
    			if (SPI_TRANSFER_TIMEOUT == spi_transaction.status)
    			{
    				PRINT_LOG("SPI transfer timed out for transfer length %d", transfer_size);
    			}
    			else
    			{
    				PRINT_LOG("[Error] Unsuccessful SPI transfer: exited with status %d", spi_transaction.status);
    			}
    			retVal = -1;
    			break;
    		}
    	}
    	PRINT_LOG("Nb of callback triggers: %llu", s_cb_cnt);
    	MCSPI_close(mcspi_handle);
    	PRINT_LOG("SPI channel closed");
    	return retVal;
    }
    
    /**
     * \brief   This is the Task function that test SPI
     *
     * \param   
     *
     * \retval  
     */
    void vTaskTestSPI(void *pvParameters)
    {
    	volatile int wait			= 1;
    
    	PRINT_LOG("********************************************\r");
    	PRINT_LOG("[FreeRTOS] SPI tests ... start !!!\r");
    	PRINT_LOG("********************************************\r");
    
    #ifdef __BOOT_LINUX__
    	int32_t ret_val			= 0;
    	uint32_t module_state	= 0;
    	uint32_t reset_state	= 0;
    	uint32_t ctx_loss_state	= 0;
    	BOARD_delay(200);
    	ret_val = Sciclient_pmGetModuleState(TISCI_DEV_MCSPI5, &module_state, &reset_state, &ctx_loss_state, SCICLIENT_SERVICE_WAIT_FOREVER);
    	configASSERT(ret_val == CSL_PASS);
    	if(module_state == TISCI_MSG_VALUE_DEVICE_HW_STATE_OFF)
    	{
    		PRINT_LOG("Current McSPI module not powered up... powering up\r");
    		ret_val = Sciclient_pmSetModuleState(TISCI_DEV_MCSPI5, TISCI_MSG_VALUE_DEVICE_SW_STATE_ON, TISCI_MSG_FLAG_AOP, SCICLIENT_SERVICE_WAIT_FOREVER);
    		configASSERT(ret_val == CSL_PASS);
    		BOARD_delay(200);
    		ret_val = Sciclient_pmGetModuleState(TISCI_DEV_MCSPI5, &module_state, &reset_state, &ctx_loss_state, SCICLIENT_SERVICE_WAIT_FOREVER);
    		configASSERT(ret_val == CSL_PASS);
    		configASSERT(module_state == TISCI_MSG_VALUE_DEVICE_HW_STATE_ON);
    		PRINT_LOG("Current McSPI module powered up !\r");
    	}
    #endif
    
    	/** 
    	 * Set the correct pinmux config
    	 * 
    	 * SPI5_CLK:	MCASP0_AXR3	(AJ38) 0x0011C07C M8
    	 * SPI5_D0:		MCAN1_RX	(AH38) 0x0011C070 M8
    	 * SPI5_D1:		MCASP0_AXR6	(AF36) 0x0011C088 M11
    	 * SPI5_CS0:	MCAN0_RX	(AE38) 0x0011C068 M8
    	 * SPI5_CS1:	MCAN0_TX	(AF38) 0x0011C064 M8
    	 */
    	*(uint32_t*)(0x0011C07C) = (uint32_t)(8U	| PIN_PULL_DISABLE | PIN_INPUT_ENABLE);
    	*(uint32_t*)(0x0011C070) = (uint32_t)(8U	| PIN_PULL_DISABLE | PIN_INPUT_ENABLE);
    	*(uint32_t*)(0x0011C088) = (uint32_t)(11U	| PIN_PULL_DISABLE | PIN_INPUT_ENABLE);
    	*(uint32_t*)(0x0011C068) = (uint32_t)(8U	| PIN_PULL_DISABLE | PIN_INPUT_ENABLE);
    	*(uint32_t*)(0x0011C064) = (uint32_t)(8U	| PIN_PULL_DISABLE | PIN_INPUT_ENABLE);
    	PRINT_LOG("SPI5 internal pins routed externally");
    
    	App_test_peripheral_mcspi_api();
    
    	PRINT_LOG("Gracefull exit\r");
    	
    	vTaskDelete(NULL);
    }
    
    #ifdef __BOOT_LINUX__
    static void Board_init_Sciclient()
    {
    	Sciclient_ConfigPrms_t config;
    	if (Sciclient_configPrmsInit(&config) != CSL_PASS) {
    		PRINT_LOG("Sciclient_configPrmsInit failed\n");
    		/* Handle error */
    	}
    
    	if (Sciclient_init(&config) != CSL_PASS) {
    		PRINT_LOG("Sciclient_init failed\n");
    		/* Handle error */
    	}
    }
    #endif
    
    #ifdef __BOOT_LINUX__
    void vTaskShutDown(void *pvParameters)
    {
    	xSemaphoreTake(shutdownSem, SemaphoreP_WAIT_FOREVER);
    	PRINT_LOG("shutting down\n");
    	BOARD_delay(100);
    
    	if (Sciclient_deinit() != CSL_PASS)
    		PRINT_LOG("Sciclient_deinit failed\n");
    
    	HwiP_disable();
    
    	asm (" idle");
    }
    #endif
    
    int main()
    {
    /*c7x_1 is defined as the main core that init the board,*/  
    #ifdef __BOOT_LINUX__
    	Board_init_Sciclient();
    	rprocInit();
    #else
    #ifdef BUILD_C7X_1
    	Board_initCfg boardCfg;
    	Board_STATUS  status;
    
    	boardCfg = BOARD_INIT_PINMUX_CONFIG |
    			BOARD_INIT_MODULE_CLOCK |
    			BOARD_INIT_UART_STDIO;
    
    	status = Board_init(boardCfg);
    
    	DebugP_assert(status == BOARD_SOK);
    #endif
    #endif
    
    	PRINT_LOG("[FreeRTOS] SPI test is starting !!!");
    	PRINT_LOG("[FreeRTOS] creating tasks ...\r");
    
    	/*Create the task to test SPI*/
    	xTaskCreate(vTaskTestSPI, "test_SPI", 4096u, NULL, 3, &xTestSPITaskHandle);
    	configASSERT(xTestSPITaskHandle);
    
    #ifdef __BOOT_LINUX__
    	/*Create the task when linux whant to shut down */
    	xTaskCreate(vTaskShutDown, "ShutDown", 4096u, NULL, 4, &xShutDownTaskHandle);
    	configASSERT(xShutDownTaskHandle);
    #endif
    
    	/* Start the scheduler to start the tasks executing. */
    	vTaskStartScheduler();
    
    	/* The following line should never be reached because vTaskStartScheduler()
    	will only return if there was not enough FreeRTOS heap memory available to
    	create the Idle and (if configured) Timer tasks.  Heap management, and
    	techniques for trapping heap exhaustion, are described in the book text. */
    	DebugP_assert(0);
    
    	return 0;
    }
    
    extern void Osal_initMmuDefault(void);
    
    void InitMmu(void)
    {
    	Osal_initMmuDefault();
    }

    Note that printing is to be mapped to your liking. I personally mapped it to print to the remoteproc trace file but this is not present in this file.
    You should see an output like this:

    [C7X_1 ] [FreeRTOS] SPI test is starting !!!
    [C7X_1 ] [FreeRTOS] creating tasks ...
    [C7X_1 ] ********************************************
    [C7X_1 ] [FreeRTOS] SPI tests ... start !!!
    [C7X_1 ] ********************************************
    [C7X_1 ] SPI5 internal pins routed externally
    [C7X_1 ] SPI config init success !
    [C7X_1 ] MCSPI callback mode
    [C7X_1 ] MCSPI instance opening (DOM 1, INST 5)!
    [C7X_1 ] Word size of 32 bits for a transfer of 64 bytes will result in 16 frames
    [C7X_1 ] SPI transfer completed!
    [C7X_1 ] Nb of callback triggers: 2
    [C7X_1 ] SPI channel closed
    [C7X_1 ] Gracefull exit

    The number of times the callback is triggered should not be 2 but 1.

  • Hi Manojna,

    Could you please print MCSPI interrupt enable and status register

    Here is what happens when printing IT enable and status registers for MCSPI_5 (the one I use, see the example I gave to Sivadeep):

    [C7X_1 ] [FreeRTOS] SPI test is starting !!!
    [C7X_1 ] [FreeRTOS] creating tasks ...
    [C7X_1 ] ********************************************
    [C7X_1 ] [FreeRTOS] SPI tests ... start !!!
    [C7X_1 ] ********************************************
    [C7X_1 ] SPI5 internal pins routed externally
    [C7X_1 ] SPI config init success !
    [C7X_1 ] MCSPI callback mode
    [C7X_1 ] MCSPI instance opening (DOM 1, INST 5)!
    [C7X_1 ] Word size of 32 bits for a transfer of 64 bytes will result in 16 frames
    Hwi start: intCode = 0x00000001, wIdx = 16, rIdx = 16
    MCSPI_IRQENABLE: 00020005
    MCSPI_IRQSTATUS: 00000001
    Hwi end:   intCode = 0x00000000, wIdx = 0, rIdx = 0
    Hwi start: intCode = 0x00000000, wIdx = 0, rIdx = 0
    MCSPI_IRQENABLE: 00000000
    MCSPI_IRQSTATUS: 00000000
    Hwi end:   intCode = 0x00000000, wIdx = 0, rIdx = 0
    [C7X_1 ] SPI transfer completed!
    [C7X_1 ] Nb of callback triggers: 2
    [C7X_1 ] SPI channel closed
    [C7X_1 ] Gracefull exit

    Also clear the interrupt from the c7x side. 

    The interrupt is already supposed to be cleared in the SPI driver on C7x side in MCSPI_v1_hwiFxn() via McSPIIntStatusClear().

    in the duplicate interrupt i could see that it is mapped to Index 0, what interrupt to that index

    In my screenshot, wIdx and rIdx represent the SPI internal write and read counters (the number of SPI words to write & read during the transfer).

    Regards,
    Nathan

  • Hi,

    Thank you for sharing, will internally discuss this with the team and get back to you.

    Regards,

    Manojna

  • Hi,

    There are some minor observation, i do not see you configuring CLEC interrupt as Level, As MCspi gives a level interrupt, not pulse.

    Regards,

    Manojna

  • Hi,

    As you suggested, I used CSL_clecConfigEventLevel() to set up the interrupt as a level interrupt (is_level = 1U).

    However, it did not solve the issue. I therefore tried with the IT in pulse mode (is_level = 0U), and it worked. I no longer see the duplicated IT.

    Do you have any idea why?

    Regards,
    Nathan

  • Hi,

    One of the things which i could think of is latency, Here McSPI might have not triggered the interrupt twice. But CLEC would have interpreted it twice. Cause of the latency.  The McSpi line could be still high when CLEC issued a clear event command which caused it to resample . Once again this is just a theory.

    Regards,

    Manojna

  • Ok, I will keep this in mind.

    Thank you very much for your help. I will mark this issue as resolved since the duplication no longer occurs.