Skip to content

Commit 9db2398

Browse files
projectgusdpgeorge
authored andcommitted
stm32/can: Refactor can.h API to not depend on pyboard can types.
This is necessary for the machine.CAN implementation to use the same low-level functions. Includes some refactoring around FIFO selection as there was a footgun where CAN_FIFO0/1 are 0/1 but FDCAN_RX_FIFO0/1 are not. Added an explicit type for non-hardware-specific FIFO numbering. Also moved responsibility for re-enabling CAN receive interrupts into the higher layer (pyb_can.c layer) after calling can_receive(). Also includes this behaviour change for FDCAN boards: - Fix for boards with FDCAN not updating error status counters (num_error_warning, num_error_passive, num_bus_off). These are now updated the same as on boards with CAN Classic controllers, as documented. - Previously FDCAN boards would trigger the RX callback function on error events instead (passing undocumented irq numbers 3, 4, 5). This behaviour has been removed in favour of the documented behaviour of updating the status counters. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <[email protected]>
1 parent 96ce08e commit 9db2398

File tree

7 files changed

+431
-362
lines changed

7 files changed

+431
-362
lines changed

ports/stm32/can.c

Lines changed: 102 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,15 @@
2828
#include "py/mperrno.h"
2929
#include "py/mphal.h"
3030
#include "can.h"
31+
#include "pyb_can.h"
3132
#include "irq.h"
3233

3334
#if MICROPY_HW_ENABLE_CAN
3435

35-
void can_init0(void) {
36-
for (uint i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
37-
MP_STATE_PORT(pyb_can_obj_all)[i] = NULL;
38-
}
39-
}
40-
41-
void can_deinit_all(void) {
42-
for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
43-
pyb_can_obj_t *can_obj = MP_STATE_PORT(pyb_can_obj_all)[i];
44-
if (can_obj != NULL) {
45-
can_deinit(can_obj);
46-
}
47-
}
48-
}
49-
5036
#if !MICROPY_HW_ENABLE_FDCAN
5137

