8000 stm32: Refactor can.h API to not depend on pyboard can types. · micropython/micropython@1344117 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1344117

Browse files
committed
stm32: 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 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 <angus@redyak.com.au>
1 parent 8987b39 commit 1344117

File tree

7 files changed

+427
-361
lines changed

7 files changed

+427
-361
lines changed

ports/stm32/can.c

Lines changed: 99 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;
@@ -219,16 +211,22 @@ int can_receive(CAN_HandleTypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint8_t
219211
// Release (free) message from FIFO
220212
*rfr |= CAN_RF0R_RFOM0;
221213

214+
// Re-enable any interrupts that were disabled in RX IRQ handlers
215+
can_enable_rx_interrupts(can, fifo, can_rx_pending(can, fifo) == 0);
216+
222217
return 0; // success
223218
}
224219

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) {
220+
// Lightly modified version of HAL CAN_Transmit to handle Timeout=0 correctly
221+
HAL_StatusTypeDef can_transmit(CAN_HandleTypeDef *hcan, CanTxMsgTypeDef *txmsg, uint8_t *data, uint32_t Timeout) {
227222
uint32_t transmitmailbox;
228223
uint32_t tickstart;
229224
uint32_t rqcpflag = 0;
230225
uint32_t txokflag = 0;
231226

227+
hcan->pTxMsg = txmsg;
228+
(void)data; // Not needed here, caller has set it up as &tx_msg->Data
229+
232230
// Check the parameters
233231
assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
234232
assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
@@ -312,119 +310,124 @@ HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) {
312310
}
313311
}
314312

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;
313+
static void can_rx_irq_handler(uint can_id, CAN_TypeDef *instance, can_rx_fifo_t fifo) {
314+
uint32_t full_flag, full_int, overrun_flag, overrun_int, pending_int;
315+
__IO uint32_t *fifo_reg;
316+
317+
if (fifo == CAN_RX_FIFO0) {
318+
fifo_reg = &instance->RF0R;
319+
full_flag = CAN_RF0R_FULL0;
320+
full_int = CAN_IER_FFIE0;
321+
overrun_flag = CAN_RF0R_FOVR0;
322+
overrun_int = CAN_IER_FOVIE0;
323+
pending_int = CAN_IER_FMPIE0;
326324
} else {
327-
callback = self->rxcallback1;
328-
state = &self->rx_state1;
325+
fifo_reg = &instance->RF1R;
326+
full_flag = CAN_RF1R_FULL1;
327+
full_int = CAN_IER_FFIE1;
328+
overrun_flag = CAN_RF1R_FOVR1;
329+
overrun_int = CAN_IER_FOVIE1;
330+
pending_int = CAN_IER_FMPIE1;
329331
}
330332

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;
333+
uint32_t fifo_status = *fifo_reg;
334+
335+
bool full = fifo_status & full_flag;
336+
bool overrun = fifo_status & overrun_flag;
337+
338+
// Note: interrupt bits are disabled below, and re-enabled
339+
// in can_receive()
340+
341+
if (full) {
342+
// Note: Can't use __HAL_CAN API here as we only have CAN_TypeDef not CAN_HandleTypeDef
343+
instance->IER &= ~full_int;
344+
*fifo_reg &= ~full_flag;
345+
if (!overrun) {
346+
can_irq_handler(can_id, CAN_INT_FIFO_FULL, fifo);
347+
}
348+
}
349+
if (overrun) {
350+
instance->IER &= ~overrun_int;
351+
*fifo_reg &= ~overrun_flag;
352+
can_irq_handler(can_id, CAN_INT_FIFO_OVERFLOW, fifo);
352353
}
353354

354-
pyb_can_handle_callback(self, fifo_id, callback, irq_reason);
355+
if (!(full || overrun)) {
356+
// Process of elimination, if neither of the above
357+
// FIFO status flags are set then message pending interrupt is what fired.
358+
instance->IER &= ~pending_int;
359+
can_irq_handler(can_id, CAN_INT_MESSAGE_RECEIVED, fifo);
360+
}
355361
}
356362

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-
}
363+
static void can_sce_irq_handler(uint can_id, CAN_TypeDef *instance) {
364+
instance->MSR = CAN_MSR_ERRI; // Write to clear ERRIE interrupt
365+
uint32_t esr = instance->ESR;
366+
if (esr & CAN_ESR_BOFF) {
367+
can_irq_handler(can_id, CAN_INT_ERR_BUS_OFF, 0);
368+
} else if (esr & CAN_ESR_EPVF) {
369+
can_irq_handler(can_id, CAN_INT_ERR_PASSIVE, 0);
370+
} else if (esr & CAN_ESR_EWGF) {
371+
can_irq_handler(can_id, CAN_INT_ERR_WARNING, 0);
369372
}
370373
}
371374

