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.

Compiler/TM4C129EKCPDT: how to config udma with two adc

Part Number: TM4C129EKCPDT

Tool/software: TI C/C++ Compiler

I can read two voltage from ADC 9 and ADC 11, but I can't use udma to save the two ADC value to array.

I don't know how to config udma with two adc channel.

I try use udma repeatedly ,but failed.

can you help me .I want to read ADC9 and ADC11 voltage use udma. that I can get the two voltage value from array.

thank you ! if you can ,can you give me some demo adbut use two adc with udma.

my code ( udna part is error,and I cannot confirm adc part is correct ):

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/rom.h"

#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
 
#include "driverlib/udma.h"
#include "driverlib/adc.h"

#include "rom_map.h"
#include "hw_adc.h"

#include "driverlib/gpio.h"
#include <string.h>
#include "stdio.h"
#include "drv_adc.h"
#include <rtthread.h>
#include "hw_memmap.h"
#include "hw_ints.h"
#include "tiva_timer.h"
#include "interrupt.h"
#include "rom.h"
#include "plc_config.h"
uint32_t g_ui32SysClock;

//*****************************************************************************
//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.
//
//*****************************************************************************
#if defined(ewarm)
#pragma data_alignment=1024
uint8_t pui8ControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(pui8ControlTable, 1024)
uint8_t pui8ControlTable[1024];
#else
uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
#endif

//*****************************************************************************
//
// The size of the memory transfer source and destination buffers (in words).
//
//*****************************************************************************
#define MEM_BUFFER_SIZE         1024
//*****************************************************************************
//
// The source and destination buffers used for memory transfers.
//
//*****************************************************************************
static uint32_t g_ui32SrcBuf[MEM_BUFFER_SIZE];
static uint32_t g_ui32DstBuf[MEM_BUFFER_SIZE];
//*****************************************************************************
//
// The count of uDMA errors.  This value is incremented by the uDMA error
// handler.
//
//*****************************************************************************
static volatile uint32_t g_ui32uDMAErrCount = 0;
//*****************************************************************************
//
// The count of memory uDMA transfer blocks.  This value is incremented by the
// uDMA interrupt handler whenever a memory block transfer is completed.
//
//*****************************************************************************
static volatile uint32_t g_ui32MemXferCount = 0;
//*****************************************************************************
//
// The count of times the uDMA interrupt occurred but the uDMA transfer was not
// complete.  This should remain 0.
//
//*****************************************************************************
static volatile uint32_t g_ui32BadISR = 0;



#define		ADC_BUFF_SIZE				64

extern char HardVer[5];

uint32_t adc_value;

float   R=0;
float   TEMP=0;
uint16_t g_temp;
uint16_t g_vol;
uint16_t g_ele;
//*****************************************************************************
//
// Initializes the uDMA software channel to perform a memory to memory uDMA
// transfer.
//
//*****************************************************************************
void
InitADC0Transfer(void)
{
    uint_fast16_t ui16Idx;

    //
    // Fill the source memory buffer with a simple incrementing pattern.
    //
    for(ui16Idx = 0; ui16Idx < MEM_BUFFER_SIZE; ui16Idx++)
    {
        g_ui32SrcBuf[ui16Idx] = ui16Idx;
    }

    //
    // Enable interrupts from the uDMA software channel.
    //
    IntEnable(INT_UDMA);

    //
    // Put the attributes in a known state for the uDMA software channel.
    // These should already be disabled by default.
    //
    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
                                    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
                                    (UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK));

    //
    // Configure the control parameters for the SW channel.  The SW channel
    // will be used to transfer between two memory buffers, 32 bits at a time.
    // Therefore the data size is 32 bits, and the address increment is 32 bits
    // for both source and destination.  The arbitration size will be set to 8,
    // which causes the uDMA controller to rearbitrate after 8 items are
    // transferred.  This keeps this channel from hogging the uDMA controller
    // once the transfer is started, and allows other channels cycles if they
    // are higher priority.
    //
    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 |
                              UDMA_ARB_8);

    //
    // Set up the transfer parameters for the software channel.  This will
    // configure the transfer buffers and the transfer size.  Auto mode must be
    // used for software transfers.
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                               UDMA_MODE_AUTO, g_ui32SrcBuf, g_ui32DstBuf,
                               MEM_BUFFER_SIZE);

    //
    // Now the software channel is primed to start a transfer.  The channel
    // must be enabled.  For software based transfers, a request must be
    // issued.  After this, the uDMA memory transfer begins.
    //
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);
    uDMAChannelRequest(UDMA_CHANNEL_ADC0);
}


