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.

RTOS/MSP430F5529: TI-RTOS, two spi(one master one slave) synchronization issue!

Part Number: MSP430F5529

Tool/software: TI-RTOS

hi everyone

Recently I cofig SPI master and SPI slave on the MSP_EXP430F5529LP develop board,  under TI-RTOS two TASK,  I found that  two spi interact with each other. When I turn off one of the tasks and the other spi works ok ,  I try to add semaphores to protect SPI_transfer() funtion, and the problem remains, I put the breakpoint and found that the problem appeared in the following figure, resulting in SPI transfer return false,  and spi slave can only send the first byte out. Who can teach me how to do it, or give me a similar example, thank you!

best regards 

xc.mo

1.

2.code 

#define spiA1_TASKSTACKSIZE   512

SPI_Handle      spiA1_master;
SPI_Params      spiA1_master_Params;
Task_Struct spiA1_master_taskStruct;
Char spiA1_master_taskStack[spiA1_TASKSTACKSIZE];

GateMutex_Handle gatemutex_handle;
GateMutex_Params gatemutex_params;


#define spiB1_TASKSTACKSIZE   512

SPI_Handle      spiB1_slave;
SPI_Params      spiB1_slave_Params;
Task_Struct spiB1_slave_taskStruct;
Char spiB1_slave_taskStack[spiB1_TASKSTACKSIZE];



//Semaphore_Handle spiB1_semHandle;
Semaphore_Params spiB1_semParams;
Semaphore_Struct spiB1_semStructP;

//Semaphore_Handle protect SPI_transfer()
Semaphore_Params two_spi_semParams;
Semaphore_Struct two_spi_semStructP;

//
//
void spiA1transferCallbackFxn(SPI_Handle handle, SPI_Transaction* transaction)
{
	Board_SPIA1_MASTER_CS_HIGH;	
	
    Semaphore_post(Semaphore_handle(&two_spi_semStructP));
     
	
    System_printf("spiA1 transferCallbackFxn inter!\n");
    System_flush();
}

/*
 *  ======== uscia1_spi taskFxn ========
 *  Task for this function is created statically. See the project's .cfg file.
 */
Void spiA1_master_taskFxn(UArg arg0, UArg arg1)
{
    /* Create I2C for usage */
    SPI_Params_init(&spiA1_master_Params);
    spiA1_master_Params.transferMode          = SPI_MODE_CALLBACK;
    spiA1_master_Params.transferCallbackFxn   = spiA1transferCallbackFxn;
    spiA1_master_Params.mode                  = SPI_MASTER;
    spiA1_master_Params.bitRate               = 500000,            /* bitRate Hz*/
    spiA1_master_Params.dataSize              = 8;
    spiA1_master_Params.frameFormat           = SPI_POL1_PHA1;

    spiA1_master = SPI_open(Board_SPIA1_MASTER, &spiA1_master_Params);
    if (spiA1_master == NULL) {
        System_abort("Error Initializing SPI\n");
    }
    else {
        System_printf("spiA1 Initialized!\n");
    }
    System_flush();

    //gatemute
    GateMutex_Params_init(&gatemutex_params);
    gatemutex_handle = GateMutex_create(&gatemutex_params, NULL);
    if (gatemutex_handle == NULL) {
        System_abort("Error GateMutex_create\n");
    }
    else {
        System_printf("GateMutex_create OK!\n");
    }

    char txbuf[5] = {0x21,0x22,0x23,0x24,0x25};
    char rxbuf[6];

    uint8_t count ;
    SPI_Transaction spiTransaction;
    while(1){

        //cs low
        Board_SPIA1_MASTER_CS_LOW;

        Semaphore_pend(Semaphore_handle(&two_spi_semStructP),BIOS_WAIT_FOREVER);

        spiTransaction.txBuf = txbuf;
        spiTransaction.rxBuf = NULL;
        spiTransaction.count = 5;
        if (SPI_transfer(spiA1_master, &spiTransaction) == NULL) {
           System_printf("spiA1 Bus fault\n");
           System_flush();
        }
		

        Task_sleep(1000);
        GPIO_toggle(Board_LED_P1_0);;
    }
}



void spiB1_CS_Fxn1(UArg arg)
{
    Semaphore_post(Semaphore_handle(&spiB1_semStructP));

    //System_printf("spiB1 CS P2_4 interrupt callback!\n");
    //System_flush();
}

