From 5a7534453999b9da808728d60d23f92ffcb421dd Mon Sep 17 00:00:00 2001 From: "Ben V. Brown" Date: Fri, 24 May 2024 20:44:42 +1000 Subject: [PATCH] Updated ADC Init --- source/Core/BSP/Pinecilv2/IRQ.cpp | 15 +++---- source/Core/BSP/Pinecilv2/Setup.cpp | 69 ++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/source/Core/BSP/Pinecilv2/IRQ.cpp b/source/Core/BSP/Pinecilv2/IRQ.cpp index 7a857b18..02bc4700 100644 --- a/source/Core/BSP/Pinecilv2/IRQ.cpp +++ b/source/Core/BSP/Pinecilv2/IRQ.cpp @@ -29,19 +29,18 @@ void adc_fifo_irq(void) { if (ADC_GetIntStatus(ADC_INT_FIFO_READY) == SET) { // Read out all entries in the fifo while (ADC_Get_FIFO_Count()) { - uint32_t reading = ADC_Read_FIFO(); - // As per manual, 26 bit reading; lowest 16 are the ADC - uint16_t sample = reading & 0xFFFF; - uint8_t source = (reading >> 21) & 0b11111; - switch (source) { + uint32_t reading = ADC_Read_FIFO(); + ADC_Result_Type parsed = {0, 0, 0}; + ADC_Parse_Result(&reading, 1, &parsed); + switch (parsed.posChan) { case TMP36_ADC_CHANNEL: - ADC_Temp.update(sample); + ADC_Temp.update(parsed.value << 2); break; case TIP_TEMP_ADC_CHANNEL: - ADC_Tip.update(sample); + ADC_Tip.update(parsed.value << 2); break; case VIN_ADC_CHANNEL: - ADC_Vin.update(sample); + ADC_Vin.update(parsed.value << 2); break; default: break; diff --git a/source/Core/BSP/Pinecilv2/Setup.cpp b/source/Core/BSP/Pinecilv2/Setup.cpp index 7e8ea542..c0e6d42d 100644 --- a/source/Core/BSP/Pinecilv2/Setup.cpp +++ b/source/Core/BSP/Pinecilv2/Setup.cpp @@ -100,17 +100,55 @@ void setup_adc(void) { ADC_IntMask(ADC_INT_ALL, MASK); + // Please also see PR #1529 for even more context + + /* + A note on ADC settings + + The bl70x ADC seems to be very sensitive to various analog settings. + It has been a challenge to determine what is the most correct way to + configure it in order to get accurate readings that can be transformed + into millivolts, for accurate measurements. + + This latest set of ADC parameters, matches the latest configuration from + the upstream bl_mcu_sdk repository from commit hash: + 9e189b69cbc0a75ffa170f600a28820848d56432 + except for one difference. + (Note: bl_mcu_sdk has been heavily refactored since it has been imported into IronOS.) + + You can make it match exactly by defining ENABLE_MIC2_DIFF, see the code + #ifdef ENABLE_MIC2_DIFF below. + I have decided to not apply this change because it appeared to make the + lower end of the input less precise. + + Note that this configuration uses an ADC trimming value that is stored in the Efuse + of the bl70x chip. The actual reading is divided by this "coe" value. + We have found the following coe values on 3 different chips: + 0.9629, 0.9438, 0.9876 + + Additional note for posterity: + PGA = programmable gain amplifier. + We would have expected to achieve the highest accuracy by disabling this amplifier, + however we found that not to be the case, and in almost all cases we have found + that there is a scaling error compared to the ideal Vref. + The only other configuration we have found to be accurate was if we had: + PGA disabled + Vref=2V + biasSel=AON + without trimming from the efuse. + But we can't use it because a Vref=2V limits the higher end of temperature and voltage readings. + Also we don't know if this other configuration is really accurate on all chips, or only + happened to be accurate on the one chip on which it has been found. + */ + adc_cfg.clkDiv = ADC_CLK_DIV_4; adc_cfg.vref = ADC_VREF_3P2V; adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_16_AVERAGE; adc_cfg.inputMode = ADC_INPUT_SINGLE_END; - adc_cfg.v18Sel = ADC_V18_SEL_1P72V; + adc_cfg.v18Sel = ADC_V18_SEL_1P82V; adc_cfg.v11Sel = ADC_V11_SEL_1P1V; - adc_cfg.gain1 = ADC_PGA_GAIN_NONE; - adc_cfg.gain2 = ADC_PGA_GAIN_NONE; - adc_cfg.chopMode = ADC_CHOP_MOD_AZ_ON; + adc_cfg.gain1 = ADC_PGA_GAIN_1; + adc_cfg.gain2 = ADC_PGA_GAIN_1; + adc_cfg.chopMode = ADC_CHOP_MOD_AZ_PGA_ON; adc_cfg.biasSel = ADC_BIAS_SEL_MAIN_BANDGAP; - adc_cfg.vcm = ADC_PGA_VCM_1P6V; + adc_cfg.vcm = ADC_PGA_VCM_1P2V; adc_cfg.offsetCalibEn = DISABLE; adc_cfg.offsetCalibVal = 0; @@ -119,11 +157,32 @@ void setup_adc(void) { ADC_Reset(); ADC_Init(&adc_cfg); +#ifdef ENABLE_MIC2_DIFF + // This is the change that enables MIC2_DIFF, for now deciding not to enable it, since it seems to make results slightly worse + { + uint32_t tmpVal; + tmpVal = BL_RD_REG(AON_BASE, AON_GPADC_REG_CMD); + tmpVal = BL_SET_REG_BITS_VAL(tmpVal, AON_GPADC_MIC2_DIFF, 1); + BL_WR_REG(AON_BASE, AON_GPADC_REG_CMD, tmpVal); + } +#endif + +#if 1 + // this sets the CVSP field (ADC conversion speed) + { + uint32_t regCfg2; + regCfg2 = BL_RD_REG(AON_BASE, AON_GPADC_REG_CONFIG2); + regCfg2 = BL_SET_REG_BITS_VAL(regCfg2, AON_GPADC_DLY_SEL, 0x02); + BL_WR_REG(AON_BASE, AON_GPADC_REG_CONFIG2, regCfg2); + } +#endif + adc_fifo_cfg.dmaEn = DISABLE; adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8; // Triger FIFO when all 8 measurements are done ADC_FIFO_Cfg(&adc_fifo_cfg); ADC_MIC_Bias_Disable(); ADC_Tsen_Disable(); + ADC_Gain_Trim(); // Enable FiFo IRQ Interrupt_Handler_Register(GPADC_DMA_IRQn, adc_fifo_irq);