LPC55xx ADC configuration and calibration

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC55xx ADC configuration and calibration

2,846 Views
ianbenton
Senior Contributor I

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.

13 Replies

2,712 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello ianbenton,

 AUXBIAS is ADC analog references, by default it is power-down, if want to use ADC, we need power it.

 

 

Alice_Yang_0-1638865982865.png

 

BR

Alice

 

0 Kudos

2,707 Views
ianbenton
Senior Contributor I

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;

2,696 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

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

0 Kudos

2,784 Views
ianbenton
Senior Contributor I

Is this important?

https://community.nxp.com/t5/LPC-Microcontrollers/LPC55S69-Power-configuration-register-0-PDRUNCFG0/...

it’s 18 months since it was posted, but there is no mention of it in either the addenda or errata.

2,801 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello ianbenton,

Please first refer to the ADC demo under SDK for LPCXpresso55s06.

 

BR

Alice

0 Kudos

2,758 Views
ianbenton
Senior Contributor I

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.

2,749 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

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

0 Kudos

2,744 Views
ianbenton
Senior Contributor I

Which routine contains the power-up commands for the a/d?

0 Kudos

2,795 Views
ianbenton
Senior Contributor I

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.

0 Kudos

2,771 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

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))
{
}
}

0 Kudos

2,832 Views
ianbenton
Senior Contributor I

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.

0 Kudos

2,828 Views
frank_m
Senior Contributor III

> 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 ?

0 Kudos

2,842 Views
frank_m
Senior Contributor III

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.

0 Kudos