From bb14e1a717c2084fa331663b68cb0e00026deb7c Mon Sep 17 00:00:00 2001 From: Mitchell Ostler Date: Mon, 17 Jun 2024 00:10:50 -0400 Subject: [PATCH] Mitch bms refactor (#287) * tmp * pwm update * tmp * tmp * Current Sense Update * stop fail when current sense isn't connected * update pd * fix message ids, add afe logging * thermistor refactor - updates with retries * Changes to run on hw, format * x86 fixes * lint --- libraries/codegen/boards/bms_carrier.yaml | 6 +- libraries/codegen/boards/centre_console.yaml | 8 +- .../codegen/boards/motor_controller.yaml | 2 +- .../codegen/boards/power_distribution.yaml | 2 +- .../codegen/templates/system_can.dbc.jinja | 2 +- libraries/ms-common/inc/pwm.h | 4 +- libraries/ms-common/src/arm/pwm.c | 41 ++-- libraries/ms-common/src/tasks.c | 6 +- libraries/ms-common/src/x86/pwm.c | 9 +- .../ms-drivers/inc/max17261_fuel_gauge.h | 36 +++- .../ms-drivers/inc/max17261_fuel_gauge_defs.h | 2 + libraries/ms-drivers/src/ltc_afe_impl.c | 56 +++--- .../ms-drivers/src/max17261_fuel_gauge.c | 184 ++++++++++++++---- projects/bms_carrier/inc/bms.h | 2 + projects/bms_carrier/inc/cell_sense.h | 4 +- projects/bms_carrier/inc/current_sense.h | 32 ++- projects/bms_carrier/inc/relays.h | 2 +- projects/bms_carrier/src/cell_sense.c | 177 ++++++++++++----- projects/bms_carrier/src/current_sense.c | 64 ++++-- projects/bms_carrier/src/fan.c | 12 +- projects/bms_carrier/src/main.c | 29 +-- projects/bms_carrier/src/relays.c | 64 ++---- projects/centre_console/src/cc_buttons.c | 16 +- .../centre_console/src/update_dashboard.c | 6 +- projects/power_distribution/inc/pd_fault.h | 2 + projects/power_distribution/inc/pin_defs.h | 9 +- .../power_distribution/inc/power_seq_fsm.h | 2 +- .../power_distribution/src/output_config.c | 15 +- projects/power_distribution/src/pd_fault.c | 4 +- .../power_distribution/src/power_seq_fsm.c | 6 +- smoke/bms_carrier/README.md | 15 -- smoke/bms_carrier/config.json | 15 -- smoke/bms_carrier/src/main.c | 33 ---- 33 files changed, 506 insertions(+), 361 deletions(-) delete mode 100644 smoke/bms_carrier/README.md delete mode 100644 smoke/bms_carrier/config.json delete mode 100644 smoke/bms_carrier/src/main.c diff --git a/libraries/codegen/boards/bms_carrier.yaml b/libraries/codegen/boards/bms_carrier.yaml index 564ca6daa..56f9b2cd0 100644 --- a/libraries/codegen/boards/bms_carrier.yaml +++ b/libraries/codegen/boards/bms_carrier.yaml @@ -11,13 +11,13 @@ --- Messages: battery_status: - id: 0 + id: 1 critical: true target: centre_console: - watchdog: 0 - power_distribution: watchdog: 3 + power_distribution: + watchdog: 5 signals: fault: length: 16 diff --git a/libraries/codegen/boards/centre_console.yaml b/libraries/codegen/boards/centre_console.yaml index ceb8a3200..68f1550dd 100644 --- a/libraries/codegen/boards/centre_console.yaml +++ b/libraries/codegen/boards/centre_console.yaml @@ -11,7 +11,7 @@ --- Messages: cc_info: - id: 4 + id: 5 critical: true target: motor_controller: @@ -30,7 +30,7 @@ Messages: hazard_enabled: length: 8 cc_pedal: - id: 2 + id: 3 critical: true target: motor_controller: @@ -43,7 +43,7 @@ Messages: brake_output: length: 8 cc_steering: - id: 5 + id: 6 critical: true target: power_distribution: @@ -54,4 +54,4 @@ Messages: input_cc: length: 8 # (cc_toggle | cc_increse | cc_decrease) input_lights: - length: 8 \ No newline at end of file + length: 8 diff --git a/libraries/codegen/boards/motor_controller.yaml b/libraries/codegen/boards/motor_controller.yaml index 8b32571e0..d7c465d33 100644 --- a/libraries/codegen/boards/motor_controller.yaml +++ b/libraries/codegen/boards/motor_controller.yaml @@ -69,7 +69,7 @@ length: 16 mc_status: - id: 3 + id: 4 critical: true target: centre_console: diff --git a/libraries/codegen/boards/power_distribution.yaml b/libraries/codegen/boards/power_distribution.yaml index 0989aec68..8a14afc9e 100644 --- a/libraries/codegen/boards/power_distribution.yaml +++ b/libraries/codegen/boards/power_distribution.yaml @@ -22,7 +22,7 @@ current: length: 16 pd_status: - id: 1 + id: 2 critical: true target: centre_console: diff --git a/libraries/codegen/templates/system_can.dbc.jinja b/libraries/codegen/templates/system_can.dbc.jinja index dc75e1cf8..53bcf345f 100644 --- a/libraries/codegen/templates/system_can.dbc.jinja +++ b/libraries/codegen/templates/system_can.dbc.jinja @@ -38,7 +38,7 @@ BU_: {% for message in messages -%} -BO_ {% if message.critical %} {{message.id * 0x20 + boards.index(message.sender)}} {% endif %} {% if not message.critical %} {{message.id}} {% endif %}{{message.name}}: {{message.signals | sum("length") // 8 }} {{message.sender}} +BO_ {% if message.critical %} {{message.id}} {% endif %} {% if not message.critical %} {{message.id * 0x20 + boards.index(message.sender)}} {% endif %}{{message.name}}: {{message.signals | sum("length") // 8 }} {{message.sender}} {%- for signal in message.signals %} SG_ {{signal.name}} : {{signal.start_bit}}|{{signal.length}}@1+ ({{signal["scale"]}},{{signal["offset"]}}) [{{signal["min"]}}|{{signal["max"]}}] "{{signal["unit"]}}" {{signal.receiver | join(", ")}} diff --git a/libraries/ms-common/inc/pwm.h b/libraries/ms-common/inc/pwm.h index 07f312236..e40e37972 100644 --- a/libraries/ms-common/inc/pwm.h +++ b/libraries/ms-common/inc/pwm.h @@ -25,12 +25,12 @@ StatusCode pwm_init(PwmTimer timer, uint16_t period_us); uint16_t pwm_get_period(PwmTimer timer); // Sets the pulse width in us of the PWM timer. Use for high resolution control. -StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us); +StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us, uint8_t channel); // Sets the duty cycle, in units of 1%, of the PWM timer. This wraps // pwm_set_pulse doing the necessary math to convert from 0-100% to the fraction // of the period. -StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc); +StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc, uint8_t channel); // Gets the duty cycle of the PWM timer. uint16_t pwm_get_dc(PwmTimer timer); diff --git a/libraries/ms-common/src/arm/pwm.c b/libraries/ms-common/src/arm/pwm.c index 6d7ed1e03..a029a5a5e 100644 --- a/libraries/ms-common/src/arm/pwm.c +++ b/libraries/ms-common/src/arm/pwm.c @@ -7,6 +7,7 @@ #include "stm32f10x_rcc.h" #include "stm32f10x_tim.h" +#define NUM_CHANNELS 4 typedef enum APBClk { APB1 = 0, APB2, @@ -102,7 +103,7 @@ uint16_t pwm_get_period(PwmTimer timer) { return s_period_us[timer]; } -StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us) { +StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us, uint8_t channel) { if (timer >= NUM_PWM_TIMERS) { return status_msg(STATUS_CODE_INVALID_ARGS, "Invalid timer id"); } else if (s_period_us[timer] == 0) { @@ -116,28 +117,36 @@ StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us) { .TIM_Pulse = pulse_width_us, .TIM_OutputState = TIM_OutputState_Enable, .TIM_OCPolarity = TIM_OCPolarity_High, - .TIM_OutputNState = TIM_OutputNState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, .TIM_OCNPolarity = TIM_OCNPolarity_High, }; // Enable PWM on all channels. - - TIM_OC1Init(s_timer_def[timer], &oc_init); - TIM_OC1PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); - - TIM_OC2Init(s_timer_def[timer], &oc_init); - TIM_OC2PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); - - TIM_OC3Init(s_timer_def[timer], &oc_init); - TIM_OC3PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); - - TIM_OC4Init(s_timer_def[timer], &oc_init); - TIM_OC4PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); + switch (channel) { + case 1: + TIM_OC1Init(s_timer_def[timer], &oc_init); + TIM_OC1PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); + break; + case 2: + TIM_OC2Init(s_timer_def[timer], &oc_init); + TIM_OC2PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); + break; + case 3: + TIM_OC3Init(s_timer_def[timer], &oc_init); + TIM_OC3PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); + break; + case 4: + TIM_OC4Init(s_timer_def[timer], &oc_init); + TIM_OC4PreloadConfig(s_timer_def[timer], TIM_OCPreload_Enable); + break; + default: + break; + } return STATUS_CODE_OK; } -StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc) { +StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc, uint8_t channel) { if (timer >= NUM_PWM_TIMERS) { return status_msg(STATUS_CODE_INVALID_ARGS, "Invalid timer id"); } else if (dc > 100) { @@ -152,7 +161,7 @@ StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc) { } } - return pwm_set_pulse(timer, pulse_width); + return pwm_set_pulse(timer, pulse_width, channel); } uint16_t pwm_get_dc(PwmTimer timer) { diff --git a/libraries/ms-common/src/tasks.c b/libraries/ms-common/src/tasks.c index 5923f3517..f4e1859db 100644 --- a/libraries/ms-common/src/tasks.c +++ b/libraries/ms-common/src/tasks.c @@ -56,7 +56,11 @@ StatusCode tasks_init_task(Task *task, TaskPriority priority, void *context) { task->context = context; task->handle = xTaskCreateStatic(prv_task, task->name, task->stack_size, task, priority, task->stack, &task->tcb); - configASSERT(task->handle != NULL); // make sure it was created + if (task->handle == NULL) { + LOG_CRITICAL("Failed to create Task %s", task->name); // make sure it was created + } else { + LOG_DEBUG("Create Task %s", task->name); // make sure it was created + } return STATUS_CODE_OK; } diff --git a/libraries/ms-common/src/x86/pwm.c b/libraries/ms-common/src/x86/pwm.c index 040ccf5bb..a74334a5e 100644 --- a/libraries/ms-common/src/x86/pwm.c +++ b/libraries/ms-common/src/x86/pwm.c @@ -29,21 +29,20 @@ uint16_t pwm_get_period(PwmTimer timer) { } return pwm[timer].period; } - -StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_ms) { +StatusCode pwm_set_pulse(PwmTimer timer, uint16_t pulse_width_us, uint8_t channel) { if (timer >= NUM_PWM_TIMERS) { return status_msg(STATUS_CODE_INVALID_ARGS, "Invalid timer id"); } else if (pwm[timer].period == 0) { return status_msg(STATUS_CODE_UNINITIALIZED, "Pwm must be initialized."); - } else if (pulse_width_ms > pwm[timer].period) { + } else if (pulse_width_us > pwm[timer].period) { return status_msg(STATUS_CODE_INVALID_ARGS, "Pulse width must be leq period."); } // Store pulse width as a duty cycle - pwm[timer].duty = (pulse_width_ms * 100) / pwm[timer].period; + pwm[timer].duty = (pulse_width_us * 100) / pwm[timer].period; return STATUS_CODE_OK; } -StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc) { +StatusCode pwm_set_dc(PwmTimer timer, uint16_t dc, uint8_t channel) { if (timer >= NUM_PWM_TIMERS) { return status_msg(STATUS_CODE_INVALID_ARGS, "Invalid timer id"); } else if (dc > 100) { diff --git a/libraries/ms-drivers/inc/max17261_fuel_gauge.h b/libraries/ms-drivers/inc/max17261_fuel_gauge.h index 51198ba5d..8856c3f2a 100644 --- a/libraries/ms-drivers/inc/max17261_fuel_gauge.h +++ b/libraries/ms-drivers/inc/max17261_fuel_gauge.h @@ -22,21 +22,33 @@ typedef struct { I2CPort i2c_port; I2CAddress i2c_address; - uint16_t design_capacity; // LSB = 5.0 (micro Volt Hours / R Sense) - uint16_t empty_voltage; // Only a 9-bit field, LSB = 78.125 (micro Volts) - uint16_t charge_term_current; // LSB = 1.5625 (micro Volts / R Sense) + uint32_t pack_design_cap_mah; + uint16_t cell_empty_voltage_v; + uint16_t + charge_term_current_ma; // ref end-of-charge detection + // https://web.archive.org/web/20220121025712mp_/https://pdfserv.maximintegrated.com/en/an/user-guide-6597-max1726x-m5-ez-rev3-p4.pdf - uint16_t i_thresh_max; - int16_t i_thresh_min; - uint16_t temp_thresh_max; + uint16_t i_thresh_max_a; + int16_t i_thresh_min_a; + uint16_t temp_thresh_max_c; - float r_sense_mohms; // Rsense in micro ohms + float sense_resistor_mohms; } Max17261Settings; typedef struct { Max17261Settings *settings; } Max17261Storage; +// Storage for parameters learned by fuel guage +// Must be stored in flash to keep up to date after power cycle +typedef struct Max27261Params { + uint16_t rcomp0; + uint16_t tempco; + uint16_t fullcaprep; + uint16_t cycles; + uint16_t fullcapnom; +} Max27261Params; + /* @brief Gets the current state of charge given by the max17261 in percentage * @param storage - a pointer to an already initialized Max17261Storage struct * @param soc_pct - state of charge in percentage will be returned in this var @@ -49,14 +61,14 @@ StatusCode max17261_state_of_charge(Max17261Storage *storage, uint16_t *soc_pct) * @param soc_pct - remaining capactity in micro amp hours returned in this var * @return STATUS_CODE_OK on success */ -StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_uAhr); +StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_mAh); /* @brief Gets the full charge capacity of the battery in micro amp hours * @param storage - a pointer to an already initialized Max17261Storage struct * @param soc_pct - full charge capacitry in micro amp hours returned in this var * @return STATUS_CODE_OK on success */ -StatusCode max17261_full_capacity(Max17261Storage *storage, uint16_t *full_cap_uAhr); +StatusCode max17261_full_capacity(Max17261Storage *storage, uint32_t *full_cap_mAh); /* @brief Gets the time to empty in milliseconds * @param storage - a pointer to an already initialized Max17261Storage struct @@ -98,4 +110,8 @@ StatusCode max17261_temp(Max17261Storage *storage, uint16_t *temp_c); * @param settings - populated settings struct * @return STATUS_CODE_OK on success */ -StatusCode max17261_init(Max17261Storage *storage, Max17261Settings *settings); +StatusCode max17261_init(Max17261Storage *storage, Max17261Settings *settings, + Max27261Params *params); + +StatusCode max17261_set_learned_params(Max17261Storage *storage, Max27261Params *params); +StatusCode max17261_get_learned_params(Max17261Storage *storage, Max27261Params *params); diff --git a/libraries/ms-drivers/inc/max17261_fuel_gauge_defs.h b/libraries/ms-drivers/inc/max17261_fuel_gauge_defs.h index edacb7000..1320ffc17 100644 --- a/libraries/ms-drivers/inc/max17261_fuel_gauge_defs.h +++ b/libraries/ms-drivers/inc/max17261_fuel_gauge_defs.h @@ -67,6 +67,8 @@ typedef enum { MAX17261_VF_REM_CAP, MAX17261_QH = 0x4D, + MAX17261_SOFT_WAKEUP = 0x60, + MAX17261_STATUS2 = 0xB0, MAX17261_POWER, MAX17261_ID, // UserMem2 diff --git a/libraries/ms-drivers/src/ltc_afe_impl.c b/libraries/ms-drivers/src/ltc_afe_impl.c index 356e778d2..caf4e5b6e 100644 --- a/libraries/ms-drivers/src/ltc_afe_impl.c +++ b/libraries/ms-drivers/src/ltc_afe_impl.c @@ -163,7 +163,6 @@ static void prv_calc_offsets(LtcAfeStorage *afe) { // Similarly, we do the opposite mapping for discharge. LtcAfeSettings *settings = &afe->settings; size_t cell_index = 0; - size_t aux_index = 0; for (size_t device = 0; device < settings->num_devices; device++) { for (size_t device_cell = 0; device_cell < LTC_AFE_MAX_CELLS_PER_DEVICE; device_cell++) { size_t cell = device * LTC_AFE_MAX_CELLS_PER_DEVICE + device_cell; @@ -174,12 +173,6 @@ static void prv_calc_offsets(LtcAfeStorage *afe) { afe->discharge_cell_lookup[cell_index] = cell; afe->cell_result_lookup[cell] = cell_index++; } - - if ((settings->aux_bitset[device] >> device_cell) & 0x1) { - // Cell input enabled - store the index that this input should be stored in - // when copying to the result array - afe->aux_result_lookup[cell] = aux_index++; - } } } } @@ -233,26 +226,15 @@ StatusCode ltc_afe_impl_read_cells(LtcAfeStorage *afe) { LtcAfeSettings *settings = &afe->settings; for (uint8_t cell_reg = 0; cell_reg < NUM_LTC_AFE_VOLTAGE_REGISTERS; ++cell_reg) { LtcAfeVoltageRegisterGroup voltage_register[LTC_AFE_MAX_DEVICES] = { 0 }; - prv_read_voltage(afe, cell_reg, voltage_register); + status_ok_or_return(prv_read_voltage(afe, cell_reg, voltage_register)); for (uint8_t device = 0; device < settings->num_devices; ++device) { - for (uint16_t cell = 0; cell < LTC6811_CELLS_IN_REG; ++cell) { - // LSB of the reading is 100 uV - uint16_t voltage = voltage_register[device].reg.voltages[cell]; - uint16_t device_cell = cell + (cell_reg * LTC6811_CELLS_IN_REG); - uint16_t index = device * LTC_AFE_MAX_CELLS_PER_DEVICE + device_cell; - - if ((settings->cell_bitset[device] >> device_cell) & 0x1) { - // Input enabled - store result - afe->cell_voltages[afe->cell_result_lookup[index]] = voltage; - } - } - // the Packet Error Code is transmitted after the cell data (see p.45) uint16_t received_pec = SWAP_UINT16(voltage_register[device].pec); uint16_t data_pec = crc15_calculate((uint8_t *)&voltage_register[device], 6); if (received_pec != data_pec) { // return early on failure + LOG_DEBUG("Communication Failed with device: %d\n\r", device); LOG_DEBUG("RECEIVED_PEC: %d\n\r", received_pec); LOG_DEBUG("DATA_PEC: %d\n\r", data_pec); LOG_DEBUG("Voltage: %d %d %d\n\r", voltage_register[device].reg.voltages[0], @@ -260,6 +242,18 @@ StatusCode ltc_afe_impl_read_cells(LtcAfeStorage *afe) { voltage_register[device].reg.voltages[2]); return status_code(STATUS_CODE_INTERNAL_ERROR); } + + for (uint16_t cell = 0; cell < LTC6811_CELLS_IN_REG; ++cell) { + // LSB of the reading is 100 uV + uint16_t voltage = voltage_register[device].reg.voltages[cell]; + uint16_t device_cell = cell + (cell_reg * LTC6811_CELLS_IN_REG); + uint16_t index = device * LTC_AFE_MAX_CELLS_PER_DEVICE + device_cell; + + if ((settings->cell_bitset[device] >> device_cell) & 0x1) { + // Input enabled - store result + afe->cell_voltages[afe->cell_result_lookup[index]] = voltage; + } + } } } @@ -271,19 +265,10 @@ StatusCode ltc_afe_impl_read_aux(LtcAfeStorage *afe, uint8_t thermistor) { LtcAfeAuxRegisterGroupPacket register_data[LTC_AFE_MAX_DEVICES] = { 0 }; size_t len = settings->num_devices * sizeof(LtcAfeAuxRegisterGroupPacket); - prv_read_register(afe, LTC_AFE_REGISTER_AUX_B, (uint8_t *)register_data, len); + status_ok_or_return( + prv_read_register(afe, LTC_AFE_REGISTER_AUX_B, (uint8_t *)register_data, len)); for (uint16_t device = 0; device < settings->num_devices; ++device) { - // data comes in in the form { 1, 1, 2, 2, 3, 3, PEC, PEC } - // we only care about GPIO4 and the PEC - uint16_t voltage = register_data[device].reg.voltages[0]; - - if ((settings->aux_bitset[device] >> thermistor) & 0x1) { - // Input enabled - store result - uint16_t index = device * LTC_AFE_MAX_CELLS_PER_DEVICE + thermistor; - afe->aux_voltages[afe->aux_result_lookup[index]] = voltage; - } - uint16_t received_pec = SWAP_UINT16(register_data[device].pec); uint16_t data_pec = crc15_calculate((uint8_t *)®ister_data[device], 6); if (received_pec != data_pec) { @@ -292,6 +277,15 @@ StatusCode ltc_afe_impl_read_aux(LtcAfeStorage *afe, uint8_t thermistor) { LOG_DEBUG("DATA_PEC: %d\n\r", data_pec); return status_code(STATUS_CODE_INTERNAL_ERROR); } + // data comes in in the form { 1, 1, 2, 2, 3, 3, PEC, PEC } + // we only care about GPIO4 and the PEC + uint16_t voltage = register_data[device].reg.voltages[0]; + + if ((settings->aux_bitset[device] >> thermistor) & 0x1) { + // Input enabled - store result + uint16_t index = device * LTC_AFE_MAX_THERMISTORS_PER_DEVICE + thermistor; + afe->aux_voltages[index] = voltage; + } } return STATUS_CODE_OK; } diff --git a/libraries/ms-drivers/src/max17261_fuel_gauge.c b/libraries/ms-drivers/src/max17261_fuel_gauge.c index d5cdd6ce0..3ea295d6a 100644 --- a/libraries/ms-drivers/src/max17261_fuel_gauge.c +++ b/libraries/ms-drivers/src/max17261_fuel_gauge.c @@ -1,14 +1,19 @@ #include "max17261_fuel_gauge.h" +#include + +#include "delay.h" #include "log.h" // See Table 3 on pg.18 of the datasheet -#define PCT_LSB (1.0f / 256) // LSBit is 1/256% -#define CAP_LSB (5.0f / storage->settings->r_sense_mohms) // LSBit is 5 micro Volt hrs / Rsense -#define TIM_LSB (5625U) // LSBit is 5625ms -#define CUR_LSB (1.5625f / storage->settings->r_sense_mohms) // LSBit is 1.5625uA / Rsense -#define VOLT_LSB (1.25f / 16) // LSBit is 1.25mV / 16 -#define TEMP_LSB (1.0f / 256) // LSBit is 1 / 256 C +#define PCT_LSB (1.0f / 256) // (%) LSBit is 1/256% +#define CAP_LSB \ + (5.0f / storage->settings->sense_resistor_mohms) // (mAh) LSBit is 5 mili Volt hrs / Rsense (mAh) +#define TIM_LSB (5625U) // (ms) LSBit is 5625ms +#define CUR_LSB \ + (1.5625f / storage->settings->sense_resistor_mohms) // (mA) LSBit is 1.5625uA / Rsense +#define VOLT_LSB (1.25f / 16) // (mV) LSBit is 1.25mV / 16 +#define TEMP_LSB (1.0f / 256) // (C) LSBit is 1 / 256 C static StatusCode max17261_get_reg(Max17261Storage *storage, Max17261Registers reg, uint16_t *value) { @@ -35,23 +40,34 @@ static StatusCode max17261_set_reg(Max17261Storage *storage, Max17261Registers r } StatusCode max17261_state_of_charge(Max17261Storage *storage, uint16_t *soc_pct) { + // clear lock bit if set - set on state of charge change + uint16_t reg = 0; + max17261_get_reg(storage, MAX17261_STATUS, ®); + if (reg & (1 << 7)) { + max17261_set_reg(storage, MAX17261_STATUS, reg & (uint16_t) ~(1 << 7)); + } + + uint16_t status = 0; + status_ok_or_return(max17261_get_reg(storage, MAX17261_STATUS, &status)); + uint16_t soc_reg_val = 0; status_ok_or_return(max17261_get_reg(storage, MAX17261_SOC, &soc_reg_val)); *soc_pct = soc_reg_val * PCT_LSB; return STATUS_CODE_OK; } -StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_uAhr) { +StatusCode max17261_remaining_capacity(Max17261Storage *storage, uint32_t *rem_cap_mAh) { uint16_t rem_cap_reg_val = 0; status_ok_or_return(max17261_get_reg(storage, MAX17261_CAP, &rem_cap_reg_val)); - *rem_cap_uAhr = rem_cap_reg_val * CAP_LSB; + *rem_cap_mAh = rem_cap_reg_val * CAP_LSB; return STATUS_CODE_OK; } -StatusCode max17261_full_capacity(Max17261Storage *storage, uint16_t *full_cap_uAhr) { +StatusCode max17261_full_capacity(Max17261Storage *storage, uint32_t *full_cap_mAh) { uint16_t full_cap_reg_val = 0; status_ok_or_return(max17261_get_reg(storage, MAX17261_FULL_CAP_REP, &full_cap_reg_val)); - *full_cap_uAhr = full_cap_reg_val * CAP_LSB; + *full_cap_mAh = full_cap_reg_val * CAP_LSB; + return STATUS_CODE_OK; } @@ -79,7 +95,8 @@ StatusCode max17261_current(Max17261Storage *storage, int16_t *current_ua) { StatusCode max17261_voltage(Max17261Storage *storage, uint16_t *vcell_mv) { uint16_t vcell_reg_val = 0; status_ok_or_return(max17261_get_reg(storage, MAX17261_VCELL, &vcell_reg_val)); - *vcell_mv = (uint16_t)((float)(vcell_reg_val)*VOLT_LSB / 2.5); // Reports 2.5x the Cell_X voltage + *vcell_mv = (uint16_t)((float)(vcell_reg_val)*VOLT_LSB); + return STATUS_CODE_OK; } @@ -90,44 +107,129 @@ StatusCode max17261_temp(Max17261Storage *storage, uint16_t *temp_c) { return STATUS_CODE_OK; } -StatusCode max17261_init(Max17261Storage *storage, Max17261Settings *settings) { +StatusCode max17261_get_learned_params(Max17261Storage *storage, Max27261Params *params) { + status_ok_or_return(max17261_get_reg(storage, MAX17261_R_COMP0, ¶ms->rcomp0)); + status_ok_or_return(max17261_get_reg(storage, MAX17261_TEMP_CO, ¶ms->tempco)); + status_ok_or_return(max17261_get_reg(storage, MAX17261_FULL_CAP_REP, ¶ms->fullcaprep)); + status_ok_or_return(max17261_get_reg(storage, MAX17261_CYCLES, ¶ms->cycles)); + status_ok_or_return(max17261_get_reg(storage, MAX17261_FULL_CAP_NOM, ¶ms->fullcapnom)); + return STATUS_CODE_OK; +} + +StatusCode max17261_set_learned_params(Max17261Storage *storage, Max27261Params *params) { + status_ok_or_return(max17261_set_reg(storage, MAX17261_R_COMP0, params->rcomp0)); + status_ok_or_return(max17261_set_reg(storage, MAX17261_TEMP_CO, params->tempco)); + // somehow replaces fullcap with repcap, throws off all calculations. Battery degredation + // shouldn't be a huge factor for our time scale + // status_ok_or_return(max17261_set_reg(storage, MAX17261_FULL_CAP_REP, params->fullcaprep)); + status_ok_or_return(max17261_set_reg(storage, MAX17261_CYCLES, params->cycles)); + status_ok_or_return(max17261_set_reg(storage, MAX17261_FULL_CAP_NOM, params->fullcapnom)); + return STATUS_CODE_OK; +} + +StatusCode max17261_init(Max17261Storage *storage, Max17261Settings *settings, + Max27261Params *params) { if (settings->i2c_port >= NUM_I2C_PORTS) { return STATUS_CODE_INVALID_ARGS; } storage->settings = settings; - // Configuration for alerts - // Enable current, voltage, and temperature alerts (pg.17 of datasheet, Config (1Dh) Format) - uint16_t config = 0; - status_ok_or_return(max17261_get_reg(storage, MAX17261_CONFIG, &config)); - config |= (1 << 2); - // Enable external temp readings - // config |= (1 << 15); - // config |= (1 << 8); - // config |= (1 << 4); - status_ok_or_return(max17261_set_reg(storage, MAX17261_CONFIG, config)); - // Upper byte is IMAX and lower byte is IMIN - uint16_t current_th = (settings->i_thresh_max << 8) & (settings->i_thresh_min & 0x00FF); - status_ok_or_return(max17261_set_reg(storage, MAX17261_I_ALRT_TH, current_th)); - // Upper byte is TMAX and lower byte is TMIN (leave TMIN as 0 C) - status_ok_or_return( - max17261_set_reg(storage, MAX17261_TEMP_ALRT_THRSH, (settings->temp_thresh_max << 8))); + // ** Based on + // https://web.archive.org/web/20240330212616/https://pdfserv.maximintegrated.com/en/an/MAX1726x-Software-Implementation-user-guide.pdf + // Step 0 - check if already configured + uint16_t status = 0; + status_ok_or_return(max17261_get_reg(storage, MAX17261_STATUS, &status)); + if ((status & 0x0002) != 0) { + // Step 1 -- delay until FSTAT.DNR bit == 0 + uint16_t fstat = 0; + status_ok_or_return(max17261_get_reg(storage, MAX17261_FSTAT, &fstat)); + // Checks that initializaton has occurred, must happen before configuration + // Should not take longer than 250 ms + TickType_t start_time = xTaskGetTickCount(); + while ((fstat & 1) != 0) { + LOG_DEBUG("data not ready, fstat: %d (%d)\n", fstat, fstat & 1); + status_ok_or_return(max17261_get_reg(storage, MAX17261_FSTAT, &fstat)); + if (xTaskGetTickCount() >= start_time + pdMS_TO_TICKS(250)) { + LOG_DEBUG("fstat failed: %d (%d)\n", fstat, fstat & 1); + break; + } + delay_ms(10); + } + + // Step 2 -- disable hibernation + uint16_t hibcfg = 0; + status_ok_or_return(max17261_get_reg(storage, MAX17261_HIB_CFG, &hibcfg)); + status_ok_or_return(max17261_set_reg(storage, MAX17261_SOFT_WAKEUP, 0x90)); // wakup ic + status_ok_or_return(max17261_set_reg(storage, MAX17261_HIB_CFG, 0x0)); // disable hibernation + status_ok_or_return( + max17261_set_reg(storage, MAX17261_SOFT_WAKEUP, 0x0)); // clear wakeup command + + delay_ms( + 25); // unsure why this works, not mentioned in any documentation. Seems reliable enough. + + // Step 2.1 -- configure + status_ok_or_return( + max17261_set_reg(storage, MAX17261_DESIGN_CAP, settings->pack_design_cap_mah / CAP_LSB)); + status_ok_or_return( + max17261_set_reg(storage, MAX17261_I_CHG_TERM, settings->charge_term_current_ma / CUR_LSB)); + status_ok_or_return( + max17261_set_reg(storage, MAX17261_V_EMPTY, settings->cell_empty_voltage_v / VOLT_LSB)); + + status_ok_or_return( + max17261_set_reg(storage, MAX17261_SOC_HOLD, 0x0)); // disable SOCHold, not relevant to us + + uint16_t modelcfg = 0; + modelcfg |= (1 << 15); // refresh + modelcfg |= (0 << 13); // R100 + modelcfg |= (0 << 10); // RChg + modelcfg |= (1 << 3); // mandatory 1 + status_ok_or_return(max17261_set_reg(storage, MAX17261_MODEL_I_CFG, modelcfg)); + + // wait for modelcfg refresh to complete + // Should not take longer than 1sec + start_time = xTaskGetTickCount(); + while (modelcfg & (1 << 15)) { + LOG_DEBUG("modelcfg refresh not cleared: %d\n", modelcfg); + status_ok_or_return(max17261_get_reg(storage, MAX17261_MODEL_I_CFG, &modelcfg)); + if (xTaskGetTickCount() >= start_time + pdMS_TO_TICKS(1000)) { + LOG_DEBUG("modelcfg failed: %d (%d)\n", fstat, fstat & 1); + break; + } + delay_ms(10); + } + + // Configure alerts + uint16_t config = 0; + status_ok_or_return(max17261_get_reg(storage, MAX17261_CONFIG, &config)); + config |= (1 << 2); // enable alerts + config |= (1 << 4); // thermal alerts + config |= (1 << 8); // external temp measurement + status_ok_or_return(max17261_set_reg(storage, MAX17261_CONFIG, config)); + + uint16_t current_th = (settings->i_thresh_max_a << 8) & (settings->i_thresh_min_a & 0x00FF); + status_ok_or_return(max17261_set_reg(storage, MAX17261_I_ALRT_TH, current_th)); + + status_ok_or_return( + max17261_set_reg(storage, MAX17261_TEMP_ALRT_THRSH, (settings->temp_thresh_max_c < 8))); + + // Disable voltage alert (handled by AFE) + status_ok_or_return(max17261_set_reg(storage, MAX17261_VOLT_ALRT_THRSH, 0xFF00)); + // Disable state of charge alerting (no need to fault on SOC) + status_ok_or_return(max17261_set_reg(storage, MAX17261_SOC_ALRT_THRSH, 0xFF00)); + + // enable hibernation + status_ok_or_return(max17261_set_reg(storage, MAX17261_HIB_CFG, hibcfg)); + } - // Make sure voltage alerts are disabled (handled by AFEs) (see datasheet pg.25 for disabled - // VAlrtTh value) - status_ok_or_return(max17261_set_reg(storage, MAX17261_VOLT_ALRT_THRSH, (0xFF00))); - // Make sure SOC alerts are disabled (see datasheet pg.26 for disabled SAlrtTh value) - status_ok_or_return(max17261_set_reg(storage, MAX17261_SOC_ALRT_THRSH, (0xFF00))); + // Step 3 + status_ok_or_return(max17261_get_reg(storage, MAX17261_STATUS, &status)); + status_ok_or_return(max17261_set_reg(storage, MAX17261_STATUS, + status & (uint16_t) ~(1 << 1))); // clear status POR bit - status_ok_or_return(max17261_set_reg(storage, MAX17261_DESIGN_CAP, settings->design_capacity)); - status_ok_or_return( - max17261_set_reg(storage, MAX17261_I_CHG_TERM, settings->charge_term_current)); - uint16_t old_vempty = 0; - status_ok_or_return(max17261_get_reg(storage, MAX17261_V_EMPTY, &old_vempty)); - // the 7 LSBits of the vempty reg is the recovery voltage, the last 9 are the empty voltage - uint16_t new_vempty = (settings->empty_voltage << 7) + (old_vempty & 0x7F); - status_ok_or_return(max17261_set_reg(storage, MAX17261_V_EMPTY, new_vempty)); + if (params) { + status_ok_or_return(max17261_set_learned_params(storage, params)); + } return STATUS_CODE_OK; } diff --git a/projects/bms_carrier/inc/bms.h b/projects/bms_carrier/inc/bms.h index f141e52f6..490c94ac8 100644 --- a/projects/bms_carrier/inc/bms.h +++ b/projects/bms_carrier/inc/bms.h @@ -21,6 +21,8 @@ typedef struct CurrentStorage { uint16_t voltage; uint16_t temperature; uint32_t fuel_guage_cycle_ms; // Time in ms between conversions (soft timer kicks) + uint32_t remaining_capacity; + uint32_t full; } CurrentStorage; typedef struct BmsStorage { diff --git a/projects/bms_carrier/inc/cell_sense.h b/projects/bms_carrier/inc/cell_sense.h index b392c383d..577372e68 100644 --- a/projects/bms_carrier/inc/cell_sense.h +++ b/projects/bms_carrier/inc/cell_sense.h @@ -14,12 +14,12 @@ #include "spi.h" #define CONV_DELAY_MS 10 +#define AUX_CONV_DELAY_MS 3 // Maximum number of retry attempts to read cell/aux data once triggered #define RETRY_DELAY_MS 1 #define CELL_SENSE_CONVERSIONS 0 -// Fault thresholds -// TODO: Verify these values! +// Fault thresholds - units of mV*10 #define CELL_OVERVOLTAGE 42500 #define CELL_UNDERVOLTAGE 25000 #define CELL_UNBALANCED 5000 diff --git a/projects/bms_carrier/inc/current_sense.h b/projects/bms_carrier/inc/current_sense.h index 10cb45fd6..518fa42fe 100644 --- a/projects/bms_carrier/inc/current_sense.h +++ b/projects/bms_carrier/inc/current_sense.h @@ -1,8 +1,5 @@ #pragma once -// Stores current readings from the ADS1259 in a ring buffer. -// Requires interrupts and soft timers to be initialized. - #include #include @@ -17,35 +14,28 @@ #define MAX17261_I2C_PORT (I2C_PORT_2) #define MAX17261_I2C_ADDR (0x36) -#define CURRENT_SENSE_R_SENSE_MOHMS (0.5) -#define PACK_CAPACITY_MAH 3000 +#define SENSE_RESISTOR_MOHM (0.5) -// Capacity in units of 5.0uVh/Rsense -#define MAIN_PACK_DESIGN_CAPACITY (PACK_CAPACITY_MAH * CURRENT_SENSE_R_SENSE_MOHMS / 5) +#define PACK_CAPACITY_MAH (160000) // one module -// LSB = 78.125 (micro Volts) -#define MAIN_PACK_EMPTY_VOLTAGE_MV 2500 -#define MAIN_PACK_EMPTY_VOLTAGE (MAIN_PACK_EMPTY_VOLTAGE_MV / 78.125) +#define CELL_EMPTY_VOLTAGE_MV 2500 // LG M50T datasheet -#define CHARGE_TERMINATION_CURRENT 0 +#define CHARGE_TERMINATION_CURRENT_MA (400) // 50 mA * 8 (one module) -// // TODO (Adel C): Change these values to their actual values -// #define CURRENT_SENSE_R_SENSE_MILLI_OHMS (0.5) -// #define MAIN_PACK_DESIGN_CAPACITY -// (1.0f / CURRENT_SENSE_R_SENSE_MILLI_OHMS) // LSB = 5.0 (micro Volt Hours / R Sense) -// #define MAIN_PACK_EMPTY_VOLTAGE (1.0f / 78.125) // Only a 9-bit field, LSB = 78.125 (micro -// Volts) #define CHARGE_TERMINATION_CURRENT (1.0f / (1.5625f / CURRENT_SENSE_R_SENSE_MILLI_OHMS)) +#define NUM_SERIES_CELLS 36 // Number of cells in series to multiply average cell voltage // Thresholds for ALRT Pin -#define CURRENT_SENSE_MAX_CURRENT_A (58.2f) // 58.2 Amps -#define CURRENT_SENSE_MIN_CURRENT_A (27.0f) // Actually -27 -#define CURRENT_SENSE_MAX_TEMP (60U) -#define CURRENT_SENSE_MAX_VOLTAGE (15000U) // uints of 10mv +#define CURRENT_SENSE_MAX_CURRENT_A (58.2f) +#define CURRENT_SENSE_MIN_CURRENT_A (-27.0f) // Actually -27 +#define CURRENT_SENSE_MAX_TEMP_C (60U) +#define CURRENT_SENSE_MAX_VOLTAGE_V (15000) #define ALRT_PIN_V_RES_MICRO_V (400) #define CELL_X_R1_KOHMS 1780 #define CELL_X_R2_KOHMS 20 +#define CURRENT_SENSE_STORE_FLASH NUM_FLASH_PAGES - 1 + // Enum for GPIO IT alerts (just the one pin) typedef enum { CURRENT_SENSE_RUN_CYCLE = 0, ALRT_GPIO_IT, KILLSWITCH_IT } CurrentSenseNotification; diff --git a/projects/bms_carrier/inc/relays.h b/projects/bms_carrier/inc/relays.h index 22872d9e5..0006ebfef 100644 --- a/projects/bms_carrier/inc/relays.h +++ b/projects/bms_carrier/inc/relays.h @@ -11,7 +11,7 @@ #include "status.h" #include "task.h" -#define BMS_CLOSE_RELAYS_DELAY_MS 300 +#define BMS_CLOSE_RELAYS_DELAY_MS 200 // Enumerated set of relays to be closed typedef enum RelayType { diff --git a/projects/bms_carrier/src/cell_sense.c b/projects/bms_carrier/src/cell_sense.c index edf134529..01090faf8 100644 --- a/projects/bms_carrier/src/cell_sense.c +++ b/projects/bms_carrier/src/cell_sense.c @@ -5,6 +5,9 @@ LtcAfeStorage *ltc_afe_storage; #define TEMP_RESISTANCE 10000 #define VREF2 30000 #define TABLE_SIZE 125 +#define LTC_RETRIES 3 + +uint8_t afe_message_index = 0; typedef enum ThermistorMap { THERMISTOR_2 = 0, @@ -61,56 +64,95 @@ static const LtcAfeSettings s_afe_settings = { .adc_mode = LTC_AFE_ADC_MODE_7KHZ, .cell_bitset = { 0xFFF, 0xFFF, 0xFFF }, - .aux_bitset = { 0xFF, 0xFF, 0xFF }, + .aux_bitset = { 0x15, 0x15, 0x15 }, .num_devices = 3, .num_cells = 12, - .num_thermistors = 0, + .num_thermistors = NUM_THERMISTORS, }; static inline StatusCode prv_cell_sense_conversions() { StatusCode status = STATUS_CODE_OK; // TODO: Figure out why cell_conv cannot happen without spi timing out (Most likely RTOS // implemntation error) Retry Mechanism - if (ltc_afe_impl_trigger_cell_conv(ltc_afe_storage)) { + for (uint8_t retries = LTC_RETRIES; retries > 0; retries--) { + status = ltc_afe_impl_trigger_cell_conv(ltc_afe_storage); + if (status == STATUS_CODE_OK) { + break; + } + LOG_DEBUG("Cell trigger conv failed, retrying %d\n", status); + delay_ms(RETRY_DELAY_MS); + } + if (status) { // If this has failed, try once more after a short delay - status |= ltc_afe_impl_trigger_cell_conv(ltc_afe_storage); + LOG_DEBUG("Cell trigger conv failed, retrying): %d\n", status); + delay_ms(RETRY_DELAY_MS); + status = ltc_afe_impl_trigger_cell_conv(ltc_afe_storage); } - delay_ms(CONV_DELAY_MS); - if (status != STATUS_CODE_OK) { LOG_DEBUG("Cell conv failed): %d\n", status); fault_bps_set(BMS_FAULT_COMMS_LOSS_AFE); return status; } + delay_ms(CONV_DELAY_MS); - status |= ltc_afe_impl_read_cells(ltc_afe_storage); - + for (uint8_t retries = LTC_RETRIES; retries > 0; retries--) { + status = ltc_afe_impl_read_cells(ltc_afe_storage); + if (status == STATUS_CODE_OK) { + break; + } + LOG_DEBUG("Cell read failed, retrying %d\n", status); + delay_ms(RETRY_DELAY_MS); + } if (status != STATUS_CODE_OK) { - LOG_DEBUG("Cell read failed\n"); + LOG_DEBUG("Cell read failed %d\n", status); fault_bps_set(BMS_FAULT_COMMS_LOSS_AFE); return status; } - for (size_t i = 0; i < s_afe_settings.num_thermistors * s_afe_settings.num_devices; i += 2) { - // Thermistor select cell 0 - status |= ltc_afe_impl_trigger_aux_conv(ltc_afe_storage, s_thermistor_map[i]); - // DELAY NEEDED for adc conv to happen - delay_ms(1); - // Thermistor read cell 0 - status |= ltc_afe_impl_read_aux(ltc_afe_storage, i); - - if (status != STATUS_CODE_OK) { - LOG_DEBUG("Thermistor read/conv failed\n"); - fault_bps_set(BMS_FAULT_COMMS_LOSS_AFE); - return status; + for (size_t thermistor = 0; thermistor < s_afe_settings.num_thermistors; thermistor += 1) { + // Thermistor indexes are read for each daisy chained dev at the same time + // Check therm bitset to determine if we need to read any at this index + bool check_therm = false; + for (uint8_t dev = 0; dev < s_afe_settings.num_devices; dev++) { + if ((s_afe_settings.aux_bitset[dev] >> thermistor) & 0x1) { + check_therm = true; + } } - // Log thermistor result - ltc_afe_storage->aux_voltages[ltc_afe_storage->aux_result_lookup[i]] = - calculate_temperature(ltc_afe_storage->aux_voltages[ltc_afe_storage->aux_result_lookup[i]]); + if (check_therm) { + // Trigger and read thermistor value + for (uint8_t retries = LTC_RETRIES; retries > 0; retries--) { + status = ltc_afe_impl_trigger_aux_conv(ltc_afe_storage, s_thermistor_map[thermistor]); + if (status == STATUS_CODE_OK) { + break; + } + LOG_DEBUG("Aux trigger conv failed, retrying: %d\n", status); + delay_ms(RETRY_DELAY_MS); + } + if (status) { + LOG_DEBUG("Thermistor conv failed for therm %d: Status %d\n", (uint8_t)thermistor, status); + fault_bps_set(BMS_FAULT_COMMS_LOSS_AFE); + return status; + } + delay_ms(AUX_CONV_DELAY_MS); + + for (uint8_t retries = LTC_RETRIES; retries > 0; retries--) { + status = ltc_afe_impl_read_aux(ltc_afe_storage, thermistor); + if (status == STATUS_CODE_OK) { + break; + } + LOG_DEBUG("Thermistor read failed, retrying %d\n", status); + delay_ms(RETRY_DELAY_MS); + } + if (status) { + LOG_DEBUG("Thermistor read trigger failed for thermistor %d, %d\n", (uint8_t)thermistor, + status); + fault_bps_set(BMS_FAULT_COMMS_LOSS_AFE); + return status; + } + } } - return status; } @@ -118,12 +160,7 @@ static inline StatusCode prv_cell_sense_conversions() { TASK(cell_sense_conversions, TASK_STACK_256) { while (true) { notify_wait(NULL, BLOCK_INDEFINITELY); - - // run conversions every 10 seconds - // if (xTaskGetTickCount() - ltc_afe_storage->timer_start >= pdMS_TO_TICKS(10000)) { prv_cell_sense_conversions(); - // } - send_task_end(); } } @@ -142,9 +179,8 @@ StatusCode cell_sense_run() { StatusCode status = STATUS_CODE_OK; uint16_t max_voltage = 0; uint16_t min_voltage = 0xffff; - for (size_t cell = 0; cell < (s_afe_settings.num_devices * s_afe_settings.num_cells); cell++) { - LOG_DEBUG("CELL %zu: %d\n\r", cell, + LOG_DEBUG("CELL %d: %d\n\r", (uint8_t)cell, ltc_afe_storage->cell_voltages[ltc_afe_storage->cell_result_lookup[cell]]); delay_ms(3); max_voltage = @@ -156,24 +192,26 @@ StatusCode cell_sense_run() { ? ltc_afe_storage->cell_voltages[ltc_afe_storage->cell_result_lookup[cell]] : min_voltage; } - // LOG_DEBUG("MAX VOLTAGE: %d\n", max_voltage); - // LOG_DEBUG("MIN VOLTAGE: %d\n", min_voltage); - set_battery_info_max_cell_v(max_voltage); + delay_ms(10); + LOG_DEBUG("MAX VOLTAGE: %d\n", max_voltage); + LOG_DEBUG("MIN VOLTAGE: %d\n", min_voltage); + LOG_DEBUG("UNBALANCE: %d\n", max_voltage - min_voltage); + set_battery_info_max_cell_v(max_voltage); if (max_voltage >= CELL_OVERVOLTAGE) { LOG_DEBUG("OVERVOLTAGE\n"); fault_bps_set(BMS_FAULT_OVERVOLTAGE); - return STATUS_CODE_INTERNAL_ERROR; + status = STATUS_CODE_INTERNAL_ERROR; } if (min_voltage <= CELL_UNDERVOLTAGE) { LOG_DEBUG("UNDERVOLTAGE\n"); fault_bps_set(BMS_FAULT_UNDERVOLTAGE); - return STATUS_CODE_INTERNAL_ERROR; + status = STATUS_CODE_INTERNAL_ERROR; } if (max_voltage - min_voltage >= CELL_UNBALANCED) { LOG_DEBUG("UNBALANCED\n"); fault_bps_set(BMS_FAULT_UNBALANCE); - return STATUS_CODE_INTERNAL_ERROR; + status = STATUS_CODE_INTERNAL_ERROR; } if (min_voltage >= AFE_BALANCING_UPPER_THRESHOLD) { @@ -184,7 +222,8 @@ StatusCode cell_sense_run() { } else { min_voltage += 250; } - // ltc_afe_storage->timer_start = xTaskGetTickCount(); + + // Balancing for (size_t cell = 0; cell < (s_afe_settings.num_devices * s_afe_settings.num_cells); cell++) { if (ltc_afe_storage->cell_voltages[ltc_afe_storage->cell_result_lookup[cell]] > min_voltage) { ltc_afe_impl_toggle_cell_discharge(ltc_afe_storage, cell, true); @@ -195,19 +234,59 @@ StatusCode cell_sense_run() { // LOG_DEBUG("Config discharge bitset %d\n", ltc_afe_storage->discharge_bitset[0]); - for (size_t thermistor = 0; - thermistor < s_afe_settings.num_thermistors * s_afe_settings.num_devices; thermistor += 2) { - // Log thermistor result - // LOG_DEBUG("Thermistor reading: %d\n", - // ltc_afe_storage->aux_voltages[ltc_afe_storage->aux_result_lookup[thermistor]]); - - if (ltc_afe_storage->aux_result_lookup[thermistor] >= CELL_MAX_TEMPERATURE) { - LOG_DEBUG("CELL OVERTEMP\n"); - fault_bps_set(BMS_FAULT_OVERTEMP_CELL); - return STATUS_CODE_INTERNAL_ERROR; + // Log and check all thermistor values based on settings bitset + for (uint8_t dev = 0; dev < s_afe_settings.num_devices; dev++) { + for (uint8_t thermistor = 0; thermistor < LTC_AFE_MAX_THERMISTORS_PER_DEVICE; thermistor += 1) { + if ((s_afe_settings.aux_bitset[dev] >> thermistor) & 0x1) { + uint8_t index = dev * LTC_AFE_MAX_THERMISTORS_PER_DEVICE + thermistor; + ltc_afe_storage->aux_voltages[index] = + calculate_temperature(ltc_afe_storage->aux_voltages[index]); + LOG_DEBUG("Thermistor reading dev %d, %d: %d\n", dev, thermistor, + ltc_afe_storage->aux_voltages[index]); + delay_ms(3); + if (ltc_afe_storage->aux_result_lookup[index] >= CELL_MAX_TEMPERATURE) { + LOG_DEBUG("CELL OVERTEMP\n"); + fault_bps_set(BMS_FAULT_OVERTEMP_CELL); + status = STATUS_CODE_INTERNAL_ERROR; + } + } } } + // CAN Logging + // AFE messages are logged with 3 voltages at a time, and an index 0-3 to encompass all voltages + const uint8_t NUM_MSG = 4; + const uint8_t READINGS_PER_MSG = 3; + + uint8_t read_index = afe_message_index * READINGS_PER_MSG; + set_AFE1_status_id(afe_message_index); + set_AFE1_status_v1(ltc_afe_storage->cell_voltages[read_index]); + set_AFE1_status_v2(ltc_afe_storage->cell_voltages[read_index + 1]); + set_AFE1_status_v3(ltc_afe_storage->cell_voltages[read_index + 2]); + + read_index = (uint8_t)s_afe_settings.num_cells + afe_message_index * READINGS_PER_MSG; + set_AFE2_status_id(afe_message_index); + set_AFE2_status_v1(ltc_afe_storage->cell_voltages[read_index]); + set_AFE2_status_v2(ltc_afe_storage->cell_voltages[read_index + 1]); + set_AFE2_status_v3(ltc_afe_storage->cell_voltages[read_index + 2]); + + read_index = (uint8_t)s_afe_settings.num_cells * 2 + afe_message_index * READINGS_PER_MSG; + set_AFE3_status_id(afe_message_index); + set_AFE3_status_v1(ltc_afe_storage->cell_voltages[read_index]); + set_AFE3_status_v2(ltc_afe_storage->cell_voltages[read_index + 1]); + set_AFE3_status_v3(ltc_afe_storage->cell_voltages[read_index + 2]); + + // Thermistors to send are at index 0, 2, 4 for each device + if (afe_message_index < + NUM_MSG - 1) { // Only 3 thermistors per device, so 4th message will be ignored + set_AFE1_status_temp(ltc_afe_storage->aux_voltages[afe_message_index * 2]); + set_AFE2_status_temp( + ltc_afe_storage->aux_voltages[LTC_AFE_MAX_THERMISTORS_PER_DEVICE + afe_message_index * 2]); + set_AFE3_status_temp(ltc_afe_storage->aux_voltages[LTC_AFE_MAX_THERMISTORS_PER_DEVICE * 2 + + afe_message_index * 2]); + } + + afe_message_index = (afe_message_index + 1) % NUM_MSG; return status; } diff --git a/projects/bms_carrier/src/current_sense.c b/projects/bms_carrier/src/current_sense.c index 482085ccc..fae9a6c1d 100644 --- a/projects/bms_carrier/src/current_sense.c +++ b/projects/bms_carrier/src/current_sense.c @@ -1,5 +1,6 @@ #include "current_sense.h" +#include #include #include "bms.h" @@ -9,13 +10,21 @@ #include "gpio_it.h" #include "interrupt.h" #include "log.h" +#include "persist.h" #include "tasks.h" +// Update stored learned params every 30 sec +#define UPDATE_FLASH_PARAMS_PERIOD_MS 10000 + static Max17261Storage s_fuel_guage_storage; static Max17261Settings s_fuel_gauge_settings; static CurrentStorage *s_current_storage; static bool s_is_charging; +static PersistStorage s_persist; +static Max27261Params s_fuel_params; +static TickType_t s_last_params_update; + // Periodically read and update the SoC of the car & update charging bool StatusCode prv_fuel_gauge_read() { StatusCode status = STATUS_CODE_OK; @@ -23,14 +32,19 @@ StatusCode prv_fuel_gauge_read() { status |= max17261_state_of_charge(&s_fuel_guage_storage, &s_current_storage->soc); status |= max17261_current(&s_fuel_guage_storage, &s_current_storage->current); status |= max17261_voltage(&s_fuel_guage_storage, &s_current_storage->voltage); - s_current_storage->voltage = (s_current_storage->voltage) * (CELL_X_R2_KOHMS + CELL_X_R1_KOHMS) / - (CELL_X_R2_KOHMS) / 10; // Convert to V -> mV status |= max17261_temp(&s_fuel_guage_storage, &s_current_storage->temperature); + status |= + max17261_remaining_capacity(&s_fuel_guage_storage, &s_current_storage->remaining_capacity); + status |= max17261_full_capacity(&s_fuel_guage_storage, &s_current_storage->full); + // Measured voltage corresponds to one cell. Multiply it by the number of cells in series + s_current_storage->voltage = s_current_storage->voltage * NUM_SERIES_CELLS / 10; LOG_DEBUG("SOC: %d\n", s_current_storage->soc); LOG_DEBUG("CURRENT: %d\n", s_current_storage->current); LOG_DEBUG("VOLTAGE: %d\n", s_current_storage->voltage); LOG_DEBUG("TEMP: %d\n", s_current_storage->temperature); + LOG_DEBUG("REMCAP: %" PRIu32 "\n", s_current_storage->remaining_capacity); + LOG_DEBUG("FULLCAP: %" PRIu32 "\n", s_current_storage->full); if (status != STATUS_CODE_OK) { // TODO (Adel): Handle a fuel gauge fault @@ -50,14 +64,24 @@ StatusCode prv_fuel_gauge_read() { if (s_current_storage->current >= CURRENT_SENSE_MAX_CURRENT_A * 1000) { fault_bps_set(BMS_FAULT_OVERCURRENT); return STATUS_CODE_INTERNAL_ERROR; - } else if (s_current_storage->voltage >= CURRENT_SENSE_MAX_VOLTAGE) { + } else if (s_current_storage->current <= CURRENT_SENSE_MIN_CURRENT_A * 1000) { + fault_bps_set(BMS_FAULT_OVERCURRENT); + return STATUS_CODE_INTERNAL_ERROR; + } else if (s_current_storage->voltage >= CURRENT_SENSE_MAX_VOLTAGE_V) { fault_bps_set(BMS_FAULT_OVERVOLTAGE); return STATUS_CODE_INTERNAL_ERROR; - } else if (s_current_storage->temperature >= CURRENT_SENSE_MAX_TEMP) { + } else if (s_current_storage->temperature >= CURRENT_SENSE_MAX_TEMP_C) { fault_bps_set(BMS_FAULT_OVERTEMP_AMBIENT); return STATUS_CODE_INTERNAL_ERROR; } + // Commit params info periodically + if (xTaskGetTickCount() > s_last_params_update + pdMS_TO_TICKS(UPDATE_FLASH_PARAMS_PERIOD_MS)) { + LOG_DEBUG("Updating params\n"); + s_last_params_update = xTaskGetTickCount(); + max17261_get_learned_params(&s_fuel_guage_storage, &s_fuel_params); + persist_commit(&s_persist); + } return status; } @@ -73,7 +97,6 @@ TASK(current_sense, TASK_STACK_256) { } else if (notification & 1 << KILLSWITCH_IT) { fault_bps_set(BMS_FAULT_KILLSWITCH); } - prv_fuel_gauge_read(); send_task_end(); } @@ -91,6 +114,7 @@ StatusCode current_sense_run() { StatusCode current_sense_init(BmsStorage *bms_storage, I2CSettings *i2c_settings, uint32_t fuel_guage_cycle_ms) { + StatusCode status = STATUS_CODE_OK; s_current_storage = &bms_storage->current_storage; s_fuel_gauge_settings = bms_storage->fuel_guage_settings; s_fuel_guage_storage = bms_storage->fuel_guage_storage; @@ -112,25 +136,27 @@ StatusCode current_sense_init(BmsStorage *bms_storage, I2CSettings *i2c_settings s_fuel_gauge_settings.i2c_port = I2C_PORT_2; s_fuel_gauge_settings.i2c_address = MAX17261_I2C_ADDR; - s_fuel_gauge_settings.charge_term_current = CHARGE_TERMINATION_CURRENT; - s_fuel_gauge_settings.design_capacity = MAIN_PACK_DESIGN_CAPACITY; - s_fuel_gauge_settings.empty_voltage = MAIN_PACK_EMPTY_VOLTAGE; + s_fuel_gauge_settings.charge_term_current_ma = CHARGE_TERMINATION_CURRENT_MA; + s_fuel_gauge_settings.pack_design_cap_mah = PACK_CAPACITY_MAH; + s_fuel_gauge_settings.cell_empty_voltage_v = CELL_EMPTY_VOLTAGE_MV; // Expected MAX current / (uV / uOhmsSense) resolution - s_fuel_gauge_settings.i_thresh_max = - ((CURRENT_SENSE_MAX_CURRENT_A) / (ALRT_PIN_V_RES_MICRO_V / CURRENT_SENSE_R_SENSE_MOHMS)); - // Expected MIN current / (uV / uOhmsSense) resolution - s_fuel_gauge_settings.i_thresh_min = - ((CURRENT_SENSE_MIN_CURRENT_A) / (ALRT_PIN_V_RES_MICRO_V / CURRENT_SENSE_R_SENSE_MOHMS)); - // Interrupt threshold limits are stored in 2s-complement format with 1C resolution - s_fuel_gauge_settings.temp_thresh_max = CURRENT_SENSE_MAX_TEMP; + // TODO impl alert + // s_fuel_gauge_settings.i_thresh_max = + // ((CURRENT_SENSE_MAX_CURRENT_A) / (ALRT_PIN_V_RES_MICRO_V / CURRENT_SENSE_R_SENSE_MOHMS)); + // // Expected MIN current / (uV / uOhmsSense) resolution + // s_fuel_gauge_settings.i_thresh_min = + // ((CURRENT_SENSE_MIN_CURRENT_A) / (ALRT_PIN_V_RES_MICRO_V / CURRENT_SENSE_R_SENSE_MOHMS)); + // // Interrupt threshold limits are stored in 2s-complement format with 1C resolution + // s_fuel_gauge_settings.temp_thresh_max = CURRENT_SENSE_MAX_TEMP; - s_fuel_gauge_settings.r_sense_mohms = CURRENT_SENSE_R_SENSE_MOHMS; + s_fuel_gauge_settings.sense_resistor_mohms = SENSE_RESISTOR_MOHM; // Soft timer period for soc & chargin check s_current_storage->fuel_guage_cycle_ms = fuel_guage_cycle_ms; - status_ok_or_return(max17261_init(&s_fuel_guage_storage, &s_fuel_gauge_settings)); - tasks_init_task(current_sense, TASK_PRIORITY(2), NULL); - return STATUS_CODE_OK; + persist_init(&s_persist, CURRENT_SENSE_STORE_FLASH, &s_fuel_params, sizeof(s_fuel_params), false); + // status = max17261_init(&s_fuel_guage_storage, &s_fuel_gauge_settings, &s_fuel_params); + // tasks_init_task(current_sense, TASK_PRIORITY(2), NULL); + return status; } diff --git a/projects/bms_carrier/src/fan.c b/projects/bms_carrier/src/fan.c index 77fcf394d..de55723da 100644 --- a/projects/bms_carrier/src/fan.c +++ b/projects/bms_carrier/src/fan.c @@ -29,14 +29,16 @@ static void prv_bms_fan_sense(void) { } void bms_run_fan(void) { + pwm_set_dc(PWM_TIMER_1, 100, 1); if (s_storage->current_storage.temperature >= BMS_FAN_TEMP_UPPER_THRESHOLD) { - pwm_set_dc(PWM_TIMER_1, 100); + pwm_set_dc(PWM_TIMER_1, 100, 1); } else if (s_storage->current_storage.temperature <= BMS_FAN_TEMP_LOWER_THRESHOLD) { - pwm_set_dc(PWM_TIMER_1, 0); + pwm_set_dc(PWM_TIMER_1, 0, 1); } else { pwm_set_dc(PWM_TIMER_1, (100 * (s_storage->current_storage.temperature - BMS_FAN_TEMP_LOWER_THRESHOLD)) / - (BMS_FAN_TEMP_UPPER_THRESHOLD - BMS_FAN_TEMP_LOWER_THRESHOLD)); + (BMS_FAN_TEMP_UPPER_THRESHOLD - BMS_FAN_TEMP_LOWER_THRESHOLD), + 1); } prv_bms_fan_sense(); } @@ -45,8 +47,8 @@ void bms_fan_init(BmsStorage *bms_storage) { s_storage = bms_storage; gpio_init_pin(&bms_fan_pwm, GPIO_ALTFN_PUSH_PULL, GPIO_STATE_LOW); pwm_init(PWM_TIMER_1, BMS_FAN_PERIOD); - pwm_set_pulse(PWM_TIMER_1, BMS_FAN_PERIOD); - pwm_set_dc(PWM_TIMER_1, 0); + pwm_set_pulse(PWM_TIMER_1, BMS_FAN_PERIOD, 1); + pwm_set_dc(PWM_TIMER_1, 0, 1); gpio_init_pin(&bms_fan_sense1, GPIO_INPUT_FLOATING, GPIO_STATE_LOW); gpio_init_pin(&bms_fan_sense2, GPIO_INPUT_FLOATING, GPIO_STATE_LOW); diff --git a/projects/bms_carrier/src/main.c b/projects/bms_carrier/src/main.c index 5eff0a40b..7f1c251f4 100644 --- a/projects/bms_carrier/src/main.c +++ b/projects/bms_carrier/src/main.c @@ -38,34 +38,36 @@ BmsStorage bms_storage; void pre_loop_init() { LOG_DEBUG("Welcome to BMS \n"); fault_bps_init(&bms_storage.bps_storage); + init_bms_relays(); current_sense_init(&bms_storage, &i2c_settings, FUEL_GAUGE_CYCLE_TIME_MS); - // cell_sense_init(&bms_storage.ltc_afe_storage); + cell_sense_init(&bms_storage.ltc_afe_storage); aux_sense_init(&bms_storage.aux_storage); - init_bms_relays(); bms_fan_init(&bms_storage); } -void run_fast_cycle() {} - -void run_medium_cycle() { +void run_fast_cycle() { run_can_rx_cycle(); wait_tasks(1); - - // cell_conversions(); + // Current sense readings + checks + // current_sense_run(); // wait_tasks(1); - current_sense_run(); + // delay_ms(10); + run_can_tx_cycle(); wait_tasks(1); +} + +void run_medium_cycle() { + // Afe Voltage Conversions + cell_conversions(); + wait_tasks(1); + cell_sense_run(); - // cell_sense_run(); aux_sense_run(); bms_run_fan(); - - run_can_tx_cycle(); - wait_tasks(1); } void run_slow_cycle() { - cell_discharge(&bms_storage.ltc_afe_storage); + // cell_discharge(&bms_storage.ltc_afe_storage); if (fault_bps_get()) { LOG_DEBUG("FAULT_BITMASK: %d\n", fault_bps_get()); @@ -73,6 +75,7 @@ void run_slow_cycle() { } int main() { + set_master_cycle_time(200); tasks_init(); log_init(); gpio_init(); diff --git a/projects/bms_carrier/src/relays.c b/projects/bms_carrier/src/relays.c index 2fbceac1e..8e2b4fdb8 100644 --- a/projects/bms_carrier/src/relays.c +++ b/projects/bms_carrier/src/relays.c @@ -2,9 +2,6 @@ #include "bms.h" -static RelayType relay_toggle = NO_RELAYS; -static SoftTimer relays_timer; - static const GpioAddress pos_relay_en = { .port = GPIO_PORT_B, .pin = 8 }; static const GpioAddress pos_relay_sense = { .port = GPIO_PORT_B, .pin = 5 }; @@ -18,51 +15,25 @@ static const GpioAddress solar_relay_sense = { .port = GPIO_PORT_B, .pin = 9 }; static const GpioAddress s_relays_sense[NUM_BMS_RELAYS] = { pos_relay_sense, neg_relay_sense, solar_relay_sense }; -static void prv_close_relays(SoftTimerId id) { +static StatusCode prv_close_relays(void) { // 200 MS GAP BETWEEN EACH RELAY BC OF CURRENT DRAW - switch (relay_toggle) { - case NO_RELAYS: { - gpio_set_state(&pos_relay_en, GPIO_STATE_HIGH); - relay_toggle = POS_RELAY; - soft_timer_start(&relays_timer); - break; - } - case POS_RELAY: { - gpio_set_state(&neg_relay_en, GPIO_STATE_HIGH); - relay_toggle = NEG_RELAY; - soft_timer_start(&relays_timer); - break; - } - case NEG_RELAY: { - gpio_set_state(&solar_relay_en, GPIO_STATE_HIGH); - relay_toggle = SOLAR_RELAY; - soft_timer_start(&relays_timer); - break; - } - case SOLAR_RELAY: { - GpioState sense_state; - gpio_get_state(&pos_relay_sense, &sense_state); - gpio_get_state(&neg_relay_sense, &sense_state); - gpio_get_state(&solar_relay_sense, &sense_state); - relay_toggle = RELAY_CHECK; - soft_timer_start(&relays_timer); - break; + gpio_set_state(&pos_relay_en, GPIO_STATE_HIGH); + delay_ms(BMS_CLOSE_RELAYS_DELAY_MS); + gpio_set_state(&neg_relay_en, GPIO_STATE_HIGH); + delay_ms(BMS_CLOSE_RELAYS_DELAY_MS); + gpio_set_state(&solar_relay_en, GPIO_STATE_HIGH); + delay_ms(BMS_CLOSE_RELAYS_DELAY_MS); + GpioState sense_state; + for (uint8_t i = 0; i < NUM_BMS_RELAYS; i++) { + gpio_get_state(&s_relays_sense[i], &sense_state); + if (sense_state != GPIO_STATE_HIGH) { + LOG_DEBUG("Relay %d not closed\n", i); + fault_bps_set(BMS_FAULT_RELAY_CLOSE_FAILED); + bms_relay_fault(); + return STATUS_CODE_INTERNAL_ERROR; } - case RELAY_CHECK: { - GpioState sense_state; - for (uint8_t i = 0; i < NUM_BMS_RELAYS; i++) { - gpio_get_state(&s_relays_sense[i], &sense_state); - if (sense_state != GPIO_STATE_HIGH) { - fault_bps_set(BMS_FAULT_RELAY_CLOSE_FAILED); - } - } - break; - } - - default: - // FAULT? SHOULD NEVER BE DEFAULT - break; } + return STATUS_CODE_OK; } void bms_relay_fault() { @@ -83,8 +54,7 @@ StatusCode init_bms_relays() { gpio_init_pin(&neg_relay_sense, GPIO_INPUT_FLOATING, GPIO_STATE_LOW); gpio_init_pin(&solar_relay_sense, GPIO_INPUT_FLOATING, GPIO_STATE_LOW); - soft_timer_init(BMS_CLOSE_RELAYS_DELAY_MS, prv_close_relays, &relays_timer); + status_ok_or_return(prv_close_relays()); set_battery_relay_info_state(EE_RELAY_STATE_CLOSE); - soft_timer_start(&relays_timer); return STATUS_CODE_OK; } diff --git a/projects/centre_console/src/cc_buttons.c b/projects/centre_console/src/cc_buttons.c index cf4ecab3c..1f6846fbd 100644 --- a/projects/centre_console/src/cc_buttons.c +++ b/projects/centre_console/src/cc_buttons.c @@ -10,7 +10,7 @@ static void prv_buzzer_beep(SoftTimerId id) { soft_timer_start(&s_timer); beep_flag = false; } else { - pwm_set_dc(PWM_TIMER_1, 0); + pwm_set_dc(PWM_TIMER_1, 0, 3); beep_flag = true; } } @@ -28,7 +28,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)®EN_BTN_MASK) != 0) { LOG_DEBUG("REGEN PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(cc_notify_task, REGEN_BUTTON_EVENT); @@ -36,7 +36,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)&HAZARD_BTN_MASK) != 0) { LOG_DEBUG("HAZARD PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(cc_notify_task, HAZARD_BUTTON_EVENT); @@ -44,7 +44,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)&POWER_BTN_MASK) != 0) { LOG_DEBUG("POWER PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(cc_notify_task, POWER_BUTTON_EVENT); @@ -53,7 +53,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)&DRIVE_BTN_MASK) != 0) { LOG_DEBUG("DRIVE PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(drive, DRIVE_BUTTON_EVENT); @@ -61,7 +61,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)&NEUTRAL_BTN_MASK) != 0) { LOG_DEBUG("NEUT PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(drive, NEUTRAL_BUTTON_EVENT); @@ -69,7 +69,7 @@ StatusCode get_button_press(void) { if ((~(pca9555_reg_val)&REVERSE_BTN_MASK) != 0) { LOG_DEBUG("REV PRESSED\n"); if (beep_flag && !get_battery_status_fault() && !get_pd_status_bps_persist()) { - pwm_set_dc(PWM_TIMER_1, 5); + pwm_set_dc(PWM_TIMER_1, 5, 3); soft_timer_start(&s_timer); } notify(drive, REVERSE_BUTTON_EVENT); @@ -81,7 +81,7 @@ StatusCode init_cc_buttons(Task *task) { cc_notify_task = task; gpio_init_pin(&buzzer, GPIO_ALTFN_PUSH_PULL, GPIO_STATE_LOW); pwm_init(PWM_TIMER_1, BUZZER_MICROSECONDS); - pwm_set_dc(PWM_TIMER_1, 0); + pwm_set_dc(PWM_TIMER_1, 0, 3); soft_timer_init(BEEP_MS, prv_buzzer_beep, &s_timer); return STATUS_CODE_OK; } diff --git a/projects/centre_console/src/update_dashboard.c b/projects/centre_console/src/update_dashboard.c index 42ffab0e4..6e3562b14 100644 --- a/projects/centre_console/src/update_dashboard.c +++ b/projects/centre_console/src/update_dashboard.c @@ -98,7 +98,7 @@ void update_indicators(uint32_t notif) { // Update Aux warning LED if (get_pd_status_fault_bitset()) { - pwm_set_dc(PWM_TIMER_1, 50); + pwm_set_dc(PWM_TIMER_1, 50, 3); pca9555_gpio_set_state(&s_output_leds[AUX_WARNING_LED], PCA9555_GPIO_STATE_HIGH); } else { // PWM will not stop, driver will pull over and diagnose issue @@ -106,11 +106,11 @@ void update_indicators(uint32_t notif) { } if (get_battery_status_fault() & get_pd_status_bps_persist() & (1 << 15)) { - pwm_set_dc(PWM_TIMER_1, 100); + pwm_set_dc(PWM_TIMER_1, 100, 3); gpio_set_state(&bps_led, GPIO_STATE_LOW); } else if ((get_battery_status_fault() & get_pd_status_bps_persist() & (1 << 14)) || get_pd_status_power_state() == EE_POWER_FAULT_STATE) { - pwm_set_dc(PWM_TIMER_1, 10); + pwm_set_dc(PWM_TIMER_1, 10, 3); gpio_set_state(&bps_led, GPIO_STATE_LOW); } else { // PWM will not stop, driver will pull over and diagnose issue diff --git a/projects/power_distribution/inc/pd_fault.h b/projects/power_distribution/inc/pd_fault.h index 41360365f..5c238defc 100644 --- a/projects/power_distribution/inc/pd_fault.h +++ b/projects/power_distribution/inc/pd_fault.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "status.h" @@ -8,3 +9,4 @@ * @return STATUS_CODE_OK on success or appropriate error code */ uint8_t check_pd_fault(void); +bool check_aux_fault(void); diff --git a/projects/power_distribution/inc/pin_defs.h b/projects/power_distribution/inc/pin_defs.h index b035dda0d..b7de14b62 100644 --- a/projects/power_distribution/inc/pin_defs.h +++ b/projects/power_distribution/inc/pin_defs.h @@ -155,10 +155,11 @@ // Fault pin addresses // GPIO #define AUX_VALID1 \ - { .port = GPIO_PORT_B, .pin = 10 } + { .port = GPIO_PORT_B, .pin = 1 } #define AUX_VALID2 \ - { .port = GPIO_PORT_B, .pin = 2 } + { .port = GPIO_PORT_B, .pin = 0 } + #define DCDC_VALID1 \ - { .port = GPIO_PORT_B, .pin = 1 } + { .port = GPIO_PORT_B, .pin = 10 } #define DCDC_VALID2 \ - { .port = GPIO_PORT_B, .pin = 0 } + { .port = GPIO_PORT_B, .pin = 2 } diff --git a/projects/power_distribution/inc/power_seq_fsm.h b/projects/power_distribution/inc/power_seq_fsm.h index adf536b0a..db38790e5 100644 --- a/projects/power_distribution/inc/power_seq_fsm.h +++ b/projects/power_distribution/inc/power_seq_fsm.h @@ -10,7 +10,7 @@ // TODO: figure out actual values for timeout #define BMS_RESPONSE_TIMEOUT_MS 3000 -#define MCI_RESPONSE_TIMEOUT_MS 300 +#define MCI_RESPONSE_TIMEOUT_MS 5000 #define BPS_FAULT_FLASH_PAGE NUM_FLASH_PAGES - 1 #define NUM_POWER_STATES 4 diff --git a/projects/power_distribution/src/output_config.c b/projects/power_distribution/src/output_config.c index 37fb728f0..1d0ff912c 100644 --- a/projects/power_distribution/src/output_config.c +++ b/projects/power_distribution/src/output_config.c @@ -313,16 +313,19 @@ static OutputGroupDef s_output_group_hazards = { static OutputGroupDef s_output_group_brake = { .num_outputs = 1, .outputs = { BRAKE_LIGHT } }; static OutputGroupDef s_output_group_power_off = { - .num_outputs = 5, .outputs = { CENTER_CONSOLE, BMS_DCDC, BMS_AUX, PEDAL, STEERING } + .num_outputs = 7, + .outputs = { CENTER_CONSOLE, BMS_DCDC, BMS_AUX, PEDAL, STEERING, REAR_CAM_LCD, SPARE_5V_AUX } }; -static OutputGroupDef s_output_group_power_drive = { .num_outputs = 9, - .outputs = { CENTER_CONSOLE, BMS_DCDC, BMS_AUX, - PEDAL, STEERING, MCI, DRL_LIGHT, - DRIVER_FAN, REAR_CAM_LCD } }; +static OutputGroupDef s_output_group_power_drive = { + .num_outputs = 10, + .outputs = { CENTER_CONSOLE, BMS_DCDC, BMS_AUX, PEDAL, STEERING, MCI, DRL_LIGHT, DRIVER_FAN, + REAR_CAM_LCD, SPARE_5V_AUX } +}; static OutputGroupDef s_output_group_power_fault = { - .num_outputs = 5, .outputs = { CENTER_CONSOLE, BMS_DCDC, PEDAL, STEERING, BPS_LIGHT } + .num_outputs = 7, + .outputs = { CENTER_CONSOLE, BMS_DCDC, PEDAL, STEERING, BPS_LIGHT, REAR_CAM_LCD, SPARE_5V_AUX } }; static OutputGroupDef s_output_group_test = { .num_outputs = 2, .outputs = { STEERING, PEDAL } }; diff --git a/projects/power_distribution/src/pd_fault.c b/projects/power_distribution/src/pd_fault.c index 80657e444..19d0089f3 100644 --- a/projects/power_distribution/src/pd_fault.c +++ b/projects/power_distribution/src/pd_fault.c @@ -23,7 +23,7 @@ static void prv_set_fault_bit(uint8_t mask, bool condition) { } } -static bool prv_check_aux_fault(void) { +bool check_aux_fault(void) { GpioState aux_valid1_state; GpioState aux_valid2_state; if (!status_ok(gpio_get_state(&aux_valid1, &aux_valid1_state)) || @@ -44,7 +44,7 @@ static bool prv_check_dcdc_fault(void) { } uint8_t check_pd_fault(void) { - prv_set_fault_bit(EE_PD_STATUS_FAULT_BITSET_AUX_FAULT_MASK, prv_check_aux_fault()); + prv_set_fault_bit(EE_PD_STATUS_FAULT_BITSET_AUX_FAULT_MASK, check_aux_fault()); prv_set_fault_bit(EE_PD_STATUS_FAULT_BITSET_DCDC_FAULT_MASK, prv_check_dcdc_fault()); set_pd_status_fault_bitset(s_fault_bitset); return s_fault_bitset; diff --git a/projects/power_distribution/src/power_seq_fsm.c b/projects/power_distribution/src/power_seq_fsm.c index abf2a940b..85ecee2c7 100644 --- a/projects/power_distribution/src/power_seq_fsm.c +++ b/projects/power_distribution/src/power_seq_fsm.c @@ -28,7 +28,11 @@ static void prv_off_state_output(void *context) { } static void prv_off_state_input(Fsm *fsm, void *context) { - pd_fault_ok_or_transition(fsm); + // On initialization, DCDC is not on, so only check aux + if (check_battery_status_msg_watchdog() || get_battery_status_fault()) { + fsm_transition(fsm, POWER_STATE_FAULT); + return; + } LOG_DEBUG("IN off state - %d\n", get_received_cc_info()); LOG_DEBUG("s_bps_storage.fault_bitset %d\n", s_bps_storage.fault_bitset); if (!get_received_cc_info()) { diff --git a/smoke/bms_carrier/README.md b/smoke/bms_carrier/README.md deleted file mode 100644 index bba80d0c2..000000000 --- a/smoke/bms_carrier/README.md +++ /dev/null @@ -1,15 +0,0 @@ - -# bms \ No newline at end of file diff --git a/smoke/bms_carrier/config.json b/smoke/bms_carrier/config.json deleted file mode 100644 index 5a1f1667e..000000000 --- a/smoke/bms_carrier/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "libs": [ - "FreeRTOS", - "ms-common", - "ms-drivers" - ], - "include": [ - "projects/bms_carrier/inc" - ], - "sources": [ - "projects/bms_carrier/src/relays_fsm.o", - "projects/bms_carrier/src/current_sense.o" - ], - "can": true -} \ No newline at end of file diff --git a/smoke/bms_carrier/src/main.c b/smoke/bms_carrier/src/main.c deleted file mode 100644 index 62b93ce44..000000000 --- a/smoke/bms_carrier/src/main.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include "delay.h" -#include "gpio.h" -#include "log.h" -#include "relays_fsm.h" -#include "spi.h" -#include "tasks.h" - -TASK(smoke_bms_task, TASK_STACK_512) { - init_bms_relays(); - close_relays(); - while (true) { - LOG_DEBUG("CLOSING RELAYS!!!!\n"); - delay_ms(2000); - // LOG_DEBUG("OPENING!!!! RELAYS!!!!\n"); - // open_relays(); - // delay_ms(2000); - } -} - -int main() { - gpio_init(); - tasks_init(); - log_init(); - LOG_DEBUG("Welcome to BMS!!!!! TEST!\n"); - - tasks_init_task(smoke_bms_task, TASK_PRIORITY(1), NULL); - - tasks_start(); - - return 0; -}