diff --git a/platforms/stm32h563/include/fdcan.h b/platforms/stm32h563/include/fdcan.h index d59c37bc..c619f82c 100644 --- a/platforms/stm32h563/include/fdcan.h +++ b/platforms/stm32h563/include/fdcan.h @@ -28,6 +28,8 @@ HAL_StatusTypeDef can_init(can_t *can, FDCAN_HandleTypeDef *hcan); HAL_StatusTypeDef can_send_msg(can_t *can, can_msg_t *msg); HAL_StatusTypeDef can_add_filter_standard(can_t *can, uint16_t can_ids[2]); HAL_StatusTypeDef can_add_filter_extended(can_t *can, uint32_t can_ids[2]); +bool can_is_bus_off(can_t *can); +HAL_StatusTypeDef can_recover_bus_off(can_t *can); // clang-format on #endif // FDCAN_H \ No newline at end of file diff --git a/platforms/stm32h563/src/fdcan.c b/platforms/stm32h563/src/fdcan.c index 2191455e..082528e3 100644 --- a/platforms/stm32h563/src/fdcan.c +++ b/platforms/stm32h563/src/fdcan.c @@ -13,19 +13,31 @@ HAL_StatusTypeDef can_init(can_t *can, FDCAN_HandleTypeDef *hcan) can->extended_filter_index = 0; can->hcan = hcan; - /* Config interrupts */ + /* Config incoming message interrupt. */ HAL_StatusTypeDef status = HAL_FDCAN_ConfigInterruptLines(can->hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, FDCAN_INTERRUPT_LINE0); if (status != HAL_OK) { - printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ConfigInterruptLines() (Status: %d).\n", status); + printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ConfigInterruptLines(can->hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, FDCAN_INTERRUPT_LINE0); (Status: %d).\n", status); return status; } - - /* Activate interrupt notifications */ status = HAL_FDCAN_ActivateNotification(can->hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); if (status != HAL_OK) { - printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ActivateNotification() (Status: %d).\n", status); + printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ActivateNotification(can->hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); (Status: %d).\n", status); + return status; + } + + /* Config BusOff interrupt. */ + status = HAL_FDCAN_ConfigInterruptLines(can->hcan, FDCAN_IT_BUS_OFF, FDCAN_INTERRUPT_LINE1); + if (status != HAL_OK) + { + printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ConfigInterruptLines(can->hcan, FDCAN_IT_BUS_OFF, FDCAN_INTERRUPT_LINE1); (Status: %d).\n", status); + return status; + } + status = HAL_FDCAN_ActivateNotification(can->hcan, FDCAN_IT_BUS_OFF, 1); + if (status != HAL_OK) + { + printf("[fdcan.c/can_init()] ERROR: Failed to run HAL_FDCAN_ActivateNotification(can->hcan, FDCAN_IT_BUS_OFF, 1); (Status: %d).\n", status); return status; } @@ -101,6 +113,36 @@ HAL_StatusTypeDef can_add_filter_extended(can_t *can, uint32_t can_ids[2]) return status; } +/* Returns true if the CAN node is in bus-off state. */ +bool can_is_bus_off(can_t *can) { + FDCAN_ProtocolStatusTypeDef status; + HAL_FDCAN_GetProtocolStatus(can->hcan, &status); + return (bool)status.BusOff; +} + +/* Recovers from bus-off by stopping and restarting the FDCAN peripheral. + Filters survive Stop/Start but notifications do not, so RX FIFO interrupt is re-enabled. */ +HAL_StatusTypeDef can_recover_bus_off(can_t *can) { + HAL_StatusTypeDef status = HAL_FDCAN_Stop(can->hcan); + if (status != HAL_OK) { + printf("[fdcan.c/can_recover_bus_off()] ERROR: HAL_FDCAN_Stop() failed (Status: %d).\n", status); + return status; + } + + status = HAL_FDCAN_Start(can->hcan); + if (status != HAL_OK) { + printf("[fdcan.c/can_recover_bus_off()] ERROR: HAL_FDCAN_Start() failed (Status: %d).\n", status); + return status; + } + + status = HAL_FDCAN_ActivateNotification(can->hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); + if (status != HAL_OK) { + printf("[fdcan.c/can_recover_bus_off()] ERROR: HAL_FDCAN_ActivateNotification() failed (Status: %d).\n", status); + } + + return status; +} + /* Sends a CAN message. */ HAL_StatusTypeDef can_send_msg(can_t *can, can_msg_t *msg) {