//*****************************************************************************
//
// The interrupt handler for uDMA errors.  This interrupt will occur if the
// uDMA encounters a bus error while trying to perform a transfer.  This
// handler just increments a counter if an error occurs.
//
//*****************************************************************************
void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    //
    // Check for uDMA error bit
    //
    ui32Status = uDMAErrorStatusGet();

    //
    // If there is a uDMA error, then clear the error and increment
    // the error counter.
    //
    if(ui32Status)
    {
        uDMAErrorStatusClear();
        g_ui32uDMAErrCount++;
    }
}

//*****************************************************************************
//
// The interrupt handler for uDMA interrupts from the memory channel.  This
// interrupt will increment a counter, and then restart another memory
// transfer.
//
//*****************************************************************************
void
uDMAIntHandler(void)
{
    uint32_t ui32Mode;

    //
    // Check for the primary control structure to indicate complete.
    //
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0);
    if(ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment the count of completed transfers.
        //
        g_ui32MemXferCount++;

        //
        // Configure it for another transfer.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_ADC0, UDMA_MODE_AUTO,
                                   g_ui32SrcBuf, g_ui32DstBuf,
                                   MEM_BUFFER_SIZE);

        //
        // Initiate another transfer.
        //
        uDMAChannelEnable(UDMA_CHANNEL_ADC0);
        uDMAChannelRequest(UDMA_CHANNEL_ADC0);
    }

    //
    // If the channel is not stopped, then something is wrong.
    //
    else
    {
        g_ui32BadISR++;
    }
}



void ADC_Init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //ADC0
    
    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//ADC GPIO-B  VER   
    GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4);//ADC PIN
    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH10 | ADC_CTL_IE |ADC_CTL_END); 
    ADCSequenceEnable(ADC0_BASE, 1);
    ADCIntClear(ADC0_BASE, 1); 
    ADCIntEnable(ADC0_BASE, 1);
    

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5);
    ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH8 | ADC_CTL_IE |ADC_CTL_END);
    ADCSequenceEnable(ADC0_BASE, 3);
    ADCIntClear(ADC0_BASE, 3); 
    ADCIntEnable(ADC0_BASE, 3);
    

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//ADC GPIO-E 
    GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);//  
    ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH11 | ADC_CTL_IE |ADC_CTL_END);
    ADCSequenceEnable(ADC0_BASE, 2);
    ADCIntClear(ADC0_BASE, 2); 
    ADCIntEnable(ADC0_BASE, 2);
    
    
    IntEnable(INT_ADC0SS0);
    return;
}

void DMA_init(void)
{
    //
    // Enable the uDMA controller at the system level.  Enable it to continue
    // to run while the processor is in sleep.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    //
    // Enable the uDMA controller error interrupt.  This interrupt will occur
    // if there is a bus error during a transfer.
    //
    IntEnable(INT_UDMAERR);

    // Enable the uDMA 

    uDMAEnable();
    //
    // Point at the control table to use for channel control structures.
    //
    uDMAControlBaseSet(pui8ControlTable);
    //
    // Initialize the uDMA memory to memory transfers.
    //
    
    InitADC0Transfer();
    
}