372375
#if defined(MICROPY_HW_CAN1_TX)
373376
void CAN1_RX0_IRQHandler(void) {
374377
IRQ_ENTER(CAN1_RX0_IRQn);
375-
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
378+
can_rx_irq_handler(PYB_CAN_1, CAN1, CAN_RX_FIFO0);
376379
IRQ_EXIT(CAN1_RX0_IRQn);
377380
}
378381

379382
void CAN1_RX1_IRQHandler(void) {
380383
IRQ_ENTER(CAN1_RX1_IRQn);
381-
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1);
384+
can_rx_irq_handler(PYB_CAN_1, CAN1, CAN_RX_FIFO1);
382385
IRQ_EXIT(CAN1_RX1_IRQn);
383386
}
384387

385388
void CAN1_SCE_IRQHandler(void) {
386389
IRQ_ENTER(CAN1_SCE_IRQn);
387-
can_sce_irq_handler(PYB_CAN_1);
390+
can_sce_irq_handler(PYB_CAN_1, CAN1);
388391
IRQ_EXIT(CAN1_SCE_IRQn);
389392
}
390393
#endif
391394

392395
#if defined(MICROPY_HW_CAN2_TX)
393396
void CAN2_RX0_IRQHandler(void) {
394397
IRQ_ENTER(CAN2_RX0_IRQn);
395-
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
398+
can_rx_irq_handler(PYB_CAN_2, CAN2, CAN_RX_FIFO0);
396399
IRQ_EXIT(CAN2_RX0_IRQn);
397400
}
398401

399402
void CAN2_RX1_IRQHandler(void) {
400403
IRQ_ENTER(CAN2_RX1_IRQn);
401-
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
404+
can_rx_irq_handler(PYB_CAN_2, CAN2, CAN_RX_FIFO1);
402405
IRQ_EXIT(CAN2_RX1_IRQn);
403406
}
404407

405408
void CAN2_SCE_IRQHandler(void) {
406409
IRQ_ENTER(CAN2_SCE_IRQn);
407-
can_sce_irq_handler(PYB_CAN_2);
410+
can_sce_irq_handler(PYB_CAN_2, CAN2);
408411
IRQ_EXIT(CAN2_SCE_IRQn);
409412
}
410413
#endif
411414

412415
#if defined(MICROPY_HW_CAN3_TX)
413416
void CAN3_RX0_IRQHandler(void) {
414417
IRQ_ENTER(CAN3_RX0_IRQn);
415-
can_rx_irq_handler(PYB_CAN_3, CAN_FIFO0);
418+
can_rx_irq_handler(PYB_CAN_3, CAN3, CAN_RX_FIFO0);
416419
IRQ_EXIT(CAN3_RX0_IRQn);
417420
}
418421

419422
void CAN3_RX1_IRQHandler(void) {
420423
IRQ_ENTER(CAN3_RX1_IRQn);
421-
can_rx_irq_handler(PYB_CAN_3, CAN_FIFO1);
424+
can_rx_irq_handler(PYB_CAN_3, CAN3, CAN_RX_FIFO1);
422425
IRQ_EXIT(CAN3_RX1_IRQn);
423426
}
424427

425428
void CAN3_SCE_IRQHandler(void) {
426429
IRQ_ENTER(CAN3_SCE_IRQn);
427-
can_sce_irq_handler(PYB_CAN_3);
430+
can_sce_irq_handler(PYB_CAN_3, CAN3);
428431
IRQ_EXIT(CAN3_SCE_IRQn);
429432
}
430433
#endif

0 commit comments

Comments
 (0)
0