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: Best Practices hitting the 1 msps rate over 3 channels using DMA

Part Number: MSP432P401R

My Customer is having trouble hitting the 1 msps (actually needs 600khz) rate over 3 channels using the DMA.  

I’m working to get the ADC14 running at 200 kSPS per channel, alternating between 3 channels for a total of 600 kSPS. I’m running at 48 MHz, have the ADC samples being triggered by TIMER_A, cycling between 3 analog channels. I’m close to 600 kSPS rate using just using ADC interrupts & no DMA, but am missing samples, as expected. I started this way (without DMA) to get my input lines, clocks, & ADC doing what I want. Now, I’m trying to fold DMA into the mix.

I need DMA to handle 2 transfer scenarios:  (1) Directly into the SPI TX, and (2) Directly into a local RAM array (for pre-processing steps before SPI transfer).

I have scoured the Project|Examples|Resource Explorer, and don’t see anything this complex. Are there other sources of examples?

Apparently, there’s only 1 DMA channel that supports being triggered by the ADC (DMA Channel 7). If I’m sampling 3 channels (A0-A2), the DMA gets triggered after all 3 are scanned, so 3 transfers occur and the DMA interrupt goes off. Then, in the DMA interrupt, I have to update the destination address to move 3 entries down. This takes too long, so am missing samples.

What speed are you running the processor?     [48 MHz]

What resolution are you running the ADC?       [14-Bit]

What is your ADC14CLK?  [24 MHz]

What is your ADDC 14PDIV? [I don’t know what this is; Using ADC_DIVIDER_2) 

What clock Source are you using?  [MCLK]

SLAA707.pdf appeared relevant, but upon review was not useful to the customer.

Code available on request for internal review.

Thanks! 