void AI_thread(void* parameter)
{
    int i,value;
    float V,I,RV;
    float ch_read;
    uint32_t p_ADC_buff[100];
    ADC_Init();
//    DMA_init();
    while(1)
    {
		// read first voltage value use  ADC
        for(i=0;i<100;i++)
        {
            ADCProcessorTrigger(ADC0_BASE,3);
            while(!ADCIntStatus(ADC0_BASE, 3, false))
            {
            }
            ADCIntClear(ADC0_BASE, 3);
            ADCSequenceDataGet(ADC0_BASE, 3, &p_ADC_buff[i]);
        }   
        for(i=0, value=0; i<100; i++)
        {
            value += p_ADC_buff[i];
        }
        value = value /100; 
        
        ch_read = value*3.3/4096.0;
        V = ch_read *100.0*1000.0/12.0;   // V is right value
        
       
/////////////////////////////////////////    read second voltage  value  use ADC
        for(i=0;i<100;i++)
        {
            ADCProcessorTrigger(ADC0_BASE,2);
            while(!ADCIntStatus(ADC0_BASE, 2, false))
            {
            }
            ADCIntClear(ADC0_BASE, 2);
            ADCSequenceDataGet(ADC0_BASE, 2, &p_ADC_buff[i]);
        }   
        for(i=0, value=0; i<100; i++)
        {
            value += p_ADC_buff[i];
        }
        value = value /100;   
        
        ch_read = value*3.3/4096.0;
        RV = ch_read/(100.0/10.0)/12.0;    // RV is right value of voltage       
        
        rt_thread_delay(20);
    }
}

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/rom.h"

#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
 
#include "driverlib/udma.h"
#include "driverlib/adc.h"

#include "rom_map.h"
#include "hw_adc.h"

#include "driverlib/gpio.h"
#include <string.h>
#include "stdio.h"
#include "drv_adc.h"
#include <rtthread.h>
#include "hw_memmap.h"
#include "hw_ints.h"
#include "tiva_timer.h"
#include "interrupt.h"
#include "rom.h"
#include "plc_config.h"
uint32_t g_ui32SysClock;

//*****************************************************************************
//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.
//
//*****************************************************************************
#if defined(ewarm)
#pragma data_alignment=1024
uint8_t pui8ControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(pui8ControlTable, 1024)
uint8_t pui8ControlTable[1024];
#else
uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
#endif

//*****************************************************************************
//
// The size of the memory transfer source and destination buffers (in words).
//
//*****************************************************************************
#define MEM_BUFFER_SIZE         1024
//*****************************************************************************
//
// The source and destination buffers used for memory transfers.
//
//*****************************************************************************
static uint32_t g_ui32SrcBuf[MEM_BUFFER_SIZE];
static uint32_t g_ui32DstBuf[MEM_BUFFER_SIZE];
//*****************************************************************************
//
// The count of uDMA errors.  This value is incremented by the uDMA error
// handler.
//
//*****************************************************************************
static volatile uint32_t g_ui32uDMAErrCount = 0;
//*****************************************************************************
//
// The count of memory uDMA transfer blocks.  This value is incremented by the
// uDMA interrupt handler whenever a memory block transfer is completed.
//
//*****************************************************************************
static volatile uint32_t g_ui32MemXferCount = 0;
//*****************************************************************************
//
// The count of times the uDMA interrupt occurred but the uDMA transfer was not
// complete.  This should remain 0.
//
//*****************************************************************************
static volatile uint32_t g_ui32BadISR = 0;



#define		ADC_BUFF_SIZE				64

extern char HardVer[5];

uint32_t adc_value;

