From da4a67e016b49cc3ea306174cc0dd1c4bebbc65f Mon Sep 17 00:00:00 2001 From: ahoysal Date: Mon, 26 Jan 2026 20:58:15 -0800 Subject: [PATCH 01/17] added id to CAN RX callback --- Lib/Peripherals/CAN/Inc/can.h | 2 +- Lib/Peripherals/CAN/Src/can.c | 2 +- Lib/Peripherals/CAN/Test/can_tests.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index d37d614df..57f5dcd72 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -13,7 +13,7 @@ // RX Callback must perform a deep copy of the data // -typedef void (*CAN_RXCallback)(void *data, uint32_t size); +typedef void (*CAN_RXCallback)(uint32_t id, void *data, uint32_t size); typedef struct { // can baud rate is set by fdcan prescaler and RCC clock configurations FDCAN_GlobalTypeDef *fdcan_instance; // Base address of FDCAN peripheral in memory (FDCAN1, FDCAN2, FDCAN3 macros) diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 1bea5c95a..9663e1a31 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -398,7 +398,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) // stack allocation should be fine? Callback needs to terminate first before stack is popped // should switch this over to malloc at some point to avoid double copies? - handle->rx_callback(rx_data, rx_header.DataLength); + handle->rx_callback(rx_data, rx_header.DataLength, rx_header.Identifier); } /* whoopsie, don't need the rx buffer yet diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 6e436cc46..a3f3c5ffb 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -12,14 +12,14 @@ int can_test_instance(FDCAN_HandleTypeDef fdcan_handle) return 0; } -void can_test_rx_callback2(void *data, uint32_t size) +void can_test_rx_callback2(void *data, uint32_t size, uint32_t id) { LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x\n", size, *(char *)data); // Is within an ISR, so needs to exit quickly return; } -void can_test_rx_callback1(void *data, uint32_t size) +void can_test_rx_callback1(void *data, uint32_t size, uint32_t id) { LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x\n", size, *(char *)data); From 05214b4da8018c9b1b1de846b0e76736a3b56978 Mon Sep 17 00:00:00 2001 From: ahoysal Date: Mon, 26 Jan 2026 21:12:02 -0800 Subject: [PATCH 02/17] Added enum as CAN identifier in RX --- CMakeLists.txt | 6 +++--- Lib/Peripherals/CAN/Inc/can.h | 3 ++- Lib/Peripherals/CAN/Test/can_tests.c | 9 +++++---- Lib/Peripherals/CAN/common.cmake | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb3126aaf..09ef35697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) set(lib_path "Lib") set(platform_path "${lib_path}/Platform") +# FIXME Temporary holdover for CAN messages until URCA is ready for merge +include("${lib_path}/FancyLayers-RENAME/GRCAN/TemporaryHoldover/temp.cmake") + # CMSIS and HAL/LL include("${lib_path}/Vendor/CMSIS_5/cmsis_5.cmake") include("${lib_path}/Vendor/STM32_HAL_LL/cube.cmake") @@ -44,9 +47,6 @@ include("${lib_path}/Peripherals/USART/common.cmake") include("${lib_path}/Peripherals/CAN/common.cmake") include("${lib_path}/FancyLayers-RENAME/ADC/adc.cmake") -# FIXME Temporary holdover for CAN messages until URCA is ready for merge -include("${lib_path}/FancyLayers-RENAME/GRCAN/TemporaryHoldover/temp.cmake") - message( STATUS "Build type: " diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index 57f5dcd72..e87e5e4e0 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -10,10 +10,11 @@ #include "can_platform_deps.h" #include "circularBuffer.h" +#include "GR_OLD_MSG_ID.h" // RX Callback must perform a deep copy of the data // -typedef void (*CAN_RXCallback)(uint32_t id, void *data, uint32_t size); +typedef void (*CAN_RXCallback)(void *data, uint32_t size, GR_OLD_MSG_ID ID); typedef struct { // can baud rate is set by fdcan prescaler and RCC clock configurations FDCAN_GlobalTypeDef *fdcan_instance; // Base address of FDCAN peripheral in memory (FDCAN1, FDCAN2, FDCAN3 macros) diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index a3f3c5ffb..2434c49f6 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -3,6 +3,7 @@ #include #include "can.h" +#include "GR_OLD_MSG_ID.h" // each family has a constant number of CAN peripherals @@ -12,16 +13,16 @@ int can_test_instance(FDCAN_HandleTypeDef fdcan_handle) return 0; } -void can_test_rx_callback2(void *data, uint32_t size, uint32_t id) +void can_test_rx_callback2(void *data, uint32_t size, GR_OLD_MSG_ID id) { - LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x\n", size, *(char *)data); + LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); // Is within an ISR, so needs to exit quickly return; } -void can_test_rx_callback1(void *data, uint32_t size, uint32_t id) +void can_test_rx_callback1(void *data, uint32_t size, GR_OLD_MSG_ID id) { - LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x\n", size, *(char *)data); + LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); // Is within an ISR, so needs to exit quickly return; diff --git a/Lib/Peripherals/CAN/common.cmake b/Lib/Peripherals/CAN/common.cmake index 120a4dcbe..5b56d3bc4 100644 --- a/Lib/Peripherals/CAN/common.cmake +++ b/Lib/Peripherals/CAN/common.cmake @@ -1,6 +1,6 @@ add_library(PERIPHERAL_CAN_LIB INTERFACE) -target_link_libraries(PERIPHERAL_CAN_LIB INTERFACE CircularBuffer_Lib) +target_link_libraries(PERIPHERAL_CAN_LIB INTERFACE CircularBuffer_Lib GR_OLD_CAN_MESSAGES) target_sources(PERIPHERAL_CAN_LIB INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can.c) From 92619658782d668950c2992d509ca47f31ef6fba Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 05:17:08 +0000 Subject: [PATCH 03/17] Automatic CMake Format: Standardized formatting automatically --- Lib/Peripherals/CAN/common.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/Peripherals/CAN/common.cmake b/Lib/Peripherals/CAN/common.cmake index 5b56d3bc4..0f086ecf4 100644 --- a/Lib/Peripherals/CAN/common.cmake +++ b/Lib/Peripherals/CAN/common.cmake @@ -1,6 +1,11 @@ add_library(PERIPHERAL_CAN_LIB INTERFACE) -target_link_libraries(PERIPHERAL_CAN_LIB INTERFACE CircularBuffer_Lib GR_OLD_CAN_MESSAGES) +target_link_libraries( + PERIPHERAL_CAN_LIB + INTERFACE + CircularBuffer_Lib + GR_OLD_CAN_MESSAGES +) target_sources(PERIPHERAL_CAN_LIB INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can.c) From f26d44fd85557718dd1cf19109accbad6d96ed99 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 05:18:10 +0000 Subject: [PATCH 04/17] Automatic Clang-Format: Standardized formatting automatically --- Lib/Peripherals/CAN/Inc/can.h | 2 +- Lib/Peripherals/CAN/Test/can_tests.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index e87e5e4e0..ce726981c 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -8,9 +8,9 @@ #error "Unsupported STM32 Family" #endif +#include "GR_OLD_MSG_ID.h" #include "can_platform_deps.h" #include "circularBuffer.h" -#include "GR_OLD_MSG_ID.h" // RX Callback must perform a deep copy of the data // diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 2434c49f6..6daf57cd1 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -2,8 +2,8 @@ #include -#include "can.h" #include "GR_OLD_MSG_ID.h" +#include "can.h" // each family has a constant number of CAN peripherals From d36a3ba39830135a0db9a6ea19dab07fa039ae27 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:15:20 -0800 Subject: [PATCH 05/17] Changed CAN_RX_Callback to take in ID, data, size --- Lib/Peripherals/CAN/Inc/can.h | 4 ++-- Lib/Peripherals/CAN/Src/can.c | 8 ++++++-- Lib/Peripherals/CAN/Test/can_tests.c | 5 ++--- Lib/Peripherals/CAN/common.cmake | 1 - 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index ce726981c..b0000b555 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -8,13 +8,13 @@ #error "Unsupported STM32 Family" #endif -#include "GR_OLD_MSG_ID.h" #include "can_platform_deps.h" #include "circularBuffer.h" + // RX Callback must perform a deep copy of the data // -typedef void (*CAN_RXCallback)(void *data, uint32_t size, GR_OLD_MSG_ID ID); +typedef void (*CAN_RXCallback)(uint32_t ID, void *data, uint32_t size); typedef struct { // can baud rate is set by fdcan prescaler and RCC clock configurations FDCAN_GlobalTypeDef *fdcan_instance; // Base address of FDCAN peripheral in memory (FDCAN1, FDCAN2, FDCAN3 macros) diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 9663e1a31..0a2545b81 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -389,16 +389,20 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) } // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; - FDCAN_RxHeaderTypeDef rx_header; + + //TODO: Stack allocation may be unsafe uint8_t rx_data[64] = {0}; + //TODO: maybe also use a timer for this? while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); // stack allocation should be fine? Callback needs to terminate first before stack is popped // should switch this over to malloc at some point to avoid double copies? - handle->rx_callback(rx_data, rx_header.DataLength, rx_header.Identifier); + //GR_OLD_NODE_ID sendingID = (rx_header.Identifier & (0xFF << 20)) >> 20; + //GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; + handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); } /* whoopsie, don't need the rx buffer yet diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 6daf57cd1..687ff85f5 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -2,7 +2,6 @@ #include -#include "GR_OLD_MSG_ID.h" #include "can.h" // each family has a constant number of CAN peripherals @@ -13,14 +12,14 @@ int can_test_instance(FDCAN_HandleTypeDef fdcan_handle) return 0; } -void can_test_rx_callback2(void *data, uint32_t size, GR_OLD_MSG_ID id) +void can_test_rx_callback2(uint32_t id, void *data, uint32_t size) { LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); // Is within an ISR, so needs to exit quickly return; } -void can_test_rx_callback1(void *data, uint32_t size, GR_OLD_MSG_ID id) +void can_test_rx_callback1(uint32_t id, void *data, uint32_t size) { LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); diff --git a/Lib/Peripherals/CAN/common.cmake b/Lib/Peripherals/CAN/common.cmake index 0f086ecf4..76e5b0268 100644 --- a/Lib/Peripherals/CAN/common.cmake +++ b/Lib/Peripherals/CAN/common.cmake @@ -4,7 +4,6 @@ target_link_libraries( PERIPHERAL_CAN_LIB INTERFACE CircularBuffer_Lib - GR_OLD_CAN_MESSAGES ) target_sources(PERIPHERAL_CAN_LIB INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can.c) From 9e1af22c4653a50300d15c551d971655b8270876 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 20:17:43 +0000 Subject: [PATCH 06/17] Automatic Clang-Format: Standardized formatting automatically --- Lib/Peripherals/CAN/Inc/can.h | 1 - Lib/Peripherals/CAN/Src/can.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index b0000b555..c20cbedae 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -11,7 +11,6 @@ #include "can_platform_deps.h" #include "circularBuffer.h" - // RX Callback must perform a deep copy of the data // typedef void (*CAN_RXCallback)(uint32_t ID, void *data, uint32_t size); diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 0a2545b81..40cb18602 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -391,17 +391,17 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; FDCAN_RxHeaderTypeDef rx_header; - //TODO: Stack allocation may be unsafe + // TODO: Stack allocation may be unsafe uint8_t rx_data[64] = {0}; - //TODO: maybe also use a timer for this? + // TODO: maybe also use a timer for this? while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); // stack allocation should be fine? Callback needs to terminate first before stack is popped // should switch this over to malloc at some point to avoid double copies? - //GR_OLD_NODE_ID sendingID = (rx_header.Identifier & (0xFF << 20)) >> 20; - //GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; + // GR_OLD_NODE_ID sendingID = (rx_header.Identifier & (0xFF << 20)) >> 20; + // GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); } From 499d15c040daac664b091faf419b98df9066deda Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 20:18:23 +0000 Subject: [PATCH 07/17] Automatic CMake Format: Standardized formatting automatically --- Lib/Peripherals/CAN/common.cmake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Lib/Peripherals/CAN/common.cmake b/Lib/Peripherals/CAN/common.cmake index 76e5b0268..120a4dcbe 100644 --- a/Lib/Peripherals/CAN/common.cmake +++ b/Lib/Peripherals/CAN/common.cmake @@ -1,10 +1,6 @@ add_library(PERIPHERAL_CAN_LIB INTERFACE) -target_link_libraries( - PERIPHERAL_CAN_LIB - INTERFACE - CircularBuffer_Lib -) +target_link_libraries(PERIPHERAL_CAN_LIB INTERFACE CircularBuffer_Lib) target_sources(PERIPHERAL_CAN_LIB INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can.c) From 4337a58b061c41c06f40e6361fb76cc453bd6861 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:34:59 -0800 Subject: [PATCH 08/17] added formatting for uint32_t id in can_tests.c --- Lib/Peripherals/CAN/Test/can_tests.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 687ff85f5..73b7c3a3c 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -3,6 +3,7 @@ #include #include "can.h" +#include // each family has a constant number of CAN peripherals @@ -14,14 +15,14 @@ int can_test_instance(FDCAN_HandleTypeDef fdcan_handle) void can_test_rx_callback2(uint32_t id, void *data, uint32_t size) { - LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); + LOGOMATIC("CAN2 Got data! Size %ld, data[0] = 0x%x, id %" PRIu32 "\n", size, *(char *)data, id); // Is within an ISR, so needs to exit quickly return; } void can_test_rx_callback1(uint32_t id, void *data, uint32_t size) { - LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x, id %u\n", size, *(char *)data, id); + LOGOMATIC("CAN1 Got data! Size %ld, data[0] = 0x%x, id %" PRIu32 "\n", size, *(char *)data, id); // Is within an ISR, so needs to exit quickly return; From 2b004730bd063d4ccd2a04f68ad1df625656936b Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 20:36:07 +0000 Subject: [PATCH 09/17] Automatic Clang-Format: Standardized formatting automatically --- Lib/Peripherals/CAN/Test/can_tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 73b7c3a3c..e4f33000e 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -1,9 +1,9 @@ #include "can_tests.h" +#include #include #include "can.h" -#include // each family has a constant number of CAN peripherals From 98923cf16755e3c3c79d06e93739e32c5ea4c46a Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:01:41 -0800 Subject: [PATCH 10/17] cleand up can.c --- Lib/Peripherals/CAN/Inc/can.h | 2 + Lib/Peripherals/CAN/Src/can.c | 1007 +++++++++++++++++---------------- 2 files changed, 528 insertions(+), 481 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index c20cbedae..8519237b2 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -44,7 +44,9 @@ typedef struct { // for release GPIO_TypeDef *rx_gpio; + uint32_t rx_pin; GPIO_TypeDef *tx_gpio; + uint32_t tx_pin; uint32_t Clock_Source; // state diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 40cb18602..50853b740 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -31,391 +31,365 @@ static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; #define CAT5(a, b,c,d,e) a##b##c##d##e #define ACTIVATE_FDCAN_HELPER(FDCANX, ITY, preirq, subirq) \ - do { \ - HAL_NVIC_SetPriority( CAT4(FDCANX##,_,ITY, _IRQn ) , preirq, subirq ); \ - HAL_NVIC_EnableIRQ( CAT4(FDCANX##,_,ITY, _IRQn ) ); \ - } while(0) + do { \ + HAL_NVIC_SetPriority( CAT4(FDCANX##,_,ITY, _IRQn ) , preirq, subirq ); \ + HAL_NVIC_EnableIRQ( CAT4(FDCANX##,_,ITY, _IRQn ) ); \ + } while(0) #define HAL_NVIC_ACTIVATE_FDCAN(FDCANX, ITY, preirq, subirq) \ do { \ - if (FDCANX == ##FDCAN1 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN1, IT0, preirq, subirq); } \ - else if (FDCANX == FDCAN1 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN1, IT1, preirq, subirq); } \ - else if (FDCANX == FDCAN2 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN2, IT0, preirq, subirq); } \ - else if (FDCANX == FDCAN2 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN2, IT1, preirq, subirq); } \ - else if (FDCANX == FDCAN3 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN3, IT0, preirq, subirq); } \ - else if (FDCANX == FDCAN3 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN3, IT1, preirq, subirq); } \ - else { LOGOMATIC("Unrecognized FDCAN and Interrupt Line combination"); } \ + if (FDCANX == ##FDCAN1 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN1, IT0, preirq, subirq); } \ + else if (FDCANX == FDCAN1 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN1, IT1, preirq, subirq); } \ + else if (FDCANX == FDCAN2 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN2, IT0, preirq, subirq); } \ + else if (FDCANX == FDCAN2 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN2, IT1, preirq, subirq); } \ + else if (FDCANX == FDCAN3 && ITY == 0) { ACTIVATE_FDCAN_HELPER(FDCAN3, IT0, preirq, subirq); } \ + else if (FDCANX == FDCAN3 && ITY == 1) { ACTIVATE_FDCAN_HELPER(FDCAN3, IT1, preirq, subirq); } \ + else { LOGOMATIC("Unrecognized FDCAN and Interrupt Line combination"); } \ } while(0) */ #define GPIOx_CLK_ENABLE(GPIOX) \ - do { \ - if (GPIOX == GPIOA) \ - __HAL_RCC_GPIOA_CLK_ENABLE(); \ - else if (GPIOX == GPIOB) \ - __HAL_RCC_GPIOB_CLK_ENABLE(); \ - else if (GPIOX == GPIOD) \ - __HAL_RCC_GPIOD_CLK_ENABLE(); \ - else \ - LOGOMATIC("BAD FDCAN GPIO Port"); \ - } while (0) + do { \ + if (GPIOX == GPIOA) \ + __HAL_RCC_GPIOA_CLK_ENABLE(); \ + else if (GPIOX == GPIOB) \ + __HAL_RCC_GPIOB_CLK_ENABLE(); \ + else if (GPIOX == GPIOD) \ + __HAL_RCC_GPIOD_CLK_ENABLE(); \ + else \ + LOGOMATIC("BAD FDCAN GPIO Port"); \ + } while (0) #define GPIOx_CLK_DISABLE(GPIOX) \ - do { \ - if (GPIOX == GPIOA) \ - __HAL_RCC_GPIOA_CLK_DISABLE(); \ - else if (GPIOX == GPIOB) \ - __HAL_RCC_GPIOB_CLK_DISABLE(); \ - else if (GPIOX == GPIOD) \ - __HAL_RCC_GPIOD_CLK_DISABLE(); \ - else \ - LOGOMATIC("BAD FDCAN GPIO Port"); \ - } while (0) + do { \ + if (GPIOX == GPIOA) \ + __HAL_RCC_GPIOA_CLK_DISABLE(); \ + else if (GPIOX == GPIOB) \ + __HAL_RCC_GPIOB_CLK_DISABLE(); \ + else if (GPIOX == GPIOD) \ + __HAL_RCC_GPIOD_CLK_DISABLE(); \ + else \ + LOGOMATIC("BAD FDCAN GPIO Port"); \ + } while (0) -static int fdcan_shared_clock_ref = 0; -static inline void fdcan_enable_shared_clock(void) -{ - uint32_t primask = __get_PRIMASK(); - __disable_irq(); - - if (fdcan_shared_clock_ref == 0) { - __HAL_RCC_FDCAN_CLK_ENABLE(); - } - fdcan_shared_clock_ref++; - __set_PRIMASK(primask); -} -static inline void fdcan_disable_shared_clock(void) -{ - uint32_t primask = __get_PRIMASK(); - __disable_irq(); - - if (fdcan_shared_clock_ref > 0) { - fdcan_shared_clock_ref--; - if (fdcan_shared_clock_ref == 0) { - __HAL_RCC_FDCAN_CLK_DISABLE(); - } - } - __set_PRIMASK(primask); -} - -static inline void gpio_clk_enable(GPIO_TypeDef *gpio) -{ - if (gpio == GPIOA) { - __HAL_RCC_GPIOA_CLK_ENABLE(); - } else if (gpio == GPIOB) { - __HAL_RCC_GPIOB_CLK_ENABLE(); - } else if (gpio == GPIOD) { - __HAL_RCC_GPIOD_CLK_ENABLE(); - } -} +//TODO: Modify helpers to work across families +//helpers ================= +static int fdcan_shared_clock_ref = 0; +static inline void fdcan_enable_shared_clock(void); +static inline void fdcan_disable_shared_clock(void); +static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan); +static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1); +inline void can_set_clksource(uint32_t clksource) { LL_RCC_SetFDCANClockSource(clksource); } +// static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) +//static inline void gpio_clk_enable(GPIO_TypeDef *gpio) +//static inline void gpio_clk_disable(GPIO_TypeDef *gpio) -static inline void gpio_clk_disable(GPIO_TypeDef *gpio) -{ - if (gpio == GPIOA) { - __HAL_RCC_GPIOA_CLK_DISABLE(); - } else if (gpio == GPIOB) { - __HAL_RCC_GPIOB_CLK_DISABLE(); - } else if (gpio == GPIOD) { - __HAL_RCC_GPIOD_CLK_DISABLE(); - } -} +static int can_msp_init(CANHandle *canHandle, CANConfig *config); +static int can_msp_deinit(CANHandle* canHandle); +static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan); -static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1); -static int can_msp_init(CANHandle *handle, CANConfig *config); +//================================================= API ======================================== CANHandle *can_init(const CANConfig *config) { - // config validation? - // assert(config != 0) - - // #ifdef STM32G474xx - CANHandle *canHandle = 0; - // #ifdef USECAN1 - if (config->fdcan_instance == FDCAN1) { - if (CAN1.init) { - LOGOMATIC("CAN: CAN1 is already initialized\n"); - return 0; - } else { - canHandle = &CAN1; - } - } - // #endif - // #ifdef USECAN2 - else if (config->fdcan_instance == FDCAN2) { - if (CAN2.init) { - LOGOMATIC("CAN: CAN2 is already initialized\n"); - return 0; - } else { - canHandle = &CAN2; - } - } - // #ifdef USECAN3 - else if (config->fdcan_instance == FDCAN3) { - if (CAN3.init) { - LOGOMATIC("CAN: CAN3 is already initialized\n"); - return 0; - } else { - canHandle = &CAN3; - } - } - // #endif - // #elif defined(STM32L476xx) - // #else - // #error "Unsupported STM32 family" - // #endif - else { - LOGOMATIC("CAN: Unrecognized FDCAN instance"); - return 0; - } - canHandle->init = false; - canHandle->started = false; - - // Initialize handle - assert(config->hal_fdcan_init.TxFifoQueueMode == FDCAN_TX_FIFO_OPERATION); - - canHandle->hal_fdcanP->Init = config->hal_fdcan_init; // copy FDCAN parameters from user - // canHandle->hal_fdcanP->Instance = config->fdcan_instance //handles initialized with correct base instance addresses - - canHandle->rx_gpio = config->rx_gpio; - canHandle->tx_gpio = config->tx_gpio; - canHandle->rx_callback = config->rx_callback; - canHandle->tx_buffer_length = config->tx_buffer_length; - - // alternately -> have can_msp_init setup state for HAL_FDCAN_MspInit to work correctly - // have can_msp_deinit setup state for HAL_FDCAN_MspDeInit to work correctly - // Then call HAL_FDCAN_Init() and HAL_FDCAN_DeInit() - - // Current idea, redefine HAL_FDCAN_MspInit and MspDeInit do nothing at all, do all the work in can_msp_init() - if (can_msp_init(canHandle, (CANConfig *)config)) { - LOGOMATIC("CAN_init: could not initialize MSP resources"); - can_release(canHandle); - } - - // PROBLEM: HAL_FDCAN_Init expects HAL_FDCAN_MspInit() to be defined - if (HAL_FDCAN_Init(canHandle->hal_fdcanP) != HAL_OK) { - LOGOMATIC("CAN: HAL Could not initialize FDCAN peripheral"); - return NULL; - // Error_Handler(); - } - - // Active FDCAN callbacks - rxcalback uses line0, txcallback uses line1 - // uint32_t rxevents = FDCAN_IT_RX_FIFO0_NEW_MESSAGE; - uint32_t status = 0; - uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL; - status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, rx_events, 0); - status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, rx_events, FDCAN_INTERRUPT_LINE0); - - // uint32_t txevents = FDCAN_IT_TX_COMPLETE; - uint32_t destinations = FDCAN_TX_BUFFER0; - uint32_t tx_events = FDCAN_IT_TX_COMPLETE | FDCAN_IT_TX_FIFO_EMPTY; - status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, tx_events, destinations); - status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, tx_events, FDCAN_INTERRUPT_LINE1); - // Callbacks redefined later - - if (status & HAL_ERROR) { - LOGOMATIC("CAN: Could not activate rx and tx interrupts\n"); - return NULL; - } - - // Circular Buffer - canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); - if (!canHandle->tx_buffer) { - LOGOMATIC("CAN: Could not allocate circular buffer\n"); - return 0; - } - - canHandle->init = true; - canHandle->started = false; - - return canHandle; + // config validation? + // assert(config != 0) + + // #ifdef STM32G474xx + CANHandle *canHandle = 0; + // #ifdef USECAN1 + if (config->fdcan_instance == FDCAN1) { + if (CAN1.init) { + LOGOMATIC("CAN: CAN1 is already initialized\n"); + return 0; + } else { + canHandle = &CAN1; + } + } + // #endif + // #ifdef USECAN2 + else if (config->fdcan_instance == FDCAN2) { + if (CAN2.init) { + LOGOMATIC("CAN: CAN2 is already initialized\n"); + return 0; + } else { + canHandle = &CAN2; + } + } + // #ifdef USECAN3 + else if (config->fdcan_instance == FDCAN3) { + if (CAN3.init) { + LOGOMATIC("CAN: CAN3 is already initialized\n"); + return 0; + } else { + canHandle = &CAN3; + } + } + // #endif + // #elif defined(STM32L476xx) + // #else + // #error "Unsupported STM32 family" + // #endif + else { + LOGOMATIC("CAN: Unrecognized FDCAN instance"); + return 0; + } + canHandle->init = false; + canHandle->started = false; + + // Initialize handle + assert(config->hal_fdcan_init.TxFifoQueueMode == FDCAN_TX_FIFO_OPERATION); + + canHandle->hal_fdcanP->Init = config->hal_fdcan_init; // copy FDCAN parameters from user + // canHandle->hal_fdcanP->Instance = config->fdcan_instance //handles initialized with correct base instance addresses + + canHandle->rx_gpio = config->rx_gpio; + canHandle->tx_gpio = config->tx_gpio; + canHandle->rx_pin = config->init_rx_gpio.Pin; + canHandle->tx_pin = config->init_tx_gpio.Pin; + + canHandle->rx_callback = config->rx_callback; + canHandle->tx_buffer_length = config->tx_buffer_length; + + // alternately -> have can_msp_init setup state for HAL_FDCAN_MspInit to work correctly + // have can_msp_deinit setup state for HAL_FDCAN_MspDeInit to work correctly + // Then call HAL_FDCAN_Init() and HAL_FDCAN_DeInit() + + // Current idea, redefine HAL_FDCAN_MspInit and MspDeInit do nothing at all, do all the work in can_msp_init() + if (can_msp_init(canHandle, (CANConfig *)config)) { + LOGOMATIC("CAN_init: could not initialize MSP resources"); + can_release(canHandle); + } + + // PROBLEM: HAL_FDCAN_Init expects HAL_FDCAN_MspInit() to be defined + if (HAL_FDCAN_Init(canHandle->hal_fdcanP) != HAL_OK) { + LOGOMATIC("CAN: HAL Could not initialize FDCAN peripheral"); + return NULL; + // Error_Handler(); + } + + // Active FDCAN callbacks - rxcalback uses line0, txcallback uses line1 + // uint32_t rxevents = FDCAN_IT_RX_FIFO0_NEW_MESSAGE; + uint32_t status = 0; + uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL; + status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, rx_events, 0); + status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, rx_events, FDCAN_INTERRUPT_LINE0); + + // uint32_t txevents = FDCAN_IT_TX_COMPLETE; + uint32_t destinations = FDCAN_TX_BUFFER0; + uint32_t tx_events = FDCAN_IT_TX_COMPLETE | FDCAN_IT_TX_FIFO_EMPTY; + status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, tx_events, destinations); + status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, tx_events, FDCAN_INTERRUPT_LINE1); + // Callbacks redefined later + + if (status & HAL_ERROR) { + LOGOMATIC("CAN: Could not activate rx and tx interrupts\n"); + return NULL; + } + + // Circular Buffer + canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); + if (!canHandle->tx_buffer) { + LOGOMATIC("CAN: Could not allocate circular buffer\n"); + return 0; + } + + canHandle->init = true; + canHandle->started = false; + + return canHandle; } -inline void can_set_clksource(uint32_t clksource) { LL_RCC_SetFDCANClockSource(clksource); } -// only valid for #STM32G474x, must redefine for each family -static int can_msp_init(CANHandle *canHandle, CANConfig *config) +int can_release(CANHandle *canHandle) { - // MSP Init ------- This could be inside HAL_FDCAN_MspInit() instead - // FDCAN Clock Select + if (!canHandle) { + LOGOMATIC("CAN: Tried to release a null handle"); + return -1; + } - fdcan_enable_shared_clock(); - // Clock speed for FDCAN determined by APB1 clock speed and FDCAN prescaler + if (!canHandle->init) { + LOGOMATIC("CAN_release: can instance is already deinitialized"); + return -1; + } + can_stop(canHandle); // try to prevent more interrupts from firing - // GPIOs init - GPIOx_CLK_ENABLE(config->rx_gpio); - GPIOx_CLK_ENABLE(config->tx_gpio); + can_msp_deinit(canHandle); - HAL_GPIO_Init(config->rx_gpio, &(config->init_rx_gpio)); - HAL_GPIO_Init(config->tx_gpio, &(config->init_tx_gpio)); + // reset FDCANx instance and message RAM and filters, clear interrupts + // HAL_FDCAN_DeInit(canHandle->hal_fdcanP); resets a little too hard + FDCAN_InstanceDeInit(canHandle->hal_fdcanP); - IRQn_Type rxit = -1; - IRQn_Type txit = -1; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rxit, &txit); + __DSB(); // Data Synchronization Barrier + __ISB(); // Instruction Synchronization Barrier - // rxfifo0 - HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); - HAL_NVIC_EnableIRQ(rxit); + // free circular buffer contents + GR_CircularBuffer_Free(&(canHandle->tx_buffer)); - // tx - HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); - HAL_NVIC_EnableIRQ(txit); - // End MSP Init -------------- + // reset can handle + FDCAN_HandleTypeDef *temp = canHandle->hal_fdcanP; + memset(canHandle, 0, sizeof(*canHandle)); + canHandle->hal_fdcanP = temp; - return 0; + return 0; } - -// valid only for STM32G4 -static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1) +//TODO: ISR DANGER +//TODO: Implement timer +//lock access to Circular Buffer when sending and dequeuing +static void can_tx_dequeue_helper(CANHandle *handle) { - if (instance == FDCAN1) { - *it0 = FDCAN1_IT0_IRQn; - *it1 = FDCAN1_IT1_IRQn; - return 0; - } - if (instance == FDCAN2) { - *it0 = FDCAN2_IT0_IRQn; - *it1 = FDCAN2_IT1_IRQn; - return 0; - } - if (instance == FDCAN3) { - *it0 = FDCAN3_IT0_IRQn; - *it1 = FDCAN3_IT1_IRQn; - return 0; - } - - return -1; // invalid instance -} + if (!handle || !handle->tx_buffer) { + LOGOMATIC("can_tx_buffer_helper: handle is invalid"); + return; + } -// valid only for STM32G4 -// static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) -// { -// if (instance == FDCAN1) { -// return "FDCAN1"; -// } else if (instance == FDCAN2) { -// return "FDCAN2"; -// } else if (instance == FDCAN3) { -// return "FDCAN3"; -// } -// return "UNKNOWN"; -// } + if (GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { + return; + } -// valid only for STM32G4 -static CANHandle *can_get_buffer_handle(FDCAN_HandleTypeDef *hfdcan) -{ - // #ifdef STM32G474xx - if (hfdcan->Instance == FDCAN1) { - return &CAN1; - } else if (hfdcan->Instance == FDCAN2) { - return &CAN2; - } else if (hfdcan->Instance == FDCAN3) { - return &CAN3; - } else { - LOGOMATIC("CAN_get_buffer_handle: was given invalid FDCAN instance\n"); - return 0; - } -} + uint32_t primask = __get_PRIMASK(); + __disable_irq(); + if (!GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { -static void can_tx_buffer_helper(CANHandle *handle) -{ - while (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP) && !GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { - FDCANTxMessage *msg = GR_CircularBuffer_Pop(handle->tx_buffer); + //Can Add to Fifo Q + if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { - if (!msg) { - break; - } + //lock the Circular Buffer + FDCANTxMessage *msg = GR_CircularBuffer_Pop(handle->tx_buffer); + if (!msg) { + return ; + } - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); + //should call Tx Buffer Callback once complete + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); - if (status != HAL_OK) { - LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); - free(msg); // Free the message we couldn't send - break; // Stop trying to send more - } + if (status != HAL_OK) { + LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); + //free(msg); // Free the message we couldn't send + return; // Stop trying to send more + } + free(msg); // Successfully sent, free the memory - free(msg); // Successfully sent, free the memory - } -} + } else { //try again later with a timer /? -void FDCAN1_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } -void FDCAN1_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } + } + } -void FDCAN2_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } -void FDCAN2_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } + __set_PRIMASK(primask); +} + +//Use to directly send +int can_send(CANHandle *canHandle, FDCANTxMessage *message) +{ + if (!canHandle || !message) { + LOGOMATIC("CAN_send: received null pointer\n"); + return -1; + } + + if (!canHandle->init || !canHandle->started) { + LOGOMATIC("CAN_send: CAN not initialized or started\n"); + return -1; + } + + uint32_t primask = __get_PRIMASK(); + __disable_irq(); + // IF TX Fifos are not full, send directly to them + // If TX Fifos are full, append to circular buffer + // If circular buffer is full, return an error code + uint32_t free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP); + + if (free > 0) { + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), + message->data // Not &message->data if data is array + ); + + __set_PRIMASK(primask); + + if (status != HAL_OK) { + LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); + return -1; + } + return 0; + } + + // Hardware FIFO full, try software buffer + if (!GR_CircularBuffer_IsFull(canHandle->tx_buffer)) { + int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); + + __set_PRIMASK(primask); + + if (result != 0) { + LOGOMATIC("CAN_send: buffer push failed\n"); + return -1; + } + return 0; + } + + // Both buffers full + __set_PRIMASK(primask); + LOGOMATIC("CAN_send: all buffers full\n"); + return -1; +} -void FDCAN3_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } -void FDCAN3_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes) { - UNUSED(BufferIndexes); - // If circular buffer has elements, send to queue - // Otherwise do nothing - // #ifdef USECAN1 - CANHandle *handle = can_get_buffer_handle(hfdcan); - - if (!handle || !handle->tx_buffer) { - return; - } - - if (GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { - return; - } - - // see if you can pop any more from the buffer - can_tx_buffer_helper(handle); + UNUSED(BufferIndexes); + // If circular buffer has elements, send to queue + // Otherwise do nothing + // #ifdef USECAN1 + CANHandle *handle = can_get_handle(hfdcan); + // see if you can pop any more from the buffer + can_tx_dequeue_helper(handle); } void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { - CANHandle *handle = can_get_buffer_handle(hfdcan); - - if (!handle || !handle->init || !handle->rx_callback) { - return; - } - - /*if (!handle->rx_buffer) { - LOGOMATIC("CAN: RX Complete, but %s Buffer was released\n", can_get_instance_name(hfdcan->Instance)); - return; - } */ // no rx buffer at the moment - - /*if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { - lost_rx++; - }*/ - - if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { - return; - } - - // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; - FDCAN_RxHeaderTypeDef rx_header; - - // TODO: Stack allocation may be unsafe - uint8_t rx_data[64] = {0}; - - // TODO: maybe also use a timer for this? - while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { - HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - - // stack allocation should be fine? Callback needs to terminate first before stack is popped - // should switch this over to malloc at some point to avoid double copies? - // GR_OLD_NODE_ID sendingID = (rx_header.Identifier & (0xFF << 20)) >> 20; - // GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; - handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); - } - - /* whoopsie, don't need the rx buffer yet - while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) & !GR_CircularBuffer_IsFull(handle->rx_buffer)) { - FDCAN_RxHeaderTypeDef rx_header; - uint8_t rx_data[64] = {0}; - HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, &rx_data); - - if (GR_CircularBuffer_IsEmpty(handle->rx_buffer)) handle->rx_callback(rx_data, rx_header.DataLength); - else { - GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); - } - }*/ + CANHandle *handle = can_get_handle(hfdcan); + + if (!handle || !handle->init || !handle->rx_callback) { + return; + } + + /*if (!handle->rx_buffer) { + LOGOMATIC("CAN: RX Complete, but %s Buffer was released\n", can_get_instance_name(hfdcan->Instance)); + return; + } */ // no rx buffer at the moment + + /*if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { + lost_rx++; + }*/ + + if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { + return; + } + + // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[64] = {0}; + + //if goign to declare on stack, might as well + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { + HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); + + // stack allocation should be fine? Callback needs to terminate first before stack is popped + // should switch this over to malloc at some point to avoid double copies? + handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); + } + + /* whoopsie, don't need the rx buffer yet + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) & !GR_CircularBuffer_IsFull(handle->rx_buffer)) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[64] = {0}; + HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, &rx_data); + + if (GR_CircularBuffer_IsEmpty(handle->rx_buffer)) handle->rx_callback(rx_data, rx_header.DataLength); + else { + GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); + } + }*/ } /* @@ -433,189 +407,260 @@ void can_read_rx_buffer(CANHandle* canHandle) { // Just alternatively just use the HAL_FDCAN_ConfigFilter directly with the canHandle->hal_fdcan int can_add_filter(CANHandle *canHandle, FDCAN_FilterTypeDef *filter) { - if (!canHandle) { - LOGOMATIC("CAN_add_filter: handle is null"); - return -1; - } - - if (!canHandle->init || canHandle->started) { - LOGOMATIC("CAN_add_filter: can instance is not initialized or already started"); - return -1; - } - - if (HAL_FDCAN_ConfigFilter(canHandle->hal_fdcanP, filter) != HAL_OK) { - LOGOMATIC("CAN_add_filter: failed to configure filter"); - return -1; - } - return 0; - // check that # of filters isn't exceeding max value + if (!canHandle) { + LOGOMATIC("CAN_add_filter: handle is null"); + return -1; + } + + if (!canHandle->init || canHandle->started) { + LOGOMATIC("CAN_add_filter: can instance is not initialized or already started"); + return -1; + } + + if (HAL_FDCAN_ConfigFilter(canHandle->hal_fdcanP, filter) != HAL_OK) { + LOGOMATIC("CAN_add_filter: failed to configure filter"); + return -1; + } + return 0; + // check that # of filters isn't exceeding max value } -// Need to int can_start(CANHandle *canHandle) { - if (!canHandle || !canHandle->init) { - return -1; - } + if (!canHandle || !canHandle->init) { + return -1; + } - GPIOx_CLK_ENABLE(canHandle->rx_gpio); - GPIOx_CLK_ENABLE(canHandle->tx_gpio); + GPIOx_CLK_ENABLE(canHandle->rx_gpio); + GPIOx_CLK_ENABLE(canHandle->tx_gpio); - HAL_FDCAN_Start(canHandle->hal_fdcanP); - canHandle->started = true; + HAL_FDCAN_Start(canHandle->hal_fdcanP); + canHandle->started = true; - return 0; + return 0; } int can_stop(CANHandle *canHandle) { - if (!canHandle || !canHandle->init) { - return -1; - } - if (!canHandle->started) { - return 0; - } + if (!canHandle || !canHandle->init) { + return -1; + } + if (!canHandle->started) { + return 0; + } - HAL_FDCAN_Stop(canHandle->hal_fdcanP); + HAL_FDCAN_Stop(canHandle->hal_fdcanP); - GPIOx_CLK_DISABLE(canHandle->rx_gpio); - GPIOx_CLK_DISABLE(canHandle->tx_gpio); + GPIOx_CLK_DISABLE(canHandle->rx_gpio); + GPIOx_CLK_DISABLE(canHandle->tx_gpio); - canHandle->started = false; + canHandle->started = false; - return 0; + return 0; } -// Valid only for STM32G474xE -/*int can_msp_deinit(CANHandle* canHandle) { - //MSP DeInit - //turn off gpio clocks - can only turn off GPIOs if no other instances are using them - return 0; -}*/ + // ==================================== HELPER FUNCTIONS =============================================== +//TODO: Abstract across families +static inline void fdcan_enable_shared_clock(void) +{ + uint32_t primask = __get_PRIMASK(); + __disable_irq(); -static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) + if (fdcan_shared_clock_ref == 0) { + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + fdcan_shared_clock_ref++; + + __set_PRIMASK(primask); +} + +static inline void fdcan_disable_shared_clock(void) { - // Enter INIT mode - hfdcan->Instance->CCCR |= FDCAN_CCCR_INIT; - while (!(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT)) - ; + uint32_t primask = __get_PRIMASK(); + __disable_irq(); + + if (fdcan_shared_clock_ref > 0) { + fdcan_shared_clock_ref--; + if (fdcan_shared_clock_ref == 0) { + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + } + __set_PRIMASK(primask); +} - // Clear filters - // TODO: fix magic numbers - memset((void *)hfdcan->msgRam.StandardFilterSA, 0, 0x0070); - memset((void *)hfdcan->msgRam.ExtendedFilterSA, 0, 0x0050); +// valid only for STM32G4 +static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1) +{ + if (instance == FDCAN1) { + *it0 = FDCAN1_IT0_IRQn; + *it1 = FDCAN1_IT1_IRQn; + return 0; + } + if (instance == FDCAN2) { + *it0 = FDCAN2_IT0_IRQn; + *it1 = FDCAN2_IT1_IRQn; + return 0; + } + if (instance == FDCAN3) { + *it0 = FDCAN3_IT0_IRQn; + *it1 = FDCAN3_IT1_IRQn; + return 0; + } + + return -1; // invalid instance +} - // Optionally reset FIFOs / buffers - // Disable interrupts - __HAL_FDCAN_DISABLE_IT(hfdcan, FDCAN_IT_LIST_RX_FIFO0 | FDCAN_IT_LIST_RX_FIFO1 | FDCAN_IT_LIST_SMSG | FDCAN_IT_LIST_TX_FIFO_ERROR | FDCAN_IT_LIST_MISC | FDCAN_IT_LIST_BIT_LINE_ERROR | - FDCAN_IT_LIST_PROTOCOL_ERROR); +// valid only for STM32G4 +static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan) +{ + // #ifdef STM32G474xx + if (hfdcan->Instance == FDCAN1) { + return &CAN1; + } else if (hfdcan->Instance == FDCAN2) { + return &CAN2; + } else if (hfdcan->Instance == FDCAN3) { + return &CAN3; + } else { + LOGOMATIC("CAN_get_handle: was given invalid FDCAN instance\n"); + return 0; + } +} - // Exit INIT mode - hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; - while (hfdcan->Instance->CCCR & FDCAN_CCCR_INIT) - ; - // Update handle state - hfdcan->State = HAL_FDCAN_STATE_RESET; +/* +static inline void gpio_clk_enable(GPIO_TypeDef *gpio) +{ + if (gpio == GPIOA) { + __HAL_RCC_GPIOA_CLK_ENABLE(); + } else if (gpio == GPIOB) { + __HAL_RCC_GPIOB_CLK_ENABLE(); + } else if (gpio == GPIOD) { + __HAL_RCC_GPIOD_CLK_ENABLE(); + } } -int can_release(CANHandle *canHandle) +static inline void gpio_clk_disable(GPIO_TypeDef *gpio) { - if (!canHandle) { - LOGOMATIC("CAN: Tried to release a null handle"); - return -1; - } + if (gpio == GPIOA) { + __HAL_RCC_GPIOA_CLK_DISABLE(); + } else if (gpio == GPIOB) { + __HAL_RCC_GPIOB_CLK_DISABLE(); + } else if (gpio == GPIOD) { + __HAL_RCC_GPIOD_CLK_DISABLE(); + } +}*/ + +// only valid for #STM32G474x, must redefine for each family +static int can_msp_init(CANHandle *canHandle, CANConfig *config) +{ + // MSP Init ------- This could be inside HAL_FDCAN_MspInit() instead + // FDCAN Clock Select + + fdcan_enable_shared_clock(); + //__HAL_RCC_FDCAN_CLK_ENABLE(); - if (!canHandle->init) { - LOGOMATIC("CAN_release: can instance is already deinitialized"); - return -1; - } - can_stop(canHandle); // try to prevent more interrupts from firing + // Clock speed for FDCAN determined by APB1 clock speed and FDCAN prescaler - // must disable NVIC IRQs before freeing circular buffer + // GPIOs init + GPIOx_CLK_ENABLE(config->rx_gpio); + GPIOx_CLK_ENABLE(config->tx_gpio); - // turn off NVIC resources - IRQn_Type rx0it = -1; - IRQn_Type txit = -1; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); - HAL_NVIC_DisableIRQ(rx0it); - HAL_NVIC_DisableIRQ(txit); + HAL_GPIO_Init(config->rx_gpio, &(config->init_rx_gpio)); + HAL_GPIO_Init(config->tx_gpio, &(config->init_tx_gpio)); - // need to check if other pins are using before disabling - do this after mvp - // GPIOx_CLK_DISABLE(canHandle->rx_gpio); - // GPIOx_CLK_DISABLE(canHandle->tx_gpio); + IRQn_Type rxit = -1; + IRQn_Type txit = -1; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rxit, &txit); - // reset FDCANx instance and message RAM and filters, clear interrupts - // HAL_FDCAN_DeInit(canHandle->hal_fdcanP); resets a little too hard - FDCAN_InstanceDeInit(canHandle->hal_fdcanP); + // rxfifo0 + HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); + HAL_NVIC_EnableIRQ(rxit); - __DSB(); // Data Synchronization Barrier - __ISB(); // Instruction Synchronization Barrier + // tx + HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); + HAL_NVIC_EnableIRQ(txit); + // End MSP Init -------------- - // free circular buffer contents - GR_CircularBuffer_Free(&(canHandle->tx_buffer)); + return 0; +} + +// Valid only for STM32G474xE +static int can_msp_deinit(CANHandle* canHandle) { + //MSP DeInit + // must disable NVIC IRQs before freeing circular buffer + + //NVIC + IRQn_Type rx0it = -1; + IRQn_Type txit = -1; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + HAL_NVIC_DisableIRQ(rx0it); + HAL_NVIC_DisableIRQ(txit); + + //TODO: turn off gpio clocks if no other peripherals are using them??? Could implement a shared GPIO layer + HAL_GPIO_DeInit(canHandle->rx_gpio, canHandle->rx_pin); + HAL_GPIO_DeInit(canHandle->tx_gpio, canHandle->tx_pin); - // reset can instance - FDCAN_HandleTypeDef *temp = canHandle->hal_fdcanP; - memset(canHandle, 0, sizeof(*canHandle)); - canHandle->hal_fdcanP = temp; + //MSP shared layer for GPIOs - fdcan_disable_shared_clock(); // only turns off clock if no other instances are running. + //RCC + fdcan_disable_shared_clock(); - return 0; + return 0; } -int can_send(CANHandle *canHandle, FDCANTxMessage *message) +static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) { - if (!canHandle || !message) { - LOGOMATIC("CAN_send: received null pointer\n"); - return -1; - } - - if (!canHandle->init || !canHandle->started) { - LOGOMATIC("CAN_send: CAN not initialized or started\n"); - return -1; - } - - uint32_t primask = __get_PRIMASK(); - __disable_irq(); - // IF TX Fifos are not full, send directly to them - // If TX Fifos are full, append to circular buffer - // If circular buffer is full, return an error code - uint32_t free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP); - - if (free > 0) { - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), - message->data // Not &message->data if data is array - ); - - __set_PRIMASK(primask); - - if (status != HAL_OK) { - LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); - return -1; - } - return 0; - } - - // Hardware FIFO full, try software buffer - if (!GR_CircularBuffer_IsFull(canHandle->tx_buffer)) { - int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); - - __set_PRIMASK(primask); - - if (result != 0) { - LOGOMATIC("CAN_send: buffer push failed\n"); - return -1; - } - return 0; - } - - // Both buffers full - __set_PRIMASK(primask); - LOGOMATIC("CAN_send: all buffers full\n"); - return -1; + // Enter INIT mode + hfdcan->Instance->CCCR |= FDCAN_CCCR_INIT; + while (!(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT)) + ; + + // Disable interrupts + __HAL_FDCAN_DISABLE_IT(hfdcan, FDCAN_IT_LIST_RX_FIFO0 | FDCAN_IT_LIST_RX_FIFO1 | FDCAN_IT_LIST_SMSG | FDCAN_IT_LIST_TX_FIFO_ERROR | FDCAN_IT_LIST_MISC | FDCAN_IT_LIST_BIT_LINE_ERROR | + FDCAN_IT_LIST_PROTOCOL_ERROR); + + // Clear filters + // TODO: fix magic numbers + memset((void *)hfdcan->msgRam.StandardFilterSA, 0, 0x0070); + memset((void *)hfdcan->msgRam.ExtendedFilterSA, 0, 0x0050); + + // Optionally clear FIFOs / buffers + + // Exit INIT mode + hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; + while (hfdcan->Instance->CCCR & FDCAN_CCCR_INIT); + + // Update handle state + hfdcan->State = HAL_FDCAN_STATE_RESET; } + + +// valid only for STM32G4 +/*static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) +{ + if (instance == FDCAN1) { + return "FDCAN1"; + } else if (instance == FDCAN2) { + return "FDCAN2"; + } else if (instance == FDCAN3) { + return "FDCAN3"; + } + return "UNKNOWN"; +}*/ + + +// ===================================== HAL Callbacks ================================ + +//TODO: Implement Family Checks +//Probably is safe from races +void FDCAN1_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); HAL_NVIC_ClearPendingIRQ(FDCAN1_IT0_IRQn);} +void FDCAN1_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); HAL_NVIC_ClearPendingIRQ(FDCAN1_IT1_IRQn);} + +void FDCAN2_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); HAL_NVIC_ClearPendingIRQ(FDCAN2_IT0_IRQn);} +void FDCAN2_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); HAL_NVIC_ClearPendingIRQ(FDCAN2_IT1_IRQn);} + +void FDCAN3_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); HAL_NVIC_ClearPendingIRQ(FDCAN3_IT0_IRQn);} +void FDCAN3_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); HAL_NVIC_ClearPendingIRQ(FDCAN3_IT1_IRQn);} From 82e770988e4cdff1d8af2730164ebbfab7338f42 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Thu, 29 Jan 2026 00:47:57 -0800 Subject: [PATCH 11/17] added basepri masking, also tried to prevent spurious NVIC interrupts in can_start and can_stop --- Lib/Peripherals/CAN/Inc/can.h | 3 + Lib/Peripherals/CAN/README.md | 51 +++++---------- Lib/Peripherals/CAN/Src/can.c | 120 ++++++++++++++++++++-------------- 3 files changed, 93 insertions(+), 81 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index 8519237b2..1ce0f19bc 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -42,6 +42,9 @@ typedef struct { CAN_RXCallback rx_callback; + uint32_t rx_interrupt_priority; + uint32_t tx_interrupt_priority; + // for release GPIO_TypeDef *rx_gpio; uint32_t rx_pin; diff --git a/Lib/Peripherals/CAN/README.md b/Lib/Peripherals/CAN/README.md index 012ab1a1a..7f05e8130 100644 --- a/Lib/Peripherals/CAN/README.md +++ b/Lib/Peripherals/CAN/README.md @@ -6,54 +6,42 @@ void can_set_clksource(uint32_t LL_RCC_FDCAN_CLKSOURCE); //ex LL_RCC_FDCAN_CLKSO int can_start(CANHandle*handle); int can_stop(CANHandle*handle); -int can_send(CANHandle*handle, FDCANMessage* buffer, size_t send); +int can_send(CANHandle*handle, FDCANMessage* buffer, size_t send); int can_release(CANHandle* handle); //deinit circular buffer and turn off can peripheral and gpios int can_add_filter(CANHandle* handle, HAL_FDCAN_FilterTypeDef * filter); -int can_add_global_filter(CANHandle* handle, HAL_FDCAN_FilterTypeDef* filter); +int can_add_global_filter(CANHandle* handle, HAL_FDCAN_FilterTypeDef* filter); //alternatively instead use the HAL filter functions -//HAL_FDCAN_ConfigGlobalFilter(canHandle->hal_fdcanP, filterTypeDef) +//HAL_FDCAN_ConfigGlobalFilter(canHandle->hal_fdcanP, filterTypeDef) //HAL_FDCAN_ConfigFilter(ca) If no filters are set, the default behaviour is to accept all standard and extended frames into the RXFIFO0 +CHANGES: +- with a single producer, single consumer tx buffer, can instead use a fixed-size ring buffer instead of the circular buffer +- avoids free issues inside the ISR +- can also use the ISR to drain the tx buffer, can_send only adds to it - - - -PROBLEMS: -Verify ISR safety, no race conditions, atomic read/writes - - Interrupts keep firing while trying to can_release() - - Could try to set the NVIC register to selectively disable interrupts (preferably using a bitmask) -- Need to discuss expected behaviour of API - - particularly can_start, can_stop - - can_release +PROBLEMS: - Freeing within ISRs whenever popping from CircularBuffer (yes its faster, than stack copies, but heap is getting fragmented) -- ISRS might take too long to resolve because popping and freeing circular buffer. +- ISRS might take too long to resolve because popping and freeing circular buffer. - HARDCODE Platform Usage Flag for compiler definitions -- CAN.H expects #STM32G4 to be defined, - - +- CAN.H expects #STM32G4 to be defined, - RX Callback must perform deep copy of data supplied to it - could also malloc, but not safe to do inside ISRs -- - - --Shouldn't disable GPIOs in the MSP layers when releasing, might affect other peripherals - IDEAS for other features: +- - DMA support for copying from circular buffer +- Circular buffer should be fixed size anyways - abstract to different STM families besides STM32G4 - Rx Buffering - TX Buffering policy, do we spread them out over multiple TX buffers -- DMA support for copying from circular buffer, circular buffer could then be stack allocated -- Smaller can headers for tx and rx (right now its just use the TXHeaderTypeDef) +- Smaller can headers for tx and rx (right now its just use the HAL TXHeaderTypeDef) - TX FIFO vs Queue policy (only allow FIFOS) - Add support for RXFifo1 - TESTING- ---------------------------------------------- -USE LOGOMATIC for return status - +USE LOGOMATIC for return status - either returns through semihosting or debug cores LOGOMATIC is defined platform by platform @@ -63,21 +51,18 @@ Testing framework - All tests are run from the top level function in can_test.c - can_test.c should initialize everything properly. -- May have to create platform specific asserts when testing state - use LOGOMATIC to return errors or throw asserts - Platform testing, such as in G4PERTESTING just needs include "can_test.h" and call top level function -in main. +in main. Two approaches: Platform centric - In G4PERTesting, include "can_tests.h" and call the top level function in can_test.c - This approach is better because we can abstract the logging and debug method -Library Centric Testing: -- Test the implementation in each library. - HAL_Rewrite: -- Alternatively, rewrite without using HAL, just use CMSIS definitions. -- PROS: Would look good on your Github. +- Alternatively, rewrite without using HAL, just use CMSIS definitions. +- There isn't actually that much going on underneath HAL, it just looks painful because of CMSIS +- PROS: Would look good on your Github. - CONS: takes too long diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 50853b740..f5382c86b 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -10,19 +10,21 @@ // HAL handles // #ifdef USECAN1 static FDCAN_HandleTypeDef hal_fdcan1 = {.Instance = FDCAN1}; -static CANHandle CAN1 = {.hal_fdcanP = &hal_fdcan1}; +volatile static CANHandle CAN1 = {.hal_fdcanP = &hal_fdcan1}; // #endif // #ifdef USECAN2 static FDCAN_HandleTypeDef hal_fdcan2 = {.Instance = FDCAN2}; -static CANHandle CAN2 = {.hal_fdcanP = &hal_fdcan2}; +volatile static CANHandle CAN2 = {.hal_fdcanP = &hal_fdcan2}; // #endif // #ifdef USECAN3 static FDCAN_HandleTypeDef hal_fdcan3 = {.Instance = FDCAN3}; -static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; +volatile static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; // #endif +#define MIN(A,B) ((A < B) ? A : B) + // macro lore /* #define CAT(a,b) a##b @@ -77,7 +79,7 @@ static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; //TODO: Modify helpers to work across families //helpers ================= -static int fdcan_shared_clock_ref = 0; +volatile static int fdcan_shared_clock_ref = 0; static inline void fdcan_enable_shared_clock(void); static inline void fdcan_disable_shared_clock(void); static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan); @@ -150,6 +152,9 @@ CANHandle *can_init(const CANConfig *config) canHandle->tx_gpio = config->tx_gpio; canHandle->rx_pin = config->init_rx_gpio.Pin; canHandle->tx_pin = config->init_tx_gpio.Pin; + canHandle->rx_interrupt_priority = config->rx_interrupt_priority; + canHandle->tx_interrupt_priority = config->tx_interrupt_priority; + canHandle->rx_callback = config->rx_callback; canHandle->tx_buffer_length = config->tx_buffer_length; @@ -223,8 +228,9 @@ int can_release(CANHandle *canHandle) // HAL_FDCAN_DeInit(canHandle->hal_fdcanP); resets a little too hard FDCAN_InstanceDeInit(canHandle->hal_fdcanP); - __DSB(); // Data Synchronization Barrier - __ISB(); // Instruction Synchronization Barrier + //TODO: Not sure these actually do anything + //__DSB(); // Data Synchronization Barrier + //__ISB(); // Instruction Synchronization Barrier // free circular buffer contents GR_CircularBuffer_Free(&(canHandle->tx_buffer)); @@ -236,7 +242,7 @@ int can_release(CANHandle *canHandle) return 0; } -//TODO: ISR DANGER +//TODO: prevent races conditions on the circular buffer //TODO: Implement timer //lock access to Circular Buffer when sending and dequeuing static void can_tx_dequeue_helper(CANHandle *handle) @@ -250,8 +256,9 @@ static void can_tx_dequeue_helper(CANHandle *handle) return; } - uint32_t primask = __get_PRIMASK(); - __disable_irq(); + //uint32_t primask = __get_PRIMASK(); + //__disable_irq(); + //TODO: No need to lock circular buffer, as this ISR cannot interrupt the thread mode (can_send) if (!GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { //Can Add to Fifo Q @@ -271,17 +278,14 @@ static void can_tx_dequeue_helper(CANHandle *handle) //free(msg); // Free the message we couldn't send return; // Stop trying to send more } - free(msg); // Successfully sent, free the memory + free(msg); // Successfully sent, free the entry in the circular buffer - } else { //try again later with a timer /? + } else { //TODO: call can_tx_dequeue_helper later with a timer? } } - - __set_PRIMASK(primask); } -//Use to directly send int can_send(CANHandle *canHandle, FDCANTxMessage *message) { if (!canHandle || !message) { @@ -294,11 +298,12 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) return -1; } - uint32_t primask = __get_PRIMASK(); - __disable_irq(); // IF TX Fifos are not full, send directly to them // If TX Fifos are full, append to circular buffer // If circular buffer is full, return an error code + uint32_t primask = __get_BASEPRI(); + __set_BASEPRI(canHandle->tx_interrupt_priority); //acquire the lock on the circular buffer + uint32_t free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP); if (free > 0) { @@ -306,8 +311,6 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) message->data // Not &message->data if data is array ); - __set_PRIMASK(primask); - if (status != HAL_OK) { LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); return -1; @@ -315,26 +318,26 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) return 0; } + // Hardware FIFO full, try software buffer if (!GR_CircularBuffer_IsFull(canHandle->tx_buffer)) { int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); - __set_PRIMASK(primask); + __set_BASEPRI(primask); if (result != 0) { LOGOMATIC("CAN_send: buffer push failed\n"); return -1; + } else { + return 0; } - return 0; } - + __set_BASEPRI(primask); // Both buffers full - __set_PRIMASK(primask); LOGOMATIC("CAN_send: all buffers full\n"); return -1; } - void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes) { UNUSED(BufferIndexes); @@ -345,6 +348,7 @@ void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t Bu // see if you can pop any more from the buffer can_tx_dequeue_helper(handle); } + void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { CANHandle *handle = can_get_handle(hfdcan); @@ -358,9 +362,9 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) return; } */ // no rx buffer at the moment - /*if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { - lost_rx++; - }*/ + if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { + //lost_rx++; + } if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { return; @@ -370,7 +374,6 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) FDCAN_RxHeaderTypeDef rx_header; uint8_t rx_data[64] = {0}; - //if goign to declare on stack, might as well while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); @@ -390,6 +393,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); } }*/ + //__set_BASEPRI(prev_priority); } /* @@ -431,12 +435,26 @@ int can_start(CANHandle *canHandle) return -1; } + if (canHandle->started) return 0; + + IRQn_Type rx0it, txit; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + + HAL_NVIC_ClearPendingIRQ(rx0it); //prevent a spurious interrupt + HAL_NVIC_ClearPendingIRQ(txit); + GPIOx_CLK_ENABLE(canHandle->rx_gpio); GPIOx_CLK_ENABLE(canHandle->tx_gpio); HAL_FDCAN_Start(canHandle->hal_fdcanP); + canHandle->started = true; + __set_PRIMASK(1); + HAL_NVIC_EnableIRQ(rx0it); + HAL_NVIC_EnableIRQ(txit); + __set_PRIMASK(0); + return 0; } @@ -445,12 +463,29 @@ int can_stop(CANHandle *canHandle) if (!canHandle || !canHandle->init) { return -1; } + if (!canHandle->started) { return 0; } + //stop can interrupts from activating + __set_PRIMASK(1); + uint32_t prev_priority = __get_BASEPRI(); + __set_PRIMASK(0); + __set_BASEPRI( MIN(canHandle->rx_interrupt_priority, canHandle->tx_interrupt_priority) ); + HAL_FDCAN_Stop(canHandle->hal_fdcanP); + IRQn_Type rx0it, txit; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + + HAL_NVIC_DisableIRQ(rx0it); + HAL_NVIC_DisableIRQ(txit); + HAL_NVIC_ClearPendingIRQ(rx0it); + HAL_NVIC_ClearPendingIRQ(txit); + + __set_BASEPRI(prev_priority); + GPIOx_CLK_DISABLE(canHandle->rx_gpio); GPIOx_CLK_DISABLE(canHandle->tx_gpio); @@ -463,31 +498,23 @@ int can_stop(CANHandle *canHandle) // ==================================== HELPER FUNCTIONS =============================================== //TODO: Abstract across families + static inline void fdcan_enable_shared_clock(void) { - uint32_t primask = __get_PRIMASK(); - __disable_irq(); - if (fdcan_shared_clock_ref == 0) { __HAL_RCC_FDCAN_CLK_ENABLE(); } fdcan_shared_clock_ref++; - - __set_PRIMASK(primask); } static inline void fdcan_disable_shared_clock(void) { - uint32_t primask = __get_PRIMASK(); - __disable_irq(); - if (fdcan_shared_clock_ref > 0) { fdcan_shared_clock_ref--; if (fdcan_shared_clock_ref == 0) { __HAL_RCC_FDCAN_CLK_DISABLE(); } } - __set_PRIMASK(primask); } // valid only for STM32G4 @@ -529,7 +556,6 @@ static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan) } } - /* static inline void gpio_clk_enable(GPIO_TypeDef *gpio) { @@ -560,7 +586,6 @@ static int can_msp_init(CANHandle *canHandle, CANConfig *config) // FDCAN Clock Select fdcan_enable_shared_clock(); - //__HAL_RCC_FDCAN_CLK_ENABLE(); // Clock speed for FDCAN determined by APB1 clock speed and FDCAN prescaler @@ -577,13 +602,13 @@ static int can_msp_init(CANHandle *canHandle, CANConfig *config) // rxfifo0 HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); - HAL_NVIC_EnableIRQ(rxit); // tx HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); - HAL_NVIC_EnableIRQ(txit); // End MSP Init -------------- + //Call can_start() to enable interrupts + return 0; } @@ -604,6 +629,7 @@ static int can_msp_deinit(CANHandle* canHandle) { HAL_GPIO_DeInit(canHandle->tx_gpio, canHandle->tx_pin); //MSP shared layer for GPIOs + //TODO: used to disable GPIOs clocks, but that might affect other peripherals //RCC fdcan_disable_shared_clock(); @@ -651,16 +677,14 @@ static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) return "UNKNOWN"; }*/ - // ===================================== HAL Callbacks ================================ - //TODO: Implement Family Checks //Probably is safe from races -void FDCAN1_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); HAL_NVIC_ClearPendingIRQ(FDCAN1_IT0_IRQn);} -void FDCAN1_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); HAL_NVIC_ClearPendingIRQ(FDCAN1_IT1_IRQn);} +void FDCAN1_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } +void FDCAN1_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } -void FDCAN2_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); HAL_NVIC_ClearPendingIRQ(FDCAN2_IT0_IRQn);} -void FDCAN2_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); HAL_NVIC_ClearPendingIRQ(FDCAN2_IT1_IRQn);} +void FDCAN2_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } +void FDCAN2_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } -void FDCAN3_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); HAL_NVIC_ClearPendingIRQ(FDCAN3_IT0_IRQn);} -void FDCAN3_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); HAL_NVIC_ClearPendingIRQ(FDCAN3_IT1_IRQn);} +void FDCAN3_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } +void FDCAN3_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } From 6d6d9ffa2c73ef46b5f2ff5faa85145a08282ed2 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Thu, 29 Jan 2026 01:12:57 -0800 Subject: [PATCH 12/17] added basepri masking, also tried to prevent spurious NVIC interrupts in can_start and can_stop --- Lib/Peripherals/CAN/Src/can.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index f5382c86b..6c6682fdc 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -301,8 +301,11 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) // IF TX Fifos are not full, send directly to them // If TX Fifos are full, append to circular buffer // If circular buffer is full, return an error code + //stop can interrupts from activating + __set_PRIMASK(1); uint32_t primask = __get_BASEPRI(); - __set_BASEPRI(canHandle->tx_interrupt_priority); //acquire the lock on the circular buffer + __set_PRIMASK(0); + __set_BASEPRI( canHandle->tx_interrupt_priority ); uint32_t free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP); From 18af90b400f838b3734e040e10678bd30ad7b5d8 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Fri, 30 Jan 2026 00:43:45 -0800 Subject: [PATCH 13/17] Refactored to use statically sized spsc buffer --- Lib/Peripherals/CAN/Inc/can.h | 13 ++- Lib/Peripherals/CAN/README.md | 4 + Lib/Peripherals/CAN/Src/can.c | 167 +++++++++++++++++---------- Lib/Peripherals/CAN/Test/can_tests.c | 1 + 4 files changed, 119 insertions(+), 66 deletions(-) diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index 1ce0f19bc..bde1aef50 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -24,7 +24,7 @@ typedef struct { uint32_t tx_interrupt_priority; // Circular Buffer - uint32_t tx_buffer_length; + //uint32_t tx_buffer_capacity; GPIO_TypeDef *rx_gpio; // Instance name, like GPIOA, GPIOB, etc. GPIO_InitTypeDef init_rx_gpio; // GPIO Parameters - set correct Alternate Function, no pullup/pulldown, high/very_high frequency @@ -36,10 +36,15 @@ typedef struct { // FDCAN peripheral for STM32G4 typedef struct { - FDCAN_HandleTypeDef *hal_fdcanP; - CircularBuffer *tx_buffer; - uint32_t tx_buffer_length; + FDCAN_HandleTypeDef *hal_fdcanP; //DO NOT REORDER THIS + //TX buffer + volatile FDCANTxMessage *tx_buffer; + volatile uint32_t tx_capacity; + volatile uint32_t tx_tail; + volatile uint32_t tx_elements; + + //RX Callback CAN_RXCallback rx_callback; uint32_t rx_interrupt_priority; diff --git a/Lib/Peripherals/CAN/README.md b/Lib/Peripherals/CAN/README.md index 7f05e8130..c26bf2f38 100644 --- a/Lib/Peripherals/CAN/README.md +++ b/Lib/Peripherals/CAN/README.md @@ -19,8 +19,12 @@ If no filters are set, the default behaviour is to accept all standard and exten CHANGES: - with a single producer, single consumer tx buffer, can instead use a fixed-size ring buffer instead of the circular buffer +- DMA support for copying from circular buffer +- Timer Support for continously dequeuing, or call can_tx_dequeue_helper after every hardware enqueue - avoids free issues inside the ISR - can also use the ISR to drain the tx buffer, can_send only adds to it +- + PROBLEMS: - Freeing within ISRs whenever popping from CircularBuffer (yes its faster, than stack copies, but heap is getting fragmented) diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 6c6682fdc..f206c25db 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -9,18 +9,24 @@ // HAL handles // #ifdef USECAN1 +#define TX_BUFFER_1_SIZE 10 static FDCAN_HandleTypeDef hal_fdcan1 = {.Instance = FDCAN1}; -volatile static CANHandle CAN1 = {.hal_fdcanP = &hal_fdcan1}; +FDCANTxMessage tx_buffer_1[TX_BUFFER_1_SIZE] = {0}; +static CANHandle CAN1 = {.hal_fdcanP = &hal_fdcan1, .tx_buffer = tx_buffer_1}; // #endif // #ifdef USECAN2 +#define TX_BUFFER_2_SIZE 10 static FDCAN_HandleTypeDef hal_fdcan2 = {.Instance = FDCAN2}; -volatile static CANHandle CAN2 = {.hal_fdcanP = &hal_fdcan2}; +FDCANTxMessage tx_buffer_2[TX_BUFFER_2_SIZE] = {0}; +static CANHandle CAN2 = {.hal_fdcanP = &hal_fdcan2, .tx_buffer = tx_buffer_2}; // #endif // #ifdef USECAN3 +#define TX_BUFFER_3_SIZE 10 static FDCAN_HandleTypeDef hal_fdcan3 = {.Instance = FDCAN3}; -volatile static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; +FDCANTxMessage tx_buffer_3[TX_BUFFER_3_SIZE] = {0}; +static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3, .tx_buffer = tx_buffer_3}; // #endif #define MIN(A,B) ((A < B) ? A : B) @@ -79,7 +85,7 @@ volatile static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3}; //TODO: Modify helpers to work across families //helpers ================= -volatile static int fdcan_shared_clock_ref = 0; +static int fdcan_shared_clock_ref = 0; static inline void fdcan_enable_shared_clock(void); static inline void fdcan_disable_shared_clock(void); static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan); @@ -109,6 +115,8 @@ CANHandle *can_init(const CANConfig *config) return 0; } else { canHandle = &CAN1; + canHandle->tx_capacity = TX_BUFFER_1_SIZE; + } } // #endif @@ -119,6 +127,8 @@ CANHandle *can_init(const CANConfig *config) return 0; } else { canHandle = &CAN2; + canHandle->tx_capacity = TX_BUFFER_2_SIZE; + } } // #ifdef USECAN3 @@ -128,6 +138,7 @@ CANHandle *can_init(const CANConfig *config) return 0; } else { canHandle = &CAN3; + canHandle->tx_capacity = TX_BUFFER_3_SIZE; } } // #endif @@ -155,27 +166,31 @@ CANHandle *can_init(const CANConfig *config) canHandle->rx_interrupt_priority = config->rx_interrupt_priority; canHandle->tx_interrupt_priority = config->tx_interrupt_priority; - canHandle->rx_callback = config->rx_callback; - canHandle->tx_buffer_length = config->tx_buffer_length; + + //tx buffer + //canHandle->tx_capacity = TX_BUFFER_SIZE_1; //dependent on can instance + canHandle->tx_tail = 0; + canHandle->tx_elements = 0; // alternately -> have can_msp_init setup state for HAL_FDCAN_MspInit to work correctly // have can_msp_deinit setup state for HAL_FDCAN_MspDeInit to work correctly // Then call HAL_FDCAN_Init() and HAL_FDCAN_DeInit() // Current idea, redefine HAL_FDCAN_MspInit and MspDeInit do nothing at all, do all the work in can_msp_init() - if (can_msp_init(canHandle, (CANConfig *)config)) { + uint32_t failure = 0; + if ( failure |= (can_msp_init(canHandle, (CANConfig *)config))) { LOGOMATIC("CAN_init: could not initialize MSP resources"); - can_release(canHandle); } // PROBLEM: HAL_FDCAN_Init expects HAL_FDCAN_MspInit() to be defined if (HAL_FDCAN_Init(canHandle->hal_fdcanP) != HAL_OK) { + failure |= HAL_ERROR; LOGOMATIC("CAN: HAL Could not initialize FDCAN peripheral"); - return NULL; // Error_Handler(); } + // Active FDCAN callbacks - rxcalback uses line0, txcallback uses line1 // uint32_t rxevents = FDCAN_IT_RX_FIFO0_NEW_MESSAGE; uint32_t status = 0; @@ -192,23 +207,35 @@ CANHandle *can_init(const CANConfig *config) if (status & HAL_ERROR) { LOGOMATIC("CAN: Could not activate rx and tx interrupts\n"); - return NULL; + failure |= status; } // Circular Buffer - canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); + //canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); + //canHandle->tx_buffer = malloc(sizeof(FDCANTxMessage)*canHandle->tx_buffer_length); if (!canHandle->tx_buffer) { - LOGOMATIC("CAN: Could not allocate circular buffer\n"); + LOGOMATIC("tx_buffer isn't valid?"); + failure |= 1; + } + + if (failure) { + can_msp_deinit(canHandle); + FDCAN_InstanceDeInit(canHandle->hal_fdcanP); + memset(canHandle+sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); //FIXME: Make sure instance is not being overwritten (FDCANx) return 0; } + /*if (!canHandle->tx_buffer) { + LOGOMATIC("CAN: Could not allocate circular buffer\n"); + return 0; + }*/ + canHandle->init = true; canHandle->started = false; return canHandle; } - int can_release(CANHandle *canHandle) { if (!canHandle) { @@ -222,6 +249,8 @@ int can_release(CANHandle *canHandle) } can_stop(canHandle); // try to prevent more interrupts from firing + //No more interrupts should be firing that modify canHandle + can_msp_deinit(canHandle); // reset FDCANx instance and message RAM and filters, clear interrupts @@ -233,12 +262,13 @@ int can_release(CANHandle *canHandle) //__ISB(); // Instruction Synchronization Barrier // free circular buffer contents - GR_CircularBuffer_Free(&(canHandle->tx_buffer)); + //GR_CircularBuffer_Free(&(canHandle->tx_buffer)); + memset(canHandle->tx_buffer, 0, canHandle->tx_capacity*sizeof(FDCANTxMessage)); + canHandle->tx_elements = 0; + canHandle->tx_tail = 0; // reset can handle - FDCAN_HandleTypeDef *temp = canHandle->hal_fdcanP; - memset(canHandle, 0, sizeof(*canHandle)); - canHandle->hal_fdcanP = temp; + memset( (void*)canHandle+sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); return 0; } @@ -252,38 +282,45 @@ static void can_tx_dequeue_helper(CANHandle *handle) return; } - if (GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { + + //TODO: use interrupt masking in case any other ISRs need to lock the circular buffer + uint32_t basepri = __get_BASEPRI(); + + __set_BASEPRI(handle->tx_interrupt_priority); + //single consumer shouldn't affect state of circular buffer too closely + if (handle->tx_elements == 0) { + __set_BASEPRI(basepri); return; } - //uint32_t primask = __get_PRIMASK(); + //uint32_t basepri = __get_basepri(); //__disable_irq(); //TODO: No need to lock circular buffer, as this ISR cannot interrupt the thread mode (can_send) - if (!GR_CircularBuffer_IsEmpty(handle->tx_buffer)) { - //Can Add to Fifo Q - if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { + //Can Add to Fifo Q + if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { + //lock the Circular Buffer + FDCANTxMessage *msg = &handle->tx_buffer[handle->tx_tail]; - //lock the Circular Buffer - FDCANTxMessage *msg = GR_CircularBuffer_Pop(handle->tx_buffer); - if (!msg) { - return ; - } + //should call Tx Buffer Callback once complete + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); - //should call Tx Buffer Callback once complete - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); + if (status != HAL_OK) { + //LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); //FIXME: Logomatic may not work with interrupts disabled + __set_BASEPRI(basepri); + return; // Stop trying to send more + } + //free(msg); // Successfully sent, free the entry in the circular buffer (which is pointed to by tail) + handle->tx_tail = ++handle->tx_tail % handle->tx_capacity; + handle->tx_elements--; - if (status != HAL_OK) { - LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); - //free(msg); // Free the message we couldn't send - return; // Stop trying to send more - } - free(msg); // Successfully sent, free the entry in the circular buffer + } else { //FIXME: call can_tx_dequeue_helper later with a timer, if this gets implemented, need to mask timer interrupts to allow atomic access + + } //alternatively, if fifo is full, tx_dequeue should get called anyways, and we don't need the else statement + + __set_BASEPRI(basepri); - } else { //TODO: call can_tx_dequeue_helper later with a timer? - } - } } int can_send(CANHandle *canHandle, FDCANTxMessage *message) @@ -301,43 +338,47 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) // IF TX Fifos are not full, send directly to them // If TX Fifos are full, append to circular buffer // If circular buffer is full, return an error code - //stop can interrupts from activating - __set_PRIMASK(1); - uint32_t primask = __get_BASEPRI(); - __set_PRIMASK(0); - __set_BASEPRI( canHandle->tx_interrupt_priority ); - uint32_t free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP); + //stop can_tx_dequeue_helper from from interleaving + uint32_t basepri = __get_BASEPRI(); + __set_BASEPRI( canHandle->tx_interrupt_priority ); - if (free > 0) { - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), - message->data // Not &message->data if data is array - ); + if (HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP) > 0) { + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); + uint32_t val = 0; if (status != HAL_OK) { LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); - return -1; + val = -1; + } else { + val = 0; } - return 0; + __set_BASEPRI( basepri ); + return val; } - // Hardware FIFO full, try software buffer - if (!GR_CircularBuffer_IsFull(canHandle->tx_buffer)) { - int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); + if (canHandle->tx_elements < canHandle->tx_capacity) { + //int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); + + uint32_t idx = (canHandle->tx_tail + canHandle->tx_elements) % canHandle->tx_capacity; + canHandle->tx_buffer[idx] = *message; + canHandle->tx_elements++; + //memcpy(&canHandle->tx_buffer[idx], message , sizeof(FDCANTxMessage) ); - __set_BASEPRI(primask); + //__set_BASEPRI(primask); - if (result != 0) { + /*if (result != 0) { LOGOMATIC("CAN_send: buffer push failed\n"); return -1; } else { return 0; - } + }*/ + } else { + LOGOMATIC("CAN_send: all buffers full\n"); } - __set_BASEPRI(primask); + __set_BASEPRI(basepri); // Both buffers full - LOGOMATIC("CAN_send: all buffers full\n"); return -1; } @@ -352,6 +393,12 @@ void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t Bu can_tx_dequeue_helper(handle); } +void HAL_FDCAN_TxFifoEmptyCallback(FDCAN_HandleTypeDef *hfdcan) +{ + CANHandle *handle = can_get_handle(hfdcan); + can_tx_dequeue_helper(handle); +} + void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { CANHandle *handle = can_get_handle(hfdcan); @@ -453,10 +500,8 @@ int can_start(CANHandle *canHandle) canHandle->started = true; - __set_PRIMASK(1); HAL_NVIC_EnableIRQ(rx0it); HAL_NVIC_EnableIRQ(txit); - __set_PRIMASK(0); return 0; } @@ -472,9 +517,7 @@ int can_stop(CANHandle *canHandle) } //stop can interrupts from activating - __set_PRIMASK(1); uint32_t prev_priority = __get_BASEPRI(); - __set_PRIMASK(0); __set_BASEPRI( MIN(canHandle->rx_interrupt_priority, canHandle->tx_interrupt_priority) ); HAL_FDCAN_Stop(canHandle->hal_fdcanP); diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index e4f33000e..c968dbbe9 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -28,6 +28,7 @@ void can_test_rx_callback1(uint32_t id, void *data, uint32_t size) return; } +//TODO: G4 tests are dependent on the System clock configuration int can_test(void) { From ebc37b8cab7f54d94f5d97e20692efda1c519749 Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Tue, 3 Feb 2026 22:57:23 -0800 Subject: [PATCH 14/17] passed human testing --- .vscode/launch.json | 4 ++-- Lib/Peripherals/CAN/Inc/can.h | 22 ++++++++++------- Lib/Peripherals/CAN/README.md | 2 +- Lib/Peripherals/CAN/Src/can.c | 35 ++++++++++++++++------------ Lib/Peripherals/CAN/Test/can_tests.c | 23 +++++++++++------- 5 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index cdb5115c9..2b606146c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -222,7 +222,7 @@ }, { "cwd": "${workspaceFolder}", - "executable": "${command:cmake.buildDirectory}/G4ADCTESTING.elf", + "executable": "${command:cmake.buildDirectory}/G4CANTESTING.elf", "name": "G4CANTESTING", "request": "launch", "type": "cortex-debug", @@ -232,7 +232,7 @@ "target/stm32g4x.cfg" ], "searchDir": [], - "preLaunchTask": "CMake: configure and build G4ADCTESTING", + "preLaunchTask": "CMake: configure and build G4CANTESTING", "showDevDebugOutput": "raw", "svdPath": "${workspaceFolder}/Lib/Platform/STM32G474xE/CompileDependencies/STM32G474.svd", "swoConfig": { diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index bde1aef50..7b7ccb1f6 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -34,6 +34,18 @@ typedef struct { // additional parameters } CANConfig; + +#define FDCAN_MAX_DATA_BYTES 64 +typedef struct { + FDCAN_TxHeaderTypeDef tx_header; + uint8_t data[FDCAN_MAX_DATA_BYTES]; +} FDCANTxMessage; +typedef struct { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t data[FDCAN_MAX_DATA_BYTES]; +} FDCANRxMessage; + + // FDCAN peripheral for STM32G4 typedef struct { FDCAN_HandleTypeDef *hal_fdcanP; //DO NOT REORDER THIS @@ -64,15 +76,7 @@ typedef struct { // error states } CANHandle; -#define FDCAN_MAX_DATA_BYTES 64 -typedef struct { - FDCAN_TxHeaderTypeDef tx_header; - uint8_t data[FDCAN_MAX_DATA_BYTES]; -} FDCANTxMessage; -typedef struct { - FDCAN_RxHeaderTypeDef rx_header; - uint8_t data[FDCAN_MAX_DATA_BYTES]; -} FDCANRxMessage; + CANHandle *can_init(const CANConfig *config); // user must supply an rx callback function int can_start(CANHandle *handle); diff --git a/Lib/Peripherals/CAN/README.md b/Lib/Peripherals/CAN/README.md index c26bf2f38..41ec73f52 100644 --- a/Lib/Peripherals/CAN/README.md +++ b/Lib/Peripherals/CAN/README.md @@ -23,7 +23,7 @@ CHANGES: - Timer Support for continously dequeuing, or call can_tx_dequeue_helper after every hardware enqueue - avoids free issues inside the ISR - can also use the ISR to drain the tx buffer, can_send only adds to it -- + PROBLEMS: diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index f206c25db..1ef7c9015 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -9,21 +9,21 @@ // HAL handles // #ifdef USECAN1 -#define TX_BUFFER_1_SIZE 10 +#define TX_BUFFER_1_SIZE 3 static FDCAN_HandleTypeDef hal_fdcan1 = {.Instance = FDCAN1}; FDCANTxMessage tx_buffer_1[TX_BUFFER_1_SIZE] = {0}; static CANHandle CAN1 = {.hal_fdcanP = &hal_fdcan1, .tx_buffer = tx_buffer_1}; // #endif // #ifdef USECAN2 -#define TX_BUFFER_2_SIZE 10 +#define TX_BUFFER_2_SIZE 3 static FDCAN_HandleTypeDef hal_fdcan2 = {.Instance = FDCAN2}; FDCANTxMessage tx_buffer_2[TX_BUFFER_2_SIZE] = {0}; static CANHandle CAN2 = {.hal_fdcanP = &hal_fdcan2, .tx_buffer = tx_buffer_2}; // #endif // #ifdef USECAN3 -#define TX_BUFFER_3_SIZE 10 +#define TX_BUFFER_3_SIZE 3 static FDCAN_HandleTypeDef hal_fdcan3 = {.Instance = FDCAN3}; FDCANTxMessage tx_buffer_3[TX_BUFFER_3_SIZE] = {0}; static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3, .tx_buffer = tx_buffer_3}; @@ -31,6 +31,8 @@ static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3, .tx_buffer = tx_buffer_3}; #define MIN(A,B) ((A < B) ? A : B) +bool hardwareEnabled = false; + // macro lore /* #define CAT(a,b) a##b @@ -343,19 +345,22 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) uint32_t basepri = __get_BASEPRI(); __set_BASEPRI( canHandle->tx_interrupt_priority ); - if (HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP) > 0) { - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); - - uint32_t val = 0; - if (status != HAL_OK) { - LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); - val = -1; - } else { - val = 0; + //FIXME: get rid of this jank + //if (hardwareEnabled) { + if (HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP) > 0) { + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); + + uint32_t val = 0; + if (status != HAL_OK) { + LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); + val = -1; + } else { + val = 0; + } + __set_BASEPRI( basepri ); + return val; } - __set_BASEPRI( basepri ); - return val; - } + //} // Hardware FIFO full, try software buffer if (canHandle->tx_elements < canHandle->tx_capacity) { diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index c968dbbe9..7df7142b6 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -31,14 +31,13 @@ void can_test_rx_callback1(uint32_t id, void *data, uint32_t size) //TODO: G4 tests are dependent on the System clock configuration int can_test(void) { - CANConfig canCfg; // canCfg.fdcan_instance = FDCAN2; canCfg.hal_fdcan_init.ClockDivider = FDCAN_CLOCK_DIV1; canCfg.hal_fdcan_init.FrameFormat = FDCAN_FRAME_FD_NO_BRS; canCfg.hal_fdcan_init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; - canCfg.hal_fdcan_init.Mode = FDCAN_MODE_NORMAL; + canCfg.hal_fdcan_init.Mode = FDCAN_MODE_INTERNAL_LOOPBACK; canCfg.hal_fdcan_init.AutoRetransmission = ENABLE; canCfg.hal_fdcan_init.TransmitPause = DISABLE; canCfg.hal_fdcan_init.ProtocolException = ENABLE; @@ -54,9 +53,8 @@ int can_test(void) canCfg.hal_fdcan_init.ExtFiltersNbr = 0; canCfg.rx_callback = NULL; // PLEASE SET - canCfg.rx_interrupt_priority = 0; // PLEASE SET - canCfg.tx_interrupt_priority = 0; // PLEASE SET - canCfg.tx_buffer_length = 3; // PLEASE SET + canCfg.rx_interrupt_priority = 5; // PLEASE SET + canCfg.tx_interrupt_priority = 5; // PLEASE SET // canCfg.rx_gpio = GPIOB; // canCfg.init_rx_gpio.Pin = GPIO_PIN_12; @@ -92,14 +90,13 @@ int can_test(void) }; FDCANTxMessage msg; - msg.data[0] = 0x80; memset(&(msg.data), 0, sizeof(msg.data)); + msg.data[0] = 0x80; msg.tx_header = TxHeader; can_set_clksource(LL_RCC_FDCAN_CLKSOURCE_PCLK1); #ifdef FDCAN1 - canCfg.fdcan_instance = FDCAN1; canCfg.rx_gpio = GPIOA; canCfg.init_rx_gpio.Pin = GPIO_PIN_11; @@ -114,11 +111,15 @@ int can_test(void) CANHandle *can1Handle = can_init(&canCfg); HAL_FDCAN_ConfigGlobalFilter(can1Handle->hal_fdcanP, 0, 0, 0, 0); + //can1Handle->tx_buffer[0] = msg; + //can1Handle->tx_buffer[1] = msg; + //can1Handle->tx_buffer[2] = msg; + //can1Handle->tx_elements = 3; + can_start(can1Handle); #endif #ifdef FDCAN2 - canCfg.fdcan_instance = FDCAN2; canCfg.rx_gpio = GPIOB; canCfg.init_rx_gpio.Pin = GPIO_PIN_12; @@ -149,11 +150,15 @@ int can_test(void) // API Testing // can_init(&canCfg); + //can2Handle->tx_buffer[0] = msg; + //can2Handle->tx_buffer[1] = msg; + //can2Handle->tx_buffer[2] = msg; + //can2Handle->tx_elements = 3; + can_start(can2Handle); can_send(can2Handle, &msg); // can_release(can2Handle); - #endif #ifdef FDCAN3 From 7245169d4a3ad2e3b6ad7c79dbb8ba54e1c5d25d Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:55:33 -0800 Subject: [PATCH 15/17] added notes in readme --- Lib/Peripherals/CAN/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Lib/Peripherals/CAN/README.md b/Lib/Peripherals/CAN/README.md index 41ec73f52..4cb128ff5 100644 --- a/Lib/Peripherals/CAN/README.md +++ b/Lib/Peripherals/CAN/README.md @@ -20,23 +20,22 @@ If no filters are set, the default behaviour is to accept all standard and exten CHANGES: - with a single producer, single consumer tx buffer, can instead use a fixed-size ring buffer instead of the circular buffer - DMA support for copying from circular buffer -- Timer Support for continously dequeuing, or call can_tx_dequeue_helper after every hardware enqueue -- avoids free issues inside the ISR -- can also use the ISR to drain the tx buffer, can_send only adds to it +- Timer Support for continously dequeuing between API calls, + - call can_tx_dequeue_helper after every successful hardware enqueue. + - avoids free issues inside the ISR +- Error counter handling, waiting for more stable CAN bus state????? PROBLEMS: -- Freeing within ISRs whenever popping from CircularBuffer (yes its faster, than stack copies, but heap is getting fragmented) - ISRS might take too long to resolve because popping and freeing circular buffer. - - HARDCODE Platform Usage Flag for compiler definitions - CAN.H expects #STM32G4 to be defined, - RX Callback must perform deep copy of data supplied to it - could also malloc, but not safe to do inside ISRs IDEAS for other features: -- - DMA support for copying from circular buffer -- Circular buffer should be fixed size anyways +- +- DMA support for copying 64 bytes from circular buffer - abstract to different STM families besides STM32G4 - Rx Buffering - TX Buffering policy, do we spread them out over multiple TX buffers From 1b2addea8614cd23a6a9a8a5415cfcdc4912a83f Mon Sep 17 00:00:00 2001 From: "vihanjay@gmail.com" <55373538+VihanJ@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:22:38 -0800 Subject: [PATCH 16/17] tried to fix CAN data baud rate in ECU/Core/Src/main.c --- ECU/Core/Src/main.c | 8 ++++---- Lib/Peripherals/CAN/Src/can.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ECU/Core/Src/main.c b/ECU/Core/Src/main.c index cf127901c..708fd6d1d 100644 --- a/ECU/Core/Src/main.c +++ b/ECU/Core/Src/main.c @@ -266,17 +266,17 @@ void CAN_Configure() canCfg.hal_fdcan_init.NominalSyncJumpWidth = 16; canCfg.hal_fdcan_init.NominalTimeSeg1 = 127; // Updated for 170MHz: (1+127+42)*1 = 170 ticks -> 1 Mbps canCfg.hal_fdcan_init.NominalTimeSeg2 = 42; - canCfg.hal_fdcan_init.DataPrescaler = 8; + canCfg.hal_fdcan_init.DataPrescaler = 2; canCfg.hal_fdcan_init.DataSyncJumpWidth = 16; - canCfg.hal_fdcan_init.DataTimeSeg1 = 15; // Updated for 170MHz: (1+15+5)*8 = 168 ticks -> ~5 Mbps - canCfg.hal_fdcan_init.DataTimeSeg2 = 5; + canCfg.hal_fdcan_init.DataTimeSeg1 = 12; // Updated for 170MHz: 170 MHz/((1+12+4)*2) = 5 Mbps + canCfg.hal_fdcan_init.DataTimeSeg2 = 4; canCfg.hal_fdcan_init.StdFiltersNbr = 1; canCfg.hal_fdcan_init.ExtFiltersNbr = 0; canCfg.rx_callback = NULL; canCfg.rx_interrupt_priority = 15; // TODO: Maybe make these not hardcoded canCfg.tx_interrupt_priority = 15; - canCfg.tx_buffer_length = CAN_TX_BUFFER_LENGTH; + //canCfg.tx_buffer_length = CAN_TX_BUFFER_LENGTH; // RX shared settings canCfg.init_rx_gpio.Mode = GPIO_MODE_AF_PP; diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index 8a72e24c0..e20593700 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -265,7 +265,7 @@ int can_release(CANHandle *canHandle) // free circular buffer contents //GR_CircularBuffer_Free(&(canHandle->tx_buffer)); - memset(canHandle->tx_buffer, 0, canHandle->tx_capacity*sizeof(FDCANTxMessage)); + memset( (void*) canHandle->tx_buffer, 0, canHandle->tx_capacity*sizeof(FDCANTxMessage)); canHandle->tx_elements = 0; canHandle->tx_tail = 0; @@ -380,7 +380,7 @@ int can_send(CANHandle *canHandle, FDCANTxMessage *message) return 0; }*/ } else { - LOGOMATIC("CAN_send: all buffers full\n"); + LOGOMATIC("CAN_send: all buffers full\n"); //p } __set_BASEPRI(basepri); // Both buffers full @@ -441,7 +441,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) // GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); } - + /* if (GR_CircularBuffer_IsEmpty(handle->rx_buffer)) handle->rx_callback(rx_data, rx_header.DataLength); else { GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); From 6afe33a605d392a116d598412ea9e731ef0cb8b6 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 03:45:32 +0000 Subject: [PATCH 17/17] Automatic Clang-Format: Standardized formatting automatically --- ECU/Core/Src/main.c | 2 +- Lib/Peripherals/CAN/Inc/can.h | 12 +- Lib/Peripherals/CAN/Src/can.c | 928 ++++++++++++++------------- Lib/Peripherals/CAN/Test/can_tests.c | 2 +- 4 files changed, 476 insertions(+), 468 deletions(-) diff --git a/ECU/Core/Src/main.c b/ECU/Core/Src/main.c index 468f4fe53..c17e9d1d3 100644 --- a/ECU/Core/Src/main.c +++ b/ECU/Core/Src/main.c @@ -280,7 +280,7 @@ void CAN_Configure() canCfg.rx_callback = NULL; canCfg.rx_interrupt_priority = 15; // TODO: Maybe make these not hardcoded canCfg.tx_interrupt_priority = 15; - //canCfg.tx_buffer_length = CAN_TX_BUFFER_LENGTH; + // canCfg.tx_buffer_length = CAN_TX_BUFFER_LENGTH; // RX shared settings canCfg.init_rx_gpio.Mode = GPIO_MODE_AF_PP; diff --git a/Lib/Peripherals/CAN/Inc/can.h b/Lib/Peripherals/CAN/Inc/can.h index 7b7ccb1f6..dbdae9863 100644 --- a/Lib/Peripherals/CAN/Inc/can.h +++ b/Lib/Peripherals/CAN/Inc/can.h @@ -24,7 +24,7 @@ typedef struct { uint32_t tx_interrupt_priority; // Circular Buffer - //uint32_t tx_buffer_capacity; + // uint32_t tx_buffer_capacity; GPIO_TypeDef *rx_gpio; // Instance name, like GPIOA, GPIOB, etc. GPIO_InitTypeDef init_rx_gpio; // GPIO Parameters - set correct Alternate Function, no pullup/pulldown, high/very_high frequency @@ -34,7 +34,6 @@ typedef struct { // additional parameters } CANConfig; - #define FDCAN_MAX_DATA_BYTES 64 typedef struct { FDCAN_TxHeaderTypeDef tx_header; @@ -45,18 +44,17 @@ typedef struct { uint8_t data[FDCAN_MAX_DATA_BYTES]; } FDCANRxMessage; - // FDCAN peripheral for STM32G4 typedef struct { - FDCAN_HandleTypeDef *hal_fdcanP; //DO NOT REORDER THIS + FDCAN_HandleTypeDef *hal_fdcanP; // DO NOT REORDER THIS - //TX buffer + // TX buffer volatile FDCANTxMessage *tx_buffer; volatile uint32_t tx_capacity; volatile uint32_t tx_tail; volatile uint32_t tx_elements; - //RX Callback + // RX Callback CAN_RXCallback rx_callback; uint32_t rx_interrupt_priority; @@ -76,8 +74,6 @@ typedef struct { // error states } CANHandle; - - CANHandle *can_init(const CANConfig *config); // user must supply an rx callback function int can_start(CANHandle *handle); int can_stop(CANHandle *handle); diff --git a/Lib/Peripherals/CAN/Src/can.c b/Lib/Peripherals/CAN/Src/can.c index e20593700..4de7d6c87 100644 --- a/Lib/Peripherals/CAN/Src/can.c +++ b/Lib/Peripherals/CAN/Src/can.c @@ -29,7 +29,7 @@ FDCANTxMessage tx_buffer_3[TX_BUFFER_3_SIZE] = {0}; static CANHandle CAN3 = {.hal_fdcanP = &hal_fdcan3, .tx_buffer = tx_buffer_3}; // #endif -#define MIN(A,B) ((A < B) ? A : B) +#define MIN(A, B) ((A < B) ? A : B) bool hardwareEnabled = false; @@ -42,8 +42,8 @@ bool hardwareEnabled = false; #define ACTIVATE_FDCAN_HELPER(FDCANX, ITY, preirq, subirq) \ do { \ - HAL_NVIC_SetPriority( CAT4(FDCANX##,_,ITY, _IRQn ) , preirq, subirq ); \ - HAL_NVIC_EnableIRQ( CAT4(FDCANX##,_,ITY, _IRQn ) ); \ + HAL_NVIC_SetPriority( CAT4(FDCANX##,_,ITY, _IRQn ) , preirq, subirq ); \ + HAL_NVIC_EnableIRQ( CAT4(FDCANX##,_,ITY, _IRQn ) ); \ } while(0) #define HAL_NVIC_ACTIVATE_FDCAN(FDCANX, ITY, preirq, subirq) \ @@ -60,370 +60,364 @@ bool hardwareEnabled = false; */ #define GPIOx_CLK_ENABLE(GPIOX) \ - do { \ - if (GPIOX == GPIOA) \ - __HAL_RCC_GPIOA_CLK_ENABLE(); \ - else if (GPIOX == GPIOB) \ - __HAL_RCC_GPIOB_CLK_ENABLE(); \ - else if (GPIOX == GPIOD) \ - __HAL_RCC_GPIOD_CLK_ENABLE(); \ - else \ - LOGOMATIC("BAD FDCAN GPIO Port"); \ - } while (0) + do { \ + if (GPIOX == GPIOA) \ + __HAL_RCC_GPIOA_CLK_ENABLE(); \ + else if (GPIOX == GPIOB) \ + __HAL_RCC_GPIOB_CLK_ENABLE(); \ + else if (GPIOX == GPIOD) \ + __HAL_RCC_GPIOD_CLK_ENABLE(); \ + else \ + LOGOMATIC("BAD FDCAN GPIO Port"); \ + } while (0) #define GPIOx_CLK_DISABLE(GPIOX) \ - do { \ - if (GPIOX == GPIOA) \ - __HAL_RCC_GPIOA_CLK_DISABLE(); \ - else if (GPIOX == GPIOB) \ - __HAL_RCC_GPIOB_CLK_DISABLE(); \ - else if (GPIOX == GPIOD) \ - __HAL_RCC_GPIOD_CLK_DISABLE(); \ - else \ - LOGOMATIC("BAD FDCAN GPIO Port"); \ - } while (0) - - - -//TODO: Modify helpers to work across families -//helpers ================= + do { \ + if (GPIOX == GPIOA) \ + __HAL_RCC_GPIOA_CLK_DISABLE(); \ + else if (GPIOX == GPIOB) \ + __HAL_RCC_GPIOB_CLK_DISABLE(); \ + else if (GPIOX == GPIOD) \ + __HAL_RCC_GPIOD_CLK_DISABLE(); \ + else \ + LOGOMATIC("BAD FDCAN GPIO Port"); \ + } while (0) + +// TODO: Modify helpers to work across families +// helpers ================= static int fdcan_shared_clock_ref = 0; static inline void fdcan_enable_shared_clock(void); static inline void fdcan_disable_shared_clock(void); static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan); static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1); -inline void can_set_clksource(uint32_t clksource) { LL_RCC_SetFDCANClockSource(clksource); } +inline void can_set_clksource(uint32_t clksource) +{ + LL_RCC_SetFDCANClockSource(clksource); +} // static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) -//static inline void gpio_clk_enable(GPIO_TypeDef *gpio) -//static inline void gpio_clk_disable(GPIO_TypeDef *gpio) +// static inline void gpio_clk_enable(GPIO_TypeDef *gpio) +// static inline void gpio_clk_disable(GPIO_TypeDef *gpio) static int can_msp_init(CANHandle *canHandle, CANConfig *config); -static int can_msp_deinit(CANHandle* canHandle); +static int can_msp_deinit(CANHandle *canHandle); static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan); - //================================================= API ======================================== CANHandle *can_init(const CANConfig *config) { - // config validation? - // assert(config != 0) - - // #ifdef STM32G474xx - CANHandle *canHandle = 0; - // #ifdef USECAN1 - if (config->fdcan_instance == FDCAN1) { - if (CAN1.init) { - LOGOMATIC("CAN: CAN1 is already initialized\n"); - return 0; - } else { - canHandle = &CAN1; - canHandle->tx_capacity = TX_BUFFER_1_SIZE; - - } - } - // #endif - // #ifdef USECAN2 - else if (config->fdcan_instance == FDCAN2) { - if (CAN2.init) { - LOGOMATIC("CAN: CAN2 is already initialized\n"); - return 0; - } else { - canHandle = &CAN2; - canHandle->tx_capacity = TX_BUFFER_2_SIZE; - - } - } - // #ifdef USECAN3 - else if (config->fdcan_instance == FDCAN3) { - if (CAN3.init) { - LOGOMATIC("CAN: CAN3 is already initialized\n"); - return 0; - } else { - canHandle = &CAN3; - canHandle->tx_capacity = TX_BUFFER_3_SIZE; - } - } - // #endif - // #elif defined(STM32L476xx) - // #else - // #error "Unsupported STM32 family" - // #endif - else { - LOGOMATIC("CAN: Unrecognized FDCAN instance"); - return 0; - } - canHandle->init = false; - canHandle->started = false; - - // Initialize handle - assert(config->hal_fdcan_init.TxFifoQueueMode == FDCAN_TX_FIFO_OPERATION); - - canHandle->hal_fdcanP->Init = config->hal_fdcan_init; // copy FDCAN parameters from user - // canHandle->hal_fdcanP->Instance = config->fdcan_instance //handles initialized with correct base instance addresses - - canHandle->rx_gpio = config->rx_gpio; - canHandle->tx_gpio = config->tx_gpio; - canHandle->rx_pin = config->init_rx_gpio.Pin; - canHandle->tx_pin = config->init_tx_gpio.Pin; - canHandle->rx_interrupt_priority = config->rx_interrupt_priority; - canHandle->tx_interrupt_priority = config->tx_interrupt_priority; + // config validation? + // assert(config != 0) + + // #ifdef STM32G474xx + CANHandle *canHandle = 0; + // #ifdef USECAN1 + if (config->fdcan_instance == FDCAN1) { + if (CAN1.init) { + LOGOMATIC("CAN: CAN1 is already initialized\n"); + return 0; + } else { + canHandle = &CAN1; + canHandle->tx_capacity = TX_BUFFER_1_SIZE; + } + } + // #endif + // #ifdef USECAN2 + else if (config->fdcan_instance == FDCAN2) { + if (CAN2.init) { + LOGOMATIC("CAN: CAN2 is already initialized\n"); + return 0; + } else { + canHandle = &CAN2; + canHandle->tx_capacity = TX_BUFFER_2_SIZE; + } + } + // #ifdef USECAN3 + else if (config->fdcan_instance == FDCAN3) { + if (CAN3.init) { + LOGOMATIC("CAN: CAN3 is already initialized\n"); + return 0; + } else { + canHandle = &CAN3; + canHandle->tx_capacity = TX_BUFFER_3_SIZE; + } + } + // #endif + // #elif defined(STM32L476xx) + // #else + // #error "Unsupported STM32 family" + // #endif + else { + LOGOMATIC("CAN: Unrecognized FDCAN instance"); + return 0; + } + canHandle->init = false; + canHandle->started = false; - canHandle->rx_callback = config->rx_callback; + // Initialize handle + assert(config->hal_fdcan_init.TxFifoQueueMode == FDCAN_TX_FIFO_OPERATION); - //tx buffer - //canHandle->tx_capacity = TX_BUFFER_SIZE_1; //dependent on can instance - canHandle->tx_tail = 0; - canHandle->tx_elements = 0; + canHandle->hal_fdcanP->Init = config->hal_fdcan_init; // copy FDCAN parameters from user + // canHandle->hal_fdcanP->Instance = config->fdcan_instance //handles initialized with correct base instance addresses - // alternately -> have can_msp_init setup state for HAL_FDCAN_MspInit to work correctly - // have can_msp_deinit setup state for HAL_FDCAN_MspDeInit to work correctly - // Then call HAL_FDCAN_Init() and HAL_FDCAN_DeInit() + canHandle->rx_gpio = config->rx_gpio; + canHandle->tx_gpio = config->tx_gpio; + canHandle->rx_pin = config->init_rx_gpio.Pin; + canHandle->tx_pin = config->init_tx_gpio.Pin; + canHandle->rx_interrupt_priority = config->rx_interrupt_priority; + canHandle->tx_interrupt_priority = config->tx_interrupt_priority; - // Current idea, redefine HAL_FDCAN_MspInit and MspDeInit do nothing at all, do all the work in can_msp_init() - uint32_t failure = 0; - if ( failure |= (can_msp_init(canHandle, (CANConfig *)config))) { - LOGOMATIC("CAN_init: could not initialize MSP resources"); - } + canHandle->rx_callback = config->rx_callback; - // PROBLEM: HAL_FDCAN_Init expects HAL_FDCAN_MspInit() to be defined - if (HAL_FDCAN_Init(canHandle->hal_fdcanP) != HAL_OK) { - failure |= HAL_ERROR; - LOGOMATIC("CAN: HAL Could not initialize FDCAN peripheral"); - // Error_Handler(); - } + // tx buffer + // canHandle->tx_capacity = TX_BUFFER_SIZE_1; //dependent on can instance + canHandle->tx_tail = 0; + canHandle->tx_elements = 0; + // alternately -> have can_msp_init setup state for HAL_FDCAN_MspInit to work correctly + // have can_msp_deinit setup state for HAL_FDCAN_MspDeInit to work correctly + // Then call HAL_FDCAN_Init() and HAL_FDCAN_DeInit() - // Active FDCAN callbacks - rxcalback uses line0, txcallback uses line1 - // uint32_t rxevents = FDCAN_IT_RX_FIFO0_NEW_MESSAGE; - uint32_t status = 0; - uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL; - status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, rx_events, 0); - status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, rx_events, FDCAN_INTERRUPT_LINE0); + // Current idea, redefine HAL_FDCAN_MspInit and MspDeInit do nothing at all, do all the work in can_msp_init() + uint32_t failure = 0; + if (failure |= (can_msp_init(canHandle, (CANConfig *)config))) { + LOGOMATIC("CAN_init: could not initialize MSP resources"); + } - // uint32_t txevents = FDCAN_IT_TX_COMPLETE; - uint32_t destinations = FDCAN_TX_BUFFER0; - uint32_t tx_events = FDCAN_IT_TX_COMPLETE | FDCAN_IT_TX_FIFO_EMPTY; - status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, tx_events, destinations); - status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, tx_events, FDCAN_INTERRUPT_LINE1); - // Callbacks redefined later + // PROBLEM: HAL_FDCAN_Init expects HAL_FDCAN_MspInit() to be defined + if (HAL_FDCAN_Init(canHandle->hal_fdcanP) != HAL_OK) { + failure |= HAL_ERROR; + LOGOMATIC("CAN: HAL Could not initialize FDCAN peripheral"); + // Error_Handler(); + } - if (status & HAL_ERROR) { - LOGOMATIC("CAN: Could not activate rx and tx interrupts\n"); - failure |= status; - } + // Active FDCAN callbacks - rxcalback uses line0, txcallback uses line1 + // uint32_t rxevents = FDCAN_IT_RX_FIFO0_NEW_MESSAGE; + uint32_t status = 0; + uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL; + status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, rx_events, 0); + status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, rx_events, FDCAN_INTERRUPT_LINE0); + + // uint32_t txevents = FDCAN_IT_TX_COMPLETE; + uint32_t destinations = FDCAN_TX_BUFFER0; + uint32_t tx_events = FDCAN_IT_TX_COMPLETE | FDCAN_IT_TX_FIFO_EMPTY; + status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, tx_events, destinations); + status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, tx_events, FDCAN_INTERRUPT_LINE1); + // Callbacks redefined later + + if (status & HAL_ERROR) { + LOGOMATIC("CAN: Could not activate rx and tx interrupts\n"); + failure |= status; + } - // Circular Buffer - //canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); - //canHandle->tx_buffer = malloc(sizeof(FDCANTxMessage)*canHandle->tx_buffer_length); - if (!canHandle->tx_buffer) { - LOGOMATIC("tx_buffer isn't valid?"); - failure |= 1; - } + // Circular Buffer + // canHandle->tx_buffer = GR_CircularBuffer_Create(config->tx_buffer_length); + // canHandle->tx_buffer = malloc(sizeof(FDCANTxMessage)*canHandle->tx_buffer_length); + if (!canHandle->tx_buffer) { + LOGOMATIC("tx_buffer isn't valid?"); + failure |= 1; + } - if (failure) { - can_msp_deinit(canHandle); - FDCAN_InstanceDeInit(canHandle->hal_fdcanP); - memset(canHandle+sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); //FIXME: Make sure instance is not being overwritten (FDCANx) - return 0; - } + if (failure) { + can_msp_deinit(canHandle); + FDCAN_InstanceDeInit(canHandle->hal_fdcanP); + memset(canHandle + sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); // FIXME: Make sure instance is not being overwritten (FDCANx) + return 0; + } - /*if (!canHandle->tx_buffer) { - LOGOMATIC("CAN: Could not allocate circular buffer\n"); - return 0; - }*/ + /*if (!canHandle->tx_buffer) { + LOGOMATIC("CAN: Could not allocate circular buffer\n"); + return 0; + }*/ - canHandle->init = true; - canHandle->started = false; + canHandle->init = true; + canHandle->started = false; - return canHandle; + return canHandle; } int can_release(CANHandle *canHandle) { - if (!canHandle) { - LOGOMATIC("CAN: Tried to release a null handle"); - return -1; - } + if (!canHandle) { + LOGOMATIC("CAN: Tried to release a null handle"); + return -1; + } - if (!canHandle->init) { - LOGOMATIC("CAN_release: can instance is already deinitialized"); - return -1; - } - can_stop(canHandle); // try to prevent more interrupts from firing + if (!canHandle->init) { + LOGOMATIC("CAN_release: can instance is already deinitialized"); + return -1; + } + can_stop(canHandle); // try to prevent more interrupts from firing - //No more interrupts should be firing that modify canHandle + // No more interrupts should be firing that modify canHandle - can_msp_deinit(canHandle); + can_msp_deinit(canHandle); - // reset FDCANx instance and message RAM and filters, clear interrupts - // HAL_FDCAN_DeInit(canHandle->hal_fdcanP); resets a little too hard - FDCAN_InstanceDeInit(canHandle->hal_fdcanP); + // reset FDCANx instance and message RAM and filters, clear interrupts + // HAL_FDCAN_DeInit(canHandle->hal_fdcanP); resets a little too hard + FDCAN_InstanceDeInit(canHandle->hal_fdcanP); - //TODO: Not sure these actually do anything - //__DSB(); // Data Synchronization Barrier - //__ISB(); // Instruction Synchronization Barrier + // TODO: Not sure these actually do anything + //__DSB(); // Data Synchronization Barrier + //__ISB(); // Instruction Synchronization Barrier - // free circular buffer contents - //GR_CircularBuffer_Free(&(canHandle->tx_buffer)); - memset( (void*) canHandle->tx_buffer, 0, canHandle->tx_capacity*sizeof(FDCANTxMessage)); - canHandle->tx_elements = 0; - canHandle->tx_tail = 0; + // free circular buffer contents + // GR_CircularBuffer_Free(&(canHandle->tx_buffer)); + memset((void *)canHandle->tx_buffer, 0, canHandle->tx_capacity * sizeof(FDCANTxMessage)); + canHandle->tx_elements = 0; + canHandle->tx_tail = 0; - // reset can handle - memset( (void*)canHandle+sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); + // reset can handle + memset((void *)canHandle + sizeof(FDCAN_HandleTypeDef), 0, sizeof(*canHandle) - sizeof(FDCAN_HandleTypeDef)); - return 0; + return 0; } -//TODO: prevent races conditions on the circular buffer -//TODO: Implement timer -//lock access to Circular Buffer when sending and dequeuing +// TODO: prevent races conditions on the circular buffer +// TODO: Implement timer +// lock access to Circular Buffer when sending and dequeuing static void can_tx_dequeue_helper(CANHandle *handle) { - if (!handle || !handle->tx_buffer) { - LOGOMATIC("can_tx_buffer_helper: handle is invalid"); - return; - } - - - //TODO: use interrupt masking in case any other ISRs need to lock the circular buffer - uint32_t basepri = __get_BASEPRI(); - - __set_BASEPRI(handle->tx_interrupt_priority); - //single consumer shouldn't affect state of circular buffer too closely - if (handle->tx_elements == 0) { - __set_BASEPRI(basepri); - return; - } + if (!handle || !handle->tx_buffer) { + LOGOMATIC("can_tx_buffer_helper: handle is invalid"); + return; + } - //uint32_t basepri = __get_basepri(); - //__disable_irq(); - //TODO: No need to lock circular buffer, as this ISR cannot interrupt the thread mode (can_send) + // TODO: use interrupt masking in case any other ISRs need to lock the circular buffer + uint32_t basepri = __get_BASEPRI(); - //Can Add to Fifo Q - if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { - //lock the Circular Buffer - FDCANTxMessage *msg = &handle->tx_buffer[handle->tx_tail]; + __set_BASEPRI(handle->tx_interrupt_priority); + // single consumer shouldn't affect state of circular buffer too closely + if (handle->tx_elements == 0) { + __set_BASEPRI(basepri); + return; + } - //should call Tx Buffer Callback once complete - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); + // uint32_t basepri = __get_basepri(); + //__disable_irq(); + // TODO: No need to lock circular buffer, as this ISR cannot interrupt the thread mode (can_send) - if (status != HAL_OK) { - //LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); //FIXME: Logomatic may not work with interrupts disabled - __set_BASEPRI(basepri); - return; // Stop trying to send more - } - //free(msg); // Successfully sent, free the entry in the circular buffer (which is pointed to by tail) - handle->tx_tail = ++handle->tx_tail % handle->tx_capacity; - handle->tx_elements--; + // Can Add to Fifo Q + if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { + // lock the Circular Buffer + FDCANTxMessage *msg = &handle->tx_buffer[handle->tx_tail]; - } else { //FIXME: call can_tx_dequeue_helper later with a timer, if this gets implemented, need to mask timer interrupts to allow atomic access + // should call Tx Buffer Callback once complete + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(handle->hal_fdcanP, &msg->tx_header, msg->data); - } //alternatively, if fifo is full, tx_dequeue should get called anyways, and we don't need the else statement + if (status != HAL_OK) { + // LOGOMATIC("CAN_tx_helper: failed to add message to FIFO\n"); //FIXME: Logomatic may not work with interrupts disabled + __set_BASEPRI(basepri); + return; // Stop trying to send more + } + // free(msg); // Successfully sent, free the entry in the circular buffer (which is pointed to by tail) + handle->tx_tail = ++handle->tx_tail % handle->tx_capacity; + handle->tx_elements--; - __set_BASEPRI(basepri); + } else { // FIXME: call can_tx_dequeue_helper later with a timer, if this gets implemented, need to mask timer interrupts to allow atomic access + } // alternatively, if fifo is full, tx_dequeue should get called anyways, and we don't need the else statement + __set_BASEPRI(basepri); } int can_send(CANHandle *canHandle, FDCANTxMessage *message) { - if (!canHandle || !message) { - LOGOMATIC("CAN_send: received null pointer\n"); - return -1; - } + if (!canHandle || !message) { + LOGOMATIC("CAN_send: received null pointer\n"); + return -1; + } - if (!canHandle->init || !canHandle->started) { - LOGOMATIC("CAN_send: CAN not initialized or started\n"); - return -1; - } + if (!canHandle->init || !canHandle->started) { + LOGOMATIC("CAN_send: CAN not initialized or started\n"); + return -1; + } - // IF TX Fifos are not full, send directly to them - // If TX Fifos are full, append to circular buffer - // If circular buffer is full, return an error code - - //stop can_tx_dequeue_helper from from interleaving - uint32_t basepri = __get_BASEPRI(); - __set_BASEPRI( canHandle->tx_interrupt_priority ); - - //FIXME: get rid of this jank - //if (hardwareEnabled) { - if (HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP) > 0) { - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); - - uint32_t val = 0; - if (status != HAL_OK) { - LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); - val = -1; - } else { - val = 0; - } - __set_BASEPRI( basepri ); - return val; - } - //} - - // Hardware FIFO full, try software buffer - if (canHandle->tx_elements < canHandle->tx_capacity) { - //int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); - - uint32_t idx = (canHandle->tx_tail + canHandle->tx_elements) % canHandle->tx_capacity; - canHandle->tx_buffer[idx] = *message; - canHandle->tx_elements++; - //memcpy(&canHandle->tx_buffer[idx], message , sizeof(FDCANTxMessage) ); - - //__set_BASEPRI(primask); - - /*if (result != 0) { - LOGOMATIC("CAN_send: buffer push failed\n"); - return -1; - } else { - return 0; - }*/ - } else { - LOGOMATIC("CAN_send: all buffers full\n"); //p - } - __set_BASEPRI(basepri); - // Both buffers full - return -1; + // IF TX Fifos are not full, send directly to them + // If TX Fifos are full, append to circular buffer + // If circular buffer is full, return an error code + + // stop can_tx_dequeue_helper from from interleaving + uint32_t basepri = __get_BASEPRI(); + __set_BASEPRI(canHandle->tx_interrupt_priority); + + // FIXME: get rid of this jank + // if (hardwareEnabled) { + if (HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP) > 0) { + HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); + + uint32_t val = 0; + if (status != HAL_OK) { + LOGOMATIC("CAN_send: failed to add to HW FIFO\n"); + val = -1; + } else { + val = 0; + } + __set_BASEPRI(basepri); + return val; + } + //} + + // Hardware FIFO full, try software buffer + if (canHandle->tx_elements < canHandle->tx_capacity) { + // int result = GR_CircularBuffer_Push(canHandle->tx_buffer, message, sizeof(FDCANTxMessage)); + + uint32_t idx = (canHandle->tx_tail + canHandle->tx_elements) % canHandle->tx_capacity; + canHandle->tx_buffer[idx] = *message; + canHandle->tx_elements++; + // memcpy(&canHandle->tx_buffer[idx], message , sizeof(FDCANTxMessage) ); + + //__set_BASEPRI(primask); + + /*if (result != 0) { + LOGOMATIC("CAN_send: buffer push failed\n"); + return -1; + } else { + return 0; + }*/ + } else { + LOGOMATIC("CAN_send: all buffers full\n"); // p + } + __set_BASEPRI(basepri); + // Both buffers full + return -1; } void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes) { - UNUSED(BufferIndexes); - // If circular buffer has elements, send to queue - // Otherwise do nothing - // #ifdef USECAN1 - CANHandle *handle = can_get_handle(hfdcan); - // see if you can pop any more from the buffer - can_tx_dequeue_helper(handle); + UNUSED(BufferIndexes); + // If circular buffer has elements, send to queue + // Otherwise do nothing + // #ifdef USECAN1 + CANHandle *handle = can_get_handle(hfdcan); + // see if you can pop any more from the buffer + can_tx_dequeue_helper(handle); } void HAL_FDCAN_TxFifoEmptyCallback(FDCAN_HandleTypeDef *hfdcan) { - CANHandle *handle = can_get_handle(hfdcan); - can_tx_dequeue_helper(handle); + CANHandle *handle = can_get_handle(hfdcan); + can_tx_dequeue_helper(handle); } void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { - CANHandle *handle = can_get_handle(hfdcan); + CANHandle *handle = can_get_handle(hfdcan); - if (!handle || !handle->init || !handle->rx_callback) { - return; - } + if (!handle || !handle->init || !handle->rx_callback) { + return; + } - /*if (!handle->rx_buffer) { - LOGOMATIC("CAN: RX Complete, but %s Buffer was released\n", can_get_instance_name(hfdcan->Instance)); - return; - } */ // no rx buffer at the moment + /*if (!handle->rx_buffer) { + LOGOMATIC("CAN: RX Complete, but %s Buffer was released\n", can_get_instance_name(hfdcan->Instance)); + return; + } */ // no rx buffer at the moment - if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { - //lost_rx++; - } + if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { + // lost_rx++; + } - if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { - return; - } + if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { + return; + } // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; FDCAN_RxHeaderTypeDef rx_header; @@ -441,12 +435,12 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) // GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; handle->rx_callback(rx_header.Identifier, rx_data, rx_header.DataLength); } - /* - if (GR_CircularBuffer_IsEmpty(handle->rx_buffer)) handle->rx_callback(rx_data, rx_header.DataLength); - else { - GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); - } - }*/ + /* + if (GR_CircularBuffer_IsEmpty(handle->rx_buffer)) handle->rx_callback(rx_data, rx_header.DataLength); + else { + GR_CircularBuffer_Push(handle->rx_buffer, rx_data, rx_header.DataLength); + } + }*/ //__set_BASEPRI(prev_priority); } @@ -465,255 +459,255 @@ void can_read_rx_buffer(CANHandle* canHandle) { // Just alternatively just use the HAL_FDCAN_ConfigFilter directly with the canHandle->hal_fdcan int can_add_filter(CANHandle *canHandle, FDCAN_FilterTypeDef *filter) { - if (!canHandle) { - LOGOMATIC("CAN_add_filter: handle is null"); - return -1; - } + if (!canHandle) { + LOGOMATIC("CAN_add_filter: handle is null"); + return -1; + } - if (!canHandle->init || canHandle->started) { - LOGOMATIC("CAN_add_filter: can instance is not initialized or already started"); - return -1; - } + if (!canHandle->init || canHandle->started) { + LOGOMATIC("CAN_add_filter: can instance is not initialized or already started"); + return -1; + } - if (HAL_FDCAN_ConfigFilter(canHandle->hal_fdcanP, filter) != HAL_OK) { - LOGOMATIC("CAN_add_filter: failed to configure filter"); - return -1; - } - return 0; - // check that # of filters isn't exceeding max value + if (HAL_FDCAN_ConfigFilter(canHandle->hal_fdcanP, filter) != HAL_OK) { + LOGOMATIC("CAN_add_filter: failed to configure filter"); + return -1; + } + return 0; + // check that # of filters isn't exceeding max value } int can_start(CANHandle *canHandle) { - if (!canHandle || !canHandle->init) { - return -1; - } + if (!canHandle || !canHandle->init) { + return -1; + } - if (canHandle->started) return 0; + if (canHandle->started) { + return 0; + } - IRQn_Type rx0it, txit; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + IRQn_Type rx0it, txit; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); - HAL_NVIC_ClearPendingIRQ(rx0it); //prevent a spurious interrupt - HAL_NVIC_ClearPendingIRQ(txit); + HAL_NVIC_ClearPendingIRQ(rx0it); // prevent a spurious interrupt + HAL_NVIC_ClearPendingIRQ(txit); - GPIOx_CLK_ENABLE(canHandle->rx_gpio); - GPIOx_CLK_ENABLE(canHandle->tx_gpio); + GPIOx_CLK_ENABLE(canHandle->rx_gpio); + GPIOx_CLK_ENABLE(canHandle->tx_gpio); - HAL_FDCAN_Start(canHandle->hal_fdcanP); + HAL_FDCAN_Start(canHandle->hal_fdcanP); - canHandle->started = true; + canHandle->started = true; - HAL_NVIC_EnableIRQ(rx0it); - HAL_NVIC_EnableIRQ(txit); + HAL_NVIC_EnableIRQ(rx0it); + HAL_NVIC_EnableIRQ(txit); - return 0; + return 0; } int can_stop(CANHandle *canHandle) { - if (!canHandle || !canHandle->init) { - return -1; - } + if (!canHandle || !canHandle->init) { + return -1; + } - if (!canHandle->started) { - return 0; - } + if (!canHandle->started) { + return 0; + } - //stop can interrupts from activating - uint32_t prev_priority = __get_BASEPRI(); - __set_BASEPRI( MIN(canHandle->rx_interrupt_priority, canHandle->tx_interrupt_priority) ); + // stop can interrupts from activating + uint32_t prev_priority = __get_BASEPRI(); + __set_BASEPRI(MIN(canHandle->rx_interrupt_priority, canHandle->tx_interrupt_priority)); - HAL_FDCAN_Stop(canHandle->hal_fdcanP); + HAL_FDCAN_Stop(canHandle->hal_fdcanP); - IRQn_Type rx0it, txit; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + IRQn_Type rx0it, txit; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); - HAL_NVIC_DisableIRQ(rx0it); - HAL_NVIC_DisableIRQ(txit); - HAL_NVIC_ClearPendingIRQ(rx0it); - HAL_NVIC_ClearPendingIRQ(txit); + HAL_NVIC_DisableIRQ(rx0it); + HAL_NVIC_DisableIRQ(txit); + HAL_NVIC_ClearPendingIRQ(rx0it); + HAL_NVIC_ClearPendingIRQ(txit); - __set_BASEPRI(prev_priority); + __set_BASEPRI(prev_priority); - GPIOx_CLK_DISABLE(canHandle->rx_gpio); - GPIOx_CLK_DISABLE(canHandle->tx_gpio); + GPIOx_CLK_DISABLE(canHandle->rx_gpio); + GPIOx_CLK_DISABLE(canHandle->tx_gpio); - canHandle->started = false; + canHandle->started = false; - return 0; + return 0; } - - - // ==================================== HELPER FUNCTIONS =============================================== -//TODO: Abstract across families +// ==================================== HELPER FUNCTIONS =============================================== +// TODO: Abstract across families static inline void fdcan_enable_shared_clock(void) { - if (fdcan_shared_clock_ref == 0) { - __HAL_RCC_FDCAN_CLK_ENABLE(); - } - fdcan_shared_clock_ref++; + if (fdcan_shared_clock_ref == 0) { + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + fdcan_shared_clock_ref++; } static inline void fdcan_disable_shared_clock(void) { - if (fdcan_shared_clock_ref > 0) { - fdcan_shared_clock_ref--; - if (fdcan_shared_clock_ref == 0) { - __HAL_RCC_FDCAN_CLK_DISABLE(); - } - } + if (fdcan_shared_clock_ref > 0) { + fdcan_shared_clock_ref--; + if (fdcan_shared_clock_ref == 0) { + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + } } // valid only for STM32G4 static int can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1) { - if (instance == FDCAN1) { - *it0 = FDCAN1_IT0_IRQn; - *it1 = FDCAN1_IT1_IRQn; - return 0; - } - if (instance == FDCAN2) { - *it0 = FDCAN2_IT0_IRQn; - *it1 = FDCAN2_IT1_IRQn; - return 0; - } - if (instance == FDCAN3) { - *it0 = FDCAN3_IT0_IRQn; - *it1 = FDCAN3_IT1_IRQn; - return 0; - } + if (instance == FDCAN1) { + *it0 = FDCAN1_IT0_IRQn; + *it1 = FDCAN1_IT1_IRQn; + return 0; + } + if (instance == FDCAN2) { + *it0 = FDCAN2_IT0_IRQn; + *it1 = FDCAN2_IT1_IRQn; + return 0; + } + if (instance == FDCAN3) { + *it0 = FDCAN3_IT0_IRQn; + *it1 = FDCAN3_IT1_IRQn; + return 0; + } - return -1; // invalid instance + return -1; // invalid instance } - // valid only for STM32G4 static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan) { - // #ifdef STM32G474xx - if (hfdcan->Instance == FDCAN1) { - return &CAN1; - } else if (hfdcan->Instance == FDCAN2) { - return &CAN2; - } else if (hfdcan->Instance == FDCAN3) { - return &CAN3; - } else { - LOGOMATIC("CAN_get_handle: was given invalid FDCAN instance\n"); - return 0; - } + // #ifdef STM32G474xx + if (hfdcan->Instance == FDCAN1) { + return &CAN1; + } else if (hfdcan->Instance == FDCAN2) { + return &CAN2; + } else if (hfdcan->Instance == FDCAN3) { + return &CAN3; + } else { + LOGOMATIC("CAN_get_handle: was given invalid FDCAN instance\n"); + return 0; + } } /* static inline void gpio_clk_enable(GPIO_TypeDef *gpio) { if (gpio == GPIOA) { - __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); } else if (gpio == GPIOB) { - __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); } else if (gpio == GPIOD) { - __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); } } static inline void gpio_clk_disable(GPIO_TypeDef *gpio) { if (gpio == GPIOA) { - __HAL_RCC_GPIOA_CLK_DISABLE(); + __HAL_RCC_GPIOA_CLK_DISABLE(); } else if (gpio == GPIOB) { - __HAL_RCC_GPIOB_CLK_DISABLE(); + __HAL_RCC_GPIOB_CLK_DISABLE(); } else if (gpio == GPIOD) { - __HAL_RCC_GPIOD_CLK_DISABLE(); + __HAL_RCC_GPIOD_CLK_DISABLE(); } }*/ // only valid for #STM32G474x, must redefine for each family static int can_msp_init(CANHandle *canHandle, CANConfig *config) { - // MSP Init ------- This could be inside HAL_FDCAN_MspInit() instead - // FDCAN Clock Select + // MSP Init ------- This could be inside HAL_FDCAN_MspInit() instead + // FDCAN Clock Select - fdcan_enable_shared_clock(); + fdcan_enable_shared_clock(); - // Clock speed for FDCAN determined by APB1 clock speed and FDCAN prescaler + // Clock speed for FDCAN determined by APB1 clock speed and FDCAN prescaler - // GPIOs init - GPIOx_CLK_ENABLE(config->rx_gpio); - GPIOx_CLK_ENABLE(config->tx_gpio); + // GPIOs init + GPIOx_CLK_ENABLE(config->rx_gpio); + GPIOx_CLK_ENABLE(config->tx_gpio); - HAL_GPIO_Init(config->rx_gpio, &(config->init_rx_gpio)); - HAL_GPIO_Init(config->tx_gpio, &(config->init_tx_gpio)); + HAL_GPIO_Init(config->rx_gpio, &(config->init_rx_gpio)); + HAL_GPIO_Init(config->tx_gpio, &(config->init_tx_gpio)); - IRQn_Type rxit = -1; - IRQn_Type txit = -1; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rxit, &txit); + IRQn_Type rxit = -1; + IRQn_Type txit = -1; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rxit, &txit); - // rxfifo0 - HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); + // rxfifo0 + HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); - // tx - HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); - // End MSP Init -------------- + // tx + HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); + // End MSP Init -------------- - //Call can_start() to enable interrupts + // Call can_start() to enable interrupts - return 0; + return 0; } // Valid only for STM32G474xE -static int can_msp_deinit(CANHandle* canHandle) { - //MSP DeInit - // must disable NVIC IRQs before freeing circular buffer +static int can_msp_deinit(CANHandle *canHandle) +{ + // MSP DeInit + // must disable NVIC IRQs before freeing circular buffer - //NVIC - IRQn_Type rx0it = -1; - IRQn_Type txit = -1; - can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); - HAL_NVIC_DisableIRQ(rx0it); - HAL_NVIC_DisableIRQ(txit); + // NVIC + IRQn_Type rx0it = -1; + IRQn_Type txit = -1; + can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit); + HAL_NVIC_DisableIRQ(rx0it); + HAL_NVIC_DisableIRQ(txit); - //TODO: turn off gpio clocks if no other peripherals are using them??? Could implement a shared GPIO layer - HAL_GPIO_DeInit(canHandle->rx_gpio, canHandle->rx_pin); - HAL_GPIO_DeInit(canHandle->tx_gpio, canHandle->tx_pin); + // TODO: turn off gpio clocks if no other peripherals are using them??? Could implement a shared GPIO layer + HAL_GPIO_DeInit(canHandle->rx_gpio, canHandle->rx_pin); + HAL_GPIO_DeInit(canHandle->tx_gpio, canHandle->tx_pin); - //MSP shared layer for GPIOs - //TODO: used to disable GPIOs clocks, but that might affect other peripherals + // MSP shared layer for GPIOs + // TODO: used to disable GPIOs clocks, but that might affect other peripherals - //RCC - fdcan_disable_shared_clock(); + // RCC + fdcan_disable_shared_clock(); - return 0; + return 0; } static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) { - // Enter INIT mode - hfdcan->Instance->CCCR |= FDCAN_CCCR_INIT; - while (!(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT)) - ; + // Enter INIT mode + hfdcan->Instance->CCCR |= FDCAN_CCCR_INIT; + while (!(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT)) + ; - // Disable interrupts - __HAL_FDCAN_DISABLE_IT(hfdcan, FDCAN_IT_LIST_RX_FIFO0 | FDCAN_IT_LIST_RX_FIFO1 | FDCAN_IT_LIST_SMSG | FDCAN_IT_LIST_TX_FIFO_ERROR | FDCAN_IT_LIST_MISC | FDCAN_IT_LIST_BIT_LINE_ERROR | - FDCAN_IT_LIST_PROTOCOL_ERROR); + // Disable interrupts + __HAL_FDCAN_DISABLE_IT(hfdcan, FDCAN_IT_LIST_RX_FIFO0 | FDCAN_IT_LIST_RX_FIFO1 | FDCAN_IT_LIST_SMSG | FDCAN_IT_LIST_TX_FIFO_ERROR | FDCAN_IT_LIST_MISC | FDCAN_IT_LIST_BIT_LINE_ERROR | + FDCAN_IT_LIST_PROTOCOL_ERROR); - // Clear filters - // TODO: fix magic numbers - memset((void *)hfdcan->msgRam.StandardFilterSA, 0, 0x0070); - memset((void *)hfdcan->msgRam.ExtendedFilterSA, 0, 0x0050); + // Clear filters + // TODO: fix magic numbers + memset((void *)hfdcan->msgRam.StandardFilterSA, 0, 0x0070); + memset((void *)hfdcan->msgRam.ExtendedFilterSA, 0, 0x0050); - // Optionally clear FIFOs / buffers + // Optionally clear FIFOs / buffers - // Exit INIT mode - hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; - while (hfdcan->Instance->CCCR & FDCAN_CCCR_INIT); + // Exit INIT mode + hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; + while (hfdcan->Instance->CCCR & FDCAN_CCCR_INIT) + ; - // Update handle state - hfdcan->State = HAL_FDCAN_STATE_RESET; + // Update handle state + hfdcan->State = HAL_FDCAN_STATE_RESET; } - // valid only for STM32G4 /*static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) { @@ -728,13 +722,31 @@ static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) }*/ // ===================================== HAL Callbacks ================================ -//TODO: Implement Family Checks -//Probably is safe from races -void FDCAN1_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } -void FDCAN1_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan1); } +// TODO: Implement Family Checks +// Probably is safe from races +void FDCAN1_IT0_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan1); +} +void FDCAN1_IT1_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan1); +} -void FDCAN2_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } -void FDCAN2_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan2); } +void FDCAN2_IT0_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan2); +} +void FDCAN2_IT1_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan2); +} -void FDCAN3_IT0_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } -void FDCAN3_IT1_IRQHandler(void) { HAL_FDCAN_IRQHandler(&hal_fdcan3); } +void FDCAN3_IT0_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan3); +} +void FDCAN3_IT1_IRQHandler(void) +{ + HAL_FDCAN_IRQHandler(&hal_fdcan3); +} diff --git a/Lib/Peripherals/CAN/Test/can_tests.c b/Lib/Peripherals/CAN/Test/can_tests.c index 53909eda9..d8310f065 100644 --- a/Lib/Peripherals/CAN/Test/can_tests.c +++ b/Lib/Peripherals/CAN/Test/can_tests.c @@ -28,7 +28,7 @@ void can_test_rx_callback1(uint32_t id, void *data, uint32_t size) return; } -//TODO: G4 tests are dependent on the System clock configuration +// TODO: G4 tests are dependent on the System clock configuration int can_test(void) { CANConfig canCfg;