Tool/software: Code Composer Studio
**EDIT** See working example at the bottom of the page
Hi,
I'm trying to learn DMA with ADC, using a modified udma_demo. But I'm a bit confused on how the readings are done and having some problems setting the ADC buffer size to 2.
#include "config/config.h" #pragma DATA_ALIGN(dmaControlTable, 1024) uint8_t dmaControlTable[1024]; #define MEM_BUFFER_SIZE 8 static uint16_t g_adcBufA[MEM_BUFFER_SIZE]; static uint16_t g_adcBufB[MEM_BUFFER_SIZE]; static uint32_t g_uDMAErrCount; void config_ADC0DMA(void) { ROM_GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_0 | GPIO_PIN_1); ROM_ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_ALWAYS, 0); ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH16); ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH17 | ADC_CTL_IE | ADC_CTL_END); //(320MHz PLL/2) / 5 = 32MHz = 2MSPS ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 5); //ROM_ADCHardwareOversampleConfigure(ADC0_BASE, 64); ROM_ADCSequenceEnable(ADC0_BASE, 1); ROM_ADCSequenceDMAEnable(ADC0_BASE, 1); ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC1, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC1, UDMA_ATTR_USEBURST); ROM_uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); ROM_uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); ROM_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO1), g_adcBufA, MEM_BUFFER_SIZE); ROM_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO1), g_adcBufB, MEM_BUFFER_SIZE); ROM_uDMAChannelEnable(UDMA_CHANNEL_ADC1); ROM_ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS1); ROM_IntEnable(INT_ADC0SS1);; } int main(void) { uint32_t g_cpuFrequency = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 120000000); ROM_FPUEnable(); ROM_FPULazyStackingEnable(); ROM_IntMasterDisable(); initPeripherals(); config_UART2(921600, g_cpuFrequency); UARTprintf("\033[2J\033[H"); ROM_IntEnable(INT_UDMAERR); ROM_uDMAEnable(); ROM_uDMAControlBaseSet(dmaControlTable); config_ADC0DMA(); ROM_IntMasterEnable(); for(;;) { UARTprintf("ADC ReadingA: %u %u %u %u %u %u %u %u Error Count: %u\n", g_adcBufA[0], g_adcBufA[1], g_adcBufA[2], g_adcBufA[3], g_adcBufA[4], g_adcBufA[5], g_adcBufA[6], g_adcBufA[7], g_uDMAErrCount); UARTprintf("ADC ReadingB: %u %u %u %u %u %u %u %u Error Count: %u\n", g_adcBufB[0], g_adcBufB[1], g_adcBufB[2], g_adcBufB[3], g_adcBufB[4], g_adcBufB[5], g_adcBufB[6], g_adcBufB[7], g_uDMAErrCount); //UARTprintf("ADC ReadingA: %u %u Error Count: %u\n", g_adcBufA[0], g_adcBufA[1], g_uDMAErrCount); //UARTprintf("ADC ReadingB: %u %u Error Count: %u\n", g_adcBufB[0], g_adcBufB[1], g_uDMAErrCount); ROM_SysCtlDelay((g_cpuFrequency/3)*0.1); } } void ADC0SS1IntHandler(void) { uint32_t ui32Mode; //limpa interrupção causada pelo DMA ADCIntClearEx(ADC0_BASE, ADC_INT_DMA_SS1); ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT); if(ui32Mode == UDMA_MODE_STOP) ROM_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO1), g_adcBufA, MEM_BUFFER_SIZE); ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT); if(ui32Mode == UDMA_MODE_STOP) ROM_uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO1), g_adcBufB, MEM_BUFFER_SIZE); } void uDMAErrorHandler(void) { uint32_t ui32Status; ui32Status = ROM_uDMAErrorStatusGet(); if(ui32Status) { ROM_uDMAErrorStatusClear(); g_uDMAErrCount++; } }
I'm trying to read from pins PK0 (GND) and PK1 (3V3). I'm setting the g_adcBufA and g_adcBufB size to 8 and getting [4095 0 4095 0 4095 0 4095 0] on each. Seems like it's reading [PK1 PK0 PK1 PK0 PK1 PK0 PK1 PK0].
The SS1 has a FIFO depth of 4 and can hold 4 readings. But I'm using a buffer of 8 positions and these are filled with PK1 and PK0 readings alternately.
Questions:
Shouldn't g_adcBufA hold the first two values and print something else in the rest?
Why can't I use a buffer of two values? It only works with 8 minimum. I need the results immediately, not waiting a buffer to be filled 8 times before I can process data.
Is the Ping-Pong the best way to use the DMA with ADC? I heard I could use Scatter-Gather, but seems rather complex, not sure if the complexity makes up for the performance gain (and I'm totally newbie with DMA, only worked once with a STM32 board, which has a rather nice software called STM32CubeMX that does all the stuff in the background).