Void spiB1_slave_taskFxn(UArg arg0, UArg arg1)
{
    /* Create SPI for usage */
    SPI_Params_init(&spiB1_slave_Params);
    spiB1_slave_Params.transferMode          = SPI_MODE_CALLBACK;
    spiB1_slave_Params.transferCallbackFxn   = spiB1_transferCallbackFxn;
    spiB1_slave_Params.mode                  = SPI_SLAVE;
    spiB1_slave_Params.dataSize              = 8;


    spiB1_slave = SPI_open(Board_SPIB1_SLAVE, &spiB1_slave_Params);
    if (spiB1_slave == NULL) {
        System_abort("Error Initializing SPI B1\n");
    }
    else {
        System_printf("SPI B1 Initialized!\n");
    }
    System_flush();

    //gatemute
    GateMutex_Params_init(&gatemutex_spiB1_params);
    gatemutex_spiB1_handle = GateMutex_create(&gatemutex_spiB1_params, NULL);
    if (gatemutex_spiB1_handle == NULL) {
        System_abort("Error gatemutex_spiB1_create\n");
    }
    else {
        System_printf("gatemutex_spiB1_create OK!\n");
    }
    System_flush();

    //CS Semaphore
    Semaphore_Params_init(&spiB1_semParams);
    spiB1_semParams.mode = Semaphore_Mode_BINARY;
    Semaphore_construct(&spiB1_semStructP, 0, &spiB1_semParams);

	
    //enable CS(P2_4)  interrupt
    GPIO_setCallback(Board_SPIB1_SLAVE_CS_P2_4, (GPIO_CallbackFxn)spiB1_CS_Fxn1);//much be before GPIO_enableInt()
    GPIO_enableInt(Board_SPIB1_SLAVE_CS_P2_4);

    char txbuf[5] = {0x12,0x13,0x14,0x15,0x16};
	
	SPI_Transaction spiTransaction;
    Task_sleep(100);
    while(1){

        //judge CS by Gpio Interrupt
        Semaphore_pend(Semaphore_handle(&spiB1_semStructP),BIOS_WAIT_FOREVER);
    
		// protect  SPI_transfer()
		Semaphore_pend(Semaphore_handle(&two_spi_semStructP),BIOS_WAIT_FOREVER);

		spiTransaction.txBuf = txbuf;
		spiTransaction.rxBuf = NULL;
		spiTransaction.count = 5;

		if (SPI_transfer(spiB1_slave, &spiTransaction) == NULL) {
			System_printf("spiB1 Bus fault\n");
			System_flush();
		}

		Semaphore_post(Semaphore_handle(&two_spi_semStructP));

        Task_sleep(1000);
		GPIO_toggle(Board_LED_P4_7);
    }
}


