|
@@ -1,229 +1,126 @@
|
|
|
#include "battery.h"
|
|
#include "battery.h"
|
|
|
#include "ti/driverlib/dl_i2c.h"
|
|
#include "ti/driverlib/dl_i2c.h"
|
|
|
#include "ti/driverlib/dl_timerg.h"
|
|
#include "ti/driverlib/dl_timerg.h"
|
|
|
|
|
+#include "ti/driverlib/dl_comp.h"
|
|
|
#include "ti_msp_dl_config.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/peripherals/temp/tmp1075.h"
|
|
|
|
|
#include "src/config.h"
|
|
#include "src/config.h"
|
|
|
|
|
|
|
|
-BatterySlot battery_slots[NUM_SLOTS];
|
|
|
|
|
|
|
+BatterySlot slot;
|
|
|
|
|
|
|
|
-static void set_dac(uint8_t slot, uint16_t value) {
|
|
|
|
|
- battery_slots[slot].dac_value = value;
|
|
|
|
|
- DAC_SingleWrite(slot, value);
|
|
|
|
|
|
|
+static void set_dac(uint16_t value) {
|
|
|
|
|
+ slot.dac_value = value;
|
|
|
|
|
+ DL_COMP_setDACCode0(COMP_0_INST, value);
|
|
|
}
|
|
}
|
|
|
-static void set_pwm(uint8_t slot, uint16_t value) {
|
|
|
|
|
- battery_slots[slot].pwm_value = value;
|
|
|
|
|
- DL_TimerG_setCaptureCompareValue(battery_slots[slot].timer, value, DL_TIMER_CC_1_INDEX);
|
|
|
|
|
- if (value > 0 && !DL_TimerG_isRunning(battery_slots[slot].timer)) {
|
|
|
|
|
- DL_TimerG_startCounter(battery_slots[slot].timer);
|
|
|
|
|
|
|
+static void set_pwm(uint16_t value) {
|
|
|
|
|
+ slot.pwm_value = value;
|
|
|
|
|
+ DL_TimerG_setCaptureCompareValue(PWM_INST, value, DL_TIMER_CC_1_INDEX);
|
|
|
|
|
+ if (value > 0 && !DL_TimerG_isRunning(PWM_INST)) {
|
|
|
|
|
+ DL_TimerG_startCounter(PWM_INST);
|
|
|
}
|
|
}
|
|
|
- if (value == 0 && DL_TimerG_isRunning(battery_slots[slot].timer)) {
|
|
|
|
|
- DL_TimerG_stopCounter(battery_slots[slot].timer);
|
|
|
|
|
|
|
+ if (value == 0 && DL_TimerG_isRunning(PWM_INST)) {
|
|
|
|
|
+ DL_TimerG_stopCounter(PWM_INST);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-static void batteryslots_disable(uint8_t slot) {
|
|
|
|
|
- if (battery_slots[slot].dac_value != 0) {
|
|
|
|
|
- set_dac(slot, 0);
|
|
|
|
|
|
|
+void slot_disable() {
|
|
|
|
|
+ if (slot.dac_value != 0) {
|
|
|
|
|
+ set_dac(0);
|
|
|
}
|
|
}
|
|
|
- if (battery_slots[slot].pwm_value != 0) {
|
|
|
|
|
- set_pwm(slot, 0);
|
|
|
|
|
|
|
+ if (slot.pwm_value != 0) {
|
|
|
|
|
+ set_pwm(0);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*Initialize battery array and default parameters*/
|
|
/*Initialize battery array and default parameters*/
|
|
|
-static void batteryslots_init() {
|
|
|
|
|
|
|
+void slot_init() {
|
|
|
|
|
|
|
|
- // initialize data structures
|
|
|
|
|
- battery_slots[0].timer = PWM_0_INST;
|
|
|
|
|
- battery_slots[0].adc_addr = ADC_TARGET_BASE_ADDRESS;
|
|
|
|
|
- battery_slots[1].timer = PWM_1_INST;
|
|
|
|
|
- battery_slots[1].adc_addr = ADC_TARGET_BASE_ADDRESS+4;
|
|
|
|
|
- battery_slots[2].timer = PWM_2_INST;
|
|
|
|
|
- battery_slots[2].adc_addr = ADC_TARGET_BASE_ADDRESS+2;
|
|
|
|
|
- battery_slots[3].timer = PWM_3_INST;
|
|
|
|
|
- battery_slots[3].adc_addr = ADC_TARGET_BASE_ADDRESS+6;
|
|
|
|
|
|
|
+ slot.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
|
|
|
|
|
+ slot.state = &slot.measurement.state;
|
|
|
|
|
|
|
|
- for(uint8_t i=0; i< NUM_SLOTS; i++){
|
|
|
|
|
|
|
+ slot.measurement.voltage = 0;
|
|
|
|
|
+ slot.measurement.current = 0;
|
|
|
|
|
+ slot.measurement.temperature = 0;
|
|
|
|
|
+ slot.set_current = 0;
|
|
|
|
|
|
|
|
- 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);
|
|
|
|
|
- set_dac(i, 0);
|
|
|
|
|
- delay_cycles(PWM_INITIALIZATION_DELAY);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /*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;
|
|
|
|
|
- }
|
|
|
|
|
- }*/
|
|
|
|
|
|
|
+ set_pwm(0);
|
|
|
|
|
+ set_dac(0);
|
|
|
}
|
|
}
|
|
|
-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);
|
|
|
|
|
- if (bare_voltage == 0xffff) {
|
|
|
|
|
- // the voltage reading is invalid -> ignore this cycle.
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- battery_slots[slot].measurement.voltage = bare_voltage*(56+100)/56; // 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);
|
|
|
|
|
- if (bare_voltage == 0xffff) {
|
|
|
|
|
- // the voltage reading is invalid -> ignore this cycle.
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- battery_slots[slot].measurement.current = bare_voltage*10/1000; // current comes on a 0.1 ohms shunt
|
|
|
|
|
-#ifdef DEBUG_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)
|
|
|
|
|
- bare_voltage = read_adc_channel(slot, 2);
|
|
|
|
|
- if (bare_voltage == 0xffff) {
|
|
|
|
|
- // the voltage reading is invalid -> ignore this cycle.
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- uint16_t shunt_current = 10*bare_voltage/1000;
|
|
|
|
|
-
|
|
|
|
|
- // read channel 3 (current reading after step conversion, 5V side)
|
|
|
|
|
- bare_voltage = read_adc_channel(slot, 3);
|
|
|
|
|
- if (bare_voltage == 0xffff) {
|
|
|
|
|
- // the voltage reading is invalid -> ignore this cycle.
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- uint16_t hi_voltage = bare_voltage*(56+100)/56;
|
|
|
|
|
-
|
|
|
|
|
- uint32_t hi_power = shunt_current*hi_voltage;
|
|
|
|
|
-
|
|
|
|
|
- // calculate the result
|
|
|
|
|
- battery_slots[slot].measurement.current = (int16_t)(hi_power/battery_slots[slot].measurement.voltage)*-1;
|
|
|
|
|
-#ifdef DEBUG_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
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- battery_slots[slot].measurement.temperature = read_temperature(slot);
|
|
|
|
|
|
|
+void slot_read_state() {
|
|
|
|
|
+ ;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void batteryslots_adjust_current(uint8_t slot) {
|
|
|
|
|
|
|
+void slot_adjust_current() {
|
|
|
|
|
|
|
|
- if (battery_slots[slot].set_current > 0) {
|
|
|
|
|
|
|
+ if (slot.set_current > 0) {
|
|
|
// positive current -> charge (with DAC)
|
|
// positive current -> charge (with DAC)
|
|
|
|
|
|
|
|
- if (battery_slots[slot].pwm_value != 0) {
|
|
|
|
|
|
|
+ if (slot.pwm_value != 0) {
|
|
|
// seems like we switched from a charging before
|
|
// seems like we switched from a charging before
|
|
|
// -> disable DAC before getting active
|
|
// -> disable DAC before getting active
|
|
|
- set_pwm(slot, 0);
|
|
|
|
|
|
|
+ set_pwm(0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (battery_slots[slot].set_current + BATTERY_CURRENT_THRESHOLD < battery_slots[slot].measurement.current) {
|
|
|
|
|
|
|
+ if (slot.set_current + BATTERY_CURRENT_THRESHOLD < slot.measurement.current) {
|
|
|
// we are outside of the tolerance band
|
|
// we are outside of the tolerance band
|
|
|
// exceeded to the upper limit
|
|
// exceeded to the upper limit
|
|
|
// -> update dac value, decrease the voltage
|
|
// -> update dac value, decrease the voltage
|
|
|
- if (battery_slots[slot].dac_value-1 >= 0) {
|
|
|
|
|
- set_dac(slot, --battery_slots[slot].dac_value);
|
|
|
|
|
|
|
+ if (slot.dac_value-1 >= 0) {
|
|
|
|
|
+ set_dac(--slot.dac_value);
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
// we want to give more current, but we can't ?!
|
|
// we want to give more current, but we can't ?!
|
|
|
- *battery_slots[slot].state = SLOT_WARN_LOWER_DAC_NOT_POSSIBLE;
|
|
|
|
|
|
|
+ *slot.state = SLOT_WARN_LOWER_DAC_NOT_POSSIBLE;
|
|
|
}
|
|
}
|
|
|
- } else if (battery_slots[slot].set_current - BATTERY_CURRENT_THRESHOLD > battery_slots[slot].measurement.current) {
|
|
|
|
|
|
|
+ } else if (slot.set_current - BATTERY_CURRENT_THRESHOLD > slot.measurement.current) {
|
|
|
// we are outside of the tolerance band
|
|
// we are outside of the tolerance band
|
|
|
// exceeded to the upplowerer limit
|
|
// exceeded to the upplowerer limit
|
|
|
// -> update dac value, increase the voltage
|
|
// -> update dac value, increase the voltage
|
|
|
- if (battery_slots[slot].dac_value+1 <= MAX_DAC_VALUE) {
|
|
|
|
|
- set_dac(slot, ++battery_slots[slot].dac_value);
|
|
|
|
|
|
|
+ if (slot.dac_value+1 <= MAX_DAC_VALUE) {
|
|
|
|
|
+ set_dac(++slot.dac_value);
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
// we want to give more current, but we can't ?!
|
|
// we want to give more current, but we can't ?!
|
|
|
- *battery_slots[slot].state = SLOT_WARN_HIGHER_DAC_NOT_POSSIBLE;
|
|
|
|
|
|
|
+ *slot.state = SLOT_WARN_HIGHER_DAC_NOT_POSSIBLE;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// no else statement here: we are ok, since we are in the tolerance measure
|
|
// no else statement here: we are ok, since we are in the tolerance measure
|
|
|
- } else if (battery_slots[slot].set_current < 0) {
|
|
|
|
|
|
|
+ } else if (slot.set_current < 0) {
|
|
|
// negative current -> discharge (with PWM)
|
|
// negative current -> discharge (with PWM)
|
|
|
- if (battery_slots[slot].dac_value != 0) {
|
|
|
|
|
|
|
+ if (slot.dac_value != 0) {
|
|
|
// seems like we switched from a charging before
|
|
// seems like we switched from a charging before
|
|
|
// -> disable DAC before getting active
|
|
// -> disable DAC before getting active
|
|
|
- set_dac(slot, 0);
|
|
|
|
|
|
|
+ set_dac(0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (battery_slots[slot].set_current + BATTERY_CURRENT_THRESHOLD < battery_slots[slot].measurement.current) {
|
|
|
|
|
|
|
+ if (slot.set_current + BATTERY_CURRENT_THRESHOLD < slot.measurement.current) {
|
|
|
// we are outside of the tolerance band
|
|
// we are outside of the tolerance band
|
|
|
// exceeded to the upper limit
|
|
// exceeded to the upper limit
|
|
|
// -> update pwm value, decrease the voltage
|
|
// -> update pwm value, decrease the voltage
|
|
|
|
|
|
|
|
- if (battery_slots[slot].pwm_value+1 <= MAX_PWM_CYCLE) {
|
|
|
|
|
|
|
+ if (slot.pwm_value+1 <= MAX_PWM_CYCLE) {
|
|
|
// pwm is inverse to the DAC since dragging more current means more negative
|
|
// pwm is inverse to the DAC since dragging more current means more negative
|
|
|
- set_pwm(slot, ++battery_slots[slot].pwm_value);
|
|
|
|
|
|
|
+ set_pwm(++slot.pwm_value);
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
// we want to give more current, but we can't ?!
|
|
// we want to give more current, but we can't ?!
|
|
|
- *battery_slots[slot].state = SLOT_WARN_HIGHER_PWM_NOT_POSSIBLE;
|
|
|
|
|
|
|
+ *slot.state = SLOT_WARN_HIGHER_PWM_NOT_POSSIBLE;
|
|
|
}
|
|
}
|
|
|
- } else if (battery_slots[slot].set_current - BATTERY_CURRENT_THRESHOLD > battery_slots[slot].measurement.current) {
|
|
|
|
|
|
|
+ } else if (slot.set_current - BATTERY_CURRENT_THRESHOLD > slot.measurement.current) {
|
|
|
// we are outside of the tolerance band
|
|
// we are outside of the tolerance band
|
|
|
// exceeded to the upplowerer limit
|
|
// exceeded to the upplowerer limit
|
|
|
// -> update pwm value, increase the voltage
|
|
// -> update pwm value, increase the voltage
|
|
|
- if (battery_slots[slot].pwm_value-1 >= 0) {
|
|
|
|
|
- set_pwm(slot, --battery_slots[slot].pwm_value);
|
|
|
|
|
|
|
+ if (slot.pwm_value-1 >= 0) {
|
|
|
|
|
+ set_pwm(--slot.pwm_value);
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
|
// we want to give more current, but we can't ?!
|
|
// we want to give more current, but we can't ?!
|
|
|
- *battery_slots[slot].state = SLOT_WARN_LOWER_PWM_NOT_POSSIBLE;
|
|
|
|
|
|
|
+ *slot.state = SLOT_WARN_LOWER_PWM_NOT_POSSIBLE;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
// we have 0 -> stop charging and discharging
|
|
// we have 0 -> stop charging and discharging
|
|
|
- batteryslots_disable(slot);
|
|
|
|
|
|
|
+ slot_disable();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-BatterySlotManager battery_slotmgr = {
|
|
|
|
|
- .init = batteryslots_init,
|
|
|
|
|
- .read_state = batteryslots_read_state,
|
|
|
|
|
- .adjust_current = batteryslots_adjust_current,
|
|
|
|
|
- .disable = batteryslots_disable
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|