float   R=0;
float   TEMP=0;
uint16_t g_temp;
uint16_t g_vol;
uint16_t g_ele;
//*****************************************************************************
//
// Initializes the uDMA software channel to perform a memory to memory uDMA
// transfer.
//
//*****************************************************************************
void
InitADC0Transfer(void)
{
    uint_fast16_t ui16Idx;

    //
    // Fill the source memory buffer with a simple incrementing pattern.
    //
    for(ui16Idx = 0; ui16Idx < MEM_BUFFER_SIZE; ui16Idx++)
    {
        g_ui32SrcBuf[ui16Idx] = ui16Idx;
    }

    //
    // Enable interrupts from the uDMA software channel.
    //
    IntEnable(INT_UDMA);

    //
    // Put the attributes in a known state for the uDMA software channel.
    // These should already be disabled by default.
    //
    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
                                    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
                                    (UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK));

    //
    // Configure the control parameters for the SW channel.  The SW channel
    // will be used to transfer between two memory buffers, 32 bits at a time.
    // Therefore the data size is 32 bits, and the address increment is 32 bits
    // for both source and destination.  The arbitration size will be set to 8,
    // which causes the uDMA controller to rearbitrate after 8 items are
    // transferred.  This keeps this channel from hogging the uDMA controller
    // once the transfer is started, and allows other channels cycles if they
    // are higher priority.
    //
    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                              UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 |
                              UDMA_ARB_8);

    //
    // Set up the transfer parameters for the software channel.  This will
    // configure the transfer buffers and the transfer size.  Auto mode must be
    // used for software transfers.
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                               UDMA_MODE_AUTO, g_ui32SrcBuf, g_ui32DstBuf,
                               MEM_BUFFER_SIZE);

    //
    // Now the software channel is primed to start a transfer.  The channel
    // must be enabled.  For software based transfers, a request must be
    // issued.  After this, the uDMA memory transfer begins.
    //
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);
    uDMAChannelRequest(UDMA_CHANNEL_ADC0);
}


//*****************************************************************************
//
// The interrupt handler for uDMA errors.  This interrupt will occur if the
// uDMA encounters a bus error while trying to perform a transfer.  This
// handler just increments a counter if an error occurs.
//
//*****************************************************************************
void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    //
    // Check for uDMA error bit
    //
    ui32Status = uDMAErrorStatusGet();

    //
    // If there is a uDMA error, then clear the error and increment
    // the error counter.
    //
    if(ui32Status)
    {
        uDMAErrorStatusClear();
        g_ui32uDMAErrCount++;
    }
}

//*****************************************************************************
//
// The interrupt handler for uDMA interrupts from the memory channel.  This
// interrupt will increment a counter, and then restart another memory
// transfer.
//
//*****************************************************************************
void
uDMAIntHandler(void)
{
    uint32_t ui32Mode;

    //
    // Check for the primary control structure to indicate complete.
    //
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0);
    if(ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment the count of completed transfers.
        //
        g_ui32MemXferCount++;

        //
        // Configure it for another transfer.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_ADC0, UDMA_MODE_AUTO,
                                   g_ui32SrcBuf, g_ui32DstBuf,
                                   MEM_BUFFER_SIZE);

        //
        // Initiate another transfer.
        //
        uDMAChannelEnable(UDMA_CHANNEL_ADC0);
        uDMAChannelRequest(UDMA_CHANNEL_ADC0);
    }

    //
    // If the channel is not stopped, then something is wrong.
    //
    else
    {
        g_ui32BadISR++;
    }
}



