//############################################################################## void setupADC(void) { //ADC defaults to 1Msps sampling rate ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_ADC0); ROM_SysCtlPeripheralEnable (SYSCTL_PERIPH_ADC1); ROM_ADCReferenceSet(ADC0_BASE,ADC_REF_EXT_3V); ROM_ADCReferenceSet(ADC1_BASE,ADC_REF_EXT_3V); //Hardware averaging implementation (ADC, samples) //Hardware averaging implementation (ADC, samples) ROM_ADCHardwareOversampleConfigure (ADC0_BASE, 4); //can go up to 64 ROM_ADCHardwareOversampleConfigure (ADC1_BASE, 4); // ROM_ADCHardwareOversampleConfigure(ADC0_BASE, 0); //0 disables oversampling, can go up to 64 // ROM_ADCHardwareOversampleConfigure(ADC1_BASE, 0); //ADC, Sequencer, trigger, priority //setting priority in this order will make sure that sequencer restarts when sequencer 1 finishes ROM_ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);//module, sequencer, interrupt, priority ROM_ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 1); ROM_ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);//module, sequencer, interrupt, priority ROM_ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_PROCESSOR, 1); //Module, sequencer, step, channel ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0); //IMON_1 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1); //VMON1_1 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2); //VMON2_1 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH3); //TCASE_1 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH4); //IMON_2 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH5); //VMON1_2 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH6); //VMON2_2 ROM_ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END); //TCASE_2 ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH19); //IMON_4 ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH20); //VMON1_3 ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH21); //IMON_3 ROM_ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END); //MCU Temp ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH8); //TCASE_3 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 1, ADC_CTL_CH9); //VMON2_3 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 2, ADC_CTL_CH10); //IMON2_1 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 3, ADC_CTL_CH11); //IMON2_2 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 4, ADC_CTL_CH12); //IMON2_3 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 5, ADC_CTL_CH13); //IMON2_4 ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 6, ADC_CTL_CH14); //spare reading ROM_ADCSequenceStepConfigure(ADC1_BASE, 0, 7, ADC_CTL_CH15 | ADC_CTL_IE | ADC_CTL_END); //spare reading ROM_ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH16); //TCASE_4 ROM_ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH17); //VMON2_4 ROM_ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH18 | ADC_CTL_IE | ADC_CTL_END); //VMON1_4 ROM_ADCSequenceEnable (ADC0_BASE, 0); //8 samples 0-7 ROM_ADCSequenceEnable (ADC0_BASE, 1); //4 samples 19-21, MCU Temp ROM_ADCSequenceEnable (ADC1_BASE, 0); //8 samples 8-15 ROM_ADCSequenceEnable (ADC1_BASE, 1); //3 samples 16-18 } //############################################################################## void readADC(void) { struct Reg *reg = allBanks[gen]; int count = 0; /* unsigned int timeout = getFutureTime(.004f); //clear ADC sample done flag on sequencer ROM_ADCIntClear(ADC0_BASE, 0); ROM_ADCIntClear (ADC0_BASE, 1); ROM_ADCIntClear(ADC1_BASE, 0); ROM_ADCIntClear (ADC1_BASE, 1); //ADC conversion trigger by sequencer ROM_ADCProcessorTrigger (ADC0_BASE, 0); ROM_ADCProcessorTrigger (ADC0_BASE, 1); ROM_ADCProcessorTrigger (ADC1_BASE, 0); ROM_ADCProcessorTrigger (ADC1_BASE, 1); */ //Get the data from the sequencer FIFO and store into buffer //assume that ADCs read in same order as appear in register map ROM_ADCSequenceDataGet (ADC0_BASE, 0, ui32ADC0_sq0); for (count = 0; count < 8; count++) { //ADCs 0-7 reg[count + ADC0_RAW].data.ui = ui32ADC0_sq0[count]; } ROM_ADCSequenceDataGet (ADC0_BASE, 1, ui32ADC0_sq1); for (count = 0; count < 4; count++) { //ADCs 19-21, temp reg[count + ADC19_RAW].data.ui = ui32ADC0_sq1[count]; } ROM_ADCSequenceDataGet (ADC1_BASE, 0, ui32ADC1_sq0); for (count = 0; count < 8; count++) { //ADCs 8-15 reg[count + ADC8_RAW].data.ui = ui32ADC1_sq0[count]; } ROM_ADCSequenceDataGet (ADC1_BASE, 1, ui32ADC1_sq1); for (count = 0; count < 3; count++) { //ADCs 16-18, temp reg[count + ADC16_RAW].data.ui = ui32ADC1_sq1[count]; } dataCaptured = true; } //############################################################################## void triggerADCSample(void) { //clear ADC sample done flag on sequencer ROM_ADCIntClear(ADC0_BASE, 0); ROM_ADCIntClear (ADC0_BASE, 1); ROM_ADCIntClear(ADC1_BASE, 0); ROM_ADCIntClear (ADC1_BASE, 1); //ADC conversion trigger by sequencer ROM_ADCProcessorTrigger (ADC0_BASE, 0); ROM_ADCProcessorTrigger (ADC0_BASE, 1); ROM_ADCProcessorTrigger (ADC1_BASE, 0); ROM_ADCProcessorTrigger (ADC1_BASE, 1); //clear trigger flag and wait for ADC sampling to be captured dataCaptured = false; } //declared in ...startup_ccs.c interrupt vector file, ~every 40us //############################################################################## void SSIADCIntHandler(void) { unsigned long status; status = GPIOIntStatus(GPIO_PORTJ_BASE, true); //if interrupt on DRDY, this function must finish before DRDY asserted low again if (status & GPIO_INT_PIN_0) { //clear interrupt status GPIOIntClear(GPIO_PORTJ_BASE, GPIO_INT_PIN_0); //fixme if timing is too tough, internal just needs to be once in every 4 cycles //start internal ADC reading if(dataCaptured) triggerADCSample(); //negative buffer so that can eventually catch up if out of sync ROM_SSIDataGetNonBlocking(SSI0_BASE, &SSIADCDataRx[0]); //buffer out data to gather direct read of channel //Frame the transmit data with CS ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, 0);//CS low //buffer out dummy data ROM_SSIDataPutNonBlocking (SSI0_BASE, SSIADCDataTx[0]); ROM_SSIDataPutNonBlocking (SSI0_BASE, SSIADCDataTx[1]); getData = true; //ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_5, 0xFF);//CS high, do this in interrupt and then grab data } } //############################################################################## /* * Control Loop */ //############################################################################## int main(void) { int i; //FIXME check for warmboot mainInit(); //setupADC(); called in here, no reason to post this code otherwise //control loop /*while(true)//TESTING { writePWMModule(tec0); }*/ triggerADCSample(); while(true) { ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_7, LED_STATUS_MASK); flash(true); //grab internal ADC data if ready, Fixme want to have completed by next external interrupt if ((ROM_ADCIntStatus (ADC0_BASE, 1, false)) && (ROM_ADCIntStatus (ADC1_BASE, 1, false)) && (ROM_ADCIntStatus (ADC0_BASE, 0, false)) && (ROM_ADCIntStatus (ADC1_BASE, 0, false))) { readADC(); } ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_7, 0x00); flash(false); }
}
I am trying to run through all the ADC channels on a TM4C1231H6PZI. I enable both ADC module 0 and 1 with sequencers 0 and 1 of each. I understand that the modules can run separately and I can trigger the sampling of another sequencer through a processor trigger. With sequencer 0 FIFO depth of 8 and sequencer 1 FIFO depth of 4 I should be able to read all 22 (+1 internal MCU temperature). I initialized the AIN pins using the pinMux utility as well as enable each ADC module. I am trying to run the sampling at the full 1MSPS rate and will trigger a new set of samples every 4us unless the conversions are not complete, then I wait for the next cycle in my control loop. While running this code I see that I get large glitches every so often in my ADC readings. When parsing through the data, these glitches seem to happen most often on ADC 1 sequencer 0, but I saw the issue once on ADC 0 sequencer 0. I have looked at my AIN input signals on a scope and the glitches do not seem to be real. I even tried swapping the input signals on ADC0, seq0 with ADC1,seq0 signals and the issue seemed to persist on ADC1, seq 0. In fact the raw data seems to suggest that the sequencer sometimes randomly samples a different sample in the sequence. The channel that is randomly sampled is not always the channel next to the expected channel, but it is always a channel from that is to be sampled in the same sequencer. Also although this is not the main issue, I tried turning on HW averaging to lessen the impact of these rogue samples, but with averaging of 8 or more the ADC raw values stop updating even when the input signals are clearly different. The code snippets from my project are above:
MAP_SysCtlPeripheralEnable and MAP_GPIOPinTypeADC calls are done automatically in the pinMux generated c file