Skip to content

Add initial support for STM32F303K8 board in BMS #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ jobs:
# The mbed target to build for
target: [LPC1768]

# Add STM32F303 target for bms
include:
- project: bms
profile: debug
target: NUCLEO_F303K8
- project: bms
profile: release
target: NUCLEO_F303K8


steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
Expand Down
2 changes: 1 addition & 1 deletion bms/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ flash: deps $(BUILD_DIR)
#

.PHONY: debug
debug: build-debug
debug:
arm-none-eabi-gdb -x .gdbinit ./$(BUILD_DIR)/$(MBED_TARGET)/$(MBED_BUILD_PROFILE)/$(MBED_TOOLCHAIN)/bms.elf

#
Expand Down
8 changes: 8 additions & 0 deletions bms/mbed_app.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"config": {
"main-stack-size": {
"value": 2048
},
"stack-size": {
"value": 1024
}
},
"target_overrides": {
"LPC1768": {
"platform.stdio-baud-rate": 115200,
Expand Down
6 changes: 3 additions & 3 deletions bms/src/BmsConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
// Global pointer to can bus object
//
// This allows for all files to access the can bus output
extern CAN* canBus;
//extern CAN* canBus;

//Global pointer to DigitalOut objects for BMS_FAULT and CHARGER_CONTROL pins
//
//This allows for all files to access BMS_FAULT and CHARGER_CONTROL pins
extern DigitalOut* bmsFault;
extern DigitalOut* chargerControl;
//extern DigitalOut* bmsFault;
//extern DigitalOut* chargerControl;

//
// BMS Master Configuration
Expand Down
16 changes: 11 additions & 5 deletions bms/src/BmsThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
#include "LTC681xCommand.h"
#include "ThisThread.h"

BMSThread::BMSThread(LTC681xBus& bus, unsigned int frequency, std::vector<Queue<BmsEvent, mailboxSize>*> mailboxes) : m_bus(bus), mailboxes(mailboxes) {
BMSThread::BMSThread(LTC681xBus& bus, unsigned int frequency, std::array<BmsEventMailbox*, 2> mailboxes)
: m_bus(bus)
, m_chips {
LTC6811(bus, 0),
LTC6811(bus, 1),
LTC6811(bus, 2),
LTC6811(bus, 3)
}
, mailboxes(mailboxes)
{
m_delay = 1000 / frequency;
for (int i = 0; i < BMS_BANK_COUNT; i++) {
m_chips.push_back(LTC6811(bus, i));
}
for (int i = 0; i < BMS_BANK_COUNT; i++) {
//m_chips[i].getConfig().gpio5 = LTC6811::GPIOOutputState::kLow;
//m_chips[i].getConfig().gpio4 = LTC6811::GPIOOutputState::kPassive;
Expand All @@ -19,7 +25,7 @@ BMSThread::BMSThread(LTC681xBus& bus, unsigned int frequency, std::vector<Queue<

void BMSThread::threadWorker() {
// Perform self tests

//
// Cell Voltage self test
m_bus.WakeupBus();
m_bus.SendCommand(LTC681xBus::BuildBroadcastBusCommand(StartSelfTestCellVoltage(AdcMode::k7k, SelfTestMode::kSelfTest1)));
Expand Down
163 changes: 3 additions & 160 deletions bms/src/BmsThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
class BMSThread {
public:

BMSThread(LTC681xBus& bus, unsigned int frequency, std::vector<BmsEventMailbox*> mailboxes);
BMSThread(LTC681xBus& bus, unsigned int frequency, std::array<BmsEventMailbox*, 2> mailboxes);

// Function to allow for starting threads from static context
static void startThread(BMSThread *p) {
Expand Down Expand Up @@ -92,169 +92,12 @@ class BMSThread {
private:
unsigned int m_delay;
LTC681xBus& m_bus;
std::vector<LTC6811> m_chips;
std::vector<BmsEventMailbox*> mailboxes;
std::array<LTC6811, BMS_BANK_COUNT> m_chips;
std::array<BmsEventMailbox*, 2> mailboxes;

// Things that need to go away
bool m_discharging = false;

void throwBmsFault();
void threadWorker();
/*
void threadWorker() {
std::array<uint16_t, BMS_BANK_COUNT * BMS_BANK_CELL_COUNT> allVoltages;
std::array<std::optional<int8_t>, BMS_BANK_COUNT * BMS_BANK_TEMP_COUNT>
allTemps;

while (true) {
for (int i = 0; i < BMS_BANK_COUNT; i++) {
// Get a reference to the config for toggling gpio
LTC6811::Configuration& conf = m_chips[i].getConfig();

// Turn on status LED
conf.gpio5 = LTC6811::GPIOOutputState::kLow;
m_chips[i].updateConfig();

uint16_t* voltages = m_chips[i].getVoltages();

int temperatures[BMS_BANK_TEMP_COUNT];

// Measure all temp sensors
for (unsigned int j = 0; j < BMS_BANK_TEMP_COUNT; j++) {
conf.gpio1 = (j & 0x01) ? LTC6811::GPIOOutputState::kHigh
: LTC6811::GPIOOutputState::kLow;
conf.gpio2 = (j & 0x02) ? LTC6811::GPIOOutputState::kHigh
: LTC6811::GPIOOutputState::kLow;
conf.gpio3 = (j & 0x04) ? LTC6811::GPIOOutputState::kHigh
: LTC6811::GPIOOutputState::kLow;
conf.gpio4 = LTC6811::GPIOOutputState::kPassive;
m_chips[i].updateConfig();

// Wait for config changes to take effect
ThisThread::sleep_for(3);

uint16_t* temps = m_chips[i].getGpioPin(GpioSelection::k4);
temperatures[j] = temps[3];

delete temps;
}

// Turn off status LED
conf.gpio5 = LTC6811::GPIOOutputState::kHigh;
m_chips[i].updateConfig();

// Done with communication at this point
// Now time to crunch numbers

// Process voltages
for (int j = 0; j < 12; j++) {
uint16_t voltage = voltages[j] / 10;

int index = BMS_CELL_MAP[j];
if (index != -1) {
allVoltages[(BMS_BANK_CELL_COUNT * i) + index] = voltage;

if (voltage >= BMS_FAULT_VOLTAGE_THRESHOLD_HIGH) {
// Set fault line
printf("***** BMS LOW VOLTAGE FAULT *****\nVoltage at
%d\n\n", voltage); throwBmsFault();
}
if (voltage <= BMS_FAULT_VOLTAGE_THRESHOLD_LOW) {
// Set fault line
printf("***** BMS HIGH VOLTAGE FAULT *****\nVoltage at
%d\n\n", voltage); throwBmsFault();
}

// Discharge cells if enabled
if(m_discharging) {
if((voltage > prevMinVoltage) && (voltage - prevMinVoltage >
BMS_DISCHARGE_THRESHOLD)) {
// Discharge

printf("DISCHARGE CELL %d: %dmV (%dmV)\n", index,
voltage, (voltage - prevMinVoltage));

// Enable discharging
conf.dischargeState.value |= (1 << j);
} else {
// Disable discharging
conf.dischargeState.value &= ~(1 << j);
}
} else {
// Disable discharging
conf.dischargeState.value &= ~(1 << j);
}
}
}

delete voltages;


for (unsigned int j = 0; j < BMS_BANK_TEMP_COUNT; j++) {
auto temp = convertTemp(temperatures[j] / 10);
allTemps[(BMS_BANK_TEMP_COUNT * i) + j] = temp;

temp.map([&](auto t){
if (t < minTemp) minTemp = t;
if (t > maxTemp) maxTemp = t;
});
}
allBanksVoltage += totalVoltage;
}

averageVoltage = allBanksVoltage / (BMS_BANK_COUNT * BMS_BANK_CELL_COUNT);
prevMinVoltage = minVoltage;

printf("Temperatures: \n");
for(int i = 0; i < BMS_BANK_COUNT * BMS_BANK_CELL_COUNT; i++){
allTemps[i].map_or_else([&](auto temp) {
if (temp >= BMS_FAULT_TEMP_THRESHOLD_HIGH) {
printf("***** BMS HIGH TEMP FAULT *****\nTemp at %d\n\n",
temp); throwBmsFault(); } else if (temp <= BMS_FAULT_TEMP_THRESHOLD_LOW) {
printf("***** BMS LOW TEMP FAULT *****\nTemp at %d\n\n",
temp); throwBmsFault();
}

printf("%3d ", temp);
},
[&]() {
printf("ERR ");
//printf("***** BMS INVALID TEMP FAULT *****\n");
//throwBmsFault();
});
if((i + 1) % BMS_BANK_CELL_COUNT == 0)
printf("\n");
}

canBus->write(BMSStatMessage(allBanksVoltage / 10, maxVoltage, minVoltage,
maxTemp, minTemp));

// Send CAN
for (size_t i = 0; i < BMS_BANK_COUNT; i++) {
// Convert from optional temp values to values with default of -127 (to
indicate error) auto temps = std::array<int8_t, BMS_BANK_TEMP_COUNT>();
std::transform(allTemps.begin() + (BMS_BANK_TEMP_COUNT * i),
allTemps.begin() + (BMS_BANK_TEMP_COUNT * (i + 1)),
temps.begin(),
[](std::optional<int8_t> t) { return t.value_or(-127); });

canBus->write(BMSTempMessage(i, (uint8_t*)temps.data()));
}

for (size_t i = 0; i < 7; i++) {
canBus->write(BMSVoltageMessage(i, allVoltages + (4 * i)));
}

// Compute time elapsed since beginning of measurements and sleep for
// m_delay accounting for elapsed time
// TODO: use a hardware timer or a virtual timer or literally anything
// else. kek.
//unsigned int timeElapsed = TIME_I2MS(chVTTimeElapsedSinceX(timeStart));
#ifdef DEBUG
//printf("BMS Thread time elapsed: %dms\n", timeElapsed);
#endif
ThisThread::sleep_for(m_delay);
}
}
*/
};
2 changes: 1 addition & 1 deletion bms/src/Event.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class BmsEvent {
virtual ~BmsEvent() {};
};

static constexpr auto mailboxSize = 4;
static constexpr auto mailboxSize = 1;
using BmsEventMailbox = Queue<BmsEvent, mailboxSize>;

// Measurement
Expand Down
80 changes: 33 additions & 47 deletions bms/src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,46 @@
#include "LTC681xBus.h"
#include "Event.h"

// When car is off maybe one reading every 10 sec
// when car is on 10 readings per second

// TODO: map 12 cells to number of cells
// TODO: change m_chips to array rather than vector
// TODO: publish fault states
// TODO: SoC tracking using Ah counting and voltage measuring

// Fault states:
// - AMS
// - IMD
//
// * Over temp
// - Under temp
// * Over voltage
// * Under voltage
//
// * Failed init
// * Comm fail


CAN* canBus;
DigitalOut* bmsFault;
DigitalOut* chargerControl;
#ifdef TARGET_NUCLEO_F303K8
// Required for setting MISO to pull up on STM32
#include <targets/TARGET_STM/TARGET_STM32F3/STM32Cube_FW/STM32F3xx_HAL_Driver/stm32f3xx_ll_gpio.h>
#endif

CAN canBus = CAN(BMS_PIN_CAN_RX, BMS_PIN_CAN_TX, BMS_CAN_FREQUENCY);
DigitalOut bmsFault = DigitalOut(BMS_PIN_BMS_FLT);
DigitalOut chargerControl = DigitalOut(BMS_PIN_CHARGER_CONTROL);

void initIO();

// TODO: We need a better way of statically allocating thread stack
constexpr size_t STACK_SIZE = 1024;
unsigned char bmsThreadStack[STACK_SIZE];
Thread bmsThreadThread = Thread(osPriorityNormal, STACK_SIZE, bmsThreadStack);

int main() {
// Init all io pins
initIO();

canBus->write(BMSCellStartup());
canBus.write(BMSCellStartup());

ThisThread::sleep_for(1s);
SPI spiDriver = SPI(BMS_PIN_SPI_MOSI,
BMS_PIN_SPI_MISO,
BMS_PIN_SPI_SCLK,
BMS_PIN_SPI_SSEL,
use_gpio_ssel);

#ifdef TARGET_NUCLEO_F303K8
// This is a hack required to set the MISO pin to use a pull up resistor
LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_6, LL_GPIO_PULL_UP);
#endif

SPI* spiDriver = new SPI(BMS_PIN_SPI_MOSI,
BMS_PIN_SPI_MISO,
BMS_PIN_SPI_SCLK,
BMS_PIN_SPI_SSEL,
use_gpio_ssel);
spiDriver->format(8, 0);
auto ltcBus = LTC681xParallelBus(spiDriver);
spiDriver.format(8, 0);
auto ltcBus = LTC681xParallelBus(&spiDriver);

auto canMailbox = new BmsEventMailbox();
auto uiMailbox = new BmsEventMailbox();
std::vector<BmsEventMailbox*> mailboxes = { canMailbox, uiMailbox };
auto canMailbox = BmsEventMailbox();
auto uiMailbox = BmsEventMailbox();
std::array<BmsEventMailbox*, 2> mailboxes = { &canMailbox, &uiMailbox };

Thread bmsThreadThread;
BMSThread bmsThread(ltcBus, 1, mailboxes);
bmsThreadThread.start(callback(&BMSThread::startThread, &bmsThread));

Expand All @@ -72,7 +64,7 @@ int main() {
}

while(true) {
auto event = canMailbox->get();
auto event = canMailbox.get();
if (event.status == osEventMessage) {
BmsEvent* msg = (BmsEvent*)event.value.p;

Expand Down Expand Up @@ -120,12 +112,6 @@ int main() {
void initIO() {
printf("INIT\n");

canBus = new CAN(BMS_PIN_CAN_RX, BMS_PIN_CAN_TX, BMS_CAN_FREQUENCY);

bmsFault = new DigitalOut(BMS_PIN_BMS_FLT);

chargerControl = new DigitalOut(BMS_PIN_CHARGER_CONTROL);

// Set modes for IO
/*
palSetLineMode(LINE_BMS_FLT_LAT, PAL_MODE_INPUT);
Expand All @@ -135,9 +121,9 @@ void initIO() {
*/

// Reset BMS fault line
bmsFault->write(1);
bmsFault->write(0);
bmsFault.write(1);
bmsFault.write(0);

// Enable charging
chargerControl->write(0);
chargerControl.write(0);
}