main
TylerK Update 20 file(s) fb8969c 1mo ago
#include "adc_sense.h"
#include "board_config.h"
#include "main.h"     /* CubeMX-generated: hadc1 handle, GPIO pin/port defines */
#include <math.h>

#define ADC_FILTER_ALPHA   0.25f

static float ema(float prev, float sample, float alpha) {
    return prev + alpha * (sample - prev);
}

void adc_sense_init(adc_filter_state_t *filt) {
    filt->vbatt_f = 0.0f;
    filt->iin_f = 0.0f;
    filt->ichg_f = 0.0f;
    filt->initialized = 0;
}

/* Reads ADC1's 3-channel scan sequence (configured in CubeMX as
 * PA0=rank1, PA1=rank2, PA2=rank3) and the two PGOOD GPIOs. */
void adc_sense_read(adc_filter_state_t *filt, sensor_frame_t *out) {
    uint32_t raw_vbatt = 0, raw_iin = 0, raw_ichg = 0;
    int ok = 1;

    /* A conversion that does not complete must NOT be reported as a reading
     * of zero. Zero volts on VBATT_SENSE is a perfectly plausible-looking
     * number that happens to mean "battery empty, charge as hard as you
     * can" -- the most dangerous possible interpretation of a dead sensor.
     * Propagate NaN instead, which charge_control's plausibility check
     * rejects, and the charger faults rather than acting on a fiction. */
    HAL_ADC_Start(&hadc1);
    if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) raw_vbatt = HAL_ADC_GetValue(&hadc1); else ok = 0;
    if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) raw_iin   = HAL_ADC_GetValue(&hadc1); else ok = 0;
    if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) raw_ichg  = HAL_ADC_GetValue(&hadc1); else ok = 0;
    HAL_ADC_Stop(&hadc1);

    if (!ok) {
        out->vbatt = out->iin = out->ichg = (float)NAN;
        out->iin_fast = out->ichg_fast = (float)NAN;
        out->mppt_pgood = 0;
        out->bias_pgood = 0;
        filt->initialized = 0;     /* re-seed the filter when readings return */
        return;
    }

    float vbatt = vbatt_from_adc(raw_vbatt);
    float iin = iin_from_adc(raw_iin);
    float ichg = ichg_from_adc(raw_ichg);

    if (!filt->initialized) {
        filt->vbatt_f = vbatt;
        filt->iin_f = iin;
        filt->ichg_f = ichg;
        filt->initialized = 1;
    } else {
        filt->vbatt_f = ema(filt->vbatt_f, vbatt, ADC_FILTER_ALPHA);
        filt->iin_f = ema(filt->iin_f, iin, ADC_FILTER_ALPHA);
        filt->ichg_f = ema(filt->ichg_f, ichg, ADC_FILTER_ALPHA);
    }

    out->vbatt = filt->vbatt_f;
    out->iin = filt->iin_f;
    out->ichg = filt->ichg_f;
    out->iin_fast = iin;      /* unfiltered, for the protection limits */
    out->ichg_fast = ichg;
    out->mppt_pgood = (HAL_GPIO_ReadPin(MPPT_PGOOD_GPIO_Port, MPPT_PGOOD_Pin) == GPIO_PIN_SET) ? 1 : 0;
    out->bias_pgood = (HAL_GPIO_ReadPin(BIAS_PGOOD_GPIO_Port, BIAS_PGOOD_Pin) == GPIO_PIN_SET) ? 1 : 0;
}