Skip to content

Commit 4c8b1ee

Browse files
committed
fix: I2C stalling/crashing due to long running interrupt handling, better buffer handling
1 parent 717808d commit 4c8b1ee

3 files changed

Lines changed: 63 additions & 34 deletions

File tree

firmware/userapp/Core/Inc/slave.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ extern "C" {
1919
#define BOOTLOADER_TRIGGER_MAGIC 0xB007B007UL
2020

2121
void Slave_Init(void);
22+
void Slave_Poll(void);
2223

2324
uint8_t Slave_RegRead(uint8_t addr);
2425
void Slave_RegWrite(uint8_t addr, uint8_t val);

firmware/userapp/Core/Src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ int main(void)
118118
while (1)
119119
{
120120
Display_Tick();
121+
Slave_Poll();
121122
/* USER CODE END WHILE */
122123

123124
/* USER CODE BEGIN 3 */

firmware/userapp/Core/Src/slave.c

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
#include "slave.h"
22
#include "bootloader.h"
3+
#include "postcodes.h"
34

45
extern I2C_HandleTypeDef hi2c1;
56

67
static uint8_t register_map[REG_MAP_SIZE] = {0}; // Register map storage
78
static uint8_t new_segment_available = 0;
8-
static uint8_t reg_index = 0; // Current write address
9+
static uint8_t reg_index = 0;
910

1011
static uint32_t error = HAL_OK;
1112
static uint8_t error_state = 0;
1213

1314
static uint8_t bootloader_magic_buf[4] = {0};
1415
static uint8_t receiving_boot_magic = 0; // Set while a BOOTLOADER_TRIGGER_I2C_ADDR write is in flight
1516

17+
static uint8_t rx_scratch[REG_MAP_SIZE + 1]; // [0]=target register, [1..]=data
18+
19+
// Set by ISR callbacks, checked by Slave_Poll() from the main loop.
20+
static volatile uint8_t need_restart = 0;
21+
1622
void Slave_Start(void);
1723

1824
/**
@@ -24,6 +30,14 @@ void Slave_Init(void)
2430
Slave_Start();
2531
}
2632

33+
void Slave_Poll(void)
34+
{
35+
if (need_restart) {
36+
need_restart = 0;
37+
Slave_Start();
38+
}
39+
}
40+
2741
void Slave_Start(void)
2842
{
2943
while (HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_BUSY) {}
@@ -36,7 +50,6 @@ void Slave_Start(void)
3650
HAL_I2C_EnableListen_IT(&hi2c1);
3751
}
3852

39-
4053
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
4154
{
4255
if (hi2c != &hi2c1) {
@@ -55,11 +68,12 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui
5568
receiving_boot_magic = 1;
5669
ret = HAL_I2C_Slave_Seq_Receive_IT(&hi2c1, bootloader_magic_buf, sizeof(bootloader_magic_buf), I2C_LAST_FRAME);
5770
} else {
58-
ret = HAL_I2C_Slave_Seq_Receive_IT(&hi2c1, &reg_index, 1, I2C_NEXT_FRAME);
71+
// Single call for the whole transaction
72+
ret = HAL_I2C_Slave_Seq_Receive_IT(&hi2c1, rx_scratch, sizeof(rx_scratch), I2C_NEXT_FRAME);
5973
}
6074

6175
if (ret != HAL_OK) {
62-
Error_Handler();
76+
need_restart = 1;
6377
}
6478
}
6579
}
@@ -70,7 +84,29 @@ void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
7084
return;
7185
}
7286

73-
Slave_Start();
87+
need_restart = 1;
88+
}
89+
90+
static void Slave_FlushRxScratch(void)
91+
{
92+
if (hi2c1.pBuffPtr >= rx_scratch && hi2c1.pBuffPtr <= rx_scratch + sizeof(rx_scratch)) {
93+
uint16_t received = (uint16_t)(hi2c1.pBuffPtr - rx_scratch);
94+
95+
if (received >= 1) {
96+
uint8_t start_addr = rx_scratch[0];
97+
uint16_t data_len = received - 1;
98+
99+
for (uint16_t i = 0; i < data_len; i++) {
100+
register_map[(start_addr + i) % REG_MAP_SIZE] = rx_scratch[1 + i];
101+
}
102+
reg_index = (uint8_t)(start_addr + data_len);
103+
104+
// Did the received range contain Segment register?
105+
if (start_addr <= REG_Segments && REG_Segments < start_addr + data_len) {
106+
new_segment_available = 1;
107+
}
108+
}
109+
}
74110
}
75111

76112
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
@@ -93,9 +129,7 @@ void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
93129
return;
94130
}
95131

96-
if (HAL_I2C_Slave_Seq_Receive_IT(hi2c, &register_map[reg_index++], 1, I2C_NEXT_FRAME) != HAL_OK) {
97-
Error_Handler();
98-
}
132+
Slave_FlushRxScratch();
99133
}
100134

101135
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c)
@@ -104,16 +138,9 @@ void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c)
104138
return;
105139
}
106140

107-
Error_Handler();
108-
}
109-
110-
void Slave_HandleComplete()
111-
{
112-
if (reg_index == 0x26 /*&& (register_map[0x24] & 0x0F) > 0*/)
113-
new_segment_available = 1;
141+
need_restart = 1;
114142
}
115143

116-
117144
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
118145
{
119146
if (hi2c != &hi2c1) {
@@ -122,31 +149,31 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
122149

123150
error = HAL_I2C_GetError(&hi2c1);
124151

125-
switch (error) {
126-
case HAL_I2C_ERROR_AF:
127-
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
128-
break;
129-
case HAL_I2C_ERROR_BERR:
130-
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
131-
error_state = 1;
132-
break;
133-
default:
134-
Error_Handler();
135-
}
136-
152+
// error is a bitmask
153+
if (error & HAL_I2C_ERROR_AF) {
154+
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
155+
}
156+
if (error & HAL_I2C_ERROR_ARLO) {
157+
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
158+
}
159+
if (error & HAL_I2C_ERROR_OVR) {
160+
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
161+
}
162+
if (error & HAL_I2C_ERROR_BERR) {
163+
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
164+
error_state = 1;
165+
}
166+
137167
hi2c->ErrorCode = 0;
138168

139169
if (receiving_boot_magic) {
140-
// Truncated bootloader-trigger write; discard it rather than
141-
// let stale reg_index state be mistaken for a completed
142-
// register-map transfer below.
170+
// Truncated bootloader-trigger write; discard it.
143171
receiving_boot_magic = 0;
144172
} else {
145-
Slave_HandleComplete();
173+
Slave_FlushRxScratch();
146174
}
147175

148-
Slave_Start();
149-
176+
need_restart = 1;
150177
}
151178

152179
uint8_t Slave_RegRead(uint8_t addr) { return register_map[addr % REG_MAP_SIZE]; }

0 commit comments

Comments
 (0)