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