From ced8dd0ab78020fc796bb82ce481afb3210a0058 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Tue, 12 May 2026 01:06:11 -0700 Subject: [PATCH 1/4] Initial changeover, totally untested Signed-off-by: Daniel Hansen --- ECU/Application/Inc/StateData.h | 2 +- ECU/Application/Inc/StateTicks.h | 2 +- ECU/Application/Inc/ecu_can.h | 140 --- ECU/Application/Inc/ecu_can_platform_deps.h | 18 - ECU/Application/Src/CANutils.c | 2 +- ECU/Application/Src/Lights.c | 2 +- ECU/Application/Src/StateTicks.c | 2 +- ECU/Application/Src/ecu_can.c | 1075 ------------------- ECU/CMakeLists.txt | 3 +- ECU/Core/Src/main.c | 3 +- ECU/Core/Src/stm32g4xx_it.c | 12 +- 11 files changed, 9 insertions(+), 1252 deletions(-) delete mode 100644 ECU/Application/Inc/ecu_can.h delete mode 100644 ECU/Application/Inc/ecu_can_platform_deps.h delete mode 100644 ECU/Application/Src/ecu_can.c diff --git a/ECU/Application/Inc/StateData.h b/ECU/Application/Inc/StateData.h index a0debf5cf..27fc53c48 100644 --- a/ECU/Application/Inc/StateData.h +++ b/ECU/Application/Inc/StateData.h @@ -3,7 +3,7 @@ #include "GRCAN_MSG_DATA.h" #include "StateMachine.h" -#include "ecu_can.h" +#include "can.h" #ifndef _STATEDATA_H_ #define _STATEDATA_H_ diff --git a/ECU/Application/Inc/StateTicks.h b/ECU/Application/Inc/StateTicks.h index 6f136f15c..636cd77a1 100644 --- a/ECU/Application/Inc/StateTicks.h +++ b/ECU/Application/Inc/StateTicks.h @@ -1,7 +1,7 @@ #include "StateData.h" #include "StateMachine.h" #include "adc.h" -#include "ecu_can.h" +#include "can.h" #ifndef _STATE_TICKS_H_ #define _STATE_TICKS_H_ diff --git a/ECU/Application/Inc/ecu_can.h b/ECU/Application/Inc/ecu_can.h deleted file mode 100644 index 6b398748e..000000000 --- a/ECU/Application/Inc/ecu_can.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef CAN_H -#define CAN_H - -// Supported STM32 Families -#ifdef STM32G4 -#elif defined(STM32L4) -#elif defined(STM32U5) -#error "Unsupported STM32 Family" -#endif - -#include "can_cfg.h" -#include "ecu_can_platform_deps.h" -// #include "StateData.h" - -// #include "circularBuffer.h" -#include - -// RX Callback must perform a deep copy of the data -// -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) - - FDCAN_InitTypeDef hal_fdcan_init; - CAN_RXCallback rx_callback; - uint32_t rx_interrupt_priority; - uint32_t tx_interrupt_priority; - - // Circular Buffer - // 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 - GPIO_TypeDef *tx_gpio; - GPIO_InitTypeDef init_tx_gpio; - - // additional parameters -} CANConfig; - -#define FDCAN_MAX_DATA_BYTES 64 -// TODO - allow user to send data without needing to construct a header for the buffer -// TODO: G4 tests are dependent on the System clock configuration?? -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; - - // TX buffer - FDCANTxMessage *const tx_buffer; - volatile uint32_t tx_capacity; - volatile uint32_t tx_tail; - volatile uint32_t tx_elements; - - // RX Callback - CAN_RXCallback rx_callback; - - uint8_t rx_interrupt_priority; // only 4 bits - uint8_t tx_interrupt_priority; - - // for release - GPIO_TypeDef *rx_gpio; - uint32_t rx_pin; - GPIO_TypeDef *tx_gpio; - uint32_t tx_pin; - // uint32_t Clock_Source; - - // state - bool init; - bool started; - - // error states - uint32_t lost_rx; -} CANHandle; - -typedef enum { - CAN_SUCCESS = 0, - CAN_ERROR -} CAN_STATUS; - -CANHandle *can_init(const CANConfig *config); // user must supply an rx callback function -CAN_STATUS can_start(CANHandle *handle); -CAN_STATUS can_stop(CANHandle *handle); -CAN_STATUS can_send(CANHandle *handle, FDCANTxMessage *buffer); -CAN_STATUS can_release(CANHandle *handle); // deinit circular buffer and turn off can peripheral and gpios -CAN_STATUS can_add_filter(CANHandle *handle, FDCAN_FilterTypeDef *filter); -CAN_STATUS can_enqueue(CANHandle *handle, FDCANTxMessage *message); // adds to software buffer, returns error if full - -// pass in a buffer to store the status string -// int can_info(char* ); - -// alternatively use -// HAL_FDCAN_ConfigGlobalFilter() //important to accept nonmatching frames into -// HAL_FDCAN_ConfigFilter() - -#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) - -#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) - -// doesn't need a handle, CAN cores share peripheral clock -void can_set_clksource(uint32_t clksource); // ex. LL_RCC_FDCAN_CLKSOURCE_PCLK1 for STM32G474RE - -// default Configuration helpers -int get_cfg(FDCAN_GlobalTypeDef *instance, CAN_RXCallback callback, CANConfig *out_cfg, uint32_t FDCAN_Mode, uint32_t numStdFilters, uint32_t numExtFilters); - -// converts CAN FD TxHeader DataLength Field -static const uint8_t CANFD_DLCtoBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; - -void CAN_Timer_Start(void); -void can_tx_dequeue_helper(CANHandle *handle); - -#endif diff --git a/ECU/Application/Inc/ecu_can_platform_deps.h b/ECU/Application/Inc/ecu_can_platform_deps.h deleted file mode 100644 index 986329ac0..000000000 --- a/ECU/Application/Inc/ecu_can_platform_deps.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ECU_CAN_PLATFORM_DEPS_H -#define ECU_CAN_PLATFORM_DEPS_H - -#if defined(STM32G4) -#include "stm32g4xx_hal.h" -#include "stm32g4xx_hal_fdcan.h" -#include "stm32g4xx_hal_gpio.h" -#include "stm32g4xx_hal_gpio_ex.h" -#include "stm32g4xx_hal_rcc.h" -#include "stm32g4xx_ll_gpio.h" -#include "stm32g4xx_ll_rcc.h" -// #elif defined(STM32L4) -// #elif defined(STM32U5) -#else -#error "Unsupported STM32 family" -#endif - -#endif // end header guard diff --git a/ECU/Application/Src/CANutils.c b/ECU/Application/Src/CANutils.c index 5f55662e7..473376efe 100644 --- a/ECU/Application/Src/CANutils.c +++ b/ECU/Application/Src/CANutils.c @@ -10,7 +10,7 @@ #include "StateData.h" #include "StateTicks.h" #include "StateUtils.h" -#include "ecu_can.h" +#include "can.h" #include "main.h" #include "stm32g4xx_hal_fdcan.h" #include "string.h" diff --git a/ECU/Application/Src/Lights.c b/ECU/Application/Src/Lights.c index 9e2b04ff1..464186e51 100644 --- a/ECU/Application/Src/Lights.c +++ b/ECU/Application/Src/Lights.c @@ -5,7 +5,7 @@ #include "StateUtils.h" #include "adc.h" #include "bitManipulations.h" -#include "ecu_can.h" +#include "can.h" #include "main.h" #include "stm32g4xx_ll_gpio.h" diff --git a/ECU/Application/Src/StateTicks.c b/ECU/Application/Src/StateTicks.c index 3c53bc9c2..34281c706 100644 --- a/ECU/Application/Src/StateTicks.c +++ b/ECU/Application/Src/StateTicks.c @@ -13,7 +13,7 @@ #include "StateMachine.h" #include "StateUtils.h" #include "Unused.h" -#include "ecu_can.h" +#include "can.h" #include "stm32g4xx_ll_gpio.h" /** diff --git a/ECU/Application/Src/ecu_can.c b/ECU/Application/Src/ecu_can.c deleted file mode 100644 index 7788bf745..000000000 --- a/ECU/Application/Src/ecu_can.c +++ /dev/null @@ -1,1075 +0,0 @@ -#include "ecu_can.h" - -#include -#include -#include -#include - -#include "stm32g4xx_ll_bus.h" -#include "stm32g4xx_ll_dma.h" -#include "stm32g4xx_ll_tim.h" - -// TODO: make the profiler cleaner -#include "Logomatic.h" -#include "main.h" - -// TODO: define DMA usage in a better way -// #define USEDMA -#ifdef USEDMA -#include "can_dma.h" - -#endif - -// CAN CONFIGURATION HEADER -#include "can_cfg.h" -#ifndef CAN_CFG_H -#error "can.c: Please define CAN_CFG_H and define at least one USECANx and TX_BUFFER_X_SIZE" -#endif -// =============================== - -// EXAMPLE Configuration in "can_cfg.h" -// #ifndef CAN_CFG_H -// #define CAN_CFG_H - -// #define USECAN1 -// #define TX_BUFFER_1_SIZE 10 - -// #endif - -// HAL handles -#ifdef USECAN1 -#ifndef TX_BUFFER_1_SIZE -#error "Please Define TX_BUFFER_1_SIZE" -#endif -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 -#ifndef TX_BUFFER_2_SIZE -#error "Please Define TX_BUFFER_2_SIZE" -#endif -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 -#ifndef TX_BUFFER_3_SIZE -#error "Please Define TX_BUFFER_3_SIZE" -#endif -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}; -#endif - -#define MIN(A, B) ((A < B) ? A : B) - -// bool hardwareEnabled = false; - -// macro lore -/* -#define CAT(a,b) a##b -#define CAT3(a, b, c) a##b##c -#define CAT4(a, b,c,d) a##b##c##d -#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) - -#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"); } \ - } 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 CAN_STATUS can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1); -static CAN_STATUS validate_can_handle(CANHandle *canHandle); - -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 CAN_STATUS can_msp_init(CANHandle *canHandle, CANConfig *config); -static CAN_STATUS can_msp_deinit(CANHandle *canHandle); -static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan); - -//================================================= API ======================================== -CANHandle *can_init(const CANConfig *config) -{ - // config validation? - // assert(config != 0) - CANHandle *canHandle = NULL; - -#ifdef STM32G474xx -#ifdef USECAN1 - if (config->fdcan_instance == FDCAN1) { - if (CAN1.init) { - LOGOMATIC("CAN: CAN1 is already initialized\n"); - return CAN_SUCCESS; - } else { - canHandle = &CAN1; - canHandle->tx_capacity = TX_BUFFER_1_SIZE; - } - } -#endif -#ifdef USECAN2 - if (config->fdcan_instance == FDCAN2) { - if (CAN2.init) { - LOGOMATIC("CAN: CAN2 is already initialized\n"); - return CAN_SUCCESS; - } else { - canHandle = &CAN2; - canHandle->tx_capacity = TX_BUFFER_2_SIZE; - LOGOMATIC("CAN: CAN2 selected with tx capacity %lu\n", canHandle->tx_capacity); - } - } -#endif -#ifdef USECAN3 - if (config->fdcan_instance == FDCAN3) { - if (CAN3.init) { - LOGOMATIC("CAN: CAN3 is already initialized\n"); - return CAN_SUCCESS; - } else { - canHandle = &CAN3; - canHandle->tx_capacity = TX_BUFFER_3_SIZE; - } - } -#endif - -// TODO: figure out a better way to extend this to other families besides ifdef soup -#elif defined(STM32G431xx) -#ifdef USECAN1 - if (config->fdcan_instance == FDCAN1) { - if (CAN1.init) { - LOGOMATIC("CAN: CAN1 is already initialized\n"); - return CAN_SUCCESS; - } else { - canHandle = &CAN1; - canHandle->tx_capacity = TX_BUFFER_1_SIZE; - } - } -#endif - -#endif - - // #elif defined(STM32L476xx) - // #else - // #error "Unsupported STM32 family" - // #endif - - if (canHandle == NULL) { - LOGOMATIC("CAN: Unrecognized FDCAN instance"); - return NULL; - } - - canHandle->init = false; - canHandle->started = false; - - // Initialize handle - assert(config->hal_fdcan_init.TxFifoQueueMode == FDCAN_TX_FIFO_OPERATION); - // assert(config->hal_fdcan_init.FrameFormat == FDCAME); - - 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; - - canHandle->rx_callback = config->rx_callback; - - // tx buffer - // canHandle->tx_capacity = TX_BUFFER_SIZE_1; //dependent on can instance - canHandle->tx_tail = 0; - canHandle->tx_elements = 0; - - // error - canHandle->lost_rx = 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 to do nothing at all, do all the work in can_msp_init() - uint32_t failure = 0; - if (failure |= (can_msp_init(canHandle, (CANConfig *)config) != CAN_SUCCESS)) { - LOGOMATIC("CAN_init: could not initialize MSP resources"); - return NULL; - } - - // 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; - uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; - 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); - - uint32_t err_events = FDCAN_IT_BUS_OFF | FDCAN_IT_ERROR_PASSIVE | FDCAN_IT_ERROR_WARNING | FDCAN_IT_ARB_PROTOCOL_ERROR | FDCAN_IT_DATA_PROTOCOL_ERROR; - status |= HAL_FDCAN_ActivateNotification(canHandle->hal_fdcanP, err_events, 0); - status |= HAL_FDCAN_ConfigInterruptLines(canHandle->hal_fdcanP, err_events, FDCAN_INTERRUPT_LINE1); - // Callbacks redefined later - - if (status & HAL_ERROR) { - LOGOMATIC("CAN: Could not activate rx, tx, and error 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; - } - - if (failure) { - can_msp_deinit(canHandle); - FDCAN_InstanceDeInit(canHandle->hal_fdcanP); - - FDCAN_HandleTypeDef *temp = canHandle->hal_fdcanP; - memset(canHandle, 0, sizeof(*canHandle)); // FIXME: Make sure instance is not being overwritten (FDCANx) - canHandle->hal_fdcanP = temp; - - return NULL; - } - -#ifdef USEDMA - // for(int i = 0; i < 10; i++); - DMA_M2M_Init(canHandle->rx_interrupt_priority, 0, canHandle->rx_callback); -#endif - - canHandle->init = true; - canHandle->started = false; - - return canHandle; -} - -CAN_STATUS can_release(CANHandle *canHandle) -{ - if (validate_can_handle(canHandle) != CAN_SUCCESS) { - return CAN_ERROR; - } - - if (!canHandle->init) { - LOGOMATIC("CAN_release: can instance is already deinitialized"); - return CAN_ERROR; - } - - if (can_stop(canHandle)) { // try to prevent more interrupts from firing - LOGOMATIC("CAN_release: could not stop instance"); - return CAN_ERROR; - } - - // No more interrupts should be firing that modify canHandle - if (can_msp_deinit(canHandle) != CAN_SUCCESS) { - LOGOMATIC("CAN_release: could not stop instance"); - return CAN_ERROR; - } - - // 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); - - __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(canHandle->tx_buffer[0])); - canHandle->tx_elements = 0; - canHandle->tx_tail = 0; - - // reset can handle - // FDCAN_HandleTypeDef *temp = canHandle->hal_fdcanP; - // uint32_t capacity = canHandle->tx_capacity; - // FDCANTxMessage* buff = canHandle->tx_buffer; - - canHandle->init = 0; - canHandle->started = 0; - canHandle->rx_callback = 0; - canHandle->tx_elements = 0; - canHandle->rx_gpio = 0; - canHandle->rx_interrupt_priority = 0; - canHandle->tx_interrupt_priority = 0; - canHandle->tx_gpio = 0; - canHandle->rx_pin = 0; - canHandle->tx_pin = 0; - canHandle->tx_tail = 0; - canHandle->lost_rx = 0; - - // memset(canHandle, 0, sizeof(*canHandle)); - // canHandle->hal_fdcanP = temp; - // canHandle->tx_capacity = capacity; - // canHandle->tx_buffer = buff; - - return CAN_SUCCESS; -} -// TODO: Implement timer -// lock access to Circular Buffer when sending and dequeuing -void can_tx_dequeue_helper(CANHandle *handle) -{ - // TODO: validate buffer - if (!handle->tx_buffer) { - LOGOMATIC("can_tx_buffer_helper: buffer is invalid"); - return; - } - - // LOGOMATIC("CAN %s, LOAD %2.2f \n", can_get_instance_name(handle->hal_fdcanP->Instance), (float)handle->tx_elements / (float)handle->tx_capacity); - - // 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 << 4); - // single consumer shouldn't affect state of circular buffer - if (handle->tx_elements == 0) { - __set_BASEPRI(basepri); - return; - } - - FDCAN_ProtocolStatusTypeDef protocol_status = {0}; - if (HAL_FDCAN_GetProtocolStatus(handle->hal_fdcanP, &protocol_status) == HAL_OK && protocol_status.BusOff) { - LOGOMATIC("CAN_send: bus off detected, attempting recovery\n"); - if (HAL_FDCAN_Stop(handle->hal_fdcanP) != HAL_OK) { - LOGOMATIC("CAN_send: failed to stop FDCAN peripheral during bus off recovery\n"); - __set_BASEPRI(basepri); - return; - } - uint32_t abort_mask = FDCAN_TX_BUFFER0 | FDCAN_TX_BUFFER1 | FDCAN_TX_BUFFER2; - HAL_FDCAN_AbortTxRequest(handle->hal_fdcanP, abort_mask); - if (HAL_FDCAN_Start(handle->hal_fdcanP) != HAL_OK) { - LOGOMATIC("CAN_send: failed to restart FDCAN peripheral during bus off recovery\n"); - __set_BASEPRI(basepri); - return; - } - } - - if (HAL_FDCAN_IsRestrictedOperationMode(handle->hal_fdcanP)) { - LOGOMATIC("CAN_send: currently in restricted operation mode\n"); - HAL_FDCAN_ExitRestrictedOperationMode(handle->hal_fdcanP); - } - - // Can Add to Fifo Q - if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hal_fdcanP)) { - const FDCANTxMessage *msg = &(handle->tx_buffer[handle->tx_tail]); - - // 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--; - - } 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); -} - -#ifdef PROFILE -dwt_timer_t send_timer = {0}; -#endif - -CAN_STATUS can_enqueue(CANHandle *canHandle, FDCANTxMessage *message) -{ - - if (validate_can_handle(canHandle) != CAN_SUCCESS) { - return CAN_ERROR; - } - - if (!canHandle->started) { - LOGOMATIC("CAN_send: instance is not started\n"); - return CAN_ERROR; - } - - if (message == NULL) { - LOGOMATIC("CAN_enqueue: received null pointer for message\n"); - return CAN_ERROR; - } - - if (!canHandle->init || !canHandle->started) { - LOGOMATIC("CAN_send: CAN not initialized or started\n"); - return CAN_ERROR; - } - - // enques can message - 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(__get_BASEPRI()); - return CAN_SUCCESS; // added to software buffer - - /*if (result != 0) { - LOGOMATIC("CAN_send: buffer push failed\n"); - return CAN_ERROR; - } else { - return CAN_SUCCESS; - }*/ - } - - LOGOMATIC("CAN_send: all buffers full\n"); // p - __set_BASEPRI(__get_BASEPRI()); - return CAN_ERROR; -} - -// ONLY CALLED FROM A TIMER -CAN_STATUS 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_tx_dequeue_helper from from interleaving - // TODO: Check BASEPRI register - uint32_t basepri = __get_BASEPRI(); - __set_BASEPRI((canHandle->tx_interrupt_priority) << 4); - - FDCAN_ProtocolStatusTypeDef protocol_status = {0}; - if (HAL_FDCAN_GetProtocolStatus(canHandle->hal_fdcanP, &protocol_status) == HAL_OK && protocol_status.BusOff) { - LOGOMATIC("CAN_send: bus off detected, attempting recovery\n"); - if (HAL_FDCAN_Stop(canHandle->hal_fdcanP) != HAL_OK) { - LOGOMATIC("CAN_send: failed to stop FDCAN peripheral during bus off recovery\n"); - __set_BASEPRI(basepri); - return CAN_ERROR; - } - uint32_t abort_mask = FDCAN_TX_BUFFER0 | FDCAN_TX_BUFFER1 | FDCAN_TX_BUFFER2; - HAL_FDCAN_AbortTxRequest(canHandle->hal_fdcanP, abort_mask); - if (HAL_FDCAN_Start(canHandle->hal_fdcanP) != HAL_OK) { - LOGOMATIC("CAN_send: failed to restart FDCAN peripheral during bus off recovery\n"); - __set_BASEPRI(basepri); - return CAN_ERROR; - } - } - - if (HAL_FDCAN_IsRestrictedOperationMode(canHandle->hal_fdcanP)) { - LOGOMATIC("CAN_send: currently in restricted operation mode\n"); - HAL_FDCAN_ExitRestrictedOperationMode(canHandle->hal_fdcanP); - } - - uint32_t free = 0; - if ((free = HAL_FDCAN_GetTxFifoFreeLevel(canHandle->hal_fdcanP)) > 0) { - HAL_StatusTypeDef status = HAL_FDCAN_AddMessageToTxFifoQ(canHandle->hal_fdcanP, &(message->tx_header), message->data); - - if (status != HAL_OK) { - LOGOMATIC("CAN_send: failed to add to HW FIFO, falling back to SW queue\n"); - } else { - __set_BASEPRI(basepri); - return CAN_SUCCESS; // Successfully added to HW FIFO - } - } - //} - - LOGOMATIC("CAN_send: all buffers full\n"); // p - __set_BASEPRI(basepri); - // Both buffers full - return CAN_ERROR; -} - -void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs) -{ - CANHandle *handle = can_get_handle(hfdcan); - if (!handle || !handle->init) { - return; - } - - LOGOMATIC("%s: FDCAN error status interrupt: 0x%08lX\n", can_get_instance_name(handle->hal_fdcanP->Instance), ErrorStatusITs); - - if (HAL_FDCAN_IsRestrictedOperationMode(hfdcan)) { - HAL_FDCAN_ExitRestrictedOperationMode(hfdcan); - } -} - -// #define PROFILE -// uint32_t PROFILE_AVG_RX_CYCLES = 0; -// uint32_t PROFILE_AVG_RX_CYCLES_SAMPLES = 0; - -#ifdef PROFILE -dwt_timer_t rx_timer = {0}; -#endif - -void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) -{ - // dwt_timer_start_measurement(&rx_timer); - - // dwt_timer_start_measurement(&rx_timer); - - 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) { - // TODO: Synchronize access to message counters - if (__builtin_uaddl_overflow(handle->lost_rx, 1, &handle->lost_rx)) { - handle->lost_rx = 0; - LOGOMATIC("%s: lost message counter overflowed\n", can_get_instance_name(handle->hal_fdcanP->Instance)); - } - } - - // If nothing else happened besides message loss - if (!(RxFifo0ITs & ~FDCAN_IT_RX_FIFO0_MESSAGE_LOST)) { - return; - } - - if (!(RxFifo0ITs & (FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL))) { - return; - } - - // if (GR_CircularBuffer_IsFull(handle->rx_buffer)) return; - FDCAN_RxHeaderTypeDef rx_header = {0}; - - // TODO: Stack allocation should be safe - // uint8_t rx_data[64] = {0}; - uint8_t rx_data[64] __attribute__((aligned(4))) = {0}; // align to word boundary for safe DMA transfer - - // TODO: Copying takes a while, may have to spread these out over multiple ISRs - while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { -#ifdef USEDMA - - // dwt_timer_start_measurement(&rx_timer); - FDCAN_GetRxMessage_DMA(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - // dwt_timer_end_measurement(&rx_timer); - -#else - - // dwt_timer_start_measurement(&rx_timer); - HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - // dwt_timer_end_measurement(&rx_timer); - -#endif - - // GR_OLD_NODE_ID sendingID = (rx_header.Identifier & (0xFF << 20)) >> 20; - // GR_OLD_MSG_ID messageID = (rx_header.Identifier & (0xFFF << 8)) >> 8; - - // TODO: move callbacks to correct positions, but right now you are using polling DMA so this is fine. - handle->rx_callback(rx_header.Identifier, rx_data, CANFD_DLCtoBytes[rx_header.DataLength]); - } - - //__set_BASEPRI(prev_priority); - // dwt_timer_end_measurement(&rx_timer); -} - -/* -void can_read_rx_buffer(CANHandle* canHandle) { - //User can call this at their leisure to pop the rx_buffer - - //read rx_buffer one element at a time? - //or read until empty -}*/ - -/*void HAL_FDCAN_RxFifo1Callback(FDCAN_HandleTypeDef * hfdcan, uint32_t RxFifo0ITs) { - -}*/ - -// Just alternatively just use the HAL_FDCAN_ConfigFilter directly with the canHandle->hal_fdcan -CAN_STATUS can_add_filter(CANHandle *canHandle, FDCAN_FilterTypeDef *filter) -{ - if (validate_can_handle(canHandle) != CAN_SUCCESS) { - return CAN_ERROR; - } - - if (!canHandle->init || canHandle->started) { - LOGOMATIC("CAN_add_filter: can instance is not initialized or already started\n"); - return CAN_ERROR; - } - - if (HAL_FDCAN_ConfigFilter(canHandle->hal_fdcanP, filter) != HAL_OK) { - LOGOMATIC("CAN_add_filter: failed to configure filter\n"); - return CAN_ERROR; - } - return CAN_SUCCESS; - // check that # of filters isn't exceeding max value -} - -CAN_STATUS can_start(CANHandle *canHandle) -{ - if (validate_can_handle(canHandle) != CAN_SUCCESS) { - return CAN_ERROR; - } - - if (!canHandle->init) { - LOGOMATIC("CAN_start: can instance is not initialized\n"); - return CAN_ERROR; - } - - if (canHandle->started) { - return CAN_SUCCESS; - } - - IRQn_Type rx0it, txit; - rx0it = txit = -1; // TOOD: Check that this is a valid way to initialize an invalid value - if (can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit) != CAN_SUCCESS) { - LOGOMATIC("can_start: could not obtain irq #s\n"); - return CAN_ERROR; - } - - 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; - - HAL_NVIC_EnableIRQ(rx0it); - HAL_NVIC_EnableIRQ(txit); - - return CAN_SUCCESS; -} - -CAN_STATUS can_stop(CANHandle *canHandle) -{ - if (validate_can_handle(canHandle) != CAN_SUCCESS) { - return CAN_ERROR; - } - - if (!canHandle->init) { - LOGOMATIC("CAN_stop: can instance is not initialized\n"); - return CAN_ERROR; - } - - if (!canHandle->started) { - return CAN_SUCCESS; - } - - // stop can interrupts from activating - uint32_t base_pri = __get_BASEPRI(); - __set_BASEPRI(MIN(canHandle->rx_interrupt_priority, canHandle->tx_interrupt_priority) << 4); - - if (HAL_FDCAN_Stop(canHandle->hal_fdcanP) != HAL_OK) { - return CAN_ERROR; - } - - IRQn_Type rx0it, txit; - rx0it = txit = -1; - if (can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit) != CAN_SUCCESS) { - return CAN_ERROR; - } - - HAL_NVIC_DisableIRQ(rx0it); - HAL_NVIC_DisableIRQ(txit); - HAL_NVIC_ClearPendingIRQ(rx0it); - HAL_NVIC_ClearPendingIRQ(txit); - - __set_BASEPRI(base_pri); - - GPIOx_CLK_DISABLE(canHandle->rx_gpio); - GPIOx_CLK_DISABLE(canHandle->tx_gpio); - - canHandle->started = false; - - // TODO: stop a DMA transfer if its in progress - - return CAN_SUCCESS; -} - -// ==================================== 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++; -} - -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(); - } - } -} - -// valid only for STM32G4 -static CAN_STATUS can_get_irqs(FDCAN_GlobalTypeDef *instance, IRQn_Type *it0, IRQn_Type *it1) -{ -#ifdef STM32G474xx - if (instance == FDCAN1) { - *it0 = FDCAN1_IT0_IRQn; - *it1 = FDCAN1_IT1_IRQn; - return CAN_SUCCESS; - } - if (instance == FDCAN2) { - *it0 = FDCAN2_IT0_IRQn; - *it1 = FDCAN2_IT1_IRQn; - return CAN_SUCCESS; - } - if (instance == FDCAN3) { - *it0 = FDCAN3_IT0_IRQn; - *it1 = FDCAN3_IT1_IRQn; - return CAN_SUCCESS; - } - - // TODO: START of possible ifdef soup -#elif defined(STM32G431xx) - if (instance == FDCAN1) { - *it0 = FDCAN1_IT0_IRQn; - *it1 = FDCAN1_IT1_IRQn; - return CAN_SUCCESS; - } -#endif - - LOGOMATIC("can_get_irqs: could not obtain irq #s\n"); - return CAN_ERROR; // invalid instance -} - -static CANHandle *can_get_handle(FDCAN_HandleTypeDef *hfdcan) -{ -#ifdef STM32G4 -#ifdef USECAN1 - if (hfdcan->Instance == FDCAN1) { - return &CAN1; - } -#endif -#ifdef USECAN2 - if (hfdcan->Instance == FDCAN2) { - return &CAN2; - } -#endif -#ifdef USECAN3 - if (hfdcan->Instance == FDCAN3) { - return &CAN3; - } -#endif -#endif - - LOGOMATIC("CAN_get_handle: was given invalid FDCAN instance\n"); - UNUSED(hfdcan); - return NULL; -} - -static CAN_STATUS validate_can_handle(CANHandle *canHandle) -{ - - if (canHandle == NULL) { - LOGOMATIC("can.c: handle is null\n"); - return CAN_ERROR; - } - -#ifdef STM32G4 -#ifdef USECAN1 - if (canHandle == &CAN1) { - return CAN_SUCCESS; - } -#endif -#ifdef USECAN2 - if (canHandle == &CAN2) { - return CAN_SUCCESS; - } -#endif -#ifdef USECAN3 - if (canHandle == &CAN3) { - return CAN_SUCCESS; - } -#endif -#endif - - LOGOMATIC("can.c: invalid can handle\n"); - return CAN_ERROR; -} - -/* -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(); - } -} - -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(); - } -}*/ - -// only valid for #STM32G474x, must redefine for each family -static CAN_STATUS can_msp_init(CANHandle *canHandle, CANConfig *config) -{ - // MSP Init ------- This could be inside HAL_FDCAN_MspInit() instead - // FDCAN Clock Select - - fdcan_enable_shared_clock(); - - // 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); - - 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; - if (can_get_irqs(canHandle->hal_fdcanP->Instance, &rxit, &txit) != CAN_SUCCESS) { - return CAN_ERROR; - } - - // rxfifo0 - HAL_NVIC_SetPriority(rxit, config->rx_interrupt_priority, 0); - - // tx - HAL_NVIC_SetPriority(txit, config->tx_interrupt_priority, 0); - // End MSP Init -------------- - - // Call can_start() to enable interrupts - - return CAN_SUCCESS; -} - -// Valid only for STM32G474xE -static CAN_STATUS can_msp_deinit(CANHandle *canHandle) -{ - // MSP DeInit - // must disable NVIC IRQs before freeing circular buffer - - // NVIC - IRQn_Type rx0it = -1; - IRQn_Type txit = -1; - if (can_get_irqs(canHandle->hal_fdcanP->Instance, &rx0it, &txit) != CAN_SUCCESS) { - return CAN_ERROR; - } - - 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); - - // MSP shared layer for GPIOs - // TODO: used to disable GPIOs clocks, but that might affect other peripherals - - // RCC - // can only disable clock after resetting all FDCAN instances - return CAN_SUCCESS; -} - -static void FDCAN_InstanceDeInit(FDCAN_HandleTypeDef *hfdcan) -{ - // Enter INIT mode - hfdcan->Instance->CCCR |= FDCAN_CCCR_INIT; - while (!(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT)) - ; - hfdcan->Instance->CCCR |= FDCAN_CCCR_CCE; - - // 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_BIT(hfdcan->Instance->ILE, (FDCAN_INTERRUPT_LINE0 | FDCAN_INTERRUPT_LINE1)); - - // 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; - - fdcan_disable_shared_clock(); -} - -// valid only for STM32G4 -static const char *can_get_instance_name(FDCAN_GlobalTypeDef *instance) -{ -#ifdef STM32G474xx - - if (instance == FDCAN1) { - return "FDCAN1"; - } else if (instance == FDCAN2) { - return "FDCAN2"; - } else if (instance == FDCAN3) { - return "FDCAN3"; - } -#elif defined(STM32G431xx) - if (instance == FDCAN1) { - return "FDCAN1"; - } -#endif - return "UNKNOWN"; -} - -// ===================================== HAL Callbacks ================================ -// TODO: Implement Family Checks -void FDCAN1_IT0_IRQHandler(void) -{ -#ifdef USECAN1 - HAL_FDCAN_IRQHandler(&hal_fdcan1); -#endif -} -void FDCAN1_IT1_IRQHandler(void) -{ -#ifdef USECAN1 - HAL_FDCAN_IRQHandler(&hal_fdcan1); -#endif -} - -void FDCAN2_IT0_IRQHandler(void) -{ -#ifdef USECAN2 - HAL_FDCAN_IRQHandler(&hal_fdcan2); -#endif -} -void FDCAN2_IT1_IRQHandler(void) -{ -#ifdef USECAN2 - HAL_FDCAN_IRQHandler(&hal_fdcan2); -#endif -} - -void FDCAN3_IT0_IRQHandler(void) -{ -#ifdef USECAN3 - HAL_FDCAN_IRQHandler(&hal_fdcan3); -#endif -} -void FDCAN3_IT1_IRQHandler(void) -{ -#ifdef USECAN3 - HAL_FDCAN_IRQHandler(&hal_fdcan3); -#endif -} - -// NEW THINGS - -void CAN_Timer_Start(void) -{ - static bool initialized = false; - - if (initialized) { - LOGOMATIC("CAN_Timer_Start: timer is already initialized\n"); - return; - } - - RCC_ClkInitTypeDef clkconfig = {0}; - uint32_t latency = 0; - HAL_RCC_GetClockConfig(&clkconfig, &latency); - - uint32_t apb1_div = clkconfig.APB1CLKDivider; - uint32_t tim_clock = (apb1_div == RCC_HCLK_DIV1) ? HAL_RCC_GetPCLK1Freq() : (2U * HAL_RCC_GetPCLK1Freq()); - - // 10 kHz counter clock keeps both PSC/ARR in range for a 1 second period. - const uint32_t counter_hz = 10000U; - if (tim_clock < counter_hz) { - LOGOMATIC("CAN_Timer_Start: APB1 clock is too slow to achieve desired timer frequency\n"); - return; - } - - uint32_t prescaler = (tim_clock / counter_hz) - 1U; - if (prescaler > 0xFFFFU) { - LOGOMATIC("CAN_Timer_Start: failed to initialize timer prescaler\n"); - return; - } - - uint32_t autoreload = ((CAN_TIMER_SEND_PERIOD_US * counter_hz) / 1000000U) - 1U; - if (autoreload > 0xFFFFU) { - LOGOMATIC("CAN_Timer_Start: failed to initialize timer autoreload\n"); - return; - } - - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM5); - - LL_TIM_InitTypeDef tim_init = {0}; - tim_init.Prescaler = prescaler; - tim_init.CounterMode = LL_TIM_COUNTERMODE_UP; - tim_init.Autoreload = autoreload; - tim_init.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - - if (LL_TIM_Init(TIM5, &tim_init) != SUCCESS) { - LOGOMATIC("CAN_Timer_Start: failed to initialize timer\n"); - return; - } - - LL_TIM_SetClockSource(TIM5, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_ClearFlag_UPDATE(TIM5); - LL_TIM_EnableIT_UPDATE(TIM5); - - HAL_NVIC_SetPriority(TIM5_IRQn, 15U, 0U); - HAL_NVIC_EnableIRQ(TIM5_IRQn); - - LL_TIM_EnableCounter(TIM5); - - initialized = true; - LOGOMATIC("CAN_Timer_Start: timer initialized\n"); - return; -} diff --git a/ECU/CMakeLists.txt b/ECU/CMakeLists.txt index d540a36e5..5c119b606 100644 --- a/ECU/CMakeLists.txt +++ b/ECU/CMakeLists.txt @@ -81,7 +81,6 @@ target_sources( Application/Src/CANutils.c Application/Src/Pinging.c Application/Src/Lights.c - Application/Src/ecu_can.c ) target_link_libraries( @@ -89,7 +88,7 @@ target_link_libraries( INTERFACE CANfigurator GR_ADC - #PERIPHERAL_CAN_LIB + PERIPHERAL_TIMEDCAN_LIB BitManipulations_Lib ) diff --git a/ECU/Core/Src/main.c b/ECU/Core/Src/main.c index efc335045..66c567d5e 100644 --- a/ECU/Core/Src/main.c +++ b/ECU/Core/Src/main.c @@ -40,7 +40,7 @@ #include "StateTicks.h" #include "StateUtils.h" #include "adc.h" -#include "ecu_can.h" +#include "can.h" #include "stm32g4xx_hal.h" /* USER CODE END Includes */ @@ -343,7 +343,6 @@ void CAN_Configure(void) // timer can can_start(stateLump.primary_can); can_start(stateLump.data_can); - CAN_Timer_Start(); } /** * @brief The application entry point. diff --git a/ECU/Core/Src/stm32g4xx_it.c b/ECU/Core/Src/stm32g4xx_it.c index 97519bf4d..01ab766d9 100644 --- a/ECU/Core/Src/stm32g4xx_it.c +++ b/ECU/Core/Src/stm32g4xx_it.c @@ -20,7 +20,7 @@ /* Includes ------------------------------------------------------------------*/ #include "stm32g4xx_it.h" -#include "ecu_can.h" +#include "can.h" #include "main.h" #include "stm32g4xx_ll_tim.h" /* Private includes ----------------------------------------------------------*/ @@ -190,13 +190,5 @@ void SysTick_Handler(void) } /* USER CODE BEGIN 1 */ -void TIM5_IRQHandler(void) -{ - if (LL_TIM_IsActiveFlag_UPDATE(TIM5)) { - LL_TIM_ClearFlag_UPDATE(TIM5); - can_tx_dequeue_helper(stateLump.primary_can); // TODO: make this work for multiple instances if needed - can_tx_dequeue_helper(stateLump.data_can); - HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11); - } -} + /* USER CODE END 1 */ From 02521ccfe91b86cf400a2069ca20ea8e1a114a46 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Tue, 12 May 2026 01:11:31 -0700 Subject: [PATCH 2/4] Bring back HOOTL testing Signed-off-by: Daniel Hansen --- ECU/CMakeLists.txt | 3 +-- ECU/Test/Inc/can.h | 2 +- ECU/Test/Inc/main.h | 2 ++ ECU/Test/Src/StateTicksTest.c | 2 +- ECU/Test/Src/can.c | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ECU/CMakeLists.txt b/ECU/CMakeLists.txt index 5c119b606..148a6806b 100644 --- a/ECU/CMakeLists.txt +++ b/ECU/CMakeLists.txt @@ -14,8 +14,7 @@ endif() get_filename_component(GR_PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) #TODO: when CAN implementation is settled, turn HOOTL tests back on -#if(CMAKE_PRESET_NAME STREQUAL "HOOTLTest") -if(FALSE) +if(CMAKE_PRESET_NAME STREQUAL "HOOTLTest") add_executable(StateTicksTest) target_include_directories( StateTicksTest diff --git a/ECU/Test/Inc/can.h b/ECU/Test/Inc/can.h index 87b34fa85..cc7810816 100644 --- a/ECU/Test/Inc/can.h +++ b/ECU/Test/Inc/can.h @@ -374,7 +374,7 @@ typedef struct { CANHandle *can_init(const CANConfig *config); // user must supply an rx callback function int can_start(CANHandle *handle); int can_stop(CANHandle *handle); -int can_send(CANHandle *handle, FDCANTxMessage *buffer); +int can_enqueue(CANHandle *canHandle, FDCANTxMessage *message); int can_release(CANHandle *handle); // deinit circular buffer and turn off can peripheral and gpios int can_add_filter(CANHandle *handle, FDCAN_FilterTypeDef *filter); // alternatively use diff --git a/ECU/Test/Inc/main.h b/ECU/Test/Inc/main.h index 4da12629e..64e24ccfa 100644 --- a/ECU/Test/Inc/main.h +++ b/ECU/Test/Inc/main.h @@ -1 +1,3 @@ #include "GRCAN_NODE_ID.h" + +#define FDCAN_CLASSIC_CAN 0 diff --git a/ECU/Test/Src/StateTicksTest.c b/ECU/Test/Src/StateTicksTest.c index ca33a402c..3f844fc29 100644 --- a/ECU/Test/Src/StateTicksTest.c +++ b/ECU/Test/Src/StateTicksTest.c @@ -5,7 +5,7 @@ #include "Logomatic.h" #include "StateData.h" #include "StateUtils.h" -#include "ecu_can.h" +#include "can.h" #include "stm32g4xx_hal.h" #include "stm32g4xx_hal_fdcan.h" diff --git a/ECU/Test/Src/can.c b/ECU/Test/Src/can.c index ba9e6581a..d8756c259 100644 --- a/ECU/Test/Src/can.c +++ b/ECU/Test/Src/can.c @@ -1,5 +1,5 @@ #include "Unused.h" -#include "ecu_can.h" +#include "can.h" int can_start(CANHandle *handle) { @@ -13,10 +13,10 @@ int can_stop(CANHandle *handle) return 0; } -int can_send(CANHandle *handle, FDCANTxMessage *buffer) +int can_enqueue(CANHandle *canHandle, FDCANTxMessage *message) { - UNUSED(handle); - UNUSED(buffer); + UNUSED(canHandle); + UNUSED(message); return 0; } From 44484e6cc9900d8c7722f5038ae05eedaf435f77 Mon Sep 17 00:00:00 2001 From: Casey Zwicker Date: Wed, 13 May 2026 00:56:45 -0700 Subject: [PATCH 3/4] Set bspd sense in test to new good value --- ECU/Test/Src/StateTicksTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ECU/Test/Src/StateTicksTest.c b/ECU/Test/Src/StateTicksTest.c index 3f844fc29..df18705da 100644 --- a/ECU/Test/Src/StateTicksTest.c +++ b/ECU/Test/Src/StateTicksTest.c @@ -70,7 +70,7 @@ int main(void) // ## Step 0.0 ## // ########################### LOGOMATIC("State Ticks test started\n"); - ECU_StateData stateLumpTest = {.ecu_state = GR_GLV_ON, .ams_sense = 1.5, .imd_sense = 1.5, .bspd_sense = 1.5}; + ECU_StateData stateLumpTest = {.ecu_state = GR_GLV_ON, .ams_sense = 1.5, .imd_sense = 1.5, .bspd_sense = 1.2}; LOGOMATIC("Check GLV ON at boot\n"); stateLumpTest.ecu_state = GR_GLV_ON; stateLumpTest.acu_software_latch = 1; From 17579a12092d8903a6116dd204ce0d29656774a2 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 17:13:30 +0000 Subject: [PATCH 4/4] Automatic Clang-Format: Standardized formatting automatically --- ECU/Test/Src/can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ECU/Test/Src/can.c b/ECU/Test/Src/can.c index d8756c259..e6154a08f 100644 --- a/ECU/Test/Src/can.c +++ b/ECU/Test/Src/can.c @@ -1,6 +1,7 @@ -#include "Unused.h" #include "can.h" +#include "Unused.h" + int can_start(CANHandle *handle) { UNUSED(handle);