int main(void)
{
    /* Call board init functions */
    Board_initGeneral();
    Board_initGPIO();
    Board_initSPI();
	
    //spi master
    taskParams.arg0         = 1000;
    taskParams.stackSize    = spiA1_TASKSTACKSIZE;
    taskParams.stack        = &spiA1_master_taskStack;
    Task_construct(&spiA1_master_taskStruct, (Task_FuncPtr)spiA1_master_taskFxn, &taskParams, NULL);

    //spiB1 slave
    taskParams.arg0         = 1000;
    taskParams.stackSize    = spiB1_TASKSTACKSIZE;
    taskParams.stack        = &spiB1_slave_taskStack;
    Task_construct(&spiB1_slave_taskStruct, (Task_FuncPtr)spiB1_slave_taskFxn, &taskParams, NULL);
	
	
    //Two_SPI Semaphore  protected  SPI_transfer()
    Semaphore_Params_init(&two_spi_semParams);
    spiB1_semParams.mode = Semaphore_Mode_BINARY;
    Semaphore_construct(&two_spi_semStructP, 1, &two_spi_semParams);
	
	
    /* Start BIOS */
    BIOS_start();

    return (0);
}

  • Hi xc.mo,

    I think the problem exists in the Semaphore_post(&two_spi_semStructP) in spiB1_slave_taskFxn().

    You have SPIB1_SLAVE opened in CALLBACK mode, so when you return from the SPI_transfer() in spiB1_slave_taskFxn(), the transfer is potentially still in progress, yet you post the "SPI available" semaphore two_spi_semStructP.  This allows spiA1_master_taskFxn() to proceed from its Semaphore_pend(&two_spi_semStructP) call into SPI_transfer(), and the transfer function SPIUSCIBDMA_transfer() sees that there is still a transaction in progress and returns failure.

    You didn't paste your SPIB1 callback function code for spiB1_transferCallbackFxn() so I can't see what it's doing, but shouldn't the Semaphore_post(&two_spi_semStructP) in spiB1_slave_taskFxn() instead be in spiB1_transferCallbackFxn(), similar to your handling of the semaphore in the spiA1_master_taskFxn()?  Or, leave it as you have it but change SPIB1's mode to BLOCKING, in which case you will know you're done with the transfer when SPI_transfer() returns true.

    Regards,

    - Rob

  • Can you confirm that you are using different TX and RX DMA channels for each of the two the SPIs ( a total of 4 different DMA channels)?

  • hi Tooma

         I'm sorry I just got back to you because of time difference.  You're right. Two spi can use different DMA channels to resolving the SPI_transfer() funtion conflicts, but  5529 only three DMA channels in the device datasheet are for peripheral use, and I have two spis, requiring a total of four DMA channels (one  spi TX and  RX),  when I use other channels (more than 3) in spi's TX or RX, the xpi's TX or RX cannot send or receive data.   Can you give me more guidance? Thank you!

    best regards

    xc.mo

    1. msp430f5529 device datasheet


    2. my spi code 

    /*
     *  =============================== DMA ===============================
     */
    /*
     *  ======== MSP_EXP430F5529LP_isrDMA ========
     *  This is a application defined DMA ISR. This ISR must map and call the
     *  appropriate Driver_event(handle) API to indicate completed DMA transfers.
     */
    #include <ti/drivers/spi/SPIUSCIADMA.h>
    #include <ti/drivers/spi/SPIUSCIBDMA.h>
    
    Void MSP_EXP430F5529LP_isrDMA(UArg arg)
    {
    
        SPIUSCIADMA_HWAttrs const  *hwAttrsA;
        SPIUSCIBDMA_HWAttrs const  *hwAttrsB;
    
        hwAttrsA = ((SPI_Handle)&(SPI_config[0]))->hwAttrs;
        hwAttrsB = ((SPI_Handle)&(SPI_config[1]))->hwAttrs;
    
    
        //Call the SPI DMA function, passing the SPI handle used for WiFi
        if(DMA_getInterruptStatus(hwAttrsA->txDMAChannelIndex) == DMA_INT_ACTIVE||
           DMA_getInterruptStatus(hwAttrsA->rxDMAChannelIndex) == DMA_INT_ACTIVE
        ){
            //DMA_clearInterrupt(hwAttrsA->txDMAChannelIndex);
            //DMA_clearInterrupt(hwAttrsA->rxDMAChannelIndex);
            //NOTE: PRINT CAN'T REMOVE  AS  DELAY
            System_printf("SPIA-SPI_serviceISR------------------\r\n");
            System_flush();
            SPI_serviceISR((SPI_Handle) &(SPI_config[0]));
        }
        if(DMA_getInterruptStatus(hwAttrsB->txDMAChannelIndex) == DMA_INT_ACTIVE||
           DMA_getInterruptStatus(hwAttrsB->rxDMAChannelIndex) == DMA_INT_ACTIVE
        ){
            //DMA_clearInterrupt(hwAttrsB->txDMAChannelIndex);
            //DMA_clearInterrupt(hwAttrsB->rxDMAChannelIndex);
            //NOTE: PRINT CAN'T REMOVE  AS  DELAY
            System_printf("SPIB-SPI_serviceISR------------------\r\n");
            System_flush();
            SPI_serviceISR((SPI_Handle) &(SPI_config[1]));
        }
    
        /* Call the SPI DMA function, passing the SPI handle used for WiFi */
        //SPI_serviceISR((SPI_Handle) &(SPI_config[0]));
        //SPI_serviceISR((SPI_Handle) &(SPI_config[1]));
    }
    
    
    /*
     *  =============================== SPI ===============================
     */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(SPI_config, ".const:SPI_config")
    #pragma DATA_SECTION(spiUSCIBDMAHWAttrs, ".const:spiUSCIADMAHWAttrs")
    #endif
    
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/spi/SPIUSCIADMA.h>
    
    //
    // USCIA
    //
    SPIUSCIADMA_Object spiUSCIADMAObjects[MSP_EXP430F5529LP_SPIA_COUNT];
    uint8_t spiUSCIADMAscratchBuf[MSP_EXP430F5529LP_SPIA_COUNT];
    
    const SPIUSCIADMA_HWAttrs spiUSCIADMAHWAttrs[MSP_EXP430F5529LP_SPIA_COUNT] = {
        {
            .baseAddr           = USCI_A1_BASE,
            .clockSource        = USCI_A_SPI_CLOCKSOURCE_SMCLK,
            .bitOrder           = USCI_A_SPI_MSB_FIRST,
            .scratchBufPtr      = &spiUSCIADMAscratchBuf[0],
            .defaultTxBufValue  = 0xff,
    
            /* DMA */
            .dmaBaseAddr        = DMA_BASE,
            /* Rx Channel */
            .rxDMAChannelIndex  = DMA_CHANNEL_1,
            .rxDMASourceTrigger = DMA_TRIGGERSOURCE_20,//look device cheel
    
            /* Tx Channel */
            .txDMAChannelIndex  = DMA_CHANNEL_0,
            .txDMASourceTrigger = DMA_TRIGGERSOURCE_21
        }
    };
    
    //
    // USCIB
    //
    #pragma DATA_SECTION(spiUSCIADMAHWAttrs, ".const:spiUSCIBDMAHWAttrs")
    #include <ti/drivers/spi/SPIUSCIBDMA.h>
    
    SPIUSCIBDMA_Object spiUSCIBDMAObjects[MSP_EXP430F5529LP_SPIB_COUNT];
    uint8_t spiUSCIBDMAscratchBuf[MSP_EXP430F5529LP_SPIB_COUNT];
    
    const SPIUSCIBDMA_HWAttrs spiUSCIBDMAHWAttrs[MSP_EXP430F5529LP_SPIB_COUNT] = {
        {
            .baseAddr           = USCI_B1_BASE,
            .clockSource        = USCI_B_SPI_CLOCKSOURCE_SMCLK,
            .bitOrder           = USCI_B_SPI_MSB_FIRST,
            .scratchBufPtr      = &spiUSCIBDMAscratchBuf[0],
            .defaultTxBufValue  = 0xff,
    
            /* DMA */
            .dmaBaseAddr        = DMA_BASE,
            /* Rx Channel */
            .rxDMAChannelIndex  = DMA_CHANNEL_2,
            .rxDMASourceTrigger = DMA_TRIGGERSOURCE_22,//look device cheel
    
            /* Tx Channel */
            .txDMAChannelIndex  = DMA_CHANNEL_0,       //like this  when change DMA_CHANNEL_3, spi can't tx 
            .txDMASourceTrigger = DMA_TRIGGERSOURCE_23
        }
    };
    
    
    const SPI_Config SPI_config[] = {
        {
            .fxnTablePtr    = &SPIUSCIADMA_fxnTable,
            .object         = &spiUSCIADMAObjects[0],
            .hwAttrs        = &spiUSCIADMAHWAttrs[0]
        },
        {
            .fxnTablePtr    = &SPIUSCIBDMA_fxnTable,
            .object         = &spiUSCIBDMAObjects[0],
            .hwAttrs        = &spiUSCIBDMAHWAttrs[0]
        },
        {NULL, NULL, NULL},
    };
    
    
    void MSP_EXP430F5529LP_initSPI(void)
    {
        //
        //USCIA1
        //
        /* Configure CS pins to disable spi slave device*/
        GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN0);
        GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN0);
    
        /* SPI CLK */
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN0);
        /* MOSI/SIMO */
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);
        /* MISO/SOMI */
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);
    
        //
        //USCIB1
        //
        //slave
        //GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN4);
        //GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN4);
        //GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4);
    
        // SPI CLK
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN3);
        // MOSI/SIMO
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN1);
        // MISO/SOMI
        GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN2);
    
        SPI_init();
    }
    

     

  • hi Rob

    Although the final solution to the SPI_transfer() funtion conflict is using different DMA channels, there is nothing wrong with your analysis,  

    1.when SpiB_Slave  open  in CALLBACK mode,  semaphores(two_spi_semStructP)  have always been occupied by spiB1_slave_taskFxn task,  and my post code may be a bit of a problem

    2.my SPIB1 callback function  just do some printf  processing. 

    3.whether slave or master, I have tried to place Semaphore_post(&two_spi_semStructP) in spiB1_transferCallbackFxn() or spiA1_transferCallbackFxn() , but still can not change anything!

    Tomorrow I will continue to verify the use of semaphore to protect one of the four dma channels, you can have time to see my response to TOOMA, Thank you very much for your reply.

    best regards

    xc.mo

**Attention** This is a public forum