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.

TM4C1233H6PZ: ADC - uDMA issue

Part Number: TM4C1233H6PZ

Hi, 

I'm trying to read in 9 analog inputs using the ADC sequencers and store the data in a buffer using the uDMA.  Both the sequencers work separately, but when they are configured together they begin to act funny.  When two sequencers are enabled, only one of the complete sequencer gets its data to the buffer.  This behavior is predictable as well.  The sequencer whose data get transferred is always the sequencer initiating the ADC sequencer interrupt. For example, if I configure sequencer 0 to initiate the interrupt only sequence 0 will be seen in the buffer, but if i configure sequencer 1 to trigger the interrupt, it will be that data that is located in the buffer.  Here is my code:

/* Private Variables **********************************************************/
/** @defgroup _eppc_adc_Private_Variables Private Variables
  * @{
  */
/** Creates an array describing the purpose of each analog input.
 *
 */
analog_inputs_t analogInputs[TOTAL_ANALOG_INPUTS];
/** Stores that values of the ADC that are transfered by the uDMA
 *
 */
uint32_t u32_aInBuffer[TOTAL_ANALOG_INPUTS];
/**
  * @}
  */

/* Private functions **********************************************************/
/** @defgroup _eppc_adc_Private_Functions Private Functions
  * @{
  */

/*  Function:   functionName */
/**
  *  @brief     Function description
  *  @param     Function parameters
  *  @retval    Return value
  */

/**
  * @}
  */

/* Public functions ***********************************************************/
/** @defgroup _eppc_adc_Public_Functions Public Functions
  * @{
  */
void adc_ss1_int_handler(void)
{
    //Get interrupt status
    uint32_t u32_adc0Status = MAP_ADCIntStatusEx(ADC0_BASE, true);
    //Clear interrupt flag
    MAP_ADCIntClearEx(ADC0_BASE, u32_adc0Status);

    //Sets transfer parameters for UDMA
    MAP_uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 |                  //ADC sequence 0
                               UDMA_PRI_SELECT,                     //Uses primary data structure
                               UDMA_MODE_BASIC,                     //Performs a basic data transfer
                               (void *)(ADC0_BASE + ADC_O_SSFIFO0), //Source of data transfer
                               u32_aInBuffer,                 //Destination of data transfer
                               8);                                  //Number of data items
    //Enable UDMA channel
    MAP_uDMAChannelEnable(UDMA_CHANNEL_ADC0);

   //Sets transfer parameters for UDMA
    MAP_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 |                  //ADC sequence 1
                               UDMA_PRI_SELECT,                     //Uses primary data structure
                               UDMA_MODE_BASIC,                     //Performs a basic data transfer
                               (void *)(ADC0_BASE + ADC_O_SSFIFO1), //Source of data transfer
                               &u32_aInBuffer[8],                 //Destination of data transfer
                               1);                                  //Number of data items
    //Enable UDMA channel
    MAP_uDMAChannelEnable(UDMA_CHANNEL_ADC1);
}
/*  Function:   adc_initialize */
/**
  *  @brief     Initializes the ADC
  *  @retval    none
  */
