I am using Rev B silicon and have implemented most (if not all) of the ADC-related fixes in the Errata.
When running the code, there are values in the ADC offset registers on both modules so I know that the offset functions are running.
However, if I put a regulated 1.634V signal on any pin, I get a bad offset.
Using the internal voltage reference:
I should get 1.634 / 3.3 * 4096 = 2028, but I get 2012 or so.
Using the external reference (custom board, regulated supply):
I should get 1.634/3.27 = 2047, but I get 2032 or so.
This behavior is exhibited on at least 3 separate boards and the input voltage was measured by multiple separate meters.
Here is some data after 60 seconds of capturing ADC results at 2kHz, using an external 3.27V reference, and sending them over CAN:
1.634V (ADC1A2) -Average: 2032.138032
1.634V (ADC2A2) -Average: 2032.236417
1.635V (ADC1A4) -Average: 2033.18649
(Std Dev < 1 count for all 3 channels)
Below is the ADC Init code:
EALLOW; // Enable EALLOW protected register access
Adc1Regs.ADCCTL1.bit.RESET = 1; // Reset the ADC
Adc2Regs.ADCCTL1.bit.RESET = 1;
asm(" NOP");
asm(" NOP");
(**Device_Cal)(); //Call Device Calibration to enter in factory offset, the reset above removes these values
//--- Power-up and configure the ADC
// bit 15 0: RESET, ADC software reset, 0=no effect, 1=resets the ADC
// bit 14 0: ADCENABLE, ADC enable, 0=disabled, 1=enabled
// bit 13 0: ADCBSY, ADC busy, read-only
// bit 12-8 0's: ADCBSYCHN, ADC busy channel, read-only
// bit 7 1: ADCPWDN, ADC power down, 0=powered down, 1=powered up
// bit 6 1: ADCBGPWD, ADC bandgap power down, 0=powered down, 1=powered up
// bit 5 1: ADCREFPWD, ADC reference power down, 0=powered down, 1=powered up
// bit 4 0: reserved
// bit 3 0: ADCREFSEL, ADC reference select, 0=internal, 1=external
// bit 2 1: INTPULSEPOS, INT pulse generation, 0=start of conversion, 1=end of conversion
// bit 1 0: VREFLOCONV, VREFLO convert, 0=VREFLO not connected, 1=VREFLO connected to B5
// bit 0 0: TEMPCONV, 1=temp sensor connected to ADCINA5
Adc1Regs.ADCCTL1.bit.ADCBGPWD= 1; // Power ADC1 BG
Adc1Regs.ADCCTL1.bit.ADCREFPWD= 1; // Power reference
Adc1Regs.ADCCTL1.bit.ADCPWDN= 1; // Power ADC1
Adc1Regs.ADCCTL2.bit.ADCNONOVERLAP= 1; // Needed per TI advisory
Adc1Regs.ADCCTL1.bit.ADCENABLE= 1; // Enable ADC1
Adc2Regs.ADCCTL1.bit.ADCBGPWD= 1; // Power ADC2 BG
Adc2Regs.ADCCTL1.bit.ADCREFPWD= 1; // Power reference
Adc2Regs.ADCCTL1.bit.ADCPWDN= 1; // Power ADC2
Adc2Regs.ADCCTL2.bit.ADCNONOVERLAP= 1; // Needed per TI advisory
Adc2Regs.ADCCTL1.bit.ADCENABLE= 1; // Enable ADC2
DELAY_US(ADC_usDELAY); // Wait 1 ms after power-up before using the ADC
/*Below is needed by TI Advisory - Do not change */
Adc1OffsetSelfCal();
Adc2OffsetSelfCal();
/*Above is needed by TI Advisory - Do not change */
Adc1Regs.ADCCTL1.bit.ADCREFSEL= 1; // Select external Analog reference
Adc1Regs.ADCCTL2.bit.CLKDIV2EN= 0; // ADC clock = CPU clock
Adc2Regs.ADCCTL1.bit.ADCREFSEL= 1; // Select external Analog reference
Adc2Regs.ADCCTL2.bit.ADCNONOVERLAP= 1; // Needed per TI advisory
Adc2Regs.ADCCTL2.bit.CLKDIV2EN= 0; // ADC clock = CPU clock
/**********************************************************************************
* Configure SOC Triggers
* ********************************************************************************
* 00h = SOC priority is handled in round robin mode for all channels.
* 01h = SOC0 is high priority, rest of channels are in round robin mode.
* 02h = SOC0-SOC1 are high priority, SOC2-SOC15 are in round robin mode.
* 03h = SOC0-SOC2 are high priority, SOC3-SOC15 are in round robin mode.
* 04h = SOC0-SOC3 are high priority, SOC4-SOC15 are in round robin mode.
* 05h = SOC0-SOC4 are high priority, SOC5-SOC15 are in round robin mode.
* 06h = SOC0-SOC5 are high priority, SOC6-SOC15 are in round robin mode.
* 07h = SOC0-SOC6 are high priority, SOC7-SOC15 are in round robin mode.
* 08h = SOC0-SOC7 are high priority, SOC8-SOC15 are in round robin mode.
* 09h = SOC0-SOC8 are high priority, SOC9-SOC15 are in round robin mode.
* 0Ah = SOC0-SOC9 are high priority, SOC10-SOC15 are in round robin mode.
* 0Bh = SOC0-SOC10 are high priority, SOC11-SOC15 are in round robin mode.
* 0Ch = SOC0-SOC11 are high priority, SOC12-SOC15 are in round robin mode.
* 0Dh = SOC0-SOC12 are high priority, SOC13-SOC15 are in round robin mode.
* 0Eh = SOC0-SOC13 are high priority, SOC14-SOC15 are in round robin mode.
* 0Fh = SOC0-SOC14 are high priority, SOC15 is in round robin mode.
* 10h = All SOCs are in high priority mode, arbitrated by SOC number
* Others = Invalid selection.*/
Adc1Regs.SOCPRICTL.bit.SOCPRIORITY = 0x0; // SOC priority mode - All SOC on ADC1 are round robin
Adc2Regs.SOCPRICTL.bit.SOCPRIORITY = 0x1; // SOC priority mode - Only SOC0 is Round Robin
/**********************************************************
SOCx ADC Interrupt Trigger Select. Selects which, if any, ADCINT triggers SOCx.
This field (x = 7 to 0) overrides the TRIGSEL field in the ADCSOCxCTL register.
00 = No ADCINT will trigger SOCx. TRIGSEL field determines SOCx trigger.
01 = ADCINT1 will trigger SOCx. TRIGSEL field is ignored.
10 = ADCINT2 will trigger SOCx. TRIGSEL field is ignored.
11 = Invalid selection.
***********************************************************/
Adc1Regs.ADCINTSOCSEL1.all = 0; // Disable all ADC Interrupt SOC triggers (use SOC Triggers below instead)
Adc1Regs.ADCINTSOCSEL2.all = 0; // Disable all ADC Interrupt SOC triggers (use SOC Triggers below instead)
Adc1Regs.INTSEL1N2.bit.INT1CONT= 1; //Continue to run ADC even if flag is not cleared.
Adc1Regs.INTSEL1N2.bit.INT1SEL= 10; //Set ADCINT1 to EOC10 (DC Link voltage)
Adc1Regs.ADCCTL1.bit.INTPULSEPOS= 1; // INT pulse generation = end of conversion
Adc2Regs.ADCINTSOCSEL1.all = 0; // Disable all ADC Interrupt SOC triggers (use SOC Triggers below instead)
Adc2Regs.ADCINTSOCSEL2.all = 0; // Disable all ADC Interrupt SOC triggers (use SOC Triggers below instead)
Adc2Regs.INTSEL1N2.bit.INT2CONT= 1; //Continue to run ADC even if flag is not cleared.
Adc2Regs.INTSEL1N2.bit.INT2SEL= 0; //Set ADCINT2 to EOC0 (RS Ph-Ph voltage)
Adc2Regs.ADCCTL1.bit.INTPULSEPOS = 1; // INT pulse generation = end of conversion
Adc1Regs.INTSEL1N2.bit.INT1E= 1; //Enable Interrupt (will be EOC based on decision in ADCCTL1)
Adc2Regs.INTSEL1N2.bit.INT2E= 1; //Enable Interrupt (will be EOC based on decision in ADCCTL1)
EDIS; // Disable EALLOW protected register access
void InitSysCtrl(void)
{
// *IMPORTANT*
// The Device_cal function MUST be called
// for the ADC and oscillators to function according
// to specification. The clocks to the ADC MUST be enabled before calling
// this function. See the device data manual and/or the ADC Reference
// Manual for more information.
*(unsigned int*)0x4E58 = 7; // Workaround for InitAnalogSystemClock() Advisory
(**InitAnalogSystemClock)(ACLKDIV4);
EALLOW;
// Initialize the Analog Sub-System and set the clock divider to divide by 4
while((**AnalogClockEnable)(AnalogConfig1,ADC1_ENABLE)); // Enable ADC 1
while((**AnalogClockEnable)(AnalogConfig2,ADC2_ENABLE)); // Enable ADC 2
(**ReadAnalogClockStatus)(AnalogConfig2); // Wait for AnalogClockEnable function to finish
// Reset both ADC in case the last reset was a debugger reset (which doesn't
// reset the ADCs
Adc1Regs.ADCCTL1.bit.RESET = 1;
Adc2Regs.ADCCTL1.bit.RESET = 1;
// Wait to ensure ADCs are out of reset before device cal is called
__asm(" nop");
__asm(" nop");
// Calibrate the device for temperature
(**Device_Cal)();
while((**AnalogClockDisable)(AnalogConfig1,ADC1_ENABLE)); // Disable ADC1
while((**AnalogClockDisable)(AnalogConfig2,ADC2_ENABLE)); // Disable ADC2
(**ReadAnalogClockStatus)(AnalogConfig2); // Wait for AnalogClockDisable function to finish
EDIS;
// Initialize the peripheral clocks
InitPeripheralClocks();
}






