Hello, I'm using uDMA to transfer samples from an ADC to memory in pong pong mode.
I want the ADC to generate an interrupt when the uDMA completes a transfer, i.e. interrupt after 10000 samples.
However, I can't seem to clear the interrupt status ADC_INT_DMA_SS0.
Is it something in the ADC/uDMA settings that I did wrong which disallows me to clear that interrupt?
/* * myadcpingpong.c */ #include <stdint.h> #include <stdbool.h> #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_adc.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" #include "driverlib/interrupt.h" #include "driverlib/uart.h" #include "driverlib/adc.h" #include "driverlib/udma.h" #include "utils/uartstdio.h" #define ADC_BUF_SIZE 1024 #define MODE_IDLE 0 #define MODE_UDMA 1 #define MODE_PRINT 2 volatile uint8_t mode; uint32_t ui32Ms; uint32_t ui32ClockFreq; uint8_t pui8DMAControlTable[1024]; uint16_t pui16AdcPriBuffer[ADC_BUF_SIZE]; uint16_t pui16AdcAltBuffer[ADC_BUF_SIZE]; uint16_t counter = 0; void print_ADC_buffer(void) { int i; for (i = 0; i < ADC_BUF_SIZE; i++) { UARTprintf("%d\n", pui16AdcPriBuffer[i]); } for (i = 0; i < ADC_BUF_SIZE; i++) { UARTprintf("%d\n", pui16AdcAltBuffer[i]); } } void delay_ms(uint32_t ms) { uint32_t ui32End; // Time when delay loop finishes ui32End = ui32Ms + ms; // Delay until ui32Ms is >= ui32End while (ui32End > ui32Ms); } void timer_int_handler(void) { TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); ui32Ms++; } void adc_int_handler(void) { uint32_t ui32uDMAChannelMode; uint32_t ui32ADCIntStatus; uint32_t ui32ADCIntStatus_true; // Clear the interrupt flag of ADC0 sequence 3 //HWREG(ADC0_BASE + 0x008) = 0; ui32ADCIntStatus = ADCIntStatus(ADC0_BASE, 0, false); ui32ADCIntStatus_true = ADCIntStatus(ADC0_BASE, 0, true); //ADCIntClear(ADC0_BASE, 3); //ADCIntClearEx(ADC0_BASE, ADC_INT_DMA_SS0); //ADCIntClearEx(ADC0_BASE, 0xFFFFFFFF); *(uint32_t *) (ADC0_BASE + ADC_O_ISC) = ADC_INT_DMA_SS0; //while(1); //HWREG(ADC0_BASE + 0x008) = (1 << 11); UARTprintf("S\n"); // Check the mode of the uDMA control structures ui32uDMAChannelMode = uDMAChannelModeGet(UDMA_CHANNEL_ADC3 | UDMA_PRI_SELECT); if ((ui32uDMAChannelMode == UDMA_MODE_STOP) && (mode == MODE_UDMA)) { // Check alt control structure ui32uDMAChannelMode = uDMAChannelModeGet(UDMA_CHANNEL_ADC3 | UDMA_ALT_SELECT); if ((ui32uDMAChannelMode == UDMA_MODE_STOP) && (mode == MODE_UDMA)) { UARTprintf("Everything done\n"); mode = MODE_PRINT; } } } void init_clock(void) { ui32ClockFreq = SysCtlClockFreqSet(SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480, 16000000); } void init_uart(void) { // Enable UART0 clock SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0)); // Enable GPIOA clock SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)); // Enable UART UARTEnable(UART0_BASE); // Configure port A pins 0 and 1 to be UART0 RX and TX GPIOPinConfigure(GPIO_PA1_U0TX); GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1 | GPIO_PIN_0); // Configure parameters of the UART UARTStdioConfig(0, 9600, ui32ClockFreq); } void init_timer(void) { // Enable timer peripheral clock and check that the peripheral is ready SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0)); // Configure the timer TimerConfigure(TIMER0_BASE, TIMER_CFG_A_PERIODIC_UP); TimerLoadSet(TIMER0_BASE, TIMER_A, (ui32ClockFreq / 1000)); // Enable timer interrupt TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); IntEnable(INT_TIMER0A); // Enable timer to trigger ADC TimerControlTrigger(TIMER0_BASE, TIMER_A, true); // Enable timer TimerEnable(TIMER0_BASE, TIMER_A); } void init_adc(void) { // Enable GPIO peripheral (ADC input) clock and check that it's ready SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)); // Set PE5 to be ADC input GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5); // Enable ADC peripheral clock and check that the peripheral is ready SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)); // Disable before configuring ADCSequenceDisable(ADC0_BASE, 0); /* * ADC0 * Sequencer 0, which has FIFO depth of 8 * Triggered by processor * Highest priority */ ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0); /* * ADC0 * Sequencer 0 * Step 0 * Config: Channel 9 (PE4), Last step in sequence, Triggers interrupt */ ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH9 | ADC_CTL_END /*| ADC_CTL_IE*/); // Set reference to be internal 3V ADCReferenceSet(ADC0_BASE, ADC_REF_INT); // Register and enable ADC interrupt //ADCIntEnable(ADC0_BASE, 3); // Set to use uDMA interrupt // The uDMA will send a dma_done mesage to the adc, which will trigger interrupt ADCIntEnableEx(ADC0_BASE, 0);//ADC_INT_DMA_SS3); ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); //ADCIntDisableEx(ADC0_BASE, ADC_INT_SS3 | ADC_INT_SS2 | ADC_INT_SS1 | ADC_INT_SS0); IntEnable(INT_ADC0SS0); // Enable DMA //ADCSequenceDMAEnable(ADC0_BASE, 3); // Enable ADC ADCSequenceEnable(ADC0_BASE, 0); } void init_uDMA(void) { // Enable uDMA peripheral clock and check that it's ready SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)); uDMAEnable(); // Enable uDMA uDMAControlBaseSet(&pui8DMAControlTable[0]); // Set the base for channel control table uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALL); // Disable all attributes of the ADC uDMA channel (not needed) /* * Set the ADC0 sequencer 3 primary control structure * Size of each transfer will be 16 bits long * Source address does not increment because sequencer 3 has a FIFO of size 1 (uint32_t) * Destination address increments by 16 bits because our word sizes are 16 bits (althogh we only use 12) * Arbitration size is 1 because we are only sending 1 item each time (again, since the FIFO is size 1) */ uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); /* Set the ADC0 sequencer 3 alternate control structure */ /* Setting should be identical to that of the primary structure */ uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1); uDMADisable(); } void start_uDMA(void) { UARTprintf("Beginning uDMA...\n"); // Disable the channel for configuration uDMAChannelDisable(UDMA_CHANNEL_ADC0); /* * Set the ADC0 sequencer 3 primary channel transfer parameters * Ping Pong mode * Source address is the address of the FIFO of sequencer 3 of ADC0 * Destination address is the buffer used to store the samples * The number of items transferred in total is given in ADC_BUF_SIZE */ uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), pui16AdcPriBuffer, ADC_BUF_SIZE); /* Do the same for the alternate structure */ uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), pui16AdcAltBuffer, ADC_BUF_SIZE); // Enable the channel uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enable the adc for this ADCSequenceDMAEnable(ADC0_BASE, 0); uDMAEnable(); } void init_hardware(void) { // Configure on-board led SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); // Wait for the peripheral to be ready, for debugging while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)); // Set LED pin as output GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0); init_clock(); init_uart(); init_timer(); init_adc(); init_uDMA(); } int main(void) { init_hardware(); mode = MODE_IDLE; while (1) { // Idle mode if (mode == MODE_IDLE) { // Wait for char input to trigger uDMA while (!UARTCharsAvail(UART0_BASE)); UARTCharGetNonBlocking(UART0_BASE); start_uDMA(); mode = MODE_UDMA; } // Printing mode if (mode == MODE_PRINT) { // Print the contents of the ADC buffer print_ADC_buffer(); mode = MODE_IDLE; } } }