| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- #include "battery.h"
- #include "ti/driverlib/dl_i2c.h"
- #include "ti_msp_dl_config.h"
- #include "src/peripherals/dac/dac.h"
- #include "src/peripherals/adc/adc.h"
- #include "src/interfaces/i2c_controller.h"
- // we need the itnerface for the ADC_TARGET_BASE_ADDRESS constant
- // refactor this somewhen to a general constants file
- #include "src/peripherals/adc/adc_interface.h"
- #include "src/config.h"
- BatterySlot battery_slots[NUM_SLOTS];
- static void set_dac(uint8_t slot, uint16_t value) {
- battery_slots[slot].dac_value = value;
- DAC_SingleWrite(slot, value);
- }
- static void set_pwm(uint8_t slot, uint16_t value) {
- battery_slots[slot].pwm_value = value;
- DL_TimerG_setCaptureCompareValue(battery_slots[0].timer, value, DL_TIMER_CC_1_INDEX);
- }
- static void batteryslots_disable(uint8_t slot) {
- if (battery_slots[slot].dac_value != 0) {
- set_dac(slot, 0);
- }
- if (battery_slots[slot].pwm_value != 0) {
- set_pwm(slot, 0);
- }
- }
- /*Initialize battery array and default parameters*/
- static void batteryslots_init() {
- // initialize data structures
- battery_slots[0].timer = PWM_0_INST;
- #if NUM_SLOTS == 4
- battery_slots[1].timer = PWM_1_INST;
- battery_slots[2].timer = PWM_2_INST;
- battery_slots[3].timer = PWM_3_INST;
- #endif
- for(uint8_t i=0; i< NUM_SLOTS; i++){
- battery_slots[i].measurement.state = SLOT_STATE_OK;
- // convinience trick:
- // with that we can set *battery_slots[i].state = SLOT_STATE_* or SLOT_ERR_*
- // like e.g. *battery_slots[i].state = SLOT_ERR_OVERTEMPERATURE
- battery_slots[i].state = &battery_slots[i].measurement.state;
- battery_slots[i].measurement.voltage = 0;
- battery_slots[i].measurement.current = 0;
- battery_slots[i].measurement.temperature = 0;
- battery_slots[i].set_current = 0;
- set_pwm(i, 0);
- }
-
- if (!i2c_discover(DAC_TARGET_ADDRESS)) {
- // there is only 1 DAC for all 4 slots
- for(uint8_t i=0; i< NUM_SLOTS; i++) {
- *battery_slots[i].state = SLOT_ERR_NO_DAC;
- }
- // Error state - no I2C on bus - we cannot continue.
- return;
- }
- for(uint8_t i=0; i< NUM_SLOTS; i++){
- set_dac(i, 0);
- if (!i2c_discover(ADC_TARGET_BASE_ADDRESS+i)) {
- // this automatically translates to the other addresses
- *battery_slots[i].state = SLOT_ERR_NO_ADC1+i;
- }
- }
- }
- static void batteryslots_read_state(uint8_t slot) {
- /*
- * Strategy:
- * 1. updateADCReading calls the ADC function that does the control loop for getting the values
- * 2. the updateADCReading also calls internally the HAL to send the i2c commands,
- * construct the configuration byte and calculate the values (voltage, current)
- * 3. the adc updates the battery slot value directly
- */
-
- // step 1: read channel 0 (voltage reading of the cell)
- uint16_t bare_voltage = read_adc_channel(slot, 0);
- battery_slots[slot].measurement.voltage = (100.0/56+1)*bare_voltage; // We have that voltage divider
- // DAC branch: we can calculate the current based on the shunt
- if (battery_slots[slot].set_current >= 0) {
- // read channel 1 (current reading on charge)
- bare_voltage = read_adc_channel(slot, 1);
- battery_slots[slot].measurement.current = bare_voltage*10/1000; // current comes in microvolts
- #ifdef DEBUG_TRACE_CTRL
- printf("Slot %d voltage: %d mV and %d mA (dac shunt)\n", slot, battery_slots[slot].measurement.voltage, battery_slots[slot].measurement.current);
- #endif
- } else {
- // we are in PWM mode, the shunt is on the high side
- // read channel 2 (voltage reading on 5V side)
- int16_t shunt_current = read_adc_channel(slot, 2)*10;
- // read channel 3 (current reading after step conversion, 5V side)
- int16_t hi_voltage = read_adc_channel(slot, 3)*100/56;
- // calculate the result
- battery_slots[slot].measurement.current = -1*shunt_current*hi_voltage/battery_slots[slot].measurement.voltage;
- #ifdef DEBUG_TRACE_CTRL
- printf("Slot %d voltage: %d mV and %d mA (pwm shunt) (hi side voltage: %d mV, hi side current: %d mA)\n", slot, battery_slots[slot].measurement.voltage, battery_slots[slot].measurement.current, hi_voltage, shunt_current);
- #endif
- }
- }
- static void batteryslots_adjust_current(uint8_t slot) {
- #ifdef DEBUG_TRACE_CTRL
- printf("Ctrl: Checking to adjust battery current. Set current: %d mA, measured current: %d mA\n",
- battery_slots[slot].set_current,
- battery_slots[slot].measurement.current
- );
- #endif
- if (battery_slots[slot].set_current > 0) {
- // positive current -> charge (with DAC)
- if (battery_slots[slot].pwm_value != 0) {
- // seems like we switched from a charging before
- // -> disable DAC before getting active
- #ifdef DEBUG_CTRL
- printf("Detected active pwm. Value: %d. Disabling.", battery_slots[slot].pwm_value);
- #endif
- set_pwm(slot, 0);
- }
- if (battery_slots[slot].set_current + BATTERY_CURRENT_THRESHOLD < battery_slots[slot].measurement.current) {
- // we are outside of the tolerance band
- // exceeded to the upper limit
- // -> update dac value, decrease the voltage
- if (battery_slots[slot].dac_value-1 >= 0) {
- #ifdef DEBUG_TRACE_CTRL
- printf("Ctrl: Decreasing DAC to %d\n", battery_slots[slot].dac_value-1);
- #endif
- set_dac(slot, --battery_slots[slot].dac_value);
- }
- else {
- // we want to give more current, but we can't ?!
- #ifdef DEBUG_CTRL
- printf("Ctrl: Unable to decrease DAC to %d\n", battery_slots[slot].dac_value-1);
- #endif
- *battery_slots[slot].state = SLOT_WARN_LOWER_DAC_NOT_POSSIBLE;
- }
- } else if (battery_slots[slot].set_current - BATTERY_CURRENT_THRESHOLD > battery_slots[slot].measurement.current) {
- // we are outside of the tolerance band
- // exceeded to the upplowerer limit
- // -> update dac value, increase the voltage
- if (battery_slots[slot].dac_value+1 <= MAX_DAC_VALUE) {
- #ifdef DEBUG_TRACE_CTRL
- printf("Ctrl: Increasing DAC to %d\n", battery_slots[slot].dac_value+1);
- #endif
- set_dac(slot, ++battery_slots[slot].dac_value);
- }
- else {
- // we want to give more current, but we can't ?!
- #ifdef DEBUG_CTRL
- printf("Ctrl: Unable to increase DAC to %d\n", battery_slots[slot].dac_value+1);
- #endif
- *battery_slots[slot].state = SLOT_WARN_HIGHER_DAC_NOT_POSSIBLE;
- }
- }
- // no else statement here: we are ok, since we are in the tolerance measure
- } else if (battery_slots[slot].set_current < 0) {
- // negative current -> discharge (with PWM)
- if (battery_slots[slot].dac_value != 0) {
- // seems like we switched from a charging before
- // -> disable DAC before getting active
- #ifdef DEBUG_CTRL
- printf("Detected active dac. Value: %d. Disabling.", battery_slots[slot].dac_value);
- #endif
- set_dac(slot, 0);
- }
- if (battery_slots[slot].set_current + BATTERY_CURRENT_THRESHOLD > battery_slots[slot].measurement.current) {
- // we are outside of the tolerance band
- // exceeded to the upper limit
- // -> update pwm value, decrease the voltage
-
- // @todo debugging & validation: ensure that this directive works
- #ifdef DEBUG_CTRL
- printf("timer count: %d\n", DL_Timer_getTimerCount(battery_slots[0].timer));
- #endif
- if (battery_slots[slot].pwm_value+1 <= DL_Timer_getTimerCount(battery_slots[0].timer)) {
- // pwm is inverse to the DAC since dragging more current means more negative
- #ifdef DEBUG_TRACE_CTRL
- printf("Ctrl: Increasing PWM to %d\n", battery_slots[slot].pwm_value+1);
- #endif
- set_pwm(slot, ++battery_slots[slot].pwm_value);
- }
- else {
- // we want to give more current, but we can't ?!
- #ifdef DEBUG_CTRL
- printf("Ctrl: Unable to increase PWM to %d\n", battery_slots[slot].pwm_value+1);
- #endif
- *battery_slots[slot].state = SLOT_WARN_HIGHER_PWM_NOT_POSSIBLE;
- }
- } else if (battery_slots[slot].set_current - BATTERY_CURRENT_THRESHOLD < battery_slots[slot].measurement.current) {
- // we are outside of the tolerance band
- // exceeded to the upplowerer limit
- // -> update pwm value, increase the voltage
- if (battery_slots[slot].pwm_value-1 >= 0) {
- #ifdef DEBUG_TRACE_CTRL
- printf("Ctrl: Decreasing PWM to %d\n", battery_slots[slot].pwm_value-1);
- #endif
- set_pwm(slot, --battery_slots[slot].pwm_value);
- }
- else {
- // we want to give more current, but we can't ?!
- #ifdef DEBUG_CTRL
- printf("Ctrl: Unable to decrease PWM to %d\n", battery_slots[slot].pwm_value-1);
- #endif
- *battery_slots[slot].state = SLOT_WARN_LOWER_PWM_NOT_POSSIBLE;
- }
- }
- } else {
- // we have 0 -> stop charging and discharging
- #ifdef DEBUG_CTRL
- printf("0 current -> Disabling slot.\n");
- #endif
- batteryslots_disable(slot);
- }
- }
- BatterySlotManager battery_slotmgr = {
- .init = batteryslots_init,
- .read_state = batteryslots_read_state,
- .adjust_current = batteryslots_adjust_current,
- .disable = batteryslots_disable
- };
|