LPBAM I2C MasterTx silently writes wrong SADD on bus (STM32CubeU5)
Summary
When an LPBAM scenario contains an I2C Master_Transmit node with the DevAddress field set to a 7-bit slave address (the value the CubeMX scenario designer accepts), the actual address byte transmitted on the I2C bus is not the expected value. The I2C peripheral sends an address byte that the slave does not recognise, so the slave does not ACK, no data is exchanged, and the response buffer stays at its uninitialised value forever.
This appears to be an interaction between (a) the CubeMX scenario designer's input validation (which accepts only 7-bit values, max 127) and (b) the LPBAM library's CR2.SADD encoding in STM32CubeU5/Utilities/lpbam/STM32U5/stm32_ll_lpbam.c (which OR's the raw DevAddress value into CR2 without shifting).
Affected versions
- STM32CubeU5 firmware: as included in STM32CubeMX 6.17 (verified locally May 2026)
- Target: STM32U5A5ZJTxQ on NUCLEO-U5A5ZJ-Q
- TrustZone: disabled (the bug is independent of TZ)
Reproduction project
Minimal CubeMX project, ~200 lines of user code, single I2C3 peripheral.
CubeMX setup
- Board Selector: NUCLEO-U5A5ZJ-Q
- TrustZone: Disabled
- HSE: Crystal/Resonator (16 MHz, X3 on-board crystal)
- PLL → SYSCLK 160 MHz, Range 1, EPOD on
- Peripherals enabled:
- USART1 (Async, 115200 8N1, PA9/PA10 for VCP)
- I2C3 (Standard mode 100 kHz, PC0/PC1, autonomous mode disabled)
- LPTIM1 (Counter mode, ARR=32767)
- LPDMA1 Channel 1
- LPBAM Application "LpbamAp1" with one queue containing 3 nodes:
LPTIM1.Start (continuous mode)
I2C3.MasterTx — 1 byte, DevAddress = 80 (0x50), no LPDMA trigger, AUTOEND, 7-bit
I2C3.MasterRx — 8 bytes, DevAddress = 80 (0x50), LPDMA trigger = LPTIM1 CH1 rising, AUTOEND, 7-bit
Hardware
- AT24C02 EEPROM (DIP-8) on I2C3:
- Pin 1-3 (A0/A1/A2): GND → slave address 0x50
- Pin 4: GND
- Pin 5 (SDA): PC1 (CN9-9)
- Pin 6 (SCL): PC0 (CN9-11)
- Pin 7 (WP): GND
- Pin 8 (VCC): 3V3
Internal pull-ups enabled in user code on PC0/PC1 (~40 kΩ — adequate for 100 kHz).
Linker script + manual edits required to make the project build
CubeMX 6.17 generates an incomplete LPBAM scenario for this configuration:
lpbam_lpbamap1_scenario_config.c is not generated — the header declares MX_LpbamAp1_Scenario_Init/Link/Start but no implementation exists. We hand-wrote stub implementations.
__attribute__((section(".lpbam_section"))) is not applied to the LPBAM node descriptors — they land in main SRAM (0x20...) instead of SRAM4 (0x28...). Added manually inside the USER CODE BEGIN Queue*_Desc blocks (regen-survivable).
extern declarations for the user data buffers (lpbam_cmd, lpbam_resp defined in main.c) had to be added in scenario_build.c USER CODE EV block.
- Linker script SRAM4 section (
.lpbam_section (NOLOAD) >SRAM4) added manually.
Each of those four items is arguably a separate CubeMX shortcoming. The bug below is independent of all of them — once the buffers and descriptors are confirmed in SRAM4, the address-encoding bug still occurs.
Expected vs Actual
Expected (based on standard CubeMX I2C semantics)
Setting DevAddress = 80 (= 0x50, the 7-bit AT24C02 address — the value the GUI accepts as a valid 7-bit address) should result in the I2C peripheral transmitting the address byte 0xA0 (= 0x50 << 1 with R/W=0) on the bus. The AT24C02 ACKs, and the chain proceeds.
Actual
A logic-analyzer capture of the bus shows the address byte decoded as 0x00 (general-call address). The AT24C02 does not ACK its own address (which is 0x50, not 0x00). The data byte the master attempts to send (the EEPROM memory pointer 0x00) is NACK'd along with the address. The response buffer lpbam_resp is never updated.
VCP output (after power-cycle to clear SRAM)
=== LPBAM single-byte MasterTx repro ===
I2C3 scan: 0x50
EEPROM page-write [C0..C7] @ 0x00: HAL=0
EEPROM verify-read: HAL=0, bytes = C0 C1 C2 C3 C4 C5 C6 C7
LPBAM scenario built: 15 nodes starting at 0x2800000C
Buffer addrs: lpbam_cmd=0x28000000 lpbam_resp=0x28000004 (SRAM4 = 0x28xxxxxx)
LPBAM started — observing chain output:
cycle 1: B0 B2 E0 1F 31 D3 CD 2F
cycle 2: B0 B2 E0 1F 31 D3 CD 2F
cycle 3: B0 B2 E0 1F 31 D3 CD 2F
The B0 B2 E0 1F 31 D3 CD 2F is uninitialised SRAM4 garbage that never gets overwritten by the LPBAM chain. The pre-pop verify confirms the EEPROM is wired correctly and contains C0..C7 at addresses 0..7 — the LPBAM read just isn't reaching it.
Bus decode
write to 0x00 ack data: 0x00
Each LPTIM1 cycle the bus shows two transactions: a 2-byte write to address 0x00 followed by an 8-byte read attempt that returns no ACKs.
Root-cause analysis (preliminary)
Looking at Utilities/lpbam/STM32U5/stm32_ll_lpbam.c line 1131:
case LPBAM_I2C_CONFIG_TRANSACTION_ID:
{
...
dummy = pConfNode->pInstance->CR2; // line 1122
*pConfNode->NodeDesc.pSrcVarReg = dummy | I2C_CR2_STOP; // line 1125
if ((mode is master)) {
dummy |= I2C_CR2_START | I2C_CR2_RELOAD | I2C_CR2_AUTOEND
| I2C_CR2_RD_WRN | pConfNode->Config.DevAddress // line 1131
| ((uint32_t)pConfNode->Config.Size << I2C_CR2_NBYTES_Pos);
...
if (master TX) dummy &= ~I2C_CR2_RD_WRN; // line 1265
dummy |= AddressingMode << I2C_CR2_ADD10_Pos; // line 1269
*pConfNode->NodeDesc.pSrcVarReg = dummy | DevAddress; // line 1272
}
}
The library OR's DevAddress directly into CR2's lower bits (SADD[9:0]). For 7-bit addressing, the I2C peripheral expects the actual 7-bit address in SADD[7:1] (i.e. shifted left by 1). With DevAddress=80 the SADD field ends up = 0x50, which the peripheral interprets as SADD[7:1] = 0x28 → bus byte = 0x50/0x51 → an analyzer would decode this as 7-bit address 0x28, not the intended 0x50.
But the bus trace decodes as 0x00, not 0x28 — so there is additional corruption beyond just the missing left-shift. Possibilities: the write at line 1125 (dummy | I2C_CR2_STOP, which has SADD bits zero) is going to the same descriptor and clobbering the SADD bits set at line 1272; or a separate later descriptor re-writes CR2 with stale STOP bits; or the I2C peripheral responds to the multi-step LPDMA write sequence in a way that ends with SADD cleared.
We did not fully isolate which of these is at fault. Manually patching DevAddress to a pre-shifted value (e.g. 0xA0 for slave 0x50) bakes the descriptor's CR2 source value correctly in SRAM (verified by reading the LPBAM source words after MX_*_Scenario_Build) — yet the bus still shows an incorrect address. Something at runtime, after LPDMA writes the descriptor's source value to CR2, is corrupting the SADD field.
Workaround
Restrict LPBAM I2C scenarios to MasterRx-only chains (single-node, hardware-triggered). Reading from a peripheral that doesn't require an address-pointer write avoids the MasterTx node entirely. The bug above prevents any single-byte MasterTx from completing successfully on the bus.
Asks of ST
- Document the
DevAddress encoding convention expected by the LPBAM I2C node — is it raw (already shifted) or 7-bit (lib should shift)?
- Fix the CubeMX scenario designer to (a) accept the matching encoding and (b) reject invalid values upfront.
- Fix the runtime address corruption that causes bus to show 0x00 even when the descriptor's SADD bits are correct in SRAM.
- Make the manual fixes listed above (scenario_config.c generation, NODE_SECTION attribute, extern decls, linker section) part of CubeMX's standard LPBAM output.
Files
- Reproduction project (zip attached)
- VCP capture (inline above)
main_user_code_scaffold.c
LPBAM-scenario.zip
LPBAM I2C MasterTx silently writes wrong SADD on bus (STM32CubeU5)
Summary
When an LPBAM scenario contains an I2C Master_Transmit node with the
DevAddressfield set to a 7-bit slave address (the value the CubeMX scenario designer accepts), the actual address byte transmitted on the I2C bus is not the expected value. The I2C peripheral sends an address byte that the slave does not recognise, so the slave does not ACK, no data is exchanged, and the response buffer stays at its uninitialised value forever.This appears to be an interaction between (a) the CubeMX scenario designer's input validation (which accepts only 7-bit values, max 127) and (b) the LPBAM library's CR2.SADD encoding in
STM32CubeU5/Utilities/lpbam/STM32U5/stm32_ll_lpbam.c(which OR's the rawDevAddressvalue into CR2 without shifting).Affected versions
Reproduction project
Minimal CubeMX project, ~200 lines of user code, single I2C3 peripheral.
CubeMX setup
LPTIM1.Start(continuous mode)I2C3.MasterTx— 1 byte, DevAddress = 80 (0x50), no LPDMA trigger, AUTOEND, 7-bitI2C3.MasterRx— 8 bytes, DevAddress = 80 (0x50), LPDMA trigger = LPTIM1 CH1 rising, AUTOEND, 7-bitHardware
Internal pull-ups enabled in user code on PC0/PC1 (~40 kΩ — adequate for 100 kHz).
Linker script + manual edits required to make the project build
CubeMX 6.17 generates an incomplete LPBAM scenario for this configuration:
lpbam_lpbamap1_scenario_config.cis not generated — the header declaresMX_LpbamAp1_Scenario_Init/Link/Startbut no implementation exists. We hand-wrote stub implementations.__attribute__((section(".lpbam_section")))is not applied to the LPBAM node descriptors — they land in main SRAM (0x20...) instead of SRAM4 (0x28...). Added manually inside theUSER CODE BEGIN Queue*_Descblocks (regen-survivable).externdeclarations for the user data buffers (lpbam_cmd,lpbam_respdefined in main.c) had to be added inscenario_build.cUSER CODE EV block..lpbam_section (NOLOAD) >SRAM4) added manually.Each of those four items is arguably a separate CubeMX shortcoming. The bug below is independent of all of them — once the buffers and descriptors are confirmed in SRAM4, the address-encoding bug still occurs.
Expected vs Actual
Expected (based on standard CubeMX I2C semantics)
Setting DevAddress = 80 (= 0x50, the 7-bit AT24C02 address — the value the GUI accepts as a valid 7-bit address) should result in the I2C peripheral transmitting the address byte
0xA0(=0x50 << 1with R/W=0) on the bus. The AT24C02 ACKs, and the chain proceeds.Actual
A logic-analyzer capture of the bus shows the address byte decoded as
0x00(general-call address). The AT24C02 does not ACK its own address (which is 0x50, not 0x00). The data byte the master attempts to send (the EEPROM memory pointer 0x00) is NACK'd along with the address. The response bufferlpbam_respis never updated.VCP output (after power-cycle to clear SRAM)
The
B0 B2 E0 1F 31 D3 CD 2Fis uninitialised SRAM4 garbage that never gets overwritten by the LPBAM chain. The pre-pop verify confirms the EEPROM is wired correctly and containsC0..C7at addresses 0..7 — the LPBAM read just isn't reaching it.Bus decode
Each LPTIM1 cycle the bus shows two transactions: a 2-byte write to address
0x00followed by an 8-byte read attempt that returns no ACKs.Root-cause analysis (preliminary)
Looking at
Utilities/lpbam/STM32U5/stm32_ll_lpbam.cline 1131:The library OR's
DevAddressdirectly into CR2's lower bits (SADD[9:0]). For 7-bit addressing, the I2C peripheral expects the actual 7-bit address inSADD[7:1](i.e. shifted left by 1). WithDevAddress=80the SADD field ends up = 0x50, which the peripheral interprets asSADD[7:1] = 0x28→ bus byte = 0x50/0x51 → an analyzer would decode this as 7-bit address0x28, not the intended0x50.But the bus trace decodes as
0x00, not0x28— so there is additional corruption beyond just the missing left-shift. Possibilities: the write at line 1125 (dummy | I2C_CR2_STOP, which has SADD bits zero) is going to the same descriptor and clobbering the SADD bits set at line 1272; or a separate later descriptor re-writes CR2 with stale STOP bits; or the I2C peripheral responds to the multi-step LPDMA write sequence in a way that ends with SADD cleared.We did not fully isolate which of these is at fault. Manually patching
DevAddressto a pre-shifted value (e.g.0xA0for slave 0x50) bakes the descriptor's CR2 source value correctly in SRAM (verified by reading the LPBAM source words afterMX_*_Scenario_Build) — yet the bus still shows an incorrect address. Something at runtime, after LPDMA writes the descriptor's source value to CR2, is corrupting the SADD field.Workaround
Restrict LPBAM I2C scenarios to MasterRx-only chains (single-node, hardware-triggered). Reading from a peripheral that doesn't require an address-pointer write avoids the MasterTx node entirely. The bug above prevents any single-byte MasterTx from completing successfully on the bus.
Asks of ST
DevAddressencoding convention expected by the LPBAM I2C node — is it raw (already shifted) or 7-bit (lib should shift)?Files
main_user_code_scaffold.c
LPBAM-scenario.zip