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.

RE: MSP432P401R: DMA SPI corrupted RX

Thanks, this was very helpful. I am trying to read data from (MAX31855 ), so I connected the MAX31855 pins, SCK to pin 3.5, CS to pin 3.6, SO to pin 3.7 of the MSP432p401R EVM. I also changed in the example code as follows: 1. removed the value defined for dummyTx. 2. changed uint8_t rxBuffer[4]; as I need to read the buffer more to get data from MAX31855. When I run the code I see the interrupts happen as they should, thanks to your explanation. But the value in the RX buffer is not correct. I know my MAX31855 is working because I can test it just when I use a normal interrupt to read SPI without the DMA. I checked it with another code that I know it works.

This is the  code with my changes:

/* --COPYRIGHT--,BSD,BSD
 * Copyright (c) 2017, Texas Instruments Incorporated
 * All rights reserved.
 *
 * 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.
 * --/COPYRIGHT--*/
/*******************************************************************************
 * MSP432 DMA - Scatter-Gather between eUSCIB2 memory and eUSCIB1
 *
 * Description: In this code example, two software initiated DMA transfers are
 * setup and executed.  The scatter-gather transfers initiated from software
 * perform two tasks.  The first task is to read three bytes from the eUSCIB2
 * SPI and the second task is to transmit two bytes from the eUSCIB1 SPI.
 * In addition to the SPI communication the tasks also manage the chip select
 * via the port registers.
 * During the first interrupt a simple computation is performed to transfer
 * the information read to the information transmitted.
 *
 *              MSP432P401
 *             ------------------
 *         /|\|                  |
 *          | |                  |
 *          --|RST           P3.0|--> CS
 *            |     P3.5(eUSCIB2)|--> CLK --- connect to SCK of MAX31855
 *            |              P3.6|--> SIMO --- connect to CS of MAX31855
 *            |              P3.7|<-- SOMI --- connect to SO of MAX431855 
 *            |                  |
 *            |              P6.1|--> CS
 *            |     P6.3(eUSCIB1)|--> CLK
 *            |              P6.4|--> SIMO
 *            |              P6.5|<-- SOMI
 *
 ******************************************************************************/
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/devices/msp432p4xx/inc/msp.h>

#define RX_TASKS    9
#define TX_TASKS    7

/* SPI Configuration Parameter */
const eUSCI_SPI_MasterConfig spiMasterConfig_B2 =
{
    EUSCI_B_SPI_CLOCKSOURCE_SMCLK, 3000000, 1000000,
    EUSCI_B_SPI_MSB_FIRST,
    EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT,
    EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH,
    EUSCI_B_SPI_3PIN
};

/* SPI Configuration Parameter */
const eUSCI_SPI_MasterConfig spiMasterConfig_B1 =
{
    EUSCI_B_SPI_CLOCKSOURCE_SMCLK, 3000000, 1000000,
    EUSCI_B_SPI_MSB_FIRST,
    EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT,
    EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH, EUSCI_B_SPI_3PIN
};

/* 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[16];  // 8 primary and 8 alternate

uint8_t outputLow = 0;
uint8_t ADC_CS = BIT0;  /* P3.0 is Chip Select */
uint8_t DAC_CS = BIT1;  /* P6.1 is Chip Select */
uint8_t dummyTX = 0;
uint8_t dummyRX;
uint8_t rxBuffer[4];
uint8_t txBuffer[2];

/*
 * ADC_DMA Sequence: This sequence sets CS, reads data, and clears CS
 * The 'MEM' instructions are automatic while the 'PER' requires a
 * peripheral trigger, which is the EUSCI_B2_RX.  The trigger is configured
 * before the sequence is started.
 */
DMA_ControlTable spiAdcDmaSeq[RX_TASKS] =
{
    /* Task1, Dummy read RX buffer to clear IFG */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                UDMA_DST_INC_NONE, &dummyRX,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task2, Clear Chip select */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &outputLow,
                UDMA_DST_INC_NONE, &P3->OUT,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task3, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &dummyTX,
                UDMA_DST_INC_NONE, &EUSCI_B2_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task4, read RX buffer to clear IFG */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                UDMA_DST_INC_NONE, &rxBuffer[0],
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task5, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &dummyTX,
                UDMA_DST_INC_NONE, &EUSCI_B2_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task6, read RX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                UDMA_DST_INC_NONE, &rxBuffer[1],
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task7, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &dummyTX,
                UDMA_DST_INC_NONE, &EUSCI_B2_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task8, read RX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                UDMA_DST_INC_NONE, &rxBuffer[2],
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task9, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &dummyTX,
                UDMA_DST_INC_NONE, &EUSCI_B2_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task10, read RX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B2_SPI->RXBUF,
                UDMA_DST_INC_NONE, &rxBuffer[3],
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task 11, set GPIO, chip select */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &ADC_CS,
                UDMA_DST_INC_NONE, &P3->OUT,
                UDMA_ARB_4, UDMA_MODE_BASIC)
};

/*
 * DAC_DMA Sequence: This sequence sets CS, reads data, and clears CS
 * The 'MEM' instructions are automatic while the 'PER' requires a
 * peripheral trigger, which is the EUSCI_B1_TX. The trigger is configured
 * before the sequence is started.
 */
DMA_ControlTable spiDacDmaSeq[TX_TASKS] =
{
    /* Task1, Dummy read RX buffer to clear IFG */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B1_SPI->RXBUF,
                UDMA_DST_INC_NONE, &dummyRX,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task2, Clear Chip select P6.2 */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &outputLow,
                UDMA_DST_INC_NONE, &P6->OUT,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task3, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &txBuffer[0],
                UDMA_DST_INC_NONE, &EUSCI_B1_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task4, Dummy read RX buffer to clear IFG, wait for RXIFG trigger */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B1_SPI->RXBUF,
                UDMA_DST_INC_NONE, &dummyRX,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task 5, load TX buffer to initiate SPI */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &txBuffer[1],
                UDMA_DST_INC_NONE, &EUSCI_B1_SPI->TXBUF,
                UDMA_ARB_4, (UDMA_MODE_PER_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /*
     * Task 6, Dummy read RX buffer to clear IFG
     * This delay ensures that the chip select happens after the last byte is transmitted
     */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &EUSCI_B1_SPI->RXBUF,
                UDMA_DST_INC_NONE, &dummyRX,
                UDMA_ARB_4, (UDMA_MODE_MEM_SCATTER_GATHER+UDMA_MODE_ALT_SELECT)),
    /* Task 7, set GPIO, chip select */
    DMA_TaskStructEntry(1, UDMA_SIZE_8,
                UDMA_SRC_INC_NONE, &DAC_CS,
                UDMA_DST_INC_NONE, &P6->OUT,
                UDMA_ARB_4, UDMA_MODE_BASIC)
};

void main(void)
{
    /* Halt watchdog timer */
    MAP_WDT_A_holdTimer();
    /*
     * Configuring P1.1 as an input and enabling interrupts
     */
    MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1);
    MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    MAP_Interrupt_enableInterrupt(INT_PORT1);

    /*
     * DAC SPI
     * Configure CLK, MOSI & MISO for SPI0 (EUSCI_B1)
     * P6.3 UCB1CLK
     * P6.4 SIMO
     * P6.5 SOMI
     *
     */
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P6,
            GPIO_PIN3 | GPIO_PIN4, GPIO_PRIMARY_MODULE_FUNCTION);
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,
            GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);
    /*
     * ADC SPI
     * Configure CLK, MOSI & MISO for SPI0 (EUSCI_B2)
     * 3.5 CLK
     * 3.6 SIMO
     * 3.7 SOMI
     */
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3,
            GPIO_PIN5 | GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION);
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,
            GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Configure CS pin P3.0 */
    P3->OUT |= BIT0;
    P3->DIR |= BIT0;
    /* Configure CS pin P6.1 */
    P6->OUT |= BIT1;
    P6->DIR |= BIT1;

    /* Debug Port P1.0       */
    P1->DIR |= BIT0;
    /*
     * LDO, Vcore0 (default)
     * 24Mhz MCLK,
     * 3Mhz SMCLK
     */

    MAP_CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24);
    MAP_CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);
    MAP_CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_8);

    /* Configuring SPI module */
    MAP_SPI_initMaster(EUSCI_B2_BASE, &spiMasterConfig_B2);
    MAP_SPI_initMaster(EUSCI_B1_BASE, &spiMasterConfig_B1);

    /* Enable the SPI module */
    MAP_SPI_enableModule(EUSCI_B2_BASE);
    MAP_SPI_enableModule(EUSCI_B1_BASE);

    MAP_SPI_clearInterruptFlag(EUSCI_B2_BASE,EUSCI_B_SPI_RECEIVE_INTERRUPT);
    MAP_SPI_clearInterruptFlag(EUSCI_B1_BASE,EUSCI_B_SPI_RECEIVE_INTERRUPT);

    /* Configuring DMA module */
    MAP_DMA_enableModule();
    MAP_DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);

    /*
     * Assign DMA triggers
     * channel 2 to EUSCI_B1_TX0
     * channel 5 to EUSCI_B2_RX0
     */

    MAP_DMA_assignChannel(DMA_CH3_EUSCIB1RX0);

    MAP_DMA_assignChannel(DMA_CH5_EUSCIB2RX0);

    /* Enable DMA interrupt */
    /*
     * Debug
     * Change to Channel1 eUSCI_B2_RX2
     */
    MAP_DMA_assignInterrupt(INT_DMA_INT1, 5);  /* Channel 5 is the ADC (RX) */
    MAP_DMA_assignInterrupt(INT_DMA_INT2, 3);  /* Channel 3 is the DAC (TX) */

    while(1)
    {
        MAP_PCM_gotoLPM0();
    }
}

