I think I must have a step missing in my LPC5502 ADC setup routine.
I followed the procedure in the manual (section 220.127.116.11) but when the GCC[RDY] flag is asserted, the value in GCC is zero.
That results in the gain offset calculation being exactly 1, and I presume that when it says "round the fractional part to 16 bits and write these values to GCR", it means that I should write ONLY the fractional part to GCR (which would be zero), and not the entire figure as 0x10000, as the field is only 16 bits wide.
(I am suspicious that the value is zero - it just seems unlikely)
Having written zero to GCR, the A/D appears to work, it is triggered by CT0, and writes 5 entries to the FIFO, but when I read them back, the all read 0x8000 (and one input has a 3V peak-to-peak 50Hz sinewave, and another has a thermistor, so 0x8000 is extremely unlikely to be correct)
I have bit 27 set in AHBCLKCTRL0 and the inputs configured as analogue in IOCON. It runs off the 12MHz clock, and ADCCLKSEL and ADCCLKDIV are both set to zero. (I also tried ADCCLKDIV =2 with the same result).
I note that there is no bit for the A/D in PDRUNCFG.
I hope there are enough clues here for someone to recognise what is missing.
The bits of PDRUNCFG are defined in fsl_power.h
Bit 19 is called LDOGPADC not AUXBIAS, and there are bits for "GPADC" and "TEMPSENSOR" (14 and 15). Should these be cleared as well? They are not even included in the peripheral view.
typedef enum pd_bits
kPDRUNCFG_PD_DCDC = (1UL << 0),
kPDRUNCFG_PD_BIAS = (1UL << 1),
kPDRUNCFG_PD_BODCORE = (1UL << 2),
kPDRUNCFG_PD_BODVBAT = (1UL << 3),
kPDRUNCFG_PD_FRO1M = (1UL << 4),
kPDRUNCFG_PD_FRO192M = (1UL << 5),
kPDRUNCFG_PD_FRO32K = (1UL << 6),
kPDRUNCFG_PD_XTAL32K = (1UL << 7),
kPDRUNCFG_PD_XTAL32M = (1UL << 8),
kPDRUNCFG_PD_PLL0 = (1UL << 9),
kPDRUNCFG_PD_PLL1 = (1UL << 10),
kPDRUNCFG_PD_COMP = (1UL << 13),
kPDRUNCFG_PD_TEMPSENS = (1UL << 14),
kPDRUNCFG_PD_GPADC = (1UL << 15),
kPDRUNCFG_PD_LDOMEM = (1UL << 16),
kPDRUNCFG_PD_LDODEEPSLEEP = (1UL << 17),
kPDRUNCFG_PD_LDOGPADC = (1UL << 19),
kPDRUNCFG_PD_LDOXO32M = (1UL << 20),
kPDRUNCFG_PD_LDOFLASHNV = (1UL << 21),
kPDRUNCFG_PD_RNG = (1UL << 22),
kPDRUNCFG_PD_PLL0_SSCG = (1UL << 23),
kPDRUNCFG_PD_ROM = (1UL << 24),
This enum member has no practical meaning,it is used to avoid MISRA issue,
user should not trying to use it.
kPDRUNCFG_ForceUnsigned = 0x80000000U,
The "enum pd_bitsf" is showing which analog peripherals can remain running and therefore can wake up the chip from deep-sleep. No relationship with ADC configuration.
Sorry please ignore the first screenshot at my last reply, just refer to
Table 317. Power configuration register 0
Table 319. Power configuration clear register
I also don't think the description in UM is clear, so recommend refer to SDK demo.
Is this important?
it’s 18 months since it was posted, but there is no mention of it in either the addenda or errata.
So, I cleared bit 19 (AUXBIAS) of PDRUNCFG0, and now it works.
There's no reference to AUXBIAS in the ADC section of the manual, and no reference to AUX BIAS in the ADC set up and driver software in the SDK.
There only reference to what AUXBIAS does was in table 335.
Your comments please.
Yes, about this part, UM doesn't describe very well.
About the peripherals , we need first enable power first, and combine with SDK dmeo.
Also I will submit your suggestion to DOC team, thanks you.
There are 1542 lines of code, and all sorts of things that are not explained - for instance, what is an "instance" of the A/D converter? What is the ADC_Type? Isn't there only one type?
void LPADC_DoAutoCalibration(ADC_Type *base) appears twice, and the two versions are different. Which one should I look at?
My code is rather more concise (77 lines, instead of 1542 lines) and well documented, and was written from the instructions in the manual.
// ----------- Set Up and Calibrate ADC ------------------------------------------------------------------------- .global SetUpADC SetUpADC: LDR R3,=LPC_SYSCON_BASE MOVS R0,#0 STR R0,[R3,ADCCLKSEL] MOVS R0,#0 STR R0,[R3,ADCCLKDIV] LDR R0,[R3,AHBCLKCTRL0] ORRS R0,R0,#1<<27 // enable clock to ADC STR R0,[R3,AHBCLKCTRL0] LDR R3,=LPC_ADC0_BASE MOVS R0,#2 // reset ADC module STR R0,[R3,ADC_CTRL] MOVW R0,#2<<8 // reset both FIFOs STR R0,[R3,ADC_CTRL] LDR R0,=1<<6|0x80<<16 // REFSEL=VREFH, PUDLY=0x80 STR R0,[R3,ADC_CFG] MOVS R0,#1 // enable ADC module STR R0,[R3,ADC_CTRL] LDR R0,=1|1<<4|7<<16 // offset calibration 128 averages STR R0,[R3,ADC_CTRL] wcal0: LDR R0,[R3,ADC_STAT] TST R0,#1<<10 // test for calibration complete BEQ.n wcal0 LDR R0,=1|1<<3|7<<16 // gain calibration 128 averages STR R0,[R3,ADC_CTRL] wcal1: LDR R0,[R3,ADC_GCC0] TST R0,#1<<24 // Gain calibration #0 valid BEQ.n wcal1 wcal2: LDR R0,[R3,ADC_GCC1] TST R0,#1<<24 // Gain calibration #1 valid BEQ.n wcal2 LDR R0,[R3,ADC_GCC0] // Calculate GCR0 UXTH R1,R0 LSLS R0,R0,#16 RSBS R1,R1,#131072 UDIV R0,R0,R1 ORRS R0,R0,#1<<24 STR R0,[R3,ADC_GCR0] LDR R0,[R3,ADC_GCC1] // Calculate GCR1 UXTH R1,R0 LSLS R0,R0,#16 RSBS R1,R1,#131072 UDIV R0,R0,R1 ORRS R0,R0,#1<<24 STR R0,[R3,ADC_GCR1] wcal3: LDR R0,[R3,ADC_STAT] // test for calibration complete TST R0,#1<<10 BEQ.n wcal3 MOVS R0,#1<<7|3<<5 // CH0A (Vbatt) only STR R0,[R3,ADC_CMDL1] LDR R0,=5<<8|4<<12|2<<24 // 35 cycles, 16 averages, next = 2 STR R0,[R3,ADC_CMDH1] MOVS R0,#1<<7|1 // CH1A (Vmains) only STR R0,[R3,ADC_CMDL2] LDR R0,=5<<8|4<<12|3<<24 // 35 cycles, 16 averages, next = 3 STR R0,[R3,ADC_CMDH2] MOVS R0,#1<<7|2 // CH2A (PSMon) only STR R0,[R3,ADC_CMDL3] LDR R0,=5<<8|4<<12|4<<24 // 35 cycles, 16 averages, next = 4 STR R0,[R3,ADC_CMDH3] MOVS R0,#1<<7|2 // CH3A (Thermistor) only STR R0,[R3,ADC_CMDL4] LDR R0,=5<<8|4<<12|5<<24 // 35 cycles, 16 averages, next = 5 STR R0,[R3,ADC_CMDH4] MOVS R0,#1<<7|1<<5|4 // CH4B (ChargerShunt) only STR R0,[R3,ADC_CMDL5] LDR R0,=5<<8|4<<12 // 35 cycles, 16 averages, finish STR R0,[R3,ADC_CMDH5] LDR R0,=1|1<<24 STR R0,[R3,ADC_TCTRL5] // trigger 5 (CTR0,MAT3), execute CMD1 MOVS R0,#1<<21 STR R0,[R3,ADC_IE] // INTERRUPT ON trigger 5 completion BX LR
The most important question is whether the GCC values should read zero. Is this normal? As the range is from 0 to 65536, the chances of it being exactly zero seem small.
If I knew whether the fault was in the reading or in the calibrating, then I would be half way to finding it.
Please refer to the below function in fsl_lpadc.c file:
void LPADC_DoAutoCalibration(ADC_Type *base)
assert((0u == LPADC_GetConvResultCount(base, 0)) && (0u == LPADC_GetConvResultCount(base, 1)));
/* Request gain calibration. */
base->CTRL |= ADC_CTRL_CAL_REQ_MASK;
while ((ADC_GCC_RDY_MASK != (base->GCC & ADC_GCC_RDY_MASK)) ||
(ADC_GCC_RDY_MASK != (base->GCC & ADC_GCC_RDY_MASK)))
/* Calculate gain offset. */
GCCa = (base->GCC & ADC_GCC_GAIN_CAL_MASK);
GCCb = (base->GCC & ADC_GCC_GAIN_CAL_MASK);
GCRa = (uint16_t)((GCCa << 16U) /
(0x1FFFFU - GCCa)); /* Gain_CalA = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC)) - 1. */
GCRb = (uint16_t)((GCCb << 16U) /
(0x1FFFFU - GCCb)); /* Gain_CalB = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC)) - 1. */
base->GCR = ADC_GCR_GCALR(GCRa);
base->GCR = ADC_GCR_GCALR(GCRb);
/* Indicate the values are valid. */
base->GCR |= ADC_GCR_RDY_MASK;
base->GCR |= ADC_GCR_RDY_MASK;
while (ADC_STAT_CAL_RDY_MASK != (base->STAT & ADC_STAT_CAL_RDY_MASK))
Thank you. That's the same A/D as in the LPC15xx, I have used them extensively and they are a doddle. But I can't get LPC15xx these days, so LPC55xx seemed like the next best thing (or, more truthfully, the only thing without a zero next to it in the "quantity available" column).
Its 16-bit A/D is a different beast entirely.
I think I have mastered the complex scheduling and triggering, but have failed at the relatively simple calibration.
> Its 16-bit A/D is a different beast entirely.
Sounds like not a SAR ADC.
Still, I would start from an SDK example, and perhaps compare it with own code.
The GPIO init is still crucial. Are you sure it is right in your case ?
I just have some experiences with the LPX54xxx series, but that hopefully applies.
Do you have the appropriate GPIO pins initialized correctly (as ADC inputs) ?
If unsure, check out an ADC example from the SDK. The respective init code is in file pinmux.c, at least for my SDK.