//##############################################################################
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