Skip to content
This repository was archived by the owner on Oct 26, 2025. It is now read-only.
13 changes: 9 additions & 4 deletions libraries/ms-drivers/inc/ltc6811.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,24 @@ static_assert(sizeof(LtcAfeConfigRegisterData) == 6, "LtcAfeConfigRegisterData m

// COMM Register, refer to LTC6803 datasheet page 31, Table 15
typedef struct {
uint8_t d0_msb : 4;
uint8_t icom0 : 4;
uint8_t d0 : 8;
uint8_t fcom0 : 4;
uint8_t d0_lsb : 4;

uint8_t d1_msb : 4;
uint8_t icom1 : 4;
uint8_t d1 : 8;
uint8_t fcom1 : 4;
uint8_t d1_lsb : 4;

uint8_t d2_msb : 4;
uint8_t icom2 : 4;
uint8_t d2 : 8;
uint8_t fcom2 : 4;
uint8_t d2_lsb : 4;
} _PACKED LtcAfeCommRegisterData;
static_assert(sizeof(LtcAfeCommRegisterData) == 6, "LtcAfeCommRegisterData must be 6 bytes");
#define LTC6811_EXTRACT_DATA_MSB(x) ((x) >> 4)
#define LTC6811_EXTRACT_DATA_LSB(x) ((x) & 0xF)

// CFGR packet
typedef struct {
Expand All @@ -101,7 +106,7 @@ typedef struct {
typedef struct {
uint8_t wrcomm[LTC6811_CMD_SIZE];
LtcAfeCommRegisterData reg;
uint8_t pec;
uint16_t pec;
} _PACKED LtcAfeWriteCommRegPacket;

// STMCOMM + clock cycles
Expand Down
6 changes: 6 additions & 0 deletions libraries/ms-drivers/src/ltc_afe_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ static void prv_afe_read_cells_output(struct Fsm *fsm, const Event *e, void *con
event_raise(afe_events->callback_run_event, 0);

if (afe->settings.cell_result_cb != NULL) {
// for(int i = 0; i < LTC_AFE_MAX_CELLS; i++) {
// LOG_DEBUG("cell_voltages[%d] = %lu\n", i, afe->cell_voltages[i]);
// }
afe->settings.cell_result_cb(afe->cell_voltages, afe->settings.num_cells,
afe->settings.result_context);
}
Expand Down Expand Up @@ -162,6 +165,9 @@ static void prv_afe_aux_complete_output(struct Fsm *fsm, const Event *e, void *c

// 12 aux conversions complete - the array should be fully populated
if (afe->settings.aux_result_cb != NULL) {
// for(int i = 0; i < LTC_AFE_MAX_CELLS; i++) {
// LOG_DEBUG("aux_voltages[%d] = %lu\n", i, afe->aux_voltages[i]);
// }
afe->settings.aux_result_cb(afe->aux_voltages, afe->settings.num_cells,
afe->settings.result_context);
}
Expand Down
37 changes: 30 additions & 7 deletions libraries/ms-drivers/src/ltc_afe_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,13 @@ static StatusCode prv_aux_write_comm_register(LtcAfeStorage *afe, uint8_t device
// We send the a byte and then we send CSBM_HIGH to
// release the SPI port
packet.reg.icom0 = LTC6811_ICOM_CSBM_LOW;
packet.reg.d0 = device_cell;
packet.reg.d0_msb = LTC6811_EXTRACT_DATA_MSB(device_cell);
packet.reg.d0_lsb = LTC6811_EXTRACT_DATA_LSB(device_cell);
packet.reg.fcom0 = LTC6811_FCOM_CSBM_HIGH;
packet.reg.icom1 = LTC6811_ICOM_NO_TRANSMIT;
packet.reg.icom2 = LTC6811_ICOM_NO_TRANSMIT;
uint16_t comm_pec = crc15_calculate((uint8_t *)&packet.reg, sizeof(LtcAfeCommRegisterData));
packet.pec = SWAP_UINT16(comm_pec);

prv_wakeup_idle(afe);
return spi_exchange(settings->spi_port, (uint8_t *)&packet, sizeof(LtcAfeWriteCommRegPacket),
Expand Down Expand Up @@ -196,10 +198,10 @@ 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;
uint16_t cell_index = 0;
uint16_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++) {
for (uint16_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;

if ((settings->cell_bitset[device] >> device_cell) & 0x1) {
Expand All @@ -216,6 +218,18 @@ static void prv_calc_offsets(LtcAfeStorage *afe) {
}
}
}

if (aux_index != afe->settings.num_cells) {
LOG_CRITICAL("Result array has max_index %d but should have max %d\n",
aux_index, (uint16_t) afe->settings.num_cells);
}

if (cell_index != afe->settings.num_cells) {
LOG_CRITICAL("Result array has max_index %d but should have max %d\n",
cell_index, (uint16_t) afe->settings.num_cells);
return;
}
LOG_DEBUG("calc_offsets is fine\n");
}

StatusCode ltc_afe_impl_init(LtcAfeStorage *afe, const LtcAfeSettings *settings) {
Expand All @@ -242,8 +256,8 @@ StatusCode ltc_afe_impl_init(LtcAfeStorage *afe, const LtcAfeSettings *settings)
spi_init(settings->spi_port, &spi_config);

// Use GPIO1 as analog input, GPIO 3-5 for SPI
uint8_t gpio_bits =
LTC6811_GPIO1_PD_OFF | LTC6811_GPIO3_PD_OFF | LTC6811_GPIO4_PD_OFF | LTC6811_GPIO5_PD_OFF;
uint8_t gpio_bits = LTC6811_GPIO1_PD_OFF | LTC6811_GPIO2_PD_ON | LTC6811_GPIO3_PD_ON |
LTC6811_GPIO4_PD_ON | LTC6811_GPIO5_PD_ON;
return prv_write_config(afe, gpio_bits);
}

Expand All @@ -262,6 +276,7 @@ StatusCode ltc_afe_impl_trigger_aux_conv(LtcAfeStorage *afe, uint8_t device_cell

StatusCode ltc_afe_impl_read_cells(LtcAfeStorage *afe) {
// Read all voltage A, then B, ...
uint16_t num_readings = 0;
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 };
Expand All @@ -274,9 +289,11 @@ StatusCode ltc_afe_impl_read_cells(LtcAfeStorage *afe) {
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) {
if (((settings->cell_bitset[device] >> device_cell) & 0x1) == 0x1) {
// Input enabled - store result
afe->cell_voltages[afe->cell_result_lookup[index]] = voltage;
LOG_DEBUG("CELL READING#%d is CELL#%d\n", afe->cell_result_lookup[index], index);
num_readings++;
}
}

Expand All @@ -290,6 +307,11 @@ StatusCode ltc_afe_impl_read_cells(LtcAfeStorage *afe) {
}
}

if (num_readings != afe->settings.num_cells) {
LOG_CRITICAL("Read %d values instead of %d", num_readings, (uint16_t)afe->settings.num_cells);
return status_code(STATUS_CODE_INTERNAL_ERROR);
}
LOG_DEBUG("read_cells is fine\n");
return STATUS_CODE_OK;
}

Expand All @@ -309,6 +331,7 @@ StatusCode ltc_afe_impl_read_aux(LtcAfeStorage *afe, uint8_t device_cell) {
// Input enabled - store result
uint16_t index = device * LTC_AFE_MAX_CELLS_PER_DEVICE + device_cell;
afe->aux_voltages[afe->aux_result_lookup[index]] = voltage;
LOG_DEBUG("AUX READING#%d is CELL#%d\n", afe->aux_result_lookup[index], index);
}

uint16_t received_pec = SWAP_UINT16(register_data[device].pec);
Expand Down
36 changes: 18 additions & 18 deletions projects/smoke_ltc6811/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

// To disable logging for an event, set the event name to NULL
static const char *s_event_names[NUM_SMOKE_LTC_EVENTS] = {
[SMOKE_LTC_AFE_TRIGGER_CELL_CONV_EVENT] = "CELL CONVERSION TRIGGERED",
[SMOKE_LTC_AFE_CELL_CONV_COMPLETE_EVENT] = "CELL CONVERSION COMPLETE",
[SMOKE_LTC_AFE_TRIGGER_AUX_CONV_EVENT] = "AUX CONVERSION TRIGGERED",
[SMOKE_LTC_AFE_AUX_CONV_COMPLETE_EVENT] = "AUX CONVERSION COMPLETE",
[SMOKE_LTC_AFE_TRIGGER_CELL_CONV_EVENT] = NULL,
[SMOKE_LTC_AFE_CELL_CONV_COMPLETE_EVENT] = NULL,
[SMOKE_LTC_AFE_TRIGGER_AUX_CONV_EVENT] = NULL,
[SMOKE_LTC_AFE_AUX_CONV_COMPLETE_EVENT] = NULL,
[SMOKE_LTC_AFE_CALLBACK_RUN_EVENT] = "CONVERSION CALLBACK RUN",
[SMOKE_LTC_AFE_FAULT_EVENT] = "FAULT OCCURED"
};
Expand All @@ -36,7 +36,7 @@ typedef struct LtcAfeReadingBound {

static LtcAfeStorage s_afe;
static uint16_t s_result_arr[SMOKE_LTC_AFE_NUM_CELLS] = { 0 };
static size_t s_num_samples = 0;
static uint16_t s_num_samples = 0;
LtcAfeReadingBound s_sample_bounds[SMOKE_LTC_AFE_NUM_CELLS] = { 0 };

static void prv_reset_sample_bounds(void) {
Expand All @@ -47,29 +47,29 @@ static void prv_reset_sample_bounds(void) {
}

static StatusCode prv_extract_and_dump_readings(uint16_t *result_arr, size_t len,
size_t max_samples) {
if (len != sizeof(s_result_arr)) {
LOG_WARN("Expected reading length to be %zu but it was %zu\n", sizeof(s_result_arr), len);
uint16_t max_samples) {
if (len != SMOKE_LTC_AFE_NUM_CELLS) {
LOG_WARN("Expected reading length to be %d but it was %zu\n", SMOKE_LTC_AFE_NUM_CELLS, len);
return STATUS_CODE_INVALID_ARGS;
}

memcpy(s_result_arr, result_arr, len);

if (s_num_samples == 0) {
LOG_DEBUG("INITIAL READINGS:");
LOG_DEBUG("INITIAL READINGS:\n");
} else if (s_num_samples == max_samples - 1) {
LOG_DEBUG("READING STATS:");
LOG_DEBUG("READING STATS:\n");
}

for (size_t cell = 0; cell < SMOKE_LTC_AFE_NUM_CELLS; ++cell) {
for (uint16_t cell = 0; cell < SMOKE_LTC_AFE_NUM_CELLS; ++cell) {
s_sample_bounds[cell].min = MIN(s_result_arr[cell], s_sample_bounds[cell].min);
s_sample_bounds[cell].max = MAX(s_result_arr[cell], s_sample_bounds[cell].max);

if (s_num_samples == 0) {
LOG_DEBUG("CELL#%zu = %d\n", cell, s_result_arr[cell]);
LOG_DEBUG("CELL#%u = %d\n", cell, s_result_arr[cell]);
} else if (s_num_samples == max_samples - 1) {
uint16_t delta = s_sample_bounds[cell].max - s_sample_bounds[cell].min;
LOG_DEBUG("CELL#%zu DELTA %d (MIN=%d, MAX=%d)\n", cell, delta, s_sample_bounds[cell].min,
LOG_DEBUG("CELL#%u DELTA %d (MIN=%d, MAX=%d)\n", cell, delta, s_sample_bounds[cell].min,
s_sample_bounds[cell].max);
}
}
Expand All @@ -91,8 +91,8 @@ static void prv_dump_voltages(uint16_t *result_arr, size_t len, void *context) {
if (s_num_samples != 0) {
if (!status_ok(ltc_afe_request_cell_conversion(&s_afe))) return;
} else {
LOG_DEBUG("==END OF VOLTAGE SAMPLES==");
LOG_DEBUG("==START OF TEMPERATURE SAMPLES==");
LOG_DEBUG("==END OF VOLTAGE SAMPLES==\n");
LOG_DEBUG("==START OF TEMPERATURE SAMPLES==\n");
if (!status_ok(ltc_afe_request_aux_conversion(&s_afe))) return;
}
}
Expand All @@ -106,7 +106,7 @@ static void prv_dump_temps(uint16_t *result_arr, size_t len, void *context) {
if (s_num_samples != 0) {
if (!status_ok(ltc_afe_request_aux_conversion(&s_afe))) return;
} else {
LOG_DEBUG("==END OF TEMPERATURE SAMPLES==");
LOG_DEBUG("==END OF TEMPERATURE SAMPLES==\n");
// TODO(SOFT-222): Could test cell discharge here as well ...
}
}
Expand Down Expand Up @@ -134,7 +134,7 @@ static StatusCode prv_ltc_init(void) {
.num_devices = SMOKE_LTC_AFE_NUM_DEVICES,
.num_cells = SMOKE_LTC_AFE_NUM_CELLS,

.ltc_events = { .trigger_cell_conv_event = SMOKE_LTC_AFE_TRIGGER_CELL_CONV_EVENT,
.ltc_events = { .trigger_cell_conv_event = SMOKE_LTC_AFE_TRIGGER_CELL_CONV_EVENT,
.cell_conv_complete_event = SMOKE_LTC_AFE_CELL_CONV_COMPLETE_EVENT,
.trigger_aux_conv_event = SMOKE_LTC_AFE_TRIGGER_AUX_CONV_EVENT,
.aux_conv_complete_event = SMOKE_LTC_AFE_AUX_CONV_COMPLETE_EVENT,
Expand Down Expand Up @@ -169,7 +169,7 @@ int main(void) {
// Initialize bound variable
prv_reset_sample_bounds();

LOG_DEBUG("==START OF VOLTAGE SAMPLES==");
LOG_DEBUG("==START OF VOLTAGE SAMPLES==\n");
status_ok_or_return(ltc_afe_request_cell_conversion(&s_afe));

Event e = { 0 };
Expand Down