diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 484a00f364..e1ce90d60d 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -113,6 +113,28 @@ Methods - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity (TEC overflowed beyond 255). +.. method:: CAN.info([list]) + + Get information about the controller's error states and TX and RX buffers. + If *list* is provided then it should be a list object with at least 8 entries, + which will be filled in with the information. Otherwise a new list will be + created and filled in. In both cases the return value of the method is the + populated list. + + The values in the list are: + + - TEC value + - REC value + - number of times the controller enterted the Error Warning state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Error Passive state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Bus Off state (wrapped + around to 0 after 65535) + - number of pending TX messages + - number of pending RX messages on fifo 0 + - number of pending RX messages on fifo 1 + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 563d15dab3..b1bcd1c3e6 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -89,6 +89,9 @@ typedef struct _pyb_can_obj_t { bool extframe : 1; byte rx_state0; byte rx_state1; + uint16_t num_error_warning; + uint16_t num_error_passive; + uint16_t num_bus_off; CAN_HandleTypeDef can; } pyb_can_obj_t; @@ -103,6 +106,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { uint32_t GPIO_Pin = 0; uint8_t GPIO_AF_CANx = 0; GPIO_TypeDef* GPIO_Port = NULL; + uint32_t sce_irq = 0; switch (can_obj->can_id) { // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 @@ -111,6 +115,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN1; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; + sce_irq = CAN1_SCE_IRQn; __CAN1_CLK_ENABLE(); break; @@ -121,6 +126,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN2; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13; + sce_irq = CAN2_SCE_IRQn; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; @@ -144,6 +150,14 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { HAL_CAN_Init(&can_obj->can); can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); return true; } @@ -459,6 +473,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { if (self->can.Instance == CAN1) { HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn); __CAN1_FORCE_RESET(); __CAN1_RELEASE_RESET(); __CAN1_CLK_DISABLE(); @@ -466,6 +481,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { } else if (self->can.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn); __CAN2_FORCE_RESET(); __CAN2_RELEASE_RESET(); __CAN2_CLK_DISABLE(); @@ -512,6 +528,36 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); +// Get info about error states and TX/RX buffers +STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_list_t *list; + if (n_args == 1) { + list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL)); + } else { + if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_raise_TypeError(NULL); + } + list = MP_OBJ_TO_PTR(args[1]); + if (list->len < 8) { + mp_raise_ValueError(NULL); + } + } + CAN_TypeDef *can = self->can.Instance; + uint32_t esr = can->ESR; + list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); + list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf; + list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); + list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); + list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); + return MP_OBJ_FROM_PTR(list); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -871,6 +917,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -979,6 +1026,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) { } } +void can_sce_irq_handler(uint can_id) { + pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + if (self) { + self->can.Instance->MSR = CAN_MSR_ERRI; + uint32_t esr = self->can.Instance->ESR; + if (esr & CAN_ESR_BOFF) { + ++self->num_bus_off; + } else if (esr & CAN_ESR_EPVF) { + ++self->num_error_passive; + } else if (esr & CAN_ESR_EWGF) { + ++self->num_error_warning; + } + } +} + STATIC const mp_stream_p_t can_stream_p = { //.read = can_read, // is read sensible for CAN? //.write = can_write, // is write sensible for CAN? diff --git a/ports/stm32/can.h b/ports/stm32/can.h index b725b59249..54e7deaa5e 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type; void can_init0(void); void can_deinit(void); void can_rx_irq_handler(uint can_id, uint fifo_id); +void can_sce_irq_handler(uint can_id); #endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0ad71771cb..77cfcc5800 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -749,6 +749,12 @@ void CAN1_RX1_IRQHandler(void) { IRQ_EXIT(CAN1_RX1_IRQn); } +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} + void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -760,6 +766,12 @@ void CAN2_RX1_IRQHandler(void) { can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); IRQ_EXIT(CAN2_RX1_IRQn); } + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} #endif // MICROPY_HW_ENABLE_CAN #if defined(MICROPY_HW_I2C1_SCL)