52-
bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart) {
53-
CAN_InitTypeDef *init = &can_obj->can.Init;
38+
bool can_init(CAN_HandleTypeDef *can, int can_id, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart) {
39+
CAN_InitTypeDef *init = &can->Init;
5440
init->Mode = mode << 4; // shift-left so modes fit in a small-int
5541
init->Prescaler = prescaler;
5642
init->SJW = ((sjw - 1) & 3) << 24;
@@ -67,7 +53,7 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_
6753
uint32_t sce_irq = 0;
6854
const machine_pin_obj_t *pins[2];
6955

70-
switch (can_obj->can_id) {
56+
switch (can_id) {
7157
#if defined(MICROPY_HW_CAN1_TX)
7258
case PYB_CAN_1:
7359
CANx = CAN1;
@@ -107,40 +93,34 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_
10793
uint32_t pin_mode = MP_HAL_PIN_MODE_ALT;
10894
uint32_t pin_pull = MP_HAL_PIN_PULL_UP;
10995
for (int i = 0; i < 2; i++) {
110-
if (!mp_hal_pin_config_alt(pins[i], pin_mode, pin_pull, AF_FN_CAN, can_obj->can_id)) {
96+
if (!mp_hal_pin_config_alt(pins[i], pin_mode, pin_pull, AF_FN_CAN, can_id)) {
11197
return false;
11298
}
11399
}
114100

115101
// init CANx
116-
can_obj->can.Instance = CANx;
117-
HAL_CAN_Init(&can_obj->can);
102+
can->Instance = CANx;
103+
HAL_CAN_Init(can);
118104

119-
can_obj->is_enabled = true;
120-
can_obj->num_error_warning = 0;
121-
can_obj->num_error_passive = 0;
122-
can_obj->num_bus_off = 0;
123-
124-
__HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG);
105+
__HAL_CAN_ENABLE_IT(can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG);
125106

126107
NVIC_SetPriority(sce_irq, IRQ_PRI_CAN);
127108
HAL_NVIC_EnableIRQ(sce_irq);
128109

129110
return true;
130111
}
131112

132-
void can_deinit(pyb_can_obj_t *self) {
133-
self->is_enabled = false;
134-
HAL_CAN_DeInit(&self->can);
135-
if (self->can.Instance == CAN1) {
113+
void can_deinit(CAN_HandleTypeDef *can) {
114+
HAL_CAN_DeInit(can);
115+
if (can->Instance == CAN1) {
136116
HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
137117
HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
138118
HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn);
139119
__HAL_RCC_CAN1_FORCE_RESET();
140120
__HAL_RCC_CAN1_RELEASE_RESET();
141121
__HAL_RCC_CAN1_CLK_DISABLE();
142122
#if defined(CAN2)
143-
} else if (self->can.Instance == CAN2) {
123+
} else if (can->Instance == CAN2) {
144124
HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
145125
HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
146126
HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn);
@@ -149,7 +129,7 @@ void can_deinit(pyb_can_obj_t *self) {
149129
__HAL_RCC_CAN2_CLK_DISABLE();
150130
#endif
151131
#if defined(CAN3)
152-
} else if (self->can.Instance == CAN3) {
132+
} else if (can->Instance == CAN3) {
153133
HAL_NVIC_DisableIRQ(CAN3_RX0_IRQn);
154134
HAL_NVIC_DisableIRQ(CAN3_RX1_IRQn);
155135
HAL_NVIC_DisableIRQ(CAN3_SCE_IRQn);
@@ -160,26 +140,38 @@ void can_deinit(pyb_can_obj_t *self) {
160140
}
161141
}
162142

163-
void can_clearfilter(pyb_can_obj_t *self, uint32_t f, uint8_t bank) {
143+
void can_disable_rx_interrupts(CAN_HandleTypeDef *can, can_rx_fifo_t fifo) {
144+
__HAL_CAN_DISABLE_IT(can, ((fifo == CAN_RX_FIFO0) ?
145+
(CAN_IT_FMP0 | CAN_IT_FF0 | CAN_IT_FOV0) :
146+
(CAN_IT_FMP1 | CAN_IT_FF1 | CAN_IT_FOV1)));
147+
}
148+
149+
void can_enable_rx_interrupts(CAN_HandleTypeDef *can, can_rx_fifo_t fifo, bool enable_msg_received) {
150+
__HAL_CAN_ENABLE_IT(can, ((fifo == CAN_RX_FIFO0) ?
151+
((enable_msg_received ? CAN_IT_FMP0 : 0) | CAN_IT_FF0 | CAN_IT_FOV0) :
152+
((enable_msg_received ? CAN_IT_FMP1 : 0) | CAN_IT_FF1 | CAN_IT_FOV1)));
153+
}
154+
155+
void can_clearfilter(CAN_HandleTypeDef *can, uint32_t filter_num, uint8_t bank) {
164156
CAN_FilterConfTypeDef filter;
165157

166158
filter.FilterIdHigh = 0;
167159
filter.FilterIdLow = 0;
168160
filter.FilterMaskIdHigh = 0;
169161
filter.FilterMaskIdLow = 0;
170162
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
171-
filter.FilterNumber = f;
163+
filter.FilterNumber = filter_num;
172164
filter.FilterMode = CAN_FILTERMODE_IDMASK;
173165
filter.FilterScale = CAN_FILTERSCALE_16BIT;
174166
filter.FilterActivation = DISABLE;
175167
filter.BankNumber = bank;
176168

177-
HAL_CAN_ConfigFilter(&self->can, &filter);
169+
HAL_CAN_ConfigFilter(can, &filter);
178170
}
179171

180-
int can_receive(CAN_HandleTypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint8_t *data, uint32_t timeout_ms) {
172+
int can_receive(CAN_HandleTypeDef *can, can_rx_fifo_t fifo, CanRxMsgTypeDef *msg, uint8_t *data, uint32_t timeout_ms) {
181173
volatile uint32_t *rfr;
182-
if (fifo == CAN_FIFO0) {
174+
if (fifo == CAN_RX_FIFO0) {
183175
rfr = &can->Instance->RF0R;
184176
} else {
185177
rfr = &can->Instance->RF1R;
@@ -222,13 +214,16 @@ int can_receive(CAN_HandleTypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint8_t
222214
return 0; // success
223215
}
224216

225-
// We have our own version of CAN transmit so we can handle Timeout=0 correctly.
226-
HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) {
217+
// Lightly modified version of HAL CAN_Transmit to handle Timeout=0 correctly
218+
HAL_StatusTypeDef can_transmit(CAN_HandleTypeDef *hcan, CanTxMsgTypeDef *txmsg, uint8_t *data, uint32_t Timeout) {
227219
uint32_t transmitmailbox;
228220
uint32_t tickstart;
229221
uint32_t rqcpflag = 0;
230222
uint32_t txokflag = 0;
231223

224+
hcan->pTxMsg = txmsg;
225+
(void)data; // Not needed here, caller has set it up as &tx_msg->Data
226+
232227
// Check the parameters
233228
assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
234229
assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
@@ -312,119 +307,130 @@ HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) {
312307
}
313308
}
314309

315-
static void can_rx_irq_handler(uint can_id, uint fifo_id) {
316-
mp_obj_t callback;
317-
pyb_can_obj_t *self;
318-
mp_obj_t irq_reason = MP_OBJ_NEW_SMALL_INT(0);
319-
byte *state;
320-
321-
self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
322-
323-
if (fifo_id == CAN_FIFO0) {
324-
callback = self->rxcallback0;
325-
state = &self->rx_state0;
310+
// Workaround for the __HAL_CAN macros expecting a CAN_HandleTypeDef which we
311+
// don't have in the ISR. Using this "fake" struct instead of CAN_HandleTypeDef
312+
// so it's not possible to accidentally call an API that uses one of the other
313+
// fields in the structure.
314+
typedef struct {
315+
CAN_TypeDef *Instance;
316+
} fake_handle_t;
317+
318+
static void can_rx_irq_handler(uint can_id, CAN_TypeDef *instance, can_rx_fifo_t fifo) {
319+
uint32_t full_flag, full_int, overrun_flag, overrun_int, pending_int;
320+
321+
const fake_handle_t handle = {
322+
.Instance = instance,
323+
};
324+
325+
if (fifo == CAN_RX_FIFO0) {
326+
full_flag = CAN_FLAG_FF0;
327+
full_int = CAN_IT_FF0;
328+
overrun_flag = CAN_FLAG_FOV0;
329+
overrun_int = CAN_IT_FOV0;
330+
pending_int = CAN_IT_FMP0;
326331
} else {
327-
callback = self->rxcallback1;
328-
state = &self->rx_state1;
332+
full_flag = CAN_FLAG_FF1;
333+
full_int = CAN_IT_FF1;
334+
overrun_flag = CAN_FLAG_FOV1;
335+
overrun_int = CAN_IT_FOV1;
336+
pending_int = CAN_IT_FMP1;
329337
}
330338

331-
switch (*state) {
332-
case RX_STATE_FIFO_EMPTY:
333-
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
334-
irq_reason = MP_OBJ_NEW_SMALL_INT(0);
335-
*state = RX_STATE_MESSAGE_PENDING;
336-
break;
337-
case RX_STATE_MESSAGE_PENDING:
338-
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
339-
__HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1);
340-
irq_reason = MP_OBJ_NEW_SMALL_INT(1);
341-
*state = RX_STATE_FIFO_FULL;
342-
break;
343-
case RX_STATE_FIFO_FULL:
344-
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
345-
__HAL_CAN_CLEAR_FLAG(&self->can, (fifo_id == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1);
346-
irq_reason = MP_OBJ_NEW_SMALL_INT(2);
347-
*state = RX_STATE_FIFO_OVERFLOW;
348-
break;
349-
case RX_STATE_FIFO_OVERFLOW:
350-
// This should never happen
351-
break;
339+
bool full = __HAL_CAN_GET_FLAG(&handle, full_flag);
340+
bool overrun = __HAL_CAN_GET_FLAG(&handle, overrun_flag);
341+
342+
// Note: receive interrupt bits are disabled below, and re-enabled by the
343+
// higher layer after calling can_receive()
344+
345+
if (full) {
346+
__HAL_CAN_DISABLE_IT(&handle, full_int);
347+
__HAL_CAN_CLEAR_FLAG(&handle, full_flag);
348+
if (!overrun) {
349+
can_irq_handler(can_id, CAN_INT_FIFO_FULL, fifo);
350+
}
351+
}
352+
if (overrun) {
353+
__HAL_CAN_DISABLE_IT(&handle, overrun_int);
354+
__HAL_CAN_CLEAR_FLAG(&handle, overrun_flag);
355+
can_irq_handler(can_id, CAN_INT_FIFO_OVERFLOW, fifo);
352356
}
353357

354-
pyb_can_handle_callback(self, fifo_id, callback, irq_reason);
358+
if (!(full || overrun)) {
359+
// Process of elimination, if neither of the above
360+
// FIFO status flags are set then message pending interrupt is what fired.
361+
__HAL_CAN_DISABLE_IT(&handle, pending_int);
362+
can_irq_handler(can_id, CAN_INT_MESSAGE_RECEIVED, fifo);
363+
}
355364
}
356365

357-
static void can_sce_irq_handler(uint can_id) {
358-
pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
359-
if (self) {
360-
self->can.Instance->MSR = CAN_MSR_ERRI;
361-
uint32_t esr = self->can.Instance->ESR;
362-
if (esr & CAN_ESR_BOFF) {
363-
++self->num_bus_off;
364-
} else if (esr & CAN_ESR_EPVF) {
365-
++self->num_error_passive;
366-
} else if (esr & CAN_ESR_EWGF) {
367-
++self->num_error_warning;
368-
}
366+
static void can_sce_irq_handler(uint can_id, CAN_TypeDef *instance) {
367+
instance->MSR = CAN_MSR_ERRI; // Write to clear ERRIE interrupt
368+
uint32_t esr = instance->ESR;
369+
if (esr & CAN_ESR_BOFF) {
370+
can_irq_handler(can_id, CAN_INT_ERR_BUS_OFF, 0);
371+
} else if (esr & CAN_ESR_EPVF) {
372+
can_irq_handler(can_id, CAN_INT_ERR_PASSIVE, 0);
373+
} else if (esr & CAN_ESR_EWGF) {
374+
can_irq_handler(can_id, CAN_INT_ERR_WARNING, 0);
369375
}
370376
}
371377

372378
#if defined(MICROPY_HW_CAN1_TX)
373379
void CAN1_RX0_IRQHandler(void) {
374380
IRQ_ENTER(CAN1_RX0_IRQn);
375-
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
381+
can_rx_irq_handler(PYB_CAN_1, CAN1, CAN_RX_FIFO0);
376382
IRQ_EXIT(CAN1_RX0_IRQn);
377383
}
378384

379385
void CAN1_RX1_IRQHandler(void) {
380386
IRQ_ENTER(CAN1_RX1_IRQn);
381-
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1);
387+
can_rx_irq_handler(PYB_CAN_1, CAN1, CAN_RX_FIFO1);
382388
IRQ_EXIT(CAN1_RX1_IRQn);
383389
}
384390

385391
void CAN1_SCE_IRQHandler(void) {
386392
IRQ_ENTER(CAN1_SCE_IRQn);
387-
can_sce_irq_handler(PYB_CAN_1);
393+
can_sce_irq_handler(PYB_CAN_1, CAN1);
388394
IRQ_EXIT(CAN1_SCE_IRQn);
389395
}
390396
#endif
391397

392398
#if defined(MICROPY_HW_CAN2_TX)
393399
void CAN2_RX0_IRQHandler(void) {
394400
IRQ_ENTER(CAN2_RX0_IRQn);
395-
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
401+
can_rx_irq_handler(PYB_CAN_2, CAN2, CAN_RX_FIFO0);
396402
IRQ_EXIT(CAN2_RX0_IRQn);
397403
}
398404

399405
void CAN2_RX1_IRQHandler(void) {
400406
IRQ_ENTER(CAN2_RX1_IRQn);
401-
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
407+
can_rx_irq_handler(PYB_CAN_2, CAN2, CAN_RX_FIFO1);
402408
IRQ_EXIT(CAN2_RX1_IRQn);
403409
}
404410

405411
void CAN2_SCE_IRQHandler(void) {
406412
IRQ_ENTER(CAN2_SCE_IRQn);
407-
can_sce_irq_handler(PYB_CAN_2);
413+
can_sce_irq_handler(PYB_CAN_2, CAN2);
408414
IRQ_EXIT(CAN2_SCE_IRQn);
409415
}
410416
#endif
411417

412418
#if defined(MICROPY_HW_CAN3_TX)
413419
void CAN3_RX0_IRQHandler(void) {
414420
IRQ_ENTER(CAN3_RX0_IRQn);
415-
can_rx_irq_handler(PYB_CAN_3, CAN_FIFO0);
421+
can_rx_irq_handler(PYB_CAN_3, CAN3, CAN_RX_FIFO0);
416422
IRQ_EXIT(CAN3_RX0_IRQn);
417423
}
418424

419425
void CAN3_RX1_IRQHandler(void) {
420426
IRQ_ENTER(CAN3_RX1_IRQn);
421-
can_rx_irq_handler(PYB_CAN_3, CAN_FIFO1);
427+
can_rx_irq_handler(PYB_CAN_3, CAN3, CAN_RX_FIFO1);
422428
IRQ_EXIT(CAN3_RX1_IRQn);
423429
}
424430

425431
void CAN3_SCE_IRQHandler(void) {
426432
IRQ_ENTER(CAN3_SCE_IRQn);
427-
can_sce_irq_handler(PYB_CAN_3);
433+
can_sce_irq_handler(PYB_CAN_3, CAN3);
428434
IRQ_EXIT(CAN3_SCE_IRQn);
429435
}
430436
#endif

0 commit comments

Comments
 (0)