I think I must have a step missing in my LPC5502 ADC setup routine.
I followed the procedure in the manual (section 39.7.5.3) 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.
Hello ianbenton,
AUXBIAS is ADC analog references, by default it is power-down, if want to use ADC, we need power it.
BR
Alice
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,
} pd_bit_t;
Hello ianbenton,
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.
BR
Alice
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.
Hello ianbenton,
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.
BR
Alice
Which routine contains the power-up commands for the a/d?
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.
Hello,
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)));uint32_t GCCa;
uint32_t GCCb;
uint32_t GCRa;
uint32_t GCRb;/* Request gain calibration. */
base->CTRL |= ADC_CTRL_CAL_REQ_MASK;
while ((ADC_GCC_RDY_MASK != (base->GCC[0] & ADC_GCC_RDY_MASK)) ||
(ADC_GCC_RDY_MASK != (base->GCC[1] & ADC_GCC_RDY_MASK)))
{
}/* Calculate gain offset. */
GCCa = (base->GCC[0] & ADC_GCC_GAIN_CAL_MASK);
GCCb = (base->GCC[1] & ADC_GCC_GAIN_CAL_MASK);
GCRa = (uint16_t)((GCCa << 16U) /
(0x1FFFFU - GCCa)); /* Gain_CalA = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC[0])) - 1. */
GCRb = (uint16_t)((GCCb << 16U) /
(0x1FFFFU - GCCb)); /* Gain_CalB = (131072 / (131072-(ADC_GCC_GAIN_CAL(ADC0->GCC[1])) - 1. */
base->GCR[0] = ADC_GCR_GCALR(GCRa);
base->GCR[1] = ADC_GCR_GCALR(GCRb);/* Indicate the values are valid. */
base->GCR[0] |= ADC_GCR_RDY_MASK;
base->GCR[1] |= 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.