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.

TMS320F280025C: Synchronizing SPI transmit and receive buffers at master and slave ends

Part Number: TMS320F280025C
Other Parts Discussed in Thread: SYSCONFIG

I have configured SPIs with DMA controller. There are two DMA channels: one for transmission and second for reception. There are two arrays on both the master and slave sides. In ideal scenario the transmit array index is same as receive array index. However if any device gets reset the the array indexes get misaligned. For e.g. if both master and slaves were initially at index number 10 then after any device reset one of the device has array index set to 0. This causes the data at array index 0 of the reset device to be written to array index 10 of the normal device.  The master can signal to the slave to reset its SPI transmission via digital I/O or UART. The question is that what is the best way to reset SPI transmission & reception at the slave side considering that it is attached to DMA controller? It appears that i will need to reset both the DMA controller channels and SPI FIFOs but I don't know the proper and best way to do this.

  • I have made below function according to my understanding:

    void SPI_DMA_Reset()
    {
        //Disabling DMA transmission channel trigger
        DMA_disableTrigger(DMA_CH5_BASE);
        //Disabling DMA reception channel trigger
        DMA_disableTrigger(DMA_CH6_BASE);
        //Disabling SPI FIFOs
        SPI_disableFIFO(SPIB_BASE);
        //Resetting transmit FIFO
        SPI_resetTxFIFO(SPIB_BASE);
        //Resetting receive FIFO
        SPI_resetRxFIFO(SPIB_BASE);
        //Re-enabling SPI FIFO
        SPI_enableFIFO(SPIB_BASE);
        SPI_setFIFOInterruptLevel(SPIB_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
        //
           // Initialize DMA
           //
           DMA_initController();
    
           //
           // Configure DMA Ch5 for TX. When there is enough space in the FIFO, data
           // will be transferred from the sData buffer to the SPI module's transmit
           // buffer register.
           //
           DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SPIB_BASE + SPI_O_TXBUF),
                               sData);
           DMA_configBurst(DMA_CH5_BASE, BURST, 1, 0);
           DMA_configTransfer(DMA_CH5_BASE, TRANSFER, 1, 0);
           DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_SPIBTX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch5 interrupts
           //
           DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_BEGINNING);
           DMA_enableInterrupt(DMA_CH5_BASE);
           DMA_enableTrigger(DMA_CH5_BASE);
    
           //
           // Configure DMA Ch6 for RX. When the FIFO contains at least 8 words to
           // read, data will be transferred from the SPI module's receive buffer
           // register to the rData buffer.
           //
           DMA_configAddresses(DMA_CH6_BASE, rData,
                               (uint16_t *)(SPIB_BASE + SPI_O_RXBUF));
           DMA_configBurst(DMA_CH6_BASE, BURST, 0, 1);
           DMA_configTransfer(DMA_CH6_BASE, TRANSFER, 0, 1);
           DMA_configMode(DMA_CH6_BASE, DMA_TRIGGER_SPIBRX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch6 interrupts
           //
           DMA_setInterruptMode(DMA_CH6_BASE, DMA_INT_AT_END);
           DMA_enableInterrupt(DMA_CH6_BASE);
           DMA_enableTrigger(DMA_CH6_BASE);
    }
    

    Please check if all of the function calls in "SPI_DMA_Reset()" are necessary or if there is a more efficient way. I don't want to reset my entire controller.

  • Asad,

    Few modifications suggested :-

    1) Disabling and enabling SPI FIFO option will automatically flush SPI FIFO contents. So you don't need to reset TX FIFO and RX FIFO separately.

    2) DMA_initController() function provides a HARDRESET to DMA and would force you re-initialize DMA completely. You can replace DMA_initcontrller with soft reset using below command

    EALLOW;

    HWREGH(DMA_CH5_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;

    NOP; //One cycle mandatory delay required to access any other DMA register

    HWREGH(DMA_CH6_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;

    NOP; //One cycle mandatory delay required to access any other DMA register

    EDIS;

    This way you don't need to completely reconfigure DMA all over again.

    Modified code:

    void SPI_DMA_Reset()
    {
        //Disabling DMA transmission channel trigger
        DMA_disableTrigger(DMA_CH5_BASE);
        //Disabling DMA reception channel trigger
        DMA_disableTrigger(DMA_CH6_BASE);
        
        //Disabling SPI FIFOs
        SPI_disableFIFO(SPIB_BASE);
        //Re-enabling SPI FIFO
        SPI_enableFIFO(SPIB_BASE);
        
        SPI_setFIFOInterruptLevel(SPIB_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
        
        // DMA channel softreset
        EALLOW;

        HWREGH(DMA_CH5_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;

        NOP; //One cycle mandatory delay required to access any other DMA register

        HWREGH(DMA_CH6_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;

        NOP; //One cycle mandatory delay required to access any other DMA register

        EDIS;
        
        //Disabling DMA transmission channel trigger
        DMA_enableTrigger(DMA_CH5_BASE);
        //Disabling DMA reception channel trigger
        DMA_enableTrigger(DMA_CH6_BASE);
    }

    Regards,

    Manoj

  • Thanks a lot for the excellent reply. Let me implement it and provide you with the feedback.

  • Dear Manoj,

         I am facing a very abnormal issue with the DMA based SPI communication. The SPI is configured as slave with 8 level deep transmit and receive FIFOs. The DMA burst size is set to 8 with transfer size of 4 such that 32 words should be transferred for one complete DMA transfer. You can see from the code at the start of this thread that I have configured two DMA channels. DMA channel 5 is configured to transfer contents of sData (32 length uint16) array into the SPI transmit buffer:

    DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SPIB_BASE + SPI_O_TXBUF),
    sData);

    DMA channel 6 is configured to transfer data from SPI buffer into rData array (32 length uint16). 

    I have initialized sData array with fixed value (0x02) for testing purposes. However the master device (arduino in this case) is reading a one word shifted version of the transmitted data. I have connected logic analyzer to capture the scenario. The snapshot is shown below:

    In the above figure the data format is MOSI | MISO. Commas separate the 16 bit transfers. The MISO (TMS320F280025C) data is a word shifted version of the MOSI (Arduino data). I have another project in which the same same configuration is working perfectly i.e. MISO and MOSI are expected data from the respective devices but in my current project I am unable to implement the same logic. I have tried comparing both projects but cannot figure out any DMA or SPI configuration differences. Your help will be highly appreciated. I am attaching SPI and DMA configuration codes as below:

    #define FIFO_LVL    8               // FIFO interrupt level
    #define BURST       FIFO_LVL        // Each burst will empty the FIFO
    #define TRANSFER    4              // It will take 4 bursts of 8 to transfer
    uint16_t sData[32];                // Send data buffer for DMA transmission
    uint16_t rData[32];                // Receive data buffer for DMA reception
    
    
    // Place buffers in GSRAM so that DMA can access these
    #pragma DATA_SECTION(sData, "ramgs0");
    #pragma DATA_SECTION(rData, "ramgs0");
    void initDMA()
    {
        //
           // Initialize DMA
           //
           DMA_initController();
    
           //
           // Configure DMA Ch5 for TX. When there is enough space in the FIFO, data
           // will be transferred from the sData buffer to the SPI module's transmit
           // buffer register.
           //
           DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SPIB_BASE + SPI_O_TXBUF),
                               sData);
           DMA_configBurst(DMA_CH5_BASE, BURST, 1, 0);
           DMA_configTransfer(DMA_CH5_BASE, TRANSFER, 1, 0);
           DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_SPIBTX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch5 interrupts
           //
           DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_BEGINNING);
           DMA_enableInterrupt(DMA_CH5_BASE);
           DMA_enableTrigger(DMA_CH5_BASE);
    
           //
           // Configure DMA Ch6 for RX. When the FIFO contains at least 8 words to
           // read, data will be transferred from the SPI module's receive buffer
           // register to the rData buffer.
           //
           DMA_configAddresses(DMA_CH6_BASE, rData,
                               (uint16_t *)(SPIB_BASE + SPI_O_RXBUF));
           DMA_configBurst(DMA_CH6_BASE, BURST, 0, 1);
           DMA_configTransfer(DMA_CH6_BASE, TRANSFER, 0, 1);
           DMA_configMode(DMA_CH6_BASE, DMA_TRIGGER_SPIBRX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch6 interrupts
           //
           DMA_setInterruptMode(DMA_CH6_BASE, DMA_INT_AT_END);
           DMA_enableInterrupt(DMA_CH6_BASE);
           DMA_enableTrigger(DMA_CH6_BASE);
    }
    
    void SPI_init()
    {
    	
    	//mySPI0 initialization
    	SPI_disableModule(mySPI0_BASE);
    	SPI_setConfig(mySPI0_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA0,
    				  SPI_MODE_SLAVE, 1000000, 	16);
    	SPI_enableFIFO(mySPI0_BASE);
    	SPI_setFIFOInterruptLevel(mySPI0_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
    	SPI_disableLoopback(mySPI0_BASE);
    	SPI_setEmulationMode(mySPI0_BASE, SPI_EMULATION_FREE_RUN);
    	SPI_enableModule(mySPI0_BASE);
    }
    

  • Dear Manoj,

    After a lot of efforts and tries I have fixed the issue. I understand that there is some issue with the SPI driver generation of the sysconfig tool. In my last project  the SPI configurations were done manually but in the present code the code was generated with sysconfig tool. I have removed SPI peripheral from the sysconfig software section and copied the manual configurations code. Now the SPI is working as intended. I will provide you the feedback on DMA & SPI reset code tomorrow. Thanks again.

  • Dear Manoj,

        I have tested the SPI & DMA reset code as sent by you. I have observed that the SPI communication stops when the reset code is executed. If i reset the power of the controller then SPI communication starts again. I think there is something missing in the reset code. Kindly check.

  • Asad,

    I don't have awareness and initialization of your code. Did you try to understand why SPI transmission didn't start? Is DMA getting triggered?

    Only way to get to the bottom of this is to debug the problem.

    Regards,

    Manoj

  • Hi Manoj,

       Please find below the codes that initialize DMA and SPI for successful communication:

    void initSPIFIFO()
    {
        //Configuring pins
        // GPIO40 is the SPISIMOB clock pin.
        //
        GPIO_setPinConfig(GPIO_30_SPIB_SIMO);
        GPIO_setPadConfig(40, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(40, GPIO_QUAL_ASYNC);
    
        //
        // GPIO41 is the SPISOMIB.
        //
        GPIO_setPinConfig(GPIO_31_SPIB_SOMI);
        GPIO_setPadConfig(41, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(41, GPIO_QUAL_ASYNC);
    
        //
        // GPIO22 is the SPICLKB.
        //
        GPIO_setPinConfig(GPIO_28_SPIB_CLK);
        GPIO_setPadConfig(22, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(22, GPIO_QUAL_ASYNC);
    
        //
        // GPIO5 is the SPISTEA.
        //
        GPIO_setPinConfig(GPIO_29_SPIB_STE);
        GPIO_setPadConfig(5, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(5, GPIO_QUAL_ASYNC);
        //
        // Must put SPI into reset before configuring it
        //
        SPI_disableModule(SPIB_BASE);
    
        //
        // FIFO configuration
        //
        SPI_enableFIFO(SPIB_BASE);
        SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_RXFF | SPI_INT_TXFF);
        SPI_setFIFOInterruptLevel(SPIB_BASE, (SPI_TxFIFOLevel) FIFO_LVL,
                                  (SPI_RxFIFOLevel) FIFO_LVL);
    
        //
        // SPI configuration. Use a 500kHz SPICLK and 16-bit word size.
        //
        SPI_setConfig(SPIB_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1,
                      SPI_MODE_SLAVE, 1000000, 16);
        SPI_disableLoopback(SPIB_BASE);
        SPI_enableModule(SPIB_BASE);
    }
    
    //************************************************************************************
    //
    // Function to Configure DMA controller. Setup two channels, one for SPI transmission
    //and second for SPI reception.
    //
    //************************************************************************************
    void initDMA()
    {
        //
           // Initialize DMA
           //
           DMA_initController();
    
           //
           // Configure DMA Ch5 for TX. When there is enough space in the FIFO, data
           // will be transferred from the sData buffer to the SPI module's transmit
           // buffer register.
           //
           DMA_configAddresses(DMA_CH5_BASE, (uint16_t *)(SPIB_BASE + SPI_O_TXBUF),
                               sData);
           DMA_configBurst(DMA_CH5_BASE, BURST, 1, 0);
           DMA_configTransfer(DMA_CH5_BASE, TRANSFER, 1, 0);
           DMA_configMode(DMA_CH5_BASE, DMA_TRIGGER_SPIBTX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch5 interrupts
           //
           DMA_setInterruptMode(DMA_CH5_BASE, DMA_INT_AT_END);
           DMA_enableInterrupt(DMA_CH5_BASE);
           DMA_enableTrigger(DMA_CH5_BASE);
    
           //
           // Configure DMA Ch6 for RX. When the FIFO contains at least 8 words to
           // read, data will be transferred from the SPI module's receive buffer
           // register to the rData buffer.
           //
           DMA_configAddresses(DMA_CH6_BASE, rData,
                               (uint16_t *)(SPIB_BASE + SPI_O_RXBUF));
           DMA_configBurst(DMA_CH6_BASE, BURST, 0, 1);
           DMA_configTransfer(DMA_CH6_BASE, TRANSFER, 0, 1);
           DMA_configMode(DMA_CH6_BASE, DMA_TRIGGER_SPIBRX, DMA_CFG_ONESHOT_DISABLE |
                          DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT);
    
           //
           // Configure DMA Ch6 interrupts
           //
           DMA_setInterruptMode(DMA_CH6_BASE, DMA_INT_AT_END);
           DMA_enableInterrupt(DMA_CH6_BASE);
           DMA_enableTrigger(DMA_CH6_BASE);
    }

    The order of execution is that initDMA is called before initSPIFIFO. However the reset code as given below causes SPI communication to stop altogether. I am working to figure out the issue with this code. If you want to add some test points then please let me know.

    void SPI_DMA_Reset()
    {
        //Disabling DMA transmission channel trigger
        DMA_disableTrigger(DMA_CH5_BASE);
        //Disabling DMA reception channel trigger
        DMA_disableTrigger(DMA_CH6_BASE);
        
        //Disabling SPI FIFOs
        SPI_disableFIFO(SPIB_BASE);
        //Re-enabling SPI FIFO
        SPI_enableFIFO(SPIB_BASE);
        
        SPI_setFIFOInterruptLevel(SPIB_BASE, SPI_FIFO_TX8, SPI_FIFO_RX8);
        
        // DMA channel softreset
        EALLOW;
    
        HWREGH(DMA_CH5_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;
    
        NOP; //One cycle mandatory delay required to access any other DMA register
    
        HWREGH(DMA_CH6_BASE + DMA_O_CONTROL) |= DMA_CONTROL_SOFTRESET;
    
        NOP; //One cycle mandatory delay required to access any other DMA register
    
        EDIS;
        
        //Disabling DMA transmission channel trigger
        DMA_enableTrigger(DMA_CH5_BASE);
        //Disabling DMA reception channel trigger
        DMA_enableTrigger(DMA_CH6_BASE);
    }

  • 1) In your code, you have configured SPI TX FIFO interrupt to trigger DMA CH5. Did you check whether SPIFFTX.TXFFINT is being set?

    2) If SPIFFTX.TXFFINT = 1, did you check whether DMACH5.CONTROL.PERINTFLG is set

    3) In your code, you have configured SPI RX FIFO interrupt to trigger DMA CH6. Did you check whether SPIFFRX.RXFFINT is being set?

    4) If SPIFFTX.TXFFINT = 1, did you check whether DMACH6.CONTROL.PERINTFLG is set

  • Hi Manoj,

       I think we were forgetting to start the DMA channels. I have added following two lines to your reset code:

    DMA_startChannel(DMA_CH6_BASE);
    DMA_startChannel(DMA_CH5_BASE);

    The SPI communication now resumes. Now I need to verify if every thing resets as required.

  • Asad,

    Good to know the progress made. I'm glad things are moving in right direction.

    Regards,

    Manoj

  • I hope you were able to get this project up and running. Can I close this thread?

  • You can close the thread. I got involved in some other project related tasks and did not get a chance to verify if every thing is working as expected. However I am hopeful that we should be able to achieve the objective with your recommended settings.