STM32F446RE with telemetry ICs.
Table of Contents
- nerve
- 1 Overview
- 2 BNO085 9-DOF IMU
- 3 BMP390 Barometric Pressure Sensor
- 4 TJA1051T/3 CAN Bus Transceiver
- 5 XBee-PRO 900HP Long Range 900 MHz OEM RF Module
- 6 SD Card
- 7 SAM-M10Q RF Receiver Galileo, GLONASS, GPS
- 8 SPLIT4-25V2 UART FPV Camera
- 9 WS2812B PWM Addressable RGB LED
- 10 Real Time Clock (RTC)
- 11 Shared Low-Level Software Features
- 12 Software Driven Features
Manufacturer Part Number | Manufacturer | Description | Quantity | Notes |
---|---|---|---|---|
STM32F446RE | STMicroelectronics | 32-bit MCU | 1 | |
BNO085 | CEVA Technologies, Inc. | 9-DOF IMU | 1 | |
BMP390 | Bosch Sensortec | Barometric Pressure Sensor | 1 | |
TJA1051T/3 | NXP USA Inc. | CAN Bus Transceiver | 2 | |
0472192001 | Molex | microSD Hinged 8 Position Connector | 1 | |
SAM-M10Q | u-blox | RF Receiver Galileo, GLONASS, GPS | 1 | |
XBee-PRO 900HP | Digi | Long Range 900 MHz OEM RF Module | 1 | Future: XBee SX 900 or XBee XR 900 |
SPLIT4-25V2 | RunCam | UART FPV Camera | 1 | |
WS2812B | (Various) | PWM Addressable RGB LED | (Many) |
Drawio file here: nerve.drawio
Pin & Peripherals Table
STM32F446RE | Peripheral | Config | Connection | Notes |
---|---|---|---|---|
PB3 | SYS_JTDO-SWO |
TC2050 SWD Pin 6: SWO |
||
PA14 | SYS_JTCK-SWCLK |
TC2050 SWD Pin 4: SWCLK |
||
PA13 | SYS_JTMS-SWDIO |
TC2050 SWD Pin 2: SWDIO |
||
TIM2_CH1 |
PWM no output | BMP390 BMP3 driver timer. | ||
TIM5_CH1 |
PWM no output | BNO085 SH2 driver timer. | ||
PA0 | SYS_WKUP0 |
External | ||
PC13 | SYS_WKUP1 |
External | ||
PC7 | SPI2_SCK |
BNO085 Pin 19: H_SCL/SCK/RX |
||
PC6 | GPIO_Output (SPI2 CS) |
Pull-up, set high | BNO085 Pin 18: H_CSN |
|
PB14 | SPI2_MISO |
BNO085 Pin 20: H_SDA/H_MISO/TX |
||
PB15 | SPI2_MOSI |
BNO085 Pin 17: SA0/H_MOSI |
||
PC0 | GPIO_EXTI0 |
Pull-up, falling edge | BNO085 Pin 14: H_INTN |
|
PC10 | GPIO_Output |
BNO085 Pin 6: PS0/Wake |
Pull low to trigger wake. | |
Hardware pull-up | BNO085 Pin 5: PS1 |
|||
PC9 | GPIO_Output |
BNO085 Pin 11: NRST |
Pull low to reset. | |
PB6 | I2C1_SCL |
BMP390 Pin 2: SCK |
||
PB7 | I2C1_SDA |
BMP390 Pin 4: SDI |
||
PA15 | GPIO_Output |
XBee-PRO 900HP Pin 6: RESET |
Pull low to reset. | |
PA10 | USART1_RX |
115200 bps | XBee-PRO 900HP Pin 3: DOUT |
|
PA9 | USART1_TX |
115200 bps | XBee-PRO 900HP Pin 4: DIN |
|
PA11 | USART1_CTS |
XBee-PRO 900HP Pin 25: CTS |
Hardware flow control (RS232). | |
PA12 | USART1_RTS |
XBee-PRO 900HP Pin 29: RTS |
Hardware flow control (RS232). | |
PA3 | USART2_RX |
115200 bps | SAM-M10Q Pin 13: TXD |
|
PA2 | USART2_TX |
115200 bps | SAM-M10Q Pin 14: RXD |
|
PA1 | GPIO_Output |
SAM-M10Q Pin 18: RESET_N |
Pull low to reset (>= 1 ms). | |
PC5 | USART3_RX |
115200 bps | SPLIT4-25V2 | |
PB10 | USART3_TX |
115200 bps | SPLIT4-25V2 | |
PB2 | SDIO_CK |
MicroSD card: CK |
||
PD2 | SDIO_CMD |
MicroSD card: CMD |
||
PC8 | SDIO_D0 |
MicroSD card: D0 |
||
PB0 | SDIO_D1 |
(Software configured) | MicroSD card: D1 |
4-bit mode is configured by software. |
PB1 | SDIO_D2 |
(Software configured) | MicroSD card: D2 |
4-bit mode is configured by software. |
PC11 | SDIO_D3 |
(Software configured) | MicroSD card: D3 |
4-bit mode is configured by software. |
PC4 | GPIO_Input |
FATFS middleware | MicroSD card: Detect |
High when SD card inserted, else GND. |
PB8 | CAN1_RX |
TJA1051T/3 (1 of 2) Pin 1: TXD |
||
PB9 | CAN1_TX |
TJA1051T/3 (1 of 2) Pin 4: RXD |
||
PB12 | CAN2_RX |
TJA1051T/3 (2 of 2) Pin 1: TXD |
||
PB13 | CAN2_TX |
TJA1051T/3 (2 of 2) Pin 4: RXD |
||
PA8 | TIM1_CH1 |
PWM Generation CH1 | WS2812B Pin: DIN |
DIN pin number depends on IC variant. |
Notes:
- PA4, PA5, PA6, PA7 can be configured for
SPI1_NSS
,SPI_SCK
,SPI1_MISO
andSPI1_MOSI
respectively. - PB4 and PB5 can be configured for
TIM3_CH1
andTIM3_CH2
respectively.
8 MHz High Speed External (HSE)
↓
Phase-Locked Loop Main (PLLM)
↓
180 MHz SYSCLK
↓
180 MHz HCLK
↓
→ 45 MHz APB1 (Maxed) → 90 MHz APB1 Timer
→ 90 MHz APB2 (Maxed) → 180 MHz APB2 Timer
↓
48 MHz PLL48CLK
↓
48 MHz SDIO
9-axis Inertial Measurement Unit (IMU) combining an accelerometer, gyroscope, and magnetometer, based on Bosch Sensortec's BNO080 hardware, with sensor fusion firmware developed by CEVA, Inc. (formerly Hillcrest Laboratories). (Non-standard) I2C and SPI capable.
Utilized reference documents:
1000-3535 - Sensor Hub Transport Protocol v1.8
1000-3600 - SH-2 SHTP Reference Manual v1.5_1
1000-3625 - SH-2 Reference Manual v1.4
1000-3918 - BNO080 Migration_1
1000-3927 - BNO080 Datasheet v1.6
1000-4044 - BNO080-BNO085 Sensor Calibration Procedure v1.3
1000-4045 - App Note - BNO080-BNO085 Tare Function Usage Guide_1
HillcrestLabs BNO080-085 DataSheet_C
The BNO085 runs the same hardware as the BNO080, however runs custom Sensor Hub 2 (SH-2) firmware to reduce development overhead on features related to sensor fusion and optimization. SH-2 is designed around the Sensor Hub Transport Protocol (SHTP), which runs on SPI, I2C, etc.
In an SPI setup, there is always one controller (master) connected to one or more peripherals (slaves). The controller controls the communication by generating a clock signal (SCK) and selecting which slave to communicate with using the Chip Select (CS) line. Data is exchanged between the controller and peripheral(s) over two data lines: COPI/MOSI and CIPO or MISO.
Basic pinouts:
-
Clock (SCK)
- The clock signal generated by the master device that synchronizes data transfer in SPI communication.
-
Chip Select (CS) or Slave Select (NSS)
- A signal used to select a specific slave device in SPI communication. When the CS line is active (usually low), the selected slave device is enabled to communicate with the master.
-
Controller Out Peripheral In (COPI) or Master Out Slave In (MOSI)
- The data line used to transfer data from the master device to the slave device. The master outputs data on this line, which the slave reads.
-
Controller In Peripheral Out (CIPO) or Master In Slave Out (MISO)
- The data line used to transfer data from the slave device to the master device. The slave outputs data on this line, which the master reads.
Full-Duplex: Data can be sent and received simultaneously.
Half-Duplex: Data is either sent or received at any given time, not both simultaneously.
CPOL (Clock Polarity): determines the idle state of the clock signal (SCK).
- CPOL = 0: The clock is low (0) when idle.
- CPOL = 1: The clock is high (1) when idle.
CPHA (Clock Phase): determines when data is sampled relative to the clock signal.
- CPHA = 0: Data is sampled on the leading (1st) clock edge.
- CPHA = 1: Data is sampled on the trailing (2nd) clock edge.
SPI Modes (Combination of CPOL and CPHA):
Mode | CPOL | CPHA | SCK idle state | Data captured on | Data output on |
---|---|---|---|---|---|
0 | 0 | 0 | Low (0) | Rising edge of SCK (1st edge) | Falling edge |
1 | 0 | 1 | Low (0) | Falling edge of SCK (2nd edge) | Rising edge |
2 | 1 | 0 | High (1) | Falling edge of SCK (1st edge) | Rising edge |
3 | 1 | 1 | High (1) | Rising edge of SCK (2nd edge) | Falling edge |
The datasheet specifies the use of CPOL = 1 (high) and CPHA = 1 (2nd edge).
As specified in the datasheet, the maximum SPI clock rate is 3 MHz. Given that SPI2 runs on the APB1 bus clock (45 MHz), and the prescaler values are powers of 2 (2, 4, 8, etc.).
PSC = 16 is used (powers of 2).
Final clock rate is 2.8125 MHz.
3 GPIO output pins are used to control pins: PS0/Wake, PS1 and NRST. These pins manage SPI/I2C switching, the SPI configuration and reset. Theoretically, some of these can be pulled low via hardware and it would still work. However, as suggested by the official SH2 driver struct and for flexibility purposes, all 3 pins are set for their own GPIO output pins.
TIM5 is configured to be used for timing operations (1 µs time base) in the SH2 SHTP drivers.
TIM5 runs based on the APB1 timer clocks which are set to 45 MHz. The prescaler (PSC) must be calculated accordingly to achieve a 1 µs (1 MHz) time base. In other words, aiming for 1 tick = 1 µs.
GPIO_EXTI0
is set up for the INTN
pin for BNO0885 to MCU response (see
datasheet).
Submodule: sh2.
Source: github.com/ceva-dsp/sh2.
STM32 HAL abstraction and runner functions:
24-bit absolute barometric pressure sensor by Bosch Sensortec, designed for performant altimeter applications. Very small package, I2C and SPI capable.
Utilized reference documents:
BST-BMP390-DS002-07 - BMP390 Datasheet v1.7
The BMP390 is ideally suited for burst communications over both I2C and SPI. I2C was chosen due to its simplified wiring and ease of peripheral integration. Additionally, in most applications, a 9-DOF IMU is likely to be used as the primary dynamic sensor. (I also just wanted to not use SPI for everything, that's kinda boring).
As specified by datasheets, I2C Fast Mode is used for the (fast mode standard) 400 kHz clock.
A clock duty cycle of 2 (50/50) is used for simplicity.
Similar to the BNO085's timer (2.4 Timer), TIM2 is configured to be used for timing operations (1 µs time base) in the BMP3 drivers.
Since TIM2 is also on APB1, the prescaler calculations are the same as the BNO085, see 2.4.1 Timer Prescaler Calculation.
Submodule: BMP3_SensorAPI.
Source: github.com/boschsensortec/BMP3_SensorAPI.
STM32 HAL abstraction and runner functions:
CAN transceiver (MCU to 2-wire CAN bus) by NXP. 3V - 5V variant of TJA1051.
Utilized reference documents:
TJA1051 Product data sheet Rev9
AH1014 - Application Hints Rev01-50
The 3V variant is used for convince, just an easy pick. (I also had experience with it previously).
CAN peripherals run on APB1 (45 MHz), the goal is for a 500 kHz CAN bus.
Prescaler = 5
Time Quanta in Bit Segment 1 = 15 times
Time Quanta in Bit Segment 2 = 2 times
Time Quantum = 111.111 ns
Lots of resources and calculators online, example here: http://www.bittiming.can-wiki.info/.
The Digi XBee series RF modules were selected for their versatility and mesh networking capabilities, making them an ideal choice for scalable and reliable wireless communication.
The XBee modules are programed using Digi XCTU.
Setting Parameter | Default Value | Change To | Reasoning | |
---|---|---|---|---|
HP | Preamble ID | 0 | Custom defined | Value to separate networks within channels. Ensure uniform value in the network. |
ID | Network PAN ID | 0x7FFF (Default) | Custom defined | Custom PAN ID for the network (isolation). Ensure uniform value in the network. |
RR | Retries | 10 | Custom defined | Max retries for unacknowledged packets, ie: 3. Use software to handle final failure/success. |
SH | Serial Number High | Device-specific | Higher 32-bits of source device's 64-bit address. Device-specific, unchangeable. | |
SL | Serial Number Low | Device-specific | Lower 32-bits of source device's 64-bit address. Device-specific, unchangeable. | |
DH | Destination High | 0 | Custom defined | Higher 32-bits of destination's 64-bit address. 0x0 = broadcast. Use software to switch per frame. |
DL | Destination Low | 0 | Custom defined | Lower 32-bits of destination's 64-bit address. 0xFFFF = broadcast. Use software to switch per frame. |
TO | Transmit Option | C0 (DigiMesh) | 0x40 = Point to Point/Multipoint, 0x80 = Repeater/Directed-Broadcast, 0xC0 = DigiMesh. |
|
NI | Node Identifier | Custom name | Human-readable name for easier identification in XCTU. | |
CI | Cluster Identifier | 0x11 | Custom | Default cluster identifier used for serial data communication. 0x12 = Destination echo mode. |
EE | Encryption Enable | 0 (Disabled) | 1 (Enabled) | Enables encryption. Ensure uniform value in the network. |
KY | AES Encryption Key | 32 hex digits | 128-bit encryption key. Ensure uniform value in the network. | |
BD | Baud Rate | 3 (9600 bps) | 7 (115200 bps) | Ensure match with MCU configuration. |
AP | API Enable | 0 (Transparent) | 1 (API Mode) | API mode (structured frame communication). 2 = API mode with escape characters. |
D6 | RTS | 0 (Disabled) | 1 (Enabled) | Enable flow control (RTS). |
D7 | CTS | 1 (Enabled) | 1 (Enabled) | Enable flow control (CTS). |
Hardware flow control is enabled.
CTS (Clear to Send) and RTS (Request to Send) are hardware flow control signals used in UART communication to manage data transmission between devices.
This help to ensure that data is only transmitted when both the sender and receiver are ready, preventing data loss or buffer overflow.
UART baud rate is set for 115200 bps.
DMA is used configured to allow continuous radio receive in hardware:
- Mode:
Circular
- Continuous data reception (useful for telemetry).
- Peripheral Increment Address:
Disabled
.- UART peripheral address stays constant.
- Memory Increment Address:
Enabled
.- DMA writes data to different memory locations in the XBee API buffer.
- (Both Peripheral and Memory) Data Width:
Byte
. - Use FIFO:
Disabled
.- Not needed for most UART applications.
STM32 HAL abstraction and runner functions:
Generic SD interface for portable nonvolatile high speed storage.
SDIO is running in 4-bit mode. In STM32CubeMX it is configured for SDIO 1-bit and 4-bit configurations are loaded in software. There are known issues with STM32 HAL related to SDIO 4-bit mode, this is the workaround I am using.
NVIC for SDIO_TX
and SDIO_RX
are enabled.
SDIO global interrupted is enabled.
FATFS middleware is enabled with the following changes, everything else is left default:
USE_LFN (Use Long Filename)
=Enabled with static working buffer on the BSS
.MAX_SS (Maximum Sector Size)
=4096
.- Advanced setting,
Use DMA template
=Enabled
.
PC4
(GPIO_Input
) is configured as the Detect_SDIO
input within Platform
Settings.
SD card logic in hardware is defined as:
- Low/GND/False when there is no SD card.
- High/3V3/True when there is.
Multi-constellation GPS module by u-blox. GPS, GLONASS, Galileo capable at 18Hz individually or dual (GPS and GLONASS) at 10 Hz. Supports both UART and I2C.
Utilized reference documents:
SAM-M10Q Data sheet 14-May-2024
SAM-M10Q Integration manual 31-May-2023
M10 firmware 5.10 interface description 11-Jul-2023
The u-blox SAM module was chosen for its ease of future updates and extremely easy integration and development.
UART baud rate is set for 9600 bps (default baud rate of u-blox module).
STM32 HAL abstraction and runner functions:
UART baud rate is set for 115200 bps.
STM32 HAL abstraction driver is made of 2 files:
Individually addressable RGB LED with an integrated control circuit over a series single-wire data protocol.
APB2: 180 MHz (clock for TIM1 PWM output channels).
All subsequent calculations assume an 180 MHz peripheral clock on the PWM timer channel.
A Pulse Width Modulation (PWM) timer is utilized generate data signals to the WS2812B.
PA8 → Timer 1 Channel 1 → PWM Generation CH1.
htim1.Instance = TIM1;
htim1.Init.Prescaler = 9-1;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 25-1;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
Given the PWM equation:
-
$f_{TIM} = 180 \space \mathrm{MHz}$ - Defined by the PWM channel's peripheral clock.
-
$ARR = 25 - 1$ - Counter period, aka Auto Reload Register (ARR) of 25 is used to simplify the translation of duty cycle percentages.
-
$f_{PWM} = 800 \space \mathrm{kHz}$ - As specified by the WS2812B datasheet, the target data transfer time
period is 1.25 µs, or
$$1.25 \times 10 ^{-6} \space \mathrm{s}$$ . - Calculating for required PWM frequency:
$f_{PWM} = \frac{1}{1.25 \times 10 ^{-6} \space \mathrm{s}} = 800 \space \mathrm{kHz}$
- As specified by the WS2812B datasheet, the target data transfer time
period is 1.25 µs, or
Thus, the prescaler,
Direct Memory Access (DMA) is used to transfer the color data for the WS2812B LEDs directly from memory to the PWM timer's registers without requiring CPU overhead.
DMA TIM1_CH1
is set up accordingly:
- Direction:
Memory to Peripheral
.- Software tells what to send on the output.
- Transaction mode:
Normal Request
.- Send the PWM signal just once, not continuous mode (repeat always).
- Source (Memory)
Increment addressing on Memory = enabled
. - Source (Memory)
Data Width = Half Word
.- The WS2812B uses a 24-bit data frame, for 3 8-bit (red, green, blue)
codes. Thus, ideally the memory source data width would be
Byte
. However, the F4 DMA architecture requires matching source and destination data widths, unlike other's (ie: L4) which allow for dynamic mismatched data widths.
- The WS2812B uses a 24-bit data frame, for 3 8-bit (red, green, blue)
codes. Thus, ideally the memory source data width would be
- Destination (Peripheral)
Increment addressing on Peripheral = disabled
. - Destination (Peripheral)
Data Width = Half Word
.- TIM1 is a 16-bit/pulse PWM timer, matching the Half Word (16-bits).
Nested Vectored Interrupt Controller (NVIC) is used to efficiently manage the interrupt generated by the DMA controller upon the completion of a data transfer. This allows the system to update the PWM signals for the WS2812B LEDs with minimal CPU overhead, enabling efficient and responsive control of the LEDs.
On CubeMX, NVIC TIM1 capture compare interrupt
is enabled for TIM1.
HAL_TIM_PWM_PulseFinishedCallback()
is called within the Interrupt Service
Routine (ISR) for end of PWM DMA transmissions.
The WS2812B driver is made of 2 files:
ws2812b_init(): Initialize DMA, flags, timers, etc.
↓
ws2812b_set_colour(): Set struct values for (R, G, B) colours.
↓
ws2812b_update(): Initialize DMA buffer and trigger PWM DMA transfer.
↓
ws2812b_callback(): Called in ISR for end of PWM, stop DMA transfer.
Duty cycle required for PWM control:
-
$D$ = Duty cycle percentage, required calculation. -
$PW$ = Pulse width (active time), as defined by the datasheet. -
$T$ = Total signal time period, 1.25 µs, as defined by the datasheet. -
$Value$ = Actual digital value to send representing the required duty cycle percentage.
Operation | Margin | Value | ||
---|---|---|---|---|
0 code | 0.4 µs | ±150 ns | 32% | 8 |
1 code | 0.8 µs | ±150 ns | 64% | 16 |
The datasheet requires a low signal of > 50 µs. Thus, the minimum number of full (low) cycles is given by:
RTC is enabled and setup for clock and calendar.
Callbacks for certain peripherals are shared by the STM32 HAL and are centralized within the following module:
This approach ensures that callback functions remain atomic and specific to individual drivers. These atomic functions are then consolidated into a single function (user implementation), overriding the weak declarations provided by the STM32 HAL.
Contains general initialization functions related to Nerve specific firmware.
Contains the primary logic running every main loop execution cycle. Anything that requires the fastest execution frequency are contained here. Anything with larger fixed frequencies are managed by the scheduler.
The main scheduler uses the microcontrollers Data Watchpoint and Trace (DWT).
Generalized functions used for managing diagnostic functions and variables.
Generalized functions related to error checking for other drivers or Nerve specific firmware.
Generalized control systems (PID) structures and functions.
The control systems implementation is defined for general-purpose 6 degrees of freedom (DOF) systems, encompassing x, y, z, pitch, yaw, and roll. This design was developed for use in various 6 DOF-capable systems, including drones.
12 PIDs are implemented in a traditional outer and inner loop architecture. The loops are structured hierarchically, progressing from the largest-scale variable (position) to the smallest-scale variable (rate of rotation).
- Position Loop
- Regulates the current position along the x, y, and z axes.
- Output: Velocity commands to correct any position errors.
- Velocity Loop
- Manages the velocity of movement along the x, y, and z axes.
- Output: Movement or attitude commands to reach target velocities.
- Attitude Loop
- Governs the vehicle’s orientation, including pitch, roll, and yaw angles.
- Output: Angular rate commands to adjust the vehicle’s orientation.
- Rate Loop
- Controls the rate of rotation, measured as angular velocity.
- Output: Movement commands to achieve the desired rotation rate.