Hi
I have copied the adcOffsetSelfCal() and its dependent functions from the piccolo example files and is called when I set up the ADCs for use after device initialisation and before my main loop starts.
However in the function adcConversion() the SOC 0-7 are initially forced to start the "ping-pong" sampling, and in my code this causes a ISR_ILLEGAL interrupt to be raised. I dont understand why.
If I set it so the while() that comes after the force only runs once it seems to run OK, but if I comment out the force, the while runs OK... adcConversion() is below
static Uint16 adcConversion(void) { // This function initiates several ADC conversions and returns the average. It uses ADCINT1 and ADCINT2 // to "ping-pong" between SOC0-7 and SOC8-15 and is referred to as "ping-pong" sampling // * IMPORTANT * This function will overwrite previous ADC settings Uint16 index; Uint16 sampleSize; Uint16 mean; Uint16 AcqpsVal; Uint16 i; Uint32 sum; index = 0; // Initialize index to 0 sampleSize = 256; // Set sample size to 256 (**NOTE: Sample size must be multiples of 2^x where is an integer >= 4) sum = 0; // Set sum to 0 mean = 999; // Initialize mean to known value AcqpsVal = 6; // Set the ADC sample window to the desired value (Sample window = ACQPS + 1) AdcRegs.ADCSOC0CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC1CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC2CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC3CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC4CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC5CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC6CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC7CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC8CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC9CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC10CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC11CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC12CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC13CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC14CTL.bit.ACQPS = AcqpsVal; AdcRegs.ADCSOC15CTL.bit.ACQPS = AcqpsVal; // Enable ping-pong sampling AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enabled ADCINT1 and ADCINT2 AdcRegs.INTSEL1N2.bit.INT2E = 1; AdcRegs.INTSEL1N2.bit.INT1CONT = 0; // Disable continuous sampling for ADCINT1 and ADCINT2 AdcRegs.INTSEL1N2.bit.INT2CONT = 0; AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;//ADCINTs trigger at end of conversion // Setup ADCINT1 and ADCINT2 trigger source AdcRegs.INTSEL1N2.bit.INT1SEL = 6; // EOC6 triggers ADCINT1 AdcRegs.INTSEL1N2.bit.INT2SEL = 14; // EOC14 triggers ADCINT2 // Setup each SOC's ADCINT trigger source AdcRegs.ADCINTSOCSEL1.bit.SOC0 = 2; // ADCINT2 starts SOC0-7 AdcRegs.ADCINTSOCSEL1.bit.SOC1 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC2 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC3 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC4 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC5 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC6 = 2; AdcRegs.ADCINTSOCSEL1.bit.SOC7 = 2; AdcRegs.ADCINTSOCSEL2.bit.SOC8 = 1; // ADCINT1 starts SOC8-15 AdcRegs.ADCINTSOCSEL2.bit.SOC9 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC10 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC11 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC12 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC13 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC14 = 1; AdcRegs.ADCINTSOCSEL2.bit.SOC15 = 1; DELAY_US(1000); // Delay 1ms before converting ADC channels //ADC Conversion AdcRegs.ADCSOCFRC1.all = 0x00FF; // Force Start SOC0-7 to begin ping-pong sampling while( index < sampleSize ){ while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0){} // Wait for ADCINT1 to trigger, then add ADCRESULT0-7 registers to sum AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // Must clear ADCINT1 flag since INT1CONT = 0 sum += AdcResult.ADCRESULT0; sum += AdcResult.ADCRESULT1; sum += AdcResult.ADCRESULT2; sum += AdcResult.ADCRESULT3; sum += AdcResult.ADCRESULT4; sum += AdcResult.ADCRESULT5; sum += AdcResult.ADCRESULT6; sum += AdcResult.ADCRESULT7; while (AdcRegs.ADCINTFLG.bit.ADCINT2 == 0){} // Wait for ADCINT2 to trigger, then add ADCRESULT8-15 registers to sum AdcRegs.ADCINTFLGCLR.bit.ADCINT2 = 1; // Must clear ADCINT2 flag since INT2CONT = 0 sum += AdcResult.ADCRESULT8; sum += AdcResult.ADCRESULT9; sum += AdcResult.ADCRESULT10; sum += AdcResult.ADCRESULT11; sum += AdcResult.ADCRESULT12; sum += AdcResult.ADCRESULT13; sum += AdcResult.ADCRESULT14; sum += AdcResult.ADCRESULT15; index+=16; } AdcRegs.INTSEL1N2.bit.INT1E = 0; // Disable ADCINT1 and ADCINT2 to STOP the ping-pong sampling AdcRegs.INTSEL1N2.bit.INT2E = 0; mean = sum / sampleSize; // Calculate average ADC sample value return mean; }
Looking over the code, everything looks fine. Are you sure that the EALLOW bit is set before this function is called? The INTSEL1N2 registers are EALLOW protected (as are some of the other registers being accessed in the function).
I didn't follow how calling the adcOffsetSelfCal() related to your issue. Did the issue begin after you put the function call in your code?
Hi Devin
Thanks for your response. My adcInit() calls adcOffsetSelfCal() which itself calls two functions adcChanSelect() and adcConversion, the 3 of which are direct from the example files. The issue began after I started trying to call adcOffsetCal() from my adcInit()
Though I did have problems with my multiple EDIS; being called (thanks for mentioning that) this doesnt seem to have solved the problem.
I have noticed that If I comment out the CPU enabling of the interrupt generated by the EOC of my regular ADC readings (i.e. at the end of adcInit()) then the ISR_ILLEGAL is not raised... however this leaves me with no interrupt for my actual ADC results... So I guess i must have some error with my interrupt occurring?
Below I have included my adcInit(), adcOffsetSelfCal() and adcChanSelect() functions:
void adcInit(void) { // Setup ADC A1, B1 & B2 to be triggerd by at 10kHz PWM3B // ADCs use round robin, so ADC B2 is last and when it's // finished it triggers ADC interrupt 1 (ADCINT1) EALLOW; AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; // Use internal bandgap AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; // Power up band gap AdcRegs.ADCCTL1.bit.ADCPWDN = 1; // Power up rest of ADC AdcRegs.ADCCTL1.bit.ADCREFPWD = 1; // Power up reference AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // Enable ADC DELAY_US(1000); // Wait 1ms for ADC to power on adcOffsetSelfCal(); // Calibrate ADC zero offset AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1;// Create interrupt pulses 1 cycle prior to result output latch // SOC0 must be read then discarded as part of workaround for first sample errata AdcRegs.ADCSOC0CTL.bit.CHSEL = 9; // Convert ADC-B1 (CH1) when SOC0 is recieved AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 9; // Set SOC0 to be triggered by ADCTRIG9 (ePWM3, ADCSOCA), // due to round robin, this will be first conversion AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // Set SOC0 S/H window to 7 ADC clk cycles (6 ACQPS plus 1) AdcRegs.ADCSOC1CTL.bit.CHSEL = 9; // Convert ADC-B1 (CH1) (I_pk) when SOC1 is recieved AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 9; // Set SOC1 to be triggered by ADCTRIG9 (ePWM3, ADCSOCA), // due to round robin, this will be second conversion AdcRegs.ADCSOC1CTL.bit.ACQPS = 6; // Set SOC1 S/H window to 6 clk cycles (117ns) AdcRegs.ADCSOC2CTL.bit.CHSEL = 10; // Convert ADC-B2 (CH2) (V_dc) when SOC2 is recieved AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 9; // Set SOC2 to be triggered by ADCTRIG9 (ePWM3, ADCSOCA), // due to round robin, this will be third conversion AdcRegs.ADCSOC2CTL.bit.ACQPS = 6; // Set SOC2 S/H window to 6 clk cycles (117ns) AdcRegs.INTSEL1N2.bit.INT1SEL = 2; // EOC2 causes ADCINT1 AdcRegs.INTSEL1N2.bit.INT1E = 1; // Enable ADC interrupt 1 PieVectTable.ADCINT1 = &adc_isr; // Map ADCINT 1 to ADC ISR EDIS; AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;// Clear ADCINT1 flag setPwm(&EPwm3Regs, 10000, 0, 0); // Set ePWM3 time-base to 10 kHz // Set ePWM3B event trigger to ADCTRIG9 (ADCSOCA) EPwm3Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group EPwm3Regs.ETSEL.bit.SOCASEL = 1; // Select SOC from ZRO EPwm3Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on first event PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block PieCtrlRegs.PIEIER10.bit.INTx1 = 1; // Enable PIE Group 10 - INT1 IER |= M_INT10; // Enable CPU INT1 } void adcOffsetSelfCal(void) { // This function re-calibrates the ADC zero offset error by converting the VREFLO reference with // the ADC and modifying the ADCOFFTRIM register. VREFLO is sampled by the ADC using an internal // MUX select which connects VREFLO to A5 without sacrificing an external ADC pin. Uint16 AdcConvMean; //EALLOW; AdcRegs.ADCCTL1.bit.ADCREFSEL = 0; //Select internal reference mode AdcRegs.ADCCTL1.bit.VREFLOCONV = 1; //Select VREFLO internal connection on B5 adcChanSelect(13); //Select channel B5 for all SOC AdcRegs.ADCOFFTRIM.bit.OFFTRIM = 80; //Apply artificial offset (+80) to account for a negative offset that may reside in the ADC core AdcConvMean = adcConversion(); //Capture ADC conversion on VREFLO AdcRegs.ADCOFFTRIM.bit.OFFTRIM = 80 - AdcConvMean; //Set offtrim register with new value (i.e remove artical offset (+80) and create a two's compliment of the offset error) AdcRegs.ADCCTL1.bit.VREFLOCONV = 0; //Select external ADCIN5 input pin on B5 //EDIS; } static void adcChanSelect(Uint16 chNo) { // This function selects the ADC channel to convert by setting all SOC channel selects to a single channel. // * IMPORTANT * This function will overwrite previous SOC channel select settings AdcRegs.ADCSOC0CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC1CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC2CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC3CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC4CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC5CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC6CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC7CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC8CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC9CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC10CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC11CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC12CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC13CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC14CTL.bit.CHSEL = chNo; AdcRegs.ADCSOC15CTL.bit.CHSEL = chNo; }
If I power down the ADC core and then power it up again after the self cal and before the ADC is setup for normal use then there appears to be no errors.
However, having added all ADC registers to the watch window there appears to be no difference between Initialising with the self cal or without other than the ADCBUSYCHAN bits in ADCCTL1... these just indicate that some channel has been converted (in the selfCAL()) and dont actually indicate that anything further needs to happen right?
Ta
I don't think you want to have the (PIE) Interrupt enabled while you run the self calibration function? The ping-pong sampling contained inside the function does not use the PIE or ISR and it keeps the ADC busy. I think you want to disable the PIE ADC ISR, call the self cal, then re-enable?