API

This documentation outlines the library created for the BMS.

DEV

Devices, representation of hardware that can be interfaced with. In general, devices are communicated with via some sort of IO interface, but that is not strictly a rule. An LED is a simplistic example of a device.

BQ76952

class BMS::DEV::BQ76952

Represents the functionality of the BQ76952.

This is a layer of abstraction which handles the I2C communication between the host and the BQ chip.

Part of the logic contained is the ability to write out BQ settings to the BQ chip itself. This will be able to handle taking in settings and making the corresponding I2C commands to write out the settings. TI Technical Reference Manual: https://www.ti.com/lit/ug/sluuby2b/sluuby2b.pdf

Public Types

enum Status

Represents the status of operation of the BQ76952.

This can be used to represent the state of the BQ76952 or the result of a BQ76952 operation.

Values:

enumerator OK

Operation took place successfully.

enumerator TIMEOUT

Timeout waiting for an operation.

enumerator I2C_ERROR

Failed at the I2C level to communicate with the BQ.

enumerator ERROR

Failed the specific BQ operation (not I2C related)

Public Functions

BQ76952(EVT::core::IO::I2C &i2c, uint8_t i2cAddress)

Create a new instance of the BQ76952 which will communicate over the given I2C bus with the given address.

Parameters
  • i2c[in] I2C interface to use to communicate on the bus

  • i2cAddress[in] The address of the BQ76952 to use

Status writeSetting(BQSetting &setting)

Write out the given setting.

Parameters

setting[in] The BQ setting to write out

Status enterConfigUpdateMode()

Enter CONFIG_UPDATE mode.

This is the mode that the BQ chip should be in whenever modifying settings. If settings are modified, and the BQ is not in CONFIG_UPDATE mode, the results are unpredictable. For more information, see Section 7.6 of the BQ76952 Technical Reference Manual.

Returns

The result of attempting to enter config update mode

Status exitConfigUpdateMode()

Exit CONFIG_UPDATE mode.

Returns

The result of attempting to exit config update mode

Status makeDirectRead(uint8_t reg, uint16_t *result)

Execute a direct read request.

Parameters
  • reg[in] The I2C register address to read from

  • result[out] The data that was read

Returns

The status of the read request attempt

Status makeSubcommandRead(uint16_t reg, uint32_t *result)

Execute a subcommand read request.

Parameters
  • reg[in] The subcommand register address

  • result[out] The result of the read request

Returns

The status of the read request attempt

BQ76952::Status commandOnlySubcommand(uint16_t reg)

Run a subcommand that has no result.

Parameters

reg[in] The subcommand register address

Returns

The status of the subcommand attempt

Status makeRAMRead(uint16_t reg, uint32_t *result)

Execute RAM read request.

Parameters
  • reg[in] The RAM register to read from

  • result[out] The data that was read

Returns

The status of the read request

Status makeDirectWrite(uint8_t reg, uint16_t data)

Execute a direct command write.

This involves writing out at most 16 bits to a register.

Parameters
  • reg[in] The I2C register address to write to

  • data[in] The data to write out

Returns

The status of the write request attempt

Status writeRAMSetting(BQSetting &setting)

Write out a subcommand settings.

Subcommands take in a 16-bit address which is written out to I2C registers 0x3E and 0x3F in little endian. Data associated with the command is written into 0x40-0x44, also in little endian.

Parameters

setting[in] The setting to write out

Returns

The result of the setting write attempt Status::I2C_ERROR => Failed to communicate with the BQ Status::ERROR => Setting not accepted by BQ Status::OK => Successfully wrote out the setting

Status inConfigMode(bool *result)

Check to see if the BQ chip is in configure mode.

Configure mode is a state where the BQ chip is able to handle making settings changes. This mode is discussed in detail in the BQ datasheet.

Parameters

result[out] Populated with true if the BQ chip is in config mode

Returns

The status of attempting to get the current mode Status::I2C_ERROR => Failed to communicate with the BQ Status::ERROR => BQ encountered an error attempting to read Status::OK => Configure mode state read successfully

Status communicationStatus()

Attempt to see if the BQ chip can be communicated with.

This will read the ID of the BQ chip, and verify it matches the expected value.

Returns

Status::OK on success, Status::ERROR otherwise

Status getCellVoltage(uint16_t cellVoltages[NUM_CELLS], uint32_t &sum, CellVoltageInfo &voltageInfo)

Fill a buffer with each cell voltage.

Parameters
  • cellVoltages[out] The buffer to fill with the cell voltage, must be NUM_CELLS in size

  • sum[out] The total voltage across all cells

  • voltageInfo[out] A struct containing the values below

Returns

The status of the read attempt

Status isBalancing(uint8_t targetCell, bool *balancing)

Determine the state of balancing on a given cell.

Parameters
  • targetCell[in] The target cell to check the balancing of

  • balancing[out] Updates to whether the cell is balancing

