Hi all,
I'm having an issue with a TM4C123G LaunchPad. I'm using Keil uvision 4 for programming. I'll try to make this as brief as possible:
My program has to acquire data from 3 ADC channels, process it, and send it via the UART. I use Timer 0 and systick interrupts.
Sequence is:
1) Configure every peripheral involved.
2) Receive a specific string from UART 0 Rx channel.
3) Enable Timer 0 A, Systick and ADC Interrupts. Systick increases a counter every 5msecs..
4) When a Timer 0 interrupt occurs, trigger an ADCProcessor conversion.
5) When a ADCInterrupt occurs (I've configured it to occur upon last conversion of the sequencer), save the ADC data in three different arrays (one for each channel), and also save the Time-stamp (i.e the Systick counter) in another array. This way, I have a sample with its corresponding time (give or take a few cycles).
6) When X amount of adquisitions are completed, disable the interrupts, and start a routine to transfer the data via the UART 0.
The problem is, the adquisition is running VERY SLOWLY. It collects something like 15 samples in... 9 seconds!.
I believe the problem may be originated in some type of interruption-crossfire (one interrupt is triggered before another one is completed, or there is some interrupt that's taking just too much processor...)
Or perhaps I've made some mistake in this peripherals configuration.
For the sake of clarity, I'm gonna attach here only the code regarding the ADC, Timer0 and UART configuration.
//UART 0
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // Configure PA0 & PA1 for UART mode.
ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); // Use 16Mhz Internal oscillator as UART clock source.
UARTStdioConfig(0, 115200, 16000000); // Initialize UART for I/O console.
ROM_IntEnable(INT_UART0);
ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT); // Enable Rx and Rt interruptions
//Timers & Systick
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // Timer 0, to trigger ADC adquisitions.
// Enable processor Interrupts
ROM_IntMasterEnable();
// Configure 32bits periodic timer.
ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet()*3);
ROM_IntEnable(INT_TIMER0A);
ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // Configure interrupts.
//Enable Timer0
// ROM_TimerEnable(TIMER0_BASE, TIMER_A);
// Enable Systick every 5msecs
ROM_SysTickPeriodSet(100000); // 5ms @ 20MHz
ROM_SysTickIntEnable();
ROM_SysTickEnable(); // Starts count
//ADC
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
ROM_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); // Configure ADC pins: PE1,PE2,PE3.
ADCSequenceDisable(ADC0_BASE, 2); //Disable Sequencer 2 before configuring.
// Configure ADC0, sequencer 2, processor trigger and priority 0 (highest).
ROM_ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PROCESSOR, 0);
// Configure every ADC steps. Step0-Channel0, Step1-Channel1 and so on.
ROM_ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH0 );
ROM_ADCSequenceStepConfigure(ADC0_BASE, 2, 1, ADC_CTL_CH1 );
ROM_ADCSequenceStepConfigure(ADC0_BASE, 2, 2, ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END); //Last sample, enable ADC interrupt.
//This way I'm certain every sample is taken when the interrupt triggers.
ROM_ADCSequenceEnable(ADC0_BASE, 2); //Enable Sequencer 2
ROM_ADCIntClear(ADC0_BASE, 2); //Clear interrupt flag before starting.
ROM_ADCIntEnable(ADC0_BASE, 2); // Enable ADC interrupts.
Then the Interrupt Handler for the Timer0 does this:
void Timer0InterruptHandler(void)
{
ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); //Erase timer0 interrupt Flag
ADCProcessorTrigger(ADC0_BASE, 2); //Trigger ADC conversion
}
And the ADC Interrupt Handler does this:
void ADCInterruptHandler(void)
{
ROM_ADCIntClear(ADC0_BASE, 2); // Erase interruption flag
// Obtain sequencer data
ROM_ADCSequenceDataGet(ADC0_BASE, 2, &SetDatosADC[0]);
ADCInterruptIsTrue=true; // Raise a flag to process data in main loop.
}
//Then, in the Main Loop.........
if (ADCInterruptIsTrue)
{
TimeStamp[indice] = ContadormsegSystick;
// Process and convert every analog input channel.
ui32Millivolts = (SetDatosADC[0] * 4100) / 819; // Position AN0=PE3.
Position[index] = (int16_t)ui32Millivolts;
ui32Millivolts = (SetDatosADC[1] * 4100) / 819; // Strength AN1= PE2.
Strength [index] = (int16_t)ui32Millivolts;
ui32Millivolts = (SetDatosADC[2] * 4100) / 819; // Temperature AN2=PE1.
Temperature[index] = (int16_t)ui32Millivolts;
ADCInterruptIsTrue=false;
index ++;
}
I've realized I can trigger an ADCTimer conversion instead of triggering the ADCProcessor inside the Timer0 Interrupt. But, I don't know if it makes any difference regarding execution speed. Does it?
I'm not sure if the clocks settings are correct, as they seem to be different for some peripherals (Example; the UART and the Timers).
I really appreciate any feedback on this matter.
Kind Regards.
Martin