Skip to content

About

Like RaceTemp, but using STM32WB with integrated BLE instead of UART + an RF module.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

RaceTemp_BLE

RaceTemp_BLE is an STM32WB55 based Bluetooth Low Energy sensor bridge for RaceChrono. It reads local sensors, packages the measurements as RaceChrono DIY CAN/BLE messages, and lets RaceChrono log them as if they came from a CAN bus.

The project is based on the RaceChrono BLE DIY device idea from Aollin's demo project:

https://github.com/aollin/racechrono-ble-diy-device

RaceTemp adds the temperature, pressure, thermocouple, RPM, engine-hours, and engine-revolutions logic used by this project.

Current Status

This is still a work in progress, but has som "track record" as it's the only logger we have used for track days and races in 2026.

Implemented:

  • BLE device name: RaceTemp
  • RaceChrono-compatible CAN message characteristic
  • Optional RaceChrono CAN filter handling
  • ADC based MAP and NTC readings
  • MAX31855 thermocouple support
  • MAX31856 thermocouple support
  • Ignition input based RPM measurement
  • Engine operating hours counter
  • Engine revolutions counter
  • Persistent storage of engine counters after the engine stops
  • Optional raw measurement snapshot message

Building

You can download the binary (Release/RaceTemp_BLE.elf) and flash it to an STM32WB55. Android field flashing has been tested with STlinkP (Android app), STLINK-V3MINIE, and the WeAct STM32WB board. One can of course also flash it via ST-Link and STM32CubeProgrammer on a PC.

If you want to compile yourself on a PC with STM32CubeMX and STM32CubeIDE, then follow this 4-step guide:

  1. Open the project in STM32CubeMX and click "GENERATE CODE". This should generate some code files and copy some library files.
  2. Run the script: .\tools\fix-cubemx-ble-duplicates.ps1 See also my CubeMX-notes at the bottom of this page.
  3. Open the project in STM32CubeIDE and build the Debug or Release configuration.
  4. Connect the STLink debug probe and flash the binary.

The intended BLE security setup is:

  • Bonding enabled
  • No passkey
  • No MITM requirement
  • No input/output capability
  • Secure connections mandatory
  • GATT caching enabled
  • Static random address C0:52:54:42:4C:45
  • Advertisement includes the complete local name RaceTemp
  • Advertisement includes the RaceChrono DIY service UUID 0x1ff8

If pairing fails after a firmware or security setting change, delete/forget the old RaceTemp pairing on the phone and pair again.

Hardware Notes

Target MCU:

  • STM32WB55CGU

The project has been developed and tested on a WeAct STM32WB55 board.

Thermocouple IC options:

  • MAX31855
  • MAX31856

The thermocouple IC is selected at compile time in:

Core/Inc/RaceTemp_config.h

Thermocouple Polarity

Do not trust wire color blindly. For many Type K thermocouples using US/ANSI colors, yellow is positive and red is negative. Other color standards and probe suppliers may differ.

A quick practical TC polarity check:

  1. Connect the thermocouple.
  2. Read the thermocouple channel in RaceChrono.
  3. Warm the thermocouple tip with your fingers, hot air, or a lighter from a safe distance.
  4. If the temperature goes up, the polarity is correct.
  5. If the temperature goes down or becomes negative, swap the two thermocouple wires.

Configuring The Thermocouple IC In Firmware

Edit Core/Inc/RaceTemp_config.h and set:

#define RACETEMP_THERMOCOUPLE_IC RACETEMP_THERMOCOUPLE_IC_MAX31855

or:

#define RACETEMP_THERMOCOUPLE_IC RACETEMP_THERMOCOUPLE_IC_MAX31856

For MAX31856, also select the thermocouple type. K-Type is most common (for motorsport and exhaust temperature).

The firmware sends the thermocouple data as raw IC bytes on CAN ID 0x13. RaceChrono then decodes those bytes with an equation. This keeps the firmware simple and makes it possible to inspect status and fault bits from the IC.

Persistent Engine Counters

PID 21 / CAN ID 0x15 is the stored engine operating time in hours. It is a lifetime counter, not time since boot. PID 22 / CAN ID 0x16 is the stored engine revolution counter.

The counters are stored in the last two 4 KB flash pages:

  • 0x0807E000
  • 0x0807F000

The linker script reserves those pages by limiting normal application flash to 504K. This makes the firmware image fail to link before it can overlap the counter storage.