Returns

The status of the read attempt

Status setBalancing(uint8_t targetCell, uint8_t enable)

Write out the balancing state to the target cell.

Writing a 1 enables balancing; writing a 0 disables balancing

Parameters
  • targetCell[in] The target cell to change the balance state of

  • enable[in] 1 for enabling balancing 0 otherwise

Returns

The status of the write attempt

Status getCurrent(int16_t &current)

Read the current running through pack.

Parameters

current[out] Current running through the pack

Returns

The status of the read attempt

Status getTotalVoltage(uint16_t &totalVoltage)

Read the total voltage of the pack.

Parameters

totalVoltage[out] Total voltage of the pack

Returns

The status of the read attempt

Status getTemps(BqTempInfo &bqTempInfo)

Read the temperature information measured by the BQ.

Parameters

bqTempInfo[out] Temperature information measured by the BQ

Returns

The status of the read attempt

Status getBQStatus(uint8_t bqStatusArr[7])

Read BQ status information.

Parameters

bqStatusArr[out] BQ status information

Returns

The status of the read attempt

Public Static Attributes

static constexpr uint8_t NUM_CELLS = 12

The number of cells connected to the BQ chip.

Interlock

class BMS::DEV::Interlock

Represents the interlock which detects if the battery is has a cable connected to it.

Public Functions

explicit Interlock(EVT::core::IO::GPIO &gpio)

Create an interlock which will detect the presence of a cable via the provided GPIO.

Pre

The GPIO is set as an input

bool isDetected()

See if a cable is detected in the interlock.

ThermistorMux

class BMS::DEV::ThermistorMux

Multiplexer connected to thermistors.

Public Functions

ThermistorMux(IO::GPIO *muxSelectArr[3], IO::ADC &adc)

Create a ThermistorMux instance.

Parameters
  • muxSelectArr[in] MUX select pins

  • adc[in] ADC instance to read

uint16_t getTemp(uint8_t thermNum)

Get temperature from one thermistor.

Parameters

thermNum[in] Number of thermistor to read

Returns

Thermistor temperature

Top-Level Classes

The rest of the classes used in this codebase are not meant to represent hardware interfaces. They are just used to separate BMS behaviors into separate units to help understanding and organizing the code.

BMS

class BMS::BMS : public CANDevice

Interface to the BMS board.

Includes the CANopen object dictionary that defines the features that are exposed by the BMS on the CANopen network.

Public Types

enum State

Represents the different states the BMS can be in.

Values:

enumerator START

When the BMS is powered on.

enumerator INITIALIZATION_ERROR

When the BMS fails startup sequence.

enumerator FACTORY_INIT

When the system is waiting for settings to be sent to the BMS.

enumerator TRANSFER_SETTINGS

When the BMS is actively sending settings over to the BQ.

enumerator SYSTEM_READY

When the BMS is ready for charging / discharging.

enumerator DEEP_SLEEP

When the system is running in a low power mode.

enumerator UNSAFE_CONDITIONS_ERROR

When a fault is detected during normal operation.

enumerator POWER_DELIVERY

When the BMS is on the bike and delivering power.

enumerator CHARGING

When the BMS is handling charging the battery pack.

Public Functions

BMS(BQSettingsStorage &bqSettingsStorage, DEV::BQ76952 bq, DEV::Interlock &interlock, IO::GPIO &alarm, SystemDetect &systemDetect, IO::GPIO &bmsOK, DEV::ThermistorMux &thermMux, ResetHandler &resetHandler, EVT::core::DEV::IWDG &iwdg)

Make a new instance of the BMS with the given devices.

Parameters
  • bqSettingsStorage – Object used to manage BQ settings storage

  • bq – BQ chip instance

  • interlock – GPIO used to check the interlock status

  • alarm – GPIO used to check the BQ alarm status

  • systemDetect – Object used to detect what system the BMS is connected to

  • bmsOK – GPIO used to output the OK signal from the BMS

  • thermMux – MUX for pack thermistors

  • resetHandler – Handler for reset messages

CO_OBJ_T *getObjectDictionary() override

Get a pointer to the start of the CANopen object dictionary.

Returns

Pointer to the start of the CANopen object dictionary.

uint8_t getNumElements() override

Get the number of elements in the object dictionary.

Returns

The number of elements in the object dictionary

uint8_t getNodeID() override

Get the device’s node ID.

Returns

the node ID of the CAN device

void canTest()

Set private variables to values that make CAN testing easy.

void process()

Handle running the core logic of the BMS.

This involves

  1. Checking for state machine related updates

  2. Polling sensor diagnostic sensor information

  3. Responding to error conditions

Public Static Attributes

static constexpr IO::Pin OK_PIN = IO::Pin::PA_6

BMS Pinout.

static constexpr uint8_t BQ_COMM_ERROR = 0x01

