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: DMAE0 External Trigger by external ADC data ready -> SPI Starts

Part Number: MSP432P401R

Hi,

i am trying to get an external DMA trigger to read ADC data with SPI.

So this is what i am trying to do. I am using the ADS131A02 and want to read 32Bit values via SPI on my MSP432.

The DRDY Pin from ADS131A02 is connected to the P7.0 from MSP432. This port is configured as PM_DMAE0.

Every time the ADC has a new value the external DMA should trigger the DMA to write to the SPI TX buffer and after 512 transactions, the DMA RX should fired an interrupt to wake the MSP432.

At the moment the DMAE0 is working and it is triggering the DMA TX that writes values to SPI TX buffer. This is only working one time and the next DMAE0 interrupt are ignored.

This is my code:

#include "ADS131A02.h"

#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* DMA Control Table */
#ifdef ewarm
#pragma data_alignment=256
#else
#pragma DATA_ALIGN(controlTable, 256)
#endif
uint8_t controlTable[256];
uint8_t DMA_recBuffer[9];
uint8_t DMA_sendBuffer[9];
#define SAMPLE_LENGTH 512
float hann[SAMPLE_LENGTH];
int8_t data_array1[SAMPLE_LENGTH];
int8_t data_array2[SAMPLE_LENGTH];
uint8_t data_array[4]={0x00,0x00,0x00,0x00};
volatile int switch_data = 0;

void ADS131A02_SPI_Setup(void)
{
    GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN0);
    GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN6);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P7, GPIO_PIN0);

    GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN0);       // CS Disable
    GPIO_setOutputHighOnPin(GPIO_PORT_P3, GPIO_PIN6);       // Reset Disable

    // SPI Master Configuration Parameter
    const eUSCI_SPI_MasterConfig spiMasterConfig =
    {
            EUSCI_A_SPI_CLOCKSOURCE_SMCLK,                              // SMCLK Clock Source
            48000000,                                                   // SMCLK = HFXT = 48Mhz
            24000000,                                                   // SPICLK =12000000
            EUSCI_A_SPI_MSB_FIRST,                                      // MSB First
            EUSCI_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT,      // Phase EUSCI_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT / EUSCI_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT
            EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW,                   // High polarity
            EUSCI_A_SPI_3PIN

    };

     /* Selecting P1.5 P1.6 and P1.7 in SPI mode */
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN5 | GPIO_PIN6  | GPIO_PIN7 , GPIO_PRIMARY_MODULE_FUNCTION);

    // Selecting pin 7.0 in DMAE0
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Configuring SPI in 3wire master mode */
    SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);
    SPI_enableModule(EUSCI_B0_BASE);

    /* Enable Interrupt */
    GPIO_clearInterruptFlag(GPIO_PORT_P7, GPIO_PIN0);
    GPIO_enableInterrupt(GPIO_PORT_P7, GPIO_PIN0);
    GPIO_interruptEdgeSelect(GPIO_PORT_P7, GPIO_PIN0,GPIO_LOW_TO_HIGH_TRANSITION);
    //Interrupt_enableInterrupt(INT_PORT7);
    SPI_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT);

}


