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.

MSP432P401R: SPI DMA I/O

Part Number: MSP432P401R

I'm trying to use DMA to read and write to an SPI peripheral on the MSP432 launchpad. I'm able to write data just fine, but the read isn't coming in correctly. Below find a screenshot of the signals:

I'm writing two 32 bit variables which I've just set to dummy values {0xAABBCCDD, 0x11223344} for now. This correponds to 0xDDCCBBAA44332211 on the MOSI line, which you can see above

My slave (in this example) is returning 0xFF69D700FF69D7A0 on DOUT, but my read buffer returns {0x69FFD769, 0x000000D7}. It seems the read is out of sync with the write. Below please find my code, I'm not sure what the issue is. I took much of the code from this ticket: https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/547391?tisearch=e2e-sitesearch&keymatch=msp432

/*************************
 * Libraries
 *************************/

/* DriverLib Includes */
#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
#include "AIC23B.h"

/************************
 * Peripherals
 ************************/

/* DMA Control Table */

#if defined(__TI_COMPILER_VERSION__)
#pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024)
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma data_alignment=1024
#elif defined(__GNUC__)
__attribute__ ((aligned (1024)))
#elif defined(__CC_ARM)
__align(1024)
#endif
static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32];

/************************************
 * Global variables
 ************************************/

//Digital audio buffers, read/wrote by DMA
uint32_t AudioDataIn[2], AudioDataOut[2]={0xAABBCCDD, 0x11223344};

//Data ready flag, to start audio processing
bool AudioDataReady=false;

/***********************************
 * Main program
 ***********************************/

int main(void)
{
    WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer

    //Initialize Slave
    initAic23b();

    //Initialize SPI
    //P3.5 CLK, P3.6 SIMO, P3.7 SOMI
    P3->SEL0 |= GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7;
    P3->SEL1 &= ~(GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7);
    EUSCI_B_CMSIS(EUSCI_B2_BASE)->CTLW0 |= EUSCI_B_CTLW0_SWRST; // Hold USCI in Reset state
    // UCB Settings:
    // Master
    // 3 Pin SPI
    // 8 data bits
    // Clock Source: SMCLK
    // Bit Rate Divider
    // No Modulation
    // MSB First
    // Clock Phase - UCCKPL = 0, UCCKPH = 1
    EUSCI_B_CMSIS(EUSCI_B2_BASE)->CTLW0 = EUSCI_B_CTLW0_CKPH | EUSCI_B_CTLW0_MSB |
            EUSCI_B_CTLW0_MST | EUSCI_B_CTLW0_MODE_0 | EUSCI_B_CTLW0_SYNC | EUSCI_B_CTLW0_UCSSEL_2 | EUSCI_B_CTLW0_SWRST;
    //Set speed to desired frequency
    EUSCI_B_CMSIS(EUSCI_B2_BASE)->BRW = (uint16_t)(CS_getSMCLK()/1000000);
    EUSCI_B_CMSIS(EUSCI_B2_BASE)->CTLW0 &= ~EUSCI_B_CTLW0_SWRST; // Release reset state

    /****************************************************
     * DMA (coupled with SPI to make I2S)
     ****************************************************/

    __enable_irq();

    //Enable DMA module
    DMA_enableModule();

    DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);

    //Assign channel 4 to EUSCI_B2_TX, channel 5 to EUSCI_B2_RX
    DMA_assignChannel(DMA_CH4_EUSCIB2TX0);
    DMA_assignChannel(DMA_CH5_EUSCIB2RX0);

    //Set TX transfer
    DMA_setChannelControl(DMA_CH4_EUSCIB2TX0 | UDMA_PRI_SELECT,
        UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);

    DMA_setChannelTransfer(DMA_CH4_EUSCIB2TX0 | UDMA_PRI_SELECT,
        UDMA_MODE_BASIC, AudioDataOut,
        (void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B2_BASE),
        8);

    //Set RX transfer
    DMA_setChannelControl(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
        UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);

    DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
        UDMA_MODE_BASIC,
        (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
        AudioDataIn,
        8);

    //Assign DMA interrupt : INT1 to TX channel
    DMA_assignInterrupt(INT_DMA_INT1, 4);

    //Enable interrupt
    Interrupt_enableInterrupt(INT_DMA_INT1);

    DMA_enableInterrupt(INT_DMA_INT1);

    //Everything is set up, we can enable the two DMA channels
    DMA_enableChannel(5);
    DMA_enableChannel(4);

    /* Interrupts activation */
    Interrupt_enableMaster();

    /* Main program loop */
    while(1)
    {
        if(AudioDataReady==true) {
            //Reset flag
            AudioDataReady=false;
            //The data is not being used yet, I'm setting a breakpoint here to check the values

            //Start another DMA transfer. This will eventually be done via timer
            //Set TX transfer
            DMA_setChannelControl(DMA_CH4_EUSCIB2TX0 | UDMA_PRI_SELECT,
                UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);

            DMA_setChannelTransfer(DMA_CH4_EUSCIB2TX0 | UDMA_PRI_SELECT,
                UDMA_MODE_BASIC, AudioDataOut,
                (void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B2_BASE),
                8);

            //Set RX transfer
            DMA_setChannelControl(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
                UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);

            DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
                UDMA_MODE_BASIC,
                (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
                AudioDataIn,
                8);

            //Enable interrupt
            Interrupt_enableInterrupt(INT_DMA_INT1);

            DMA_enableInterrupt(INT_DMA_INT1);

            //Everything is set up, we can enable the two DMA channels
            DMA_enableChannel(5);
            DMA_enableChannel(4);

        }
    }
}


/** Interrupt routines */

/* Completion interrupt for DMA */
void DMA_INT1_IRQHandler(void)
{
    //Clear interrupt flag
    DMA_clearInterruptFlag(4);
    //Set flag for audio processing
    AudioDataReady=true;
}

  • Yes, I did. I ended up getting this to work after upping the cpu frequency from 3MHz to 48MHz. I think part of the problem is that since DMA triggers on the tx flag (after the tx buffer gets flushed out but not necessarily before the data is transmitted), DMA is writing the next byte before the rx buffer has been read. I guess running at 48MHz instead gets rid of this issue because it's much faster and I can read the rx buffer before DMA triggers the next write. I tried triggering DMA on the rx flag instead (changing the 4 to a 5 on lines 106 and 168), but when I do that the DMA interrupt never gets triggered. Right now I'm just going to use a 48MHz clock and live with the potentially incorrect code because it works for my application. However, if anyone knows how to fix this issue I'm still open to suggestions.

  • Yes, I think you've characterized it. In the steady state, the RXIFG and TXIFG trigger simultaneously. With the SPI running very close to MCLK speed (the case when running at 3MHz) the DMA  may not have time to service both; if it happens to do the TXIFG first the RX side can overrun.

    When I do this, I try to make the RX side higher priority than the TX side (the TX side can't overrun). Speeding MCLK way up without speeding up the SPI (as you have done) will also make this disappear, since the DMA then has plenty of time to do its work.

    Also keep in mind that the TX side DMA will complete two byte-times before the RX side. Right now I think the interrupt overhead is saving you, but I suggest you interrupt on RX side (DMA) completion instead.

    [Edit: I just noticed you already tried interrupting on RX-side completion. Try it again now that the RX side isn't overrunning.]

**Attention** This is a public forum