Hello,
Sometime ago I got some help with the ADC part of my project, and it was all working fine, however now I noticed I am getting more points then expected for a given period of acquisition.
I am using a TM4C123 launchpad board and this is how i set up the frequency of acquisition of ADC:
uint32_t ui32convrate = 7000;
uint32_t ui32period = SysCtlClockGet()/ui32convrate;
Clock is running at 20MHz, and that is what I get when I print the value of SysCtlClockGet() value.
So I was expecting a 7K samples per second conversion rate, and since I average every 4 samples, I was counting on 1750 samples/second per channel. However, i am getting more than that.
When I printed the ui32period value I get 2285 instead of 2857 (value returned by the calculator of 20000000/7000).
If i got this right, ui32period is the number of revolutions of the system clock to make one revolution of the virtual ADC clock, which with this value gives 1/20M * 2285 = 0.000114 acquisiton period, which is equivalent to 8752Hz and not 7000.
There's probably something about the ADC setup that I am not quite getting, but I'd like some help understanding this so I can figure out why acquisiton is over the 1750 samples/second i wanted. If it has to do with the clock setup or maybe some other part of my code.
I attached my code.
//
// PS3chan.c
//
//
// Created by Ricardo Cabrita on 25/01/16.
//
//
// Includes ------------------------------------------------------------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_i2c.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/adc.h"
#include "driverlib/timer.h"
#include "utils/uartstdio.h"
#include "utils/ringbuf.h"
// Defines -------------------------------------------------------------------------------------------
#define LED_RED GPIO_PIN_1
#define LED_BLUE GPIO_PIN_2
#define LED_GREEN GPIO_PIN_3
//#define ch1 0001000000000000
// Variables -----------------------------------------------------------------------------------------
uint32_t ui32Seq0Value[4] = {0,0,0,0},ui32Seq1Value[4] = {0,0,0,0}, ui32Seq2Value[4] = {0,0,0,0};
uint32_t averagedADC1,averagedADC2,averagedADC3;
uint32_t ui32Baud = 1000000;
//Ring Buffer Variables
tRingBufObject adcBuff;
uint32_t buffSize = 20000;
uint8_t ui8buff[20000];
//Tracker Variables
float wAVG1 = 0, wAVG2 = 0, wAVG3 = 0;
uint32_t time_stamps = 1;
// Functions -----------------------------------------------------------------------------------------
void ADCinit(uint32_t ui32period){
//Initialize ADC
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //Pin for ADC input
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //ADC peripheral
//Enable Timer 0
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
//Pins used for ADC channels (3)
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1); //set GPIO_E3 for channel 1
//GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2); //set GPIO_E2 for channel 2
//GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1); //set GPIO_E1 for channel 3
ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0); //sequencer 0
ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 1); //sequencer 1
ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_TIMER, 2); //sequencer 2
//sequencer 0
ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH0 | ADC_CTL_END);
//sequencer 1
ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH1 | ADC_CTL_END);
//sequencer 2
ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 2, 1, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 2, 2, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 2, 3, ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END);
//
//Initialize Timer 0 to trigger an ADC conversion
//
TimerConfigure(TIMER0_BASE,TIMER_CFG_PERIODIC);
TimerLoadSet(TIMER0_BASE,TIMER_A,ui32period-1); // sampling rate
TimerEnable(TIMER0_BASE, TIMER_A);
TimerControlTrigger(TIMER0_BASE,TIMER_A,true);
ADCSequenceEnable(ADC0_BASE,0);
ADCSequenceEnable(ADC0_BASE, 1);
ADCSequenceEnable(ADC0_BASE, 2);
//ADCIntEnable(ADC0_BASE,0);
ADCIntEnable(ADC0_BASE,2);
//IntEnable(INT_ADC0SS1);
}
void ConfigureUART1(void){
// Enable the peripherals used by UART
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
// Set GPIO A0 and A1 as UART pins.
GPIOPinConfigure(GPIO_PB0_U1RX);
GPIOPinConfigure(GPIO_PB1_U1TX);
GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// Configure UART clock using UART utils
UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(1, ui32Baud, 16000000);
}
void ADC0IntHandler(void){
//short a,b;
uint8_t putme[24];
uint32_t avgSeq0, avgSeq1, avgSeq2;
//Clear ADC interrupt here if interrupt is Light Cycle and small nr of instructions
//ADCIntClear(ADC0_BASE,1);
//get averaged data from the ADC
ADCSequenceDataGet(ADC0_BASE,0,ui32Seq0Value);
ADCSequenceDataGet(ADC0_BASE,1,ui32Seq1Value);
ADCSequenceDataGet(ADC0_BASE,2,ui32Seq2Value);
avgSeq0 = (ui32Seq0Value[0]+ui32Seq0Value[1]+ui32Seq0Value[2]+ui32Seq0Value[3])/4;
avgSeq1 = (ui32Seq1Value[0]+ui32Seq1Value[1]+ui32Seq1Value[2]+ui32Seq1Value[3])/4;
avgSeq2 = (ui32Seq2Value[0]+ui32Seq2Value[1]+ui32Seq2Value[2]+ui32Seq2Value[3])/4;
//write to RingBuffer (all values without averaging)
/*putme[0] = ui32Seq0Value[0] & 0xff; //Chan0 (0)
putme[1] = ui32Seq0Value[0] >> 8;
putme[2] = ui32Seq1Value[0] & 0xff; //Chan1 (0)
putme[3] = ui32Seq1Value[0] >> 8;
putme[4] = ui32Seq2Value[0] & 0xff; //Chan2 (0)
putme[5] = ui32Seq2Value[0] >> 8;
putme[6] = ui32Seq0Value[1] & 0xff; //Chan0 (1)
putme[7] = ui32Seq0Value[1] >> 8;
putme[8] = ui32Seq1Value[1] & 0xff;//Chan1 (1)
putme[9] = ui32Seq1Value[1] >> 8;
putme[10] = ui32Seq2Value[1] & 0xff;//Chan2 (1)
putme[11] = ui32Seq2Value[1] >> 8;
putme[12] = ui32Seq0Value[2] & 0xff;//Chan0 (2)
putme[13] = ui32Seq0Value[2] >> 8;
putme[14] = ui32Seq1Value[2] & 0xff;//Chan1 (2)
putme[15] = ui32Seq1Value[2] >> 8;
putme[16] = ui32Seq2Value[2] & 0xff;//Chan2 (2)
putme[17] = ui32Seq2Value[2] >> 8;
putme[18] = ui32Seq0Value[3] & 0xff;//Chan0 (3)
putme[19] = ui32Seq0Value[3] >> 8;
putme[20] = ui32Seq1Value[3] & 0xff;//Chan1 (3)
putme[21] = ui32Seq1Value[3] >> 8;
putme[22] = ui32Seq2Value[3] & 0xff;//Chan2 (3)
putme[23] = ui32Seq2Value[3] >> 8;*/
//send averaged values
putme[0] = avgSeq0 & 0xff; //Chan0 (0)
putme[1] = avgSeq0 >> 8;
putme[2] = avgSeq1 & 0xff; //Chan1 (0)
putme[3] = avgSeq1 >> 8;
putme[4] = avgSeq2 & 0xff; //Chan2 (0)
putme[5] = avgSeq2 >> 8;
//Debug
//UARTprintf("chan0:%d | %d | %d | %d \n",ui32Seq0Value[0],ui32Seq0Value[1],ui32Seq0Value[2],ui32Seq0Value[3]);
//UARTprintf("chan1:%d | %d | %d | %d \n",ui32Seq1Value[0],ui32Seq1Value[1],ui32Seq1Value[2],ui32Seq1Value[3]);
//UARTprintf("chan2:%d | %d | %d | %d \n",ui32Seq2Value[0],ui32Seq2Value[1],ui32Seq2Value[2],ui32Seq2Value[3]);
if(RingBufFull(&adcBuff)){ //light RED LED if buffer is full (means lost data)
GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, LED_RED);
}
RingBufWrite(&adcBuff,putme,6);
//otherwise clear here (might loose some data points)
//ADCIntClear(ADC0_BASE,0);
ADCIntClear(ADC0_BASE,2);
}
void printADC(){
uint8_t readme[6];
uint16_t chan1, chan2, chan3;
uint16_t bufload;
uint32_t send1,send2;
uint32_t start = 122, checksum; // 0x00FF start byte
bufload = RingBufUsed(&adcBuff);
if(bufload>6){
RingBufRead(&adcBuff,readme,6);
chan1 = readme[1];
chan1 = (chan1 << 8)+readme[0];
chan2 = readme[3];
chan2 = (chan2 << 8)+readme[2];
chan3 = readme[5];
chan3 = (chan3 << 8)+readme[4];
//UARTprintf("chan1:%d | chan2:%d | chan3:%d\n",chan1,chan2,chan3); //for putty
//check sum
checksum = chan1 ^ chan2 ^ chan3;
//prepare stream to send, 7 bytes in send1 and send2
// start byte + chan1 + chan2 + chan3 + checksum:
send1 = chan2 << 20; //put chan2 in the enf of send1
send1 = send1 + (chan1<<8);//add chan1 and leave room for start byte
send1 = send1 + start; //add start byte to stream
send2 = checksum << 12; //put checksum and leave space for chan3
send2 = send2 + chan3; //add chan3
UARTCharPut(UART1_BASE,send1); //start byte
UARTCharPut(UART1_BASE,send1 >> 8); //least sig byte of chan1
UARTCharPut(UART1_BASE,send1 >> 16); //4 most sig bits of chan1 and least sig 4 bits of chan2
UARTCharPut(UART1_BASE,send1 >> 24); //most sig byte of chan2
UARTCharPut(UART1_BASE,send2); // least sig byte of chan3
UARTCharPut(UART1_BASE,send2 >> 8); //4 most sig bits of chan3 and least sig 4 bits of checksum
UARTCharPut(UART1_BASE,send2 >> 16); //most sig byte of checksum
}
}
// Main ----------------------------------------------------------------------------------------------
int main(void){
uint32_t ui32convrate = 7000;
uint32_t ui32period = SysCtlClockGet()/ui32convrate;
// Enable lazy stacking
FPULazyStackingEnable();
//Initialize circular buffer
RingBufInit(&adcBuff,ui8buff,buffSize);
// Set the system clock to run at 20Mhz off PLL with external crystal as reference.
SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
// Initialize the UART and write status.
ConfigureUART1();
UARTprintf("ADC CRASH OVERRIDE!! Using clock %d and period %d\n", SysCtlClockGet(),ui32period);
// Enable LEDs
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, LED_RED|LED_BLUE|LED_GREEN);
GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, LED_BLUE);
//Initialize ADC
ADCinit(ui32period);
//UARTprintf("ADC Sequence Initiated!\n");
ADCIntClear(ADC0_BASE,2);
ADCIntEnable(ADC0_BASE,2);
IntEnable(INT_ADC0SS2);
IntMasterEnable();
// Create print variables
while(1){
printADC();
}
}
thanks everyone,
Ricardo Cabrita