void ADC_Init(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //?a??ADC0
    
    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//?a??ADC GPIO-B  VER   
    GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4);//????ADC ��y??PIN    
    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);//D����D����??��?????D����D��?����?���䣤�����?��??��??0
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH10 | ADC_CTL_IE |ADC_CTL_END); //2��?�������̨�10 VER
    ADCSequenceEnable(ADC0_BASE, 1);//��1?��2��?��D����D��1?��
    ADCIntClear(ADC0_BASE, 1); //??3y?D??����??
    ADCIntEnable(ADC0_BASE, 1);//ADC?D??��1?��
    

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);//?a??ADC GPIO-E  ��??1��?����   
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5);//????ADC ��y??PIN    
    ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);//D����D����??��?????D����D��?����?���䣤�����?��??��??0
    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH8 | ADC_CTL_IE |ADC_CTL_END); //2��?�������̨�8 ��??1��?����
    ADCSequenceEnable(ADC0_BASE, 3);//��1?��2��?��D����D��1?��
    ADCIntClear(ADC0_BASE, 3); //??3y?D??����??
    ADCIntEnable(ADC0_BASE, 3);//ADC?D??��1?��
    

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);//?a??ADC GPIO-E  ��??1��?����   
    GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);//????ADC ��y??PIN    
    ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PROCESSOR, 0);//D����D����??��?????D����D��?����?���䣤�����?��??��??0
    ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH11 | ADC_CTL_IE |ADC_CTL_END); //2��?�������̨�8 ��??1��?����
    ADCSequenceEnable(ADC0_BASE, 2);//��1?��2��?��D����D��1?��
    ADCIntClear(ADC0_BASE, 2); //??3y?D??����??
    ADCIntEnable(ADC0_BASE, 2);//ADC?D??��1?��
    
    
    IntEnable(INT_ADC0SS0);//��1?��ADC2��?��D����D?D??
    return;
}

void DMA_init(void)
{
    //
    // Enable the uDMA controller at the system level.  Enable it to continue
    // to run while the processor is in sleep.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    //
    // Enable the uDMA controller error interrupt.  This interrupt will occur
    // if there is a bus error during a transfer.
    //
    IntEnable(INT_UDMAERR);

    // Enable the uDMA 

    uDMAEnable();
    //
    // Point at the control table to use for channel control structures.
    //
    uDMAControlBaseSet(pui8ControlTable);
    //
    // Initialize the uDMA memory to memory transfers.
    //
    
    InitADC0Transfer();
    
}


void AI_thread(void* parameter)
{
    int i,value;
    float V,I,RV;
    float ch_read;
    uint32_t p_ADC_buff[100];
    ADC_Init();
//    DMA_init();
    while(1)
    {
		// read first voltage value use  ADC
        for(i=0;i<100;i++)
        {
            ADCProcessorTrigger(ADC0_BASE,3);
            while(!ADCIntStatus(ADC0_BASE, 3, false))
            {
            }
            ADCIntClear(ADC0_BASE, 3);
            ADCSequenceDataGet(ADC0_BASE, 3, &p_ADC_buff[i]);
        }   
        for(i=0, value=0; i<100; i++)
        {
            value += p_ADC_buff[i];
        }
        value = value /100; 
        
        ch_read = value*3.3/4096.0;
        V = ch_read *100.0*1000.0/12.0;   // V is right value
        
       
/////////////////////////////////////////    read second voltage  value  use ADC
        for(i=0;i<100;i++)
        {
            ADCProcessorTrigger(ADC0_BASE,2);
            while(!ADCIntStatus(ADC0_BASE, 2, false))
            {
            }
            ADCIntClear(ADC0_BASE, 2);
            ADCSequenceDataGet(ADC0_BASE, 2, &p_ADC_buff[i]);
        }   
        for(i=0, value=0; i<100; i++)
        {
            value += p_ADC_buff[i];
        }
        value = value /100;   
        
        ch_read = value*3.3/4096.0;
        RV = ch_read/(100.0/10.0)/12.0;    // RV is right value of voltage       
        
        rt_thread_delay(20);
    }
}

  • The simple answer to your question is that if the ADC samples are done with different sequences, you simply use the uDMA channel for that ADC sequence. In the code above you use ADC0, sequences 2 and 3. You should use UDMA_CHANNEL_ADC2 when configuring uDMA channel 16 for ADC0 sequence 2, and use UDMA_CHANNEL_ADC3 when configuring uDMA channel 17 for ADC0 sequence 3. You were using UDMA_CHANNEL_ADC0 which is for sequence 0.

    But is this what you really want, 100 conversion on one channel, then 100 conversions on the next? If the readings of both channels are to be done at approximately the same time, use one sequence with two steps. Then in the data array alternating values will represent the data from each channel.