Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Project repo: https://github.com/UWARG/efs-can-power-module

Specifications (from the EE Team)

Overall Hardware Architecture (taken from https://uwarg-docs.atlassian.net/wiki/x/AoCsmQ )

Inc drawio
zoom1
simple0
isSketch0
custContentId2795208817
pageId2578219010
lbox1
diagramDisplayNameUntitled Diagram-1719935379177.drawio
hiResPreview0
baseUrlhttps://uwarg-docs.atlassian.net/wiki
imgPageId2841149698
diagramNameUntitled Diagram-1719935379177.drawio
pCenter0
aspectgNHAFkkuJoC4MAd_17IC 1
width1656
includedDiagram1
aspectHash515ab772fb9a87493f9c5f2f2354dc7c48aabf45
linksauto
tbstyletop
height764

Background

The drone uses a battery pack containing 12 cells, where 2 groups of 6 cells are each connected in series (hence 6S).

Each group of 6 cells is connected to a battery monitoring circuit (shortened as BMC later).

This circuit measures:

  • The voltage of each cell

  • The current delivered by the group

    • This is done by forcing the battery to deliver current through a resistor with a tiny resistance. This resistor, called a shunt/shunt resistor, follows Ohm’s law: V=IR

    • This implies that I=V/R, which means that the current passing through a shunt is equal to its voltage (which can be measured easily), divided by its resistance (which is a known constant).

And it sends:

Note

We are not exactly sure of everything yet.

  • Battery-related information relating to the voltages and currents

  • The voltage and current information are sent as 2 analog signals, which our microcontroller converts to digital ones via an Analog-to-Digital Converter (ADC).

  • Some other information is sent via the I2C protocol

Description

Info
  • MCU (STM32xX) in the top right is the microcontroller that we are writing the code to

  • Its job is to translate the messages it receives from the BQ76925 6s LiPo Battery Monitor boards and send the corresponding messages to the flight controller (FC) using the CAN protocol

    • The flight controller we are using is a Pixhawk 4, which runs the Ardupilot firmware

    • Because battery voltages and currents will change over time, the “translation” is continuous

Expand
titleWhy are we making this?

The FC needs this information to make other decisions, e.g. if a part is consuming too much power, or when to land

Specific Hardware Information (taken from https://uwarg-docs.atlassian.net/wiki/x/HYBXq)

308fff19-3cb7-4e74-b29c-ef6484d78e5b-0000.pngImage Modified
Info

The ports we are interested in:

  • PA9: SCL_1, Serial Clock line for I2C 1, to configure BMC 1

  • PA10: SDA_1, Serial Data line for I2C 1, to configure BMC 1

  • PA7: SCL_2, Serial Clock line for I2C 2, to configure BMC 2

  • PB4: SDA_

...

  • 2, Serial Data line for I2C 2, to configure BMC 2

  • PA12: CAN_TX, Transmit line for CAN

  • PA11: CAN_RX

...

  • , Receive line for CAN

  • PA3:

...

  • OVERCURRENT, receives 5.5 V when an overcurrent occurs, and 0 V otherwise

  • PA4: VIOUT_FILT, receives 0.25-1.25 V (REF_SEL=0) / 0.5-2.5 V (REF_SEL=1), representing the cell current for cells 1-6

...

  • , as measured by a 1-milliohm shunt

  • PA5: VCOUT1_FILT, receives 1.47-1.53 V (REF_SEL=0) / 2.94-3.06 V (REF_SEL=1), representing the cell voltages for cells 1-6

...

  • PB0: ADC1_FILT, receives VREF, the ADC reference voltage

  • PB1: VCOUT2_FILT, receives 1.47-1.53 V (REF_SEL=0) / 2.94-3.06 V (REF_SEL=1), representing the cell voltages for cells 7-12

  • PA2:

...

  • ADC2_FILT, receives VREF, the ADC reference voltage


\uD83E\uDD14 Current Roadblocks

Note

Libcanard has a high learning curve. Neither the DroneCAN website nor the Libcanard repo has beginner-friendly tutorials. YouTube videos also won’t help directly

Tasks Break Down:

✅  Action Items

  •  

...

  • Initialize the Battery Monitoring Circuit using I2C
  •  Read battery data using the specified ports

\uD83D\uDEA9 Milestones

  •  Understand project specifications
  •  Understand the I2C protocol
  •  Understand the CAN protocol
  •  Understand DroneCAN
  •  etc.

Open Questions

...

Are our speculated ports correct?

...

What is transmitted over I2C?

...


\uD83D\uDD17 Reference materials

Relevant protocols

Project Resources

Battery Monitoring Circuit

Datasheet: https://www.ti.com/product/BQ76925?qgpn=bq76925#software-development

  • Addressing: all I2C addresses are calculated using the formula

    Code Block
    languagec
    ADDRESS = 0x20 + REG_ADDR

Where ADDRESS is the real address to read/write to, and REG_ADDR is the register address mentioned on the datasheet, from 0x00 to 0x1F.
Remember this distinction between the real and register addresses. All I2C addresses you see after this point will be register addresses.

Source: Datasheet, 8.5.1.1 I2C Addressing

  • Selecting the cell for the VCOUT pin:
    To select the cell to measure the voltage of:

    Code Block
    languagec
    // Write to the register address:
    REG_ADDR = 0x01
    
    // With data:
    DATA = 0x10 + CELL

Where CELL is the cell number. CELL=0x0 refers to cell 1, CELL=0x1 refers to cell 2, and so on, up to CELL=0x5referring to cell 6.

Source: Datasheet, 8.6.1 Register Descriptions (Tables 6 to 8)

  • Reference voltage selection:

    Code Block
    languagec
    // Write to the register address:
    REG_ADDR = 0x04
    
    // With data:
    DATA = REF_SEL

Where REF_SEL can be set to 0 or 1, with the following effects on the BMC pins:

Table 14. Reference Voltage Selection

REF_SEL

VREF (V)

VCOUT Gain (V)

VIOUT Voltage Range (V)

0

1.5

0.3

0.25 - 1.25

1

3.0

0.6

0.5 - 2.5

Expand
titleWhat about Cyclic Redundancy Check (CRC)?

Yes, it’s true that you could also enable CRC with this memory address. To do that, add 0x80 to DATA above.

We haven’t decided whether we want CRC though, so right now we’ll use the default option… which is “disabled“.

Source: Datasheet, 8.6.1 Register Descriptions (Tables 13 and 14)

  • Cell Voltage Monitoring

    Code Block
    languagec
    // The voltage of the currently selected cell, VCn,
    // is calculated with the following formula:
    VCn = ((VCOUT * GC_VREF + OC_VCOUT) / G_VCOUT) * (1 + GC_VCOUT)
    
    // Where:
    VCOUT = ADC_count / Full_scale_count * VREF_NOMINAL // This is the voltage of the VCOUT pin, as measured by the MCU
    GC_VCOUT = ((VCn_GC_4 << 4) + VCn_GAIN_CORR) * 1E-3
    OC_VCOUT = ((VCn_OC_4 << 4) + VCn_OFFSET_CORR) * 1E-3
    GC_VREF = (1 + ((VREF_GC_4 << 4) + VREF_GAIN_CORR) * 1E-3) 
              + (((VREF_OC_5 << 5) + (VREF_OC_4 << 4) + VREF_OFFSET_CORR) * 1E-3)/VREF_NOMINAL

Several values can be accessed through the I2C interface:

  • VCn_GC_4, where n is the cell number

    • VC1_GC_4

      • I2C register address: 0x17

      • Data bit location: 6

    • VC2_GC_4

      • I2C register address: 0x17

      • Data bit location: 4

    • VC3_GC_4

      • I2C register address: 0x18

      • Data bit location: 6

    • VC4_GC_4

      • I2C register address: 0x18

      • Data bit location: 4

    • VC5_GC_4

      • I2C register address: 0x18

      • Data bit location: 2

    • VC6_GC_4

      • I2C register address: 0x18

      • Data bit location: 0

  • VCn_OFFSET_CORR,
    where n is the cell number

    • VC1_OFFSET_CORR

      • I2C register address: 0x11

      • Data bit locations: 7 to 4

    • VC2_OFFSET_CORR

      • I2C register address: 0x12

      • Data bit locations: 7 to 4

    • VC3_OFFSET_CORR

      • I2C register address: 0x13

      • Data bit locations: 7 to 4

    • VC4_OFFSET_CORR

      • I2C register address: 0x14

      • Data bit locations: 7 to 4

    • VC5_OFFSET_CORR

      • I2C register address: 0x15

      • Data bit locations: 7 to 4

    • VC6_OFFSET_CORR

      • I2C register address: 0x16

      • Data bit locations: 7 to 4

  • VCn_OC_4, where n is the cell number

    • VC1_OC_4

      • I2C register address: 0x17

      • Data bit location: 7

    • VC2_OC_4

      • I2C register address: 0x17

      • Data bit location: 5

    • VC3_OC_4

      • I2C register address: 0x18

      • Data bit location: 7

    • VC4_OC_4

      • I2C register address: 0x18

      • Data bit location: 5

    • VC5_OC_4

      • I2C register address: 0x18

      • Data bit location: 3

    • VC6_OC_4

      • I2C register address: 0x18

      • Data bit location: 1

  • VCn_GAIN_CORR,
    where n is the cell number

    • VC1_GAIN_CORR

      • I2C register address: 0x11

      • Data bit locations: 3 to 0

    • VC2_GAIN_CORR

      • I2C register address: 0x12

      • Data bit locations: 3 to 0

    • VC3_GAIN_CORR

      • I2C register address: 0x13

      • Data bit locations: 3 to 0

    • VC4_GAIN_CORR

      • I2C register address: 0x14

      • Data bit locations: 3 to 0

    • VC5_GAIN_CORR

      • I2C register address: 0x15

      • Data bit locations: 3 to 0

    • VC6_GAIN_CORR

      • I2C register address: 0x16

      • Data bit locations: 3 to 0

  • VREF_OC_5

    • I2C register address: 0x1b

    • Data bit location: 2

  • VREF_OC_4

    • I2C register address: 0x1b

    • Data bit location: 1

  • VREF_GC_4

    • I2C register address: 0x1b

    • Data bit location: 0

Source: Datasheet, 8.3.2.2 Cell Voltage Monitoring



Up-to-date electrical schematics from the EE team

Project 6s Power Module (Ask the EE team for access)

Receiving incoming messages (Polling/Interrupt/DMA)

We are going to receive messages from an external device (the BMC), but we can’t predict when we will receive them. There are 3 solutions to this:

  • Polling: repeatedly checking whether a message was received using a loop. If a message gets detected, it gets processed, then the loop continues. This is a purely software solution.

    • Advantages:

      • Very easy to implement

      • You don’t need to worry about race conditions (when multiple pieces of code unintentionally access and modify some variable at the same time)

    • Disadvantages:

      • Extremely inefficient. The loop eats up most of the microcontroller’s computational resources, which it needs for many other tasks.

  • Interrupt: when a message gets received, it triggers a hardware interrupt. This causes all other processes to stop. Then the message gets processed, and the other processes resume after that. STM32 microcontrollers support many internal interrupts (for common events like receiving an I2C message), and external interrupts (triggered by a GPIO pin).

    • Advantages:

      • More efficient than polling

    • Disadvantages:

      • You need to be careful about race conditions

      • Still needs the microcontroller for data reception

  • Direct Memory Access (DMA): Similar to an interrupt, except the peripheral writes its message directly to the microcontroller’s memory. Then it signals the microcontroller that a new message came.

    • Advantages:

      • Most efficient for large messages

    • Disadvantages:

      • You need to be careful about race conditions

      • Less efficient than regular interrupts for small messages