Expected flashing behavior:

  • Flashing with "erase necessary pages only" should preserve the counters.
  • Flashing with mass erase / full chip erase resets the counters to zero.
  • Manually erasing pages 0x0807E000 or 0x0807F000 resets the counters.

The firmware writes the counters to flash when RPM times out after the engine stops. If the RPM input is left floating during bench testing, false pulses can increase the counters, so keep the RPM input at a defined level when it is not connected to a signal source.

Using With RaceChrono

  1. Power the RaceTemp device.
  2. Pair the phone with the BLE device named RaceTemp.
  3. Open RaceChrono.
  4. Add/connect it as a RaceChrono BLE DIY/CAN device.
  5. Add custom CAN channels for the CAN IDs listed below.
  6. Enable the channels you want to log.

RaceChrono may show CAN IDs in either hexadecimal or decimal form. For example, 0x13 is decimal 19.

RaceChrono equations are documented here:

https://racechrono.com/support/equations

The thermocouple equations below use RaceChrono's bitsToInt() function. In RaceChrono, bit offset 0 is the most significant bit of payload byte 0. For the MAX31855 and MAX31856 temperature channels, the recommended equations below use bytesToInt() because they are easier to enter correctly on a phone.

RaceChrono CAN Channels

Most RaceTemp channels are sent as little-endian 32-bit floats. For those channels, use this RaceChrono equation:

bytesToFloatLe(raw, 0, 4)
CAN ID Decimal Channel Payload Unit RaceChrono equation
0x0B 11 MAP pressure float32 little-endian kPa bytesToFloatLe(raw, 0, 4)
0x0C 12 MAP NTC temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x0D 13 Volvo NTC temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x0E 14 AC NTC temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x0F 15 KOSO NTC temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x10 16 STM32 MCU temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x11 17 MAP raw ADC value float32 little-endian ADC count bytesToFloatLe(raw, 0, 4)
0x12 18 NTC raw ADC value float32 little-endian ADC count bytesToFloatLe(raw, 0, 4)
0x13 19 Thermocouple raw data IC-specific raw bytes deg C See thermocouple sections below
0x14 20 Engine speed float32 little-endian RPM bytesToFloatLe(raw, 0, 4)
0x15 21 Engine operating time float32 little-endian hours bytesToFloatLe(raw, 0, 4)
0x16 22 Engine revolutions float32 little-endian rev bytesToFloatLe(raw, 0, 4)
0x17 23 Ignition period float32 little-endian timer ticks bytesToFloatLe(raw, 0, 4)
0x18 24 Ignition captures float32 little-endian count bytesToFloatLe(raw, 0, 4)
0x19 25 Ignition rejects float32 little-endian count bytesToFloatLe(raw, 0, 4)
0x1A 26 EGT temperature float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x1B 27 Engine speed peak hold float32 little-endian RPM bytesToFloatLe(raw, 0, 4)
0x1C 28 EGT peak hold float32 little-endian deg C bytesToFloatLe(raw, 0, 4)
0x1D 29 Engine speed filtered float32 little-endian RPM bytesToFloatLe(raw, 0, 4)
0x1E 30 Thermocouple status float32 little-endian bitmask bytesToFloatLe(raw, 0, 4)
0x1F 31 Thermocouple recoveries float32 little-endian count bytesToFloatLe(raw, 0, 4)
0x20 32 Raw measurement snapshot packed raw bytes debug See source layout
0x21 33 RPM fast packet packed float32 little-endian values RPM See RPM fast packet below

The peak hold channels keep a new maximum value visible for 5 seconds. The RPM peak hold uses the filtered RPM channel so single noisy periods do not create false peaks. After 5 seconds without a higher sample, the held channels return to the current live value.

The filtered RPM channel is calculated from a short recent ignition-period window with outlier trimming. It is intended for the driver display. The raw RPM channel remains useful for ignition pickup debugging.

RPM Fast Packet

CAN ID 0x21 is sent at 25 Hz. It packs the driver-facing RPM values into one BLE notification:

Offset Channel Unit RaceChrono equation
0 RPM raw RPM bytesToFloatLe(raw, 0, 4)
4 RPM filtered RPM bytesToFloatLe(raw, 4, 4)
8 RPM peak hold RPM bytesToFloatLe(raw, 8, 4)

The individual RPM and ignition debug channels remain available at the slower sensor publishing rate for comparison and troubleshooting.