void ADS131A02_DMASetup(void)
{

    //Assigning DMA to SPI Channels
    DMA_enableModule();
    DMA_setControlBase(controlTable);


    DMA_assignChannel(DMA_CH0_EUSCIB0TX0);
    DMA_assignChannel(DMA_CH1_EUSCIB0RX0);
    DMA_assignChannel(DMA_CH6_EXTERNALPIN);

    DMA_disableChannelAttribute(DMA_CH6_EXTERNALPIN,UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |UDMA_ATTR_HIGH_PRIORITY |UDMA_ATTR_REQMASK);

    // Setup the TX transfer characteristics & buffers
    DMA_setChannelControl( DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1);

    DMA_setChannelControl (DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),512);

    DMA_setChannelControl (DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_MODE_PINGPONG,(void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array1,512);

    DMA_setChannelControl (DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_MODE_PINGPONG,(void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array2,512);

    DMA_assignInterrupt(DMA_INT1, 1);
    DMA_clearInterruptFlag(INT_DMA_INT1);
    DMA_clearInterruptFlag(1);

    Interrupt_enableInterrupt(DMA_INT1);
    Interrupt_enableMaster();
    DMA_enableChannel(6);
    DMA_enableChannel(0);
    DMA_enableChannel(1);
}


void DMA_INT1_IRQHandler(void)
{
    DMA_clearInterruptFlag(1);
    /* Switch between primary and alternate bufferes with DMA's PingPong mode */
    if (DMA_getChannelAttribute(1) & UDMA_ATTR_ALTSELECT)
    {
        DMA_setChannelControl(UDMA_PRI_SELECT  | DMA_CH1_EUSCIB0RX0,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
        DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH1_EUSCIB0RX0,UDMA_MODE_PINGPONG, (void*)MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array1, SAMPLE_LENGTH);
        switch_data = 1;
    }
    else
    {
        DMA_setChannelControl(UDMA_ALT_SELECT | DMA_CH1_EUSCIB0RX0,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
        DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH1_EUSCIB0RX0,UDMA_MODE_PINGPONG, (void*)MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array2, SAMPLE_LENGTH);
        switch_data = 0;
    }
}

DMAE0 is triggering the SPI TX and SPI will write 511 times to the ADC. I am getting the DMA RX interrupt with 512 values and i change then the pingpong buffer.

After that nothing else happens. 

If i change the SPI TX from 512 to 4 Bytes, the SPI send only 4 Bytes and nothing else happens. Why is the TX DMA not writing to the SPI TX after a new DMAE0 trigger has occured?

Do i have to reconfigure the DMA TX again? 

  • Hello MIchael,

    In the function for the DMA setup, you are configuring the Primary channel twice with the API's DMA_setChannelControl and DMA_setChannelTransfer. Instead you need to configure one time for the Primary channel and one time for the Alternate channel.

    DMA_setChannelControl (DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH1_EUSCIB0RX0 | UDMA_PRI_SELECT,UDMA_MODE_PINGPONG,(void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array1,512);

    DMA_setChannelControl (DMA_CH1_EUSCIB0RX0 | UDMA_ALT_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    DMA_setChannelTransfer(DMA_CH1_EUSCIB0RX0 | UDMA_ALT_SELECT,UDMA_MODE_PINGPONG,(void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B0_BASE),data_array2,512);
  • I don't have my materials here (and I don't speak driverlib very well) but: Does your DMAE0 just enable the SPI (Tx) DMA, or does it write directly into the (SPI) TXBUF?

    I ask since I'm pretty sure the DMA "eats" the TXIFG that drives it forward, so it may be left at 0 after the DMA sequence. Just enabling the SPI DMA won't start (the 2nd time) in this case, but writing directly into TXBUF will re-start the cascade. You may want to peek at Registers->USCIB0->UCBIFG when you get into this state.
  • Hi Amit,

    thanks that was it. But this configuration sends really 512 Bytes to read to the ADC. I only need 4 so i change this:

    // Setup the TX transfer characteristics & buffers 
    DMA_setChannelControl( DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1); 
    DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1); 
    DMA_setChannelControl (DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1); 
    DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),3);

    Now the problem is that everytime the DMAE0 gets trigger 4 Bytes are send by SPI TX and i have to reconfigure DMA again. So i implemented an interrupt like this to reconfigure DMA every time TX is done:

    void DMA_INT2_IRQHandler(void)
    {
        ADS131A02_CS_Enable();
        DMA_clearInterruptFlag(INT_DMA_INT2);
    
        // Setup the TX transfer characteristics & buffers
        DMA_setChannelControl( DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);
        DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE), 1);
    
        DMA_setChannelControl (DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
        DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,UDMA_MODE_BASIC, data_array,(void *) MAP_SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),3);
    
        DMA_enableChannel(0);
        DMA_enableChannel(6);
    }
    

    So is there a way to avoid this or is this the only way?

  • Hello Michael,

    There is a more complicated method of Peripheral Scatter Gather that can re-initialize itself. However the problem with the same method is there would not be any interrupt generated directly. You would need to toggle an IO via the DMA to generate an IO interrupt.

    Please see the following example in the SDK for MSP432P4

    C:\ti\simplelink_msp432p4_sdk_2_20_00_12\examples\nortos\MSP_EXP432P401R\demos\cmsis_dsplib_ulp
  • Hi Amit,

    the external triger DMAE0 is not really working to what i want to achieve.
    I move now to GPIO interrupt and there i set my DMA to TX.
  • Hello Michael,

    Can you please share the configuration you are doing for the external trigger for DMA.
  • Hi Amit,

    the source code is in the first question.
    External DMA only send out one TX and it triggered DMA SPI TX to send more.
    This is taking too long. Doing a simple GPIO as input interrupt to set /CS and enable SPI TX DMA is quicker.
    I need to read 48kHz samples and the MSP432 couldnt handle it with external DMAE0.
  • Michael,
    I think the issue you are seeing is explained here: e2e.ti.com/.../1888708 . The GPIO sounds like the better implementation along with the use of the timer capture.

    Regards,
    Chris

**Attention** This is a public forum