void adc_initialize(void)
{
    //Initialize analog input struct
    //AIN0
    analogInputs[0] = (analog_inputs_t){0,false};
    //AIN1
    analogInputs[1] = (analog_inputs_t){0,false};
    //AIN2
    analogInputs[2] = (analog_inputs_t){0,false};
    //AIN3
    analogInputs[3] = (analog_inputs_t){0,false};
    //AIN4
    analogInputs[4] = (analog_inputs_t){0,false};
    //AIN5
    analogInputs[5] = (analog_inputs_t){0,false};
    //AIN6
    analogInputs[6] = (analog_inputs_t){0,false};
    //AIN7
    analogInputs[7] = (analog_inputs_t){0,false};
    //Pump Current
    analogInputs[8] = (analog_inputs_t){0,false};

    //Enable the ADC0 peripheral
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //Averages 64 ADC samples to provide a higher resolution measurement
    MAP_ADCHardwareOversampleConfigure(ADC0_BASE, 64);

    //Enable peripherals
    MAP_SysCtlPeripheralEnable(AIN_PERIPH_0TO3);
    MAP_SysCtlPeripheralEnable(AIN_PERIPH_4TO7);
    MAP_SysCtlPeripheralEnable(AIN_PERIPH_PUMP);

    //Enable analog input on gpio pins
    MAP_GPIOPinTypeADC(AIN_PORT_0TO3, AIN_PIN_0 | AIN_PIN_1 | AIN_PIN_2 | AIN_PIN_3);
    MAP_GPIOPinTypeADC(AIN_PORT_4TO7, AIN_PIN_4 | AIN_PIN_5 | AIN_PIN_6 | AIN_PIN_7);
    MAP_GPIOPinTypeADC(AIN_PORT_PUMP, AIN_PIN_PUMP);

    //Configure ADC Sequencers
    MAP_ADCSequenceConfigure(ADC0_BASE,                 //ADC Base 0
                             0,                         //Sequencer 0 (captures up to 8 samples)
                             ADC_TRIGGER_TIMER,         //ADC trigger is generated by a timer
                             0);                        //Sequencer priority
    MAP_ADCSequenceConfigure(ADC0_BASE,                 //ADC Base 0
                             1,                         //Sequencer 1 (captures up to 4 samples)
                             ADC_TRIGGER_TIMER,         //ADC trigger is generated by a timer
                             1);                        //Sequencer priority

    //Configures the steps of each ADC sequence
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 0,                     //Sequence order
                                 AIN_0);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 1,                     //Sequence order
                                 AIN_1);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 2,                     //Sequence order
                                 AIN_2);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 3,                     //Sequence order
                                 AIN_3);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 4,                     //Sequence order
                                 AIN_4);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 5,                     //Sequence order
                                 AIN_5);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 6,                     //Sequence order
                                 AIN_6);                //ADC channel
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 0,                     //Sequence number
                                 7,                     //Sequence order
                                 AIN_7 | ADC_CTL_END);  //ADC channel and last channel in the sequence
    MAP_ADCSequenceStepConfigure(ADC0_BASE,             //ADC Base
                                 1,                     //Sequence number
                                 0,                     //Sequence order
                                 AIN_PUMP | ADC_CTL_END | ADC_CTL_IE);  //ADC channel and last channel in the sequence.
    //Once sequencer 1 finishes it generates an interrupt to tell the processor the FIFO is filled

    //Enables ADC sequences 0 and 1
    MAP_ADCSequenceEnable(ADC0_BASE, 0);
    MAP_ADCSequenceEnable(ADC0_BASE, 1);

    //Enables DMA for sequences 0 and 1
    MAP_ADCSequenceDMAEnable(ADC0_BASE, 0);
    MAP_ADCSequenceDMAEnable(ADC0_BASE, 1);



    //CONFIGURE UDMA FOR ADC SEQUENCES


    //Sequence 0 uDMA configuration
    //Enables attribute of UDMA channel
    MAP_uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0,               //ADC sequence 0
                                   UDMA_ATTR_USEBURST);             //Restrict transfers to burst only mode
    //Sets control parameters for UDMA
    MAP_uDMAChannelControlSet(UDMA_CHANNEL_ADC0 |                   //ADC sequence 0
                              UDMA_PRI_SELECT,                      //Uses primary data structure
                              UDMA_SIZE_32 |                        //32bit data size
                              UDMA_SRC_INC_NONE |                   //No source address increment
                              UDMA_DST_INC_32 |                     //Destination address increment set to 32bits
                              UDMA_ARB_1);                          //Sends 8 items before bus is re-arbitrated
    //Sets transfer parameters for UDMA
    MAP_uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 |                  //ADC sequence 0
                               UDMA_PRI_SELECT,                     //Uses primary data structure
                               UDMA_MODE_BASIC,                     //Performs a basic data transfer
                               (void *)(ADC0_BASE + ADC_O_SSFIFO0), //Source of data transfer
                               u32_aInBuffer,                 //Destination of data transfer
                               8);                                  //Number of data items
    //Enable UDMA channel
    MAP_uDMAChannelEnable(UDMA_CHANNEL_ADC0);

    //Sequence 3 uDMA configuration
    //Enables attribute of UDMA channel
    MAP_uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC1,               //ADC sequence 1
                                   UDMA_ATTR_USEBURST);             //Restrict transfers to burst only mode
    //Sets control parameters for UDMA
    MAP_uDMAChannelControlSet(UDMA_CHANNEL_ADC1 |                   //ADC sequence 1
                              UDMA_PRI_SELECT,                      //Uses primary data structure
                              UDMA_SIZE_32 |                        //32bit data size
                              UDMA_SRC_INC_NONE |                   //No source address increment
                              UDMA_DST_INC_32 |                     //Destination address increment set to 32bits
                              UDMA_ARB_8);                          //Sends 1 items before bus is re-arbitrated
    //Sets transfer parameters for UDMA
    MAP_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 |                  //ADC sequence 1
                               UDMA_PRI_SELECT,                     //Uses primary data structure
                               UDMA_MODE_BASIC,                     //Performs a basic data transfer
                               (void *)(ADC0_BASE + ADC_O_SSFIFO1), //Source of data transfer
                               &u32_aInBuffer[8],                 //Destination of data transfer
                               1);                                  //Number of data items
    //Enable UDMA channel
    MAP_uDMAChannelEnable(UDMA_CHANNEL_ADC1);


    //CONFIGURE INTERRUPT FOR ANALOG INPUT
    //Clear the sequence 1 interrupt flag before enabling
    MAP_ADCIntClearEx(ADC0_BASE, ADC_INT_SS1);
    //Enable sequence 1 interrupt in peripheral
    MAP_ADCIntEnableEx(ADC0_BASE, ADC_INT_SS1);
    //Enable the sequence 1 interrupt in the NVIC
    MAP_IntEnable(INT_ADC0SS1);

    //CONFIGURE TIMER FOR TRIGGERING ADC
    //Enable timer peripheral
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    //Configures the system clock as the clock source
    MAP_TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_SYSTEM);
    //Configures timer as a full width periodic timer
    MAP_TimerConfigure(TIMER1_BASE,TIMER_CFG_PERIODIC);
    //Enables the ADC trigger output
    MAP_TimerControlTrigger(TIMER1_BASE, TIMER_A, true);
    //Prevent timer from counting when halted by debugger
    MAP_TimerControlStall(TIMER1_BASE, TIMER_A, true);
    //Load timer for 1ms frequency
    MAP_TimerLoadSet(TIMER1_BASE, TIMER_A, 160000);
    //Start ADC timer
    MAP_TimerEnable(TIMER1_BASE, TIMER_A);
}