@stoffera said in Reading battery voltage?:
Gist with code: https://gist.github.com/stoffera/9ce4704c3cb2044b7a017fcced95ab74
Be aware that the measure is quite noisy - so you will need to do some filtering.
I'm now experimenting with different filtering methods. I'm currently trying initial delay of 50 µs, then 10 µs delay between samples, and taking average of 64 samples. Result seems quite stable and I can even watch value go down few mV at a time. (This measurement takes a bit under 1200 µs total.)
Here is current code as single method:
// BASED ON psoc_battery_voltage.{cpp,h}
// https://gist.github.com/stoffera/9ce4704c3cb2044b7a017fcced95ab74
uint16_t AppController::readBatteryVoltage() {
static const uint32_t RawAdcMax = 0xFFF;
static const uint32_t ReferenceVoltage = 0x400;
static const uint32_t CorrectionFactor = 1588;
static const uint32_t CorrectDenominator = 1000;
static const uint32_t CorrectionOffset = 440;
static const uint32_t CorrectionScale =
RawAdcMax*CorrectionFactor/CorrectDenominator*ReferenceVoltage;
static bool isStarted = false;
if (!isStarted) {
ADC_SAR_1_Start();
isStarted = true;
}
// Disconnect AMUXBUSL ; Connect AG5 / CMP2 to AG5 / vref to CMP2
CY_SET_REG8(CYDEV_ANAIF_RT_SAR0_SW3, CY_GET_REG8(CYDEV_ANAIF_RT_SAR0_SW3) & ~0x01);
CY_SET_REG8(CYDEV_ANAIF_RT_SAR0_SW0, CY_GET_REG8(CYDEV_ANAIF_RT_SAR0_SW0) | 0x20);
CY_SET_REG8(CYDEV_ANAIF_RT_CMP2_SW4, CY_GET_REG8(CYDEV_ANAIF_RT_CMP2_SW4) | 0x20);
CY_SET_REG8(CYDEV_ANAIF_RT_CMP2_SW3, CY_GET_REG8(CYDEV_ANAIF_RT_CMP2_SW3) | 0x20);
// wait for voltage level to settle
wait_us(50);
uint32_t count_log = 6;
uint32_t sum = 0;
for (uint32_t n = 0; n < (uint32_t)1 << count_log; n++) {
ADC_SAR_1_StartConvert();
ADC_SAR_1_IsEndConversion(ADC_SAR_1_WAIT_FOR_RESULT);
uint16_t reading = ADC_SAR_1_GetResult16();
// After reset value seems to stay at 0 for some time.
// In that case don't try to calculate average, just return 0.
if (reading == 0) return 0;
sum += ADC_SAR_1_GetResult16();
wait_us(10);
}
uint32_t avg = sum >> count_log;
// Disconnect CMP2 from vref and AG5 / AG5 from ADC ; Connect ADC to AMUXBUSL
CY_SET_REG8(CYDEV_ANAIF_RT_CMP2_SW4, CY_GET_REG8(CYDEV_ANAIF_RT_CMP2_SW4) & ~0x20);
CY_SET_REG8(CYDEV_ANAIF_RT_CMP2_SW3, CY_GET_REG8(CYDEV_ANAIF_RT_CMP2_SW3) & ~0x20);
CY_SET_REG8(CYDEV_ANAIF_RT_SAR0_SW0, CY_GET_REG8(CYDEV_ANAIF_RT_SAR0_SW0) & ~0x20);
CY_SET_REG8(CYDEV_ANAIF_RT_SAR0_SW3, CY_GET_REG8(CYDEV_ANAIF_RT_SAR0_SW3) | 0x01);
// scale from 12 bit ADC to mV
return CorrectionScale / avg + CorrectionOffset;
}
EDIT: And I just noticed a bug - the "return 0" special case I added doesn't restore state properly.