/* Completion interrupt for DMA */
void DMA_INT1_IRQHandler(void)
{
    MAP_DMA_disableChannel(5);
    MAP_DMA_disableInterrupt(INT_DMA_INT1);
    MAP_Interrupt_disableInterrupt(INT_DMA_INT1);
    MAP_SPI_clearInterruptFlag(EUSCI_B2_BASE,EUSCI_B_IFG_RXIFG0);
    MAP_DMA_clearInterruptFlag(5);
    /*
     * Translate ADC data to DAC data
     * 0 -> MSB (transmit first)
     * 1 -> LSB (transmit second)
     */
    txBuffer[0] = (rxBuffer[0] & 0x3) << 6;
    txBuffer[0] |= (rxBuffer[1] & 0xFC) >> 2;
    txBuffer[1] = (rxBuffer[1] & 0x3) << 6;
    txBuffer[1] |= (rxBuffer[2] & 0xFC) >> 2;

    MAP_SPI_clearInterruptFlag(EUSCI_B1_BASE,EUSCI_B_SPI_RECEIVE_INTERRUPT);
    MAP_DMA_setChannelScatterGather(DMA_CH3_EUSCIB1RX0,TX_TASKS,(void*)&spiDacDmaSeq[0],0);
    MAP_DMA_clearInterruptFlag(DMA_CH3_EUSCIB1RX0 & 0x0F);
    /* Assigning/Enabling Interrupts */
    MAP_DMA_enableInterrupt(INT_DMA_INT2);
    MAP_Interrupt_enableInterrupt(INT_DMA_INT2);
    MAP_DMA_enableChannel(3);
    EUSCI_B1_SPI->IFG |= EUSCI_B_IFG_RXIFG0;
}

void DMA_INT2_IRQHandler(void)
{
    MAP_DMA_disableChannel(3);
    MAP_DMA_disableInterrupt(INT_DMA_INT2);
    MAP_Interrupt_disableInterrupt(INT_DMA_INT2);
    MAP_SPI_clearInterruptFlag(EUSCI_B1_BASE,EUSCI_B_IFG_RXIFG0);
    MAP_DMA_clearInterruptFlag(3);
    P1->OUT ^= BIT0;
}

void PORT1_IRQHandler(void)
{
    uint32_t status;

    status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);

    /* Toggling the output on the LED */
    if(status & GPIO_PIN1)
    {
        rxBuffer[0] = 1;
        rxBuffer[1] = 2;
        rxBuffer[2] = 3;
        rxBuffer[3] = 4;

        txBuffer[0] = 5;
        txBuffer[1] = 6;

        /*
         * Start SPI read
         */
        while(status & GPIO_PIN1)
        {
            status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
            MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
        }
        /*
         * Peripheral trigger.  Memory Scatter Gather
         */
        MAP_DMA_setChannelScatterGather(DMA_CH5_EUSCIB2RX0,RX_TASKS,(void*)&spiAdcDmaSeq[0],0);
        MAP_DMA_clearInterruptFlag(DMA_CH5_EUSCIB2RX0 & 0x0F);

        /* Assigning/Enabling Interrupts */
        MAP_DMA_enableInterrupt(INT_DMA_INT1);
        MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
        MAP_DMA_enableChannel(5);

        /*
         * The DMA channel5 is set to trigger off of theEUSCIB0RX IFG.  This
         * did not really happen but is forced manually to start the
         * scatter-gather sequence.  Because the setting is 'memory'
         * scatter-gather all triggers (transitions) from primary to
         * auxiliary actions will be automatic.  The auxiliary action triggers
         * are defined in the task list.
         */
        EUSCI_B2_SPI->IFG |= EUSCI_B_IFG_RXIFG0;
    }
}

**Attention** This is a public forum