Error values.

static constexpr uint8_t NODE_ID = 20

The node ID used to identify the device on the CAN network.

BQSetting

class BMS::BQSetting

Represents the settings that are sent out to the BQ chip.

Settings are made to three potential areas of the BQ chip.

  1. Direct: Settings applied directly via an I2C address. ex) Register 0xC4 is given to 0x56

  2. Subcommand: The subcommand address is written out to two I2C registers of the BQ chip and the value is written out to the 4 value register.

  3. RAM: Similar to subcommand

Public Types

enum BQSettingType

Represents the different options where the settings can be applied.

Values:

enumerator UNINITIALIZED
enumerator DIRECT
enumerator RAM
enumerator SUBCOMMAND

Public Functions

BQSetting(BQSettingType settingType, uint8_t numBytes, uint16_t address, uint32_t data)

Constructor with given setting parameters.

Parameters
  • settingType[in] – The type of the setting

  • numBytes[in] – The number of bytes the setting will store

  • address[in] – The target address of the setting

  • data[in] – The data to store (unused if numBytes == 0)

BQSetting()

Constructor for an uninitialized BQ setting.

void fromArray(const uint8_t buffer[ARRAY_SIZE])

Populate the content of the object with the values parsed from the provided array.

The array is in the format below: Byte 0: Bit 0 and Bit 1: Command type 00 -> Direct 01 -> Subcommand 10 -> RAM 11 -> Unused Bit 2-4: Number of bytes of data Direct -> Always 1 Subcommand -> Either 4 or 0 RAM -> Either 4 or 0 Byte 1-2: Address to write to of the BQ chip Byte 3-6: Data

Parameters

buffer[in] – The array to pull data from

void toArray(uint8_t buffer[ARRAY_SIZE])

Populate an array with the bit representation of the BQSettings.

This follows the form shown on BQSetting::fromArray.

Parameters

buffer[out] – The array to populate with parsed data

BQSettingType getSettingType()

Get the setting type.

Returns

The setting type

uint16_t getAddress()

Get the address of the setting.

For direct commands the address is 8 bits in size; for subcommand and RAM it is 16 bits.

Returns

The address of the setting

uint32_t getData()

Get the contained data as a 32-bit value.

Returns

The data as a 32-bit value

uint8_t getNumBytes()

Get the number of bytes stored in the data.

Returns

The number of bytes of data stored

Public Static Attributes

static constexpr uint8_t ARRAY_SIZE = 7

The size of the array in which the BQSetting can be fit into.

Units are bytes.

BQSettingStorage

Warning

doxygenclass: Cannot find class “BMS::BQSettingStorage” in doxygen xml output for project “BMS” from directory: ../build/doxygen/xml/

ResetHandler

class BMS::ResetHandler

Detects and reports reset CAN messages.

Public Functions

ResetHandler()

Make new handler instance.

void registerInput(EVT::core::IO::CANMessage msg)

Register a received CAN message.

Parameters

msg – Message to register

bool shouldReset()

Check whether reset messages have been received, indicating that the BMS should reset.

Returns

Whether the BMS should reset

SystemDetect

class BMS::SystemDetect

Device which has the ability to determine if the BMS system is connected to the charger or the bike system.

This is handled by checking for a CANopen heartbeat for specific devices (pre-charge board for the bike, charge controller for the charging). The device also has the ability to check how long since the last heartbeat has been detected.

The main way this device is used is with a CAN interrupt handler. Essentially, this device should be passed into the CAN interrupt handler and given the ability to check for the specific heartbeat values.

Public Types

enum System

The different systems that could be detected.

If no heartbeat has been processed within a given timeout, the system is left as unknown.

Values:

enumerator BIKE
enumerator CHARGER
enumerator UNKNOWN

Public Functions

SystemDetect(uint32_t bikeHeartbeat, uint32_t chargeHeartbeat, uint32_t timeout)

Create the system detect device which will work to identify the provided beat CANopen IDs.

Parameters
  • bikeHeartbeat[in] The heartbeat CANopen ID associated with the bike.

  • chargeHeartbeat[in] The heartbeat CANopen ID associated with the charger

  • timeout[in] The timeout which represents time between getting heartbeat values where the device still recognizes the system it is attached to. If the heartbeat is not received within this timeout, device assumes it does not know what the system is attached to. This heartbeat has been detected is in milliseconds.

void processHeartbeat(uint32_t heartbeatID)

Check the given CAN ID to see if it represents a system detect heartbeat.

Parameters

heartbeatID[in] The ID to potentially identify as a system detect

System getIdentifiedSystem()

Get the currently detected system, could be unknown.

Returns

The current identified system

Structures

To make passing data between certain BMS functions more compact, some structs have been defined.

CellVoltageInfo

struct CellVoltageInfo

PackTempInfo

struct PackTempInfo

BqTempInfo

struct BqTempInfo