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.

Timer Triggered ADC with uDMA



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

}

  • Hi refe,
    > I am running the LauchPad at 40 MHz

    Perhaps you calculated Systick 1us from 16Mhz (62.5ns) and not a 40Mhz SYSCLK and though PLL why is not indicated a VCO speed?
  • BP101 said:
    and though PLL why is not indicated a VCO speed?

    You did note that poster is using a "123 device" - did you not?    (VCO speed is not "much in evidence" that part - as you know...)

    If poster made a 16/40 error - as you suggest - would not his error be FAR LESS than noted?  (16/1280)

  • Regardless the VCO frequency, (Systick default clock source) for producing @1us tick rate infers MOSC set 16Mhz as posters source and not 40Mhz as stated. Checking after reply; Tivaware allows possibility to set an alternate clock source PIOSC might be necessary if SYSCLK is actually set 40Mhz by PLL VCO frequency divisor.

    Producing 40Mhz from 16Mhz XTAL seemingly requires a PLL/VCO frequency divisor. Perhaps CB1 infers a POR value default sets VCO frequency on TM4C123 devices. Should the PLL/VCO produce SYSCLK frequency based on 16Mhz_XTAL value it would be nice to see that in source listing. Seem to recall TM4C123 a costly MCU and would expect all kinds of XTAL/PLL/VCO configurations.
  • Here's poster's code - this is quite standard for yielding 40MHZ via an external xtal. (poster notes 16MHz xtal) Had you missed this?

    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    There is NO inference - simply this long standard code line. You state that it, "Would be nice to see in source listing" - it is RIGHT THERE - is it not?

    Your 4C123 recall is completely wrong. TM4C123 is this vendor's most basic entry w/in Cortex M4 - replaced the departed LX4F.
  • Hi BP101,
    thanks for the reply. As the SysTick period is working with same config in other projects correctly I assume the SysTick period here is correct too.
  • Was referring to there is no VCO frequency specified clock configuration and one can only assume SYSCLK is thus 40Mhz or even the Systick clock source. Last time checked TI store TM4C123 launch pad cost well over $100.00 and assumed must have several kinds of bells and whistles.

    Oddly the same math (SYSCLK/1M=1us) works out the same Systick period for either 40Mhz/250ns SYSCLK or 16Mhz/62.5ns SYSCLK. Perhaps something else is going on in the source or peripheral clocking etc....
  • Even though it is a while now and a different solution was found. The mistake might have been the configuration of the µDMA Channel is set to "UDMA_MODE_AUTO" (see line 160 in example code). If this is set to "UDMA_MODE_BASIC" the results should be as expected. Maybe someone will find this helpful.
    Thanks to BP101 and cb1 for participating!
    Cheers,
    Felix