Thermocouple status is a bitmask:

  • 1: current EGT sample is valid
  • 2: SPI/read error
  • 4: thermocouple IC fault bit set
  • 8: MAX31856 config readback mismatch/error
  • 16: recovery was triggered on this sample
  • 32: implausible thermocouple temperature

When the thermocouple sample is invalid, the EGT channel sends 0 C. This is intentionally obvious in the driver display and logs; the firmware does not hold the last good EGT value.

Reading MAX31855 In RaceChrono

When RACETEMP_THERMOCOUPLE_IC_MAX31855 is selected, CAN ID 0x13 contains the four raw bytes read from the MAX31855. The byte order is the same as the IC SPI transfer: most significant byte first.

The MAX31855 thermocouple temperature is a signed 14-bit value with 0.25 deg C per bit.

Recommended RaceChrono equation:

bytesToInt(raw, 0, 2) / 16.0

Equivalent bitfield equation:

bitsToInt(raw, 0, 14) * 0.25

The bytesToInt() version works because the MAX31855 thermocouple value is left-aligned in the first two raw bytes.

Useful notes:

  • The MAX31855 fault flag is bit D16 of the 32-bit raw value.
  • The low bits contain the IC-specific fault details.
  • A separate RaceChrono status channel can use bytesToUint(raw, 3, 1) to show the lowest raw byte.
  • If the thermocouple channel shows unrealistic values, first confirm that the RaceTemp firmware is built for MAX31855 and not MAX31856.

Reading MAX31856 In RaceChrono

When RACETEMP_THERMOCOUPLE_IC_MAX31856 is selected, CAN ID 0x13 contains four bytes:

Payload byte Contents
0 MAX31856 LTCBH register
1 MAX31856 LTCBM register
2 MAX31856 LTCBL register
3 MAX31856 fault/status register

The MAX31856 thermocouple temperature is a signed 19-bit value with 0.0078125 deg C per bit.

Recommended RaceChrono equation:

bytesToInt(raw, 0, 3) / 4096.0

Equivalent bitfield equation:

bitsToInt(raw, 0, 19) * 0.0078125

The bytesToInt() version works because the MAX31856 thermocouple value is left-aligned in the first three raw bytes.

Useful notes:

  • Select the correct thermocouple type in RaceTemp_config.h.
  • Payload byte 3 is the MAX31856 fault/status register.
  • A separate RaceChrono status channel can use bytesToUint(raw, 3, 1).
  • If the temperature is wrong but changes with heat, check the selected thermocouple type first.
  • If the value is completely wrong, confirm that RaceChrono is using the MAX31856 equation and not the MAX31855 equation.

Raw Measurement Snapshot

CAN ID 0x20 is intended for development and debugging. It sends one packed snapshot of the raw measurement buffer:

  • ADC samples
  • Thermocouple SPI bytes
  • Ignition timing data

Normal RaceChrono logging should usually use the individual channels instead. The raw snapshot is useful when checking new sensors or debugging conversion logic.

Notes About CubeMX Regeneration

Unfortunately the current version of CubeMX can make some mistakes (it can duplicate user-section content in the BLE files), and some generated files contain project-specific settings. After regenerating the code, run the cleanup script before building:

powershell -ExecutionPolicy Bypass -File .\tools\fix-cubemx-ble-duplicates.ps1

The script removes duplicate CubeMX generated BLE functions, restores the RaceChrono BLE callbacks, restores the BLE security/address settings used by this project, and repairs the local linker script.

Important local linker-script repairs:

  • Normal application flash is limited to 504K.
  • PERSIST reserves the last two 4 KB flash pages for engine counters.
  • MAPPING_TABLE is placed at 0x20030000.
  • MB_MEM1 and .MB_MEM2 are placed in the CPU2 shared RAMB area.
  • .MB_MEM2 is 4-byte aligned so startup initialization does not fault.

The script also removes the extra generated HSEM lock before MX_APPE_Init(). Leaving that duplicate lock in place can stall BLE startup or lead to an early HardFault.

To re-generate the code from CubeMX:

  1. Open the .ioc file in CubeMX and click "GENERATE CODE"
  2. Run tools/fix-cubemx-ble-duplicates.ps1
  3. Build in STM32CubeIDE
  4. Check that pairing still works with RaceTemp

Keep project-specific RaceTemp logic in the RaceTemp source files where possible. This reduces the amount of code that lives inside CubeMX user sections.

About

Like RaceTemp, but using STM32WB with integrated BLE instead of UART + an RF module.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages