Hi all,
I am using a TM4C123G LaunchPad with CCS v.6.1.3 on Linux Mint.
What I am trying to do is setting up a Timer Triggered ADC which works with uDMA. My intension is to reduce the number of interrupts. From what I have read in other posts it should be possible to set up the ADC as Timer Triggered (in my example code with a frequency of 50 kHz) and additionally set up uDMA Transfers to a specified array of given length (in the example the buffer size is 64).
As far as I understood (and what my intension is) the uDMA is giving an interrupt every time a uDMA Transfer is completed. So in the example code it should give an interrupt after the transfer of 64 elements. So what I would expect is that the ADC ISR is getting called every 64 * (1/50.000) s = 1280 µs
Unfortunately this is not the case and the ISR gets called every ~16 µs. Which is close to the timer frequency. As I am setting the buffer to a size of 256 the elapsed time before entering the ISR is increasing, which is telling me the uDMA config is somewhat correct.
Attached is the example code. I am running the LauchPad at 40 MHz, am setting up the Peripherals and do the initalization of the ADC and uDMA. The SysTick Period is set so 1µs. For testing purposes I am only using a single ADC input pin.
If someone is able to help me I would be very thankful.
Thanks in advance and regards,
Felix
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_udma.h"
#include "inc/hw_emac.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/adc.h"
#include "driverlib/udma.h"
#include "driverlib/emac.h"
#include "driverlib/timer.h"
#define TARGET_IS_BLIZZARD_RB1
#include "driverlib/rom.h"
#define ADC_SAMPLE_BUF_SIZE 64
#pragma DATA_ALIGN(ucControlTable, 1024)
uint8_t ucControlTable[1024];
static uint16_t ADC_OUT[ADC_SAMPLE_BUF_SIZE];
uint32_t n=0;
void init_ADC();
static uint32_t g_ui32DMAErrCount = 0;
static uint32_t g_ui32SysTickCount;
volatile uint32_t start, stop;
void uDMAErrorHandler(void)
{
uint32_t ui32Status;
ui32Status = ROM_uDMAErrorStatusGet();
if(ui32Status)
{
ROM_uDMAErrorStatusClear();
g_ui32DMAErrCount++;
}
}
void
SysTickIntHandler(void)
{
//
// Update our system tick counter.
//
g_ui32SysTickCount++;
}
void ADCseq0Handler()
{
stop = g_ui32SysTickCount;
ADCIntClear(ADC0_BASE, 0);
n++;
if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_ADC0))
{
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_AUTO, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
uDMAChannelEnable(UDMA_CHANNEL_ADC0);
}
start = stop;
}
int main(void)
{
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
SysCtlDelay(20);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //Enable the clock to ADC module
SysCtlDelay(10); // Time for the peripheral enable to set
SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
SysCtlDelay(10);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
SysCtlDelay(30);
ROM_SysTickPeriodSet(SysCtlClockGet() / 1000000);
ROM_SysTickIntEnable();
ROM_SysTickEnable();
ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet()/50000 -1); //TODO: Timer Load Value is set here
ROM_TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
SysCtlDelay(80);
IntMasterEnable();
init_ADC();
TimerEnable(TIMER0_BASE, TIMER_A);
start = g_ui32SysTickCount;
while(1)
{
}
}
void init_ADC()
{
//ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_HALF, 1);
SysCtlDelay(10); // Time for the clock configuration to set
IntDisable(INT_ADC0SS0);
ADCIntDisable(ADC0_BASE, 0);
ADCSequenceDisable(ADC0_BASE,0);
// With sequence disabled, it is now safe to load the new configuration parameters
ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH1| ADC_CTL_END | ADC_CTL_IE);
ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer
ADCIntClear(ADC0_BASE,0);
uDMAEnable(); // Enables uDMA
uDMAControlBaseSet(ucControlTable);
ADCSequenceDMAEnable(ADC0_BASE,0);
// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
// Only allow burst transfers
uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1024);
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_AUTO, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
ADCIntEnable(ADC0_BASE,0);
IntEnable(INT_ADC0SS0);
uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers
}