Blake

 

  • Blake,
    A couple of things about the comments. First, since the ADC divider is being used this means that the 1MSPS will not be achievable. The number of clocks required for just the conversion alone (assuming 14-bit resolution) is 16 clocks so the ADC (16clocks/12Mhz) would not support a 1us (1MSPS) timing. Second, the ADC needs to be in either the extended sample mode with the manual trigger or the pulse sample mode with the automatic trigger. If you are using the pulse sample mode with manual trigger there are additional clock cycles required for synchronization which will prohibit 1MSPS.

    How much data is being collected at a time? Is this a continuous stream of data or is it collected in bursts? I can put together an example, but any additional context will help.

    Thanks,
    Chris
  • Hi Chris,

    Thanks for the quick response.

    The customer replies:

    I use the divide by 2 to get the 48 MHz clock down to what I ~think~ is the maximum ADC14 clock rate (24 MHz). What is the maximum ADC14 clock rate? Does it have to be over-clocked to get the 1MSPS?

    Pulse sample mode with automatic trigger sounds best for us.

    How much data is being collected at a time? Is this a continuous stream of data or is it collected in bursts? I can put together an example, but any additional context will help.

    There are 2 scenarios:  (1) In one “Monitor” mode, we need a continuous stream of data dumped over SPI. In this mode, samples from 3 channels must be taken at 200 kHz/channel, and dumped in real-time over a SPI bus; (2) In “Run” mode, a few baud-worth of data (800 uS/baud) will be collected at 600 kHz overall (200 kHz/3 channels) in bursts. This’ll be maybe a couple thousand samples. Ping-pong / double-buffering may work for this. Alternative, we might be able sample to a single buffer, process, and do it again.

    14-bit resolution is very much desired. This is a battery-powered device, so using DMA to maximize sleep time is very desirable.

    Thanks!  Blake

  • Blake,

        Technically you are not supposed to feed the ADC anything greater than 25Mhz (per datasheet http://www.ti.com/lit/ds/symlink/msp432p401r.pdf#page=65 ).  The ADCOSC is an internal 25Mhz oscillator intended for the ADC.  There are some subtleties about supplying the 24Mhz or 48Mhz and then dividing down within the peripheral, so I typically recommend just using the ADCOSC or a 24Mhz signal from SMCLK when using an HFXT.

        I have not been able to put together examples for both of the use cases, but hopefully the attached will give some ideas.  In this example I am running the ADC at 1MSPS and it moves through the sequence of three channels so that the effective sample rate of each is ~333Khz.  Also, I have not tested this in the lab, but just verified the timings.  Please let me know if you see any issues and I will try to get into the lab with this.

    /* --COPYRIGHT--,BSD_EX
     * Copyright (c) 2013, 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--
     */
    //******************************************************************************
    /*
     * ADC_DAC_04.c
     *
     * Timer (1MHz) Triggered sequence of conversions (ADC14 4,5,6), where each
     * conversion in the sequence is triggered manually and the sample-hold time
     * is a function of the negative duty cycle.
     * Timing of ADC14 in pulse-sample mode:
     *     Sample-hold: defined by timer 5 cycles (timer source is TACLK, 24Mhz)
     *     Sync: 2 cycle (25Mhz)
     *     Conversion: 16 cycles (25Mhz)
     *     Mem Transfer: 1 cycle (25Mhz)
     *
     * The ADC triggers the DMA which moves the data from ADCMEM to the array
     * memory.
     *
     */
    
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    #include <stdio.h>
    
    /* Standard Includes */
    #include <stdint.h>
    #include <string.h>
    
    //#define WORKAROUND
    
    /* Clock system frequencies */
    #define MCLK_FREQUENCY      48000000
    #define SMCLK_FREQUENCY     24000000
    
    #define NUMBER_OF_SAMPLES       32
    #define CONVERSIONS_PER_SAMPLE  3
    
    #define ADC_TASKS               34
    
    uint32_t dataSet_01[NUMBER_OF_SAMPLES][CONVERSIONS_PER_SAMPLE];
    uint32_t dataSet_02[NUMBER_OF_SAMPLES][CONVERSIONS_PER_SAMPLE];
    
    uint16_t sampleCnt;
    
    
    /* 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
    
    volatile uint8_t switch_data = 0;
    
    const uint8_t forceP1B2ISR = 0x04;  // P1.2 is high
    const uint8_t forceP1B3ISR = 0x08;  // P1.3 is high
    /*
     * TA0 PWM Configuration
     * Timer used to Trigger ADC
     * SMCLK -> SMCLK_FREQUENCY
     * Sample Frequency -> SAMPLE_FREQUENCY
     */
    const Timer_A_PWMConfig pwmConfig =
    {
            TIMER_A_CLOCKSOURCE_SMCLK,              // 24Mhz
            TIMER_A_CLOCKSOURCE_DIVIDER_1,          //
            23,                                     // 23+1 period,
            TIMER_A_CAPTURECOMPARE_REGISTER_1,      // Duty Cycle Defined in CCR1
            TIMER_A_OUTPUTMODE_SET_RESET,
            19                                      // Set on 19 and reset on 0
    };
    
    /* SPI Master Configuration Parameter */
    const eUSCI_SPI_MasterConfig spiMasterConfig =
    {
            EUSCI_B_SPI_CLOCKSOURCE_SMCLK,             // SMCLK Clock Source
            SMCLK_FREQUENCY,                           // SMCLK = DCO = 24MHZ
            12000000,                                  // SPICLK = 12Mhz
            EUSCI_B_SPI_MSB_FIRST,                     // MSB First
            EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT,    // Phase
            EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH, // High polarity
            EUSCI_B_SPI_3PIN                           // 3Wire SPI Mode
    };
    /* DMA Task Structure */
    DMA_ControlTable pingTask,pongTask;
    /*
     *
     */
    const DMA_ControlTable AdcDmaSeq_01[ADC_TASKS] =
    {
        /*
         * Task1,
         */
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[0][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[1][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[2][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[3][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[4][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[5][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[6][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[7][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[8][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[9][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[10][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[11][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[12][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[13][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[14][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[15][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[16][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[17][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[18][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[19][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[20][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[21][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[22][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[23][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[24][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[25][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[26][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[27][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[28][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[29][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[30][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_01[31][0],
                    UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
    
       DMA_TaskStructEntry(1, UDMA_SIZE_8,
                     UDMA_SRC_INC_8, (void *)&forceP1B2ISR,
                     UDMA_DST_INC_8, (void *)&P1->OUT,
                     UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
        DMA_TaskStructEntry(4, UDMA_SIZE_32,
                    UDMA_SRC_INC_32, (void *)&pongTask,
                    UDMA_DST_INC_32, (void *)&MSP_EXP432P401RLP_DMAControlTable[7],
                    UDMA_ARB_4, UDMA_MODE_MEM_SCATTER_GATHER)
    };
    
    const DMA_ControlTable AdcDmaSeq_02[ADC_TASKS] =
    {
        /*
         * Task1,
         */
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[0][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[1][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[2][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[3][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[4][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[5][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[6][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[7][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[8][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[9][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[10][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[11][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[12][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[13][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[14][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[15][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[16][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[17][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[18][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[19][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[20][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[21][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[22][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[23][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[24][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[25][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[26][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[27][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[28][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[29][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[30][0],
                    UDMA_ARB_1, UDMA_MODE_PER_SCATTER_GATHER),
        DMA_TaskStructEntry(3, UDMA_SIZE_32,
                    UDMA_SRC_INC_32,(void*)&ADC14->MEM[0],
                    UDMA_DST_INC_32, &dataSet_02[31][0],
                    UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
    
        DMA_TaskStructEntry(1, UDMA_SIZE_8,
                    UDMA_SRC_INC_8, (void *)&forceP1B3ISR,
                    UDMA_DST_INC_8, (void *)&P1->OUT,
                    UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER),
        DMA_TaskStructEntry(4, UDMA_SIZE_32,
                    UDMA_SRC_INC_32, (void *)&pingTask,
                    UDMA_DST_INC_32, (void *)&MSP_EXP432P401RLP_DMAControlTable[7],
                    UDMA_ARB_4, UDMA_MODE_MEM_SCATTER_GATHER)
    };
    
    uint16_t adcIndex;
    bool dataSet0Ready;
    
    int main(void)
    {
        volatile uint16_t ii,jj;
        /* Halting WDT  */
        MAP_WDT_A_holdTimer();
    
        /*
         * Revision C silicon supports wait states of 1 at 48Mhz
         */
        MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
        MAP_FlashCtl_setWaitState(FLASH_BANK0, 1);
        MAP_FlashCtl_setWaitState(FLASH_BANK1, 1);
    
        /*
         * Setting up clocks
         * MCLK = MCLK = 48MHz
         * SMCLK = MCLK/2 = 24Mhz
         * ACLK = REFO = 32Khz
         */
        MAP_CS_setDCOFrequency(48000000);
        MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
        MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_2);
        MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
    
        /*
         * Debug,
         * output TA0.1
         */
        P2->DIR |= (BIT4);
        P2->SEL0 |= BIT4;
        P2->SEL1 &= ~BIT4;
    
        /* Configuring P1.0 as output for debug */
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
    
        /*
         * Non-conventional usage of P1.2 and P1.3 as 'internal' interrupt
         * triggered from DMA.
         */
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, (GPIO_PIN2 + GPIO_PIN3));
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, (GPIO_PIN2 + GPIO_PIN3));
        MAP_GPIO_interruptEdgeSelect(GPIO_PORT_P1,(GPIO_PIN2 + GPIO_PIN3),
                                        GPIO_LOW_TO_HIGH_TRANSITION);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1,(GPIO_PIN2 + GPIO_PIN3));
        MAP_GPIO_enableInterrupt(GPIO_PORT_P1,(GPIO_PIN2 + GPIO_PIN3));
    
        /* Selecting P1.5 P1.6 and P1.7 in SPI mode */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
    
        /* Configure P2.0, P2.1, and P2.2 for debug*/
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN0|GPIO_PIN1|GPIO_PIN2);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN0|GPIO_PIN1|GPIO_PIN2);
    
        /* Configuring GPIOs for Analog In P4.5,4.6,4.7 */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,
                GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_TERTIARY_MODULE_FUNCTION);
    
        /*
         * Initializing ADC (ADCOSC/1/1)
         * 25Mhz
         */
        MAP_ADC14_enableModule();
        MAP_ADC14_initModule(ADC_CLOCKSOURCE_ADCOSC, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
                0);
    
        /* Configuring ADC Memory (ADC_MEM0 - ADC_MEM4 (A4 - A6)  with repeat)
         * with internal 2.5v reference */
        MAP_ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM2, true);
        MAP_ADC14_configureConversionMemory(ADC_MEM0,
                ADC_VREFPOS_AVCC_VREFNEG_VSS,
                ADC_INPUT_A4, ADC_NONDIFFERENTIAL_INPUTS);
        MAP_ADC14_configureConversionMemory(ADC_MEM1,
                ADC_VREFPOS_AVCC_VREFNEG_VSS,
                ADC_INPUT_A5, ADC_NONDIFFERENTIAL_INPUTS);
        MAP_ADC14_configureConversionMemory(ADC_MEM2,
                ADC_VREFPOS_AVCC_VREFNEG_VSS,
                ADC_INPUT_A6, ADC_NONDIFFERENTIAL_INPUTS);
        /*
         * Configuring the sample trigger to be sourced from Timer_A0 CCR1
         * and setting it to automatic iteration after it is triggered
         */
        MAP_ADC14_setSampleHoldTrigger(ADC_TRIGGER_SOURCE1, false);
        /*
         * Disable sample timer (default), use pulse mode.
         */
        MAP_ADC14_disableSampleTimer();
        MAP_ADC14_enableConversion();
    
        /* Configuring DMA module */
        MAP_DMA_enableModule();
        MAP_DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);
    
         /* Disabling channel attributes */
        MAP_DMA_disableChannelAttribute(DMA_CH7_ADC14,
                                     UDMA_ATTR_USEBURST |
                                     UDMA_ATTR_HIGH_PRIORITY |
                                     UDMA_ATTR_REQMASK);
    
        MAP_DMA_setChannelScatterGather(DMA_CH7_ADC14,ADC_TASKS,(void*)&AdcDmaSeq_02[0],true);
        pongTask = MSP_EXP432P401RLP_DMAControlTable[7];
    
        MAP_DMA_setChannelScatterGather(DMA_CH7_ADC14,ADC_TASKS,(void*)&AdcDmaSeq_01[0],true);
        pingTask = MSP_EXP432P401RLP_DMAControlTable[7];
    
        MAP_DMA_assignChannel(DMA_CH7_ADC14);
        MAP_DMA_enableChannel(7);
    
        /*
         *
         */
        /* Configuring SPI in 3wire master mode */
        MAP_SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);
    
        /* Enable SPI module */
        MAP_SPI_enableModule(EUSCI_B0_BASE);
    
        MAP_Interrupt_disableSleepOnIsrExit();
    
        MAP_Interrupt_enableInterrupt(INT_PORT1);
        MAP_Interrupt_enableMaster();
    
        /*
         * Starting the Timer
         * Configuring Timer_A in continuous mode and sourced from SMCLK
         */
        MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwmConfig);
    
    
        while(1)
        {
            MAP_PCM_gotoLPM0();
    //        Debug
    //        P2->OUT |= BIT0;
            if(dataSet0Ready)
            {
                /*
                 *
                 */
                for(ii=0;ii<NUMBER_OF_SAMPLES;ii++)
                {
                    for(jj=0;jj<CONVERSIONS_PER_SAMPLE;jj++)
                    {
                        while(!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));
                        EUSCI_B0->TXBUF = (uint8_t)dataSet_01[ii][jj];
                        while(!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));
                        EUSCI_B0->TXBUF = (uint8_t)(dataSet_01[ii][jj]>>8);
                    }
                }
            }
            else
            {
                for(ii=0;ii<NUMBER_OF_SAMPLES;ii++)
                {
                    for(jj=0;jj<CONVERSIONS_PER_SAMPLE;jj++)
                    {
                        while(!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));
                        EUSCI_B0->TXBUF = (uint8_t)dataSet_02[ii][jj];
                        while(!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0));
                        EUSCI_B0->TXBUF = (uint8_t)(dataSet_02[ii][jj]>>8);
                    }
                }
            }
    //        Debug
    //        P2->OUT &= ~BIT0;
        }
    }
    
    #if     __TI_COMPILER_VERSION__ >= 15009000
    __attribute__((ramfunc))
    #endif
    void PORT1_IRQHandler(void)
    {
        uint32_t status;
        volatile uint16_t   ii;
    //        Debug
    //  P2->OUT |= BIT1;
        status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);
    
        if(status == GPIO_PIN2)
        {
            MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN2);
            dataSet0Ready = true;
        }
        if(status == GPIO_PIN3)
        {
            MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN3);
            dataSet0Ready = false;
        }
    //        Debug
    //    P2->OUT &= ~BIT1;
    }
    

    Chris

  • Blake,

       The attached file is in error.  The arbitration should be set to 4 so that each ADC trigger that goes to the DMA (ADC triggers DMA at the end of the sequence) causes the DMA to move all three pieces of data (size of task set to 3).   I neglected the note found on page 450 of the TRM.

    So in the example I have provided N is equal to 3 and 2^R = 1.  Therefore the DMA will always perform sequences of '1' until N=1.  This will result in 3 seperate sequences each requiring a trigger and therefor each trigger will only move one piece of data although all three are ready.  This is also illustrated in the peripheral scatter-gather description (note task A):

    Thanks and Regards,

    Chris

**Attention** This is a public forum