From 688feab290dd6acffdcd56611ef1506b86627210 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 9 Jul 2026 02:16:43 -0700 Subject: [PATCH 01/38] REVERT ME --- Nucleo blinky demo Signed-off-by: Daniel Hansen --- CMakeLists.txt | 2 + Nucleo-Blinky/CMakeLists.txt | 41 ++ Nucleo-Blinky/Core/Inc/gpio.h | 49 +++ Nucleo-Blinky/Core/Inc/main.h | 86 ++++ Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h | 380 ++++++++++++++++++ Nucleo-Blinky/Core/Inc/stm32g4xx_it.h | 67 +++ .../Core/Inc/stm32g4xx_nucleo_conf.h | 78 ++++ Nucleo-Blinky/Core/Src/gpio.c | 55 +++ Nucleo-Blinky/Core/Src/main.c | 209 ++++++++++ Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c | 85 ++++ Nucleo-Blinky/Core/Src/stm32g4xx_it.c | 217 ++++++++++ Nucleo-Blinky/Nucleo-Blinky.ioc | 179 +++++++++ 12 files changed, 1448 insertions(+) create mode 100644 Nucleo-Blinky/CMakeLists.txt create mode 100644 Nucleo-Blinky/Core/Inc/gpio.h create mode 100644 Nucleo-Blinky/Core/Inc/main.h create mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h create mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_it.h create mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h create mode 100644 Nucleo-Blinky/Core/Src/gpio.c create mode 100644 Nucleo-Blinky/Core/Src/main.c create mode 100644 Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c create mode 100644 Nucleo-Blinky/Core/Src/stm32g4xx_it.c create mode 100644 Nucleo-Blinky/Nucleo-Blinky.ioc diff --git a/CMakeLists.txt b/CMakeLists.txt index dd6d899d4..a6023104a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,3 +185,5 @@ add_gr_project(STM32G474xE BLINKY G4ECHO) # Onboarding Workshops add_gr_project(STM32G474xE Onboarding W3_G4SPI_Receive) add_gr_project(STM32G474xE Onboarding W3_G4SPI_Transmit) + +add_gr_project(STM32G474xE Nucleo-Blinky) diff --git a/Nucleo-Blinky/CMakeLists.txt b/Nucleo-Blinky/CMakeLists.txt new file mode 100644 index 000000000..657a90cdb --- /dev/null +++ b/Nucleo-Blinky/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.25) + +# Setup compiler settings +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) + +# Define the build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# Enable CMake support for ASM and C languages +enable_language( + C + ASM +) + +# Core project settings +project(${CMAKE_PROJECT_NAME}) + +# what, does in fact not get the filename of somthing but rather the name of the project from the path +get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) + +add_library(${PROJECT_NAME}_USER_CODE INTERFACE) +target_sources( + ${PROJECT_NAME}_USER_CODE + INTERFACE + Core/Src/gpio.c + Core/Src/main.c + Core/Src/stm32g4xx_hal_msp.c + Core/Src/stm32g4xx_it.c +) + +target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE) + +target_include_directories( + ${PROJECT_NAME}_USER_CODE + INTERFACE + Core/Inc +) diff --git a/Nucleo-Blinky/Core/Inc/gpio.h b/Nucleo-Blinky/Core/Inc/gpio.h new file mode 100644 index 000000000..3c91c4dd6 --- /dev/null +++ b/Nucleo-Blinky/Core/Inc/gpio.h @@ -0,0 +1,49 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file gpio.h + * @brief This file contains all the function prototypes for + * the gpio.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_GPIO_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ GPIO_H__ */ + diff --git a/Nucleo-Blinky/Core/Inc/main.h b/Nucleo-Blinky/Core/Inc/main.h new file mode 100644 index 000000000..e55f7d718 --- /dev/null +++ b/Nucleo-Blinky/Core/Inc/main.h @@ -0,0 +1,86 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32g4xx_hal.h" + +#include "stm32g4xx_nucleo.h" +#include + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define RCC_OSC32_IN_Pin GPIO_PIN_14 +#define RCC_OSC32_IN_GPIO_Port GPIOC +#define RCC_OSC32_OUT_Pin GPIO_PIN_15 +#define RCC_OSC32_OUT_GPIO_Port GPIOC +#define RCC_OSC_IN_Pin GPIO_PIN_0 +#define RCC_OSC_IN_GPIO_Port GPIOF +#define RCC_OSC_OUT_Pin GPIO_PIN_1 +#define RCC_OSC_OUT_GPIO_Port GPIOF +#define T_SWDIO_Pin GPIO_PIN_13 +#define T_SWDIO_GPIO_Port GPIOA +#define T_SWCLK_Pin GPIO_PIN_14 +#define T_SWCLK_GPIO_Port GPIOA +#define T_SWO_Pin GPIO_PIN_3 +#define T_SWO_GPIO_Port GPIOB + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h new file mode 100644 index 000000000..3844b8157 --- /dev/null +++ b/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h @@ -0,0 +1,380 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file + ****************************************************************************** + * @attention + * + * Copyright (c) 2019 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32G4xx_HAL_CONF_H +#define STM32G4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED + + /*#define HAL_ADC_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CORDIC_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +/*#define HAL_FDCAN_MODULE_ENABLED */ +/*#define HAL_FMAC_MODULE_ENABLED */ +/*#define HAL_HRTIM_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_I2C_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_PCD_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +/*#define HAL_RTC_MODULE_ENABLED */ +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_TIM_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Register Callbacks selection ############################## */ +/** + * @brief This is the list of modules where register callback can be used + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U +#define USE_HAL_COMP_REGISTER_CALLBACKS 0U +#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U +#define USE_HAL_EXTI_REGISTER_CALLBACKS 0U +#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U +#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U +#define USE_HAL_HRTIM_REGISTER_CALLBACKS 0U +#define USE_HAL_I2C_REGISTER_CALLBACKS 0U +#define USE_HAL_I2S_REGISTER_CALLBACKS 0U +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U +#define USE_HAL_NAND_REGISTER_CALLBACKS 0U +#define USE_HAL_NOR_REGISTER_CALLBACKS 0U +#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U +#define USE_HAL_RNG_REGISTER_CALLBACKS 0U +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U +#define USE_HAL_SAI_REGISTER_CALLBACKS 0U +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U +#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U +#define USE_HAL_TIM_REGISTER_CALLBACKS 0U +#define USE_HAL_UART_REGISTER_CALLBACKS 0U +#define USE_HAL_USART_REGISTER_CALLBACKS 0U +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE (24000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT (100UL) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE (48000000UL) /*!< Value of the Internal High Speed oscillator for USB FS/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) +/*!< Value of the Internal Low Speed oscillator in Hz +The real value may vary depending on the variations in voltage and temperature.*/ +#define LSI_VALUE (32000UL) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) +#define LSE_VALUE (32768UL) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT (5000UL) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S and SAI peripherals + * This value is used by the I2S and SAI HAL modules to compute the I2S and SAI clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) +#define EXTERNAL_CLOCK_VALUE (12288000UL) /*!< Value of the External oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY (0UL) /*!< tick interrupt priority (lowest by default) */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 0U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ + #define USE_FULL_ASSERT 1U + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED +#include "stm32g4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED +#include "stm32g4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED +#include "stm32g4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED +#include "stm32g4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED +#include "stm32g4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED +#include "stm32g4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CORDIC_MODULE_ENABLED +#include "stm32g4xx_hal_cordic.h" +#endif /* HAL_CORDIC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED +#include "stm32g4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED +#include "stm32g4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED +#include "stm32g4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED +#include "stm32g4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED +#include "stm32g4xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED +#include "stm32g4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_FMAC_MODULE_ENABLED +#include "stm32g4xx_hal_fmac.h" +#endif /* HAL_FMAC_MODULE_ENABLED */ + +#ifdef HAL_HRTIM_MODULE_ENABLED +#include "stm32g4xx_hal_hrtim.h" +#endif /* HAL_HRTIM_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED +#include "stm32g4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED +#include "stm32g4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED +#include "stm32g4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED +#include "stm32g4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32g4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED +#include "stm32g4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED +#include "stm32g4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32g4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED +#include "stm32g4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED +#include "stm32g4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED +#include "stm32g4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED +#include "stm32g4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED +#include "stm32g4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED +#include "stm32g4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED +#include "stm32g4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED +#include "stm32g4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED +#include "stm32g4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm32g4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED +#include "stm32g4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED +#include "stm32g4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED +#include "stm32g4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED +#include "stm32g4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ +#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else +#define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32G4xx_HAL_CONF_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h new file mode 100644 index 000000000..001ebdf89 --- /dev/null +++ b/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h @@ -0,0 +1,67 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32G4xx_IT_H +#define __STM32G4xx_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +void EXTI15_10_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32G4xx_IT_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h new file mode 100644 index 000000000..602b3233e --- /dev/null +++ b/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h @@ -0,0 +1,78 @@ + +/** + ****************************************************************************** + * @file stm32g4xx_nucleo_conf.h + * @author MCD Application Team + * @brief STM32G4xx_Nucleo board configuration file. + * This file should be copied to the application folder and renamed + * to stm32g4xx_nucleo_conf.h + ****************************************************************************** + * @attention + * + * Copyright (c) 2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32G4XX_NUCLEO_CONF_H +#define STM32G4XX_NUCLEO_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32g4xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32G4XX_NUCLEO + * @{ + */ + +/** @defgroup STM32G4XX_NUCLEO_CONFIG Config + * @{ + */ + +/** @defgroup STM32C0XX_NUCLEO_CONFIG_Exported_Constants Exported Constants + * @{ + */ +/* Nucleo pin and part number defines */ +#define USE_STM32G4XX_NUCLEO + +/* COM define */ +#define USE_COM_LOG 1U +#define USE_BSP_COM_FEATURE 1U + +/* IRQ priorities */ +#define BSP_BUTTON_USER_IT_PRIORITY 15U + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32G4XX_NUCLEO_CONF_H */ diff --git a/Nucleo-Blinky/Core/Src/gpio.c b/Nucleo-Blinky/Core/Src/gpio.c new file mode 100644 index 000000000..3a44fbc3e --- /dev/null +++ b/Nucleo-Blinky/Core/Src/gpio.c @@ -0,0 +1,55 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file gpio.c + * @brief This file provides code for the configuration + * of all used GPIO pins. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "gpio.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/*----------------------------------------------------------------------------*/ +/* Configure GPIO */ +/*----------------------------------------------------------------------------*/ +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** Configure pins as + * Analog + * Input + * Output + * EVENT_OUT + * EXTI +*/ +void MX_GPIO_Init(void) +{ + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + +} + +/* USER CODE BEGIN 2 */ + +/* USER CODE END 2 */ diff --git a/Nucleo-Blinky/Core/Src/main.c b/Nucleo-Blinky/Core/Src/main.c new file mode 100644 index 000000000..ab141cb7c --- /dev/null +++ b/Nucleo-Blinky/Core/Src/main.c @@ -0,0 +1,209 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ + +COM_InitTypeDef BspCOMInit; + +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + + /* USER CODE BEGIN 1 */ + + /* USER CODE END 1 */ + + /* MCU Configuration--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); + + /* USER CODE BEGIN Init */ + + /* USER CODE END Init */ + + /* Configure the system clock */ + SystemClock_Config(); + + /* USER CODE BEGIN SysInit */ + + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + /* USER CODE BEGIN 2 */ + + /* USER CODE END 2 */ + + /* Initialize led */ + BSP_LED_Init(LED_GREEN); + + /* Initialize USER push-button, will be used to trigger an interrupt each time it's pressed.*/ + BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI); + + /* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */ + BspCOMInit.BaudRate = 115200; + BspCOMInit.WordLength = COM_WORDLENGTH_8B; + BspCOMInit.StopBits = COM_STOPBITS_1; + BspCOMInit.Parity = COM_PARITY_NONE; + BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE; + if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE) + { + Error_Handler(); + } + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + HAL_Delay(100); + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin); + + if (BSP_PB_GetState(BUTTON_USER) == GPIO_PIN_SET) + { + HAL_Delay(10); + } + } + /* USER CODE END 3 */ +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4; + RCC_OscInitStruct.PLL.PLLN = 85; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) + { + Error_Handler(); + } +} + +/* USER CODE BEGIN 4 */ + +/* USER CODE END 4 */ + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +void Error_Handler(void) +{ + /* USER CODE BEGIN Error_Handler_Debug */ + /* User can add his own implementation to report the HAL error return state */ + __disable_irq(); + while (1) + { + } + /* USER CODE END Error_Handler_Debug */ +} +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c b/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c new file mode 100644 index 000000000..d908bd772 --- /dev/null +++ b/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c @@ -0,0 +1,85 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_hal_msp.c + * @brief This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral + */ + HAL_PWREx_DisableUCPDDeadBattery(); + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/Nucleo-Blinky/Core/Src/stm32g4xx_it.c b/Nucleo-Blinky/Core/Src/stm32g4xx_it.c new file mode 100644 index 000000000..f98aa5695 --- /dev/null +++ b/Nucleo-Blinky/Core/Src/stm32g4xx_it.c @@ -0,0 +1,217 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "stm32g4xx_it.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ + +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex-M4 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + while (1) + { + } + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Prefetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ + /* USER CODE BEGIN SVCall_IRQn 0 */ + + /* USER CODE END SVCall_IRQn 0 */ + /* USER CODE BEGIN SVCall_IRQn 1 */ + + /* USER CODE END SVCall_IRQn 1 */ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ + /* USER CODE BEGIN PendSV_IRQn 0 */ + + /* USER CODE END PendSV_IRQn 0 */ + /* USER CODE BEGIN PendSV_IRQn 1 */ + + /* USER CODE END PendSV_IRQn 1 */ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ + /* USER CODE BEGIN SysTick_IRQn 0 */ + + /* USER CODE END SysTick_IRQn 0 */ + HAL_IncTick(); + /* USER CODE BEGIN SysTick_IRQn 1 */ + + /* USER CODE END SysTick_IRQn 1 */ +} + +/******************************************************************************/ +/* STM32G4xx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32g4xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles EXTI line[15:10] interrupts. + */ +void EXTI15_10_IRQHandler(void) +{ + /* USER CODE BEGIN EXTI15_10_IRQn 0 */ + + /* USER CODE END EXTI15_10_IRQn 0 */ + BSP_PB_IRQHandler(BUTTON_USER); + /* USER CODE BEGIN EXTI15_10_IRQn 1 */ + + /* USER CODE END EXTI15_10_IRQn 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/Nucleo-Blinky/Nucleo-Blinky.ioc b/Nucleo-Blinky/Nucleo-Blinky.ioc new file mode 100644 index 000000000..1bc08b38e --- /dev/null +++ b/Nucleo-Blinky/Nucleo-Blinky.ioc @@ -0,0 +1,179 @@ +#MicroXplorer Configuration settings - do not modify +BSP_IP_NAME=NUCLEO-G474RE +CAD.formats= +CAD.pinconfig= +CAD.provider= +File.Version=6 +KeepUserPlacement=false +Mcu.CPN=STM32G474RET6 +Mcu.Family=STM32G4 +Mcu.IP0=NUCLEO-G474RE +Mcu.IP1=NVIC +Mcu.IP2=RCC +Mcu.IP3=SYS +Mcu.IPNb=5 +Mcu.Name=STM32G474R(B-C-E)Tx +Mcu.Package=LQFP64 +Mcu.Pin0=PC13 +Mcu.Pin1=PC14-OSC32_IN +Mcu.Pin10=PB3 +Mcu.Pin11=VP_SYS_VS_Systick +Mcu.Pin12=VP_SYS_VS_DBSignals +Mcu.Pin13=VP_NUCLEO-G474RE_VS_BSP_COMMON +Mcu.Pin2=PC15-OSC32_OUT +Mcu.Pin3=PF0-OSC_IN +Mcu.Pin4=PF1-OSC_OUT +Mcu.Pin5=PA2 +Mcu.Pin6=PA3 +Mcu.Pin7=PA5 +Mcu.Pin8=PA13 +Mcu.Pin9=PA14 +Mcu.PinsNb=14 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32G474RETx +MxCube.Version=6.18.0 +MxDb.Version=DB.6.0.180 +NUCLEO-G474RE.BUTTON=1 +NUCLEO-G474RE.IPParameters=BUTTON,LD2,VCP +NUCLEO-G474RE.LD2=true +NUCLEO-G474RE.VCP=true +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.EXTI15_10_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA13.GPIOParameters=GPIO_Label +PA13.GPIO_Label=T_SWDIO +PA13.Locked=true +PA13.Signal=SYS_JTMS-SWDIO +PA14.GPIOParameters=GPIO_Label +PA14.GPIO_Label=T_SWCLK +PA14.Locked=true +PA14.Signal=SYS_JTCK-SWCLK +PA2.Locked=true +PA2.Signal=LPUART1_TX +PA3.Locked=true +PA3.Signal=LPUART1_RX +PA5.Locked=true +PB3.GPIOParameters=GPIO_Label +PB3.GPIO_Label=T_SWO +PB3.Locked=true +PB3.Signal=SYS_JTDO-SWO +PC13.Locked=true +PC14-OSC32_IN.GPIOParameters=GPIO_Label +PC14-OSC32_IN.GPIO_Label=RCC_OSC32_IN +PC14-OSC32_IN.Locked=true +PC14-OSC32_IN.Signal=RCC_OSC32_IN +PC15-OSC32_OUT.GPIOParameters=GPIO_Label +PC15-OSC32_OUT.GPIO_Label=RCC_OSC32_OUT +PC15-OSC32_OUT.Locked=true +PC15-OSC32_OUT.Signal=RCC_OSC32_OUT +PF0-OSC_IN.GPIOParameters=GPIO_Label +PF0-OSC_IN.GPIO_Label=RCC_OSC_IN +PF0-OSC_IN.Locked=true +PF0-OSC_IN.Signal=RCC_OSC_IN +PF1-OSC_OUT.GPIOParameters=GPIO_Label +PF1-OSC_OUT.GPIO_Label=RCC_OSC_OUT +PF1-OSC_OUT.Locked=true +PF1-OSC_OUT.Signal=RCC_OSC_OUT +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32G474RETx +ProjectManager.FirmwarePackage=STM32Cube FW_G4 V1.6.3 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext= +ProjectManager.HalAssertFull=true +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=2 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=Nucleo-Blinky.ioc +ProjectManager.ProjectName=Nucleo-Blinky +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=EWARM V8.50 +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,false-0--NUCLEO-G474RE-true-HAL-true +RCC.ADC12Freq_Value=170000000 +RCC.ADC345Freq_Value=170000000 +RCC.AHBFreq_Value=170000000 +RCC.APB1Freq_Value=170000000 +RCC.APB1TimFreq_Value=170000000 +RCC.APB2Freq_Value=170000000 +RCC.APB2TimFreq_Value=170000000 +RCC.CRSFreq_Value=48000000 +RCC.CortexFreq_Value=170000000 +RCC.EXTERNAL_CLOCK_VALUE=12288000 +RCC.FCLKCortexFreq_Value=170000000 +RCC.FDCANFreq_Value=170000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=170000000 +RCC.HRTIM1Freq_Value=170000000 +RCC.HSE_VALUE=24000000 +RCC.HSI48_VALUE=48000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=170000000 +RCC.I2C2Freq_Value=170000000 +RCC.I2C3Freq_Value=170000000 +RCC.I2C4Freq_Value=170000000 +RCC.I2SFreq_Value=170000000 +RCC.IPParameters=ADC12Freq_Value,ADC345Freq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CRSFreq_Value,CortexFreq_Value,EXTERNAL_CLOCK_VALUE,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HRTIM1Freq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LPTIM1Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,PLLM,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PWRFreq_Value,QSPIFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value +RCC.LPTIM1Freq_Value=170000000 +RCC.LPUART1Freq_Value=170000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO1PinFreq_Value=16000000 +RCC.PLLM=RCC_PLLM_DIV4 +RCC.PLLN=85 +RCC.PLLPoutputFreq_Value=170000000 +RCC.PLLQoutputFreq_Value=170000000 +RCC.PLLRCLKFreq_Value=170000000 +RCC.PWRFreq_Value=170000000 +RCC.QSPIFreq_Value=170000000 +RCC.RNGFreq_Value=170000000 +RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE +RCC.RTCFreq_Value=32768 +RCC.SAI1Freq_Value=170000000 +RCC.SYSCLKFreq_VALUE=170000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.UART4Freq_Value=170000000 +RCC.UART5Freq_Value=170000000 +RCC.USART1Freq_Value=170000000 +RCC.USART2Freq_Value=170000000 +RCC.USART3Freq_Value=170000000 +RCC.USBFreq_Value=170000000 +RCC.VCOInputFreq_Value=4000000 +RCC.VCOOutputFreq_Value=340000000 +VP_NUCLEO-G474RE_VS_BSP_COMMON.Mode=COMMON +VP_NUCLEO-G474RE_VS_BSP_COMMON.Signal=NUCLEO-G474RE_VS_BSP_COMMON +VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals +VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=NUCLEO-G474RE +boardIOC=true From 5876dcfb9b6641a89e4c6e59c1f141ef553b7d84 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 9 Jul 2026 02:20:09 -0700 Subject: [PATCH 02/38] Revert "REVERT ME --- Nucleo blinky demo" This reverts commit da7387f34276a452111577b51896c4276b35a762. --- CMakeLists.txt | 2 - Nucleo-Blinky/CMakeLists.txt | 41 -- Nucleo-Blinky/Core/Inc/gpio.h | 49 --- Nucleo-Blinky/Core/Inc/main.h | 86 ---- Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h | 380 ------------------ Nucleo-Blinky/Core/Inc/stm32g4xx_it.h | 67 --- .../Core/Inc/stm32g4xx_nucleo_conf.h | 78 ---- Nucleo-Blinky/Core/Src/gpio.c | 55 --- Nucleo-Blinky/Core/Src/main.c | 209 ---------- Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c | 85 ---- Nucleo-Blinky/Core/Src/stm32g4xx_it.c | 217 ---------- Nucleo-Blinky/Nucleo-Blinky.ioc | 179 --------- 12 files changed, 1448 deletions(-) delete mode 100644 Nucleo-Blinky/CMakeLists.txt delete mode 100644 Nucleo-Blinky/Core/Inc/gpio.h delete mode 100644 Nucleo-Blinky/Core/Inc/main.h delete mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h delete mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_it.h delete mode 100644 Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h delete mode 100644 Nucleo-Blinky/Core/Src/gpio.c delete mode 100644 Nucleo-Blinky/Core/Src/main.c delete mode 100644 Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c delete mode 100644 Nucleo-Blinky/Core/Src/stm32g4xx_it.c delete mode 100644 Nucleo-Blinky/Nucleo-Blinky.ioc diff --git a/CMakeLists.txt b/CMakeLists.txt index a6023104a..dd6d899d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,5 +185,3 @@ add_gr_project(STM32G474xE BLINKY G4ECHO) # Onboarding Workshops add_gr_project(STM32G474xE Onboarding W3_G4SPI_Receive) add_gr_project(STM32G474xE Onboarding W3_G4SPI_Transmit) - -add_gr_project(STM32G474xE Nucleo-Blinky) diff --git a/Nucleo-Blinky/CMakeLists.txt b/Nucleo-Blinky/CMakeLists.txt deleted file mode 100644 index 657a90cdb..000000000 --- a/Nucleo-Blinky/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -cmake_minimum_required(VERSION 3.25) - -# Setup compiler settings -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_EXTENSIONS ON) - -# Define the build type -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# Enable CMake support for ASM and C languages -enable_language( - C - ASM -) - -# Core project settings -project(${CMAKE_PROJECT_NAME}) - -# what, does in fact not get the filename of somthing but rather the name of the project from the path -get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) - -add_library(${PROJECT_NAME}_USER_CODE INTERFACE) -target_sources( - ${PROJECT_NAME}_USER_CODE - INTERFACE - Core/Src/gpio.c - Core/Src/main.c - Core/Src/stm32g4xx_hal_msp.c - Core/Src/stm32g4xx_it.c -) - -target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE) - -target_include_directories( - ${PROJECT_NAME}_USER_CODE - INTERFACE - Core/Inc -) diff --git a/Nucleo-Blinky/Core/Inc/gpio.h b/Nucleo-Blinky/Core/Inc/gpio.h deleted file mode 100644 index 3c91c4dd6..000000000 --- a/Nucleo-Blinky/Core/Inc/gpio.h +++ /dev/null @@ -1,49 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file gpio.h - * @brief This file contains all the function prototypes for - * the gpio.c file - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __GPIO_H__ -#define __GPIO_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "main.h" - -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -void MX_GPIO_Init(void); - -/* USER CODE BEGIN Prototypes */ - -/* USER CODE END Prototypes */ - -#ifdef __cplusplus -} -#endif -#endif /*__ GPIO_H__ */ - diff --git a/Nucleo-Blinky/Core/Inc/main.h b/Nucleo-Blinky/Core/Inc/main.h deleted file mode 100644 index e55f7d718..000000000 --- a/Nucleo-Blinky/Core/Inc/main.h +++ /dev/null @@ -1,86 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MAIN_H -#define __MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32g4xx_hal.h" - -#include "stm32g4xx_nucleo.h" -#include - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); - -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -/* Private defines -----------------------------------------------------------*/ -#define RCC_OSC32_IN_Pin GPIO_PIN_14 -#define RCC_OSC32_IN_GPIO_Port GPIOC -#define RCC_OSC32_OUT_Pin GPIO_PIN_15 -#define RCC_OSC32_OUT_GPIO_Port GPIOC -#define RCC_OSC_IN_Pin GPIO_PIN_0 -#define RCC_OSC_IN_GPIO_Port GPIOF -#define RCC_OSC_OUT_Pin GPIO_PIN_1 -#define RCC_OSC_OUT_GPIO_Port GPIOF -#define T_SWDIO_Pin GPIO_PIN_13 -#define T_SWDIO_GPIO_Port GPIOA -#define T_SWCLK_Pin GPIO_PIN_14 -#define T_SWCLK_GPIO_Port GPIOA -#define T_SWO_Pin GPIO_PIN_3 -#define T_SWO_GPIO_Port GPIOB - -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MAIN_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h deleted file mode 100644 index 3844b8157..000000000 --- a/Nucleo-Blinky/Core/Inc/stm32g4xx_hal_conf.h +++ /dev/null @@ -1,380 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32g4xx_hal_conf.h - * @author MCD Application Team - * @brief HAL configuration file - ****************************************************************************** - * @attention - * - * Copyright (c) 2019 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef STM32G4xx_HAL_CONF_H -#define STM32G4xx_HAL_CONF_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ - -/* ########################## Module Selection ############################## */ -/** - * @brief This is the list of modules to be used in the HAL driver - */ - -#define HAL_MODULE_ENABLED - - /*#define HAL_ADC_MODULE_ENABLED */ -/*#define HAL_COMP_MODULE_ENABLED */ -/*#define HAL_CORDIC_MODULE_ENABLED */ -/*#define HAL_CRC_MODULE_ENABLED */ -/*#define HAL_CRYP_MODULE_ENABLED */ -/*#define HAL_DAC_MODULE_ENABLED */ -/*#define HAL_FDCAN_MODULE_ENABLED */ -/*#define HAL_FMAC_MODULE_ENABLED */ -/*#define HAL_HRTIM_MODULE_ENABLED */ -/*#define HAL_IRDA_MODULE_ENABLED */ -/*#define HAL_IWDG_MODULE_ENABLED */ -/*#define HAL_I2C_MODULE_ENABLED */ -/*#define HAL_I2S_MODULE_ENABLED */ -/*#define HAL_LPTIM_MODULE_ENABLED */ -/*#define HAL_NAND_MODULE_ENABLED */ -/*#define HAL_NOR_MODULE_ENABLED */ -/*#define HAL_OPAMP_MODULE_ENABLED */ -/*#define HAL_PCD_MODULE_ENABLED */ -/*#define HAL_QSPI_MODULE_ENABLED */ -/*#define HAL_RNG_MODULE_ENABLED */ -/*#define HAL_RTC_MODULE_ENABLED */ -/*#define HAL_SAI_MODULE_ENABLED */ -/*#define HAL_SMARTCARD_MODULE_ENABLED */ -/*#define HAL_SMBUS_MODULE_ENABLED */ -/*#define HAL_SPI_MODULE_ENABLED */ -/*#define HAL_SRAM_MODULE_ENABLED */ -/*#define HAL_TIM_MODULE_ENABLED */ -#define HAL_UART_MODULE_ENABLED -/*#define HAL_USART_MODULE_ENABLED */ -/*#define HAL_WWDG_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_EXTI_MODULE_ENABLED -#define HAL_DMA_MODULE_ENABLED -#define HAL_RCC_MODULE_ENABLED -#define HAL_FLASH_MODULE_ENABLED -#define HAL_PWR_MODULE_ENABLED -#define HAL_CORTEX_MODULE_ENABLED - -/* ########################## Register Callbacks selection ############################## */ -/** - * @brief This is the list of modules where register callback can be used - */ -#define USE_HAL_ADC_REGISTER_CALLBACKS 0U -#define USE_HAL_COMP_REGISTER_CALLBACKS 0U -#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U -#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U -#define USE_HAL_DAC_REGISTER_CALLBACKS 0U -#define USE_HAL_EXTI_REGISTER_CALLBACKS 0U -#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U -#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U -#define USE_HAL_HRTIM_REGISTER_CALLBACKS 0U -#define USE_HAL_I2C_REGISTER_CALLBACKS 0U -#define USE_HAL_I2S_REGISTER_CALLBACKS 0U -#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U -#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U -#define USE_HAL_NAND_REGISTER_CALLBACKS 0U -#define USE_HAL_NOR_REGISTER_CALLBACKS 0U -#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U -#define USE_HAL_PCD_REGISTER_CALLBACKS 0U -#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U -#define USE_HAL_RNG_REGISTER_CALLBACKS 0U -#define USE_HAL_RTC_REGISTER_CALLBACKS 0U -#define USE_HAL_SAI_REGISTER_CALLBACKS 0U -#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U -#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U -#define USE_HAL_SPI_REGISTER_CALLBACKS 0U -#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U -#define USE_HAL_TIM_REGISTER_CALLBACKS 0U -#define USE_HAL_UART_REGISTER_CALLBACKS 0U -#define USE_HAL_USART_REGISTER_CALLBACKS 0U -#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U - -/* ########################## Oscillator Values adaptation ####################*/ -/** - * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSE is used as system clock source, directly or through the PLL). - */ -#if !defined (HSE_VALUE) - #define HSE_VALUE (24000000UL) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT (100UL) /*!< Time out for HSE start up, in ms */ -#endif /* HSE_STARTUP_TIMEOUT */ - -/** - * @brief Internal High Speed oscillator (HSI) value. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSI is used as system clock source, directly or through the PLL). - */ -#if !defined (HSI_VALUE) - #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ -#endif /* HSI_VALUE */ - -/** - * @brief Internal High Speed oscillator (HSI48) value for USB FS and RNG. - * This internal oscillator is mainly dedicated to provide a high precision clock to - * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. - * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency - * which is subject to manufacturing process variations. - */ -#if !defined (HSI48_VALUE) - #define HSI48_VALUE (48000000UL) /*!< Value of the Internal High Speed oscillator for USB FS/RNG in Hz. - The real value my vary depending on manufacturing process variations.*/ -#endif /* HSI48_VALUE */ - -/** - * @brief Internal Low Speed oscillator (LSI) value. - */ -#if !defined (LSI_VALUE) -/*!< Value of the Internal Low Speed oscillator in Hz -The real value may vary depending on the variations in voltage and temperature.*/ -#define LSI_VALUE (32000UL) /*!< LSI Typical Value in Hz*/ -#endif /* LSI_VALUE */ -/** - * @brief External Low Speed oscillator (LSE) value. - * This value is used by the UART, RTC HAL module to compute the system frequency - */ -#if !defined (LSE_VALUE) -#define LSE_VALUE (32768UL) /*!< Value of the External Low Speed oscillator in Hz */ -#endif /* LSE_VALUE */ - -#if !defined (LSE_STARTUP_TIMEOUT) -#define LSE_STARTUP_TIMEOUT (5000UL) /*!< Time out for LSE start up, in ms */ -#endif /* LSE_STARTUP_TIMEOUT */ - -/** - * @brief External clock source for I2S and SAI peripherals - * This value is used by the I2S and SAI HAL modules to compute the I2S and SAI clock source - * frequency, this source is inserted directly through I2S_CKIN pad. - */ -#if !defined (EXTERNAL_CLOCK_VALUE) -#define EXTERNAL_CLOCK_VALUE (12288000UL) /*!< Value of the External oscillator in Hz*/ -#endif /* EXTERNAL_CLOCK_VALUE */ - -/* Tip: To avoid modifying this file each time you need to use different HSE, - === you can define the HSE value in your toolchain compiler preprocessor. */ - -/* ########################### System Configuration ######################### */ -/** - * @brief This is the HAL system configuration section - */ - -#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY (0UL) /*!< tick interrupt priority (lowest by default) */ -#define USE_RTOS 0U -#define PREFETCH_ENABLE 0U -#define INSTRUCTION_CACHE_ENABLE 1U -#define DATA_CACHE_ENABLE 1U - -/* ########################## Assert Selection ############################## */ -/** - * @brief Uncomment the line below to expanse the "assert_param" macro in the - * HAL drivers code - */ - #define USE_FULL_ASSERT 1U - -/* ################## SPI peripheral configuration ########################## */ - -/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver - * Activated: CRC code is present inside driver - * Deactivated: CRC code cleaned from driver - */ - -#define USE_SPI_CRC 0U - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED -#include "stm32g4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED -#include "stm32g4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED -#include "stm32g4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED -#include "stm32g4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED -#include "stm32g4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_COMP_MODULE_ENABLED -#include "stm32g4xx_hal_comp.h" -#endif /* HAL_COMP_MODULE_ENABLED */ - -#ifdef HAL_CORDIC_MODULE_ENABLED -#include "stm32g4xx_hal_cordic.h" -#endif /* HAL_CORDIC_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED -#include "stm32g4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED -#include "stm32g4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED -#include "stm32g4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_EXTI_MODULE_ENABLED -#include "stm32g4xx_hal_exti.h" -#endif /* HAL_EXTI_MODULE_ENABLED */ - -#ifdef HAL_FDCAN_MODULE_ENABLED -#include "stm32g4xx_hal_fdcan.h" -#endif /* HAL_FDCAN_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED -#include "stm32g4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_FMAC_MODULE_ENABLED -#include "stm32g4xx_hal_fmac.h" -#endif /* HAL_FMAC_MODULE_ENABLED */ - -#ifdef HAL_HRTIM_MODULE_ENABLED -#include "stm32g4xx_hal_hrtim.h" -#endif /* HAL_HRTIM_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED -#include "stm32g4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED -#include "stm32g4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED -#include "stm32g4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED -#include "stm32g4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_LPTIM_MODULE_ENABLED -#include "stm32g4xx_hal_lptim.h" -#endif /* HAL_LPTIM_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED -#include "stm32g4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED -#include "stm32g4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_OPAMP_MODULE_ENABLED -#include "stm32g4xx_hal_opamp.h" -#endif /* HAL_OPAMP_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED -#include "stm32g4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED -#include "stm32g4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_QSPI_MODULE_ENABLED -#include "stm32g4xx_hal_qspi.h" -#endif /* HAL_QSPI_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED -#include "stm32g4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED -#include "stm32g4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED -#include "stm32g4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED -#include "stm32g4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_SMBUS_MODULE_ENABLED -#include "stm32g4xx_hal_smbus.h" -#endif /* HAL_SMBUS_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED -#include "stm32g4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED -#include "stm32g4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED -#include "stm32g4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED -#include "stm32g4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED -#include "stm32g4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED -#include "stm32g4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -/* Exported macro ------------------------------------------------------------*/ -#ifdef USE_FULL_ASSERT -/** - * @brief The assert_param macro is used for function's parameters check. - * @param expr: If expr is false, it calls assert_failed function - * which reports the name of the source file and the source - * line number of the call that failed. - * If expr is true, it returns no value. - * @retval None - */ -#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) -/* Exported functions ------------------------------------------------------- */ -void assert_failed(uint8_t *file, uint32_t line); -#else -#define assert_param(expr) ((void)0U) -#endif /* USE_FULL_ASSERT */ - -#ifdef __cplusplus -} -#endif - -#endif /* STM32G4xx_HAL_CONF_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h deleted file mode 100644 index 001ebdf89..000000000 --- a/Nucleo-Blinky/Core/Inc/stm32g4xx_it.h +++ /dev/null @@ -1,67 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32g4xx_it.h - * @brief This file contains the headers of the interrupt handlers. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32G4xx_IT_H -#define __STM32G4xx_IT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void NMI_Handler(void); -void HardFault_Handler(void); -void MemManage_Handler(void); -void BusFault_Handler(void); -void UsageFault_Handler(void); -void SVC_Handler(void); -void DebugMon_Handler(void); -void PendSV_Handler(void); -void SysTick_Handler(void); -void EXTI15_10_IRQHandler(void); -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32G4xx_IT_H */ diff --git a/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h b/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h deleted file mode 100644 index 602b3233e..000000000 --- a/Nucleo-Blinky/Core/Inc/stm32g4xx_nucleo_conf.h +++ /dev/null @@ -1,78 +0,0 @@ - -/** - ****************************************************************************** - * @file stm32g4xx_nucleo_conf.h - * @author MCD Application Team - * @brief STM32G4xx_Nucleo board configuration file. - * This file should be copied to the application folder and renamed - * to stm32g4xx_nucleo_conf.h - ****************************************************************************** - * @attention - * - * Copyright (c) 2022 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef STM32G4XX_NUCLEO_CONF_H -#define STM32G4XX_NUCLEO_CONF_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32g4xx_hal.h" - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup STM32G4XX_NUCLEO - * @{ - */ - -/** @defgroup STM32G4XX_NUCLEO_CONFIG Config - * @{ - */ - -/** @defgroup STM32C0XX_NUCLEO_CONFIG_Exported_Constants Exported Constants - * @{ - */ -/* Nucleo pin and part number defines */ -#define USE_STM32G4XX_NUCLEO - -/* COM define */ -#define USE_COM_LOG 1U -#define USE_BSP_COM_FEATURE 1U - -/* IRQ priorities */ -#define BSP_BUTTON_USER_IT_PRIORITY 15U - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* STM32G4XX_NUCLEO_CONF_H */ diff --git a/Nucleo-Blinky/Core/Src/gpio.c b/Nucleo-Blinky/Core/Src/gpio.c deleted file mode 100644 index 3a44fbc3e..000000000 --- a/Nucleo-Blinky/Core/Src/gpio.c +++ /dev/null @@ -1,55 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file gpio.c - * @brief This file provides code for the configuration - * of all used GPIO pins. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "gpio.h" - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/*----------------------------------------------------------------------------*/ -/* Configure GPIO */ -/*----------------------------------------------------------------------------*/ -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ - -/** Configure pins as - * Analog - * Input - * Output - * EVENT_OUT - * EXTI -*/ -void MX_GPIO_Init(void) -{ - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOF_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - -} - -/* USER CODE BEGIN 2 */ - -/* USER CODE END 2 */ diff --git a/Nucleo-Blinky/Core/Src/main.c b/Nucleo-Blinky/Core/Src/main.c deleted file mode 100644 index ab141cb7c..000000000 --- a/Nucleo-Blinky/Core/Src/main.c +++ /dev/null @@ -1,209 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "gpio.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN PTD */ - -/* USER CODE END PTD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ - -COM_InitTypeDef BspCOMInit; - -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -void SystemClock_Config(void); -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/** - * @brief The application entry point. - * @retval int - */ -int main(void) -{ - - /* USER CODE BEGIN 1 */ - - /* USER CODE END 1 */ - - /* MCU Configuration--------------------------------------------------------*/ - - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); - - /* USER CODE BEGIN Init */ - - /* USER CODE END Init */ - - /* Configure the system clock */ - SystemClock_Config(); - - /* USER CODE BEGIN SysInit */ - - /* USER CODE END SysInit */ - - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - /* USER CODE BEGIN 2 */ - - /* USER CODE END 2 */ - - /* Initialize led */ - BSP_LED_Init(LED_GREEN); - - /* Initialize USER push-button, will be used to trigger an interrupt each time it's pressed.*/ - BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI); - - /* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */ - BspCOMInit.BaudRate = 115200; - BspCOMInit.WordLength = COM_WORDLENGTH_8B; - BspCOMInit.StopBits = COM_STOPBITS_1; - BspCOMInit.Parity = COM_PARITY_NONE; - BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE; - if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE) - { - Error_Handler(); - } - - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - HAL_Delay(100); - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin); - - if (BSP_PB_GetState(BUTTON_USER) == GPIO_PIN_SET) - { - HAL_Delay(10); - } - } - /* USER CODE END 3 */ -} - -/** - * @brief System Clock Configuration - * @retval None - */ -void SystemClock_Config(void) -{ - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - - /** Configure the main internal regulator output voltage - */ - HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); - - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; - RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4; - RCC_OscInitStruct.PLL.PLLN = 85; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; - RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - - /** Initializes the CPU, AHB and APB buses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) - { - Error_Handler(); - } -} - -/* USER CODE BEGIN 4 */ - -/* USER CODE END 4 */ - -/** - * @brief This function is executed in case of error occurrence. - * @retval None - */ -void Error_Handler(void) -{ - /* USER CODE BEGIN Error_Handler_Debug */ - /* User can add his own implementation to report the HAL error return state */ - __disable_irq(); - while (1) - { - } - /* USER CODE END Error_Handler_Debug */ -} -#ifdef USE_FULL_ASSERT -/** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ -void assert_failed(uint8_t *file, uint32_t line) -{ - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ -} -#endif /* USE_FULL_ASSERT */ diff --git a/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c b/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c deleted file mode 100644 index d908bd772..000000000 --- a/Nucleo-Blinky/Core/Src/stm32g4xx_hal_msp.c +++ /dev/null @@ -1,85 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32g4xx_hal_msp.c - * @brief This file provides code for the MSP Initialization - * and de-Initialization codes. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN Define */ - -/* USER CODE END Define */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN Macro */ - -/* USER CODE END Macro */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* External functions --------------------------------------------------------*/ -/* USER CODE BEGIN ExternalFunctions */ - -/* USER CODE END ExternalFunctions */ - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ -/** - * Initializes the Global MSP. - */ -void HAL_MspInit(void) -{ - - /* USER CODE BEGIN MspInit 0 */ - - /* USER CODE END MspInit 0 */ - - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - /* System interrupt init*/ - - /** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral - */ - HAL_PWREx_DisableUCPDDeadBattery(); - - /* USER CODE BEGIN MspInit 1 */ - - /* USER CODE END MspInit 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ diff --git a/Nucleo-Blinky/Core/Src/stm32g4xx_it.c b/Nucleo-Blinky/Core/Src/stm32g4xx_it.c deleted file mode 100644 index f98aa5695..000000000 --- a/Nucleo-Blinky/Core/Src/stm32g4xx_it.c +++ /dev/null @@ -1,217 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32g4xx_it.c - * @brief Interrupt Service Routines. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "stm32g4xx_it.h" -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/* External variables --------------------------------------------------------*/ - -/* USER CODE BEGIN EV */ - -/* USER CODE END EV */ - -/******************************************************************************/ -/* Cortex-M4 Processor Interruption and Exception Handlers */ -/******************************************************************************/ -/** - * @brief This function handles Non maskable interrupt. - */ -void NMI_Handler(void) -{ - /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ - - /* USER CODE END NonMaskableInt_IRQn 0 */ - /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ - while (1) - { - } - /* USER CODE END NonMaskableInt_IRQn 1 */ -} - -/** - * @brief This function handles Hard fault interrupt. - */ -void HardFault_Handler(void) -{ - /* USER CODE BEGIN HardFault_IRQn 0 */ - - /* USER CODE END HardFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_HardFault_IRQn 0 */ - /* USER CODE END W1_HardFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Memory management fault. - */ -void MemManage_Handler(void) -{ - /* USER CODE BEGIN MemoryManagement_IRQn 0 */ - - /* USER CODE END MemoryManagement_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ - /* USER CODE END W1_MemoryManagement_IRQn 0 */ - } -} - -/** - * @brief This function handles Prefetch fault, memory access fault. - */ -void BusFault_Handler(void) -{ - /* USER CODE BEGIN BusFault_IRQn 0 */ - - /* USER CODE END BusFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_BusFault_IRQn 0 */ - /* USER CODE END W1_BusFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Undefined instruction or illegal state. - */ -void UsageFault_Handler(void) -{ - /* USER CODE BEGIN UsageFault_IRQn 0 */ - - /* USER CODE END UsageFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ - /* USER CODE END W1_UsageFault_IRQn 0 */ - } -} - -/** - * @brief This function handles System service call via SWI instruction. - */ -void SVC_Handler(void) -{ - /* USER CODE BEGIN SVCall_IRQn 0 */ - - /* USER CODE END SVCall_IRQn 0 */ - /* USER CODE BEGIN SVCall_IRQn 1 */ - - /* USER CODE END SVCall_IRQn 1 */ -} - -/** - * @brief This function handles Debug monitor. - */ -void DebugMon_Handler(void) -{ - /* USER CODE BEGIN DebugMonitor_IRQn 0 */ - - /* USER CODE END DebugMonitor_IRQn 0 */ - /* USER CODE BEGIN DebugMonitor_IRQn 1 */ - - /* USER CODE END DebugMonitor_IRQn 1 */ -} - -/** - * @brief This function handles Pendable request for system service. - */ -void PendSV_Handler(void) -{ - /* USER CODE BEGIN PendSV_IRQn 0 */ - - /* USER CODE END PendSV_IRQn 0 */ - /* USER CODE BEGIN PendSV_IRQn 1 */ - - /* USER CODE END PendSV_IRQn 1 */ -} - -/** - * @brief This function handles System tick timer. - */ -void SysTick_Handler(void) -{ - /* USER CODE BEGIN SysTick_IRQn 0 */ - - /* USER CODE END SysTick_IRQn 0 */ - HAL_IncTick(); - /* USER CODE BEGIN SysTick_IRQn 1 */ - - /* USER CODE END SysTick_IRQn 1 */ -} - -/******************************************************************************/ -/* STM32G4xx Peripheral Interrupt Handlers */ -/* Add here the Interrupt Handlers for the used peripherals. */ -/* For the available peripheral interrupt handler names, */ -/* please refer to the startup file (startup_stm32g4xx.s). */ -/******************************************************************************/ - -/** - * @brief This function handles EXTI line[15:10] interrupts. - */ -void EXTI15_10_IRQHandler(void) -{ - /* USER CODE BEGIN EXTI15_10_IRQn 0 */ - - /* USER CODE END EXTI15_10_IRQn 0 */ - BSP_PB_IRQHandler(BUTTON_USER); - /* USER CODE BEGIN EXTI15_10_IRQn 1 */ - - /* USER CODE END EXTI15_10_IRQn 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ diff --git a/Nucleo-Blinky/Nucleo-Blinky.ioc b/Nucleo-Blinky/Nucleo-Blinky.ioc deleted file mode 100644 index 1bc08b38e..000000000 --- a/Nucleo-Blinky/Nucleo-Blinky.ioc +++ /dev/null @@ -1,179 +0,0 @@ -#MicroXplorer Configuration settings - do not modify -BSP_IP_NAME=NUCLEO-G474RE -CAD.formats= -CAD.pinconfig= -CAD.provider= -File.Version=6 -KeepUserPlacement=false -Mcu.CPN=STM32G474RET6 -Mcu.Family=STM32G4 -Mcu.IP0=NUCLEO-G474RE -Mcu.IP1=NVIC -Mcu.IP2=RCC -Mcu.IP3=SYS -Mcu.IPNb=5 -Mcu.Name=STM32G474R(B-C-E)Tx -Mcu.Package=LQFP64 -Mcu.Pin0=PC13 -Mcu.Pin1=PC14-OSC32_IN -Mcu.Pin10=PB3 -Mcu.Pin11=VP_SYS_VS_Systick -Mcu.Pin12=VP_SYS_VS_DBSignals -Mcu.Pin13=VP_NUCLEO-G474RE_VS_BSP_COMMON -Mcu.Pin2=PC15-OSC32_OUT -Mcu.Pin3=PF0-OSC_IN -Mcu.Pin4=PF1-OSC_OUT -Mcu.Pin5=PA2 -Mcu.Pin6=PA3 -Mcu.Pin7=PA5 -Mcu.Pin8=PA13 -Mcu.Pin9=PA14 -Mcu.PinsNb=14 -Mcu.ThirdPartyNb=0 -Mcu.UserConstants= -Mcu.UserName=STM32G474RETx -MxCube.Version=6.18.0 -MxDb.Version=DB.6.0.180 -NUCLEO-G474RE.BUTTON=1 -NUCLEO-G474RE.IPParameters=BUTTON,LD2,VCP -NUCLEO-G474RE.LD2=true -NUCLEO-G474RE.VCP=true -NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.EXTI15_10_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true -NVIC.ForceEnableDMAVector=true -NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 -NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false -NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -PA13.GPIOParameters=GPIO_Label -PA13.GPIO_Label=T_SWDIO -PA13.Locked=true -PA13.Signal=SYS_JTMS-SWDIO -PA14.GPIOParameters=GPIO_Label -PA14.GPIO_Label=T_SWCLK -PA14.Locked=true -PA14.Signal=SYS_JTCK-SWCLK -PA2.Locked=true -PA2.Signal=LPUART1_TX -PA3.Locked=true -PA3.Signal=LPUART1_RX -PA5.Locked=true -PB3.GPIOParameters=GPIO_Label -PB3.GPIO_Label=T_SWO -PB3.Locked=true -PB3.Signal=SYS_JTDO-SWO -PC13.Locked=true -PC14-OSC32_IN.GPIOParameters=GPIO_Label -PC14-OSC32_IN.GPIO_Label=RCC_OSC32_IN -PC14-OSC32_IN.Locked=true -PC14-OSC32_IN.Signal=RCC_OSC32_IN -PC15-OSC32_OUT.GPIOParameters=GPIO_Label -PC15-OSC32_OUT.GPIO_Label=RCC_OSC32_OUT -PC15-OSC32_OUT.Locked=true -PC15-OSC32_OUT.Signal=RCC_OSC32_OUT -PF0-OSC_IN.GPIOParameters=GPIO_Label -PF0-OSC_IN.GPIO_Label=RCC_OSC_IN -PF0-OSC_IN.Locked=true -PF0-OSC_IN.Signal=RCC_OSC_IN -PF1-OSC_OUT.GPIOParameters=GPIO_Label -PF1-OSC_OUT.GPIO_Label=RCC_OSC_OUT -PF1-OSC_OUT.Locked=true -PF1-OSC_OUT.Signal=RCC_OSC_OUT -PinOutPanel.RotationAngle=0 -ProjectManager.AskForMigrate=true -ProjectManager.BackupPrevious=false -ProjectManager.CompilerLinker=GCC -ProjectManager.CompilerOptimize=6 -ProjectManager.ComputerToolchain=false -ProjectManager.CoupleFile=true -ProjectManager.CustomerFirmwarePackage= -ProjectManager.DefaultFWLocation=true -ProjectManager.DeletePrevious=true -ProjectManager.DeviceId=STM32G474RETx -ProjectManager.FirmwarePackage=STM32Cube FW_G4 V1.6.3 -ProjectManager.FreePins=false -ProjectManager.FreePinsContext= -ProjectManager.HalAssertFull=true -ProjectManager.HeapSize=0x200 -ProjectManager.KeepUserCode=true -ProjectManager.LastFirmware=true -ProjectManager.LibraryCopy=2 -ProjectManager.MainLocation=Core/Src -ProjectManager.NoMain=false -ProjectManager.PreviousToolchain= -ProjectManager.ProjectBuild=false -ProjectManager.ProjectFileName=Nucleo-Blinky.ioc -ProjectManager.ProjectName=Nucleo-Blinky -ProjectManager.ProjectStructure= -ProjectManager.RegisterCallBack= -ProjectManager.StackSize=0x400 -ProjectManager.TargetToolchain=EWARM V8.50 -ProjectManager.ToolChainLocation= -ProjectManager.UAScriptAfterPath= -ProjectManager.UAScriptBeforePath= -ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,false-0--NUCLEO-G474RE-true-HAL-true -RCC.ADC12Freq_Value=170000000 -RCC.ADC345Freq_Value=170000000 -RCC.AHBFreq_Value=170000000 -RCC.APB1Freq_Value=170000000 -RCC.APB1TimFreq_Value=170000000 -RCC.APB2Freq_Value=170000000 -RCC.APB2TimFreq_Value=170000000 -RCC.CRSFreq_Value=48000000 -RCC.CortexFreq_Value=170000000 -RCC.EXTERNAL_CLOCK_VALUE=12288000 -RCC.FCLKCortexFreq_Value=170000000 -RCC.FDCANFreq_Value=170000000 -RCC.FamilyName=M -RCC.HCLKFreq_Value=170000000 -RCC.HRTIM1Freq_Value=170000000 -RCC.HSE_VALUE=24000000 -RCC.HSI48_VALUE=48000000 -RCC.HSI_VALUE=16000000 -RCC.I2C1Freq_Value=170000000 -RCC.I2C2Freq_Value=170000000 -RCC.I2C3Freq_Value=170000000 -RCC.I2C4Freq_Value=170000000 -RCC.I2SFreq_Value=170000000 -RCC.IPParameters=ADC12Freq_Value,ADC345Freq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CRSFreq_Value,CortexFreq_Value,EXTERNAL_CLOCK_VALUE,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HRTIM1Freq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LPTIM1Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,PLLM,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PWRFreq_Value,QSPIFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value -RCC.LPTIM1Freq_Value=170000000 -RCC.LPUART1Freq_Value=170000000 -RCC.LSCOPinFreq_Value=32000 -RCC.LSE_VALUE=32768 -RCC.LSI_VALUE=32000 -RCC.MCO1PinFreq_Value=16000000 -RCC.PLLM=RCC_PLLM_DIV4 -RCC.PLLN=85 -RCC.PLLPoutputFreq_Value=170000000 -RCC.PLLQoutputFreq_Value=170000000 -RCC.PLLRCLKFreq_Value=170000000 -RCC.PWRFreq_Value=170000000 -RCC.QSPIFreq_Value=170000000 -RCC.RNGFreq_Value=170000000 -RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE -RCC.RTCFreq_Value=32768 -RCC.SAI1Freq_Value=170000000 -RCC.SYSCLKFreq_VALUE=170000000 -RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK -RCC.UART4Freq_Value=170000000 -RCC.UART5Freq_Value=170000000 -RCC.USART1Freq_Value=170000000 -RCC.USART2Freq_Value=170000000 -RCC.USART3Freq_Value=170000000 -RCC.USBFreq_Value=170000000 -RCC.VCOInputFreq_Value=4000000 -RCC.VCOOutputFreq_Value=340000000 -VP_NUCLEO-G474RE_VS_BSP_COMMON.Mode=COMMON -VP_NUCLEO-G474RE_VS_BSP_COMMON.Signal=NUCLEO-G474RE_VS_BSP_COMMON -VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals -VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals -VP_SYS_VS_Systick.Mode=SysTick -VP_SYS_VS_Systick.Signal=SYS_VS_Systick -board=NUCLEO-G474RE -boardIOC=true From 888c569a9cddfd0e30ddf2c17134d1b50e24bb20 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 9 Jul 2026 22:13:05 -0700 Subject: [PATCH 03/38] Initial skeleton commit Signed-off-by: Daniel Hansen --- CMakeLists.txt | 1 + Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 6 ++++++ Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 6 ++++++ Lib/Peripherals/CubeCAN/Src/can_clock.c | 0 Lib/Peripherals/CubeCAN/Src/can_it.c | 0 Lib/Peripherals/CubeCAN/Src/can_utils.c | 0 Lib/Peripherals/CubeCAN/cubemx_can.cmake | 17 +++++++++++++++++ 7 files changed, 30 insertions(+) create mode 100644 Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h create mode 100644 Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h create mode 100644 Lib/Peripherals/CubeCAN/Src/can_clock.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_it.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_utils.c create mode 100644 Lib/Peripherals/CubeCAN/cubemx_can.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dd6d899d4..c729556c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ include("Autogen/CAN/CANfigurator.cmake") include("${lib_path}/Peripherals/USART/common.cmake") include("${lib_path}/Peripherals/TimedCAN/common.cmake") include("${lib_path}/Peripherals/CAN/common.cmake") +include("${lib_path}/Peripherals/CubeCAN/cubemx_can.cmake") include("${lib_path}/FancyLayers-RENAME/GRCAN/grcan_fancylayer.cmake") include("${lib_path}/FancyLayers-RENAME/ADC/adc.cmake") diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h new file mode 100644 index 000000000..0bac3f962 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -0,0 +1,6 @@ +#ifndef CUBEMX_CAN_H +#define CUBEMX_CAN_H + +// TODO + +#endif diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h new file mode 100644 index 000000000..2b6c3c544 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -0,0 +1,6 @@ +#ifndef CUBEMX_CAN_EXT_H +#define CUBEMX_CAN_EXT_H + +// TODO + +#endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_clock.c b/Lib/Peripherals/CubeCAN/Src/can_clock.c new file mode 100644 index 000000000..e69de29bb diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c new file mode 100644 index 000000000..e69de29bb diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c new file mode 100644 index 000000000..e69de29bb diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake new file mode 100644 index 000000000..ab7d9470e --- /dev/null +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -0,0 +1,17 @@ +add_library(CUBEMX_CAN_LIB INTERFACE) + +target_include_directories( + CUBEMX_CAN_LIB + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/Inc +) + +target_sources( + CUBEMX_CAN_LIB + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/Src/can_it.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_clock.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_utils.c +) + +# TODO Unit testing From 729d331f20f1c9f4cef1b20f54e9f4685c687251 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 9 Jul 2026 23:21:21 -0700 Subject: [PATCH 04/38] Completely random test project Signed-off-by: Daniel Hansen --- CMakeLists.txt | 1 + CUBEMXTESTING/Application/Inc/loop.h | 6 + CUBEMXTESTING/Application/Inc/vcp_config.h | 8 + CUBEMXTESTING/Application/Src/loop.c | 17 + CUBEMXTESTING/CMakeLists.txt | 43 +++ CUBEMXTESTING/CUBEMXTESTING.ioc | 175 +++++++++ CUBEMXTESTING/Core/Inc/fdcan.h | 55 +++ CUBEMXTESTING/Core/Inc/gpio.h | 49 +++ CUBEMXTESTING/Core/Inc/main.h | 84 +++++ CUBEMXTESTING/Core/Inc/stm32_assert.h | 53 +++ CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h | 380 ++++++++++++++++++++ CUBEMXTESTING/Core/Inc/stm32g4xx_it.h | 66 ++++ CUBEMXTESTING/Core/Src/fdcan.c | 224 ++++++++++++ CUBEMXTESTING/Core/Src/gpio.c | 347 ++++++++++++++++++ CUBEMXTESTING/Core/Src/main.c | 209 +++++++++++ CUBEMXTESTING/Core/Src/stm32g4xx_it.c | 203 +++++++++++ 16 files changed, 1920 insertions(+) create mode 100644 CUBEMXTESTING/Application/Inc/loop.h create mode 100644 CUBEMXTESTING/Application/Inc/vcp_config.h create mode 100644 CUBEMXTESTING/Application/Src/loop.c create mode 100644 CUBEMXTESTING/CMakeLists.txt create mode 100644 CUBEMXTESTING/CUBEMXTESTING.ioc create mode 100644 CUBEMXTESTING/Core/Inc/fdcan.h create mode 100644 CUBEMXTESTING/Core/Inc/gpio.h create mode 100644 CUBEMXTESTING/Core/Inc/main.h create mode 100644 CUBEMXTESTING/Core/Inc/stm32_assert.h create mode 100644 CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h create mode 100644 CUBEMXTESTING/Core/Inc/stm32g4xx_it.h create mode 100644 CUBEMXTESTING/Core/Src/fdcan.c create mode 100644 CUBEMXTESTING/Core/Src/gpio.c create mode 100644 CUBEMXTESTING/Core/Src/main.c create mode 100644 CUBEMXTESTING/Core/Src/stm32g4xx_it.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c729556c6..86537662b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ add_gr_project(STM32G474xE G4PERTESTING) add_gr_project(STM32G474xE G4SPITESTING) add_gr_project(STM32G474xE G4ADCTESTING) add_gr_project(STM32G474xE G4NEOTESTING) +add_gr_project(STM32G474xE CUBEMXTESTING) # CAN Peripheral Testing add_gr_project(STM32G474xE G474xE_CAN_TESTING CAN_BASIC_TEST) diff --git a/CUBEMXTESTING/Application/Inc/loop.h b/CUBEMXTESTING/Application/Inc/loop.h new file mode 100644 index 000000000..4b447f829 --- /dev/null +++ b/CUBEMXTESTING/Application/Inc/loop.h @@ -0,0 +1,6 @@ +#ifndef LOOP_H +#define LOOP_H + +void MainLoop(void); + +#endif diff --git a/CUBEMXTESTING/Application/Inc/vcp_config.h b/CUBEMXTESTING/Application/Inc/vcp_config.h new file mode 100644 index 000000000..77a62a7f7 --- /dev/null +++ b/CUBEMXTESTING/Application/Inc/vcp_config.h @@ -0,0 +1,8 @@ +#ifndef VCP_CONFIG +#define VCP_CONFIG + +#define VCP_CONFIG_CLAIM_USART2 + +#define VCP_TX_BUFFER_SIZE 128 + +#endif diff --git a/CUBEMXTESTING/Application/Src/loop.c b/CUBEMXTESTING/Application/Src/loop.c new file mode 100644 index 000000000..5e1d17751 --- /dev/null +++ b/CUBEMXTESTING/Application/Src/loop.c @@ -0,0 +1,17 @@ +#include "loop.h" + +#include "Logomatic.h" +#include "main.h" + +void MainLoop(void) +{ + LL_GPIO_TogglePin(USER_LED_GPIO_Port, USER_LED_Pin); + + if (LL_GPIO_IsInputPinSet(USER_BUTTON_GPIO_Port, USER_BUTTON_Pin)) { + LL_GPIO_SetOutputPin(USER_LED_GPIO_Port, USER_LED_Pin); + } else { + LL_GPIO_ResetOutputPin(USER_LED_GPIO_Port, USER_LED_Pin); + } + + LOGOMATIC("Doing things!\n"); +} diff --git a/CUBEMXTESTING/CMakeLists.txt b/CUBEMXTESTING/CMakeLists.txt new file mode 100644 index 000000000..7b5232e56 --- /dev/null +++ b/CUBEMXTESTING/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.25) + +# Setup compiler settings +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) + +# Define the build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# Enable CMake support for ASM and C languages +enable_language( + C + ASM +) + +# Core project settings +project(${CMAKE_PROJECT_NAME}) + +# what, does in fact not get the filename of somthing but rather the name of the project from the path +get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) + +add_library(${PROJECT_NAME}_USER_CODE INTERFACE) +target_sources( + ${PROJECT_NAME}_USER_CODE + INTERFACE + Application/Src/loop.c + Core/Src/fdcan.c + Core/Src/gpio.c + Core/Src/main.c + Core/Src/stm32g4xx_it.c +) + +target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB) + +target_include_directories( + ${PROJECT_NAME}_USER_CODE + INTERFACE + Core/Inc + Application/Inc +) diff --git a/CUBEMXTESTING/CUBEMXTESTING.ioc b/CUBEMXTESTING/CUBEMXTESTING.ioc new file mode 100644 index 000000000..be9a705f8 --- /dev/null +++ b/CUBEMXTESTING/CUBEMXTESTING.ioc @@ -0,0 +1,175 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats=[] +CAD.pinconfig=Dual +CAD.provider= +FDCAN1.AutoRetransmission=ENABLE +FDCAN1.CalculateBaudRateNominal=1000000 +FDCAN1.CalculateTimeBitNominal=1000 +FDCAN1.CalculateTimeQuantumNominal=6.25 +FDCAN1.DataPrescaler=8 +FDCAN1.DataSyncJumpWidth=16 +FDCAN1.DataTimeSeg1=14 +FDCAN1.DataTimeSeg2=5 +FDCAN1.ExtFiltersNbr=2 +FDCAN1.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,NominalSyncJumpWidth,AutoRetransmission,ProtocolException,DataPrescaler,DataSyncJumpWidth,DataTimeSeg1,DataTimeSeg2,ExtFiltersNbr,NominalPrescaler,NominalTimeSeg1,NominalTimeSeg2 +FDCAN1.NominalPrescaler=1 +FDCAN1.NominalSyncJumpWidth=16 +FDCAN1.NominalTimeSeg1=119 +FDCAN1.NominalTimeSeg2=40 +FDCAN1.ProtocolException=ENABLE +FDCAN2.AutoRetransmission=ENABLE +FDCAN2.CalculateBaudRateNominal=1000000 +FDCAN2.CalculateTimeBitNominal=1000 +FDCAN2.CalculateTimeQuantumNominal=6.25 +FDCAN2.DataPrescaler=8 +FDCAN2.DataSyncJumpWidth=16 +FDCAN2.DataTimeSeg1=14 +FDCAN2.DataTimeSeg2=5 +FDCAN2.ExtFiltersNbr=2 +FDCAN2.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,AutoRetransmission,ProtocolException,NominalSyncJumpWidth,DataPrescaler,DataSyncJumpWidth,DataTimeSeg1,DataTimeSeg2,ExtFiltersNbr,NominalPrescaler,NominalTimeSeg1,NominalTimeSeg2 +FDCAN2.NominalPrescaler=1 +FDCAN2.NominalSyncJumpWidth=16 +FDCAN2.NominalTimeSeg1=119 +FDCAN2.NominalTimeSeg2=40 +FDCAN2.ProtocolException=ENABLE +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=false +Mcu.CPN=STM32G474RET6 +Mcu.Family=STM32G4 +Mcu.IP0=FDCAN1 +Mcu.IP1=FDCAN2 +Mcu.IP2=NVIC +Mcu.IP3=RCC +Mcu.IP4=SYS +Mcu.IPNb=5 +Mcu.Name=STM32G474R(B-C-E)Tx +Mcu.Package=LQFP64 +Mcu.Pin0=PC13 +Mcu.Pin1=PA5 +Mcu.Pin2=PB12 +Mcu.Pin3=PB13 +Mcu.Pin4=PB8-BOOT0 +Mcu.Pin5=PB9 +Mcu.Pin6=VP_SYS_VS_Systick +Mcu.Pin7=VP_SYS_VS_DBSignals +Mcu.PinsNb=8 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32G474RETx +MxCube.Version=6.18.0 +MxDb.Version=DB.6.0.180 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.ForceEnableDMAVector=false +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA5.GPIOParameters=GPIO_Label +PA5.GPIO_Label=USER_LED +PA5.Locked=true +PA5.Signal=GPIO_Output +PB12.Mode=FDCAN_Activate +PB12.Signal=FDCAN2_RX +PB13.Mode=FDCAN_Activate +PB13.Signal=FDCAN2_TX +PB8-BOOT0.Mode=FDCAN_Activate +PB8-BOOT0.Signal=FDCAN1_RX +PB9.Mode=FDCAN_Activate +PB9.Signal=FDCAN1_TX +PC13.GPIOParameters=GPIO_Label +PC13.GPIO_Label=USER_BUTTON +PC13.Locked=true +PC13.Signal=GPIO_Input +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32G474RETx +ProjectManager.FirmwarePackage=STM32Cube FW_G4 V1.6.3 +ProjectManager.FreePins=true +ProjectManager.FreePinsContext= +ProjectManager.HalAssertFull=true +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=2 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=CUBEMXTESTING.ioc +ProjectManager.ProjectName=CUBEMXTESTING +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=EWARM V8.50 +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_FDCAN2_Init-FDCAN2-false-HAL-true +RCC.ADC12Freq_Value=160000000 +RCC.ADC345Freq_Value=160000000 +RCC.AHBFreq_Value=160000000 +RCC.APB1Freq_Value=160000000 +RCC.APB1TimFreq_Value=160000000 +RCC.APB2Freq_Value=160000000 +RCC.APB2TimFreq_Value=160000000 +RCC.CRSFreq_Value=48000000 +RCC.CortexFreq_Value=160000000 +RCC.EXTERNAL_CLOCK_VALUE=12288000 +RCC.FCLKCortexFreq_Value=160000000 +RCC.FDCANFreq_Value=160000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=160000000 +RCC.HRTIM1Freq_Value=160000000 +RCC.HSE_VALUE=16000000 +RCC.HSI48_VALUE=48000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=160000000 +RCC.I2C2Freq_Value=160000000 +RCC.I2C3Freq_Value=160000000 +RCC.I2C4Freq_Value=160000000 +RCC.I2SFreq_Value=160000000 +RCC.IPParameters=ADC12Freq_Value,ADC345Freq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CRSFreq_Value,CortexFreq_Value,EXTERNAL_CLOCK_VALUE,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HRTIM1Freq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LPTIM1Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PWRFreq_Value,QSPIFreq_Value,RNGFreq_Value,SAI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value +RCC.LPTIM1Freq_Value=160000000 +RCC.LPUART1Freq_Value=160000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO1PinFreq_Value=16000000 +RCC.PLLN=20 +RCC.PLLPoutputFreq_Value=160000000 +RCC.PLLQoutputFreq_Value=160000000 +RCC.PLLRCLKFreq_Value=160000000 +RCC.PWRFreq_Value=160000000 +RCC.QSPIFreq_Value=160000000 +RCC.RNGFreq_Value=160000000 +RCC.SAI1Freq_Value=160000000 +RCC.SYSCLKFreq_VALUE=160000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.UART4Freq_Value=160000000 +RCC.UART5Freq_Value=160000000 +RCC.USART1Freq_Value=160000000 +RCC.USART2Freq_Value=160000000 +RCC.USART3Freq_Value=160000000 +RCC.USBFreq_Value=160000000 +RCC.VCOInputFreq_Value=16000000 +RCC.VCOOutputFreq_Value=320000000 +VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals +VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=custom diff --git a/CUBEMXTESTING/Core/Inc/fdcan.h b/CUBEMXTESTING/Core/Inc/fdcan.h new file mode 100644 index 000000000..b0fa74968 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/fdcan.h @@ -0,0 +1,55 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file fdcan.h + * @brief This file contains all the function prototypes for + * the fdcan.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __FDCAN_H__ +#define __FDCAN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern FDCAN_HandleTypeDef hfdcan1; + +extern FDCAN_HandleTypeDef hfdcan2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_FDCAN1_Init(void); +void MX_FDCAN2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __FDCAN_H__ */ + diff --git a/CUBEMXTESTING/Core/Inc/gpio.h b/CUBEMXTESTING/Core/Inc/gpio.h new file mode 100644 index 000000000..3c91c4dd6 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/gpio.h @@ -0,0 +1,49 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file gpio.h + * @brief This file contains all the function prototypes for + * the gpio.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_GPIO_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif +#endif /*__ GPIO_H__ */ + diff --git a/CUBEMXTESTING/Core/Inc/main.h b/CUBEMXTESTING/Core/Inc/main.h new file mode 100644 index 000000000..3a736d114 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/main.h @@ -0,0 +1,84 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32g4xx_hal.h" + +#include "stm32g4xx_ll_rcc.h" +#include "stm32g4xx_ll_bus.h" +#include "stm32g4xx_ll_crs.h" +#include "stm32g4xx_ll_system.h" +#include "stm32g4xx_ll_exti.h" +#include "stm32g4xx_ll_cortex.h" +#include "stm32g4xx_ll_utils.h" +#include "stm32g4xx_ll_pwr.h" +#include "stm32g4xx_ll_dma.h" +#include "stm32g4xx_ll_gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define USER_BUTTON_Pin LL_GPIO_PIN_13 +#define USER_BUTTON_GPIO_Port GPIOC +#define USER_LED_Pin LL_GPIO_PIN_5 +#define USER_LED_GPIO_Port GPIOA + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/CUBEMXTESTING/Core/Inc/stm32_assert.h b/CUBEMXTESTING/Core/Inc/stm32_assert.h new file mode 100644 index 000000000..61631c41e --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/stm32_assert.h @@ -0,0 +1,53 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32_assert.h + * @author MCD Application Team + * @brief STM32 assert file. + ****************************************************************************** + * @attention + * + * Copyright (c) 2019 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ASSERT_H +#define __STM32_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Includes ------------------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ +#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else +#define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ASSERT_H */ + diff --git a/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h b/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h new file mode 100644 index 000000000..16ef7e356 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h @@ -0,0 +1,380 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file + ****************************************************************************** + * @attention + * + * Copyright (c) 2019 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32G4xx_HAL_CONF_H +#define STM32G4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED + + /*#define HAL_ADC_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CORDIC_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +#define HAL_FDCAN_MODULE_ENABLED +/*#define HAL_FMAC_MODULE_ENABLED */ +/*#define HAL_HRTIM_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_I2C_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_PCD_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +/*#define HAL_RTC_MODULE_ENABLED */ +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_TIM_MODULE_ENABLED */ +/*#define HAL_UART_MODULE_ENABLED */ +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Register Callbacks selection ############################## */ +/** + * @brief This is the list of modules where register callback can be used + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U +#define USE_HAL_COMP_REGISTER_CALLBACKS 0U +#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U +#define USE_HAL_EXTI_REGISTER_CALLBACKS 0U +#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U +#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U +#define USE_HAL_HRTIM_REGISTER_CALLBACKS 0U +#define USE_HAL_I2C_REGISTER_CALLBACKS 0U +#define USE_HAL_I2S_REGISTER_CALLBACKS 0U +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U +#define USE_HAL_NAND_REGISTER_CALLBACKS 0U +#define USE_HAL_NOR_REGISTER_CALLBACKS 0U +#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U +#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U +#define USE_HAL_RNG_REGISTER_CALLBACKS 0U +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U +#define USE_HAL_SAI_REGISTER_CALLBACKS 0U +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U +#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U +#define USE_HAL_TIM_REGISTER_CALLBACKS 0U +#define USE_HAL_UART_REGISTER_CALLBACKS 0U +#define USE_HAL_USART_REGISTER_CALLBACKS 0U +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE (16000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT (100UL) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE (16000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE (48000000UL) /*!< Value of the Internal High Speed oscillator for USB FS/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) +/*!< Value of the Internal Low Speed oscillator in Hz +The real value may vary depending on the variations in voltage and temperature.*/ +#define LSI_VALUE (32000UL) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) +#define LSE_VALUE (32768UL) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT (5000UL) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S and SAI peripherals + * This value is used by the I2S and SAI HAL modules to compute the I2S and SAI clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) +#define EXTERNAL_CLOCK_VALUE (12288000UL) /*!< Value of the External oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY (15UL) /*!< tick interrupt priority (lowest by default) */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 0U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ + #define USE_FULL_ASSERT 1U + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED +#include "stm32g4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED +#include "stm32g4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED +#include "stm32g4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED +#include "stm32g4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED +#include "stm32g4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED +#include "stm32g4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CORDIC_MODULE_ENABLED +#include "stm32g4xx_hal_cordic.h" +#endif /* HAL_CORDIC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED +#include "stm32g4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED +#include "stm32g4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED +#include "stm32g4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED +#include "stm32g4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED +#include "stm32g4xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED +#include "stm32g4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_FMAC_MODULE_ENABLED +#include "stm32g4xx_hal_fmac.h" +#endif /* HAL_FMAC_MODULE_ENABLED */ + +#ifdef HAL_HRTIM_MODULE_ENABLED +#include "stm32g4xx_hal_hrtim.h" +#endif /* HAL_HRTIM_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED +#include "stm32g4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED +#include "stm32g4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED +#include "stm32g4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED +#include "stm32g4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32g4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED +#include "stm32g4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED +#include "stm32g4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32g4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED +#include "stm32g4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED +#include "stm32g4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED +#include "stm32g4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED +#include "stm32g4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED +#include "stm32g4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED +#include "stm32g4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED +#include "stm32g4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED +#include "stm32g4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED +#include "stm32g4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm32g4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED +#include "stm32g4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED +#include "stm32g4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED +#include "stm32g4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED +#include "stm32g4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ +#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else +#define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32G4xx_HAL_CONF_H */ diff --git a/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h b/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h new file mode 100644 index 000000000..1a144ad22 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h @@ -0,0 +1,66 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32G4xx_IT_H +#define __STM32G4xx_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32G4xx_IT_H */ diff --git a/CUBEMXTESTING/Core/Src/fdcan.c b/CUBEMXTESTING/Core/Src/fdcan.c new file mode 100644 index 000000000..a1e13a2e8 --- /dev/null +++ b/CUBEMXTESTING/Core/Src/fdcan.c @@ -0,0 +1,224 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file fdcan.c + * @brief This file provides code for the configuration + * of the FDCAN instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "fdcan.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +FDCAN_HandleTypeDef hfdcan1; +FDCAN_HandleTypeDef hfdcan2; + +/* FDCAN1 init function */ +void MX_FDCAN1_Init(void) +{ + + /* USER CODE BEGIN FDCAN1_Init 0 */ + + /* USER CODE END FDCAN1_Init 0 */ + + /* USER CODE BEGIN FDCAN1_Init 1 */ + + /* USER CODE END FDCAN1_Init 1 */ + hfdcan1.Instance = FDCAN1; + hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; + hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; + hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; + hfdcan1.Init.AutoRetransmission = ENABLE; + hfdcan1.Init.TransmitPause = DISABLE; + hfdcan1.Init.ProtocolException = ENABLE; + hfdcan1.Init.NominalPrescaler = 1; + hfdcan1.Init.NominalSyncJumpWidth = 16; + hfdcan1.Init.NominalTimeSeg1 = 119; + hfdcan1.Init.NominalTimeSeg2 = 40; + hfdcan1.Init.DataPrescaler = 8; + hfdcan1.Init.DataSyncJumpWidth = 16; + hfdcan1.Init.DataTimeSeg1 = 14; + hfdcan1.Init.DataTimeSeg2 = 5; + hfdcan1.Init.StdFiltersNbr = 0; + hfdcan1.Init.ExtFiltersNbr = 2; + hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN FDCAN1_Init 2 */ + + /* USER CODE END FDCAN1_Init 2 */ + +} +/* FDCAN2 init function */ +void MX_FDCAN2_Init(void) +{ + + /* USER CODE BEGIN FDCAN2_Init 0 */ + + /* USER CODE END FDCAN2_Init 0 */ + + /* USER CODE BEGIN FDCAN2_Init 1 */ + + /* USER CODE END FDCAN2_Init 1 */ + hfdcan2.Instance = FDCAN2; + hfdcan2.Init.ClockDivider = FDCAN_CLOCK_DIV1; + hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC; + hfdcan2.Init.Mode = FDCAN_MODE_NORMAL; + hfdcan2.Init.AutoRetransmission = ENABLE; + hfdcan2.Init.TransmitPause = DISABLE; + hfdcan2.Init.ProtocolException = ENABLE; + hfdcan2.Init.NominalPrescaler = 1; + hfdcan2.Init.NominalSyncJumpWidth = 16; + hfdcan2.Init.NominalTimeSeg1 = 119; + hfdcan2.Init.NominalTimeSeg2 = 40; + hfdcan2.Init.DataPrescaler = 8; + hfdcan2.Init.DataSyncJumpWidth = 16; + hfdcan2.Init.DataTimeSeg1 = 14; + hfdcan2.Init.DataTimeSeg2 = 5; + hfdcan2.Init.StdFiltersNbr = 0; + hfdcan2.Init.ExtFiltersNbr = 2; + hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN FDCAN2_Init 2 */ + + /* USER CODE END FDCAN2_Init 2 */ + +} + +static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0; + +void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(fdcanHandle->Instance==FDCAN1) + { + /* USER CODE BEGIN FDCAN1_MspInit 0 */ + + /* USER CODE END FDCAN1_MspInit 0 */ + LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PCLK1); + + /* FDCAN1 clock enable */ + HAL_RCC_FDCAN_CLK_ENABLED++; + if(HAL_RCC_FDCAN_CLK_ENABLED==1){ + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**FDCAN1 GPIO Configuration + PB8-BOOT0 ------> FDCAN1_RX + PB9 ------> FDCAN1_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN FDCAN1_MspInit 1 */ + + /* USER CODE END FDCAN1_MspInit 1 */ + } + else if(fdcanHandle->Instance==FDCAN2) + { + /* USER CODE BEGIN FDCAN2_MspInit 0 */ + + /* USER CODE END FDCAN2_MspInit 0 */ + + LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PCLK1); + + /* FDCAN2 clock enable */ + HAL_RCC_FDCAN_CLK_ENABLED++; + if(HAL_RCC_FDCAN_CLK_ENABLED==1){ + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**FDCAN2 GPIO Configuration + PB12 ------> FDCAN2_RX + PB13 ------> FDCAN2_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN FDCAN2_MspInit 1 */ + + /* USER CODE END FDCAN2_MspInit 1 */ + } +} + +void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle) +{ + + if(fdcanHandle->Instance==FDCAN1) + { + /* USER CODE BEGIN FDCAN1_MspDeInit 0 */ + + /* USER CODE END FDCAN1_MspDeInit 0 */ + /* Peripheral clock disable */ + HAL_RCC_FDCAN_CLK_ENABLED--; + if(HAL_RCC_FDCAN_CLK_ENABLED==0){ + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + + /**FDCAN1 GPIO Configuration + PB8-BOOT0 ------> FDCAN1_RX + PB9 ------> FDCAN1_TX + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); + + /* USER CODE BEGIN FDCAN1_MspDeInit 1 */ + + /* USER CODE END FDCAN1_MspDeInit 1 */ + } + else if(fdcanHandle->Instance==FDCAN2) + { + /* USER CODE BEGIN FDCAN2_MspDeInit 0 */ + + /* USER CODE END FDCAN2_MspDeInit 0 */ + /* Peripheral clock disable */ + HAL_RCC_FDCAN_CLK_ENABLED--; + if(HAL_RCC_FDCAN_CLK_ENABLED==0){ + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + + /**FDCAN2 GPIO Configuration + PB12 ------> FDCAN2_RX + PB13 ------> FDCAN2_TX + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_13); + + /* USER CODE BEGIN FDCAN2_MspDeInit 1 */ + + /* USER CODE END FDCAN2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + diff --git a/CUBEMXTESTING/Core/Src/gpio.c b/CUBEMXTESTING/Core/Src/gpio.c new file mode 100644 index 000000000..09690886a --- /dev/null +++ b/CUBEMXTESTING/Core/Src/gpio.c @@ -0,0 +1,347 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file gpio.c + * @brief This file provides code for the configuration + * of all used GPIO pins. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "gpio.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/*----------------------------------------------------------------------------*/ +/* Configure GPIO */ +/*----------------------------------------------------------------------------*/ +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/** Configure pins +*/ +void MX_GPIO_Init(void) +{ + + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* GPIO Ports Clock Enable */ + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOF); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOG); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); + + /**/ + LL_GPIO_ResetOutputPin(USER_LED_GPIO_Port, USER_LED_Pin); + + /**/ + GPIO_InitStruct.Pin = USER_BUTTON_Pin; + GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(USER_BUTTON_GPIO_Port, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_14; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_15; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_10; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOG, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_2; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_3; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_2; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_3; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_4; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = USER_LED_Pin; + GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(USER_LED_GPIO_Port, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_6; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_4; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_5; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_0; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_1; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_2; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_10; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_11; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_14; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_15; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_6; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_8; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_9; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_8; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_9; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_10; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_11; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_12; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_13; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_14; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_15; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_10; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_11; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_12; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_2; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_3; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_4; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_5; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_6; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /**/ + GPIO_InitStruct.Pin = LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(GPIOB, &GPIO_InitStruct); + +} + +/* USER CODE BEGIN 2 */ + +/* USER CODE END 2 */ diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c new file mode 100644 index 000000000..0491c7152 --- /dev/null +++ b/CUBEMXTESTING/Core/Src/main.c @@ -0,0 +1,209 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +#include "fdcan.h" +#include "gpio.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include "Logomatic.h" +#include "loop.h" +#include "vcp.h" +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ +LogomaticConfig logomaticConfig = {.clock_source = LOGOMATIC_PCLK1, + .bus = LOGOMATIC_BUS, + .gpio_port = LOGOMATIC_GPIOA, + .gpio_pin_rx_tx_mask = LL_GPIO_PIN_9 | LL_GPIO_PIN_10, + .baud_rate = 115200, + .data_width = LOGOMATIC_DATAWIDTH_8B, + .stop_bits = LOGOMATIC_STOPBITS_1, + .parity = LOGOMATIC_PARITY_NONE, + .transfer_direction = LOGOMATIC_DIRECTION_TX, + .hardware_flow_control = LOGOMATIC_HWCONTROL_NONE, + .prescaler = LOGOMATIC_PRESCALER_DIV1, + .tx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8, + .rx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8}; + +VCP_Config vcp_config = {.baud_rate = 2000000, + .clock_source = VCP_CLOCK_PCLK, + .gpio_tx_rx_pin_mask = LL_GPIO_PIN_2 | LL_GPIO_PIN_3, + .bus_port = VCP_Port_A, + .parity = VCP_Parity_None, + .prescaler = VCP_Prescalar_Div2, + .stop_bits = VCP_StopBits_1, + .oversampling = VCP_Oversampling_16, + .tx_fifo_threshold = VCP_Threshold_1_8, + .rx_fifo_threshold = VCP_Threshold_1_8, + .alternate_function = LL_GPIO_AF_7, + .rx_callback = NULL}; +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + + /* USER CODE BEGIN 1 */ + + /* USER CODE END 1 */ + + /* MCU Configuration--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); + + /* USER CODE BEGIN Init */ + + /* USER CODE END Init */ + + /* Configure the system clock */ + SystemClock_Config(); + + /* USER CODE BEGIN SysInit */ + + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_FDCAN1_Init(); + MX_FDCAN2_Init(); + /* USER CODE BEGIN 2 */ + Logomatic_Init(&logomaticConfig); + VCP_Init(&vcp_config); + /* USER CODE END 2 */ + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + LOGOMATIC("Hello World!\n"); + while (1) { + /* USER CODE END WHILE */ + MainLoop(); + LL_mDelay(500); + /* USER CODE BEGIN 3 */ + } + /* USER CODE END 3 */ +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); + while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) {} + LL_PWR_EnableRange1BoostMode(); + LL_RCC_HSI_Enable(); + /* Wait till HSI is ready */ + while (LL_RCC_HSI_IsReady() != 1) {} + + LL_RCC_HSI_SetCalibTrimming(64); + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 20, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_EnableDomain_SYS(); + LL_RCC_PLL_Enable(); + /* Wait till PLL is ready */ + while (LL_RCC_PLL_IsReady() != 1) {} + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + /* Wait till System clock is ready */ + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {} + + /* Insure 1us transition state at intermediate medium speed clock*/ + for (__IO uint32_t i = (170 >> 1); i != 0; i--) + ; + + /* Set AHB prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + LL_SetSystemCoreClock(160000000); + + /* Update the time base */ + if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK) { + Error_Handler(); + } +} + +/* USER CODE BEGIN 4 */ + +/* USER CODE END 4 */ + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +void Error_Handler(void) +{ + /* USER CODE BEGIN Error_Handler_Debug */ + /* User can add his own implementation to report the HAL error return state */ + __disable_irq(); + while (1) {} + /* USER CODE END Error_Handler_Debug */ +} +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/CUBEMXTESTING/Core/Src/stm32g4xx_it.c b/CUBEMXTESTING/Core/Src/stm32g4xx_it.c new file mode 100644 index 000000000..13e0f0c20 --- /dev/null +++ b/CUBEMXTESTING/Core/Src/stm32g4xx_it.c @@ -0,0 +1,203 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "stm32g4xx_it.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ + +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex-M4 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + while (1) + { + } + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Prefetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ + /* USER CODE BEGIN SVCall_IRQn 0 */ + + /* USER CODE END SVCall_IRQn 0 */ + /* USER CODE BEGIN SVCall_IRQn 1 */ + + /* USER CODE END SVCall_IRQn 1 */ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ + /* USER CODE BEGIN PendSV_IRQn 0 */ + + /* USER CODE END PendSV_IRQn 0 */ + /* USER CODE BEGIN PendSV_IRQn 1 */ + + /* USER CODE END PendSV_IRQn 1 */ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ + /* USER CODE BEGIN SysTick_IRQn 0 */ + + /* USER CODE END SysTick_IRQn 0 */ + HAL_IncTick(); + /* USER CODE BEGIN SysTick_IRQn 1 */ + + /* USER CODE END SysTick_IRQn 1 */ +} + +/******************************************************************************/ +/* STM32G4xx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32g4xx.s). */ +/******************************************************************************/ + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ From 2ae50b1e73b454b92e6ef8eec906d0d37bd91615 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 10 Jul 2026 00:02:53 -0700 Subject: [PATCH 05/38] In progress --- Work on getting initial CAN peripheral abstraction copied over from TimedCAN Signed-off-by: Daniel Hansen --- .../Application/Inc/CubeCAN_Config.h | 12 ++ CUBEMXTESTING/CMakeLists.txt | 2 +- CUBEMXTESTING/Core/Src/main.c | 26 ++-- Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 41 +++++- Lib/Peripherals/CubeCAN/Inc/Private/common.h | 15 +++ Lib/Peripherals/CubeCAN/Src/can_clock.c | 0 Lib/Peripherals/CubeCAN/Src/can_it.c | 123 ++++++++++++++++++ Lib/Peripherals/CubeCAN/Src/can_mcu.c | 26 ++++ Lib/Peripherals/CubeCAN/Src/can_utils.c | 29 +++++ Lib/Peripherals/CubeCAN/cubemx_can.cmake | 7 +- 10 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 CUBEMXTESTING/Application/Inc/CubeCAN_Config.h create mode 100644 Lib/Peripherals/CubeCAN/Inc/Private/common.h delete mode 100644 Lib/Peripherals/CubeCAN/Src/can_clock.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_mcu.c diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h new file mode 100644 index 000000000..83444c479 --- /dev/null +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -0,0 +1,12 @@ +#ifndef CUBE_CAN_CONFIG_H +#define CUBE_CAN_CONFIG_H + +// TODO Add a template to the library + +#define USECAN1 +#define TX_BUFFER_1_SIZE 20 + +#define USECAN2 +#define TX_BUFFER_2_SIZE 20 + +#endif diff --git a/CUBEMXTESTING/CMakeLists.txt b/CUBEMXTESTING/CMakeLists.txt index 7b5232e56..bfd25f877 100644 --- a/CUBEMXTESTING/CMakeLists.txt +++ b/CUBEMXTESTING/CMakeLists.txt @@ -33,7 +33,7 @@ target_sources( Core/Src/stm32g4xx_it.c ) -target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB) +target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB CUBEMX_CAN_LIB) target_include_directories( ${PROJECT_NAME}_USER_CODE diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 0491c7152..03e70c599 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -48,18 +48,18 @@ /* USER CODE BEGIN PV */ LogomaticConfig logomaticConfig = {.clock_source = LOGOMATIC_PCLK1, - .bus = LOGOMATIC_BUS, - .gpio_port = LOGOMATIC_GPIOA, - .gpio_pin_rx_tx_mask = LL_GPIO_PIN_9 | LL_GPIO_PIN_10, - .baud_rate = 115200, - .data_width = LOGOMATIC_DATAWIDTH_8B, - .stop_bits = LOGOMATIC_STOPBITS_1, - .parity = LOGOMATIC_PARITY_NONE, - .transfer_direction = LOGOMATIC_DIRECTION_TX, - .hardware_flow_control = LOGOMATIC_HWCONTROL_NONE, - .prescaler = LOGOMATIC_PRESCALER_DIV1, - .tx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8, - .rx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8}; + .bus = LOGOMATIC_BUS, + .gpio_port = LOGOMATIC_GPIOA, + .gpio_pin_rx_tx_mask = LL_GPIO_PIN_9 | LL_GPIO_PIN_10, + .baud_rate = 115200, + .data_width = LOGOMATIC_DATAWIDTH_8B, + .stop_bits = LOGOMATIC_STOPBITS_1, + .parity = LOGOMATIC_PARITY_NONE, + .transfer_direction = LOGOMATIC_DIRECTION_TX, + .hardware_flow_control = LOGOMATIC_HWCONTROL_NONE, + .prescaler = LOGOMATIC_PRESCALER_DIV1, + .tx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8, + .rx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8}; VCP_Config vcp_config = {.baud_rate = 2000000, .clock_source = VCP_CLOCK_PCLK, @@ -203,7 +203,7 @@ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h index 2b6c3c544..2e9475dcd 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -1,6 +1,45 @@ +#include + +#include "GRCAN_MSG_ID.h" +#include "GRCAN_NODE_ID.h" + #ifndef CUBEMX_CAN_EXT_H #define CUBEMX_CAN_EXT_H -// TODO +/** + * @brief CAN Identifier structure + * + * This structure is used to represent a CAN message identifier, which consists of a transmitting node ID, a receiving node ID, and a message ID. The structure is used in conjunction with the + * Construct_Message_ID and Deconstruct_Message_ID functions to convert between the structure representation and the 32-bit integer representation of the CAN message identifier. + * + * @warning The structure does not represent cusotm IDs. + * @warning The structure does not represent actual bit depth + */ +typedef struct { + GRCAN_NODE_ID tx_node_id; + GRCAN_NODE_ID rx_node_id; + GRCAN_MSG_ID msg_id; +} CAN_Identifier; + +/** + * @brief Constructs a CAN message identifier from the given transmitting node ID, receiving node ID, and message ID. + * + * @param identifier Pointer to the CAN_Identifier structure containing the node and message IDs. + * + * @return The constructed 29-bit CAN message extended identifier. + */ +uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier); + +/** + * @brief Deconstructs a 29-bit CAN message extended identifier into its constituent transmitting node ID, receiving node ID, and message ID. + * + * @param message_id The 29-bit CAN message extended identifier to be deconstructed. + * + * @return A CAN_Identifier structure containing the deconstructed node and message IDs. + * + * @warning The function does not guarantee that the returned structure will represent a valid CAN message identifier. + * @warning The function does not support custom IDs. + */ +CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id); #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/common.h b/Lib/Peripherals/CubeCAN/Inc/Private/common.h new file mode 100644 index 000000000..c1f43d093 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Inc/Private/common.h @@ -0,0 +1,15 @@ +#include "main.h" + +#ifndef CUBEMX_CAN_INTERNAL_H +#define CUBEMX_CAN_INTERNAL_H + +/** + * @brief Get the name of the FDCAN instance as a string. + * + * @param instance Pointer to the FDCAN instance. + * + * @return A string representing the name of the FDCAN instance. If the instance is not recognized, returns "UNKNOWN". + */ +const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance); + +#endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_clock.c b/Lib/Peripherals/CubeCAN/Src/can_clock.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index e69de29bb..569a3979c 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -0,0 +1,123 @@ +#include "CubeCAN_Config.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Private/common.h" +#include "main.h" + +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 +} + +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; +} + +void TIM5_IRQHandler(void) +{ + if (LL_TIM_IsActiveFlag_UPDATE(TIM5)) { + LL_TIM_ClearFlag_UPDATE(TIM5); +#ifdef USECAN1 + can_tx_dequeue_helper(can_get_handle(&hal_fdcan1)); +#endif +#ifdef USECAN2 + can_tx_dequeue_helper(can_get_handle(&hal_fdcan2)); +#endif +#ifdef USECAN3 + can_tx_dequeue_helper(can_get_handle(&hal_fdcan3)); +#endif + } +} diff --git a/Lib/Peripherals/CubeCAN/Src/can_mcu.c b/Lib/Peripherals/CubeCAN/Src/can_mcu.c new file mode 100644 index 000000000..68edf9675 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_mcu.c @@ -0,0 +1,26 @@ +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Logomatic.h" +#include "Private/common.h" + +const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance) +{ + if (instance == NULL) { + return "NULL"; + } +#if defined(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 + LOGOMATIC("Get CAN instance name: unknown instance\n"); + return "UNKNOWN"; +} diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index e69de29bb..6119f63f0 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -0,0 +1,29 @@ +#include + +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "GRCAN_MSG_ID.h" +#include "GRCAN_NODE_ID.h" +#include "Private/common.h" + +uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) +{ + uint32_t message_id = 0; + + message_id |= ((0xFF & identifier->tx_node_id) << 20); + message_id |= ((0xFFF & identifier->msg_id) << 8); + message_id |= (0xFF & identifier->rx_node_id); + + return message_id; +} + +CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id) +{ + CAN_Identifier identifier = {0}; + + identifier.tx_node_id = (GRCAN_NODE_ID)((message_id >> 20) & 0xFF); + identifier.msg_id = (GRCAN_MSG_ID)((message_id >> 8) & 0xFFF); + identifier.rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFF); + + return identifier; +} diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake index ab7d9470e..85cd3db36 100644 --- a/Lib/Peripherals/CubeCAN/cubemx_can.cmake +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -10,8 +10,13 @@ target_sources( CUBEMX_CAN_LIB INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can_it.c - ${CMAKE_CURRENT_LIST_DIR}/Src/can_clock.c ${CMAKE_CURRENT_LIST_DIR}/Src/can_utils.c ) +target_link_libraries( + CUBEMX_CAN_LIB + INTERFACE + CANfigurator +) + # TODO Unit testing From 29bc3326625fc95adddb38ff18f12166459283c8 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 10 Jul 2026 00:16:43 -0700 Subject: [PATCH 06/38] In progress --- Resolve a few include errors Signed-off-by: Daniel Hansen --- CUBEMXTESTING/Application/Inc/CubeCAN_Config.h | 4 ++++ CUBEMXTESTING/Core/Inc/main.h | 3 ++- Lib/Peripherals/CubeCAN/Inc/Private/common.h | 4 ++-- Lib/Peripherals/CubeCAN/Src/can_it.c | 4 ++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index 83444c479..866efc956 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -3,10 +3,14 @@ // TODO Add a template to the library +#include "stm32g4xx_ll_tim.h" + #define USECAN1 #define TX_BUFFER_1_SIZE 20 #define USECAN2 #define TX_BUFFER_2_SIZE 20 +#define CAN_TIMER_SEND_PERIOD_US 500 + #endif diff --git a/CUBEMXTESTING/Core/Inc/main.h b/CUBEMXTESTING/Core/Inc/main.h index 3a736d114..c050c5e89 100644 --- a/CUBEMXTESTING/Core/Inc/main.h +++ b/CUBEMXTESTING/Core/Inc/main.h @@ -42,7 +42,8 @@ extern "C" { /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ - +#include "stm32g4xx_ll_usart.h" +#include "stm32g4xx_ll_lpuart.h" /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/common.h b/Lib/Peripherals/CubeCAN/Inc/Private/common.h index c1f43d093..a2ae5d5e7 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/common.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/common.h @@ -1,7 +1,7 @@ #include "main.h" -#ifndef CUBEMX_CAN_INTERNAL_H -#define CUBEMX_CAN_INTERNAL_H +#ifndef CUBE_CAN_PRIVATE_COMMON_H +#define CUBE_CAN_PRIVATE_COMMON_H /** * @brief Get the name of the FDCAN instance as a string. diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index 569a3979c..242e861fe 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -1,6 +1,10 @@ +#include +#include + #include "CubeCAN_Config.h" #include "CubeMXCan.h" #include "CubeMXCanExt.h" +#include "Logomatic.h" #include "Private/common.h" #include "main.h" From 73e0747d4ecd5b0c9ae506950a64f50845a5097d Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Tue, 14 Jul 2026 23:26:29 -0700 Subject: [PATCH 07/38] Add template from [Discord](https://discord.com/channels/756738476887638107/1525038985175367720/1526432730273943714) to the monorepo Also update extension list for freemarker support Co-authored-by: TrainmanR Signed-off-by: Daniel Hansen --- .vscode/extensions.json | 3 +- Lib/CubeMXTemplates/can_cfg_h.ftl | 66 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Lib/CubeMXTemplates/can_cfg_h.ftl diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b5c60d558..3e5fd3c28 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -9,6 +9,7 @@ "github.vscode-pull-request-github", "eamodio.gitlens", "davidanson.vscode-markdownlint", - "ms-vscode.vscode-serial-monitor" + "ms-vscode.vscode-serial-monitor", + "dcortes92.freemarker" ] } diff --git a/Lib/CubeMXTemplates/can_cfg_h.ftl b/Lib/CubeMXTemplates/can_cfg_h.ftl new file mode 100644 index 000000000..395f27387 --- /dev/null +++ b/Lib/CubeMXTemplates/can_cfg_h.ftl @@ -0,0 +1,66 @@ +[#ftl] +[#-- + Example STM32CubeMX FreeMarker template + + Suggested filename: + can_cfg_h.ftl + + Expected generated filename: + can_cfg.h + + Purpose: + Detect which FDCAN peripherals are enabled in CubeMX and generate + compile-time configuration macros for the Gaucho Racing CAN library. +--] + +[#list configs as dt] + +[#assign usedIPs = (dt.usedIPs)![]] + +[#assign hasFDCAN1 = false] +[#assign hasFDCAN2 = false] +[#assign hasFDCAN3 = false] + +[#list usedIPs as ip] + [#assign ipName = ip?string] + + [#if ipName == "FDCAN1"] + [#assign hasFDCAN1 = true] + [/#if] + + [#if ipName == "FDCAN2"] + [#assign hasFDCAN2 = true] + [/#if] + + [#if ipName == "FDCAN3"] + [#assign hasFDCAN3 = true] + [/#if] +[/#list] + +#ifndef CAN_CFG_H +#define CAN_CFG_H + +/* Generated automatically by STM32CubeMX FreeMarker. */ + +[#if hasFDCAN1] +#define USECAN1 +#define TX_BUFFER_1_SIZE 20U +[/#if] + +[#if hasFDCAN2] +#define USECAN2 +#define TX_BUFFER_2_SIZE 20U +[/#if] + +[#if hasFDCAN3] +#define USECAN3 +#define TX_BUFFER_3_SIZE 20U +[/#if] + +[#if !hasFDCAN1 && !hasFDCAN2 && !hasFDCAN3] +#error "No FDCAN peripheral is enabled in STM32CubeMX" +[/#if] + +#endif /* CAN_CFG_H */ + +[/#list] From 32e59e898d2ae71bad70c9f986d9d841a59df263 Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Wed, 15 Jul 2026 14:29:29 -0700 Subject: [PATCH 08/38] New changes to template can_cfg_h.ftl; aimed to preserve user-changed code, while before it would be erased on re-generation of the file. --- Lib/CubeMXTemplates/can_cfg_h.ftl | 42 ++++++++++++++----------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/Lib/CubeMXTemplates/can_cfg_h.ftl b/Lib/CubeMXTemplates/can_cfg_h.ftl index 395f27387..8036a8133 100644 --- a/Lib/CubeMXTemplates/can_cfg_h.ftl +++ b/Lib/CubeMXTemplates/can_cfg_h.ftl @@ -1,17 +1,4 @@ [#ftl] -[#-- - Example STM32CubeMX FreeMarker template - - Suggested filename: - can_cfg_h.ftl - - Expected generated filename: - can_cfg.h - - Purpose: - Detect which FDCAN peripherals are enabled in CubeMX and generate - compile-time configuration macros for the Gaucho Racing CAN library. ---] [#list configs as dt] @@ -24,15 +11,15 @@ [#list usedIPs as ip] [#assign ipName = ip?string] - [#if ipName == "FDCAN1"] + [#if ipName?contains("FDCAN1")] [#assign hasFDCAN1 = true] [/#if] - [#if ipName == "FDCAN2"] + [#if ipName?contains("FDCAN2")] [#assign hasFDCAN2 = true] [/#if] - [#if ipName == "FDCAN3"] + [#if ipName?contains("FDCAN3")] [#assign hasFDCAN3 = true] [/#if] [/#list] @@ -42,23 +29,32 @@ /* Generated automatically by STM32CubeMX FreeMarker. */ +/* USER CODE BEGIN CAN_USER_CONFIG */ + +#ifndef TX_BUFFER_1_SIZE +#define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE +#define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE +#define TX_BUFFER_3_SIZE 20U +#endif + +/* USER CODE END CAN_USER_CONFIG */ + [#if hasFDCAN1] #define USECAN1 -#define TX_BUFFER_1_SIZE 20U [/#if] [#if hasFDCAN2] #define USECAN2 -#define TX_BUFFER_2_SIZE 20U [/#if] [#if hasFDCAN3] #define USECAN3 -#define TX_BUFFER_3_SIZE 20U -[/#if] - -[#if !hasFDCAN1 && !hasFDCAN2 && !hasFDCAN3] -#error "No FDCAN peripheral is enabled in STM32CubeMX" [/#if] #endif /* CAN_CFG_H */ From 10fba33a507562b9db4dbd598627be24adcc4a90 Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Wed, 15 Jul 2026 14:34:10 -0700 Subject: [PATCH 09/38] Added comments to explain new functionality in the can_cfg_h.ftl template file. --- Lib/CubeMXTemplates/can_cfg_h.ftl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/CubeMXTemplates/can_cfg_h.ftl b/Lib/CubeMXTemplates/can_cfg_h.ftl index 8036a8133..f3a1bcf98 100644 --- a/Lib/CubeMXTemplates/can_cfg_h.ftl +++ b/Lib/CubeMXTemplates/can_cfg_h.ftl @@ -1,5 +1,15 @@ [#ftl] +[#-- +Generates can_cfg.h from the active STM32CubeMX project. + +Detects enabled FDCAN instances and emits the corresponding USECANx macros. +TX buffer sizes remain user-configurable and are preserved across normal +CubeMX regeneration. + +STM32 hardware configuration remains owned by CubeMX. +--] + [#list configs as dt] [#assign usedIPs = (dt.usedIPs)![]] From 30060a91334b9e1595abe270641f662ff6071bb8 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Wed, 15 Jul 2026 22:20:43 -0700 Subject: [PATCH 10/38] Modify how we handle templates within the monorepo based on new information Signed-off-by: Daniel Hansen --- Lib/CubeMXTemplates/{ => Autogen/Inc}/can_cfg_h.ftl | 0 Lib/CubeMXTemplates/Autogen/Src/.gitkeep | 0 Lib/CubeMXTemplates/README.md | 9 +++++++++ 3 files changed, 9 insertions(+) rename Lib/CubeMXTemplates/{ => Autogen/Inc}/can_cfg_h.ftl (100%) create mode 100644 Lib/CubeMXTemplates/Autogen/Src/.gitkeep create mode 100644 Lib/CubeMXTemplates/README.md diff --git a/Lib/CubeMXTemplates/can_cfg_h.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl similarity index 100% rename from Lib/CubeMXTemplates/can_cfg_h.ftl rename to Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl diff --git a/Lib/CubeMXTemplates/Autogen/Src/.gitkeep b/Lib/CubeMXTemplates/Autogen/Src/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/Lib/CubeMXTemplates/README.md b/Lib/CubeMXTemplates/README.md new file mode 100644 index 000000000..37ba973d7 --- /dev/null +++ b/Lib/CubeMXTemplates/README.md @@ -0,0 +1,9 @@ +# STM32 CubeMX Templates + +## Instructions + +1. Uncheck use default location and configure it to point to this folder (not `Autogen`!) +2. Add all of the relevant templates from available into selected +3. TODO (As we figure out the destination folder bit) + +## TODO From 6068b2378f5efa26d85a26db9ba8d5e9557ab105 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Wed, 15 Jul 2026 22:34:30 -0700 Subject: [PATCH 11/38] Modify line placement and ensure ordering has no precedence on broken builds Signed-off-by: Daniel Hansen --- Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl index f3a1bcf98..de4b84222 100644 --- a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl +++ b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl @@ -33,7 +33,6 @@ STM32 hardware configuration remains owned by CubeMX. [#assign hasFDCAN3 = true] [/#if] [/#list] - #ifndef CAN_CFG_H #define CAN_CFG_H @@ -41,17 +40,9 @@ STM32 hardware configuration remains owned by CubeMX. /* USER CODE BEGIN CAN_USER_CONFIG */ -#ifndef TX_BUFFER_1_SIZE #define TX_BUFFER_1_SIZE 20U -#endif - -#ifndef TX_BUFFER_2_SIZE #define TX_BUFFER_2_SIZE 20U -#endif - -#ifndef TX_BUFFER_3_SIZE #define TX_BUFFER_3_SIZE 20U -#endif /* USER CODE END CAN_USER_CONFIG */ From 38c1a58d8e2808c8c97efd6ff87d8e4d5f4f19e3 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 16 Jul 2026 00:13:44 -0700 Subject: [PATCH 12/38] Copy ftl from [Discord](https://discord.com/channels/756738476887638107/1525038985175367720/1527205781462712471) into git vcs Co-authored-by: TrainmanR Signed-off-by: Daniel Hansen --- Lib/CubeMXTemplates/can_cfg_h_timer.ftl | 177 ++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 Lib/CubeMXTemplates/can_cfg_h_timer.ftl diff --git a/Lib/CubeMXTemplates/can_cfg_h_timer.ftl b/Lib/CubeMXTemplates/can_cfg_h_timer.ftl new file mode 100644 index 000000000..b7ace5741 --- /dev/null +++ b/Lib/CubeMXTemplates/can_cfg_h_timer.ftl @@ -0,0 +1,177 @@ +[#ftl] +[#-- + Generates can_cfg.h from the active STM32CubeMX project. + + Detects enabled FDCAN instances and emits the corresponding USECANx macros. + Software TX queue sizes and CAN timer settings remain user-configurable and + are preserved across normal CubeMX regeneration. + + CubeMX remains responsible for configuring and generating MX_FDCANx_Init() + and MX_TIMx_Init(). This file only selects the CubeMX-generated timer handle + used to service the CAN software TX queues. +--] + +[#list configs as dt] + +[#assign usedIPs = (dt.usedIPs)![]] +[#assign hasFDCAN1 = false] +[#assign hasFDCAN2 = false] +[#assign hasFDCAN3 = false] +[#assign hasTIM1 = false] +[#assign hasTIM2 = false] +[#assign hasTIM3 = false] +[#assign hasTIM4 = false] +[#assign hasTIM5 = false] +[#assign hasTIM6 = false] +[#assign hasTIM7 = false] +[#assign hasTIM8 = false] +[#assign hasTIM15 = false] +[#assign hasTIM16 = false] +[#assign hasTIM17 = false] + +[#list usedIPs as ip] + [#assign ipName = ip?string] + + [#if ipName?contains("FDCAN1")][#assign hasFDCAN1 = true][/#if] + [#if ipName?contains("FDCAN2")][#assign hasFDCAN2 = true][/#if] + [#if ipName?contains("FDCAN3")][#assign hasFDCAN3 = true][/#if] + + [#if ipName?contains("TIM1")][#assign hasTIM1 = true][/#if] + [#if ipName?contains("TIM2")][#assign hasTIM2 = true][/#if] + [#if ipName?contains("TIM3")][#assign hasTIM3 = true][/#if] + [#if ipName?contains("TIM4")][#assign hasTIM4 = true][/#if] + [#if ipName?contains("TIM5")][#assign hasTIM5 = true][/#if] + [#if ipName?contains("TIM6")][#assign hasTIM6 = true][/#if] + [#if ipName?contains("TIM7")][#assign hasTIM7 = true][/#if] + [#if ipName?contains("TIM8")][#assign hasTIM8 = true][/#if] + [#if ipName?contains("TIM15")][#assign hasTIM15 = true][/#if] + [#if ipName?contains("TIM16")][#assign hasTIM16 = true][/#if] + [#if ipName?contains("TIM17")][#assign hasTIM17 = true][/#if] +[/#list] + +#ifndef CAN_CFG_H +#define CAN_CFG_H + +/* Generated automatically by STM32CubeMX FreeMarker. */ + +/* USER CODE BEGIN CAN_USER_CONFIG */ + +#ifndef TX_BUFFER_1_SIZE +#define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE +#define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE +#define TX_BUFFER_3_SIZE 20U +#endif + +/* Selects htim5 when set to 5. */ +#ifndef CAN_TIMER_INDEX +#define CAN_TIMER_INDEX 5 +#endif + +/* Dequeue one CAN message every X milliseconds. */ +#ifndef CAN_DEQUEUE_PERIOD_MS +#define CAN_DEQUEUE_PERIOD_MS 2U +#endif + +/* USER CODE END CAN_USER_CONFIG */ + +[#if hasFDCAN1] +#define USECAN1 +[/#if] +[#if hasFDCAN2] +#define USECAN2 +[/#if] +[#if hasFDCAN3] +#define USECAN3 +[/#if] + +[#if hasTIM1] +#define CUBEMX_HAS_TIM1 +[/#if] +[#if hasTIM2] +#define CUBEMX_HAS_TIM2 +[/#if] +[#if hasTIM3] +#define CUBEMX_HAS_TIM3 +[/#if] +[#if hasTIM4] +#define CUBEMX_HAS_TIM4 +[/#if] +[#if hasTIM5] +#define CUBEMX_HAS_TIM5 +[/#if] +[#if hasTIM6] +#define CUBEMX_HAS_TIM6 +[/#if] +[#if hasTIM7] +#define CUBEMX_HAS_TIM7 +[/#if] +[#if hasTIM8] +#define CUBEMX_HAS_TIM8 +[/#if] +[#if hasTIM15] +#define CUBEMX_HAS_TIM15 +[/#if] +[#if hasTIM16] +#define CUBEMX_HAS_TIM16 +[/#if] +[#if hasTIM17] +#define CUBEMX_HAS_TIM17 +[/#if] + +#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) +#error "TX_BUFFER_1_SIZE must be greater than zero" +#endif +#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) +#error "TX_BUFFER_2_SIZE must be greater than zero" +#endif +#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) +#error "TX_BUFFER_3_SIZE must be greater than zero" +#endif +#if CAN_DEQUEUE_PERIOD_MS == 0U +#error "CAN_DEQUEUE_PERIOD_MS must be greater than zero" +#endif + +#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) +#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) +#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) +#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) +#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) +#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) +#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) +#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) +#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) +#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) +#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) +#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX != 1) && (CAN_TIMER_INDEX != 2) && \ + (CAN_TIMER_INDEX != 3) && (CAN_TIMER_INDEX != 4) && \ + (CAN_TIMER_INDEX != 5) && (CAN_TIMER_INDEX != 6) && \ + (CAN_TIMER_INDEX != 7) && (CAN_TIMER_INDEX != 8) && \ + (CAN_TIMER_INDEX != 15) && (CAN_TIMER_INDEX != 16) && \ + (CAN_TIMER_INDEX != 17) +#error "CAN_TIMER_INDEX selects an unsupported timer" +#endif + +#define CAN_CFG_JOIN_INNER(a, b) a##b +#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) +#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) + +#endif /* CAN_CFG_H */ + +[/#list] From dffed5279aaa61b24a8e8295344c332029dc6c0a Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 16 Jul 2026 00:28:51 -0700 Subject: [PATCH 13/38] In progress --- Computer seconds from dying so it probably doesn't compile at all so sorry Signed-off-by: Daniel Hansen --- .../Application/Inc/CubeCAN_Config.h | 9 +- CUBEMXTESTING/Core/Src/main.c | 184 ++++++++-------- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 100 ++++++++- Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 6 + .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 88 ++++++++ Lib/Peripherals/CubeCAN/Inc/Private/common.h | 15 -- Lib/Peripherals/CubeCAN/Src/can_init.c | 208 ++++++++++++++++++ Lib/Peripherals/CubeCAN/Src/can_it.c | 126 +++-------- Lib/Peripherals/CubeCAN/Src/can_mcu.c | 26 --- Lib/Peripherals/CubeCAN/Src/can_utils.c | 87 +++++++- Lib/Peripherals/CubeCAN/cubemx_can.cmake | 1 + 11 files changed, 609 insertions(+), 241 deletions(-) create mode 100644 Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h delete mode 100644 Lib/Peripherals/CubeCAN/Inc/Private/common.h create mode 100644 Lib/Peripherals/CubeCAN/Src/can_init.c delete mode 100644 Lib/Peripherals/CubeCAN/Src/can_mcu.c diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index 866efc956..f3c02252e 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -3,14 +3,13 @@ // TODO Add a template to the library -#include "stm32g4xx_ll_tim.h" +#include "main.h" #define USECAN1 -#define TX_BUFFER_1_SIZE 20 - #define USECAN2 -#define TX_BUFFER_2_SIZE 20 -#define CAN_TIMER_SEND_PERIOD_US 500 +#define CUBEMX_CAN_TIMER_INSTANCE TIM5 +#define CUBEMX_CAN_TX_QUEUE_SIZE 20U +#define CAN_TIMER_SEND_PERIOD_US 500U #endif diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 03e70c599..45a24d683 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -18,7 +18,6 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" - #include "fdcan.h" #include "gpio.h" @@ -48,18 +47,18 @@ /* USER CODE BEGIN PV */ LogomaticConfig logomaticConfig = {.clock_source = LOGOMATIC_PCLK1, - .bus = LOGOMATIC_BUS, - .gpio_port = LOGOMATIC_GPIOA, - .gpio_pin_rx_tx_mask = LL_GPIO_PIN_9 | LL_GPIO_PIN_10, - .baud_rate = 115200, - .data_width = LOGOMATIC_DATAWIDTH_8B, - .stop_bits = LOGOMATIC_STOPBITS_1, - .parity = LOGOMATIC_PARITY_NONE, - .transfer_direction = LOGOMATIC_DIRECTION_TX, - .hardware_flow_control = LOGOMATIC_HWCONTROL_NONE, - .prescaler = LOGOMATIC_PRESCALER_DIV1, - .tx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8, - .rx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8}; + .bus = LOGOMATIC_BUS, + .gpio_port = LOGOMATIC_GPIOA, + .gpio_pin_rx_tx_mask = LL_GPIO_PIN_9 | LL_GPIO_PIN_10, + .baud_rate = 115200, + .data_width = LOGOMATIC_DATAWIDTH_8B, + .stop_bits = LOGOMATIC_STOPBITS_1, + .parity = LOGOMATIC_PARITY_NONE, + .transfer_direction = LOGOMATIC_DIRECTION_TX, + .hardware_flow_control = LOGOMATIC_HWCONTROL_NONE, + .prescaler = LOGOMATIC_PRESCALER_DIV1, + .tx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8, + .rx_fifo_threshold = LOGOMATIC_FIFOTHRESHOLD_1_8}; VCP_Config vcp_config = {.baud_rate = 2000000, .clock_source = VCP_CLOCK_PCLK, @@ -87,92 +86,99 @@ void SystemClock_Config(void); /* USER CODE END 0 */ /** - * @brief The application entry point. - * @retval int - */ + * @brief The application entry point. + * @retval int + */ int main(void) { - /* USER CODE BEGIN 1 */ + /* USER CODE BEGIN 1 */ - /* USER CODE END 1 */ + /* USER CODE END 1 */ - /* MCU Configuration--------------------------------------------------------*/ + /* MCU Configuration--------------------------------------------------------*/ - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); - /* USER CODE BEGIN Init */ + /* USER CODE BEGIN Init */ - /* USER CODE END Init */ + /* USER CODE END Init */ - /* Configure the system clock */ - SystemClock_Config(); + /* Configure the system clock */ + SystemClock_Config(); - /* USER CODE BEGIN SysInit */ + /* USER CODE BEGIN SysInit */ - /* USER CODE END SysInit */ + /* USER CODE END SysInit */ - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_FDCAN1_Init(); - MX_FDCAN2_Init(); - /* USER CODE BEGIN 2 */ + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_FDCAN1_Init(); + MX_FDCAN2_Init(); + /* USER CODE BEGIN 2 */ Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); - /* USER CODE END 2 */ + /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ LOGOMATIC("Hello World!\n"); while (1) { - /* USER CODE END WHILE */ - MainLoop(); - LL_mDelay(500); - /* USER CODE BEGIN 3 */ + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ } - /* USER CODE END 3 */ + /* USER CODE END 3 */ } /** - * @brief System Clock Configuration - * @retval None - */ + * @brief System Clock Configuration + * @retval None + */ void SystemClock_Config(void) { - LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); - while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) {} - LL_PWR_EnableRange1BoostMode(); - LL_RCC_HSI_Enable(); - /* Wait till HSI is ready */ - while (LL_RCC_HSI_IsReady() != 1) {} - - LL_RCC_HSI_SetCalibTrimming(64); - LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 20, LL_RCC_PLLR_DIV_2); - LL_RCC_PLL_EnableDomain_SYS(); - LL_RCC_PLL_Enable(); - /* Wait till PLL is ready */ - while (LL_RCC_PLL_IsReady() != 1) {} - - LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); - LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); - /* Wait till System clock is ready */ - while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {} - - /* Insure 1us transition state at intermediate medium speed clock*/ - for (__IO uint32_t i = (170 >> 1); i != 0; i--) - ; - - /* Set AHB prescaler*/ - LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); - LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); - LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); - LL_SetSystemCoreClock(160000000); - - /* Update the time base */ - if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK) { - Error_Handler(); - } + LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); + while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) + { + } + LL_PWR_EnableRange1BoostMode(); + LL_RCC_HSI_Enable(); + /* Wait till HSI is ready */ + while(LL_RCC_HSI_IsReady() != 1) + { + } + + LL_RCC_HSI_SetCalibTrimming(64); + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 20, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_EnableDomain_SYS(); + LL_RCC_PLL_Enable(); + /* Wait till PLL is ready */ + while(LL_RCC_PLL_IsReady() != 1) + { + } + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + /* Wait till System clock is ready */ + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + { + } + + /* Insure 1us transition state at intermediate medium speed clock*/ + for (__IO uint32_t i = (170 >> 1); i !=0; i--); + + /* Set AHB prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + LL_SetSystemCoreClock(160000000); + + /* Update the time base */ + if (HAL_InitTick (TICK_INT_PRIORITY) != HAL_OK) + { + Error_Handler(); + } } /* USER CODE BEGIN 4 */ @@ -180,30 +186,30 @@ void SystemClock_Config(void) /* USER CODE END 4 */ /** - * @brief This function is executed in case of error occurrence. - * @retval None - */ + * @brief This function is executed in case of error occurrence. + * @retval None + */ void Error_Handler(void) { - /* USER CODE BEGIN Error_Handler_Debug */ + /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) {} - /* USER CODE END Error_Handler_Debug */ + /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ void assert_failed(uint8_t *file, uint32_t line) { - /* USER CODE BEGIN 6 */ + /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 0bac3f962..8a258cc72 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -1,6 +1,104 @@ +#include +#include + +#include "CubeCAN_Config.h" +#include "CubeMXCanExt.h" +#include "main.h" + #ifndef CUBEMX_CAN_H #define CUBEMX_CAN_H -// TODO +#define FDCAN_MAX_DATA_BYTES 64U + +/** + * @brief Received CAN message structure + * + * This structure is used to represent a received CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and other relevant parameters. The data payload contains the actual data bytes of the message. + * + * @warning The length of the data array may be longer than the actual CAN message. + */ +typedef struct { + /// @brief The header of the received CAN message, containing information such as the identifier, data length, and other relevant parameters. + FDCAN_RxHeaderTypeDef rx_header; + /// @brief The data payload of the received CAN message, containing the actual data bytes of the message. The length of this array may be longer than the actual CAN message. + uint8_t data[FDCAN_MAX_DATA_BYTES]; +} GRCAN_RxMessage; + +/** + * @brief Transmission CAN message structure + * + * This structure is used to represent a transmission CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and other relevant parameters. The data payload contains the actual data bytes of the message. + * + * @warning The length of the data array may be longer than the actual CAN message. + */ +typedef struct { + FDCAN_TxHeaderTypeDef tx_header; + uint8_t data[FDCAN_MAX_DATA_BYTES]; +} GRCAN_TxMessage; + +/// @brief CAN handle for CubeMX CAN. @warning Do not access directly, use the provided API functions. +typedef struct CubeMXCan_Handle CubeMXCan_Handle; + +/// @brief Callback function type for receiving CAN messages. @warning Do not call directly, use the provided API functions. +typedef void (*CubeCAN_RxCallback)(void *user_ctx, const CAN_Identifier *identifier, const uint8_t *data, uint8_t size); + +/** + * @brief Configuration structure for CubeMX CAN. + * + * This structure is used to configure the CubeMX CAN handle, including the receive callback function and user context. The receive callback function is called when a CAN message is received, and the user context is a pointer to user-defined data that can be passed to the callback function. + * + * @warning Do not edit after initialization, as it may lead to undefined behavior. + */ +typedef struct { + /// @brief Callback function for receiving CAN messages. This function is called when a CAN message is received. + CubeCAN_RxCallback rx_callback; + /// @brief User-defined context pointer that can be passed to the receive callback function. This can be used to pass additional data or state information to the callback function. + void *user_ctx; +} CubeCAN_Config; + +/** + * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration. + * @param hfdcan Pointer to the FDCAN handle. + * @param config Pointer to the CubeCAN configuration structure. + * @return Pointer to the initialized CubeMX CAN handle, or NULL if initialization fails. + */ +CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config); + +/** + * @brief Starts the CubeMX CAN handle, enabling message transmission and reception. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle); + +/** + * @brief Stops the CubeMX CAN handle, disabling message transmission and reception. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle); + +/** + * @brief Releases the resources associated with the CubeMX CAN handle. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle); + +/** + * @brief Adds a filter to the CubeMX CAN handle, allowing for selective message reception based on the specified filter criteria. + * @param handle Pointer to the CubeMX CAN handle. + * @param filter Pointer to the FDCAN filter configuration structure. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter); + +/** + * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. + * @param handle Pointer to the CubeMX CAN handle. + * @param message Pointer to the GRCAN transmission message structure. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message); #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h index 2e9475dcd..64eff376a 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -2,6 +2,7 @@ #include "GRCAN_MSG_ID.h" #include "GRCAN_NODE_ID.h" +#include "main.h" #ifndef CUBEMX_CAN_EXT_H #define CUBEMX_CAN_EXT_H @@ -42,4 +43,9 @@ uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier); */ CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id); +/** + * @brief Builds an exact-match extended-ID filter for a given CAN identifier. + */ +HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter); + #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h new file mode 100644 index 000000000..3baff2c60 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -0,0 +1,88 @@ +#include +#include + +#include "CubeMXCan.h" +#include "main.h" + +#ifndef PRIVATE_CUBE_MX_CAN_H +#define PRIVATE_CUBE_MX_CAN_H + +/** + * @brief CubeMX CAN handle structure + * + * This structure is used to represent a CubeMX CAN handle, which consists of a pointer to the FDCAN handle, a configuration structure, a transmission queue, and other relevant parameters.\ + * + * @warning Use the provided API functions to interact with the CubeMX CAN handle. + * @warning The structure is intended for internal use only and should not be accessed directly by user code. + */ +typedef struct CubeMXCan_Handle { + /// @brief Pointer to the FDCAN handle associated with this CubeMX CAN handle. + FDCAN_HandleTypeDef *hfdcan; + /// @brief Configuration structure for the CubeMX CAN handle, containing the receive callback and user context. + CubeCAN_Config config; + /// @brief Transmission queue for the CubeMX CAN handle, containing the messages to be transmitted. + GRCAN_TxMessage tx_queue[CUBEMX_CAN_TX_QUEUE_SIZE]; + /// @brief Index of the head of the transmission queue, indicating the next message to be transmitted. + uint32_t tx_head; + /// @brief Count of messages in the transmission queue, indicating the number of messages waiting to be transmitted. + uint32_t tx_count; + /// @brief Flag indicating whether the CubeMX CAN handle has been started. + bool started; +} CubeMXCan_Handle; + +/// @brief Maximum number of CubeMX CAN instances supported by the library. +#define CUBEMX_CAN_MAX_INSTANCES 3U + +/** + * @brief Retrieves the CubeMX CAN handle associated with the given FDCAN handle. + * @param hfdcan Pointer to the FDCAN handle. + * @return Pointer to the CubeMX CAN handle associated with the given FDCAN handle + */ +CubeMXCan_Handle *CubeMXCan_Private_GetHandle(FDCAN_HandleTypeDef *hfdcan); + +/** + * @brief Registers a CubeMX CAN handle with the given FDCAN handle. + * @param hfdcan Pointer to the FDCAN handle. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_Private_RegisterHandle(FDCAN_HandleTypeDef *hfdcan, CubeMXCan_Handle *handle); + +/** + * @brief Unregisters the CubeMX CAN handle associated with the given FDCAN handle. + * @param hfdcan Pointer to the FDCAN handle. + */ +void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan); + +/** + * @brief Sends a queued message from the CubeMX CAN handle. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + */ +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle); + +/** + * @brief Dispatches a received message from the CubeMX CAN handle. + * @param hfdcan Pointer to the FDCAN handle. + */ +void CubeMXCan_Private_DispatchRx(FDCAN_HandleTypeDef *hfdcan); + +/** + * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. + * @param dlc The Data Length Code to be converted. + * @return The number of bytes corresponding to the given DLC. + */ +uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc); + +/** + * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. + */ +void CubeMXCan_Tick(void); + +/** + * @brief Callback function for handling received messages from the FDCAN peripheral. This function is called when a message is received in the RX FIFO 0 of the FDCAN peripheral. + * @param hfdcan Pointer to the FDCAN handle associated with the received message. + */ +void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan); + +#endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/common.h b/Lib/Peripherals/CubeCAN/Inc/Private/common.h deleted file mode 100644 index a2ae5d5e7..000000000 --- a/Lib/Peripherals/CubeCAN/Inc/Private/common.h +++ /dev/null @@ -1,15 +0,0 @@ -#include "main.h" - -#ifndef CUBE_CAN_PRIVATE_COMMON_H -#define CUBE_CAN_PRIVATE_COMMON_H - -/** - * @brief Get the name of the FDCAN instance as a string. - * - * @param instance Pointer to the FDCAN instance. - * - * @return A string representing the name of the FDCAN instance. If the instance is not recognized, returns "UNKNOWN". - */ -const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance); - -#endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c new file mode 100644 index 000000000..2d164d059 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -0,0 +1,208 @@ +#include +#include + +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Logomatic.h" +#include "Private/PrivateCubeMXCAN.h" + +typedef struct { + FDCAN_GlobalTypeDef *instance; + CubeMXCan_Handle *handle; +} CubeMXCan_RegistryEntry; + +static CubeMXCan_RegistryEntry s_registry[CUBEMX_CAN_MAX_INSTANCES] = {0}; +static CubeMXCan_Handle s_handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; +static bool s_timer_started = false; + +static CubeMXCan_RegistryEntry *CubeMXCan_FindRegistryEntry(FDCAN_GlobalTypeDef *instance) +{ + for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (s_registry[i].instance == instance) { + return &s_registry[i]; + } + } + + return NULL; +} + +static CubeMXCan_RegistryEntry *CubeMXCan_AllocRegistryEntry(FDCAN_GlobalTypeDef *instance) +{ + CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(instance); + if (entry != NULL) { + return entry; + } + + for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (s_registry[i].instance == NULL) { + s_registry[i].instance = instance; + return &s_registry[i]; + } + } + + return NULL; +} + +CubeMXCan_Handle *CubeMXCan_Private_GetHandle(FDCAN_HandleTypeDef *hfdcan) +{ + if (hfdcan == NULL) { + return NULL; + } + + CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(hfdcan->Instance); + return (entry != NULL) ? entry->handle : NULL; +} + +HAL_StatusTypeDef CubeMXCan_Private_RegisterHandle(FDCAN_HandleTypeDef *hfdcan, CubeMXCan_Handle *handle) +{ + if (hfdcan == NULL || handle == NULL) { + return HAL_ERROR; + } + + CubeMXCan_RegistryEntry *entry = CubeMXCan_AllocRegistryEntry(hfdcan->Instance); + if (entry == NULL) { + return HAL_ERROR; + } + + entry->handle = handle; + return HAL_OK; +} + +void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan) +{ + if (hfdcan == NULL) { + return; + } + + CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(hfdcan->Instance); + if (entry != NULL) { + entry->instance = NULL; + entry->handle = NULL; + } +} + +void CubeMXCan_Tick(void) +{ + for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + CubeMXCan_Handle *handle = s_registry[i].handle; + if (handle == NULL || !handle->started) { + continue; + } + + (void)CubeMXCan_Private_SendQueuedMessage(handle); + } +} + +CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config) +{ + if (hfdcan == NULL || config == NULL) { + return NULL; + } + + CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); + if (handle == NULL) { + for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (s_handles[i].hfdcan == NULL) { + handle = &s_handles[i]; + memset(handle, 0, sizeof(*handle)); + handle->hfdcan = hfdcan; + break; + } + } + } + + if (handle == NULL) { + LOGOMATIC("CubeMXCan_Init: no free handle slots\n"); + return NULL; + } + + handle->config = *config; + handle->tx_head = 0U; + handle->tx_count = 0U; + handle->started = false; + + if (CubeMXCan_Private_RegisterHandle(hfdcan, handle) != HAL_OK) { + LOGOMATIC("CubeMXCan_Init: failed to register handle\n"); + return NULL; + } + + uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; + if (HAL_FDCAN_ActivateNotification(hfdcan, rx_events, 0U) != HAL_OK) { + LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); + return NULL; + } + + if (!s_timer_started) { + s_timer_started = true; + } + + return handle; +} + +HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL) { + return HAL_ERROR; + } + + if (HAL_FDCAN_Start(handle->hfdcan) != HAL_OK) { + return HAL_ERROR; + } + + handle->started = true; + return HAL_OK; +} + +HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL) { + return HAL_ERROR; + } + + if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { + return HAL_ERROR; + } + + handle->started = false; + + return HAL_OK; +} + +HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL) { + return HAL_ERROR; + } + + (void)CubeMXCan_Stop(handle); + CubeMXCan_Private_UnregisterHandle(handle->hfdcan); + memset(handle, 0, sizeof(*handle)); + return HAL_OK; +} + +HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) +{ + if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { + return HAL_ERROR; + } + + return HAL_FDCAN_ConfigFilter(handle->hfdcan, (FDCAN_FilterTypeDef *)filter); +} + +HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message) +{ + if (handle == NULL || message == NULL) { + return HAL_ERROR; + } + + uint32_t insert_index = (handle->tx_head + handle->tx_count) % CUBEMX_CAN_TX_QUEUE_SIZE; + handle->tx_queue[insert_index] = *message; + + if (handle->tx_count < CUBEMX_CAN_TX_QUEUE_SIZE) { + handle->tx_count++; + } else { + handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; + } + + return HAL_OK; +} diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index 242e861fe..309f6d174 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -1,127 +1,59 @@ #include -#include +#include #include "CubeCAN_Config.h" #include "CubeMXCan.h" #include "CubeMXCanExt.h" #include "Logomatic.h" -#include "Private/common.h" -#include "main.h" +#include "Private/PrivateCubeMXCAN.h" -void FDCAN1_IT0_IRQHandler(void) +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { -#ifdef USECAN1 - HAL_FDCAN_IRQHandler(&hal_fdcan1); -#endif + if (htim != NULL && htim->Instance == CUBEMX_CAN_TIMER_INSTANCE) { + CubeMXCan_Tick(); + } } -void FDCAN1_IT1_IRQHandler(void) +void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { -#ifdef USECAN1 - HAL_FDCAN_IRQHandler(&hal_fdcan1); -#endif + (void)RxFifo0ITs; + CubeMXCan_OnRxFifo0(hfdcan); } -void FDCAN2_IT0_IRQHandler(void) -{ -#ifdef USECAN2 - HAL_FDCAN_IRQHandler(&hal_fdcan2); -#endif -} -void FDCAN2_IT1_IRQHandler(void) +void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes) { -#ifdef USECAN2 - HAL_FDCAN_IRQHandler(&hal_fdcan2); -#endif + (void)hfdcan; + (void)BufferIndexes; } -void FDCAN3_IT0_IRQHandler(void) +void CubeMXCan_Private_DispatchRx(FDCAN_HandleTypeDef *hfdcan) { -#ifdef USECAN3 - HAL_FDCAN_IRQHandler(&hal_fdcan3); -#endif -} -void FDCAN3_IT1_IRQHandler(void) -{ -#ifdef USECAN3 - HAL_FDCAN_IRQHandler(&hal_fdcan3); -#endif + CubeMXCan_OnRxFifo0(hfdcan); } -void CAN_Timer_Start(void) +void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan) { - static bool initialized = false; - - if (initialized) { - LOGOMATIC("CAN_Timer_Start: timer is already initialized\n"); + if (hfdcan == NULL) { 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"); + CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); + if (handle == NULL || handle->config.rx_callback == NULL) { + FDCAN_RxHeaderTypeDef rx_header = {0}; + uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; + (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); + LOGOMATIC("CubeMXCan_OnRxFifo0: no handle or callback registered for %s\n", can_get_instance_name(hfdcan->Instance)); 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"); + FDCAN_RxHeaderTypeDef rx_header = {0}; + uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) != HAL_OK) { + LOGOMATIC("CubeMXCan_OnRxFifo0: failed to get RX message\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; -} - -void TIM5_IRQHandler(void) -{ - if (LL_TIM_IsActiveFlag_UPDATE(TIM5)) { - LL_TIM_ClearFlag_UPDATE(TIM5); -#ifdef USECAN1 - can_tx_dequeue_helper(can_get_handle(&hal_fdcan1)); -#endif -#ifdef USECAN2 - can_tx_dequeue_helper(can_get_handle(&hal_fdcan2)); -#endif -#ifdef USECAN3 - can_tx_dequeue_helper(can_get_handle(&hal_fdcan3)); -#endif - } + CAN_Identifier identifier = Deconstruct_CAN_Identifier(rx_header.Identifier); + uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); + handle->config.rx_callback(handle->config.user_ctx, &identifier, rx_data, size); } diff --git a/Lib/Peripherals/CubeCAN/Src/can_mcu.c b/Lib/Peripherals/CubeCAN/Src/can_mcu.c deleted file mode 100644 index 68edf9675..000000000 --- a/Lib/Peripherals/CubeCAN/Src/can_mcu.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "CubeMXCan.h" -#include "CubeMXCanExt.h" -#include "Logomatic.h" -#include "Private/common.h" - -const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance) -{ - if (instance == NULL) { - return "NULL"; - } -#if defined(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 - LOGOMATIC("Get CAN instance name: unknown instance\n"); - return "UNKNOWN"; -} diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 6119f63f0..2ba864b0a 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -4,15 +4,45 @@ #include "CubeMXCanExt.h" #include "GRCAN_MSG_ID.h" #include "GRCAN_NODE_ID.h" -#include "Private/common.h" +#include "Logomatic.h" +#include "Private/PrivateCubeMXCAN.h" + +static const uint8_t s_dlc_to_bytes[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U}; + +const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance) +{ + if (instance == NULL) { + return "NULL"; + } +#ifdef USECAN1 + if (instance == FDCAN1) { + return "FDCAN1"; + } +#endif +#ifdef USECAN2 + if (instance == FDCAN2) { + return "FDCAN2"; + } +#endif +#ifdef USECAN3 + if (instance == FDCAN3) { + return "FDCAN3"; + } +#endif + LOGOMATIC("Get CAN instance name: unknown instance\n"); + return "UNKNOWN"; +} uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) { - uint32_t message_id = 0; + if (identifier == NULL) { + return 0U; + } - message_id |= ((0xFF & identifier->tx_node_id) << 20); - message_id |= ((0xFFF & identifier->msg_id) << 8); - message_id |= (0xFF & identifier->rx_node_id); + uint32_t message_id = 0U; + message_id |= ((uint32_t)(identifier->tx_node_id & 0xFFU) << 20U); + message_id |= ((uint32_t)(identifier->msg_id & 0xFFFU) << 8U); + message_id |= (uint32_t)(identifier->rx_node_id & 0xFFU); return message_id; } @@ -21,9 +51,50 @@ CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id) { CAN_Identifier identifier = {0}; - identifier.tx_node_id = (GRCAN_NODE_ID)((message_id >> 20) & 0xFF); - identifier.msg_id = (GRCAN_MSG_ID)((message_id >> 8) & 0xFFF); - identifier.rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFF); + identifier.tx_node_id = (GRCAN_NODE_ID)((message_id >> 20U) & 0xFFU); + identifier.msg_id = (GRCAN_MSG_ID)((message_id >> 8U) & 0xFFFU); + identifier.rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFFU); return identifier; } + +HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter) +{ + if (identifier == NULL || filter == NULL) { + return HAL_ERROR; + } + + filter->IdType = FDCAN_EXTENDED_ID; + filter->FilterIndex = filter_index; + filter->FilterType = FDCAN_FILTER_MASK; + filter->FilterConfig = fifo; + filter->FilterID1 = Construct_CAN_Identifier(identifier); + filter->FilterID2 = 0x1FFFFFFFU; + + return HAL_OK; +} + +uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) +{ + if (dlc > 15U) { + return 64U; + } + + return s_dlc_to_bytes[dlc]; +} + +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL || handle->tx_count == 0U) { + return HAL_OK; + } + + const GRCAN_TxMessage *message = &handle->tx_queue[handle->tx_head]; + if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message->tx_header, message->data) != HAL_OK) { + return HAL_ERROR; + } + + handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; + handle->tx_count--; + return HAL_OK; +} diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake index 85cd3db36..3fe5c3cd6 100644 --- a/Lib/Peripherals/CubeCAN/cubemx_can.cmake +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -11,6 +11,7 @@ target_sources( INTERFACE ${CMAKE_CURRENT_LIST_DIR}/Src/can_it.c ${CMAKE_CURRENT_LIST_DIR}/Src/can_utils.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_init.c ) target_link_libraries( From 0e51979ebd7d62b84b15a665b9d73d29fb284ace Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Thu, 16 Jul 2026 14:31:40 -0700 Subject: [PATCH 14/38] Timer Update Allows timer to be selected in the CubeMX GUI and generates the necessary code for timer initializat ion and interrupt handling. --- CUBEMXTESTING/CUBEMXTESTING.ioc | 19 +- CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h | 2 +- CUBEMXTESTING/Core/Inc/stm32g4xx_it.h | 1 + CUBEMXTESTING/Core/Inc/tim.h | 52 ++++ CUBEMXTESTING/Core/Src/main.c | 24 ++ CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c | 85 ++++++ CUBEMXTESTING/Core/Src/stm32g4xx_it.c | 16 +- CUBEMXTESTING/Core/Src/tim.c | 112 ++++++++ CUBEMXTESTING/can_cfg_h.updated | 145 ++++++++++ .../Autogen/Inc/can_cfg_h_updated.ftl | 268 ++++++++++++++++++ 10 files changed, 719 insertions(+), 5 deletions(-) create mode 100644 CUBEMXTESTING/Core/Inc/tim.h create mode 100644 CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c create mode 100644 CUBEMXTESTING/Core/Src/tim.c create mode 100644 CUBEMXTESTING/can_cfg_h.updated create mode 100644 Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl diff --git a/CUBEMXTESTING/CUBEMXTESTING.ioc b/CUBEMXTESTING/CUBEMXTESTING.ioc index be9a705f8..7c2f2f98e 100644 --- a/CUBEMXTESTING/CUBEMXTESTING.ioc +++ b/CUBEMXTESTING/CUBEMXTESTING.ioc @@ -42,7 +42,8 @@ Mcu.IP1=FDCAN2 Mcu.IP2=NVIC Mcu.IP3=RCC Mcu.IP4=SYS -Mcu.IPNb=5 +Mcu.IP5=TIM5 +Mcu.IPNb=6 Mcu.Name=STM32G474R(B-C-E)Tx Mcu.Package=LQFP64 Mcu.Pin0=PC13 @@ -53,7 +54,8 @@ Mcu.Pin4=PB8-BOOT0 Mcu.Pin5=PB9 Mcu.Pin6=VP_SYS_VS_Systick Mcu.Pin7=VP_SYS_VS_DBSignals -Mcu.PinsNb=8 +Mcu.Pin8=VP_TIM5_VS_ClockSourceINT +Mcu.PinsNb=9 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32G474RETx @@ -69,6 +71,7 @@ NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.TIM5_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false PA5.GPIOParameters=GPIO_Label PA5.GPIO_Label=USER_LED @@ -115,11 +118,16 @@ ProjectManager.ProjectStructure= ProjectManager.RegisterCallBack= ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=EWARM V8.50 +ProjectManager.TemplateDestinationPath=C\:\\Users\\maxnm\\Firmware\\CUBEMXTESTING +ProjectManager.TemplateSourcePath=C\:\\Users\\maxnm\\Firmware\\Lib\\CubeMXTemplates\\Autogen\\Inc +ProjectManager.TemplatesList=\\can_cfg_h_updated.ftl, ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_FDCAN2_Init-FDCAN2-false-HAL-true +ProjectManager.UseDefaultDestinationPath=true +ProjectManager.UseDefaultSourcePath=true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_FDCAN2_Init-FDCAN2-false-HAL-true,5-MX_TIM5_Init-TIM5-false-HAL-true RCC.ADC12Freq_Value=160000000 RCC.ADC345Freq_Value=160000000 RCC.AHBFreq_Value=160000000 @@ -168,8 +176,13 @@ RCC.USART3Freq_Value=160000000 RCC.USBFreq_Value=160000000 RCC.VCOInputFreq_Value=16000000 RCC.VCOOutputFreq_Value=320000000 +TIM5.IPParameters=Prescaler,PeriodNoDither +TIM5.PeriodNoDither=999 +TIM5.Prescaler=15999 VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals VP_SYS_VS_Systick.Mode=SysTick VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM5_VS_ClockSourceINT.Mode=Internal +VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT board=custom diff --git a/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h b/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h index 16ef7e356..33793dda8 100644 --- a/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h +++ b/CUBEMXTESTING/Core/Inc/stm32g4xx_hal_conf.h @@ -62,7 +62,7 @@ /*#define HAL_SMBUS_MODULE_ENABLED */ /*#define HAL_SPI_MODULE_ENABLED */ /*#define HAL_SRAM_MODULE_ENABLED */ -/*#define HAL_TIM_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED /*#define HAL_UART_MODULE_ENABLED */ /*#define HAL_USART_MODULE_ENABLED */ /*#define HAL_WWDG_MODULE_ENABLED */ diff --git a/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h b/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h index 1a144ad22..980377814 100644 --- a/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h +++ b/CUBEMXTESTING/Core/Inc/stm32g4xx_it.h @@ -55,6 +55,7 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); +void TIM5_IRQHandler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ diff --git a/CUBEMXTESTING/Core/Inc/tim.h b/CUBEMXTESTING/Core/Inc/tim.h new file mode 100644 index 000000000..18374feb3 --- /dev/null +++ b/CUBEMXTESTING/Core/Inc/tim.h @@ -0,0 +1,52 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file tim.h + * @brief This file contains all the function prototypes for + * the tim.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TIM_H__ +#define __TIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +extern TIM_HandleTypeDef htim5; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_TIM5_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIM_H__ */ + diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 45a24d683..54131f9fd 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -19,6 +19,7 @@ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "fdcan.h" +#include "tim.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ @@ -26,6 +27,10 @@ #include "Logomatic.h" #include "loop.h" #include "vcp.h" + +#include "can.h" +#include "can_cfg.h" +#include "gr_can_init.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -116,9 +121,16 @@ int main(void) MX_GPIO_Init(); MX_FDCAN1_Init(); MX_FDCAN2_Init(); + MX_TIM5_Init(); /* USER CODE BEGIN 2 */ Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); + + GR_CAN_Init(); + + if (CAN_Timer_Start() != HAL_OK) { + Error_Handler(); + } /* USER CODE END 2 */ /* Infinite loop */ @@ -183,6 +195,18 @@ void SystemClock_Config(void) /* USER CODE BEGIN 4 */ +/** + * @brief Route the CubeMX-generated CAN service timer callback to the CAN runtime. + * + * CAN_TIMER_HANDLE is generated by can_cfg.h from CAN_TIMER_INDEX. + */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim == &CAN_TIMER_HANDLE) { + CAN_Timer_Tick(); + } +} + /* USER CODE END 4 */ /** diff --git a/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c b/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c new file mode 100644 index 000000000..d908bd772 --- /dev/null +++ b/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c @@ -0,0 +1,85 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32g4xx_hal_msp.c + * @brief This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral + */ + HAL_PWREx_DisableUCPDDeadBattery(); + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/CUBEMXTESTING/Core/Src/stm32g4xx_it.c b/CUBEMXTESTING/Core/Src/stm32g4xx_it.c index 13e0f0c20..b4fb77dff 100644 --- a/CUBEMXTESTING/Core/Src/stm32g4xx_it.c +++ b/CUBEMXTESTING/Core/Src/stm32g4xx_it.c @@ -55,7 +55,7 @@ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ - +extern TIM_HandleTypeDef htim5; /* USER CODE BEGIN EV */ /* USER CODE END EV */ @@ -198,6 +198,20 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32g4xx.s). */ /******************************************************************************/ +/** + * @brief This function handles TIM5 global interrupt. + */ +void TIM5_IRQHandler(void) +{ + /* USER CODE BEGIN TIM5_IRQn 0 */ + + /* USER CODE END TIM5_IRQn 0 */ + HAL_TIM_IRQHandler(&htim5); + /* USER CODE BEGIN TIM5_IRQn 1 */ + + /* USER CODE END TIM5_IRQn 1 */ +} + /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ diff --git a/CUBEMXTESTING/Core/Src/tim.c b/CUBEMXTESTING/Core/Src/tim.c new file mode 100644 index 000000000..d1aa2063a --- /dev/null +++ b/CUBEMXTESTING/Core/Src/tim.c @@ -0,0 +1,112 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file tim.c + * @brief This file provides code for the configuration + * of the TIM instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "tim.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +TIM_HandleTypeDef htim5; + +/* TIM5 init function */ +void MX_TIM5_Init(void) +{ + + /* USER CODE BEGIN TIM5_Init 0 */ + + /* USER CODE END TIM5_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + /* USER CODE BEGIN TIM5_Init 1 */ + + /* USER CODE END TIM5_Init 1 */ + htim5.Instance = TIM5; + htim5.Init.Prescaler = 15999; + htim5.Init.CounterMode = TIM_COUNTERMODE_UP; + htim5.Init.Period = 999; + htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim5) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM5_Init 2 */ + + /* USER CODE END TIM5_Init 2 */ + +} + +void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM5) + { + /* USER CODE BEGIN TIM5_MspInit 0 */ + + /* USER CODE END TIM5_MspInit 0 */ + /* TIM5 clock enable */ + __HAL_RCC_TIM5_CLK_ENABLE(); + + /* TIM5 interrupt Init */ + HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM5_IRQn); + /* USER CODE BEGIN TIM5_MspInit 1 */ + + /* USER CODE END TIM5_MspInit 1 */ + } +} + +void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) +{ + + if(tim_baseHandle->Instance==TIM5) + { + /* USER CODE BEGIN TIM5_MspDeInit 0 */ + + /* USER CODE END TIM5_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM5_CLK_DISABLE(); + + /* TIM5 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM5_IRQn); + /* USER CODE BEGIN TIM5_MspDeInit 1 */ + + /* USER CODE END TIM5_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + diff --git a/CUBEMXTESTING/can_cfg_h.updated b/CUBEMXTESTING/can_cfg_h.updated new file mode 100644 index 000000000..288ec9a9b --- /dev/null +++ b/CUBEMXTESTING/can_cfg_h.updated @@ -0,0 +1,145 @@ + +#ifndef CAN_CFG_H +#define CAN_CFG_H + +/* Generated automatically by STM32CubeMX FreeMarker. */ + +/* + * User-editable CAN runtime configuration. + * + * CAN_TIMER_INDEX: + * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. + * + * CAN_TIMER_TICK_US: + * Duration of one timer counter tick, determined by the CubeMX prescaler. + * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. + * + * CAN_DEQUEUE_PERIOD_US: + * Time between attempts to dequeue and send one software-queued CAN message. + */ +/* USER CODE BEGIN CAN_USER_CONFIG */ + +#ifndef TX_BUFFER_1_SIZE +#define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE +#define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE +#define TX_BUFFER_3_SIZE 20U +#endif + +#ifndef CAN_TIMER_INDEX +#define CAN_TIMER_INDEX 5 +#endif + +#ifndef CAN_TIMER_TICK_US +#define CAN_TIMER_TICK_US 100U +#endif + +#ifndef CAN_DEQUEUE_PERIOD_US +#define CAN_DEQUEUE_PERIOD_US 500U +#endif + +/* USER CODE END CAN_USER_CONFIG */ + +/* Enabled FDCAN peripherals. */ + +#define USECAN1 + +#define USECAN2 + +/* Timers enabled in CubeMX. */ + +#define CUBEMX_HAS_TIM5 + +/* Configuration validation. */ + +#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) +#error "TX_BUFFER_1_SIZE must be greater than zero" +#endif + +#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) +#error "TX_BUFFER_2_SIZE must be greater than zero" +#endif + +#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) +#error "TX_BUFFER_3_SIZE must be greater than zero" +#endif + +#if CAN_TIMER_TICK_US == 0U +#error "CAN_TIMER_TICK_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US == 0U +#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US +#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" +#endif + +#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U +#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" +#endif + +#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU +#error "CAN dequeue period exceeds the supported timer auto-reload range" +#endif + +#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) +#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) +#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) +#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) +#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) +#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) +#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) +#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) +#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) +#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) +#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) +#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX != 1) && \ + (CAN_TIMER_INDEX != 2) && \ + (CAN_TIMER_INDEX != 3) && \ + (CAN_TIMER_INDEX != 4) && \ + (CAN_TIMER_INDEX != 5) && \ + (CAN_TIMER_INDEX != 6) && \ + (CAN_TIMER_INDEX != 7) && \ + (CAN_TIMER_INDEX != 8) && \ + (CAN_TIMER_INDEX != 15) && \ + (CAN_TIMER_INDEX != 16) && \ + (CAN_TIMER_INDEX != 17) +#error "CAN_TIMER_INDEX selects an unsupported timer" +#endif + +#define CAN_TIMER_PERIOD_COUNTS \ + (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) + +#define CAN_TIMER_AUTORELOAD \ + (CAN_TIMER_PERIOD_COUNTS - 1U) + +/* + * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. + * + * CAN_TIMER_INDEX = 5 + * CAN_TIMER_HANDLE = htim5 + */ +#define CAN_CFG_JOIN_INNER(a, b) a##b +#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) +#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) + +#endif /* CAN_CFG_H */ + diff --git a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl new file mode 100644 index 000000000..815c29617 --- /dev/null +++ b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl @@ -0,0 +1,268 @@ +[#ftl] +[#-- + Generates can_cfg.h from the active STM32CubeMX project. + + Detects enabled FDCAN and TIM peripherals and emits compile-time configuration + for the Gaucho Racing CAN runtime. + + CubeMX remains responsible for: + - FDCAN clocks, GPIO, bit timing, HAL handles, and MX_FDCANx_Init() + - TIM clocks, prescaler, NVIC configuration, HAL handle, and MX_TIMx_Init() + + The CAN runtime uses the selected CubeMX-generated TIM handle to periodically + service its software TX queues. +--] + +[#list configs as dt] + +[#assign usedIPs = (dt.usedIPs)![]] + +[#assign hasFDCAN1 = false] +[#assign hasFDCAN2 = false] +[#assign hasFDCAN3 = false] + +[#assign hasTIM1 = false] +[#assign hasTIM2 = false] +[#assign hasTIM3 = false] +[#assign hasTIM4 = false] +[#assign hasTIM5 = false] +[#assign hasTIM6 = false] +[#assign hasTIM7 = false] +[#assign hasTIM8 = false] +[#assign hasTIM15 = false] +[#assign hasTIM16 = false] +[#assign hasTIM17 = false] + +[#list usedIPs as ip] + [#assign ipName = ip?string] + + [#if ipName == "FDCAN1"] + [#assign hasFDCAN1 = true] + [/#if] + [#if ipName == "FDCAN2"] + [#assign hasFDCAN2 = true] + [/#if] + [#if ipName == "FDCAN3"] + [#assign hasFDCAN3 = true] + [/#if] + + [#if ipName == "TIM1"] + [#assign hasTIM1 = true] + [/#if] + [#if ipName == "TIM2"] + [#assign hasTIM2 = true] + [/#if] + [#if ipName == "TIM3"] + [#assign hasTIM3 = true] + [/#if] + [#if ipName == "TIM4"] + [#assign hasTIM4 = true] + [/#if] + [#if ipName == "TIM5"] + [#assign hasTIM5 = true] + [/#if] + [#if ipName == "TIM6"] + [#assign hasTIM6 = true] + [/#if] + [#if ipName == "TIM7"] + [#assign hasTIM7 = true] + [/#if] + [#if ipName == "TIM8"] + [#assign hasTIM8 = true] + [/#if] + [#if ipName == "TIM15"] + [#assign hasTIM15 = true] + [/#if] + [#if ipName == "TIM16"] + [#assign hasTIM16 = true] + [/#if] + [#if ipName == "TIM17"] + [#assign hasTIM17 = true] + [/#if] +[/#list] + +#ifndef CAN_CFG_H +#define CAN_CFG_H + +/* Generated automatically by STM32CubeMX FreeMarker. */ + +/* + * User-editable CAN runtime configuration. + * + * CAN_TIMER_INDEX: + * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. + * + * CAN_TIMER_TICK_US: + * Duration of one timer counter tick, determined by the CubeMX prescaler. + * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. + * + * CAN_DEQUEUE_PERIOD_US: + * Time between attempts to dequeue and send one software-queued CAN message. + */ +/* USER CODE BEGIN CAN_USER_CONFIG */ + +#ifndef TX_BUFFER_1_SIZE +#define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE +#define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE +#define TX_BUFFER_3_SIZE 20U +#endif + +#ifndef CAN_TIMER_INDEX +#define CAN_TIMER_INDEX 5 +#endif + +#ifndef CAN_TIMER_TICK_US +#define CAN_TIMER_TICK_US 100U +#endif + +#ifndef CAN_DEQUEUE_PERIOD_US +#define CAN_DEQUEUE_PERIOD_US 500U +#endif + +/* USER CODE END CAN_USER_CONFIG */ + +/* Enabled FDCAN peripherals. */ + +[#if hasFDCAN1] +#define USECAN1 +[/#if] + +[#if hasFDCAN2] +#define USECAN2 +[/#if] + +[#if hasFDCAN3] +#define USECAN3 +[/#if] + +/* Timers enabled in CubeMX. */ + +[#if hasTIM1] +#define CUBEMX_HAS_TIM1 +[/#if] +[#if hasTIM2] +#define CUBEMX_HAS_TIM2 +[/#if] +[#if hasTIM3] +#define CUBEMX_HAS_TIM3 +[/#if] +[#if hasTIM4] +#define CUBEMX_HAS_TIM4 +[/#if] +[#if hasTIM5] +#define CUBEMX_HAS_TIM5 +[/#if] +[#if hasTIM6] +#define CUBEMX_HAS_TIM6 +[/#if] +[#if hasTIM7] +#define CUBEMX_HAS_TIM7 +[/#if] +[#if hasTIM8] +#define CUBEMX_HAS_TIM8 +[/#if] +[#if hasTIM15] +#define CUBEMX_HAS_TIM15 +[/#if] +[#if hasTIM16] +#define CUBEMX_HAS_TIM16 +[/#if] +[#if hasTIM17] +#define CUBEMX_HAS_TIM17 +[/#if] + +/* Configuration validation. */ + +#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) +#error "TX_BUFFER_1_SIZE must be greater than zero" +#endif + +#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) +#error "TX_BUFFER_2_SIZE must be greater than zero" +#endif + +#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) +#error "TX_BUFFER_3_SIZE must be greater than zero" +#endif + +#if CAN_TIMER_TICK_US == 0U +#error "CAN_TIMER_TICK_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US == 0U +#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US +#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" +#endif + +#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U +#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" +#endif + +#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU +#error "CAN dequeue period exceeds the supported timer auto-reload range" +#endif + +#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) +#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) +#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) +#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) +#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) +#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) +#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) +#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) +#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) +#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) +#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) +#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX != 1) && \ + (CAN_TIMER_INDEX != 2) && \ + (CAN_TIMER_INDEX != 3) && \ + (CAN_TIMER_INDEX != 4) && \ + (CAN_TIMER_INDEX != 5) && \ + (CAN_TIMER_INDEX != 6) && \ + (CAN_TIMER_INDEX != 7) && \ + (CAN_TIMER_INDEX != 8) && \ + (CAN_TIMER_INDEX != 15) && \ + (CAN_TIMER_INDEX != 16) && \ + (CAN_TIMER_INDEX != 17) +#error "CAN_TIMER_INDEX selects an unsupported timer" +#endif + +#define CAN_TIMER_PERIOD_COUNTS \ + (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) + +#define CAN_TIMER_AUTORELOAD \ + (CAN_TIMER_PERIOD_COUNTS - 1U) + +/* + * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. + * + * CAN_TIMER_INDEX = 5 + * CAN_TIMER_HANDLE = htim5 + */ +#define CAN_CFG_JOIN_INNER(a, b) a##b +#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) +#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) + +#endif /* CAN_CFG_H */ + +[/#list] From e2d5282e6b6698a591be0736b7c7c38f373b07ad Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Thu, 16 Jul 2026 21:16:53 -0700 Subject: [PATCH 15/38] README_CAN_Timer_Configuration.md Added Added readme for information on changes/how-to guide. --- .../README_CAN_Timer_Configuration.md | 941 ++++++++++++++++++ 1 file changed, 941 insertions(+) create mode 100644 CUBEMXTESTING/README_CAN_Timer_Configuration.md diff --git a/CUBEMXTESTING/README_CAN_Timer_Configuration.md b/CUBEMXTESTING/README_CAN_Timer_Configuration.md new file mode 100644 index 000000000..ee8330180 --- /dev/null +++ b/CUBEMXTESTING/README_CAN_Timer_Configuration.md @@ -0,0 +1,941 @@ +# CAN Timer Configuration Guide + +This guide explains how to configure, modify, and extend the CubeMX-based CAN timer implementation. + +The current design uses STM32CubeMX for hardware configuration and a custom CAN runtime for software queue handling. + +--- + +# 1. Ownership Model + +## CubeMX controls + +CubeMX owns all hardware-level configuration: + +- enabled FDCAN peripherals +- enabled timer peripherals +- FDCAN GPIO pins +- FDCAN clock source +- FDCAN bit timing +- timer clock source +- timer prescaler +- initial timer period +- NVIC interrupt enable +- NVIC interrupt priority +- generated HAL handles +- generated interrupt handlers + +Examples: + +```c +FDCAN_HandleTypeDef hfdcan1; +FDCAN_HandleTypeDef hfdcan2; +TIM_HandleTypeDef htim5; +``` + +CubeMX also generates: + +```c +MX_FDCAN1_Init(); +MX_FDCAN2_Init(); +MX_TIM5_Init(); +``` + +Do not manually duplicate this hardware initialization inside the custom CAN library. + +## User-controlled runtime settings + +The user-controlled values are stored in the generated `can_cfg.h` file inside a preserved user-code section. + +Example: + +```c +/* USER CODE BEGIN CAN_USER_CONFIG */ + +#ifndef TX_BUFFER_1_SIZE +#define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE +#define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE +#define TX_BUFFER_3_SIZE 20U +#endif + +#ifndef CAN_TIMER_INDEX +#define CAN_TIMER_INDEX 5 +#endif + +#ifndef CAN_TIMER_TICK_US +#define CAN_TIMER_TICK_US 100U +#endif + +#ifndef CAN_DEQUEUE_PERIOD_US +#define CAN_DEQUEUE_PERIOD_US 500U +#endif + +/* USER CODE END CAN_USER_CONFIG */ +``` + +CubeMX preserves values inside this section when code is regenerated. + +--- + +# 2. Editable Values + +## `TX_BUFFER_1_SIZE` + +Controls the number of software-queued transmit messages for CAN1. + +```c +#define TX_BUFFER_1_SIZE 20U +``` + +Example: + +```c +#define TX_BUFFER_1_SIZE 50U +``` + +Use a larger value when CAN1 may temporarily produce messages faster than the hardware can transmit them. + +A larger queue consumes more RAM. + +## `TX_BUFFER_2_SIZE` + +Controls the software TX queue size for CAN2. + +```c +#define TX_BUFFER_2_SIZE 20U +``` + +## `TX_BUFFER_3_SIZE` + +Controls the software TX queue size for CAN3. + +```c +#define TX_BUFFER_3_SIZE 20U +``` + +This value is ignored when CAN3 is not enabled. + +Queue sizes must be greater than zero. + +--- + +## `CAN_TIMER_INDEX` + +Selects the CubeMX-generated timer used for CAN queue servicing. + +```c +#define CAN_TIMER_INDEX 5 +``` + +This maps to: + +```c +htim5 +``` + +Examples: + +```c +#define CAN_TIMER_INDEX 1 +``` + +selects: + +```c +htim1 +``` + +```c +#define CAN_TIMER_INDEX 2 +``` + +selects: + +```c +htim2 +``` + +```c +#define CAN_TIMER_INDEX 3 +``` + +selects: + +```c +htim3 +``` + +The selected timer must also be enabled in CubeMX. + +If the selected timer is not enabled, the generated configuration should produce a compile-time error. + +--- + +## `CAN_TIMER_TICK_US` + +Defines the duration of one timer counter tick in microseconds. + +```c +#define CAN_TIMER_TICK_US 100U +``` + +This value must match the timer prescaler configured in CubeMX. + +The equation is: + +```text +Timer counter frequency = +Timer input clock / (Prescaler + 1) +``` + +Then: + +```text +Timer tick duration = +1 / Timer counter frequency +``` + +For a 160 MHz timer clock and: + +```c +Prescaler = 15999 +``` + +the counter frequency is: + +```text +160,000,000 / 16,000 = 10,000 Hz +``` + +Therefore: + +```text +1 count = 100 us +``` + +The matching runtime value is: + +```c +#define CAN_TIMER_TICK_US 100U +``` + +### Example: 10 us timer tick + +To create a 10 us timer tick with a 160 MHz timer clock: + +```text +Prescaler = 1599 +``` + +because: + +```text +160,000,000 / 1600 = 100,000 Hz +``` + +Therefore: + +```text +1 count = 10 us +``` + +The matching configuration is: + +```c +#define CAN_TIMER_TICK_US 10U +``` + +Always change the prescaler through CubeMX. + +Do not manually edit the generated `tim.c` file. + +--- + +## `CAN_DEQUEUE_PERIOD_US` + +Controls how often the runtime attempts to dequeue and transmit a queued CAN message. + +```c +#define CAN_DEQUEUE_PERIOD_US 500U +``` + +For: + +```c +#define CAN_TIMER_TICK_US 100U +``` + +the timer uses: + +```text +500 us / 100 us = 5 counts +``` + +The auto-reload value becomes: + +```text +ARR = 5 - 1 = 4 +``` + +The generated macros calculate this automatically: + +```c +#define CAN_TIMER_PERIOD_COUNTS \ + (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) + +#define CAN_TIMER_AUTORELOAD \ + (CAN_TIMER_PERIOD_COUNTS - 1U) +``` + +### Example periods + +With a 100 us timer tick: + +| Desired dequeue period | `CAN_DEQUEUE_PERIOD_US` | ARR | +|---:|---:|---:| +| 500 us | `500U` | 4 | +| 1 ms | `1000U` | 9 | +| 2 ms | `2000U` | 19 | +| 5 ms | `5000U` | 49 | +| 10 ms | `10000U` | 99 | +| 100 ms | `100000U` | 999 | + +The dequeue period must be evenly divisible by the timer tick. + +Valid: + +```c +#define CAN_TIMER_TICK_US 100U +#define CAN_DEQUEUE_PERIOD_US 500U +``` + +Invalid: + +```c +#define CAN_TIMER_TICK_US 100U +#define CAN_DEQUEUE_PERIOD_US 550U +``` + +The second example is invalid because 550 us cannot be represented exactly using 100 us timer counts. + +--- + +# 3. Changing the Active Timer + +To change from TIM5 to TIM2: + +## Step 1: Enable TIM2 in CubeMX + +In CubeMX: + +```text +Pinout & Configuration + Timers + TIM2 + Clock Source: Internal Clock +``` + +Configure the desired prescaler and period. + +Enable: + +```text +TIM2 global interrupt +``` + +## Step 2: Regenerate code + +CubeMX should generate: + +```c +TIM_HandleTypeDef htim2; +void MX_TIM2_Init(void); +``` + +and: + +```c +void TIM2_IRQHandler(void) +{ + HAL_TIM_IRQHandler(&htim2); +} +``` + +## Step 3: Change `can_cfg.h` + +```c +#define CAN_TIMER_INDEX 2 +``` + +## Step 4: Update the timer tick + +Set `CAN_TIMER_TICK_US` to match TIM2's prescaler. + +Example: + +```c +#define CAN_TIMER_TICK_US 100U +``` + +## Step 5: Initialize TIM2 in `main.c` + +CubeMX should generate: + +```c +MX_TIM2_Init(); +``` + +before: + +```c +CAN_Timer_Start(); +``` + +--- + +# 4. Using One Shared Timer + +The current implementation uses one selected timer for all enabled CAN buses. + +Example: + +```text +TIM5 + | + +--> CAN_Timer_Tick() + | + +--> service CAN1 queue + +--> service CAN2 queue +``` + +This is the recommended design in most cases. + +Advantages: + +- fewer hardware timers used +- simpler configuration +- simpler startup +- one callback +- easier CubeMX integration +- easier synchronization between CAN buses + +The callback is: + +```c +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim == &CAN_TIMER_HANDLE) { + CAN_Timer_Tick(); + } +} +``` + +--- + +# 5. Servicing Multiple CAN Buses + +## Priority-based scheduling + +This approach always checks CAN1 first: + +```c +void CAN_Timer_Tick(void) +{ +#ifdef USECAN1 + if (CAN_ProcessOneTxMessage(&can1)) { + return; + } +#endif + +#ifdef USECAN2 + if (CAN_ProcessOneTxMessage(&can2)) { + return; + } +#endif + +#ifdef USECAN3 + (void)CAN_ProcessOneTxMessage(&can3); +#endif +} +``` + +Advantages: + +- simple +- supports bus priority + +Disadvantage: + +- lower-priority buses can be starved + +## Round-robin scheduling + +This approach alternates between buses: + +```c +void CAN_Timer_Tick(void) +{ + static uint8_t next_bus = 0U; + +#if defined(USECAN1) && defined(USECAN2) + + if (next_bus == 0U) { + (void)CAN_ProcessOneTxMessage(&can1); + next_bus = 1U; + } else { + (void)CAN_ProcessOneTxMessage(&can2); + next_bus = 0U; + } + +#elif defined(USECAN1) + + (void)CAN_ProcessOneTxMessage(&can1); + +#elif defined(USECAN2) + + (void)CAN_ProcessOneTxMessage(&can2); + +#endif +} +``` + +Advantages: + +- fairer between buses +- avoids CAN1 permanently dominating CAN2 + +--- + +# 6. Using Multiple Active Timers + +The current template selects one shared timer. + +It can be extended so each CAN peripheral uses a separate timer. + +Example: + +```text +TIM1 services CAN1 +TIM2 services CAN2 +TIM3 services CAN3 +``` + +Use separate configuration values: + +```c +#define CAN1_TIMER_INDEX 1 +#define CAN2_TIMER_INDEX 2 +#define CAN3_TIMER_INDEX 3 + +#define CAN1_TIMER_TICK_US 100U +#define CAN2_TIMER_TICK_US 100U +#define CAN3_TIMER_TICK_US 100U + +#define CAN1_DEQUEUE_PERIOD_US 500U +#define CAN2_DEQUEUE_PERIOD_US 1000U +#define CAN3_DEQUEUE_PERIOD_US 2000U +``` + +Create separate timer handles: + +```c +#define CAN1_TIMER_HANDLE \ + CAN_CFG_JOIN(htim, CAN1_TIMER_INDEX) + +#define CAN2_TIMER_HANDLE \ + CAN_CFG_JOIN(htim, CAN2_TIMER_INDEX) + +#define CAN3_TIMER_HANDLE \ + CAN_CFG_JOIN(htim, CAN3_TIMER_INDEX) +``` + +Create separate auto-reload values: + +```c +#define CAN1_TIMER_AUTORELOAD \ + ((CAN1_DEQUEUE_PERIOD_US / CAN1_TIMER_TICK_US) - 1U) + +#define CAN2_TIMER_AUTORELOAD \ + ((CAN2_DEQUEUE_PERIOD_US / CAN2_TIMER_TICK_US) - 1U) + +#define CAN3_TIMER_AUTORELOAD \ + ((CAN3_DEQUEUE_PERIOD_US / CAN3_TIMER_TICK_US) - 1U) +``` + +The callback would route each timer separately: + +```c +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ +#ifdef USECAN1 + if (htim == &CAN1_TIMER_HANDLE) { + CAN1_Timer_Tick(); + return; + } +#endif + +#ifdef USECAN2 + if (htim == &CAN2_TIMER_HANDLE) { + CAN2_Timer_Tick(); + return; + } +#endif + +#ifdef USECAN3 + if (htim == &CAN3_TIMER_HANDLE) { + CAN3_Timer_Tick(); + return; + } +#endif +} +``` + +Each timer must also be started separately: + +```c +if (CAN1_Timer_Start() != HAL_OK) { + Error_Handler(); +} + +if (CAN2_Timer_Start() != HAL_OK) { + Error_Handler(); +} + +if (CAN3_Timer_Start() != HAL_OK) { + Error_Handler(); +} +``` + +Use multiple timers only when the buses require: + +- independent transmission periods +- strict timing separation +- different interrupt priorities +- separate bandwidth policies + +For most applications, one shared timer with round-robin queue servicing is simpler and more efficient. + +--- + +# 7. Timer Startup Function + +The shared-timer implementation should use: + +```c +HAL_StatusTypeDef CAN_Timer_Start(void) +{ + TIM_HandleTypeDef *htim = &CAN_TIMER_HANDLE; + + __HAL_TIM_DISABLE(htim); + + __HAL_TIM_SET_AUTORELOAD( + htim, + CAN_TIMER_AUTORELOAD); + + __HAL_TIM_SET_COUNTER(htim, 0U); + + htim->Instance->EGR = TIM_EGR_UG; + + __HAL_TIM_CLEAR_FLAG( + htim, + TIM_FLAG_UPDATE); + + return HAL_TIM_Base_Start_IT(htim); +} +``` + +This function changes only the runtime period. + +It does not configure: + +- timer clocks +- timer prescaler +- NVIC +- timer instance +- timer IRQ handler + +CubeMX owns those settings. + +--- + +# 8. Required Startup Order + +The hardware initialization must happen before custom runtime initialization. + +Correct: + +```c +MX_GPIO_Init(); +MX_FDCAN1_Init(); +MX_FDCAN2_Init(); +MX_TIM5_Init(); + +GR_CAN_Init(); + +if (CAN_Timer_Start() != HAL_OK) { + Error_Handler(); +} +``` + +Incorrect: + +```c +CAN_Timer_Start(); +MX_TIM5_Init(); +``` + +The timer handle is not ready until `MX_TIM5_Init()` runs. + +--- + +# 9. Files That May Be Edited + +## Edit directly + +These files contain custom code: + +```text +can.c +can.h +gr_can_init.c +gr_can_init.h +can_cfg_h.ftl +README +CMakeLists.txt +``` + +## Edit only inside user-code sections + +```text +main.c +``` + +Examples: + +```c +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ +``` + +```c +/* USER CODE BEGIN 2 */ +/* USER CODE END 2 */ +``` + +```c +/* USER CODE BEGIN 4 */ +/* USER CODE END 4 */ +``` + +## Do not manually edit + +These files are generated by CubeMX: + +```text +fdcan.c +fdcan.h +tim.c +tim.h +gpio.c +gpio.h +stm32g4xx_it.c +stm32g4xx_it.h +stm32g4xx_hal_conf.h +``` + +Modify their settings through CubeMX and regenerate. + +--- + +# 10. Regeneration Checklist + +After regenerating CubeMX code, verify: + +```text +main.c includes tim.h +main.c calls MX_TIM5_Init() +tim.c exists +tim.h exists +htim5 is declared +TIM5_IRQHandler exists +HAL_TIM_MODULE_ENABLED is defined +FDCAN1 and FDCAN2 still initialize +can_cfg.h contains USECAN1 and USECAN2 +Core/Src/tim.c is included in the build +``` + +Also verify that custom code remains inside user-code sections. + +--- + +# 11. Testing Changes + +## Test timer frequency + +Temporarily replace queue servicing with a counter: + +```c +volatile uint32_t can_timer_ticks = 0U; + +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim == &CAN_TIMER_HANDLE) { + can_timer_ticks++; + } +} +``` + +With: + +```c +#define CAN_DEQUEUE_PERIOD_US 500U +``` + +the counter should increment approximately 2,000 times per second. + +For easier debugging: + +```c +#define CAN_DEQUEUE_PERIOD_US 100000U +``` + +This creates one callback every 100 ms. + +## Test CAN queue servicing + +1. Initialize FDCAN. +2. Initialize the custom CAN runtime. +3. Start the timer. +4. Add one frame to the software queue. +5. Confirm `CAN_Timer_Tick()` runs. +6. Confirm one frame is removed from the queue. +7. Confirm the HAL transmit function succeeds. +8. Confirm another CAN node receives the frame. + +--- + +# 12. Common Errors + +## Selected timer is not enabled + +Example: + +```text +CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX +``` + +Fix: + +- enable TIM2 in CubeMX, or +- select an enabled timer + +## `htim5` linker error + +Confirm: + +```text +Core/Src/tim.c +``` + +is included in the build. + +## No timer callback + +Confirm: + +- `MX_TIM5_Init()` is called +- `CAN_Timer_Start()` returns `HAL_OK` +- the timer interrupt is enabled +- `TIM5_IRQHandler()` exists +- `HAL_TIM_IRQHandler(&htim5)` is called +- global interrupts are enabled + +## Wrong timer rate + +Confirm: + +- timer input clock +- prescaler +- `CAN_TIMER_TICK_US` +- `CAN_DEQUEUE_PERIOD_US` + +All four values must agree. + +## Duplicate interrupt handler + +Do not define another: + +```c +TIM5_IRQHandler() +``` + +inside the CAN library. + +CubeMX owns the IRQ handler. + +## Messages remain queued + +Check: + +- FDCAN was started +- the hardware TX FIFO has room +- another node is present to acknowledge messages +- the transceiver is enabled +- bus bit timing matches +- queue dequeue code is being called + +--- + +# 13. Current Default Configuration + +Current timer: + +```text +TIM5 +``` + +Timer input clock: + +```text +160 MHz +``` + +Prescaler: + +```text +15999 +``` + +Timer tick: + +```text +100 us +``` + +CAN dequeue period: + +```text +500 us +``` + +Calculated auto-reload: + +```text +4 +``` + +Default queue sizes: + +```text +CAN1: 20 messages +CAN2: 20 messages +CAN3: 20 messages +``` + +The current implementation uses one shared timer for all enabled CAN buses. From a2f629f915a7e686629d6734a7653a42114b2bf6 Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Sat, 18 Jul 2026 18:28:04 -0700 Subject: [PATCH 16/38] Template Autogen Folders Fixed previous issue with can_cfg_h.ftl template not being copied to Autogen folder, and instead generated in CubeMX template. When using do not open/edit template settings, as then we'll need to reedit .ioc's paths. --- .../Inc/can_cfg.h} | 0 CUBEMXTESTING/CUBEMXTESTING.ioc | 39 ++- CUBEMXTESTING/Core/Inc/fdcan.h | 3 + CUBEMXTESTING/Core/Src/fdcan.c | 90 ++++++ CUBEMXTESTING/Core/Src/gpio.c | 12 - CUBEMXTESTING/Core/Src/main.c | 1 + Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl | 227 ++++++++++++++- .../Autogen/Inc/can_cfg_h_updated.ftl | 268 ------------------ Lib/CubeMXTemplates/Autogen/Src/.gitkeep | 0 Lib/CubeMXTemplates/can_cfg_h_timer.ftl | 177 ------------ 10 files changed, 335 insertions(+), 482 deletions(-) rename CUBEMXTESTING/{can_cfg_h.updated => Autogen/Inc/can_cfg.h} (100%) delete mode 100644 Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl delete mode 100644 Lib/CubeMXTemplates/Autogen/Src/.gitkeep delete mode 100644 Lib/CubeMXTemplates/can_cfg_h_timer.ftl diff --git a/CUBEMXTESTING/can_cfg_h.updated b/CUBEMXTESTING/Autogen/Inc/can_cfg.h similarity index 100% rename from CUBEMXTESTING/can_cfg_h.updated rename to CUBEMXTESTING/Autogen/Inc/can_cfg.h diff --git a/CUBEMXTESTING/CUBEMXTESTING.ioc b/CUBEMXTESTING/CUBEMXTESTING.ioc index 7c2f2f98e..1d4d092cb 100644 --- a/CUBEMXTESTING/CUBEMXTESTING.ioc +++ b/CUBEMXTESTING/CUBEMXTESTING.ioc @@ -32,6 +32,10 @@ FDCAN2.NominalSyncJumpWidth=16 FDCAN2.NominalTimeSeg1=119 FDCAN2.NominalTimeSeg2=40 FDCAN2.ProtocolException=ENABLE +FDCAN3.CalculateBaudRateNominal=3333333 +FDCAN3.CalculateTimeBitNominal=300 +FDCAN3.CalculateTimeQuantumNominal=100.0 +FDCAN3.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal File.Version=6 GPIO.groupedBy=Group By Peripherals KeepUserPlacement=false @@ -39,23 +43,26 @@ Mcu.CPN=STM32G474RET6 Mcu.Family=STM32G4 Mcu.IP0=FDCAN1 Mcu.IP1=FDCAN2 -Mcu.IP2=NVIC -Mcu.IP3=RCC -Mcu.IP4=SYS -Mcu.IP5=TIM5 -Mcu.IPNb=6 +Mcu.IP2=FDCAN3 +Mcu.IP3=NVIC +Mcu.IP4=RCC +Mcu.IP5=SYS +Mcu.IP6=TIM5 +Mcu.IPNb=7 Mcu.Name=STM32G474R(B-C-E)Tx Mcu.Package=LQFP64 Mcu.Pin0=PC13 Mcu.Pin1=PA5 +Mcu.Pin10=VP_TIM5_VS_ClockSourceINT Mcu.Pin2=PB12 Mcu.Pin3=PB13 -Mcu.Pin4=PB8-BOOT0 -Mcu.Pin5=PB9 -Mcu.Pin6=VP_SYS_VS_Systick -Mcu.Pin7=VP_SYS_VS_DBSignals -Mcu.Pin8=VP_TIM5_VS_ClockSourceINT -Mcu.PinsNb=9 +Mcu.Pin4=PA8 +Mcu.Pin5=PA15 +Mcu.Pin6=PB8-BOOT0 +Mcu.Pin7=PB9 +Mcu.Pin8=VP_SYS_VS_Systick +Mcu.Pin9=VP_SYS_VS_DBSignals +Mcu.PinsNb=11 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32G474RETx @@ -73,10 +80,14 @@ NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false NVIC.TIM5_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA15.Mode=FDCAN_Activate +PA15.Signal=FDCAN3_TX PA5.GPIOParameters=GPIO_Label PA5.GPIO_Label=USER_LED PA5.Locked=true PA5.Signal=GPIO_Output +PA8.Mode=FDCAN_Activate +PA8.Signal=FDCAN3_RX PB12.Mode=FDCAN_Activate PB12.Signal=FDCAN2_RX PB13.Mode=FDCAN_Activate @@ -118,9 +129,9 @@ ProjectManager.ProjectStructure= ProjectManager.RegisterCallBack= ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=EWARM V8.50 -ProjectManager.TemplateDestinationPath=C\:\\Users\\maxnm\\Firmware\\CUBEMXTESTING -ProjectManager.TemplateSourcePath=C\:\\Users\\maxnm\\Firmware\\Lib\\CubeMXTemplates\\Autogen\\Inc -ProjectManager.TemplatesList=\\can_cfg_h_updated.ftl, +ProjectManager.TemplateDestinationPath=. +ProjectManager.TemplateSourcePath=..\\Lib\\CubeMXTemplates +ProjectManager.TemplatesList=Autogen\\Inc\\can_cfg_h.ftl, ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= diff --git a/CUBEMXTESTING/Core/Inc/fdcan.h b/CUBEMXTESTING/Core/Inc/fdcan.h index b0fa74968..4b2cb4094 100644 --- a/CUBEMXTESTING/Core/Inc/fdcan.h +++ b/CUBEMXTESTING/Core/Inc/fdcan.h @@ -36,12 +36,15 @@ extern FDCAN_HandleTypeDef hfdcan1; extern FDCAN_HandleTypeDef hfdcan2; +extern FDCAN_HandleTypeDef hfdcan3; + /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ void MX_FDCAN1_Init(void); void MX_FDCAN2_Init(void); +void MX_FDCAN3_Init(void); /* USER CODE BEGIN Prototypes */ diff --git a/CUBEMXTESTING/Core/Src/fdcan.c b/CUBEMXTESTING/Core/Src/fdcan.c index a1e13a2e8..d1f107673 100644 --- a/CUBEMXTESTING/Core/Src/fdcan.c +++ b/CUBEMXTESTING/Core/Src/fdcan.c @@ -26,6 +26,7 @@ FDCAN_HandleTypeDef hfdcan1; FDCAN_HandleTypeDef hfdcan2; +FDCAN_HandleTypeDef hfdcan3; /* FDCAN1 init function */ void MX_FDCAN1_Init(void) @@ -102,6 +103,44 @@ void MX_FDCAN2_Init(void) /* USER CODE END FDCAN2_Init 2 */ +} +/* FDCAN3 init function */ +void MX_FDCAN3_Init(void) +{ + + /* USER CODE BEGIN FDCAN3_Init 0 */ + + /* USER CODE END FDCAN3_Init 0 */ + + /* USER CODE BEGIN FDCAN3_Init 1 */ + + /* USER CODE END FDCAN3_Init 1 */ + hfdcan3.Instance = FDCAN3; + hfdcan3.Init.ClockDivider = FDCAN_CLOCK_DIV1; + hfdcan3.Init.FrameFormat = FDCAN_FRAME_CLASSIC; + hfdcan3.Init.Mode = FDCAN_MODE_NORMAL; + hfdcan3.Init.AutoRetransmission = DISABLE; + hfdcan3.Init.TransmitPause = DISABLE; + hfdcan3.Init.ProtocolException = DISABLE; + hfdcan3.Init.NominalPrescaler = 16; + hfdcan3.Init.NominalSyncJumpWidth = 1; + hfdcan3.Init.NominalTimeSeg1 = 1; + hfdcan3.Init.NominalTimeSeg2 = 1; + hfdcan3.Init.DataPrescaler = 1; + hfdcan3.Init.DataSyncJumpWidth = 1; + hfdcan3.Init.DataTimeSeg1 = 1; + hfdcan3.Init.DataTimeSeg2 = 1; + hfdcan3.Init.StdFiltersNbr = 0; + hfdcan3.Init.ExtFiltersNbr = 0; + hfdcan3.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + if (HAL_FDCAN_Init(&hfdcan3) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN FDCAN3_Init 2 */ + + /* USER CODE END FDCAN3_Init 2 */ + } static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0; @@ -169,6 +208,36 @@ void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle) /* USER CODE END FDCAN2_MspInit 1 */ } + else if(fdcanHandle->Instance==FDCAN3) + { + /* USER CODE BEGIN FDCAN3_MspInit 0 */ + + /* USER CODE END FDCAN3_MspInit 0 */ + + LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PCLK1); + + /* FDCAN3 clock enable */ + HAL_RCC_FDCAN_CLK_ENABLED++; + if(HAL_RCC_FDCAN_CLK_ENABLED==1){ + __HAL_RCC_FDCAN_CLK_ENABLE(); + } + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**FDCAN3 GPIO Configuration + PA8 ------> FDCAN3_RX + PA15 ------> FDCAN3_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_FDCAN3; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USER CODE BEGIN FDCAN3_MspInit 1 */ + + /* USER CODE END FDCAN3_MspInit 1 */ + } } void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle) @@ -216,6 +285,27 @@ void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle) /* USER CODE END FDCAN2_MspDeInit 1 */ } + else if(fdcanHandle->Instance==FDCAN3) + { + /* USER CODE BEGIN FDCAN3_MspDeInit 0 */ + + /* USER CODE END FDCAN3_MspDeInit 0 */ + /* Peripheral clock disable */ + HAL_RCC_FDCAN_CLK_ENABLED--; + if(HAL_RCC_FDCAN_CLK_ENABLED==0){ + __HAL_RCC_FDCAN_CLK_DISABLE(); + } + + /**FDCAN3 GPIO Configuration + PA8 ------> FDCAN3_RX + PA15 ------> FDCAN3_TX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8|GPIO_PIN_15); + + /* USER CODE BEGIN FDCAN3_MspDeInit 1 */ + + /* USER CODE END FDCAN3_MspDeInit 1 */ + } } /* USER CODE BEGIN 1 */ diff --git a/CUBEMXTESTING/Core/Src/gpio.c b/CUBEMXTESTING/Core/Src/gpio.c index 09690886a..5d1912e85 100644 --- a/CUBEMXTESTING/Core/Src/gpio.c +++ b/CUBEMXTESTING/Core/Src/gpio.c @@ -238,12 +238,6 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOC, &GPIO_InitStruct); - /**/ - GPIO_InitStruct.Pin = LL_GPIO_PIN_8; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /**/ GPIO_InitStruct.Pin = LL_GPIO_PIN_9; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; @@ -280,12 +274,6 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /**/ - GPIO_InitStruct.Pin = LL_GPIO_PIN_15; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /**/ GPIO_InitStruct.Pin = LL_GPIO_PIN_10; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 54131f9fd..e189561ec 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -122,6 +122,7 @@ int main(void) MX_FDCAN1_Init(); MX_FDCAN2_Init(); MX_TIM5_Init(); + MX_FDCAN3_Init(); /* USER CODE BEGIN 2 */ Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); diff --git a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl index de4b84222..815c29617 100644 --- a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl +++ b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl @@ -1,13 +1,16 @@ [#ftl] - [#-- -Generates can_cfg.h from the active STM32CubeMX project. + Generates can_cfg.h from the active STM32CubeMX project. + + Detects enabled FDCAN and TIM peripherals and emits compile-time configuration + for the Gaucho Racing CAN runtime. -Detects enabled FDCAN instances and emits the corresponding USECANx macros. -TX buffer sizes remain user-configurable and are preserved across normal -CubeMX regeneration. + CubeMX remains responsible for: + - FDCAN clocks, GPIO, bit timing, HAL handles, and MX_FDCANx_Init() + - TIM clocks, prescaler, NVIC configuration, HAL handle, and MX_TIMx_Init() -STM32 hardware configuration remains owned by CubeMX. + The CAN runtime uses the selected CubeMX-generated TIM handle to periodically + service its software TX queues. --] [#list configs as dt] @@ -18,34 +21,114 @@ STM32 hardware configuration remains owned by CubeMX. [#assign hasFDCAN2 = false] [#assign hasFDCAN3 = false] +[#assign hasTIM1 = false] +[#assign hasTIM2 = false] +[#assign hasTIM3 = false] +[#assign hasTIM4 = false] +[#assign hasTIM5 = false] +[#assign hasTIM6 = false] +[#assign hasTIM7 = false] +[#assign hasTIM8 = false] +[#assign hasTIM15 = false] +[#assign hasTIM16 = false] +[#assign hasTIM17 = false] + [#list usedIPs as ip] [#assign ipName = ip?string] - [#if ipName?contains("FDCAN1")] + [#if ipName == "FDCAN1"] [#assign hasFDCAN1 = true] [/#if] - - [#if ipName?contains("FDCAN2")] + [#if ipName == "FDCAN2"] [#assign hasFDCAN2 = true] [/#if] - - [#if ipName?contains("FDCAN3")] + [#if ipName == "FDCAN3"] [#assign hasFDCAN3 = true] [/#if] + + [#if ipName == "TIM1"] + [#assign hasTIM1 = true] + [/#if] + [#if ipName == "TIM2"] + [#assign hasTIM2 = true] + [/#if] + [#if ipName == "TIM3"] + [#assign hasTIM3 = true] + [/#if] + [#if ipName == "TIM4"] + [#assign hasTIM4 = true] + [/#if] + [#if ipName == "TIM5"] + [#assign hasTIM5 = true] + [/#if] + [#if ipName == "TIM6"] + [#assign hasTIM6 = true] + [/#if] + [#if ipName == "TIM7"] + [#assign hasTIM7 = true] + [/#if] + [#if ipName == "TIM8"] + [#assign hasTIM8 = true] + [/#if] + [#if ipName == "TIM15"] + [#assign hasTIM15 = true] + [/#if] + [#if ipName == "TIM16"] + [#assign hasTIM16 = true] + [/#if] + [#if ipName == "TIM17"] + [#assign hasTIM17 = true] + [/#if] [/#list] + #ifndef CAN_CFG_H #define CAN_CFG_H /* Generated automatically by STM32CubeMX FreeMarker. */ +/* + * User-editable CAN runtime configuration. + * + * CAN_TIMER_INDEX: + * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. + * + * CAN_TIMER_TICK_US: + * Duration of one timer counter tick, determined by the CubeMX prescaler. + * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. + * + * CAN_DEQUEUE_PERIOD_US: + * Time between attempts to dequeue and send one software-queued CAN message. + */ /* USER CODE BEGIN CAN_USER_CONFIG */ +#ifndef TX_BUFFER_1_SIZE #define TX_BUFFER_1_SIZE 20U +#endif + +#ifndef TX_BUFFER_2_SIZE #define TX_BUFFER_2_SIZE 20U +#endif + +#ifndef TX_BUFFER_3_SIZE #define TX_BUFFER_3_SIZE 20U +#endif + +#ifndef CAN_TIMER_INDEX +#define CAN_TIMER_INDEX 5 +#endif + +#ifndef CAN_TIMER_TICK_US +#define CAN_TIMER_TICK_US 100U +#endif + +#ifndef CAN_DEQUEUE_PERIOD_US +#define CAN_DEQUEUE_PERIOD_US 500U +#endif /* USER CODE END CAN_USER_CONFIG */ +/* Enabled FDCAN peripherals. */ + [#if hasFDCAN1] #define USECAN1 [/#if] @@ -58,6 +141,128 @@ STM32 hardware configuration remains owned by CubeMX. #define USECAN3 [/#if] +/* Timers enabled in CubeMX. */ + +[#if hasTIM1] +#define CUBEMX_HAS_TIM1 +[/#if] +[#if hasTIM2] +#define CUBEMX_HAS_TIM2 +[/#if] +[#if hasTIM3] +#define CUBEMX_HAS_TIM3 +[/#if] +[#if hasTIM4] +#define CUBEMX_HAS_TIM4 +[/#if] +[#if hasTIM5] +#define CUBEMX_HAS_TIM5 +[/#if] +[#if hasTIM6] +#define CUBEMX_HAS_TIM6 +[/#if] +[#if hasTIM7] +#define CUBEMX_HAS_TIM7 +[/#if] +[#if hasTIM8] +#define CUBEMX_HAS_TIM8 +[/#if] +[#if hasTIM15] +#define CUBEMX_HAS_TIM15 +[/#if] +[#if hasTIM16] +#define CUBEMX_HAS_TIM16 +[/#if] +[#if hasTIM17] +#define CUBEMX_HAS_TIM17 +[/#if] + +/* Configuration validation. */ + +#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) +#error "TX_BUFFER_1_SIZE must be greater than zero" +#endif + +#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) +#error "TX_BUFFER_2_SIZE must be greater than zero" +#endif + +#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) +#error "TX_BUFFER_3_SIZE must be greater than zero" +#endif + +#if CAN_TIMER_TICK_US == 0U +#error "CAN_TIMER_TICK_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US == 0U +#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" +#endif + +#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US +#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" +#endif + +#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U +#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" +#endif + +#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU +#error "CAN dequeue period exceeds the supported timer auto-reload range" +#endif + +#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) +#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) +#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) +#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) +#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) +#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) +#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) +#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) +#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) +#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) +#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) +#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" +#elif (CAN_TIMER_INDEX != 1) && \ + (CAN_TIMER_INDEX != 2) && \ + (CAN_TIMER_INDEX != 3) && \ + (CAN_TIMER_INDEX != 4) && \ + (CAN_TIMER_INDEX != 5) && \ + (CAN_TIMER_INDEX != 6) && \ + (CAN_TIMER_INDEX != 7) && \ + (CAN_TIMER_INDEX != 8) && \ + (CAN_TIMER_INDEX != 15) && \ + (CAN_TIMER_INDEX != 16) && \ + (CAN_TIMER_INDEX != 17) +#error "CAN_TIMER_INDEX selects an unsupported timer" +#endif + +#define CAN_TIMER_PERIOD_COUNTS \ + (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) + +#define CAN_TIMER_AUTORELOAD \ + (CAN_TIMER_PERIOD_COUNTS - 1U) + +/* + * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. + * + * CAN_TIMER_INDEX = 5 + * CAN_TIMER_HANDLE = htim5 + */ +#define CAN_CFG_JOIN_INNER(a, b) a##b +#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) +#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) + #endif /* CAN_CFG_H */ [/#list] diff --git a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl deleted file mode 100644 index 815c29617..000000000 --- a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h_updated.ftl +++ /dev/null @@ -1,268 +0,0 @@ -[#ftl] -[#-- - Generates can_cfg.h from the active STM32CubeMX project. - - Detects enabled FDCAN and TIM peripherals and emits compile-time configuration - for the Gaucho Racing CAN runtime. - - CubeMX remains responsible for: - - FDCAN clocks, GPIO, bit timing, HAL handles, and MX_FDCANx_Init() - - TIM clocks, prescaler, NVIC configuration, HAL handle, and MX_TIMx_Init() - - The CAN runtime uses the selected CubeMX-generated TIM handle to periodically - service its software TX queues. ---] - -[#list configs as dt] - -[#assign usedIPs = (dt.usedIPs)![]] - -[#assign hasFDCAN1 = false] -[#assign hasFDCAN2 = false] -[#assign hasFDCAN3 = false] - -[#assign hasTIM1 = false] -[#assign hasTIM2 = false] -[#assign hasTIM3 = false] -[#assign hasTIM4 = false] -[#assign hasTIM5 = false] -[#assign hasTIM6 = false] -[#assign hasTIM7 = false] -[#assign hasTIM8 = false] -[#assign hasTIM15 = false] -[#assign hasTIM16 = false] -[#assign hasTIM17 = false] - -[#list usedIPs as ip] - [#assign ipName = ip?string] - - [#if ipName == "FDCAN1"] - [#assign hasFDCAN1 = true] - [/#if] - [#if ipName == "FDCAN2"] - [#assign hasFDCAN2 = true] - [/#if] - [#if ipName == "FDCAN3"] - [#assign hasFDCAN3 = true] - [/#if] - - [#if ipName == "TIM1"] - [#assign hasTIM1 = true] - [/#if] - [#if ipName == "TIM2"] - [#assign hasTIM2 = true] - [/#if] - [#if ipName == "TIM3"] - [#assign hasTIM3 = true] - [/#if] - [#if ipName == "TIM4"] - [#assign hasTIM4 = true] - [/#if] - [#if ipName == "TIM5"] - [#assign hasTIM5 = true] - [/#if] - [#if ipName == "TIM6"] - [#assign hasTIM6 = true] - [/#if] - [#if ipName == "TIM7"] - [#assign hasTIM7 = true] - [/#if] - [#if ipName == "TIM8"] - [#assign hasTIM8 = true] - [/#if] - [#if ipName == "TIM15"] - [#assign hasTIM15 = true] - [/#if] - [#if ipName == "TIM16"] - [#assign hasTIM16 = true] - [/#if] - [#if ipName == "TIM17"] - [#assign hasTIM17 = true] - [/#if] -[/#list] - -#ifndef CAN_CFG_H -#define CAN_CFG_H - -/* Generated automatically by STM32CubeMX FreeMarker. */ - -/* - * User-editable CAN runtime configuration. - * - * CAN_TIMER_INDEX: - * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. - * - * CAN_TIMER_TICK_US: - * Duration of one timer counter tick, determined by the CubeMX prescaler. - * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. - * - * CAN_DEQUEUE_PERIOD_US: - * Time between attempts to dequeue and send one software-queued CAN message. - */ -/* USER CODE BEGIN CAN_USER_CONFIG */ - -#ifndef TX_BUFFER_1_SIZE -#define TX_BUFFER_1_SIZE 20U -#endif - -#ifndef TX_BUFFER_2_SIZE -#define TX_BUFFER_2_SIZE 20U -#endif - -#ifndef TX_BUFFER_3_SIZE -#define TX_BUFFER_3_SIZE 20U -#endif - -#ifndef CAN_TIMER_INDEX -#define CAN_TIMER_INDEX 5 -#endif - -#ifndef CAN_TIMER_TICK_US -#define CAN_TIMER_TICK_US 100U -#endif - -#ifndef CAN_DEQUEUE_PERIOD_US -#define CAN_DEQUEUE_PERIOD_US 500U -#endif - -/* USER CODE END CAN_USER_CONFIG */ - -/* Enabled FDCAN peripherals. */ - -[#if hasFDCAN1] -#define USECAN1 -[/#if] - -[#if hasFDCAN2] -#define USECAN2 -[/#if] - -[#if hasFDCAN3] -#define USECAN3 -[/#if] - -/* Timers enabled in CubeMX. */ - -[#if hasTIM1] -#define CUBEMX_HAS_TIM1 -[/#if] -[#if hasTIM2] -#define CUBEMX_HAS_TIM2 -[/#if] -[#if hasTIM3] -#define CUBEMX_HAS_TIM3 -[/#if] -[#if hasTIM4] -#define CUBEMX_HAS_TIM4 -[/#if] -[#if hasTIM5] -#define CUBEMX_HAS_TIM5 -[/#if] -[#if hasTIM6] -#define CUBEMX_HAS_TIM6 -[/#if] -[#if hasTIM7] -#define CUBEMX_HAS_TIM7 -[/#if] -[#if hasTIM8] -#define CUBEMX_HAS_TIM8 -[/#if] -[#if hasTIM15] -#define CUBEMX_HAS_TIM15 -[/#if] -[#if hasTIM16] -#define CUBEMX_HAS_TIM16 -[/#if] -[#if hasTIM17] -#define CUBEMX_HAS_TIM17 -[/#if] - -/* Configuration validation. */ - -#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) -#error "TX_BUFFER_1_SIZE must be greater than zero" -#endif - -#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) -#error "TX_BUFFER_2_SIZE must be greater than zero" -#endif - -#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) -#error "TX_BUFFER_3_SIZE must be greater than zero" -#endif - -#if CAN_TIMER_TICK_US == 0U -#error "CAN_TIMER_TICK_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US == 0U -#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US -#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" -#endif - -#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U -#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" -#endif - -#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU -#error "CAN dequeue period exceeds the supported timer auto-reload range" -#endif - -#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) -#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) -#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) -#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) -#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) -#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) -#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) -#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) -#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) -#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) -#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) -#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX != 1) && \ - (CAN_TIMER_INDEX != 2) && \ - (CAN_TIMER_INDEX != 3) && \ - (CAN_TIMER_INDEX != 4) && \ - (CAN_TIMER_INDEX != 5) && \ - (CAN_TIMER_INDEX != 6) && \ - (CAN_TIMER_INDEX != 7) && \ - (CAN_TIMER_INDEX != 8) && \ - (CAN_TIMER_INDEX != 15) && \ - (CAN_TIMER_INDEX != 16) && \ - (CAN_TIMER_INDEX != 17) -#error "CAN_TIMER_INDEX selects an unsupported timer" -#endif - -#define CAN_TIMER_PERIOD_COUNTS \ - (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - -#define CAN_TIMER_AUTORELOAD \ - (CAN_TIMER_PERIOD_COUNTS - 1U) - -/* - * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. - * - * CAN_TIMER_INDEX = 5 - * CAN_TIMER_HANDLE = htim5 - */ -#define CAN_CFG_JOIN_INNER(a, b) a##b -#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) -#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) - -#endif /* CAN_CFG_H */ - -[/#list] diff --git a/Lib/CubeMXTemplates/Autogen/Src/.gitkeep b/Lib/CubeMXTemplates/Autogen/Src/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/Lib/CubeMXTemplates/can_cfg_h_timer.ftl b/Lib/CubeMXTemplates/can_cfg_h_timer.ftl deleted file mode 100644 index b7ace5741..000000000 --- a/Lib/CubeMXTemplates/can_cfg_h_timer.ftl +++ /dev/null @@ -1,177 +0,0 @@ -[#ftl] -[#-- - Generates can_cfg.h from the active STM32CubeMX project. - - Detects enabled FDCAN instances and emits the corresponding USECANx macros. - Software TX queue sizes and CAN timer settings remain user-configurable and - are preserved across normal CubeMX regeneration. - - CubeMX remains responsible for configuring and generating MX_FDCANx_Init() - and MX_TIMx_Init(). This file only selects the CubeMX-generated timer handle - used to service the CAN software TX queues. ---] - -[#list configs as dt] - -[#assign usedIPs = (dt.usedIPs)![]] -[#assign hasFDCAN1 = false] -[#assign hasFDCAN2 = false] -[#assign hasFDCAN3 = false] -[#assign hasTIM1 = false] -[#assign hasTIM2 = false] -[#assign hasTIM3 = false] -[#assign hasTIM4 = false] -[#assign hasTIM5 = false] -[#assign hasTIM6 = false] -[#assign hasTIM7 = false] -[#assign hasTIM8 = false] -[#assign hasTIM15 = false] -[#assign hasTIM16 = false] -[#assign hasTIM17 = false] - -[#list usedIPs as ip] - [#assign ipName = ip?string] - - [#if ipName?contains("FDCAN1")][#assign hasFDCAN1 = true][/#if] - [#if ipName?contains("FDCAN2")][#assign hasFDCAN2 = true][/#if] - [#if ipName?contains("FDCAN3")][#assign hasFDCAN3 = true][/#if] - - [#if ipName?contains("TIM1")][#assign hasTIM1 = true][/#if] - [#if ipName?contains("TIM2")][#assign hasTIM2 = true][/#if] - [#if ipName?contains("TIM3")][#assign hasTIM3 = true][/#if] - [#if ipName?contains("TIM4")][#assign hasTIM4 = true][/#if] - [#if ipName?contains("TIM5")][#assign hasTIM5 = true][/#if] - [#if ipName?contains("TIM6")][#assign hasTIM6 = true][/#if] - [#if ipName?contains("TIM7")][#assign hasTIM7 = true][/#if] - [#if ipName?contains("TIM8")][#assign hasTIM8 = true][/#if] - [#if ipName?contains("TIM15")][#assign hasTIM15 = true][/#if] - [#if ipName?contains("TIM16")][#assign hasTIM16 = true][/#if] - [#if ipName?contains("TIM17")][#assign hasTIM17 = true][/#if] -[/#list] - -#ifndef CAN_CFG_H -#define CAN_CFG_H - -/* Generated automatically by STM32CubeMX FreeMarker. */ - -/* USER CODE BEGIN CAN_USER_CONFIG */ - -#ifndef TX_BUFFER_1_SIZE -#define TX_BUFFER_1_SIZE 20U -#endif - -#ifndef TX_BUFFER_2_SIZE -#define TX_BUFFER_2_SIZE 20U -#endif - -#ifndef TX_BUFFER_3_SIZE -#define TX_BUFFER_3_SIZE 20U -#endif - -/* Selects htim5 when set to 5. */ -#ifndef CAN_TIMER_INDEX -#define CAN_TIMER_INDEX 5 -#endif - -/* Dequeue one CAN message every X milliseconds. */ -#ifndef CAN_DEQUEUE_PERIOD_MS -#define CAN_DEQUEUE_PERIOD_MS 2U -#endif - -/* USER CODE END CAN_USER_CONFIG */ - -[#if hasFDCAN1] -#define USECAN1 -[/#if] -[#if hasFDCAN2] -#define USECAN2 -[/#if] -[#if hasFDCAN3] -#define USECAN3 -[/#if] - -[#if hasTIM1] -#define CUBEMX_HAS_TIM1 -[/#if] -[#if hasTIM2] -#define CUBEMX_HAS_TIM2 -[/#if] -[#if hasTIM3] -#define CUBEMX_HAS_TIM3 -[/#if] -[#if hasTIM4] -#define CUBEMX_HAS_TIM4 -[/#if] -[#if hasTIM5] -#define CUBEMX_HAS_TIM5 -[/#if] -[#if hasTIM6] -#define CUBEMX_HAS_TIM6 -[/#if] -[#if hasTIM7] -#define CUBEMX_HAS_TIM7 -[/#if] -[#if hasTIM8] -#define CUBEMX_HAS_TIM8 -[/#if] -[#if hasTIM15] -#define CUBEMX_HAS_TIM15 -[/#if] -[#if hasTIM16] -#define CUBEMX_HAS_TIM16 -[/#if] -[#if hasTIM17] -#define CUBEMX_HAS_TIM17 -[/#if] - -#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) -#error "TX_BUFFER_1_SIZE must be greater than zero" -#endif -#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) -#error "TX_BUFFER_2_SIZE must be greater than zero" -#endif -#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) -#error "TX_BUFFER_3_SIZE must be greater than zero" -#endif -#if CAN_DEQUEUE_PERIOD_MS == 0U -#error "CAN_DEQUEUE_PERIOD_MS must be greater than zero" -#endif - -#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) -#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) -#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) -#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) -#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) -#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) -#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) -#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) -#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) -#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) -#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) -#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX != 1) && (CAN_TIMER_INDEX != 2) && \ - (CAN_TIMER_INDEX != 3) && (CAN_TIMER_INDEX != 4) && \ - (CAN_TIMER_INDEX != 5) && (CAN_TIMER_INDEX != 6) && \ - (CAN_TIMER_INDEX != 7) && (CAN_TIMER_INDEX != 8) && \ - (CAN_TIMER_INDEX != 15) && (CAN_TIMER_INDEX != 16) && \ - (CAN_TIMER_INDEX != 17) -#error "CAN_TIMER_INDEX selects an unsupported timer" -#endif - -#define CAN_CFG_JOIN_INNER(a, b) a##b -#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) -#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) - -#endif /* CAN_CFG_H */ - -[/#list] From d5c1ae37bace22d356886ff4f4b6419d0a63b163 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sat, 18 Jul 2026 17:26:04 -0700 Subject: [PATCH 17/38] Critical section macro that needs testing still Signed-off-by: Daniel Hansen --- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 3baff2c60..882eede84 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -2,11 +2,39 @@ #include #include "CubeMXCan.h" +#include "Stringification.h" #include "main.h" #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H +/** + * @brief Internal function to automatically restore the interrupt state when exiting a critical section. + * + * This function is intended to be used with the GCC cleanup attribute to automatically restore the interrupt state when a critical section is exited. It takes a pointer to a state variable that holds + * the previous interrupt state and restores it using the __set_PRIMASK function. + * + * @warning This function is intended for internal use only and should not be called directly by user code. Use the CRITICAL_SECTION macro instead. + */ +static inline void _magic_auto_exit_critical(uint32_t *state_var) +{ + if (state_var) { + __set_PRIMASK(*state_var); + } +} + +/** + * @brief Macro to create a critical section that disables interrupts for the duration of the block. + * + * This macro uses the GCC cleanup attribute to automatically restore the interrupt state when the block is exited, regardless of how the block is exited (e.g., return, break, continue). + * + * @warning This macro should be used with caution, as it can lead to deadlocks or other issues if not used correctly. It is recommended to use this macro only in situations where it is necessary to + * disable interrupts for a short period of time. + */ +#define CRITICAL_SECTION \ + for (__attribute__((cleanup(_magic_auto_exit_critical))) uint32_t CONCAT(auto_state_, __LINE__) = __get_PRIMASK(), CONCAT(auto_run_, __LINE__) = (__disable_irq(), 1); \ + CONCAT(auto_run_, __LINE__); CONCAT(auto_run_, __LINE__) = 0) + /** * @brief CubeMX CAN handle structure * From e251bd0df77b34968af5dc6626b7806edcd9b25d Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sat, 18 Jul 2026 17:45:54 -0700 Subject: [PATCH 18/38] Critical section safe code Signed-off-by: Daniel Hansen --- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 1 + Lib/Peripherals/CubeCAN/Src/can_init.c | 79 +++++++++++++------ Lib/Peripherals/CubeCAN/Src/can_it.c | 16 +++- Lib/Peripherals/CubeCAN/Src/can_utils.c | 4 + 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 882eede84..f0e0a8dfa 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -1,3 +1,4 @@ +#include #include #include diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 2d164d059..78904cfe8 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -99,14 +99,34 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf return NULL; } - CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); - if (handle == NULL) { - for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (s_handles[i].hfdcan == NULL) { - handle = &s_handles[i]; + CubeMXCan_Handle *handle = NULL; + bool register_ok = false; + + CRITICAL_SECTION + { + handle = CubeMXCan_Private_GetHandle(hfdcan); + if (handle == NULL) { + for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (s_handles[i].hfdcan == NULL) { + handle = &s_handles[i]; + memset(handle, 0, sizeof(*handle)); + handle->hfdcan = hfdcan; + break; + } + } + } + + if (handle != NULL) { + handle->config = *config; + handle->tx_head = 0U; + handle->tx_count = 0U; + handle->started = false; + + if (CubeMXCan_Private_RegisterHandle(hfdcan, handle) == HAL_OK) { + register_ok = true; + } else { memset(handle, 0, sizeof(*handle)); - handle->hfdcan = hfdcan; - break; + handle = NULL; } } } @@ -116,12 +136,7 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf return NULL; } - handle->config = *config; - handle->tx_head = 0U; - handle->tx_count = 0U; - handle->started = false; - - if (CubeMXCan_Private_RegisterHandle(hfdcan, handle) != HAL_OK) { + if (!register_ok) { LOGOMATIC("CubeMXCan_Init: failed to register handle\n"); return NULL; } @@ -135,7 +150,6 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf if (!s_timer_started) { s_timer_started = true; } - return handle; } @@ -149,7 +163,11 @@ HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle) return HAL_ERROR; } - handle->started = true; + CRITICAL_SECTION + { + handle->started = true; + } + return HAL_OK; } @@ -159,12 +177,15 @@ HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle) return HAL_ERROR; } + CRITICAL_SECTION + { + handle->started = false; + } + if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { return HAL_ERROR; } - handle->started = false; - return HAL_OK; } @@ -175,8 +196,13 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) } (void)CubeMXCan_Stop(handle); - CubeMXCan_Private_UnregisterHandle(handle->hfdcan); - memset(handle, 0, sizeof(*handle)); + + CRITICAL_SECTION + { + CubeMXCan_Private_UnregisterHandle(handle->hfdcan); + memset(handle, 0, sizeof(*handle)); + } + return HAL_OK; } @@ -195,13 +221,16 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess return HAL_ERROR; } - uint32_t insert_index = (handle->tx_head + handle->tx_count) % CUBEMX_CAN_TX_QUEUE_SIZE; - handle->tx_queue[insert_index] = *message; + CRITICAL_SECTION + { + uint32_t insert_index = (handle->tx_head + handle->tx_count) % CUBEMX_CAN_TX_QUEUE_SIZE; + handle->tx_queue[insert_index] = *message; - if (handle->tx_count < CUBEMX_CAN_TX_QUEUE_SIZE) { - handle->tx_count++; - } else { - handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; + if (handle->tx_count < CUBEMX_CAN_TX_QUEUE_SIZE) { + handle->tx_count++; + } else { + handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; + } } return HAL_OK; diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index 309f6d174..b9ffa71ad 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -37,8 +37,18 @@ void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan) return; } - CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); - if (handle == NULL || handle->config.rx_callback == NULL) { + CubeCAN_RxCallback rx_callback_stack = NULL; + void *user_ctx_stack = NULL; + + CRITICAL_SECTION { + CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); + if (handle != NULL && handle->config.rx_callback != NULL) { + rx_callback_stack = handle->config.rx_callback; + user_ctx_stack = handle->config.user_ctx; + } + } + + if (rx_callback_stack == NULL) { FDCAN_RxHeaderTypeDef rx_header = {0}; uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); @@ -55,5 +65,5 @@ void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan) CAN_Identifier identifier = Deconstruct_CAN_Identifier(rx_header.Identifier); uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); - handle->config.rx_callback(handle->config.user_ctx, &identifier, rx_data, size); + rx_callback_stack(user_ctx_stack, &identifier, rx_data, size); } diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 2ba864b0a..09f2932e3 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -86,6 +86,10 @@ uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) { if (handle == NULL || handle->hfdcan == NULL || handle->tx_count == 0U) { + return HAL_ERROR; + } + + if (handle->tx_count == 0U) { return HAL_OK; } From 1893a6c24a00c765f2702daee53b36b60b718717 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sat, 18 Jul 2026 18:24:24 -0700 Subject: [PATCH 19/38] HOOTL testing of critical sections is very important Signed-off-by: Daniel Hansen --- Lib/GlobalShare/Inc/CriticalSection.h | 59 ++++++++++ Lib/GlobalShare/Test/criticalsection.c | 109 ++++++++++++++++++ Lib/GlobalShare/common.cmake | 10 ++ .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 28 +---- Lib/Peripherals/CubeCAN/cubemx_can.cmake | 4 +- Lib/cmake/HOOTL.cmake | 1 + 6 files changed, 183 insertions(+), 28 deletions(-) create mode 100644 Lib/GlobalShare/Inc/CriticalSection.h create mode 100644 Lib/GlobalShare/Test/criticalsection.c diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h new file mode 100644 index 000000000..d9b47c01a --- /dev/null +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -0,0 +1,59 @@ +#include + +#include "Stringification.h" + +#ifndef CRITICAL_SECTION_H +#define CRITICAL_SECTION_H + +#ifdef HOOTL_TEST +#include + +extern pthread_mutex_t __mock_global_irq_mutex; +extern uint32_t __mock_primask_state; + +static inline uint32_t __get_PRIMASK(void) +{ + return __mock_primask_state; +} + +static inline void __disable_irq(void) +{ + pthread_mutex_lock(&__mock_global_irq_mutex); + __mock_primask_state = 1; +} + +static inline void __set_PRIMASK(uint32_t state) +{ + pthread_mutex_unlock(&__mock_global_irq_mutex); + __mock_primask_state = state; +} +#endif + +/** + * @brief Internal function to automatically restore the interrupt state when exiting a critical section. + * + * This function is intended to be used with the GCC cleanup attribute to automatically restore the interrupt state when a critical section is exited. It takes a pointer to a state variable that holds + * the previous interrupt state and restores it using the __set_PRIMASK function. + * + * @warning This function is intended for internal use only and should not be called directly by user code. Use the CRITICAL_SECTION macro instead. + */ +static inline void _magic_auto_exit_critical(uint32_t *state_var) +{ + if (state_var) { + __set_PRIMASK(*state_var); + } +} + +/** + * @brief Macro to create a critical section that disables interrupts for the duration of the block. + * + * This macro uses the GCC cleanup attribute to automatically restore the interrupt state when the block is exited, regardless of how the block is exited (e.g., return, break, continue). + * + * @warning This macro should be used with caution, as it can lead to deadlocks or other issues if not used correctly. It is recommended to use this macro only in situations where it is necessary to + * disable interrupts for a short period of time. + */ +#define CRITICAL_SECTION \ + for (__attribute__((cleanup(_magic_auto_exit_critical))) uint32_t CONCAT(auto_state_, __LINE__) = __get_PRIMASK(), CONCAT(auto_run_, __LINE__) = (__disable_irq(), 1); \ + CONCAT(auto_run_, __LINE__); CONCAT(auto_run_, __LINE__) = 0) + +#endif diff --git a/Lib/GlobalShare/Test/criticalsection.c b/Lib/GlobalShare/Test/criticalsection.c new file mode 100644 index 000000000..472d61a44 --- /dev/null +++ b/Lib/GlobalShare/Test/criticalsection.c @@ -0,0 +1,109 @@ +#include "CriticalSection.h" + +#include +#include +#include + +#include "Unused.h" + +#define NUM_THREADS 40 +#define INCREMENTS_PER_THREAD 100000 + +pthread_mutex_t __mock_global_irq_mutex; +uint32_t __mock_primask_state = 0; + +__attribute__((constructor)) static void init_recursive_mock_mutex(void) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&__mock_global_irq_mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +long long global_counter = 0; + +void *thread_worker_good(void *arg) +{ + UNUSED(arg); + + for (int i = 0; i < INCREMENTS_PER_THREAD; i++) { + CRITICAL_SECTION + { + CRITICAL_SECTION + { + global_counter++; + } + } + } + + return NULL; +} + +void *thread_worker_bad(void *arg) +{ + UNUSED(arg); + + for (int i = 0; i < INCREMENTS_PER_THREAD; i++) { + global_counter++; + } + + return NULL; +} + +int main(void) +{ + pthread_t threads[NUM_THREADS]; + int thread_ids[NUM_THREADS]; + + printf("Starting %d 'good' threads, each incrementing %d times...\n", NUM_THREADS, INCREMENTS_PER_THREAD); + global_counter = 0; + + for (int i = 0; i < NUM_THREADS; i++) { + thread_ids[i] = i; + if (pthread_create(&threads[i], NULL, thread_worker_good, &thread_ids[i]) != 0) { + printf("Failed to create thread"); + return 1; + } + } + + for (int i = 0; i < NUM_THREADS; i++) { + pthread_join(threads[i], NULL); + } + + long long expected_value = (long long)NUM_THREADS * INCREMENTS_PER_THREAD; + printf("\tExpected final counter value: %lld\n", expected_value); + printf("\tActual global_counter value: %lld\n", global_counter); + + if (global_counter == expected_value) { + printf("\tMocks and nested critical sections passed!\n"); + } else { + printf("\tData race detected! Your critical section failed.\n"); + return 2; + } + + printf("\nStarting %d 'bad' threads, each incrementing %d times...\n", NUM_THREADS, INCREMENTS_PER_THREAD); + global_counter = 0; + + for (int i = 0; i < NUM_THREADS; i++) { + thread_ids[i] = i; + if (pthread_create(&threads[i], NULL, thread_worker_bad, &thread_ids[i]) != 0) { + printf("Failed to create thread"); + return 3; + } + } + + for (int i = 0; i < NUM_THREADS; i++) { + pthread_join(threads[i], NULL); + } + + printf("\tExpected final counter value: %lld\n", expected_value); + printf("\tActual global_counter value: %lld\n", global_counter); + if (global_counter == expected_value) { + printf("\tUnexpectedly, the counter is correct without critical sections. This is highly unlikely and may indicate a problem with the test setup.\n"); + return 4; + } + + printf("\tAs expected, the counter is incorrect without critical sections. Data race detected!\n"); + return 0; +} diff --git a/Lib/GlobalShare/common.cmake b/Lib/GlobalShare/common.cmake index c47123510..116b5485b 100644 --- a/Lib/GlobalShare/common.cmake +++ b/Lib/GlobalShare/common.cmake @@ -51,4 +51,14 @@ if(CMAKE_PRESET_NAME STREQUAL "HOOTLTest") ) target_link_libraries(verify_min_max PRIVATE GLOBALSHARE_LIB) add_test(verify_min_max_test verify_min_max) + + find_package(Threads REQUIRED) + add_executable(criticalsection) + target_sources( + criticalsection + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/Test/criticalsection.c + ) + target_link_libraries(criticalsection PRIVATE GLOBALSHARE_LIB Threads::Threads) + add_test(criticalsection_test criticalsection) endif() diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index f0e0a8dfa..7477ffb06 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -4,38 +4,12 @@ #include "CubeMXCan.h" #include "Stringification.h" +#include "Logomatic.h" #include "main.h" #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H -/** - * @brief Internal function to automatically restore the interrupt state when exiting a critical section. - * - * This function is intended to be used with the GCC cleanup attribute to automatically restore the interrupt state when a critical section is exited. It takes a pointer to a state variable that holds - * the previous interrupt state and restores it using the __set_PRIMASK function. - * - * @warning This function is intended for internal use only and should not be called directly by user code. Use the CRITICAL_SECTION macro instead. - */ -static inline void _magic_auto_exit_critical(uint32_t *state_var) -{ - if (state_var) { - __set_PRIMASK(*state_var); - } -} - -/** - * @brief Macro to create a critical section that disables interrupts for the duration of the block. - * - * This macro uses the GCC cleanup attribute to automatically restore the interrupt state when the block is exited, regardless of how the block is exited (e.g., return, break, continue). - * - * @warning This macro should be used with caution, as it can lead to deadlocks or other issues if not used correctly. It is recommended to use this macro only in situations where it is necessary to - * disable interrupts for a short period of time. - */ -#define CRITICAL_SECTION \ - for (__attribute__((cleanup(_magic_auto_exit_critical))) uint32_t CONCAT(auto_state_, __LINE__) = __get_PRIMASK(), CONCAT(auto_run_, __LINE__) = (__disable_irq(), 1); \ - CONCAT(auto_run_, __LINE__); CONCAT(auto_run_, __LINE__) = 0) - /** * @brief CubeMX CAN handle structure * diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake index 3fe5c3cd6..23a051caa 100644 --- a/Lib/Peripherals/CubeCAN/cubemx_can.cmake +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -20,4 +20,6 @@ target_link_libraries( CANfigurator ) -# TODO Unit testing +if(CMAKE_PRESET_NAME STREQUAL "HOOTLTest") + # FIXME Add HOOTL tests +endif() diff --git a/Lib/cmake/HOOTL.cmake b/Lib/cmake/HOOTL.cmake index e9fc8b613..e2dfaea15 100644 --- a/Lib/cmake/HOOTL.cmake +++ b/Lib/cmake/HOOTL.cmake @@ -29,6 +29,7 @@ add_compile_options( -Wvla -Wdouble-promotion -g + -DHOOTL_TEST ) if(APPLE) # MacOS has a different syntax for linker fatal warnings From 83fdb204ebd2970e812efbd002b958520a5a9cb0 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sat, 18 Jul 2026 18:28:58 -0700 Subject: [PATCH 20/38] Make variable names harder to accidentally cross And also you should never start a variable with `_` unless you are doing the dark magic, not merely using it... Signed-off-by: Daniel Hansen --- Lib/GlobalShare/Inc/CriticalSection.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h index d9b47c01a..7e6fd0d8d 100644 --- a/Lib/GlobalShare/Inc/CriticalSection.h +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -37,7 +37,7 @@ static inline void __set_PRIMASK(uint32_t state) * * @warning This function is intended for internal use only and should not be called directly by user code. Use the CRITICAL_SECTION macro instead. */ -static inline void _magic_auto_exit_critical(uint32_t *state_var) +static inline void _magic_auto_critical_exit(uint32_t *state_var) { if (state_var) { __set_PRIMASK(*state_var); @@ -53,7 +53,7 @@ static inline void _magic_auto_exit_critical(uint32_t *state_var) * disable interrupts for a short period of time. */ #define CRITICAL_SECTION \ - for (__attribute__((cleanup(_magic_auto_exit_critical))) uint32_t CONCAT(auto_state_, __LINE__) = __get_PRIMASK(), CONCAT(auto_run_, __LINE__) = (__disable_irq(), 1); \ - CONCAT(auto_run_, __LINE__); CONCAT(auto_run_, __LINE__) = 0) + for (__attribute__((cleanup(_magic_auto_critical_exit))) uint32_t CONCAT(_magic_auto_critical_state_, __LINE__) = __get_PRIMASK(), CONCAT(_magic_auto_critical_run_, __LINE__) = (__disable_irq(), 1); \ + CONCAT(_magic_auto_critical_run_, __LINE__); CONCAT(_magic_auto_critical_run_, __LINE__) = 0) #endif From 0f949c7fa1848b3ac8c75c157bbc601ed06ea6f3 Mon Sep 17 00:00:00 2001 From: TrainmanR Date: Mon, 20 Jul 2026 12:19:43 -0700 Subject: [PATCH 21/38] Scripting for CubeMX Templates IOC Generation Numereous issues with relative paths that were created in CUBEMX, so to solve template generation we decided to test scripts, the CMAKE one is meant for all OS/use, but the rest are just redundancies/backups in case it fails --- CUBEMXTESTING/Autogen/Inc/can_cfg.h | 2 + CUBEMXTESTING/CUBEMXTESTING.ioc | 8 +- tools/ConfigureCubeMXPaths.cmake | 220 +++++++++++++++++++++++ tools/configure_cubemx_paths.ps1 | 119 +++++++++++++ tools/configure_cubemx_paths_linux.sh | 245 ++++++++++++++++++++++++++ tools/configure_cubemx_paths_macos.sh | 245 ++++++++++++++++++++++++++ 6 files changed, 835 insertions(+), 4 deletions(-) create mode 100644 tools/ConfigureCubeMXPaths.cmake create mode 100644 tools/configure_cubemx_paths.ps1 create mode 100644 tools/configure_cubemx_paths_linux.sh create mode 100644 tools/configure_cubemx_paths_macos.sh diff --git a/CUBEMXTESTING/Autogen/Inc/can_cfg.h b/CUBEMXTESTING/Autogen/Inc/can_cfg.h index 288ec9a9b..0c6609c06 100644 --- a/CUBEMXTESTING/Autogen/Inc/can_cfg.h +++ b/CUBEMXTESTING/Autogen/Inc/can_cfg.h @@ -51,6 +51,8 @@ #define USECAN2 +#define USECAN3 + /* Timers enabled in CubeMX. */ #define CUBEMX_HAS_TIM5 diff --git a/CUBEMXTESTING/CUBEMXTESTING.ioc b/CUBEMXTESTING/CUBEMXTESTING.ioc index 1d4d092cb..098aab57a 100644 --- a/CUBEMXTESTING/CUBEMXTESTING.ioc +++ b/CUBEMXTESTING/CUBEMXTESTING.ioc @@ -129,16 +129,16 @@ ProjectManager.ProjectStructure= ProjectManager.RegisterCallBack= ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=EWARM V8.50 -ProjectManager.TemplateDestinationPath=. -ProjectManager.TemplateSourcePath=..\\Lib\\CubeMXTemplates -ProjectManager.TemplatesList=Autogen\\Inc\\can_cfg_h.ftl, +ProjectManager.TemplateDestinationPath=C\:\\Users\\maxnm\\Firmware\\CUBEMXTESTING +ProjectManager.TemplateSourcePath=C\:\\Users\\maxnm\\Firmware\\Lib\\CubeMXTemplates +ProjectManager.TemplatesList=\\Autogen\\Inc\\can_cfg_h.ftl, ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false ProjectManager.UseDefaultDestinationPath=true ProjectManager.UseDefaultSourcePath=true -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_FDCAN2_Init-FDCAN2-false-HAL-true,5-MX_TIM5_Init-TIM5-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_FDCAN2_Init-FDCAN2-false-HAL-true,5-MX_TIM5_Init-TIM5-false-HAL-true,6-MX_FDCAN3_Init-FDCAN3-false-HAL-true RCC.ADC12Freq_Value=160000000 RCC.ADC345Freq_Value=160000000 RCC.AHBFreq_Value=160000000 diff --git a/tools/ConfigureCubeMXPaths.cmake b/tools/ConfigureCubeMXPaths.cmake new file mode 100644 index 000000000..767cc4bd9 --- /dev/null +++ b/tools/ConfigureCubeMXPaths.cmake @@ -0,0 +1,220 @@ +# ConfigureCubeMXPaths.cmake +# +# Cross-platform STM32CubeMX template path configuration. +# +# Expected repository layout: +# +# Firmware/ +# ├── tools/ +# │ └── ConfigureCubeMXPaths.cmake +# ├── CUBEMXTESTING/ +# │ └── CUBEMXTESTING.ioc +# └── Lib/ +# └── CubeMXTemplates/ +# └── Autogen/ +# └── Inc/ +# └── can_cfg_h.ftl +# +# Run manually from the repository root: +# +# cmake -P tools/ConfigureCubeMXPaths.cmake +# +# Optional overrides: +# +# cmake +# -DIOC_FILE=/path/to/project.ioc +# -DTEMPLATE_ROOT=/path/to/CubeMXTemplates +# -DPROJECT_OUTPUT_DIR=/path/to/project +# -P tools/ConfigureCubeMXPaths.cmake +# +# This script writes absolute paths because STM32CubeMX does not reliably +# resolve relative custom-template paths. + +cmake_minimum_required(VERSION 3.20) + +# --------------------------------------------------------------------------- +# Locate repository and default paths +# --------------------------------------------------------------------------- + +get_filename_component(SCRIPT_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) +get_filename_component(REPOSITORY_ROOT "${SCRIPT_DIR}/.." ABSOLUTE) + +if(NOT DEFINED IOC_FILE) + set(IOC_FILE + "${REPOSITORY_ROOT}/CUBEMXTESTING/CUBEMXTESTING.ioc" + ) +endif() + +if(NOT DEFINED PROJECT_OUTPUT_DIR) + set(PROJECT_OUTPUT_DIR + "${REPOSITORY_ROOT}/CUBEMXTESTING" + ) +endif() + +if(NOT DEFINED TEMPLATE_ROOT) + set(TEMPLATE_ROOT + "${REPOSITORY_ROOT}/Lib/CubeMXTemplates" + ) +endif() + +set(TEMPLATE_RELATIVE_PATH + "Autogen/Inc/can_cfg_h.ftl" +) + +get_filename_component(IOC_FILE "${IOC_FILE}" ABSOLUTE) +get_filename_component(PROJECT_OUTPUT_DIR "${PROJECT_OUTPUT_DIR}" ABSOLUTE) +get_filename_component(TEMPLATE_ROOT "${TEMPLATE_ROOT}" ABSOLUTE) + +set(TEMPLATE_FILE + "${TEMPLATE_ROOT}/${TEMPLATE_RELATIVE_PATH}" +) + +# --------------------------------------------------------------------------- +# Validate inputs +# --------------------------------------------------------------------------- + +if(NOT EXISTS "${IOC_FILE}") + message(FATAL_ERROR + "CubeMX .ioc file was not found:\n" + " ${IOC_FILE}" + ) +endif() + +if(NOT IS_DIRECTORY "${PROJECT_OUTPUT_DIR}") + message(FATAL_ERROR + "CubeMX project output directory was not found:\n" + " ${PROJECT_OUTPUT_DIR}" + ) +endif() + +if(NOT IS_DIRECTORY "${TEMPLATE_ROOT}") + message(FATAL_ERROR + "CubeMX template root was not found:\n" + " ${TEMPLATE_ROOT}" + ) +endif() + +if(NOT EXISTS "${TEMPLATE_FILE}") + message(FATAL_ERROR + "CubeMX FreeMarker template was not found:\n" + " ${TEMPLATE_FILE}" + ) +endif() + +# --------------------------------------------------------------------------- +# Convert paths to the format expected by CubeMX's .ioc property file +# --------------------------------------------------------------------------- + +function(convert_to_cubemx_path INPUT_PATH OUTPUT_VARIABLE) + if(WIN32) + # Convert: + # C:/Users/name/Firmware + # to: + # C\:\\Users\\name\\Firmware + file(TO_NATIVE_PATH "${INPUT_PATH}" NATIVE_PATH) + string(REPLACE "\\" "\\\\" ESCAPED_PATH "${NATIVE_PATH}") + string(REPLACE ":" "\\:" ESCAPED_PATH "${ESCAPED_PATH}") + else() + # macOS/Linux paths use forward slashes and require no drive-letter + # escaping. + file(TO_CMAKE_PATH "${INPUT_PATH}" ESCAPED_PATH) + endif() + + set("${OUTPUT_VARIABLE}" "${ESCAPED_PATH}" PARENT_SCOPE) +endfunction() + +convert_to_cubemx_path( + "${PROJECT_OUTPUT_DIR}" + CUBEMX_PROJECT_OUTPUT_DIR +) + +convert_to_cubemx_path( + "${TEMPLATE_ROOT}" + CUBEMX_TEMPLATE_ROOT +) + +if(WIN32) + set(CUBEMX_TEMPLATE_LIST + "\\\\Autogen\\\\Inc\\\\can_cfg_h.ftl," + ) +else() + set(CUBEMX_TEMPLATE_LIST + "/Autogen/Inc/can_cfg_h.ftl," + ) +endif() + +set(DESTINATION_LINE + "ProjectManager.TemplateDestinationPath=${CUBEMX_PROJECT_OUTPUT_DIR}" +) + +set(SOURCE_LINE + "ProjectManager.TemplateSourcePath=${CUBEMX_TEMPLATE_ROOT}" +) + +set(TEMPLATES_LINE + "ProjectManager.TemplatesList=${CUBEMX_TEMPLATE_LIST}" +) + +# --------------------------------------------------------------------------- +# Rewrite or add the three CubeMX settings +# --------------------------------------------------------------------------- + +file(STRINGS "${IOC_FILE}" IOC_LINES ENCODING UTF-8) + +set(UPDATED_CONTENT "") +set(FOUND_DESTINATION FALSE) +set(FOUND_SOURCE FALSE) +set(FOUND_TEMPLATES FALSE) + +foreach(LINE IN LISTS IOC_LINES) + if(LINE MATCHES "^ProjectManager\\.TemplateDestinationPath=") + string(APPEND UPDATED_CONTENT "${DESTINATION_LINE}\n") + set(FOUND_DESTINATION TRUE) + + elseif(LINE MATCHES "^ProjectManager\\.TemplateSourcePath=") + string(APPEND UPDATED_CONTENT "${SOURCE_LINE}\n") + set(FOUND_SOURCE TRUE) + + elseif(LINE MATCHES "^ProjectManager\\.TemplatesList=") + string(APPEND UPDATED_CONTENT "${TEMPLATES_LINE}\n") + set(FOUND_TEMPLATES TRUE) + + else() + string(APPEND UPDATED_CONTENT "${LINE}\n") + endif() +endforeach() + +if(NOT FOUND_DESTINATION) + string(APPEND UPDATED_CONTENT "${DESTINATION_LINE}\n") +endif() + +if(NOT FOUND_SOURCE) + string(APPEND UPDATED_CONTENT "${SOURCE_LINE}\n") +endif() + +if(NOT FOUND_TEMPLATES) + string(APPEND UPDATED_CONTENT "${TEMPLATES_LINE}\n") +endif() + +# Keep a backup of the current .ioc file before modifying it. +configure_file( + "${IOC_FILE}" + "${IOC_FILE}.bak" + COPYONLY +) + +file(WRITE "${IOC_FILE}" "${UPDATED_CONTENT}") + +# --------------------------------------------------------------------------- +# Report result +# --------------------------------------------------------------------------- + +message(STATUS "") +message(STATUS "CubeMX template configuration updated successfully.") +message(STATUS "") +message(STATUS "${DESTINATION_LINE}") +message(STATUS "${SOURCE_LINE}") +message(STATUS "${TEMPLATES_LINE}") +message(STATUS "") +message(STATUS "Backup created at:") +message(STATUS " ${IOC_FILE}.bak") diff --git a/tools/configure_cubemx_paths.ps1 b/tools/configure_cubemx_paths.ps1 new file mode 100644 index 000000000..4144b2eba --- /dev/null +++ b/tools/configure_cubemx_paths.ps1 @@ -0,0 +1,119 @@ +# configure_cubemx_paths.ps1 +# Updates STM32CubeMX template paths using the current repository location. +# +# Expected repository structure: +# Firmware/ +# ├── tools/configure_cubemx_paths.ps1 +# ├── CUBEMXTESTING/CUBEMXTESTING.ioc +# └── Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl + +$ErrorActionPreference = "Stop" + +# Script location: Firmware/tools +$toolsDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path + +# Repository root: Firmware +$repoRoot = Split-Path -Parent $toolsDirectory + +$iocPath = Join-Path $repoRoot "CUBEMXTESTING\CUBEMXTESTING.ioc" +$projectPath = Join-Path $repoRoot "CUBEMXTESTING" +$templatePath = Join-Path $repoRoot "Lib\CubeMXTemplates" + +if (!(Test-Path -LiteralPath $iocPath)) { + Write-Error "Could not find CubeMX project file: $iocPath" + exit 1 +} + +if (!(Test-Path -LiteralPath $templatePath)) { + Write-Error "Could not find CubeMX template folder: $templatePath" + exit 1 +} + +$templateFile = Join-Path $templatePath "Autogen\Inc\can_cfg_h.ftl" +if (!(Test-Path -LiteralPath $templateFile)) { + Write-Error "Could not find CubeMX template file: $templateFile" + exit 1 +} + +# CubeMX .ioc escaping: +# C:\Users\... becomes C\:\\Users\\... +function Convert-ToCubeMXPath { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + return $Path.Replace("\", "\\").Replace(":", "\:") +} + +$escapedProjectPath = Convert-ToCubeMXPath -Path $projectPath +$escapedTemplatePath = Convert-ToCubeMXPath -Path $templatePath + +$desiredDestinationLine = "ProjectManager.TemplateDestinationPath=$escapedProjectPath" +$desiredSourceLine = "ProjectManager.TemplateSourcePath=$escapedTemplatePath" + +# CubeMX expects a leading escaped backslash and a trailing comma here. +$desiredTemplatesLine = "ProjectManager.TemplatesList=\\Autogen\\Inc\\can_cfg_h.ftl," + +$content = Get-Content -LiteralPath $iocPath + +function Set-OrAddLine { + param( + [Parameter(Mandatory = $true)] + [string[]]$Content, + + [Parameter(Mandatory = $true)] + [string]$Key, + + [Parameter(Mandatory = $true)] + [string]$Replacement + ) + + $pattern = "^" + [regex]::Escape($Key) + "=.*$" + $found = $false + + $updated = foreach ($line in $Content) { + if ($line -match $pattern) { + $found = $true + $Replacement + } + else { + $line + } + } + + if (!$found) { + $updated += $Replacement + } + + return ,$updated +} + +$content = Set-OrAddLine ` + -Content $content ` + -Key "ProjectManager.TemplateDestinationPath" ` + -Replacement $desiredDestinationLine + +$content = Set-OrAddLine ` + -Content $content ` + -Key "ProjectManager.TemplateSourcePath" ` + -Replacement $desiredSourceLine + +$content = Set-OrAddLine ` + -Content $content ` + -Key "ProjectManager.TemplatesList" ` + -Replacement $desiredTemplatesLine + +# Preserve a normal text encoding without adding a UTF-8 BOM. +[System.IO.File]::WriteAllLines( + $iocPath, + $content, + [System.Text.UTF8Encoding]::new($false) +) + +Write-Host "" +Write-Host "CubeMX template configuration updated successfully." +Write-Host "" +Write-Host $desiredDestinationLine +Write-Host $desiredSourceLine +Write-Host $desiredTemplatesLine \ No newline at end of file diff --git a/tools/configure_cubemx_paths_linux.sh b/tools/configure_cubemx_paths_linux.sh new file mode 100644 index 000000000..fda034ba7 --- /dev/null +++ b/tools/configure_cubemx_paths_linux.sh @@ -0,0 +1,245 @@ +#!/usr/bin/env bash +# +# Cross-platform Unix STM32CubeMX custom-template path configurator. +# Compatible with macOS Bash 3.2+ and common Linux Bash versions. +# +# Expected repository structure: +# +# Firmware/ +# ├── tools/ +# │ └── configure_cubemx_paths_linux.sh +# ├── CUBEMXTESTING/ +# │ └── CUBEMXTESTING.ioc +# └── Lib/ +# └── CubeMXTemplates/ +# └── Autogen/ +# └── Inc/ +# └── can_cfg_h.ftl +# +# Usage: +# bash tools/configure_cubemx_paths_linux.sh +# +# Optional overrides: +# IOC_FILE=/path/project.ioc \ +# PROJECT_OUTPUT_DIR=/path/project \ +# TEMPLATE_ROOT=/path/CubeMXTemplates \ +# bash tools/configure_cubemx_paths_linux.sh +# +# Behavior: +# - validates all expected paths; +# - removes stale or duplicate CubeMX template properties; +# - writes exactly one correct copy of each property; +# - creates an .ioc.bak backup; +# - writes through a temporary file; +# - verifies the result from disk; +# - is idempotent. + +set -euo pipefail + +EXPECTED_OS="linux" + +die() { + printf 'ERROR: %s\n' "$*" >&2 + exit 1 +} + +info() { + printf '%s\n' "$*" +} + +detect_os() { + case "$(uname -s)" in + Darwin) printf '%s\n' "macos" ;; + Linux) printf '%s\n' "linux" ;; + *) printf '%s\n' "unsupported" ;; + esac +} + +CURRENT_OS="$(detect_os)" +if [ "$CURRENT_OS" != "$EXPECTED_OS" ]; then + die "This script is intended for $EXPECTED_OS, but detected $CURRENT_OS." +fi + +# Resolve the physical directory containing this script without requiring +# realpath, which is not included with older macOS installations. +SCRIPT_DIR="$( + CDPATH= cd -- "$(dirname -- "$0")" >/dev/null 2>&1 + pwd -P +)" +REPOSITORY_ROOT="$( + CDPATH= cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 + pwd -P +)" + +IOC_FILE="${IOC_FILE:-$REPOSITORY_ROOT/CUBEMXTESTING/CUBEMXTESTING.ioc}" +PROJECT_OUTPUT_DIR="${PROJECT_OUTPUT_DIR:-$REPOSITORY_ROOT/CUBEMXTESTING}" +TEMPLATE_ROOT="${TEMPLATE_ROOT:-$REPOSITORY_ROOT/Lib/CubeMXTemplates}" +TEMPLATE_FILE="$TEMPLATE_ROOT/Autogen/Inc/can_cfg_h.ftl" + +[ -f "$IOC_FILE" ] || + die "CubeMX .ioc file was not found: $IOC_FILE" + +[ -d "$PROJECT_OUTPUT_DIR" ] || + die "CubeMX project output directory was not found: $PROJECT_OUTPUT_DIR" + +[ -d "$TEMPLATE_ROOT" ] || + die "CubeMX template root was not found: $TEMPLATE_ROOT" + +[ -f "$TEMPLATE_FILE" ] || + die "CubeMX FreeMarker template was not found: $TEMPLATE_FILE" + +# Convert directories to physical absolute paths. +PROJECT_OUTPUT_DIR="$( + CDPATH= cd -- "$PROJECT_OUTPUT_DIR" >/dev/null 2>&1 + pwd -P +)" +TEMPLATE_ROOT="$( + CDPATH= cd -- "$TEMPLATE_ROOT" >/dev/null 2>&1 + pwd -P +)" + +DESTINATION_KEY='ProjectManager.TemplateDestinationPath' +SOURCE_KEY='ProjectManager.TemplateSourcePath' +TEMPLATES_KEY='ProjectManager.TemplatesList' + +DESTINATION_LINE="${DESTINATION_KEY}=${PROJECT_OUTPUT_DIR}" +SOURCE_LINE="${SOURCE_KEY}=${TEMPLATE_ROOT}" +TEMPLATES_LINE="${TEMPLATES_KEY}=/Autogen/Inc/can_cfg_h.ftl," + +IOC_DIRECTORY="$(dirname -- "$IOC_FILE")" +IOC_BASENAME="$(basename -- "$IOC_FILE")" +BACKUP_FILE="${IOC_FILE}.bak" +TEMP_FILE="$(mktemp "${IOC_DIRECTORY}/.${IOC_BASENAME}.tmp.XXXXXX")" + +cleanup() { + if [ -n "${TEMP_FILE:-}" ] && [ -f "$TEMP_FILE" ]; then + rm -f -- "$TEMP_FILE" + fi +} +trap cleanup EXIT HUP INT TERM + +# Back up the current file before any modification. +cp -p -- "$IOC_FILE" "$BACKUP_FILE" + +# Remove every existing copy of the three properties and append one stable, +# complete block. awk preserves all unrelated lines verbatim at the text level, +# including semicolons and similarly named properties. +awk \ + -v destination_key="$DESTINATION_KEY" \ + -v source_key="$SOURCE_KEY" \ + -v templates_key="$TEMPLATES_KEY" \ + -v destination_line="$DESTINATION_LINE" \ + -v source_line="$SOURCE_LINE" \ + -v templates_line="$TEMPLATES_LINE" ' +BEGIN { + destination_prefix = destination_key "=" + source_prefix = source_key "=" + templates_prefix = templates_key "=" +} +{ + # Remove a possible CR from CRLF input so Unix output is consistently LF. + sub(/\r$/, "", $0) + + if (index($0, destination_prefix) == 1) { + next + } + + if (index($0, source_prefix) == 1) { + next + } + + if (index($0, templates_prefix) == 1) { + next + } + + lines[++count] = $0 +} +END { + # Remove trailing blank lines before appending the generated block. + while (count > 0 && lines[count] == "") { + count-- + } + + for (i = 1; i <= count; i++) { + print lines[i] + } + + if (count > 0) { + print "" + } + + print destination_line + print source_line + print templates_line +} +' "$IOC_FILE" > "$TEMP_FILE" + +[ -s "$TEMP_FILE" ] || + die "Generated temporary .ioc file is empty: $TEMP_FILE" + +verify_exact_line_once() { + expected_line="$1" + description="$2" + + # grep -F treats the path as literal text. -x requires the full line. + count="$( + grep -Fxc -- "$expected_line" "$TEMP_FILE" 2>/dev/null || true + )" + + [ "$count" -eq 1 ] || + die "$description verification failed; expected exactly once, found $count." +} + +verify_key_once() { + key="$1" + description="$2" + + count="$( + awk -v prefix="${key}=" ' + index($0, prefix) == 1 { count++ } + END { print count + 0 } + ' "$TEMP_FILE" + )" + + [ "$count" -eq 1 ] || + die "$description key verification failed; expected exactly one property, found $count." +} + +verify_key_once "$DESTINATION_KEY" "Destination path" +verify_key_once "$SOURCE_KEY" "Source path" +verify_key_once "$TEMPLATES_KEY" "Template list" + +verify_exact_line_once "$DESTINATION_LINE" "Destination path" +verify_exact_line_once "$SOURCE_LINE" "Source path" +verify_exact_line_once "$TEMPLATES_LINE" "Template list" + +# Replace the original only after all temporary-file checks pass. +mv -f -- "$TEMP_FILE" "$IOC_FILE" +TEMP_FILE="" + +# Verify the file again after it has been moved into place. +verify_disk_line_once() { + expected_line="$1" + description="$2" + + count="$( + grep -Fxc -- "$expected_line" "$IOC_FILE" 2>/dev/null || true + )" + + [ "$count" -eq 1 ] || + die "Post-write $description verification failed; found $count copies." +} + +verify_disk_line_once "$DESTINATION_LINE" "destination path" +verify_disk_line_once "$SOURCE_LINE" "source path" +verify_disk_line_once "$TEMPLATES_LINE" "template list" + +info "" +info "CubeMX template configuration updated and verified." +info "" +info "$DESTINATION_LINE" +info "$SOURCE_LINE" +info "$TEMPLATES_LINE" +info "" +info "Backup:" +info " $BACKUP_FILE" diff --git a/tools/configure_cubemx_paths_macos.sh b/tools/configure_cubemx_paths_macos.sh new file mode 100644 index 000000000..f7c0bafde --- /dev/null +++ b/tools/configure_cubemx_paths_macos.sh @@ -0,0 +1,245 @@ +#!/usr/bin/env bash +# +# Cross-platform Unix STM32CubeMX custom-template path configurator. +# Compatible with macOS Bash 3.2+ and common Linux Bash versions. +# +# Expected repository structure: +# +# Firmware/ +# ├── tools/ +# │ └── configure_cubemx_paths_macos.sh +# ├── CUBEMXTESTING/ +# │ └── CUBEMXTESTING.ioc +# └── Lib/ +# └── CubeMXTemplates/ +# └── Autogen/ +# └── Inc/ +# └── can_cfg_h.ftl +# +# Usage: +# bash tools/configure_cubemx_paths_macos.sh +# +# Optional overrides: +# IOC_FILE=/path/project.ioc \ +# PROJECT_OUTPUT_DIR=/path/project \ +# TEMPLATE_ROOT=/path/CubeMXTemplates \ +# bash tools/configure_cubemx_paths_macos.sh +# +# Behavior: +# - validates all expected paths; +# - removes stale or duplicate CubeMX template properties; +# - writes exactly one correct copy of each property; +# - creates an .ioc.bak backup; +# - writes through a temporary file; +# - verifies the result from disk; +# - is idempotent. + +set -euo pipefail + +EXPECTED_OS="macos" + +die() { + printf 'ERROR: %s\n' "$*" >&2 + exit 1 +} + +info() { + printf '%s\n' "$*" +} + +detect_os() { + case "$(uname -s)" in + Darwin) printf '%s\n' "macos" ;; + Linux) printf '%s\n' "linux" ;; + *) printf '%s\n' "unsupported" ;; + esac +} + +CURRENT_OS="$(detect_os)" +if [ "$CURRENT_OS" != "$EXPECTED_OS" ]; then + die "This script is intended for $EXPECTED_OS, but detected $CURRENT_OS." +fi + +# Resolve the physical directory containing this script without requiring +# realpath, which is not included with older macOS installations. +SCRIPT_DIR="$( + CDPATH= cd -- "$(dirname -- "$0")" >/dev/null 2>&1 + pwd -P +)" +REPOSITORY_ROOT="$( + CDPATH= cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 + pwd -P +)" + +IOC_FILE="${IOC_FILE:-$REPOSITORY_ROOT/CUBEMXTESTING/CUBEMXTESTING.ioc}" +PROJECT_OUTPUT_DIR="${PROJECT_OUTPUT_DIR:-$REPOSITORY_ROOT/CUBEMXTESTING}" +TEMPLATE_ROOT="${TEMPLATE_ROOT:-$REPOSITORY_ROOT/Lib/CubeMXTemplates}" +TEMPLATE_FILE="$TEMPLATE_ROOT/Autogen/Inc/can_cfg_h.ftl" + +[ -f "$IOC_FILE" ] || + die "CubeMX .ioc file was not found: $IOC_FILE" + +[ -d "$PROJECT_OUTPUT_DIR" ] || + die "CubeMX project output directory was not found: $PROJECT_OUTPUT_DIR" + +[ -d "$TEMPLATE_ROOT" ] || + die "CubeMX template root was not found: $TEMPLATE_ROOT" + +[ -f "$TEMPLATE_FILE" ] || + die "CubeMX FreeMarker template was not found: $TEMPLATE_FILE" + +# Convert directories to physical absolute paths. +PROJECT_OUTPUT_DIR="$( + CDPATH= cd -- "$PROJECT_OUTPUT_DIR" >/dev/null 2>&1 + pwd -P +)" +TEMPLATE_ROOT="$( + CDPATH= cd -- "$TEMPLATE_ROOT" >/dev/null 2>&1 + pwd -P +)" + +DESTINATION_KEY='ProjectManager.TemplateDestinationPath' +SOURCE_KEY='ProjectManager.TemplateSourcePath' +TEMPLATES_KEY='ProjectManager.TemplatesList' + +DESTINATION_LINE="${DESTINATION_KEY}=${PROJECT_OUTPUT_DIR}" +SOURCE_LINE="${SOURCE_KEY}=${TEMPLATE_ROOT}" +TEMPLATES_LINE="${TEMPLATES_KEY}=/Autogen/Inc/can_cfg_h.ftl," + +IOC_DIRECTORY="$(dirname -- "$IOC_FILE")" +IOC_BASENAME="$(basename -- "$IOC_FILE")" +BACKUP_FILE="${IOC_FILE}.bak" +TEMP_FILE="$(mktemp "${IOC_DIRECTORY}/.${IOC_BASENAME}.tmp.XXXXXX")" + +cleanup() { + if [ -n "${TEMP_FILE:-}" ] && [ -f "$TEMP_FILE" ]; then + rm -f -- "$TEMP_FILE" + fi +} +trap cleanup EXIT HUP INT TERM + +# Back up the current file before any modification. +cp -p -- "$IOC_FILE" "$BACKUP_FILE" + +# Remove every existing copy of the three properties and append one stable, +# complete block. awk preserves all unrelated lines verbatim at the text level, +# including semicolons and similarly named properties. +awk \ + -v destination_key="$DESTINATION_KEY" \ + -v source_key="$SOURCE_KEY" \ + -v templates_key="$TEMPLATES_KEY" \ + -v destination_line="$DESTINATION_LINE" \ + -v source_line="$SOURCE_LINE" \ + -v templates_line="$TEMPLATES_LINE" ' +BEGIN { + destination_prefix = destination_key "=" + source_prefix = source_key "=" + templates_prefix = templates_key "=" +} +{ + # Remove a possible CR from CRLF input so Unix output is consistently LF. + sub(/\r$/, "", $0) + + if (index($0, destination_prefix) == 1) { + next + } + + if (index($0, source_prefix) == 1) { + next + } + + if (index($0, templates_prefix) == 1) { + next + } + + lines[++count] = $0 +} +END { + # Remove trailing blank lines before appending the generated block. + while (count > 0 && lines[count] == "") { + count-- + } + + for (i = 1; i <= count; i++) { + print lines[i] + } + + if (count > 0) { + print "" + } + + print destination_line + print source_line + print templates_line +} +' "$IOC_FILE" > "$TEMP_FILE" + +[ -s "$TEMP_FILE" ] || + die "Generated temporary .ioc file is empty: $TEMP_FILE" + +verify_exact_line_once() { + expected_line="$1" + description="$2" + + # grep -F treats the path as literal text. -x requires the full line. + count="$( + grep -Fxc -- "$expected_line" "$TEMP_FILE" 2>/dev/null || true + )" + + [ "$count" -eq 1 ] || + die "$description verification failed; expected exactly once, found $count." +} + +verify_key_once() { + key="$1" + description="$2" + + count="$( + awk -v prefix="${key}=" ' + index($0, prefix) == 1 { count++ } + END { print count + 0 } + ' "$TEMP_FILE" + )" + + [ "$count" -eq 1 ] || + die "$description key verification failed; expected exactly one property, found $count." +} + +verify_key_once "$DESTINATION_KEY" "Destination path" +verify_key_once "$SOURCE_KEY" "Source path" +verify_key_once "$TEMPLATES_KEY" "Template list" + +verify_exact_line_once "$DESTINATION_LINE" "Destination path" +verify_exact_line_once "$SOURCE_LINE" "Source path" +verify_exact_line_once "$TEMPLATES_LINE" "Template list" + +# Replace the original only after all temporary-file checks pass. +mv -f -- "$TEMP_FILE" "$IOC_FILE" +TEMP_FILE="" + +# Verify the file again after it has been moved into place. +verify_disk_line_once() { + expected_line="$1" + description="$2" + + count="$( + grep -Fxc -- "$expected_line" "$IOC_FILE" 2>/dev/null || true + )" + + [ "$count" -eq 1 ] || + die "Post-write $description verification failed; found $count copies." +} + +verify_disk_line_once "$DESTINATION_LINE" "destination path" +verify_disk_line_once "$SOURCE_LINE" "source path" +verify_disk_line_once "$TEMPLATES_LINE" "template list" + +info "" +info "CubeMX template configuration updated and verified." +info "" +info "$DESTINATION_LINE" +info "$SOURCE_LINE" +info "$TEMPLATES_LINE" +info "" +info "Backup:" +info " $BACKUP_FILE" From 86477cfa0652b0fbe22ea16d0ca3886cc5ce505d Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sat, 18 Jul 2026 19:00:10 -0700 Subject: [PATCH 22/38] Advanced critical section usage Signed-off-by: Daniel Hansen --- Lib/GlobalShare/Inc/CriticalSection.h | 17 +++++++++++--- Lib/GlobalShare/Test/criticalsection.c | 5 +++-- Lib/Peripherals/CubeCAN/Src/can_it.c | 2 +- Lib/Peripherals/CubeCAN/Src/can_utils.c | 30 +++++++++++++++++++------ Lib/cmake/HOOTL.cmake | 2 ++ 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h index 7e6fd0d8d..c792731dc 100644 --- a/Lib/GlobalShare/Inc/CriticalSection.h +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -9,7 +9,8 @@ #include extern pthread_mutex_t __mock_global_irq_mutex; -extern uint32_t __mock_primask_state; +extern _Thread_local uint32_t __mock_primask_state; +extern _Thread_local uint32_t __mock_irq_nesting_depth; static inline uint32_t __get_PRIMASK(void) { @@ -19,13 +20,23 @@ static inline uint32_t __get_PRIMASK(void) static inline void __disable_irq(void) { pthread_mutex_lock(&__mock_global_irq_mutex); - __mock_primask_state = 1; + if (__mock_irq_nesting_depth == 0) { + __mock_primask_state = 1; + } + __mock_irq_nesting_depth++; } static inline void __set_PRIMASK(uint32_t state) { + (void)state; + + __mock_irq_nesting_depth--; + + if (__mock_irq_nesting_depth == 0) { + __mock_primask_state = 0; + } + pthread_mutex_unlock(&__mock_global_irq_mutex); - __mock_primask_state = state; } #endif diff --git a/Lib/GlobalShare/Test/criticalsection.c b/Lib/GlobalShare/Test/criticalsection.c index 472d61a44..68ebae386 100644 --- a/Lib/GlobalShare/Test/criticalsection.c +++ b/Lib/GlobalShare/Test/criticalsection.c @@ -10,7 +10,8 @@ #define INCREMENTS_PER_THREAD 100000 pthread_mutex_t __mock_global_irq_mutex; -uint32_t __mock_primask_state = 0; +_Thread_local uint32_t __mock_primask_state = 0; +_Thread_local uint32_t __mock_irq_nesting_depth = 0; __attribute__((constructor)) static void init_recursive_mock_mutex(void) { @@ -21,7 +22,7 @@ __attribute__((constructor)) static void init_recursive_mock_mutex(void) pthread_mutexattr_destroy(&attr); } -long long global_counter = 0; +volatile long long global_counter = 0; void *thread_worker_good(void *arg) { diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index b9ffa71ad..f44df2258 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -52,7 +52,7 @@ void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan) FDCAN_RxHeaderTypeDef rx_header = {0}; uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - LOGOMATIC("CubeMXCan_OnRxFifo0: no handle or callback registered for %s\n", can_get_instance_name(hfdcan->Instance)); + LOGOMATIC("CubeMXCan_OnRxFifo0: no handle or callback registered for %s\n", CAN_GetInstanceName(hfdcan->Instance)); return; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 09f2932e3..c0f247cef 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -85,20 +85,36 @@ uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) { - if (handle == NULL || handle->hfdcan == NULL || handle->tx_count == 0U) { + if (handle == NULL || handle->hfdcan == NULL) { return HAL_ERROR; } - if (handle->tx_count == 0U) { - return HAL_OK; + GRCAN_TxMessage message_copy; + bool message_found = false; + + CRITICAL_SECTION + { + if (handle->tx_count > 0U) { + message_copy = handle->tx_queue[handle->tx_head]; + message_found = true; + } + } + + if (!message_found) { + return HAL_ERROR; } - const GRCAN_TxMessage *message = &handle->tx_queue[handle->tx_head]; - if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message->tx_header, message->data) != HAL_OK) { + if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { return HAL_ERROR; } - handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; - handle->tx_count--; + CRITICAL_SECTION + { + if (handle->tx_count > 0U) { + handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; + handle->tx_count--; + } + } + return HAL_OK; } diff --git a/Lib/cmake/HOOTL.cmake b/Lib/cmake/HOOTL.cmake index e2dfaea15..5689d4ce9 100644 --- a/Lib/cmake/HOOTL.cmake +++ b/Lib/cmake/HOOTL.cmake @@ -59,11 +59,13 @@ if(ADDRESS_SANITIZER) -fsanitize=address -fsanitize=undefined -fsanitize=leak + # -fsanitize=thread ) add_link_options( -fsanitize=address -fsanitize=undefined -fsanitize=leak + # -fsanitize=thread ) endif() endif() From efdd02c198402bc08bdebf1fb47833d703340ed7 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Sun, 19 Jul 2026 23:15:17 -0700 Subject: [PATCH 23/38] In progress --- Check point save while working with atomics Signed-off-by: Daniel Hansen --- .../Application/Inc/CubeCAN_Config.h | 2 +- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 13 ++-- Lib/Peripherals/CubeCAN/Src/can_init.c | 43 ++++++----- Lib/Peripherals/CubeCAN/Src/can_it.c | 3 + Lib/Peripherals/CubeCAN/Src/can_utils.c | 73 ++++++++++++++----- 5 files changed, 93 insertions(+), 41 deletions(-) diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index f3c02252e..3df036604 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -9,7 +9,7 @@ #define USECAN2 #define CUBEMX_CAN_TIMER_INSTANCE TIM5 -#define CUBEMX_CAN_TX_QUEUE_SIZE 20U +#define CUBEMX_CAN_TX_QUEUE_SIZE 32U #define CAN_TIMER_SEND_PERIOD_US 500U #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 7477ffb06..7816f8086 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -1,15 +1,18 @@ #include +#include #include #include #include "CubeMXCan.h" -#include "Stringification.h" #include "Logomatic.h" +#include "Stringification.h" #include "main.h" #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H +#define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) + /** * @brief CubeMX CAN handle structure * @@ -25,10 +28,10 @@ typedef struct CubeMXCan_Handle { CubeCAN_Config config; /// @brief Transmission queue for the CubeMX CAN handle, containing the messages to be transmitted. GRCAN_TxMessage tx_queue[CUBEMX_CAN_TX_QUEUE_SIZE]; - /// @brief Index of the head of the transmission queue, indicating the next message to be transmitted. - uint32_t tx_head; - /// @brief Count of messages in the transmission queue, indicating the number of messages waiting to be transmitted. - uint32_t tx_count; + /// @brief Atomic head index for the transmission queue, indicating the next message to be transmitted. + _Atomic uint32_t tx_head; + /// @brief Atomic tail index for the transmission queue, indicating the next available slot for a new message. + _Atomic uint32_t tx_tail; /// @brief Flag indicating whether the CubeMX CAN handle has been started. bool started; } CubeMXCan_Handle; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 78904cfe8..35fc89899 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -17,7 +17,7 @@ static bool s_timer_started = false; static CubeMXCan_RegistryEntry *CubeMXCan_FindRegistryEntry(FDCAN_GlobalTypeDef *instance) { - for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { if (s_registry[i].instance == instance) { return &s_registry[i]; } @@ -33,7 +33,7 @@ static CubeMXCan_RegistryEntry *CubeMXCan_AllocRegistryEntry(FDCAN_GlobalTypeDef return entry; } - for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { if (s_registry[i].instance == NULL) { s_registry[i].instance = instance; return &s_registry[i]; @@ -83,12 +83,20 @@ void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan) void CubeMXCan_Tick(void) { - for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { CubeMXCan_Handle *handle = s_registry[i].handle; - if (handle == NULL || !handle->started) { + if (handle == NULL || handle->hfdcan == NULL || !handle->started) { continue; } + if (CubeMXCan_Private_IsDisabled(handle)) { + LOGOMATIC("CAN_send: currently in restricted operation mode\n"); + if (CubeMXCan_Private_RecoverPeripheral(handle->hfdcan) != HAL_OK) { + LOGOMATIC("CAN_send %d: failed to recover peripheral\n", (int)i); + continue; + } + } + (void)CubeMXCan_Private_SendQueuedMessage(handle); } } @@ -106,7 +114,7 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf { handle = CubeMXCan_Private_GetHandle(hfdcan); if (handle == NULL) { - for (uint32_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { if (s_handles[i].hfdcan == NULL) { handle = &s_handles[i]; memset(handle, 0, sizeof(*handle)); @@ -118,8 +126,8 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf if (handle != NULL) { handle->config = *config; - handle->tx_head = 0U; - handle->tx_count = 0U; + atomic_init (&handle->tx_head, 0U); + atomic_init (&handle->tx_tail, 0U); handle->started = false; if (CubeMXCan_Private_RegisterHandle(hfdcan, handle) == HAL_OK) { @@ -196,7 +204,7 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) } (void)CubeMXCan_Stop(handle); - + CRITICAL_SECTION { CubeMXCan_Private_UnregisterHandle(handle->hfdcan); @@ -221,17 +229,18 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess return HAL_ERROR; } - CRITICAL_SECTION - { - uint32_t insert_index = (handle->tx_head + handle->tx_count) % CUBEMX_CAN_TX_QUEUE_SIZE; - handle->tx_queue[insert_index] = *message; + uint32_t current_tail = atomic_load(&handle->tx_tail); + uint32_t current_head = atomic_load(&handle->tx_head); - if (handle->tx_count < CUBEMX_CAN_TX_QUEUE_SIZE) { - handle->tx_count++; - } else { - handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; - } + if ((current_tail - current_head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { + LOGOMATIC("CubeMXCan_QueueTx: queue is full\n"); + return HAL_BUSY; // FIXME QUEUE IS FULL WHAT TO DO } + uint32_t insert_index = current_tail & TX_QUEUE_MASK; + handle->tx_queue[insert_index] = *message; + + atomic_store_explicit(&handle->tx_tail, current_tail + 1U, memory_order_release); + return HAL_OK; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c index f44df2258..cfd576b67 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ b/Lib/Peripherals/CubeCAN/Src/can_it.c @@ -6,6 +6,9 @@ #include "CubeMXCanExt.h" #include "Logomatic.h" #include "Private/PrivateCubeMXCAN.h" +#include + +static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of 2"); void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index c0f247cef..abf20f17d 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -83,38 +83,75 @@ uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) return s_dlc_to_bytes[dlc]; } -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) +bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle) { if (handle == NULL || handle->hfdcan == NULL) { - return HAL_ERROR; + return true; + } + + HAL_FDCAN_StateTypeDef state = HAL_FDCAN_GetState(handle->hfdcan); + if (state == HAL_FDCAN_STATE_ERROR || state == HAL_FDCAN_STATE_READY) { + return true; } - GRCAN_TxMessage message_copy; - bool message_found = false; + uint32_t error_status = HAL_FDCAN_GetErrorStatus(handle->hfdcan); + if ((error_status & FDCAN_PSR_BO) != 0U) { // BO = Bus-Off Flag + return true; + } + + return false; +} + +HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle) +{ + FDCAN_ProtocolStatusTypeDef protocol_status = {0}; + + if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff) { + LOGOMATIC("CAN_send: bus off detected, attempting recovery\n"); - CRITICAL_SECTION - { - if (handle->tx_count > 0U) { - message_copy = handle->tx_queue[handle->tx_head]; - message_found = true; + if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { + LOGOMATIC("CAN_send: failed to stop FDCAN peripheral during bus off recovery\n"); + return HAL_ERROR; + } + + HAL_FDCAN_AbortTxRequest(handle->hfdcan, FDCAN_TX_BUFFER0 | FDCAN_TX_BUFFER1 | FDCAN_TX_BUFFER2); + + if (HAL_FDCAN_Start(handle->hfdcan) != HAL_OK) { + LOGOMATIC("CAN_send: failed to restart FDCAN peripheral during bus off recovery\n"); + return HAL_ERROR; } } - if (!message_found) { - return HAL_ERROR; + if (HAL_FDCAN_IsRestrictedOperationMode(handle->hfdcan)) { + LOGOMATIC("CAN_send: currently in restricted operation mode\n"); + HAL_FDCAN_ExitRestrictedOperationMode(handle->hfdcan); } - if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { + return HAL_OK; +} + +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL) { + // Invalid parameter return HAL_ERROR; } - CRITICAL_SECTION - { - if (handle->tx_count > 0U) { - handle->tx_head = (handle->tx_head + 1U) % CUBEMX_CAN_TX_QUEUE_SIZE; - handle->tx_count--; - } + uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); + uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_acquire); + + if (current_head == current_tail) { + // Queue empty + return HAL_OK; + } + + uint32_t current_index = current_head & TX_QUEUE_MASK; + GRCAN_TxMessage message_copy = handle->tx_queue[current_index]; + + if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { + return HAL_ERROR; } + atomic_store_explicit(&handle->tx_head, (current_head + 1U), memory_order_release); return HAL_OK; } From 1c5e7d7d44bb5e804df32cbfa3829bd1cba80333 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Tue, 21 Jul 2026 02:54:53 -0700 Subject: [PATCH 24/38] Getting pretty close to a compiling build, needs timer integration work Signed-off-by: Daniel Hansen --- .../Application/Inc/CubeCAN_Config.h | 1 + CUBEMXTESTING/CMakeLists.txt | 2 +- CUBEMXTESTING/Core/Inc/main.h | 48 ++--- CUBEMXTESTING/Core/Src/main.c | 9 +- Lib/GlobalShare/Inc/CriticalSection.h | 4 +- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 9 + Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 1 + .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 65 ++++++- Lib/Peripherals/CubeCAN/Src/can_assert.c | 28 +++ Lib/Peripherals/CubeCAN/Src/can_global.c | 12 ++ Lib/Peripherals/CubeCAN/Src/can_init.c | 184 +++++------------- Lib/Peripherals/CubeCAN/Src/can_it.c | 72 ------- Lib/Peripherals/CubeCAN/Src/can_rx.c | 44 +++++ Lib/Peripherals/CubeCAN/Src/can_tx.c | 80 ++++++++ Lib/Peripherals/CubeCAN/Src/can_utils.c | 113 ++++------- Lib/Peripherals/CubeCAN/cubemx_can.cmake | 7 +- Lib/Utils/Logomatic/Inc/Logomatic.h | 16 +- 17 files changed, 363 insertions(+), 332 deletions(-) create mode 100644 Lib/Peripherals/CubeCAN/Src/can_assert.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_global.c delete mode 100644 Lib/Peripherals/CubeCAN/Src/can_it.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_rx.c create mode 100644 Lib/Peripherals/CubeCAN/Src/can_tx.c diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index 3df036604..7ff7a2a33 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -11,5 +11,6 @@ #define CUBEMX_CAN_TIMER_INSTANCE TIM5 #define CUBEMX_CAN_TX_QUEUE_SIZE 32U #define CAN_TIMER_SEND_PERIOD_US 500U +#define CAN_TIMER_HANDLE TIM5 #endif diff --git a/CUBEMXTESTING/CMakeLists.txt b/CUBEMXTESTING/CMakeLists.txt index bfd25f877..c8fcc8050 100644 --- a/CUBEMXTESTING/CMakeLists.txt +++ b/CUBEMXTESTING/CMakeLists.txt @@ -33,7 +33,7 @@ target_sources( Core/Src/stm32g4xx_it.c ) -target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB CUBEMX_CAN_LIB) +target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB CUBEMX_CAN_LIB LOGOMATIC_LIB) target_include_directories( ${PROJECT_NAME}_USER_CODE diff --git a/CUBEMXTESTING/Core/Inc/main.h b/CUBEMXTESTING/Core/Inc/main.h index c050c5e89..2ca19b1c6 100644 --- a/CUBEMXTESTING/Core/Inc/main.h +++ b/CUBEMXTESTING/Core/Inc/main.h @@ -1,21 +1,21 @@ /* USER CODE BEGIN Header */ /** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ @@ -28,22 +28,22 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include "stm32g4xx_hal.h" - -#include "stm32g4xx_ll_rcc.h" #include "stm32g4xx_ll_bus.h" -#include "stm32g4xx_ll_crs.h" -#include "stm32g4xx_ll_system.h" -#include "stm32g4xx_ll_exti.h" #include "stm32g4xx_ll_cortex.h" -#include "stm32g4xx_ll_utils.h" -#include "stm32g4xx_ll_pwr.h" +#include "stm32g4xx_ll_crs.h" #include "stm32g4xx_ll_dma.h" +#include "stm32g4xx_ll_exti.h" #include "stm32g4xx_ll_gpio.h" +#include "stm32g4xx_ll_pwr.h" +#include "stm32g4xx_ll_rcc.h" +#include "stm32g4xx_ll_system.h" +#include "stm32g4xx_ll_utils.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include "stm32g4xx_ll_usart.h" #include "stm32g4xx_ll_lpuart.h" +#include "stm32g4xx_ll_rcc.h" +#include "stm32g4xx_ll_usart.h" /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index e189561ec..7dc29b231 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -28,9 +28,9 @@ #include "loop.h" #include "vcp.h" -#include "can.h" -#include "can_cfg.h" -#include "gr_can_init.h" +// #include "can.h" +// #include "can_cfg.h" +// #include "gr_can_init.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -233,8 +233,7 @@ void Error_Handler(void) void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + printf("Assert failed! File %s on line %d\n", file, line); /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h index c792731dc..d83cdc242 100644 --- a/Lib/GlobalShare/Inc/CriticalSection.h +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -1,6 +1,7 @@ #include #include "Stringification.h" +#include "main.h" #ifndef CRITICAL_SECTION_H #define CRITICAL_SECTION_H @@ -64,7 +65,8 @@ static inline void _magic_auto_critical_exit(uint32_t *state_var) * disable interrupts for a short period of time. */ #define CRITICAL_SECTION \ - for (__attribute__((cleanup(_magic_auto_critical_exit))) uint32_t CONCAT(_magic_auto_critical_state_, __LINE__) = __get_PRIMASK(), CONCAT(_magic_auto_critical_run_, __LINE__) = (__disable_irq(), 1); \ + for (__attribute__((cleanup(_magic_auto_critical_exit))) uint32_t CONCAT(_magic_auto_critical_state_, __LINE__) = __get_PRIMASK(), \ + CONCAT(_magic_auto_critical_run_, __LINE__) = (__disable_irq(), 1); \ CONCAT(_magic_auto_critical_run_, __LINE__); CONCAT(_magic_auto_critical_run_, __LINE__) = 0) #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 8a258cc72..89db887a7 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -1,3 +1,4 @@ +#include #include #include @@ -101,4 +102,12 @@ HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_Filt */ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message); +/** + * @brief Converts a Data Length Code (DLC) to the corresponding number of data bytes. + * @param dlc The Data Length Code to be converted. + * @return The number of data bytes corresponding to the given DLC. + * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. + */ +bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle); + #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h index 64eff376a..3cc2ad110 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -1,3 +1,4 @@ +#include #include #include "GRCAN_MSG_ID.h" diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 7816f8086..127a8c910 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -1,8 +1,8 @@ -#include #include #include #include +#include "CubeCAN_Config.h" #include "CubeMXCan.h" #include "Logomatic.h" #include "Stringification.h" @@ -11,17 +11,37 @@ #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H +/** + * @brief Macro to convert a CubeMX CAN instance pointer to its corresponding index. + * + * Works on all supported boards, but new boards should be verified against this operation + * + * @param inst Pointer to the CubeMX CAN instance (FDCAN1, FDCAN2, or FDCAN3). + * @return The index corresponding to the given CubeMX CAN instance (0 for FDCAN1, 1 for FDCAN2, and 2 for FDCAN3). + * @warning This macro assumes that the CubeMX CAN instances are contiguous in memory and that FDCAN1 is the first instance. It may not work correctly if the instances are not contiguous or if FDCAN1 + * is not the first instance. + */ +#define CUBEMX_CAN_INSTANCE_TO_INDEX(inst) ((uint32_t)((uintptr_t)(inst) - FDCAN1_BASE) >> 10) + +/** + * @brief Mask for the transmission queue index, used to wrap around the queue when it reaches its maximum size. + * + * Application code should not use this macro directly. It is intended for internal use only + * + * @warning The transmission queue size must be a power of two for this mask to work correctly + * @warning The transmission queue size must be defined as CUBEMX_CAN_TX_QUEUE_SIZE in the CubeMX CAN configuration header file + */ #define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) /** * @brief CubeMX CAN handle structure * - * This structure is used to represent a CubeMX CAN handle, which consists of a pointer to the FDCAN handle, a configuration structure, a transmission queue, and other relevant parameters.\ + * This structure is used to represent a CubeMX CAN handle, which consists of a pointer to the FDCAN handle, a configuration structure, a transmission queue, and other relevant parameters. * * @warning Use the provided API functions to interact with the CubeMX CAN handle. * @warning The structure is intended for internal use only and should not be accessed directly by user code. */ -typedef struct CubeMXCan_Handle { +struct CubeMXCan_Handle { /// @brief Pointer to the FDCAN handle associated with this CubeMX CAN handle. FDCAN_HandleTypeDef *hfdcan; /// @brief Configuration structure for the CubeMX CAN handle, containing the receive callback and user context. @@ -34,7 +54,7 @@ typedef struct CubeMXCan_Handle { _Atomic uint32_t tx_tail; /// @brief Flag indicating whether the CubeMX CAN handle has been started. bool started; -} CubeMXCan_Handle; +}; /// @brief Maximum number of CubeMX CAN instances supported by the library. #define CUBEMX_CAN_MAX_INSTANCES 3U @@ -91,4 +111,41 @@ void CubeMXCan_Tick(void); */ void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan); +/** + * @brief Structure representing a registry entry for the CubeMX CAN library, used to associate a CubeMX CAN handle with its corresponding FDCAN handle. + */ +struct CubeMXCan_RegistryEntry { + /// @brief Pointer to the FDCAN instance associated with this registry entry. + FDCAN_GlobalTypeDef *instance; + /// @brief Pointer to the CubeMX CAN handle associated with this registry entry. + CubeMXCan_Handle *handle; +}; + +/** + * @brief Registry entry structure for the CubeMX CAN library, used to associate a CubeMX CAN handle with its corresponding FDCAN handle. + * @note The number of entries in the registry is defined by CUBEMX_CAN_MAX_INSTANCES. + */ +extern struct CubeMXCan_RegistryEntry registry[CUBEMX_CAN_MAX_INSTANCES]; + +/** + * @brief Array of CubeMX CAN handles, one for each supported instance. + * @note The number of instances is defined by CUBEMX_CAN_MAX_INSTANCES. + */ +extern struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; + +/** + * @brief Flag indicating whether the CubeMX CAN Tx timer has been started. + */ +extern bool s_timer_started; + +/** + * @brief Attempts to recover the FDCAN peripheral associated with the given CubeMX CAN handle. + * + * Handles recovery from bus off or restricted operation mode by reinitializing the FDCAN peripheral and restoring its configuration. + * + * @param handle Pointer to the CubeMX CAN handle associated with the FDCAN peripheral to be recovered. + * @return HAL_StatusTypeDef indicating the success or failure of the recovery operation. + */ +HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle); + #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c new file mode 100644 index 000000000..93df889de --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -0,0 +1,28 @@ +#include +#include + +#include "CriticalSection.h" +#include "CubeCAN_Config.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Private/PrivateCubeMXCAN.h" +#include "main.h" + +#pragma region Platform Assertions + +static_assert(sizeof(((CubeMXCan_Handle *)0)->tx_head) == sizeof(uint32_t), "tx_head must be 32 bits"); + +static_assert(sizeof(GRCAN_TxMessage) == (sizeof(FDCAN_TxHeaderTypeDef) + 64), "GRCAN_TxMessage size is incorrect"); + +static_assert(_Alignof(GRCAN_TxMessage) >= 4, "GRCAN_TxMessage must have at least 4-byte alignment"); + +static_assert(ATOMIC_INT_LOCK_FREE == 2, "ATOMIC_INT_LOCK_FREE must be enabled for atomic operations on tx_head and tx_tail"); + +#pragma endregion +#pragma region Configuration Validations + +static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); + +static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "CUBEMX_CAN_MAX_INSTANCES must be configured between 1 and 3 inclusive"); + +#pragma endregion diff --git a/Lib/Peripherals/CubeCAN/Src/can_global.c b/Lib/Peripherals/CubeCAN/Src/can_global.c new file mode 100644 index 000000000..aa7613e89 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_global.c @@ -0,0 +1,12 @@ +#include +#include +#include + +#include "CriticalSection.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Private/PrivateCubeMXCAN.h" + +struct CubeMXCan_RegistryEntry registry[CUBEMX_CAN_MAX_INSTANCES] = {0}; +struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; +bool timer_started = false; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 35fc89899..627d37eea 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -1,97 +1,88 @@ +#include #include +#include #include +#include "CriticalSection.h" #include "CubeMXCan.h" #include "CubeMXCanExt.h" #include "Logomatic.h" #include "Private/PrivateCubeMXCAN.h" +#include "main.h" -typedef struct { - FDCAN_GlobalTypeDef *instance; - CubeMXCan_Handle *handle; -} CubeMXCan_RegistryEntry; - -static CubeMXCan_RegistryEntry s_registry[CUBEMX_CAN_MAX_INSTANCES] = {0}; -static CubeMXCan_Handle s_handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; -static bool s_timer_started = false; - -static CubeMXCan_RegistryEntry *CubeMXCan_FindRegistryEntry(FDCAN_GlobalTypeDef *instance) +CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config) { - for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (s_registry[i].instance == instance) { - return &s_registry[i]; - } + if (hfdcan == NULL || config == NULL) { + LOGOMATIC("CubeMXCan_Init: invalid null parameters\n"); + return NULL; } - return NULL; -} - -static CubeMXCan_RegistryEntry *CubeMXCan_AllocRegistryEntry(FDCAN_GlobalTypeDef *instance) -{ - CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(instance); - if (entry != NULL) { - return entry; - } + CubeMXCan_Handle *handle = NULL; + CRITICAL_SECTION + { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (handles[i].hfdcan == hfdcan || handles[i].hfdcan == NULL) { + handle = &handles[i]; + break; + } + } - for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (s_registry[i].instance == NULL) { - s_registry[i].instance = instance; - return &s_registry[i]; + if (handle != NULL) { + memset(handle, 0, sizeof(*handle)); + handle->hfdcan = hfdcan; + handle->config = *config; + atomic_init(&handle->tx_head, 0U); + atomic_init(&handle->tx_tail, 0U); + handle->started = false; } } - return NULL; -} + if (handle == NULL) { + LOGOMATIC("CubeMXCan_Init: no free handle slots\n"); + return NULL; + } -CubeMXCan_Handle *CubeMXCan_Private_GetHandle(FDCAN_HandleTypeDef *hfdcan) -{ - if (hfdcan == NULL) { + uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; + if (HAL_FDCAN_ActivateNotification(hfdcan, rx_events, 0U) != HAL_OK) { + LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); + memset(handle, 0, sizeof(*handle)); return NULL; } - CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(hfdcan->Instance); - return (entry != NULL) ? entry->handle : NULL; + return handle; } -HAL_StatusTypeDef CubeMXCan_Private_RegisterHandle(FDCAN_HandleTypeDef *hfdcan, CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) { - if (hfdcan == NULL || handle == NULL) { - return HAL_ERROR; - } - - CubeMXCan_RegistryEntry *entry = CubeMXCan_AllocRegistryEntry(hfdcan->Instance); - if (entry == NULL) { + if (handle == NULL || handle->hfdcan == NULL) { return HAL_ERROR; } - entry->handle = handle; - return HAL_OK; -} + (void)CubeMXCan_Stop(handle); -void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan) -{ - if (hfdcan == NULL) { - return; + CRITICAL_SECTION + { + memset(handle, 0, sizeof(*handle)); } - CubeMXCan_RegistryEntry *entry = CubeMXCan_FindRegistryEntry(hfdcan->Instance); - if (entry != NULL) { - entry->instance = NULL; - entry->handle = NULL; - } + return HAL_OK; } void CubeMXCan_Tick(void) { for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - CubeMXCan_Handle *handle = s_registry[i].handle; - if (handle == NULL || handle->hfdcan == NULL || !handle->started) { - continue; + CubeMXCan_Handle *handle = registry[i].handle; + + CRITICAL_SECTION + { + if (handle == NULL || handle->hfdcan == NULL || !handle->started) { + continue; + } } if (CubeMXCan_Private_IsDisabled(handle)) { LOGOMATIC("CAN_send: currently in restricted operation mode\n"); - if (CubeMXCan_Private_RecoverPeripheral(handle->hfdcan) != HAL_OK) { + if (CubeMXCan_Private_RecoverPeripheral(handle) != HAL_OK) { LOGOMATIC("CAN_send %d: failed to recover peripheral\n", (int)i); continue; } @@ -101,66 +92,6 @@ void CubeMXCan_Tick(void) } } -CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config) -{ - if (hfdcan == NULL || config == NULL) { - return NULL; - } - - CubeMXCan_Handle *handle = NULL; - bool register_ok = false; - - CRITICAL_SECTION - { - handle = CubeMXCan_Private_GetHandle(hfdcan); - if (handle == NULL) { - for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (s_handles[i].hfdcan == NULL) { - handle = &s_handles[i]; - memset(handle, 0, sizeof(*handle)); - handle->hfdcan = hfdcan; - break; - } - } - } - - if (handle != NULL) { - handle->config = *config; - atomic_init (&handle->tx_head, 0U); - atomic_init (&handle->tx_tail, 0U); - handle->started = false; - - if (CubeMXCan_Private_RegisterHandle(hfdcan, handle) == HAL_OK) { - register_ok = true; - } else { - memset(handle, 0, sizeof(*handle)); - handle = NULL; - } - } - } - - if (handle == NULL) { - LOGOMATIC("CubeMXCan_Init: no free handle slots\n"); - return NULL; - } - - if (!register_ok) { - LOGOMATIC("CubeMXCan_Init: failed to register handle\n"); - return NULL; - } - - uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; - if (HAL_FDCAN_ActivateNotification(hfdcan, rx_events, 0U) != HAL_OK) { - LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); - return NULL; - } - - if (!s_timer_started) { - s_timer_started = true; - } - return handle; -} - HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle) { if (handle == NULL || handle->hfdcan == NULL) { @@ -197,23 +128,6 @@ HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle) return HAL_OK; } -HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) -{ - if (handle == NULL || handle->hfdcan == NULL) { - return HAL_ERROR; - } - - (void)CubeMXCan_Stop(handle); - - CRITICAL_SECTION - { - CubeMXCan_Private_UnregisterHandle(handle->hfdcan); - memset(handle, 0, sizeof(*handle)); - } - - return HAL_OK; -} - HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) { if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { @@ -234,7 +148,7 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess if ((current_tail - current_head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { LOGOMATIC("CubeMXCan_QueueTx: queue is full\n"); - return HAL_BUSY; // FIXME QUEUE IS FULL WHAT TO DO + return HAL_TIMEOUT; } uint32_t insert_index = current_tail & TX_QUEUE_MASK; diff --git a/Lib/Peripherals/CubeCAN/Src/can_it.c b/Lib/Peripherals/CubeCAN/Src/can_it.c deleted file mode 100644 index cfd576b67..000000000 --- a/Lib/Peripherals/CubeCAN/Src/can_it.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include - -#include "CubeCAN_Config.h" -#include "CubeMXCan.h" -#include "CubeMXCanExt.h" -#include "Logomatic.h" -#include "Private/PrivateCubeMXCAN.h" -#include - -static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of 2"); - -void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) -{ - if (htim != NULL && htim->Instance == CUBEMX_CAN_TIMER_INSTANCE) { - CubeMXCan_Tick(); - } -} - -void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) -{ - (void)RxFifo0ITs; - CubeMXCan_OnRxFifo0(hfdcan); -} - -void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes) -{ - (void)hfdcan; - (void)BufferIndexes; -} - -void CubeMXCan_Private_DispatchRx(FDCAN_HandleTypeDef *hfdcan) -{ - CubeMXCan_OnRxFifo0(hfdcan); -} - -void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan) -{ - if (hfdcan == NULL) { - return; - } - - CubeCAN_RxCallback rx_callback_stack = NULL; - void *user_ctx_stack = NULL; - - CRITICAL_SECTION { - CubeMXCan_Handle *handle = CubeMXCan_Private_GetHandle(hfdcan); - if (handle != NULL && handle->config.rx_callback != NULL) { - rx_callback_stack = handle->config.rx_callback; - user_ctx_stack = handle->config.user_ctx; - } - } - - if (rx_callback_stack == NULL) { - FDCAN_RxHeaderTypeDef rx_header = {0}; - uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; - (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - LOGOMATIC("CubeMXCan_OnRxFifo0: no handle or callback registered for %s\n", CAN_GetInstanceName(hfdcan->Instance)); - return; - } - - FDCAN_RxHeaderTypeDef rx_header = {0}; - uint8_t rx_data[FDCAN_MAX_DATA_BYTES] = {0}; - if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) != HAL_OK) { - LOGOMATIC("CubeMXCan_OnRxFifo0: failed to get RX message\n"); - return; - } - - CAN_Identifier identifier = Deconstruct_CAN_Identifier(rx_header.Identifier); - uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); - rx_callback_stack(user_ctx_stack, &identifier, rx_data, size); -} diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c new file mode 100644 index 000000000..e21f05d9d --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -0,0 +1,44 @@ +#include +#include + +#include "CriticalSection.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Logomatic.h" +#include "Private/PrivateCubeMXCAN.h" +#include "Unused.h" +#include "main.h" + +void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) +{ + UNUSED(RxFifo0ITs); + + if (hfdcan == NULL) { + return; + } + + CubeMXCan_Handle *handle = NULL; + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (s_handles[i].hfdcan == hfdcan) { + handle = &s_handles[i]; + break; + } + } + + if (handle == NULL || handle->config.rx_callback == NULL) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[FDCAN_MAX_DATA_BYTES]; + (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); + LOGOMATIC("Rx Callback missing for instance\n"); + return; + } + + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[FDCAN_MAX_DATA_BYTES]; + + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { + CAN_Identifier id = Deconstruct_CAN_Identifier(rx_header.Identifier); + uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); + handle->config.rx_callback(handle->config.user_ctx, &id, rx_data, size); + } +} diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c new file mode 100644 index 000000000..3bb804ea8 --- /dev/null +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -0,0 +1,80 @@ +#include +#include + +#include "CriticalSection.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" +#include "Logomatic.h" +#include "Private/PrivateCubeMXCAN.h" +#include "main.h" + +void CubeMXCan_Tick(void) +{ + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + CubeMXCan_Handle *handle = &handles[i]; + + if (handle->hfdcan == NULL || !handle->started) { + continue; + } + + if (CubeMXCan_Private_IsDisabled(handle)) { + LOGOMATIC("CAN_send: currently in restricted operation mode\n"); + if (CubeMXCan_Private_RecoverPeripheral(handle) != HAL_OK) { + LOGOMATIC("CAN_send %d: failed to recover peripheral\n", (int)i); + continue; + } + } + + (void)CubeMXCan_Private_SendQueuedMessage(handle); + } +} + +HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message) +{ + if (handle == NULL || message == NULL) { + return HAL_ERROR; + } + + uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_relaxed); + uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_acquire); + + if ((current_tail - current_head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { + LOGOMATIC("CubeMXCan_QueueTx: queue is full\n"); + return HAL_TIMEOUT; + } + + handle->tx_queue[current_tail & TX_QUEUE_MASK] = *message; + atomic_store_explicit(&handle->tx_tail, current_tail + 1U, memory_order_release); + return HAL_OK; +} + +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim != NULL && htim->Instance == CUBEMX_CAN_TIMER_INSTANCE) { + CubeMXCan_Tick(); + } +} + +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) +{ + if (handle == NULL || handle->hfdcan == NULL) { + LOGOMATIC("CubeMXCan_Private_SendQueuedMessage: invalid null parameter\n"); + return HAL_ERROR; + } + + uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); + uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_acquire); + + if (current_head == current_tail) { + return HAL_OK; + } + + GRCAN_TxMessage message_copy = handle->tx_queue[current_head & TX_QUEUE_MASK]; + + if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { + return HAL_ERROR; + } + + atomic_store_explicit(&handle->tx_head, (current_head + 1U), memory_order_release); + return HAL_OK; +} diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index abf20f17d..c60010bdd 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -1,5 +1,8 @@ +#include +#include #include +#include "CriticalSection.h" #include "CubeMXCan.h" #include "CubeMXCanExt.h" #include "GRCAN_MSG_ID.h" @@ -7,55 +10,28 @@ #include "Logomatic.h" #include "Private/PrivateCubeMXCAN.h" -static const uint8_t s_dlc_to_bytes[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U}; - -const char *CAN_GetInstanceName(FDCAN_GlobalTypeDef *instance) -{ - if (instance == NULL) { - return "NULL"; - } -#ifdef USECAN1 - if (instance == FDCAN1) { - return "FDCAN1"; - } -#endif -#ifdef USECAN2 - if (instance == FDCAN2) { - return "FDCAN2"; - } -#endif -#ifdef USECAN3 - if (instance == FDCAN3) { - return "FDCAN3"; - } -#endif - LOGOMATIC("Get CAN instance name: unknown instance\n"); - return "UNKNOWN"; -} - uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) { if (identifier == NULL) { return 0U; } - uint32_t message_id = 0U; - message_id |= ((uint32_t)(identifier->tx_node_id & 0xFFU) << 20U); - message_id |= ((uint32_t)(identifier->msg_id & 0xFFFU) << 8U); - message_id |= (uint32_t)(identifier->rx_node_id & 0xFFU); - - return message_id; + return // Transmitting node + ((uint32_t)(identifier->tx_node_id & 0xFFU) << 20U) + // Message ID + | ((uint32_t)(identifier->msg_id & 0xFFFU) << 8U) + // Receiving node + | (uint32_t)(identifier->rx_node_id & 0xFFU); } CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id) { - CAN_Identifier identifier = {0}; - - identifier.tx_node_id = (GRCAN_NODE_ID)((message_id >> 20U) & 0xFFU); - identifier.msg_id = (GRCAN_MSG_ID)((message_id >> 8U) & 0xFFFU); - identifier.rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFFU); - - return identifier; + return (CAN_Identifier){// Transmitting node + .tx_node_id = (GRCAN_NODE_ID)((message_id >> 20U) & 0xFFU), + // Message ID + .msg_id = (GRCAN_MSG_ID)((message_id >> 8U) & 0xFFFU), + // Receiving node + .rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFFU)}; } HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter) @@ -74,13 +50,23 @@ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifie return HAL_OK; } -uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) +HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) { - if (dlc > 15U) { - return 64U; + if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { + LOGOMATIC("CubeMXCan_AddFilter: Invalid null parameter\n"); + return HAL_ERROR; } - return s_dlc_to_bytes[dlc]; + return HAL_FDCAN_ConfigFilter(handle->hfdcan, (FDCAN_FilterTypeDef *)filter); +} + +uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) +{ + static const uint8_t dlc_to_bytes[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U}; + + static_assert((sizeof(dlc_to_bytes) / sizeof(dlc_to_bytes[0])) == 16, "dlc_to_bytes array must have 16 elements"); + + return (dlc > 15U) ? 64U : dlc_to_bytes[dlc]; } bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle) @@ -90,16 +76,13 @@ bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle) } HAL_FDCAN_StateTypeDef state = HAL_FDCAN_GetState(handle->hfdcan); - if (state == HAL_FDCAN_STATE_ERROR || state == HAL_FDCAN_STATE_READY) { - return true; - } - - uint32_t error_status = HAL_FDCAN_GetErrorStatus(handle->hfdcan); - if ((error_status & FDCAN_PSR_BO) != 0U) { // BO = Bus-Off Flag - return true; - } + FDCAN_ProtocolStatusTypeDef protocol_status = {0}; - return false; + return // HAL states + state == HAL_FDCAN_STATE_ERROR || + state == HAL_FDCAN_STATE_READY + // Check for bus off condition + || (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff); } HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle) @@ -129,29 +112,3 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle) return HAL_OK; } - -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) -{ - if (handle == NULL || handle->hfdcan == NULL) { - // Invalid parameter - return HAL_ERROR; - } - - uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); - uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_acquire); - - if (current_head == current_tail) { - // Queue empty - return HAL_OK; - } - - uint32_t current_index = current_head & TX_QUEUE_MASK; - GRCAN_TxMessage message_copy = handle->tx_queue[current_index]; - - if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { - return HAL_ERROR; - } - - atomic_store_explicit(&handle->tx_head, (current_head + 1U), memory_order_release); - return HAL_OK; -} diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake index 23a051caa..7f0492132 100644 --- a/Lib/Peripherals/CubeCAN/cubemx_can.cmake +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -9,9 +9,12 @@ target_include_directories( target_sources( CUBEMX_CAN_LIB INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/Src/can_it.c - ${CMAKE_CURRENT_LIST_DIR}/Src/can_utils.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_assert.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_global.c ${CMAKE_CURRENT_LIST_DIR}/Src/can_init.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_rx.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_tx.c + ${CMAKE_CURRENT_LIST_DIR}/Src/can_utils.c ) target_link_libraries( diff --git a/Lib/Utils/Logomatic/Inc/Logomatic.h b/Lib/Utils/Logomatic/Inc/Logomatic.h index d291f296a..21734ba64 100644 --- a/Lib/Utils/Logomatic/Inc/Logomatic.h +++ b/Lib/Utils/Logomatic/Inc/Logomatic.h @@ -3,8 +3,8 @@ #include "main.h" -#ifndef _LOGOMATIC_H_ -#define _LOGOMATIC_H_ +#ifndef LOGOMATIC_H +#define LOGOMATIC_H #if defined(ITM) && defined(LL_GPIO_MODE_ALTERNATE) typedef enum { @@ -113,10 +113,8 @@ void Setup_Logomatic(LogomaticConfig *config); */ #define LOGOMATIC(...) \ do { \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wdouble-promotion\""); \ - printf(__VA_ARGS__); \ - _Pragma("GCC diagnostic pop"); \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdouble-promotion\"") printf(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") \ } while (0) #else @@ -129,10 +127,8 @@ void Setup_Logomatic(LogomaticConfig *config); #define LOGOMATIC(...) \ do { \ if (0) { \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wdouble-promotion\""); \ - printf(__VA_ARGS__); \ - _Pragma("GCC diagnostic pop"); \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdouble-promotion\"") printf(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") \ } \ } while (0) #endif From 685a4ef96e7634789babf2fc7afaffde3b16c91a Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Wed, 22 Jul 2026 23:48:08 -0700 Subject: [PATCH 25/38] Further improvements to internal setup Signed-off-by: Daniel Hansen --- CUBEMXTESTING/Core/Src/main.c | 165 +++++++++--------- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 22 ++- Lib/Peripherals/CubeCAN/Src/can_rx.c | 4 +- Lib/Peripherals/CubeCAN/Src/can_utils.c | 22 +++ Lib/Peripherals/CubeCAN/cubemx_can.cmake | 1 + 5 files changed, 114 insertions(+), 100 deletions(-) diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 7dc29b231..ae2deaf7b 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -18,9 +18,10 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" + #include "fdcan.h" -#include "tim.h" #include "gpio.h" +#include "tim.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ @@ -91,39 +92,39 @@ void SystemClock_Config(void); /* USER CODE END 0 */ /** - * @brief The application entry point. - * @retval int - */ + * @brief The application entry point. + * @retval int + */ int main(void) { - /* USER CODE BEGIN 1 */ + /* USER CODE BEGIN 1 */ - /* USER CODE END 1 */ + /* USER CODE END 1 */ - /* MCU Configuration--------------------------------------------------------*/ + /* MCU Configuration--------------------------------------------------------*/ - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); - /* USER CODE BEGIN Init */ + /* USER CODE BEGIN Init */ - /* USER CODE END Init */ + /* USER CODE END Init */ - /* Configure the system clock */ - SystemClock_Config(); + /* Configure the system clock */ + SystemClock_Config(); - /* USER CODE BEGIN SysInit */ + /* USER CODE BEGIN SysInit */ - /* USER CODE END SysInit */ + /* USER CODE END SysInit */ - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_FDCAN1_Init(); - MX_FDCAN2_Init(); - MX_TIM5_Init(); - MX_FDCAN3_Init(); - /* USER CODE BEGIN 2 */ + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_FDCAN1_Init(); + MX_FDCAN2_Init(); + MX_TIM5_Init(); + MX_FDCAN3_Init(); + /* USER CODE BEGIN 2 */ Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); @@ -132,66 +133,58 @@ int main(void) if (CAN_Timer_Start() != HAL_OK) { Error_Handler(); } - /* USER CODE END 2 */ + /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ LOGOMATIC("Hello World!\n"); while (1) { - /* USER CODE END WHILE */ + /* USER CODE END WHILE */ - /* USER CODE BEGIN 3 */ + /* USER CODE BEGIN 3 */ } - /* USER CODE END 3 */ + /* USER CODE END 3 */ } /** - * @brief System Clock Configuration - * @retval None - */ + * @brief System Clock Configuration + * @retval None + */ void SystemClock_Config(void) { - LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); - while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) - { - } - LL_PWR_EnableRange1BoostMode(); - LL_RCC_HSI_Enable(); - /* Wait till HSI is ready */ - while(LL_RCC_HSI_IsReady() != 1) - { - } - - LL_RCC_HSI_SetCalibTrimming(64); - LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 20, LL_RCC_PLLR_DIV_2); - LL_RCC_PLL_EnableDomain_SYS(); - LL_RCC_PLL_Enable(); - /* Wait till PLL is ready */ - while(LL_RCC_PLL_IsReady() != 1) - { - } - - LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); - LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); - /* Wait till System clock is ready */ - while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) - { - } - - /* Insure 1us transition state at intermediate medium speed clock*/ - for (__IO uint32_t i = (170 >> 1); i !=0; i--); - - /* Set AHB prescaler*/ - LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); - LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); - LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); - LL_SetSystemCoreClock(160000000); - - /* Update the time base */ - if (HAL_InitTick (TICK_INT_PRIORITY) != HAL_OK) - { - Error_Handler(); - } + LL_FLASH_SetLatency(LL_FLASH_LATENCY_4); + while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) {} + LL_PWR_EnableRange1BoostMode(); + LL_RCC_HSI_Enable(); + /* Wait till HSI is ready */ + while (LL_RCC_HSI_IsReady() != 1) {} + + LL_RCC_HSI_SetCalibTrimming(64); + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 20, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_EnableDomain_SYS(); + LL_RCC_PLL_Enable(); + /* Wait till PLL is ready */ + while (LL_RCC_PLL_IsReady() != 1) {} + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + /* Wait till System clock is ready */ + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {} + + /* Insure 1us transition state at intermediate medium speed clock*/ + for (__IO uint32_t i = (170 >> 1); i != 0; i--) + ; + + /* Set AHB prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + LL_SetSystemCoreClock(160000000); + + /* Update the time base */ + if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK) { + Error_Handler(); + } } /* USER CODE BEGIN 4 */ @@ -211,29 +204,29 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) /* USER CODE END 4 */ /** - * @brief This function is executed in case of error occurrence. - * @retval None - */ + * @brief This function is executed in case of error occurrence. + * @retval None + */ void Error_Handler(void) { - /* USER CODE BEGIN Error_Handler_Debug */ + /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) {} - /* USER CODE END Error_Handler_Debug */ + /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ void assert_failed(uint8_t *file, uint32_t line) { - /* USER CODE BEGIN 6 */ - printf("Assert failed! File %s on line %d\n", file, line); - /* USER CODE END 6 */ + /* USER CODE BEGIN 6 */ + printf("Assert failed! File %s on line %ld\n", file, line); + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 127a8c910..70445e57c 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -11,18 +11,6 @@ #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H -/** - * @brief Macro to convert a CubeMX CAN instance pointer to its corresponding index. - * - * Works on all supported boards, but new boards should be verified against this operation - * - * @param inst Pointer to the CubeMX CAN instance (FDCAN1, FDCAN2, or FDCAN3). - * @return The index corresponding to the given CubeMX CAN instance (0 for FDCAN1, 1 for FDCAN2, and 2 for FDCAN3). - * @warning This macro assumes that the CubeMX CAN instances are contiguous in memory and that FDCAN1 is the first instance. It may not work correctly if the instances are not contiguous or if FDCAN1 - * is not the first instance. - */ -#define CUBEMX_CAN_INSTANCE_TO_INDEX(inst) ((uint32_t)((uintptr_t)(inst) - FDCAN1_BASE) >> 10) - /** * @brief Mask for the transmission queue index, used to wrap around the queue when it reaches its maximum size. * @@ -33,6 +21,16 @@ */ #define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) +/** + * @brief Function to convert a CubeMX CAN instance pointer to its corresponding index. + * + * Works on all supported boards, but new boards should be verified against this operation + * + * @param can Pointer to the CubeMX CAN instance (FDCAN1, FDCAN2, or FDCAN3). + * @return The index corresponding to the given CubeMX CAN instance (0 for FDCAN1, 1 for FDCAN2, and 2 for FDCAN3). + */ +uint32_t CubeMXCan_Private_InstanceToIndex(FDCAN_GlobalTypeDef *can); + /** * @brief CubeMX CAN handle structure * diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index e21f05d9d..a786d6c2f 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -19,8 +19,8 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) CubeMXCan_Handle *handle = NULL; for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (s_handles[i].hfdcan == hfdcan) { - handle = &s_handles[i]; + if (handles[i].hfdcan == hfdcan) { + handle = &handles[i]; break; } } diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index c60010bdd..5cd85f551 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -10,6 +10,28 @@ #include "Logomatic.h" #include "Private/PrivateCubeMXCAN.h" +uint32_t CubeMXCan_Private_InstanceToIndex(FDCAN_GlobalTypeDef *can) +{ + assert(can != NULL && "Invalid null parameter"); + + switch ((uint32_t)can) { +#if defined(FDCAN1) + case (uint32_t)FDCAN1: + return 0U; +#endif +#if defined(FDCAN2) + case (uint32_t)FDCAN2: + return 1U; +#endif +#if defined(FDCAN3) + case (uint32_t)FDCAN3: + return 2U; +#endif + default: + assert(false && "Invalid CubeMX CAN instance or improper setup in main.h, please use CubeMX to regenerate code and verify your parameters."); + } +} + uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) { if (identifier == NULL) { diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cubemx_can.cmake index 7f0492132..998f3da0c 100644 --- a/Lib/Peripherals/CubeCAN/cubemx_can.cmake +++ b/Lib/Peripherals/CubeCAN/cubemx_can.cmake @@ -21,6 +21,7 @@ target_link_libraries( CUBEMX_CAN_LIB INTERFACE CANfigurator + LOGOMATIC_LIB ) if(CMAKE_PRESET_NAME STREQUAL "HOOTLTest") From 338679a3f5a63b63aae670734e63f9f5b6919c91 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 23 Jul 2026 00:23:48 -0700 Subject: [PATCH 26/38] Fix locking and atomics, and cleanup Signed-off-by: Daniel Hansen --- Lib/GlobalShare/Inc/CriticalSection.h | 1 + Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 2 +- Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 2 +- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 55 +--------------- Lib/Peripherals/CubeCAN/Src/can_global.c | 1 - Lib/Peripherals/CubeCAN/Src/can_init.c | 66 ++----------------- Lib/Peripherals/CubeCAN/Src/can_tx.c | 27 +++++--- Lib/Peripherals/CubeCAN/Src/can_utils.c | 49 +++++--------- 8 files changed, 44 insertions(+), 159 deletions(-) diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h index d83cdc242..3d6fa7453 100644 --- a/Lib/GlobalShare/Inc/CriticalSection.h +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -63,6 +63,7 @@ static inline void _magic_auto_critical_exit(uint32_t *state_var) * * @warning This macro should be used with caution, as it can lead to deadlocks or other issues if not used correctly. It is recommended to use this macro only in situations where it is necessary to * disable interrupts for a short period of time. + * @warning If you use goto statements it will not automatically cleanup. However, you should not use goto at all. */ #define CRITICAL_SECTION \ for (__attribute__((cleanup(_magic_auto_critical_exit))) uint32_t CONCAT(_magic_auto_critical_state_, __LINE__) = __get_PRIMASK(), \ diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 89db887a7..d9b381610 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -98,7 +98,7 @@ HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_Filt * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. * @param handle Pointer to the CubeMX CAN handle. * @param message Pointer to the GRCAN transmission message structure. - * @return HAL_StatusTypeDef indicating the success or failure of the operation. + * @return HAL_StatusTypeDef if the parameters are non-null or the queue is full. */ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message); diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h index 3cc2ad110..82f36e008 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -14,7 +14,7 @@ * This structure is used to represent a CAN message identifier, which consists of a transmitting node ID, a receiving node ID, and a message ID. The structure is used in conjunction with the * Construct_Message_ID and Deconstruct_Message_ID functions to convert between the structure representation and the 32-bit integer representation of the CAN message identifier. * - * @warning The structure does not represent cusotm IDs. + * @warning The structure does not represent custom IDs. * @warning The structure does not represent actual bit depth */ typedef struct { diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 70445e57c..e9d6c3c7c 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -21,16 +21,6 @@ */ #define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) -/** - * @brief Function to convert a CubeMX CAN instance pointer to its corresponding index. - * - * Works on all supported boards, but new boards should be verified against this operation - * - * @param can Pointer to the CubeMX CAN instance (FDCAN1, FDCAN2, or FDCAN3). - * @return The index corresponding to the given CubeMX CAN instance (0 for FDCAN1, 1 for FDCAN2, and 2 for FDCAN3). - */ -uint32_t CubeMXCan_Private_InstanceToIndex(FDCAN_GlobalTypeDef *can); - /** * @brief CubeMX CAN handle structure * @@ -57,27 +47,6 @@ struct CubeMXCan_Handle { /// @brief Maximum number of CubeMX CAN instances supported by the library. #define CUBEMX_CAN_MAX_INSTANCES 3U -/** - * @brief Retrieves the CubeMX CAN handle associated with the given FDCAN handle. - * @param hfdcan Pointer to the FDCAN handle. - * @return Pointer to the CubeMX CAN handle associated with the given FDCAN handle - */ -CubeMXCan_Handle *CubeMXCan_Private_GetHandle(FDCAN_HandleTypeDef *hfdcan); - -/** - * @brief Registers a CubeMX CAN handle with the given FDCAN handle. - * @param hfdcan Pointer to the FDCAN handle. - * @param handle Pointer to the CubeMX CAN handle. - * @return HAL_StatusTypeDef indicating the success or failure of the operation. - */ -HAL_StatusTypeDef CubeMXCan_Private_RegisterHandle(FDCAN_HandleTypeDef *hfdcan, CubeMXCan_Handle *handle); - -/** - * @brief Unregisters the CubeMX CAN handle associated with the given FDCAN handle. - * @param hfdcan Pointer to the FDCAN handle. - */ -void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan); - /** * @brief Sends a queued message from the CubeMX CAN handle. * @param handle Pointer to the CubeMX CAN handle. @@ -85,12 +54,6 @@ void CubeMXCan_Private_UnregisterHandle(FDCAN_HandleTypeDef *hfdcan); */ HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle); -/** - * @brief Dispatches a received message from the CubeMX CAN handle. - * @param hfdcan Pointer to the FDCAN handle. - */ -void CubeMXCan_Private_DispatchRx(FDCAN_HandleTypeDef *hfdcan); - /** * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. * @param dlc The Data Length Code to be converted. @@ -109,22 +72,6 @@ void CubeMXCan_Tick(void); */ void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan); -/** - * @brief Structure representing a registry entry for the CubeMX CAN library, used to associate a CubeMX CAN handle with its corresponding FDCAN handle. - */ -struct CubeMXCan_RegistryEntry { - /// @brief Pointer to the FDCAN instance associated with this registry entry. - FDCAN_GlobalTypeDef *instance; - /// @brief Pointer to the CubeMX CAN handle associated with this registry entry. - CubeMXCan_Handle *handle; -}; - -/** - * @brief Registry entry structure for the CubeMX CAN library, used to associate a CubeMX CAN handle with its corresponding FDCAN handle. - * @note The number of entries in the registry is defined by CUBEMX_CAN_MAX_INSTANCES. - */ -extern struct CubeMXCan_RegistryEntry registry[CUBEMX_CAN_MAX_INSTANCES]; - /** * @brief Array of CubeMX CAN handles, one for each supported instance. * @note The number of instances is defined by CUBEMX_CAN_MAX_INSTANCES. @@ -134,7 +81,7 @@ extern struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; /** * @brief Flag indicating whether the CubeMX CAN Tx timer has been started. */ -extern bool s_timer_started; +extern bool timer_started; /** * @brief Attempts to recover the FDCAN peripheral associated with the given CubeMX CAN handle. diff --git a/Lib/Peripherals/CubeCAN/Src/can_global.c b/Lib/Peripherals/CubeCAN/Src/can_global.c index aa7613e89..71f39ff0a 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_global.c +++ b/Lib/Peripherals/CubeCAN/Src/can_global.c @@ -7,6 +7,5 @@ #include "CubeMXCanExt.h" #include "Private/PrivateCubeMXCAN.h" -struct CubeMXCan_RegistryEntry registry[CUBEMX_CAN_MAX_INSTANCES] = {0}; struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; bool timer_started = false; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 627d37eea..6621bdf0b 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -58,7 +58,10 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) return HAL_ERROR; } - (void)CubeMXCan_Stop(handle); + if (CubeMXCan_Stop(handle) != HAL_OK) { + LOGOMATIC("CubeMXCan_Release: failed to stop CAN peripheral\n"); + return HAL_ERROR; + } CRITICAL_SECTION { @@ -68,30 +71,6 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) return HAL_OK; } -void CubeMXCan_Tick(void) -{ - for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - CubeMXCan_Handle *handle = registry[i].handle; - - CRITICAL_SECTION - { - if (handle == NULL || handle->hfdcan == NULL || !handle->started) { - continue; - } - } - - if (CubeMXCan_Private_IsDisabled(handle)) { - LOGOMATIC("CAN_send: currently in restricted operation mode\n"); - if (CubeMXCan_Private_RecoverPeripheral(handle) != HAL_OK) { - LOGOMATIC("CAN_send %d: failed to recover peripheral\n", (int)i); - continue; - } - } - - (void)CubeMXCan_Private_SendQueuedMessage(handle); - } -} - HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle) { if (handle == NULL || handle->hfdcan == NULL) { @@ -116,45 +95,14 @@ HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle) return HAL_ERROR; } - CRITICAL_SECTION - { - handle->started = false; - } - if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { return HAL_ERROR; } - return HAL_OK; -} - -HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) -{ - if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { - return HAL_ERROR; - } - - return HAL_FDCAN_ConfigFilter(handle->hfdcan, (FDCAN_FilterTypeDef *)filter); -} - -HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message) -{ - if (handle == NULL || message == NULL) { - return HAL_ERROR; - } - - uint32_t current_tail = atomic_load(&handle->tx_tail); - uint32_t current_head = atomic_load(&handle->tx_head); - - if ((current_tail - current_head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { - LOGOMATIC("CubeMXCan_QueueTx: queue is full\n"); - return HAL_TIMEOUT; + CRITICAL_SECTION + { + handle->started = false; } - uint32_t insert_index = current_tail & TX_QUEUE_MASK; - handle->tx_queue[insert_index] = *message; - - atomic_store_explicit(&handle->tx_tail, current_tail + 1U, memory_order_release); - return HAL_OK; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index 3bb804ea8..ed71ad3fe 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -18,9 +18,9 @@ void CubeMXCan_Tick(void) } if (CubeMXCan_Private_IsDisabled(handle)) { - LOGOMATIC("CAN_send: currently in restricted operation mode\n"); + LOGOMATIC("CubeMXCan_Tick: currently in restricted operation mode\n"); if (CubeMXCan_Private_RecoverPeripheral(handle) != HAL_OK) { - LOGOMATIC("CAN_send %d: failed to recover peripheral\n", (int)i); + LOGOMATIC("CubeMXCan_Tick %d: failed to recover peripheral\n", (int)i); continue; } } @@ -35,17 +35,24 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess return HAL_ERROR; } - uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_relaxed); - uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_acquire); + HAL_StatusTypeDef status = HAL_OK; - if ((current_tail - current_head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { - LOGOMATIC("CubeMXCan_QueueTx: queue is full\n"); - return HAL_TIMEOUT; + CRITICAL_SECTION + { + uint32_t tail = atomic_load_explicit(&handle->tx_tail, memory_order_relaxed); + uint32_t head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); + + if ((tail - head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { + head++; // Drop oldest message to make room for the new one + atomic_store_explicit(&handle->tx_head, head, memory_order_relaxed); + status = HAL_TIMEOUT; + } + handle->tx_queue[tail & TX_QUEUE_MASK] = *message; + + atomic_store_explicit(&handle->tx_tail, tail + 1U, memory_order_release); } - handle->tx_queue[current_tail & TX_QUEUE_MASK] = *message; - atomic_store_explicit(&handle->tx_tail, current_tail + 1U, memory_order_release); - return HAL_OK; + return status; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 5cd85f551..c0ff274ef 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -10,27 +10,11 @@ #include "Logomatic.h" #include "Private/PrivateCubeMXCAN.h" -uint32_t CubeMXCan_Private_InstanceToIndex(FDCAN_GlobalTypeDef *can) -{ - assert(can != NULL && "Invalid null parameter"); - - switch ((uint32_t)can) { -#if defined(FDCAN1) - case (uint32_t)FDCAN1: - return 0U; -#endif -#if defined(FDCAN2) - case (uint32_t)FDCAN2: - return 1U; -#endif -#if defined(FDCAN3) - case (uint32_t)FDCAN3: - return 2U; -#endif - default: - assert(false && "Invalid CubeMX CAN instance or improper setup in main.h, please use CubeMX to regenerate code and verify your parameters."); - } -} +#define CAN_TX_NODE_SHIFT 20U +#define CAN_MSG_SHIFT 8U +#define CAN_RX_NODE_SHIFT 0U +#define CAN_NODE_MASK 0xFFU +#define CAN_MSG_MASK 0xFFFU uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) { @@ -39,21 +23,21 @@ uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) } return // Transmitting node - ((uint32_t)(identifier->tx_node_id & 0xFFU) << 20U) + ((uint32_t)(identifier->tx_node_id & CAN_NODE_MASK) << CAN_TX_NODE_SHIFT) // Message ID - | ((uint32_t)(identifier->msg_id & 0xFFFU) << 8U) + | ((uint32_t)(identifier->msg_id & CAN_MSG_MASK) << CAN_MSG_SHIFT) // Receiving node - | (uint32_t)(identifier->rx_node_id & 0xFFU); + | ((uint32_t)(identifier->rx_node_id & CAN_NODE_MASK) << CAN_RX_NODE_SHIFT); } CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id) { return (CAN_Identifier){// Transmitting node - .tx_node_id = (GRCAN_NODE_ID)((message_id >> 20U) & 0xFFU), + .tx_node_id = (GRCAN_NODE_ID)((message_id >> CAN_TX_NODE_SHIFT) & CAN_NODE_MASK), // Message ID - .msg_id = (GRCAN_MSG_ID)((message_id >> 8U) & 0xFFFU), + .msg_id = (GRCAN_MSG_ID)((message_id >> CAN_MSG_SHIFT) & CAN_MSG_MASK), // Receiving node - .rx_node_id = (GRCAN_NODE_ID)(message_id & 0xFFU)}; + .rx_node_id = (GRCAN_NODE_ID)(message_id >> CAN_RX_NODE_SHIFT) & CAN_NODE_MASK}; } HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter) @@ -75,11 +59,10 @@ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifie HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) { if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { - LOGOMATIC("CubeMXCan_AddFilter: Invalid null parameter\n"); return HAL_ERROR; } - return HAL_FDCAN_ConfigFilter(handle->hfdcan, (FDCAN_FilterTypeDef *)filter); + return HAL_FDCAN_ConfigFilter(handle->hfdcan, filter); } uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) @@ -112,23 +95,23 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle) FDCAN_ProtocolStatusTypeDef protocol_status = {0}; if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff) { - LOGOMATIC("CAN_send: bus off detected, attempting recovery\n"); + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: bus off detected, attempting recovery\n"); if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { - LOGOMATIC("CAN_send: failed to stop FDCAN peripheral during bus off recovery\n"); + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: failed to stop FDCAN peripheral during bus off recovery\n"); return HAL_ERROR; } HAL_FDCAN_AbortTxRequest(handle->hfdcan, FDCAN_TX_BUFFER0 | FDCAN_TX_BUFFER1 | FDCAN_TX_BUFFER2); if (HAL_FDCAN_Start(handle->hfdcan) != HAL_OK) { - LOGOMATIC("CAN_send: failed to restart FDCAN peripheral during bus off recovery\n"); + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: failed to restart FDCAN peripheral during bus off recovery\n"); return HAL_ERROR; } } if (HAL_FDCAN_IsRestrictedOperationMode(handle->hfdcan)) { - LOGOMATIC("CAN_send: currently in restricted operation mode\n"); + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: currently in restricted operation mode\n"); HAL_FDCAN_ExitRestrictedOperationMode(handle->hfdcan); } From 42f575e5f14b8ed3bbcf73de99fc6bfaf8ffd261 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 23 Jul 2026 00:54:59 -0700 Subject: [PATCH 27/38] Ensure proper handling of tick Signed-off-by: Daniel Hansen --- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 6 ++++++ Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 5 ----- Lib/Peripherals/CubeCAN/Src/can_tx.c | 7 ------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index d9b381610..8867628c9 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -110,4 +110,10 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess */ bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle); +/** + * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. + * @warning This function sends one can message per configured bus per call. Not calling it will simply not send any messages. + */ +void CubeMXCan_Tick(void); + #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index e9d6c3c7c..ff7d16b9e 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -61,11 +61,6 @@ HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle); */ uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc); -/** - * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. - */ -void CubeMXCan_Tick(void); - /** * @brief Callback function for handling received messages from the FDCAN peripheral. This function is called when a message is received in the RX FIFO 0 of the FDCAN peripheral. * @param hfdcan Pointer to the FDCAN handle associated with the received message. diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index ed71ad3fe..9346df5b0 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -55,13 +55,6 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess return status; } -void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) -{ - if (htim != NULL && htim->Instance == CUBEMX_CAN_TIMER_INSTANCE) { - CubeMXCan_Tick(); - } -} - HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) { if (handle == NULL || handle->hfdcan == NULL) { From 0305d2c2750eb07f8b1e11a41c4b57e04100d0e8 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Thu, 23 Jul 2026 01:04:38 -0700 Subject: [PATCH 28/38] Cleanup defines Signed-off-by: Daniel Hansen --- CUBEMXTESTING/Application/Inc/CubeCAN_Config.h | 6 ------ Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 9 +++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index 7ff7a2a33..bd5e39a5a 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -5,12 +5,6 @@ #include "main.h" -#define USECAN1 -#define USECAN2 - -#define CUBEMX_CAN_TIMER_INSTANCE TIM5 #define CUBEMX_CAN_TX_QUEUE_SIZE 32U -#define CAN_TIMER_SEND_PERIOD_US 500U -#define CAN_TIMER_HANDLE TIM5 #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index ff7d16b9e..8c8870e5d 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -6,6 +6,7 @@ #include "CubeMXCan.h" #include "Logomatic.h" #include "Stringification.h" +#include "fdcan.h" #include "main.h" #ifndef PRIVATE_CUBE_MX_CAN_H @@ -45,7 +46,15 @@ struct CubeMXCan_Handle { }; /// @brief Maximum number of CubeMX CAN instances supported by the library. +#if defined(FDCAN3) || defined(CAN3) #define CUBEMX_CAN_MAX_INSTANCES 3U +#elif (defined(FDCAN2) || defined(CAN2)) +#define CUBEMX_CAN_MAX_INSTANCES 2U +#elif (defined(FDCAN1) || defined(CAN1)) +#define CUBEMX_CAN_MAX_INSTANCES 1U +#else +#error "No CAN or FDCAN instances defined. Please check your CubeMX configuration." +#endif /** * @brief Sends a queued message from the CubeMX CAN handle. From 41984c914572025f63a3b5e7e2f0a35e975519de Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 02:20:51 -0700 Subject: [PATCH 29/38] Redundancy checking on max instances Signed-off-by: Daniel Hansen --- Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 8c8870e5d..bdb91aac0 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -46,15 +46,17 @@ struct CubeMXCan_Handle { }; /// @brief Maximum number of CubeMX CAN instances supported by the library. -#if defined(FDCAN3) || defined(CAN3) +#ifndef CUBEMX_CAN_MAX_INSTANCES +#if (defined(FDCAN3) || defined(CAN3)) && (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) #define CUBEMX_CAN_MAX_INSTANCES 3U -#elif (defined(FDCAN2) || defined(CAN2)) +#elif (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) #define CUBEMX_CAN_MAX_INSTANCES 2U #elif (defined(FDCAN1) || defined(CAN1)) #define CUBEMX_CAN_MAX_INSTANCES 1U #else #error "No CAN or FDCAN instances defined. Please check your CubeMX configuration." #endif +#endif /** * @brief Sends a queued message from the CubeMX CAN handle. From fe29a42b6afa44e4efc1b9e836c35ac20b9921b2 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 02:29:35 -0700 Subject: [PATCH 30/38] Remove templates, very broken sadly Thanks to Rehan for trying out different iterations of them Signed-off-by: Daniel Hansen --- Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl | 268 ------------------ Lib/CubeMXTemplates/README.md | 9 - 2 files changed, 277 deletions(-) delete mode 100644 Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl delete mode 100644 Lib/CubeMXTemplates/README.md diff --git a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl b/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl deleted file mode 100644 index 815c29617..000000000 --- a/Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl +++ /dev/null @@ -1,268 +0,0 @@ -[#ftl] -[#-- - Generates can_cfg.h from the active STM32CubeMX project. - - Detects enabled FDCAN and TIM peripherals and emits compile-time configuration - for the Gaucho Racing CAN runtime. - - CubeMX remains responsible for: - - FDCAN clocks, GPIO, bit timing, HAL handles, and MX_FDCANx_Init() - - TIM clocks, prescaler, NVIC configuration, HAL handle, and MX_TIMx_Init() - - The CAN runtime uses the selected CubeMX-generated TIM handle to periodically - service its software TX queues. ---] - -[#list configs as dt] - -[#assign usedIPs = (dt.usedIPs)![]] - -[#assign hasFDCAN1 = false] -[#assign hasFDCAN2 = false] -[#assign hasFDCAN3 = false] - -[#assign hasTIM1 = false] -[#assign hasTIM2 = false] -[#assign hasTIM3 = false] -[#assign hasTIM4 = false] -[#assign hasTIM5 = false] -[#assign hasTIM6 = false] -[#assign hasTIM7 = false] -[#assign hasTIM8 = false] -[#assign hasTIM15 = false] -[#assign hasTIM16 = false] -[#assign hasTIM17 = false] - -[#list usedIPs as ip] - [#assign ipName = ip?string] - - [#if ipName == "FDCAN1"] - [#assign hasFDCAN1 = true] - [/#if] - [#if ipName == "FDCAN2"] - [#assign hasFDCAN2 = true] - [/#if] - [#if ipName == "FDCAN3"] - [#assign hasFDCAN3 = true] - [/#if] - - [#if ipName == "TIM1"] - [#assign hasTIM1 = true] - [/#if] - [#if ipName == "TIM2"] - [#assign hasTIM2 = true] - [/#if] - [#if ipName == "TIM3"] - [#assign hasTIM3 = true] - [/#if] - [#if ipName == "TIM4"] - [#assign hasTIM4 = true] - [/#if] - [#if ipName == "TIM5"] - [#assign hasTIM5 = true] - [/#if] - [#if ipName == "TIM6"] - [#assign hasTIM6 = true] - [/#if] - [#if ipName == "TIM7"] - [#assign hasTIM7 = true] - [/#if] - [#if ipName == "TIM8"] - [#assign hasTIM8 = true] - [/#if] - [#if ipName == "TIM15"] - [#assign hasTIM15 = true] - [/#if] - [#if ipName == "TIM16"] - [#assign hasTIM16 = true] - [/#if] - [#if ipName == "TIM17"] - [#assign hasTIM17 = true] - [/#if] -[/#list] - -#ifndef CAN_CFG_H -#define CAN_CFG_H - -/* Generated automatically by STM32CubeMX FreeMarker. */ - -/* - * User-editable CAN runtime configuration. - * - * CAN_TIMER_INDEX: - * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. - * - * CAN_TIMER_TICK_US: - * Duration of one timer counter tick, determined by the CubeMX prescaler. - * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. - * - * CAN_DEQUEUE_PERIOD_US: - * Time between attempts to dequeue and send one software-queued CAN message. - */ -/* USER CODE BEGIN CAN_USER_CONFIG */ - -#ifndef TX_BUFFER_1_SIZE -#define TX_BUFFER_1_SIZE 20U -#endif - -#ifndef TX_BUFFER_2_SIZE -#define TX_BUFFER_2_SIZE 20U -#endif - -#ifndef TX_BUFFER_3_SIZE -#define TX_BUFFER_3_SIZE 20U -#endif - -#ifndef CAN_TIMER_INDEX -#define CAN_TIMER_INDEX 5 -#endif - -#ifndef CAN_TIMER_TICK_US -#define CAN_TIMER_TICK_US 100U -#endif - -#ifndef CAN_DEQUEUE_PERIOD_US -#define CAN_DEQUEUE_PERIOD_US 500U -#endif - -/* USER CODE END CAN_USER_CONFIG */ - -/* Enabled FDCAN peripherals. */ - -[#if hasFDCAN1] -#define USECAN1 -[/#if] - -[#if hasFDCAN2] -#define USECAN2 -[/#if] - -[#if hasFDCAN3] -#define USECAN3 -[/#if] - -/* Timers enabled in CubeMX. */ - -[#if hasTIM1] -#define CUBEMX_HAS_TIM1 -[/#if] -[#if hasTIM2] -#define CUBEMX_HAS_TIM2 -[/#if] -[#if hasTIM3] -#define CUBEMX_HAS_TIM3 -[/#if] -[#if hasTIM4] -#define CUBEMX_HAS_TIM4 -[/#if] -[#if hasTIM5] -#define CUBEMX_HAS_TIM5 -[/#if] -[#if hasTIM6] -#define CUBEMX_HAS_TIM6 -[/#if] -[#if hasTIM7] -#define CUBEMX_HAS_TIM7 -[/#if] -[#if hasTIM8] -#define CUBEMX_HAS_TIM8 -[/#if] -[#if hasTIM15] -#define CUBEMX_HAS_TIM15 -[/#if] -[#if hasTIM16] -#define CUBEMX_HAS_TIM16 -[/#if] -[#if hasTIM17] -#define CUBEMX_HAS_TIM17 -[/#if] - -/* Configuration validation. */ - -#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) -#error "TX_BUFFER_1_SIZE must be greater than zero" -#endif - -#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) -#error "TX_BUFFER_2_SIZE must be greater than zero" -#endif - -#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) -#error "TX_BUFFER_3_SIZE must be greater than zero" -#endif - -#if CAN_TIMER_TICK_US == 0U -#error "CAN_TIMER_TICK_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US == 0U -#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US -#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" -#endif - -#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U -#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" -#endif - -#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU -#error "CAN dequeue period exceeds the supported timer auto-reload range" -#endif - -#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) -#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) -#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) -#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) -#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) -#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) -#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) -#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) -#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) -#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) -#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) -#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX != 1) && \ - (CAN_TIMER_INDEX != 2) && \ - (CAN_TIMER_INDEX != 3) && \ - (CAN_TIMER_INDEX != 4) && \ - (CAN_TIMER_INDEX != 5) && \ - (CAN_TIMER_INDEX != 6) && \ - (CAN_TIMER_INDEX != 7) && \ - (CAN_TIMER_INDEX != 8) && \ - (CAN_TIMER_INDEX != 15) && \ - (CAN_TIMER_INDEX != 16) && \ - (CAN_TIMER_INDEX != 17) -#error "CAN_TIMER_INDEX selects an unsupported timer" -#endif - -#define CAN_TIMER_PERIOD_COUNTS \ - (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - -#define CAN_TIMER_AUTORELOAD \ - (CAN_TIMER_PERIOD_COUNTS - 1U) - -/* - * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. - * - * CAN_TIMER_INDEX = 5 - * CAN_TIMER_HANDLE = htim5 - */ -#define CAN_CFG_JOIN_INNER(a, b) a##b -#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) -#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) - -#endif /* CAN_CFG_H */ - -[/#list] diff --git a/Lib/CubeMXTemplates/README.md b/Lib/CubeMXTemplates/README.md deleted file mode 100644 index 37ba973d7..000000000 --- a/Lib/CubeMXTemplates/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# STM32 CubeMX Templates - -## Instructions - -1. Uncheck use default location and configure it to point to this folder (not `Autogen`!) -2. Add all of the relevant templates from available into selected -3. TODO (As we figure out the destination folder bit) - -## TODO From b00386f6f97311ae02e27eadb2ba3787340b3f29 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 04:14:56 -0700 Subject: [PATCH 31/38] Harden testing of the critical section code Signed-off-by: Daniel Hansen --- Lib/GlobalShare/Inc/CriticalSection.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/GlobalShare/Inc/CriticalSection.h b/Lib/GlobalShare/Inc/CriticalSection.h index 3d6fa7453..7e53dd0b5 100644 --- a/Lib/GlobalShare/Inc/CriticalSection.h +++ b/Lib/GlobalShare/Inc/CriticalSection.h @@ -1,7 +1,6 @@ #include #include "Stringification.h" -#include "main.h" #ifndef CRITICAL_SECTION_H #define CRITICAL_SECTION_H @@ -29,16 +28,17 @@ static inline void __disable_irq(void) static inline void __set_PRIMASK(uint32_t state) { - (void)state; - - __mock_irq_nesting_depth--; - - if (__mock_irq_nesting_depth == 0) { - __mock_primask_state = 0; + if (__mock_irq_nesting_depth > 0) { + __mock_irq_nesting_depth--; + if (__mock_irq_nesting_depth == 0 || state == 0) { + __mock_primask_state = 0; + __mock_irq_nesting_depth = 0; + } } - pthread_mutex_unlock(&__mock_global_irq_mutex); } +#else +#include "main.h" #endif /** From 8a48cf7f47dcc673fa30c865f50ecefd06bb4226 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 04:15:11 -0700 Subject: [PATCH 32/38] Harden CubeCAN Signed-off-by: Daniel Hansen --- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 31 ++-- Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 6 +- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 23 ++- Lib/Peripherals/CubeCAN/Src/can_assert.c | 13 +- Lib/Peripherals/CubeCAN/Src/can_init.c | 68 +++++---- Lib/Peripherals/CubeCAN/Src/can_rx.c | 49 +++++-- Lib/Peripherals/CubeCAN/Src/can_tx.c | 19 ++- Lib/Peripherals/CubeCAN/Src/can_utils.c | 137 ++++++++++++------ 8 files changed, 216 insertions(+), 130 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 8867628c9..91ed9f493 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -14,7 +14,8 @@ /** * @brief Received CAN message structure * - * This structure is used to represent a received CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and other relevant parameters. The data payload contains the actual data bytes of the message. + * This structure is used to represent a received CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and + * other relevant parameters. The data payload contains the actual data bytes of the message. * * @warning The length of the data array may be longer than the actual CAN message. */ @@ -28,7 +29,8 @@ typedef struct { /** * @brief Transmission CAN message structure * - * This structure is used to represent a transmission CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and other relevant parameters. The data payload contains the actual data bytes of the message. + * This structure is used to represent a transmission CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, + * and other relevant parameters. The data payload contains the actual data bytes of the message. * * @warning The length of the data array may be longer than the actual CAN message. */ @@ -41,12 +43,13 @@ typedef struct { typedef struct CubeMXCan_Handle CubeMXCan_Handle; /// @brief Callback function type for receiving CAN messages. @warning Do not call directly, use the provided API functions. -typedef void (*CubeCAN_RxCallback)(void *user_ctx, const CAN_Identifier *identifier, const uint8_t *data, uint8_t size); +typedef void (*CubeCAN_RxCallback)(const void *const user_ctx, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); /** * @brief Configuration structure for CubeMX CAN. * - * This structure is used to configure the CubeMX CAN handle, including the receive callback function and user context. The receive callback function is called when a CAN message is received, and the user context is a pointer to user-defined data that can be passed to the callback function. + * This structure is used to configure the CubeMX CAN handle, including the receive callback function and user context. The receive callback function is called when a CAN message is received, and the + * user context is a pointer to user-defined data that can be passed to the callback function. * * @warning Do not edit after initialization, as it may lead to undefined behavior. */ @@ -63,28 +66,28 @@ typedef struct { * @param config Pointer to the CubeCAN configuration structure. * @return Pointer to the initialized CubeMX CAN handle, or NULL if initialization fails. */ -CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config); +CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); /** * @brief Starts the CubeMX CAN handle, enabling message transmission and reception. * @param handle Pointer to the CubeMX CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle); /** * @brief Stops the CubeMX CAN handle, disabling message transmission and reception. * @param handle Pointer to the CubeMX CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *const handle); /** * @brief Releases the resources associated with the CubeMX CAN handle. * @param handle Pointer to the CubeMX CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *const handle); /** * @brief Adds a filter to the CubeMX CAN handle, allowing for selective message reception based on the specified filter criteria. @@ -92,7 +95,7 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle); * @param filter Pointer to the FDCAN filter configuration structure. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter); +HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *const filter); /** * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. @@ -100,15 +103,7 @@ HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_Filt * @param message Pointer to the GRCAN transmission message structure. * @return HAL_StatusTypeDef if the parameters are non-null or the queue is full. */ -HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message); - -/** - * @brief Converts a Data Length Code (DLC) to the corresponding number of data bytes. - * @param dlc The Data Length Code to be converted. - * @return The number of data bytes corresponding to the given DLC. - * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. - */ -bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *const handle, const GRCAN_TxMessage *const message); /** * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h index 82f36e008..6316e7604 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h @@ -30,7 +30,7 @@ typedef struct { * * @return The constructed 29-bit CAN message extended identifier. */ -uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier); +uint32_t Construct_CAN_Identifier(const CAN_Identifier *const identifier); /** * @brief Deconstructs a 29-bit CAN message extended identifier into its constituent transmitting node ID, receiving node ID, and message ID. @@ -42,11 +42,11 @@ uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier); * @warning The function does not guarantee that the returned structure will represent a valid CAN message identifier. * @warning The function does not support custom IDs. */ -CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id); +CAN_Identifier Deconstruct_CAN_Identifier(const uint32_t message_id); /** * @brief Builds an exact-match extended-ID filter for a given CAN identifier. */ -HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter); +HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const identifier, const uint32_t filter_index, const uint32_t fifo, FDCAN_FilterTypeDef *const filter); #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index bdb91aac0..53decb535 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -22,6 +22,13 @@ */ #define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) +/** + * @brief Rx events mask for FDCAN notifications. + * + * This mask is used to enable notifications for new messages, full FIFO, and message lost events in the FDCAN peripheral. + */ +static const uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; + /** * @brief CubeMX CAN handle structure * @@ -63,20 +70,20 @@ struct CubeMXCan_Handle { * @param handle Pointer to the CubeMX CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle); /** * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. * @param dlc The Data Length Code to be converted. * @return The number of bytes corresponding to the given DLC. */ -uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc); +uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); /** * @brief Callback function for handling received messages from the FDCAN peripheral. This function is called when a message is received in the RX FIFO 0 of the FDCAN peripheral. * @param hfdcan Pointer to the FDCAN handle associated with the received message. */ -void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *hfdcan); +void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *const hfdcan); /** * @brief Array of CubeMX CAN handles, one for each supported instance. @@ -97,6 +104,14 @@ extern bool timer_started; * @param handle Pointer to the CubeMX CAN handle associated with the FDCAN peripheral to be recovered. * @return HAL_StatusTypeDef indicating the success or failure of the recovery operation. */ -HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *const handle); + +/** + * @brief Converts a Data Length Code (DLC) to the corresponding number of data bytes. + * @param dlc The Data Length Code to be converted. + * @return The number of data bytes corresponding to the given DLC. + * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. + */ +bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle); #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c index 93df889de..87440aeb3 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_assert.c +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -8,21 +8,14 @@ #include "Private/PrivateCubeMXCAN.h" #include "main.h" -#pragma region Platform Assertions - static_assert(sizeof(((CubeMXCan_Handle *)0)->tx_head) == sizeof(uint32_t), "tx_head must be 32 bits"); - static_assert(sizeof(GRCAN_TxMessage) == (sizeof(FDCAN_TxHeaderTypeDef) + 64), "GRCAN_TxMessage size is incorrect"); static_assert(_Alignof(GRCAN_TxMessage) >= 4, "GRCAN_TxMessage must have at least 4-byte alignment"); - static_assert(ATOMIC_INT_LOCK_FREE == 2, "ATOMIC_INT_LOCK_FREE must be enabled for atomic operations on tx_head and tx_tail"); -#pragma endregion -#pragma region Configuration Validations - -static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); +static_assert((offsetof(struct CubeMXCan_Handle, tx_head) % 4U) == 0U, "The atomic tx_head is unaligned"); +static_assert((offsetof(struct CubeMXCan_Handle, tx_tail) % 4U) == 0U, "The atomic tx_tail is unaligned"); +static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1U)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "CUBEMX_CAN_MAX_INSTANCES must be configured between 1 and 3 inclusive"); - -#pragma endregion diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 6621bdf0b..77d19f8c9 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -10,7 +10,7 @@ #include "Private/PrivateCubeMXCAN.h" #include "main.h" -CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Config *config) +CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) { if (hfdcan == NULL || config == NULL) { LOGOMATIC("CubeMXCan_Init: invalid null parameters\n"); @@ -42,10 +42,12 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf return NULL; } - uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; if (HAL_FDCAN_ActivateNotification(hfdcan, rx_events, 0U) != HAL_OK) { LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); - memset(handle, 0, sizeof(*handle)); + CRITICAL_SECTION + { + memset(handle, 0, sizeof(*handle)); + } return NULL; } @@ -54,55 +56,71 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, const CubeCAN_Conf HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) { - if (handle == NULL || handle->hfdcan == NULL) { + if (handle == NULL) { return HAL_ERROR; } - if (CubeMXCan_Stop(handle) != HAL_OK) { - LOGOMATIC("CubeMXCan_Release: failed to stop CAN peripheral\n"); - return HAL_ERROR; - } + HAL_StatusTypeDef status = HAL_OK; CRITICAL_SECTION { - memset(handle, 0, sizeof(*handle)); - } + if (handle->hfdcan != NULL) { + status = HAL_FDCAN_Stop(handle->hfdcan); - return HAL_OK; + if (status == HAL_OK) { + status = HAL_FDCAN_DeactivateNotification(handle->hfdcan, rx_events); + } + if (status == HAL_OK) { + memset(handle, 0, sizeof(*handle)); + } else { + LOGOMATIC("CubeMXCan_Release: peripheral deactivation failed\n"); + } + + return status; + } else { + return HAL_ERROR; + } + } } -HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle) { - if (handle == NULL || handle->hfdcan == NULL) { + if (handle == NULL) { return HAL_ERROR; } - if (HAL_FDCAN_Start(handle->hfdcan) != HAL_OK) { - return HAL_ERROR; - } + HAL_StatusTypeDef status = HAL_ERROR; CRITICAL_SECTION { - handle->started = true; + if (handle->hfdcan != NULL && !handle->started) { + status = HAL_FDCAN_Start(handle->hfdcan); + if (status == HAL_OK) { + handle->started = true; + } + } } - return HAL_OK; + return status; } -HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *const handle) { - if (handle == NULL || handle->hfdcan == NULL) { + if (handle == NULL) { return HAL_ERROR; } - if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { - return HAL_ERROR; - } + HAL_StatusTypeDef status = HAL_ERROR; CRITICAL_SECTION { - handle->started = false; + if (handle->hfdcan != NULL && handle->started) { + status = HAL_FDCAN_Stop(handle->hfdcan); + if (status == HAL_OK) { + handle->started = false; + } + } } - return HAL_OK; + return status; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index a786d6c2f..0ebf7676e 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -11,34 +11,53 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { - UNUSED(RxFifo0ITs); + if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) { + LOGOMATIC("WARNING: CAN Rx FIFO is overflowing, messages are being lost!\n"); + } if (hfdcan == NULL) { return; } - CubeMXCan_Handle *handle = NULL; - for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (handles[i].hfdcan == hfdcan) { - handle = &handles[i]; - break; + const void* user_ctx = NULL; + CubeCAN_RxCallback rx_callback = NULL; + bool is_started = false; + + CRITICAL_SECTION + { + for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { + if (handles[i].hfdcan == hfdcan) { + user_ctx = handles[i].config.user_ctx; + rx_callback = handles[i].config.rx_callback; + is_started = handles[i].started; + break; + } } } - if (handle == NULL || handle->config.rx_callback == NULL) { - FDCAN_RxHeaderTypeDef rx_header; - uint8_t rx_data[FDCAN_MAX_DATA_BYTES]; - (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data); - LOGOMATIC("Rx Callback missing for instance\n"); + if (!is_started || rx_callback == NULL) { + FDCAN_RxHeaderTypeDef dump_header; + uint8_t dump_data[FDCAN_MAX_DATA_BYTES]; + + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0U) { + (void)HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &dump_header, dump_data); + } + + LOGOMATIC("HAL_FDCAN_RxFifo0Callback: Message dropped, unmapped handle or instance stopped\n"); return; } FDCAN_RxHeaderTypeDef rx_header; uint8_t rx_data[FDCAN_MAX_DATA_BYTES]; - if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { - CAN_Identifier id = Deconstruct_CAN_Identifier(rx_header.Identifier); - uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); - handle->config.rx_callback(handle->config.user_ctx, &id, rx_data, size); + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0U) { + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { + CAN_Identifier id = Deconstruct_CAN_Identifier(rx_header.Identifier); + uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); + rx_callback(user_ctx, &id, rx_data, size); + } else { + LOGOMATIC("HAL_FDCAN_RxFifo0Callback: Failed to get Rx message from FIFO\n"); + break; + } } } diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index 9346df5b0..2179ffb94 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -39,13 +39,13 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess CRITICAL_SECTION { - uint32_t tail = atomic_load_explicit(&handle->tx_tail, memory_order_relaxed); + const uint32_t tail = atomic_load_explicit(&handle->tx_tail, memory_order_relaxed); uint32_t head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); if ((tail - head) >= CUBEMX_CAN_TX_QUEUE_SIZE) { head++; // Drop oldest message to make room for the new one atomic_store_explicit(&handle->tx_head, head, memory_order_relaxed); - status = HAL_TIMEOUT; + status = HAL_BUSY; } handle->tx_queue[tail & TX_QUEUE_MASK] = *message; @@ -55,23 +55,28 @@ HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMess return status; } -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle) { if (handle == NULL || handle->hfdcan == NULL) { LOGOMATIC("CubeMXCan_Private_SendQueuedMessage: invalid null parameter\n"); return HAL_ERROR; } - uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); - uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_acquire); + if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hfdcan) == 0U) { + LOGOMATIC("CubeMXCan_Private_SendQueuedMessage: Tx FIFO full, cannot send message\n"); + return HAL_BUSY; + } + + const uint32_t current_head = atomic_load_explicit(&handle->tx_head, memory_order_relaxed); + const uint32_t current_tail = atomic_load_explicit(&handle->tx_tail, memory_order_acquire); if (current_head == current_tail) { return HAL_OK; } - GRCAN_TxMessage message_copy = handle->tx_queue[current_head & TX_QUEUE_MASK]; + const GRCAN_TxMessage *const message_ptr = &handle->tx_queue[current_head & TX_QUEUE_MASK]; - if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_copy.tx_header, message_copy.data) != HAL_OK) { + if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_ptr->tx_header, message_ptr->data) != HAL_OK) { return HAL_ERROR; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index c0ff274ef..ef2fd46cf 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -22,25 +22,23 @@ uint32_t Construct_CAN_Identifier(const CAN_Identifier *identifier) return 0U; } - return // Transmitting node - ((uint32_t)(identifier->tx_node_id & CAN_NODE_MASK) << CAN_TX_NODE_SHIFT) - // Message ID - | ((uint32_t)(identifier->msg_id & CAN_MSG_MASK) << CAN_MSG_SHIFT) - // Receiving node - | ((uint32_t)(identifier->rx_node_id & CAN_NODE_MASK) << CAN_RX_NODE_SHIFT); + const uint32_t tx_node_id = identifier->tx_node_id & CAN_NODE_MASK; + const uint32_t msg_id = identifier->msg_id & CAN_MSG_MASK; + const uint32_t rx_node_id = identifier->rx_node_id & CAN_NODE_MASK; + + return (tx_node_id << CAN_TX_NODE_SHIFT) | (msg_id << CAN_MSG_SHIFT) | (rx_node_id << CAN_RX_NODE_SHIFT); } -CAN_Identifier Deconstruct_CAN_Identifier(uint32_t message_id) +CAN_Identifier Deconstruct_CAN_Identifier(const uint32_t message_id) { - return (CAN_Identifier){// Transmitting node - .tx_node_id = (GRCAN_NODE_ID)((message_id >> CAN_TX_NODE_SHIFT) & CAN_NODE_MASK), - // Message ID - .msg_id = (GRCAN_MSG_ID)((message_id >> CAN_MSG_SHIFT) & CAN_MSG_MASK), - // Receiving node - .rx_node_id = (GRCAN_NODE_ID)(message_id >> CAN_RX_NODE_SHIFT) & CAN_NODE_MASK}; + const GRCAN_NODE_ID tx_node_id = (message_id >> CAN_TX_NODE_SHIFT) & CAN_NODE_MASK; + const GRCAN_MSG_ID msg_id = (message_id >> CAN_MSG_SHIFT) & CAN_MSG_MASK; + const GRCAN_NODE_ID rx_node_id = (message_id >> CAN_RX_NODE_SHIFT) & CAN_NODE_MASK; + + return (CAN_Identifier){.tx_node_id = tx_node_id, .msg_id = msg_id, .rx_node_id = rx_node_id}; } -HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifier, uint32_t filter_index, uint32_t fifo, FDCAN_FilterTypeDef *filter) +HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const identifier, const uint32_t filter_index, const uint32_t fifo, FDCAN_FilterTypeDef *const filter) { if (identifier == NULL || filter == NULL) { return HAL_ERROR; @@ -56,64 +54,107 @@ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *identifie return HAL_OK; } -HAL_StatusTypeDef CubeMXCan_AddFilter(CubeMXCan_Handle *handle, const FDCAN_FilterTypeDef *filter) +HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *filter) { - if (handle == NULL || handle->hfdcan == NULL || filter == NULL) { + if (handle == NULL || filter == NULL) { return HAL_ERROR; } - return HAL_FDCAN_ConfigFilter(handle->hfdcan, filter); + HAL_StatusTypeDef status = HAL_ERROR; + + CRITICAL_SECTION + { + if (handle->hfdcan != NULL) { + status = HAL_FDCAN_ConfigFilter(handle->hfdcan, filter); + } + } + + return status; } -uint8_t CubeMXCan_Private_DlcToBytes(uint32_t dlc) +uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc) { - static const uint8_t dlc_to_bytes[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U}; + uint32_t dlc_index = (dlc >> 16U) & 0x0FU; + + if (dlc <= 8U) { + return (uint8_t)dlc; + } + + if (dlc_index == 0U) { + dlc_index = dlc & 0x0FU; + } - static_assert((sizeof(dlc_to_bytes) / sizeof(dlc_to_bytes[0])) == 16, "dlc_to_bytes array must have 16 elements"); + static const uint8_t dlc_to_bytes[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; - return (dlc > 15U) ? 64U : dlc_to_bytes[dlc]; + return (dlc_index > 15U) ? 0U : dlc_to_bytes[dlc_index]; } -bool CubeMXCan_Private_IsDisabled(CubeMXCan_Handle *handle) +bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle) { - if (handle == NULL || handle->hfdcan == NULL) { + if (handle == NULL) { return true; } - HAL_FDCAN_StateTypeDef state = HAL_FDCAN_GetState(handle->hfdcan); - FDCAN_ProtocolStatusTypeDef protocol_status = {0}; + bool disabled = true; - return // HAL states - state == HAL_FDCAN_STATE_ERROR || - state == HAL_FDCAN_STATE_READY - // Check for bus off condition - || (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff); -} + CRITICAL_SECTION + { + if (handle->hfdcan != NULL) { + const HAL_FDCAN_StateTypeDef state = HAL_FDCAN_GetState(handle->hfdcan); + FDCAN_ProtocolStatusTypeDef protocol_status = {0}; -HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(CubeMXCan_Handle *handle) -{ - FDCAN_ProtocolStatusTypeDef protocol_status = {0}; + bool is_bus_off = false; - if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: bus off detected, attempting recovery\n"); + if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK) { + is_bus_off = protocol_status.BusOff; + } - if (HAL_FDCAN_Stop(handle->hfdcan) != HAL_OK) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: failed to stop FDCAN peripheral during bus off recovery\n"); - return HAL_ERROR; + disabled = (state == HAL_FDCAN_STATE_ERROR || state == HAL_FDCAN_STATE_READY || is_bus_off); } + } - HAL_FDCAN_AbortTxRequest(handle->hfdcan, FDCAN_TX_BUFFER0 | FDCAN_TX_BUFFER1 | FDCAN_TX_BUFFER2); + return disabled; +} - if (HAL_FDCAN_Start(handle->hfdcan) != HAL_OK) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: failed to restart FDCAN peripheral during bus off recovery\n"); - return HAL_ERROR; - } +HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *const handle) +{ + if (handle == NULL) { + return HAL_ERROR; } - if (HAL_FDCAN_IsRestrictedOperationMode(handle->hfdcan)) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: currently in restricted operation mode\n"); - HAL_FDCAN_ExitRestrictedOperationMode(handle->hfdcan); + HAL_StatusTypeDef status = HAL_OK; + + CRITICAL_SECTION + { + if (handle->hfdcan != NULL && handle->started) { + FDCAN_ProtocolStatusTypeDef protocol_status = {0}; + + if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff) { + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: CRITICAL BUS-OFF DETECTED. Forcing instant hardware reset...\n"); + + HAL_FDCAN_Stop(handle->hfdcan); + + status = HAL_FDCAN_Init(handle->hfdcan); + + if (status == HAL_OK) { + status = HAL_FDCAN_ActivateNotification(handle->hfdcan, rx_events, 0U); + } + + if (status == HAL_OK) { + status = HAL_FDCAN_Start(handle->hfdcan); + } + + if (status != HAL_OK) { + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: Aggressive hardware start failed!\n"); + } + } + + if (HAL_FDCAN_IsRestrictedOperationMode(handle->hfdcan)) { + LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: Forcing exit from restricted operation mode\n"); + HAL_FDCAN_ExitRestrictedOperationMode(handle->hfdcan); + } + } } - return HAL_OK; + return status; } From acb153bbd7b144371f98e49028fc6f5b509659ef Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 04:15:23 -0700 Subject: [PATCH 33/38] Tweak CUBEMXTESTING to align with new pattern Signed-off-by: Daniel Hansen --- CUBEMXTESTING/Application/Inc/CANdler.h | 8 ++ CUBEMXTESTING/Application/Src/CANdler.c | 9 ++ CUBEMXTESTING/Autogen/Inc/can_cfg.h | 147 ------------------------ CUBEMXTESTING/Core/Inc/tim.h | 35 +++--- CUBEMXTESTING/Core/Src/main.c | 12 +- 5 files changed, 41 insertions(+), 170 deletions(-) create mode 100644 CUBEMXTESTING/Application/Inc/CANdler.h create mode 100644 CUBEMXTESTING/Application/Src/CANdler.c delete mode 100644 CUBEMXTESTING/Autogen/Inc/can_cfg.h diff --git a/CUBEMXTESTING/Application/Inc/CANdler.h b/CUBEMXTESTING/Application/Inc/CANdler.h new file mode 100644 index 000000000..64739c684 --- /dev/null +++ b/CUBEMXTESTING/Application/Inc/CANdler.h @@ -0,0 +1,8 @@ +#include "CubeMXCan.h" + +#ifndef CANDLER_H +#define CANDLER_H + +void CANdler_Callback(CubeMXCan_Handle *const handle, void *const user_ctx); + +#endif diff --git a/CUBEMXTESTING/Application/Src/CANdler.c b/CUBEMXTESTING/Application/Src/CANdler.c new file mode 100644 index 000000000..cfae5c588 --- /dev/null +++ b/CUBEMXTESTING/Application/Src/CANdler.c @@ -0,0 +1,9 @@ +#include "CANdler.h" + +#include "CubeMXCan.h" + +void CANdler_Callback(CubeMXCan_Handle *const handle, void *const user_ctx) +{ + LOGOMATIC("CANdler_Callback: Received CAN message on handle %p with user context %p\n", (void *)handle, user_ctx); + // TODO +} diff --git a/CUBEMXTESTING/Autogen/Inc/can_cfg.h b/CUBEMXTESTING/Autogen/Inc/can_cfg.h deleted file mode 100644 index 0c6609c06..000000000 --- a/CUBEMXTESTING/Autogen/Inc/can_cfg.h +++ /dev/null @@ -1,147 +0,0 @@ - -#ifndef CAN_CFG_H -#define CAN_CFG_H - -/* Generated automatically by STM32CubeMX FreeMarker. */ - -/* - * User-editable CAN runtime configuration. - * - * CAN_TIMER_INDEX: - * Selects the CubeMX-generated timer handle. Example: 5 selects htim5. - * - * CAN_TIMER_TICK_US: - * Duration of one timer counter tick, determined by the CubeMX prescaler. - * For a 160 MHz TIM clock and Prescaler = 15999, one tick is 100 us. - * - * CAN_DEQUEUE_PERIOD_US: - * Time between attempts to dequeue and send one software-queued CAN message. - */ -/* USER CODE BEGIN CAN_USER_CONFIG */ - -#ifndef TX_BUFFER_1_SIZE -#define TX_BUFFER_1_SIZE 20U -#endif - -#ifndef TX_BUFFER_2_SIZE -#define TX_BUFFER_2_SIZE 20U -#endif - -#ifndef TX_BUFFER_3_SIZE -#define TX_BUFFER_3_SIZE 20U -#endif - -#ifndef CAN_TIMER_INDEX -#define CAN_TIMER_INDEX 5 -#endif - -#ifndef CAN_TIMER_TICK_US -#define CAN_TIMER_TICK_US 100U -#endif - -#ifndef CAN_DEQUEUE_PERIOD_US -#define CAN_DEQUEUE_PERIOD_US 500U -#endif - -/* USER CODE END CAN_USER_CONFIG */ - -/* Enabled FDCAN peripherals. */ - -#define USECAN1 - -#define USECAN2 - -#define USECAN3 - -/* Timers enabled in CubeMX. */ - -#define CUBEMX_HAS_TIM5 - -/* Configuration validation. */ - -#if defined(USECAN1) && (TX_BUFFER_1_SIZE == 0U) -#error "TX_BUFFER_1_SIZE must be greater than zero" -#endif - -#if defined(USECAN2) && (TX_BUFFER_2_SIZE == 0U) -#error "TX_BUFFER_2_SIZE must be greater than zero" -#endif - -#if defined(USECAN3) && (TX_BUFFER_3_SIZE == 0U) -#error "TX_BUFFER_3_SIZE must be greater than zero" -#endif - -#if CAN_TIMER_TICK_US == 0U -#error "CAN_TIMER_TICK_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US == 0U -#error "CAN_DEQUEUE_PERIOD_US must be greater than zero" -#endif - -#if CAN_DEQUEUE_PERIOD_US < CAN_TIMER_TICK_US -#error "CAN_DEQUEUE_PERIOD_US cannot be shorter than one timer tick" -#endif - -#if (CAN_DEQUEUE_PERIOD_US % CAN_TIMER_TICK_US) != 0U -#error "CAN_DEQUEUE_PERIOD_US must be divisible by CAN_TIMER_TICK_US" -#endif - -#if ((CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - 1U) > 0xFFFFFFFFU -#error "CAN dequeue period exceeds the supported timer auto-reload range" -#endif - -#if (CAN_TIMER_INDEX == 1) && !defined(CUBEMX_HAS_TIM1) -#error "CAN_TIMER_INDEX selects TIM1, but TIM1 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 2) && !defined(CUBEMX_HAS_TIM2) -#error "CAN_TIMER_INDEX selects TIM2, but TIM2 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 3) && !defined(CUBEMX_HAS_TIM3) -#error "CAN_TIMER_INDEX selects TIM3, but TIM3 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 4) && !defined(CUBEMX_HAS_TIM4) -#error "CAN_TIMER_INDEX selects TIM4, but TIM4 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 5) && !defined(CUBEMX_HAS_TIM5) -#error "CAN_TIMER_INDEX selects TIM5, but TIM5 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 6) && !defined(CUBEMX_HAS_TIM6) -#error "CAN_TIMER_INDEX selects TIM6, but TIM6 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 7) && !defined(CUBEMX_HAS_TIM7) -#error "CAN_TIMER_INDEX selects TIM7, but TIM7 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 8) && !defined(CUBEMX_HAS_TIM8) -#error "CAN_TIMER_INDEX selects TIM8, but TIM8 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 15) && !defined(CUBEMX_HAS_TIM15) -#error "CAN_TIMER_INDEX selects TIM15, but TIM15 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 16) && !defined(CUBEMX_HAS_TIM16) -#error "CAN_TIMER_INDEX selects TIM16, but TIM16 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX == 17) && !defined(CUBEMX_HAS_TIM17) -#error "CAN_TIMER_INDEX selects TIM17, but TIM17 is not enabled in CubeMX" -#elif (CAN_TIMER_INDEX != 1) && \ - (CAN_TIMER_INDEX != 2) && \ - (CAN_TIMER_INDEX != 3) && \ - (CAN_TIMER_INDEX != 4) && \ - (CAN_TIMER_INDEX != 5) && \ - (CAN_TIMER_INDEX != 6) && \ - (CAN_TIMER_INDEX != 7) && \ - (CAN_TIMER_INDEX != 8) && \ - (CAN_TIMER_INDEX != 15) && \ - (CAN_TIMER_INDEX != 16) && \ - (CAN_TIMER_INDEX != 17) -#error "CAN_TIMER_INDEX selects an unsupported timer" -#endif - -#define CAN_TIMER_PERIOD_COUNTS \ - (CAN_DEQUEUE_PERIOD_US / CAN_TIMER_TICK_US) - -#define CAN_TIMER_AUTORELOAD \ - (CAN_TIMER_PERIOD_COUNTS - 1U) - -/* - * Convert CAN_TIMER_INDEX into CubeMX's generated HAL timer handle. - * - * CAN_TIMER_INDEX = 5 - * CAN_TIMER_HANDLE = htim5 - */ -#define CAN_CFG_JOIN_INNER(a, b) a##b -#define CAN_CFG_JOIN(a, b) CAN_CFG_JOIN_INNER(a, b) -#define CAN_TIMER_HANDLE CAN_CFG_JOIN(htim, CAN_TIMER_INDEX) - -#endif /* CAN_CFG_H */ - diff --git a/CUBEMXTESTING/Core/Inc/tim.h b/CUBEMXTESTING/Core/Inc/tim.h index 18374feb3..2d20bd560 100644 --- a/CUBEMXTESTING/Core/Inc/tim.h +++ b/CUBEMXTESTING/Core/Inc/tim.h @@ -1,21 +1,21 @@ /* USER CODE BEGIN Header */ /** - ****************************************************************************** - * @file tim.h - * @brief This file contains all the function prototypes for - * the tim.c file - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ + ****************************************************************************** + * @file tim.h + * @brief This file contains all the function prototypes for + * the tim.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __TIM_H__ @@ -35,7 +35,7 @@ extern "C" { extern TIM_HandleTypeDef htim5; /* USER CODE BEGIN Private defines */ - +#define CAN_TIMER_HANDLE htim5 /* USER CODE END Private defines */ void MX_TIM5_Init(void); @@ -49,4 +49,3 @@ void MX_TIM5_Init(void); #endif #endif /* __TIM_H__ */ - diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index ae2deaf7b..9f6e59804 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -25,8 +25,12 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include "CANdler.h" +#include "CubeMXCan.h" +#include "CubeMXCanExt.h" #include "Logomatic.h" #include "loop.h" +#include "tim.h" #include "vcp.h" // #include "can.h" @@ -128,11 +132,9 @@ int main(void) Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); - GR_CAN_Init(); + CubeCAN_Config can_config = {.rx_callback = CANdler_Callback, .user_ctx = (void *)1}; - if (CAN_Timer_Start() != HAL_OK) { - Error_Handler(); - } + CubeMXCan_Init(&hfdcan1, &can_config); /* USER CODE END 2 */ /* Infinite loop */ @@ -197,7 +199,7 @@ void SystemClock_Config(void) void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &CAN_TIMER_HANDLE) { - CAN_Timer_Tick(); + CubeMXCan_Tick(); } } From ba4bc5cc3c769eaf2be4b914612cec7f64aab5a1 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 04:29:23 -0700 Subject: [PATCH 34/38] Add helper oneshot functions, harden init Signed-off-by: Daniel Hansen --- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 18 ++++ Lib/Peripherals/CubeCAN/Src/can_init.c | 132 +++++++++++++++++++----- 2 files changed, 126 insertions(+), 24 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 91ed9f493..06206875b 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -60,6 +60,24 @@ typedef struct { void *user_ctx; } CubeCAN_Config; +/** + * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration, and starts the CAN peripheral. + * @param hfdcan Pointer to the FDCAN handle. + * @param config Pointer to the CubeCAN configuration structure. + * @return Pointer to the initialized CubeMX CAN handle, or NULL if initialization fails. + * @note This functions wraps CubeMXCan_Init and CubeMXCan_Start into a single call. If either of those functions fails, this function will return NULL and the handle will be released. + */ +CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); + +/** + * @brief Stops the CubeMX CAN peripheral and releases the associated handle. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + * @note This functions wraps CubeMXCan_Stop and CubeMXCan_Release into a single call. If either of those functions fails, this function will return the error code and the handle will not be released. + * @note This function can be used regardless of if CubeMXCan_OneShotInitStart was used to initialize the handle. +*/ +HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle); + /** * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration. * @param hfdcan Pointer to the FDCAN handle. diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 77d19f8c9..f8af80ca2 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -10,6 +10,41 @@ #include "Private/PrivateCubeMXCAN.h" #include "main.h" +CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) +{ + CubeMXCan_Handle *handle = CubeMXCan_Init(hfdcan, config); + + if (handle == NULL) { + LOGOMATIC("CubeMXCan_OneShotInit: failed to initialize handle\n"); + return NULL; + } + + if (CubeMXCan_Start(handle) != HAL_OK) { + LOGOMATIC("CubeMXCan_OneShotInit: failed to start handle\n"); + CubeMXCan_Release(handle); + return NULL; + } + + return handle; +} + +HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle) +{ + if (handle == NULL) { + LOGOMATIC("CubeMXCan_OneShotReleaseStop: invalid null parameter\n"); + return NULL; + } + + HAL_StatusTypeDef status = CubeMXCan_Stop(handle); + + if (status != HAL_OK) { + LOGOMATIC("CubeMXCan_OneShotReleaseStop: failed to stop FDCAN instance\n"); + return status; + } + + return CubeMXCan_Release(handle); +} + CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) { if (hfdcan == NULL || config == NULL) { @@ -18,16 +53,24 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *co } CubeMXCan_Handle *handle = NULL; + uint8_t free_handle_index = (uint8_t)-1; + CRITICAL_SECTION { for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - if (handles[i].hfdcan == hfdcan || handles[i].hfdcan == NULL) { + if (handles[i].hfdcan == hfdcan) { handle = &handles[i]; break; + } else if (handles[i].hfdcan == NULL && free_handle_index == (uint8_t)-1) { + free_handle_index = i; } } if (handle != NULL) { + LOGOMATIC("CubeMXCan_Init: handle already initialized for this FDCAN instance\n"); + return NULL; + } else if (free_handle_index != (uint8_t)-1) { + handle = &handles[free_handle_index]; memset(handle, 0, sizeof(*handle)); handle->hfdcan = hfdcan; handle->config = *config; @@ -60,27 +103,44 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) return HAL_ERROR; } - HAL_StatusTypeDef status = HAL_OK; + FDCAN_HandleTypeDef *hfdcan_to_stop = NULL; CRITICAL_SECTION { if (handle->hfdcan != NULL) { - status = HAL_FDCAN_Stop(handle->hfdcan); + hfdcan_to_stop = handle->hfdcan; + handle->hfdcan = NULL; + handle->started = false; + } + } - if (status == HAL_OK) { - status = HAL_FDCAN_DeactivateNotification(handle->hfdcan, rx_events); - } - if (status == HAL_OK) { - memset(handle, 0, sizeof(*handle)); - } else { - LOGOMATIC("CubeMXCan_Release: peripheral deactivation failed\n"); - } + if (hfdcan_to_stop == NULL) { + return HAL_ERROR; + } - return status; - } else { - return HAL_ERROR; + HAL_StatusTypeDef status = HAL_FDCAN_Stop(hfdcan_to_stop); + + if (status == HAL_OK) { + status = HAL_FDCAN_DeactivateNotification(hfdcan_to_stop, rx_events); + } + + if (status != HAL_OK) { + LOGOMATIC("CubeMXCan_Release: peripheral deactivation failed\n"); + + CRITICAL_SECTION + { + handle->hfdcan = hfdcan_to_stop; } + + return status; + } + + CRITICAL_SECTION + { + memset(handle, 0, sizeof(*handle)); } + + return HAL_OK; } HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle) @@ -89,15 +149,27 @@ HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle) return HAL_ERROR; } - HAL_StatusTypeDef status = HAL_ERROR; + bool dynamic_start = false; + FDCAN_HandleTypeDef *hfdcan = NULL; CRITICAL_SECTION { if (handle->hfdcan != NULL && !handle->started) { - status = HAL_FDCAN_Start(handle->hfdcan); - if (status == HAL_OK) { - handle->started = true; - } + hfdcan = handle->hfdcan; + dynamic_start = true; + } + } + + if (!dynamic_start) { + return HAL_ERROR; + } + + HAL_StatusTypeDef status = HAL_FDCAN_Start(hfdcan); + + if (status == HAL_OK) { + CRITICAL_SECTION + { + handle->started = true; } } @@ -110,15 +182,27 @@ HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *const handle) return HAL_ERROR; } - HAL_StatusTypeDef status = HAL_ERROR; + bool dynamic_stop = false; + FDCAN_HandleTypeDef *hfdcan = NULL; CRITICAL_SECTION { if (handle->hfdcan != NULL && handle->started) { - status = HAL_FDCAN_Stop(handle->hfdcan); - if (status == HAL_OK) { - handle->started = false; - } + hfdcan = handle->hfdcan; + dynamic_stop = true; + } + } + + if (!dynamic_stop) { + return HAL_ERROR; + } + + HAL_StatusTypeDef status = HAL_FDCAN_Stop(hfdcan); + + if (status == HAL_OK) { + CRITICAL_SECTION + { + handle->started = false; } } From 01e6db37b7b0772bcf09b84bd1087d1c9e1cb694 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 05:43:40 -0700 Subject: [PATCH 35/38] So much peripheral lockdown Signed-off-by: Daniel Hansen --- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 63 +++++-------- .../CubeCAN/Inc/Private/PrivateCubeMXCAN.h | 59 ++++++++---- Lib/Peripherals/CubeCAN/Src/can_assert.c | 16 ++-- Lib/Peripherals/CubeCAN/Src/can_global.c | 2 +- Lib/Peripherals/CubeCAN/Src/can_init.c | 6 +- Lib/Peripherals/CubeCAN/Src/can_rx.c | 6 +- Lib/Peripherals/CubeCAN/Src/can_tx.c | 55 +++++++++++- Lib/Peripherals/CubeCAN/Src/can_utils.c | 90 ++++++++++++++++--- 8 files changed, 211 insertions(+), 86 deletions(-) diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index 06206875b..efb93091e 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -11,39 +11,11 @@ #define FDCAN_MAX_DATA_BYTES 64U -/** - * @brief Received CAN message structure - * - * This structure is used to represent a received CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, and - * other relevant parameters. The data payload contains the actual data bytes of the message. - * - * @warning The length of the data array may be longer than the actual CAN message. - */ -typedef struct { - /// @brief The header of the received CAN message, containing information such as the identifier, data length, and other relevant parameters. - FDCAN_RxHeaderTypeDef rx_header; - /// @brief The data payload of the received CAN message, containing the actual data bytes of the message. The length of this array may be longer than the actual CAN message. - uint8_t data[FDCAN_MAX_DATA_BYTES]; -} GRCAN_RxMessage; - -/** - * @brief Transmission CAN message structure - * - * This structure is used to represent a transmission CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, - * and other relevant parameters. The data payload contains the actual data bytes of the message. - * - * @warning The length of the data array may be longer than the actual CAN message. - */ -typedef struct { - FDCAN_TxHeaderTypeDef tx_header; - uint8_t data[FDCAN_MAX_DATA_BYTES]; -} GRCAN_TxMessage; - /// @brief CAN handle for CubeMX CAN. @warning Do not access directly, use the provided API functions. -typedef struct CubeMXCan_Handle CubeMXCan_Handle; +typedef struct CubeMXCan_Private_Handle CubeMXCan_Handle; /// @brief Callback function type for receiving CAN messages. @warning Do not call directly, use the provided API functions. -typedef void (*CubeCAN_RxCallback)(const void *const user_ctx, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); +typedef void (*CubeCAN_RxCallback)(const void *const user_context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); /** * @brief Configuration structure for CubeMX CAN. @@ -54,10 +26,12 @@ typedef void (*CubeCAN_RxCallback)(const void *const user_ctx, const CAN_Identif * @warning Do not edit after initialization, as it may lead to undefined behavior. */ typedef struct { + /// @brief User-defined context pointer that can be passed to the receive callback function. This can be used to pass additional data or state information to the callback function. + void *user_context; /// @brief Callback function for receiving CAN messages. This function is called when a CAN message is received. CubeCAN_RxCallback rx_callback; - /// @brief User-defined context pointer that can be passed to the receive callback function. This can be used to pass additional data or state information to the callback function. - void *user_ctx; + /// @brief Node ID of the sending device. This is used to identify the source of the CAN messages and must be unique on the CAN bus. + GRCAN_NODE_ID sending_node_id; } CubeCAN_Config; /** @@ -73,9 +47,10 @@ CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCA * @brief Stops the CubeMX CAN peripheral and releases the associated handle. * @param handle Pointer to the CubeMX CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. - * @note This functions wraps CubeMXCan_Stop and CubeMXCan_Release into a single call. If either of those functions fails, this function will return the error code and the handle will not be released. + * @note This functions wraps CubeMXCan_Stop and CubeMXCan_Release into a single call. If either of those functions fails, this function will return the error code and the handle will + * not be released. * @note This function can be used regardless of if CubeMXCan_OneShotInitStart was used to initialize the handle. -*/ + */ HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle); /** @@ -115,18 +90,22 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *const handle); */ HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *const filter); -/** - * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. - * @param handle Pointer to the CubeMX CAN handle. - * @param message Pointer to the GRCAN transmission message structure. - * @return HAL_StatusTypeDef if the parameters are non-null or the queue is full. - */ -HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *const handle, const GRCAN_TxMessage *const message); - /** * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. * @warning This function sends one can message per configured bus per call. Not calling it will simply not send any messages. */ void CubeMXCan_Tick(void); +/** + * @brief Sends a CAN message using the CubeMX CAN handle, with the specified receive node, message ID, data payload, and size. + * @param handle Pointer to the CubeMX CAN handle. + * @param rx_node The receive node identifier for the message. + * @param msg_id The message ID for the message. + * @param data Pointer to the data payload of the message. + * @param size The size of the data payload in bytes. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + * @note The size of the data payload must not exceed FDCAN_MAX_DATA_BYTES (64 bytes). If the size exceeds this limit, the function will return HAL_ERROR. + */ +HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size); + #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h index 53decb535..6b56924fd 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h @@ -3,7 +3,6 @@ #include #include "CubeCAN_Config.h" -#include "CubeMXCan.h" #include "Logomatic.h" #include "Stringification.h" #include "fdcan.h" @@ -27,7 +26,20 @@ * * This mask is used to enable notifications for new messages, full FIFO, and message lost events in the FDCAN peripheral. */ -static const uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST; +#define FDCAN_IT_RX_EVENTS (FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST) + +/** + * @brief Transmission CAN message structure + * + * This structure is used to represent a transmission CAN message, which consists of a header and data payload. The header contains information about the message, such as its identifier, data length, + * and other relevant parameters. The data payload contains the actual data bytes of the message. + * + * @warning The length of the data array may be longer than the actual CAN message. + */ +typedef struct { + FDCAN_TxHeaderTypeDef tx_header; + uint8_t data[FDCAN_MAX_DATA_BYTES]; +} GRCAN_Private_TxMessage; /** * @brief CubeMX CAN handle structure @@ -37,13 +49,13 @@ static const uint32_t rx_events = FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FI * @warning Use the provided API functions to interact with the CubeMX CAN handle. * @warning The structure is intended for internal use only and should not be accessed directly by user code. */ -struct CubeMXCan_Handle { +struct CubeMXCan_Private_Handle { /// @brief Pointer to the FDCAN handle associated with this CubeMX CAN handle. FDCAN_HandleTypeDef *hfdcan; /// @brief Configuration structure for the CubeMX CAN handle, containing the receive callback and user context. CubeCAN_Config config; /// @brief Transmission queue for the CubeMX CAN handle, containing the messages to be transmitted. - GRCAN_TxMessage tx_queue[CUBEMX_CAN_TX_QUEUE_SIZE]; + GRCAN_Private_TxMessage tx_queue[CUBEMX_CAN_TX_QUEUE_SIZE]; /// @brief Atomic head index for the transmission queue, indicating the next message to be transmitted. _Atomic uint32_t tx_head; /// @brief Atomic tail index for the transmission queue, indicating the next available slot for a new message. @@ -72,24 +84,11 @@ struct CubeMXCan_Handle { */ HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle); -/** - * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. - * @param dlc The Data Length Code to be converted. - * @return The number of bytes corresponding to the given DLC. - */ -uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); - -/** - * @brief Callback function for handling received messages from the FDCAN peripheral. This function is called when a message is received in the RX FIFO 0 of the FDCAN peripheral. - * @param hfdcan Pointer to the FDCAN handle associated with the received message. - */ -void CubeMXCan_OnRxFifo0(FDCAN_HandleTypeDef *const hfdcan); - /** * @brief Array of CubeMX CAN handles, one for each supported instance. * @note The number of instances is defined by CUBEMX_CAN_MAX_INSTANCES. */ -extern struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; +extern struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; /** * @brief Flag indicating whether the CubeMX CAN Tx timer has been started. @@ -114,4 +113,28 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *co */ bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle); +/** + * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. + * @param handle Pointer to the CubeMX CAN handle. + * @param message Pointer to the GRCAN transmission message structure. + * @return HAL_StatusTypeDef if the parameters are non-null or the queue is full. + */ +HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *const handle, const GRCAN_Private_TxMessage *const message); + +/** + * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. + * @param dlc The Data Length Code to be converted. + * @return The number of bytes corresponding to the given DLC. + * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. + */ +uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); + +/** + * @brief Converts a number of bytes to the corresponding Data Length Code (DLC). + * @param bytes The number of bytes to be converted. + * @return The Data Length Code corresponding to the given number of bytes. + * @warning The number of bytes must be between 0 and 8, inclusive. Values outside this range will result in undefined behavior. + */ +uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes); + #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c index 87440aeb3..594c6ca4e 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_assert.c +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include "CriticalSection.h" #include "CubeCAN_Config.h" @@ -8,14 +10,18 @@ #include "Private/PrivateCubeMXCAN.h" #include "main.h" -static_assert(sizeof(((CubeMXCan_Handle *)0)->tx_head) == sizeof(uint32_t), "tx_head must be 32 bits"); -static_assert(sizeof(GRCAN_TxMessage) == (sizeof(FDCAN_TxHeaderTypeDef) + 64), "GRCAN_TxMessage size is incorrect"); +static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_head) == sizeof(uint32_t), "tx_head must be 32 bits"); +static_assert(sizeof(GRCAN_Private_TxMessage) == (sizeof(FDCAN_TxHeaderTypeDef) + 64), "GRCAN_Private_TxMessage size is incorrect"); -static_assert(_Alignof(GRCAN_TxMessage) >= 4, "GRCAN_TxMessage must have at least 4-byte alignment"); +static_assert(alignof(GRCAN_Private_TxMessage) >= 4, "GRCAN_Private_TxMessage must have at least 4-byte alignment"); static_assert(ATOMIC_INT_LOCK_FREE == 2, "ATOMIC_INT_LOCK_FREE must be enabled for atomic operations on tx_head and tx_tail"); -static_assert((offsetof(struct CubeMXCan_Handle, tx_head) % 4U) == 0U, "The atomic tx_head is unaligned"); -static_assert((offsetof(struct CubeMXCan_Handle, tx_tail) % 4U) == 0U, "The atomic tx_tail is unaligned"); +static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_head) % 4U) == 0U, "The atomic tx_head is unaligned"); +static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_tail) % 4U) == 0U, "The atomic tx_tail is unaligned"); static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1U)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "CUBEMX_CAN_MAX_INSTANCES must be configured between 1 and 3 inclusive"); + +#ifndef CUBEMX_SENDING_NODE_ID +#error "CUBEMX_SENDING_NODE_ID must be defined in CubeCAN_Config.h. This is the node ID of the sending device and must be unique on the CAN bus." +#endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_global.c b/Lib/Peripherals/CubeCAN/Src/can_global.c index 71f39ff0a..20b10badf 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_global.c +++ b/Lib/Peripherals/CubeCAN/Src/can_global.c @@ -7,5 +7,5 @@ #include "CubeMXCanExt.h" #include "Private/PrivateCubeMXCAN.h" -struct CubeMXCan_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; +struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; bool timer_started = false; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index f8af80ca2..f82cd5a20 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -32,7 +32,7 @@ HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle) { if (handle == NULL) { LOGOMATIC("CubeMXCan_OneShotReleaseStop: invalid null parameter\n"); - return NULL; + return HAL_ERROR; } HAL_StatusTypeDef status = CubeMXCan_Stop(handle); @@ -85,7 +85,7 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *co return NULL; } - if (HAL_FDCAN_ActivateNotification(hfdcan, rx_events, 0U) != HAL_OK) { + if (HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_EVENTS, 0U) != HAL_OK) { LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); CRITICAL_SECTION { @@ -121,7 +121,7 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) HAL_StatusTypeDef status = HAL_FDCAN_Stop(hfdcan_to_stop); if (status == HAL_OK) { - status = HAL_FDCAN_DeactivateNotification(hfdcan_to_stop, rx_events); + status = HAL_FDCAN_DeactivateNotification(hfdcan_to_stop, FDCAN_IT_RX_EVENTS); } if (status != HAL_OK) { diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index 0ebf7676e..47f908973 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -19,7 +19,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) return; } - const void* user_ctx = NULL; + const void *user_context = NULL; CubeCAN_RxCallback rx_callback = NULL; bool is_started = false; @@ -27,7 +27,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { if (handles[i].hfdcan == hfdcan) { - user_ctx = handles[i].config.user_ctx; + user_context = handles[i].config.user_context; rx_callback = handles[i].config.rx_callback; is_started = handles[i].started; break; @@ -54,7 +54,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { CAN_Identifier id = Deconstruct_CAN_Identifier(rx_header.Identifier); uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); - rx_callback(user_ctx, &id, rx_data, size); + rx_callback(user_context, &id, rx_data, size); } else { LOGOMATIC("HAL_FDCAN_RxFifo0Callback: Failed to get Rx message from FIFO\n"); break; diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index 2179ffb94..012911a3c 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -1,5 +1,6 @@ #include #include +#include #include "CriticalSection.h" #include "CubeMXCan.h" @@ -29,7 +30,57 @@ void CubeMXCan_Tick(void) } } -HAL_StatusTypeDef CubeMXCan_QueueTx(CubeMXCan_Handle *handle, const GRCAN_TxMessage *message) +HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size) +{ + if (handle == NULL || data == NULL || size > FDCAN_MAX_DATA_BYTES) { + return HAL_ERROR; + } + + const uint32_t dlc = CubeMXCan_Private_BytesToDlc(size); + if (dlc == FDCAN_DLC_BYTES_0 && size != 0) { + LOGOMATIC("CubeMXCan_Send: invalid data length code\n"); + return HAL_ERROR; + } + + uint32_t fdformat = 0; + uint32_t brs = 0; + switch (handle->hfdcan->Init.FrameFormat) { + case FDCAN_FRAME_CLASSIC: + fdformat = FDCAN_CLASSIC_CAN; + brs = FDCAN_BRS_OFF; + break; + case FDCAN_FRAME_FD_NO_BRS: + fdformat = FDCAN_FD_CAN; + brs = FDCAN_BRS_OFF; + break; + case FDCAN_FRAME_FD_BRS: + fdformat = FDCAN_FD_CAN; + brs = FDCAN_BRS_ON; + break; + default: + LOGOMATIC("CubeMXCan_Send: unsupported frame format\n"); + return HAL_ERROR; + } + + const CAN_Identifier identifier_struct = {.tx_node_id = handle->config.sending_node_id, .rx_node_id = rx_node, .msg_id = msg_id}; + + const FDCAN_TxHeaderTypeDef header = {.BitRateSwitch = brs, + .DataLength = CubeMXCan_Private_BytesToDlc(size), + .ErrorStateIndicator = FDCAN_ESI_ACTIVE, + .FDFormat = fdformat, + .Identifier = Construct_CAN_Identifier(&identifier_struct), + .IdType = FDCAN_EXTENDED_ID, + .MessageMarker = 0U, // TODO We can do cool things with this to track transmission queue statistics + .TxEventFifoControl = FDCAN_NO_TX_EVENTS, + .TxFrameType = FDCAN_DATA_FRAME}; + + GRCAN_Private_TxMessage message = {.tx_header = header}; + memcpy(message.data, data, size); + + return CubeMXCan_Private_QueueTx(handle, &message); +} + +HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *handle, const GRCAN_Private_TxMessage *message) { if (handle == NULL || message == NULL) { return HAL_ERROR; @@ -74,7 +125,7 @@ HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *co return HAL_OK; } - const GRCAN_TxMessage *const message_ptr = &handle->tx_queue[current_head & TX_QUEUE_MASK]; + const GRCAN_Private_TxMessage *const message_ptr = &handle->tx_queue[current_head & TX_QUEUE_MASK]; if (HAL_FDCAN_AddMessageToTxFifoQ(handle->hfdcan, &message_ptr->tx_header, message_ptr->data) != HAL_OK) { return HAL_ERROR; diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index ef2fd46cf..17feaf007 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -57,6 +57,7 @@ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const ide HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *filter) { if (handle == NULL || filter == NULL) { + LOGOMATIC("CubeMXCan_AddFilter: Invalid handle or filter pointer\n"); return HAL_ERROR; } @@ -72,21 +73,86 @@ HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, cons return status; } -uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc) +uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes) { - uint32_t dlc_index = (dlc >> 16U) & 0x0FU; - - if (dlc <= 8U) { - return (uint8_t)dlc; + switch (bytes) { + case 0U: + return FDCAN_DLC_BYTES_0; + case 1U: + return FDCAN_DLC_BYTES_1; + case 2U: + return FDCAN_DLC_BYTES_2; + case 3U: + return FDCAN_DLC_BYTES_3; + case 4U: + return FDCAN_DLC_BYTES_4; + case 5U: + return FDCAN_DLC_BYTES_5; + case 6U: + return FDCAN_DLC_BYTES_6; + case 7U: + return FDCAN_DLC_BYTES_7; + case 8U: + return FDCAN_DLC_BYTES_8; + case 12U: + return FDCAN_DLC_BYTES_12; + case 16U: + return FDCAN_DLC_BYTES_16; + case 20U: + return FDCAN_DLC_BYTES_20; + case 24U: + return FDCAN_DLC_BYTES_24; + case 32U: + return FDCAN_DLC_BYTES_32; + case 48U: + return FDCAN_DLC_BYTES_48; + case 64U: + return FDCAN_DLC_BYTES_64; + default: + LOGOMATIC("CubeMXCan_Private_BytesToDlc: Invalid byte count\n"); + return FDCAN_DLC_BYTES_0; } +} - if (dlc_index == 0U) { - dlc_index = dlc & 0x0FU; +uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc) +{ + switch (dlc) { + case FDCAN_DLC_BYTES_0: + return 0U; + case FDCAN_DLC_BYTES_1: + return 1U; + case FDCAN_DLC_BYTES_2: + return 2U; + case FDCAN_DLC_BYTES_3: + return 3U; + case FDCAN_DLC_BYTES_4: + return 4U; + case FDCAN_DLC_BYTES_5: + return 5U; + case FDCAN_DLC_BYTES_6: + return 6U; + case FDCAN_DLC_BYTES_7: + return 7U; + case FDCAN_DLC_BYTES_8: + return 8U; + case FDCAN_DLC_BYTES_12: + return 12U; + case FDCAN_DLC_BYTES_16: + return 16U; + case FDCAN_DLC_BYTES_20: + return 20U; + case FDCAN_DLC_BYTES_24: + return 24U; + case FDCAN_DLC_BYTES_32: + return 32U; + case FDCAN_DLC_BYTES_48: + return 48U; + case FDCAN_DLC_BYTES_64: + return 64U; + default: + LOGOMATIC("CubeMXCan_Private_DlcToBytes: Invalid DLC value\n"); + return 0U; } - - static const uint8_t dlc_to_bytes[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; - - return (dlc_index > 15U) ? 0U : dlc_to_bytes[dlc_index]; } bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle) @@ -137,7 +203,7 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *co status = HAL_FDCAN_Init(handle->hfdcan); if (status == HAL_OK) { - status = HAL_FDCAN_ActivateNotification(handle->hfdcan, rx_events, 0U); + status = HAL_FDCAN_ActivateNotification(handle->hfdcan, FDCAN_IT_RX_EVENTS, 0U); } if (status == HAL_OK) { From 30de6e532c22e9d6d03dfb521666056ddbcf69a4 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 06:10:04 -0700 Subject: [PATCH 36/38] Reorganize ownership patterns, finalize api Signed-off-by: Daniel Hansen --- CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c | 85 ------------------- Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h | 53 +++++++++++- Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h | 52 ------------ .../PrivateInc/internal.h} | 64 +++++++++----- Lib/Peripherals/CubeCAN/Src/can_assert.c | 28 +++--- Lib/Peripherals/CubeCAN/Src/can_global.c | 4 +- Lib/Peripherals/CubeCAN/Src/can_init.c | 3 +- Lib/Peripherals/CubeCAN/Src/can_rx.c | 3 +- Lib/Peripherals/CubeCAN/Src/can_tx.c | 3 +- Lib/Peripherals/CubeCAN/Src/can_utils.c | 3 +- 10 files changed, 117 insertions(+), 181 deletions(-) delete mode 100644 CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c delete mode 100644 Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h rename Lib/Peripherals/CubeCAN/{Inc/Private/PrivateCubeMXCAN.h => Src/PrivateInc/internal.h} (87%) diff --git a/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c b/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c deleted file mode 100644 index d908bd772..000000000 --- a/CUBEMXTESTING/Core/Src/stm32g4xx_hal_msp.c +++ /dev/null @@ -1,85 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32g4xx_hal_msp.c - * @brief This file provides code for the MSP Initialization - * and de-Initialization codes. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN Define */ - -/* USER CODE END Define */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN Macro */ - -/* USER CODE END Macro */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* External functions --------------------------------------------------------*/ -/* USER CODE BEGIN ExternalFunctions */ - -/* USER CODE END ExternalFunctions */ - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ -/** - * Initializes the Global MSP. - */ -void HAL_MspInit(void) -{ - - /* USER CODE BEGIN MspInit 0 */ - - /* USER CODE END MspInit 0 */ - - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - /* System interrupt init*/ - - /** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral - */ - HAL_PWREx_DisableUCPDDeadBattery(); - - /* USER CODE BEGIN MspInit 1 */ - - /* USER CODE END MspInit 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h index efb93091e..b4adc3595 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h @@ -3,13 +3,15 @@ #include #include "CubeCAN_Config.h" -#include "CubeMXCanExt.h" +#include "GRCAN_CUSTOM_ID.h" +#include "GRCAN_MSG_ID.h" +#include "GRCAN_NODE_ID.h" #include "main.h" #ifndef CUBEMX_CAN_H #define CUBEMX_CAN_H -#define FDCAN_MAX_DATA_BYTES 64U +#pragma region Type Definitions /// @brief CAN handle for CubeMX CAN. @warning Do not access directly, use the provided API functions. typedef struct CubeMXCan_Private_Handle CubeMXCan_Handle; @@ -17,6 +19,21 @@ typedef struct CubeMXCan_Private_Handle CubeMXCan_Handle; /// @brief Callback function type for receiving CAN messages. @warning Do not call directly, use the provided API functions. typedef void (*CubeCAN_RxCallback)(const void *const user_context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); +/** + * @brief CAN Identifier structure + * + * This structure is used to represent a CAN message identifier, which consists of a transmitting node ID, a receiving node ID, and a message ID. The structure is used in conjunction with the + * Construct_Message_ID and Deconstruct_Message_ID functions to convert between the structure representation and the 32-bit integer representation of the CAN message identifier. + * + * @warning The structure does not represent custom IDs. + * @warning The structure does not represent actual bit depth + */ +typedef struct { + GRCAN_NODE_ID tx_node_id; + GRCAN_NODE_ID rx_node_id; + GRCAN_MSG_ID msg_id; +} CAN_Identifier; + /** * @brief Configuration structure for CubeMX CAN. * @@ -34,6 +51,10 @@ typedef struct { GRCAN_NODE_ID sending_node_id; } CubeCAN_Config; +#pragma endregion + +#pragma region Function Prototypes + /** * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration, and starts the CAN peripheral. * @param hfdcan Pointer to the FDCAN handle. @@ -108,4 +129,32 @@ void CubeMXCan_Tick(void); */ HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size); +/** + * @brief Constructs a CAN message identifier from the given transmitting node ID, receiving node ID, and message ID. + * + * @param identifier Pointer to the CAN_Identifier structure containing the node and message IDs. + * + * @return The constructed 29-bit CAN message extended identifier. + */ +uint32_t Construct_CAN_Identifier(const CAN_Identifier *const identifier); + +/** + * @brief Deconstructs a 29-bit CAN message extended identifier into its constituent transmitting node ID, receiving node ID, and message ID. + * + * @param message_id The 29-bit CAN message extended identifier to be deconstructed. + * + * @return A CAN_Identifier structure containing the deconstructed node and message IDs. + * + * @warning The function does not guarantee that the returned structure will represent a valid CAN message identifier. + * @warning The function does not support custom IDs. + */ +CAN_Identifier Deconstruct_CAN_Identifier(const uint32_t message_id); + +/** + * @brief Builds an exact-match extended-ID filter for a given CAN identifier. + */ +HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const identifier, const uint32_t filter_index, const uint32_t fifo, FDCAN_FilterTypeDef *const filter); + +#pragma endregion + #endif diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h b/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h deleted file mode 100644 index 6316e7604..000000000 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCanExt.h +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include "GRCAN_MSG_ID.h" -#include "GRCAN_NODE_ID.h" -#include "main.h" - -#ifndef CUBEMX_CAN_EXT_H -#define CUBEMX_CAN_EXT_H - -/** - * @brief CAN Identifier structure - * - * This structure is used to represent a CAN message identifier, which consists of a transmitting node ID, a receiving node ID, and a message ID. The structure is used in conjunction with the - * Construct_Message_ID and Deconstruct_Message_ID functions to convert between the structure representation and the 32-bit integer representation of the CAN message identifier. - * - * @warning The structure does not represent custom IDs. - * @warning The structure does not represent actual bit depth - */ -typedef struct { - GRCAN_NODE_ID tx_node_id; - GRCAN_NODE_ID rx_node_id; - GRCAN_MSG_ID msg_id; -} CAN_Identifier; - -/** - * @brief Constructs a CAN message identifier from the given transmitting node ID, receiving node ID, and message ID. - * - * @param identifier Pointer to the CAN_Identifier structure containing the node and message IDs. - * - * @return The constructed 29-bit CAN message extended identifier. - */ -uint32_t Construct_CAN_Identifier(const CAN_Identifier *const identifier); - -/** - * @brief Deconstructs a 29-bit CAN message extended identifier into its constituent transmitting node ID, receiving node ID, and message ID. - * - * @param message_id The 29-bit CAN message extended identifier to be deconstructed. - * - * @return A CAN_Identifier structure containing the deconstructed node and message IDs. - * - * @warning The function does not guarantee that the returned structure will represent a valid CAN message identifier. - * @warning The function does not support custom IDs. - */ -CAN_Identifier Deconstruct_CAN_Identifier(const uint32_t message_id); - -/** - * @brief Builds an exact-match extended-ID filter for a given CAN identifier. - */ -HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const identifier, const uint32_t filter_index, const uint32_t fifo, FDCAN_FilterTypeDef *const filter); - -#endif diff --git a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h similarity index 87% rename from Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h rename to Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h index 6b56924fd..e0c381632 100644 --- a/Lib/Peripherals/CubeCAN/Inc/Private/PrivateCubeMXCAN.h +++ b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h @@ -11,6 +11,27 @@ #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H +#pragma region Definitions + +/** + * @brief Maximum number of CubeMX CAN instances supported by the library. + * + * This value is determined based on the available FDCAN peripherals in the STM32 microcontroller. + * + * @warning You can override it, but you should only reduce it to a lower value, there is no point to increase it beyond what their is hardware for. + */ +#ifndef CUBEMX_CAN_MAX_INSTANCES +#if (defined(FDCAN3) || defined(CAN3)) && (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) +#define CUBEMX_CAN_MAX_INSTANCES (3U) +#elif (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) +#define CUBEMX_CAN_MAX_INSTANCES (2U) +#elif (defined(FDCAN1) || defined(CAN1)) +#define CUBEMX_CAN_MAX_INSTANCES (1U) +#else +#error "No CAN or FDCAN instances defined. Please check your CubeMX configuration." +#endif +#endif + /** * @brief Mask for the transmission queue index, used to wrap around the queue when it reaches its maximum size. * @@ -28,6 +49,17 @@ */ #define FDCAN_IT_RX_EVENTS (FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO0_MESSAGE_LOST) +/** + * @brief Maximum number of data bytes in an FDCAN message. + * + * This macro defines the maximum number of data bytes that can be included in an FDCAN message. + */ +#define FDCAN_MAX_DATA_BYTES (64U) + +#pragma endregion + +#pragma region Type Definitions + /** * @brief Transmission CAN message structure * @@ -64,25 +96,9 @@ struct CubeMXCan_Private_Handle { bool started; }; -/// @brief Maximum number of CubeMX CAN instances supported by the library. -#ifndef CUBEMX_CAN_MAX_INSTANCES -#if (defined(FDCAN3) || defined(CAN3)) && (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) -#define CUBEMX_CAN_MAX_INSTANCES 3U -#elif (defined(FDCAN2) || defined(CAN2)) && (defined(FDCAN1) || defined(CAN1)) -#define CUBEMX_CAN_MAX_INSTANCES 2U -#elif (defined(FDCAN1) || defined(CAN1)) -#define CUBEMX_CAN_MAX_INSTANCES 1U -#else -#error "No CAN or FDCAN instances defined. Please check your CubeMX configuration." -#endif -#endif +#pragma endregion -/** - * @brief Sends a queued message from the CubeMX CAN handle. - * @param handle Pointer to the CubeMX CAN handle. - * @return HAL_StatusTypeDef indicating the success or failure of the operation. - */ -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle); +#pragma region External Variables /** * @brief Array of CubeMX CAN handles, one for each supported instance. @@ -90,10 +106,16 @@ HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *co */ extern struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; +#pragma endregion + +#pragma region Function Prototypes + /** - * @brief Flag indicating whether the CubeMX CAN Tx timer has been started. + * @brief Sends a queued message from the CubeMX CAN handle. + * @param handle Pointer to the CubeMX CAN handle. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -extern bool timer_started; +HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle); /** * @brief Attempts to recover the FDCAN peripheral associated with the given CubeMX CAN handle. @@ -137,4 +159,6 @@ uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); */ uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes); +#pragma endregion + #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c index 594c6ca4e..379d6df3d 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_assert.c +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -6,22 +6,28 @@ #include "CriticalSection.h" #include "CubeCAN_Config.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" #include "main.h" -static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_head) == sizeof(uint32_t), "tx_head must be 32 bits"); -static_assert(sizeof(GRCAN_Private_TxMessage) == (sizeof(FDCAN_TxHeaderTypeDef) + 64), "GRCAN_Private_TxMessage size is incorrect"); +#pragma region Compiler Assertions -static_assert(alignof(GRCAN_Private_TxMessage) >= 4, "GRCAN_Private_TxMessage must have at least 4-byte alignment"); -static_assert(ATOMIC_INT_LOCK_FREE == 2, "ATOMIC_INT_LOCK_FREE must be enabled for atomic operations on tx_head and tx_tail"); +static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_head) == sizeof(uint32_t), "CubeMXCan internal tx_head must be 32 bits"); +static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_tail) == sizeof(uint32_t), "CubeMXCan internal tx_tail must be 32 bits"); -static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_head) % 4U) == 0U, "The atomic tx_head is unaligned"); -static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_tail) % 4U) == 0U, "The atomic tx_tail is unaligned"); +static_assert(alignof(GRCAN_Private_TxMessage) >= 4, "CubeMXCan internal GRCAN_Private_TxMessage must have at least 4-byte alignment"); +static_assert(alignof(struct CubeMXCan_Private_Handle) >= 4, "CubeMXCan internal CubeMXCan_Private_Handle must have at least 4-byte alignment"); + +static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_head) % 4U) == 0U, "CubeMXCan internal atomic tx_head is unaligned"); +static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_tail) % 4U) == 0U, "CubeMXCan internal atomic tx_tail is unaligned"); + +static_assert(ATOMIC_INT_LOCK_FREE == 2, "CubeMXCan internal ATOMIC_INT_LOCK_FREE must be enabled for atomic operations"); +static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "CubeMXCan internal ATOMIC_BOOL_LOCK_FREE must be enabled for atomic operations"); + +#pragma endregion + +#pragma region Configuration Checks static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1U)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "CUBEMX_CAN_MAX_INSTANCES must be configured between 1 and 3 inclusive"); -#ifndef CUBEMX_SENDING_NODE_ID -#error "CUBEMX_SENDING_NODE_ID must be defined in CubeCAN_Config.h. This is the node ID of the sending device and must be unique on the CAN bus." -#endif +#pragma endregion diff --git a/Lib/Peripherals/CubeCAN/Src/can_global.c b/Lib/Peripherals/CubeCAN/Src/can_global.c index 20b10badf..90921d16c 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_global.c +++ b/Lib/Peripherals/CubeCAN/Src/can_global.c @@ -4,8 +4,6 @@ #include "CriticalSection.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; -bool timer_started = false; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index f82cd5a20..053ca8725 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -5,9 +5,8 @@ #include "CriticalSection.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" #include "Logomatic.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" #include "main.h" CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index 47f908973..a520b6bac 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -3,9 +3,8 @@ #include "CriticalSection.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" #include "Logomatic.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" #include "Unused.h" #include "main.h" diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index 012911a3c..5cf78ae52 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -4,9 +4,8 @@ #include "CriticalSection.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" #include "Logomatic.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" #include "main.h" void CubeMXCan_Tick(void) diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 17feaf007..8b66dd76e 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -4,11 +4,10 @@ #include "CriticalSection.h" #include "CubeMXCan.h" -#include "CubeMXCanExt.h" #include "GRCAN_MSG_ID.h" #include "GRCAN_NODE_ID.h" #include "Logomatic.h" -#include "Private/PrivateCubeMXCAN.h" +#include "PrivateInc/internal.h" #define CAN_TX_NODE_SHIFT 20U #define CAN_MSG_SHIFT 8U From 97b18018e71880384ccd49b03503e9d0a7f18525 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 06:19:15 -0700 Subject: [PATCH 37/38] Remove tools Signed-off-by: Daniel Hansen --- tools/ConfigureCubeMXPaths.cmake | 220 ----------------------- tools/configure_cubemx_paths.ps1 | 119 ------------- tools/configure_cubemx_paths_linux.sh | 245 -------------------------- tools/configure_cubemx_paths_macos.sh | 245 -------------------------- 4 files changed, 829 deletions(-) delete mode 100644 tools/ConfigureCubeMXPaths.cmake delete mode 100644 tools/configure_cubemx_paths.ps1 delete mode 100644 tools/configure_cubemx_paths_linux.sh delete mode 100644 tools/configure_cubemx_paths_macos.sh diff --git a/tools/ConfigureCubeMXPaths.cmake b/tools/ConfigureCubeMXPaths.cmake deleted file mode 100644 index 767cc4bd9..000000000 --- a/tools/ConfigureCubeMXPaths.cmake +++ /dev/null @@ -1,220 +0,0 @@ -# ConfigureCubeMXPaths.cmake -# -# Cross-platform STM32CubeMX template path configuration. -# -# Expected repository layout: -# -# Firmware/ -# ├── tools/ -# │ └── ConfigureCubeMXPaths.cmake -# ├── CUBEMXTESTING/ -# │ └── CUBEMXTESTING.ioc -# └── Lib/ -# └── CubeMXTemplates/ -# └── Autogen/ -# └── Inc/ -# └── can_cfg_h.ftl -# -# Run manually from the repository root: -# -# cmake -P tools/ConfigureCubeMXPaths.cmake -# -# Optional overrides: -# -# cmake -# -DIOC_FILE=/path/to/project.ioc -# -DTEMPLATE_ROOT=/path/to/CubeMXTemplates -# -DPROJECT_OUTPUT_DIR=/path/to/project -# -P tools/ConfigureCubeMXPaths.cmake -# -# This script writes absolute paths because STM32CubeMX does not reliably -# resolve relative custom-template paths. - -cmake_minimum_required(VERSION 3.20) - -# --------------------------------------------------------------------------- -# Locate repository and default paths -# --------------------------------------------------------------------------- - -get_filename_component(SCRIPT_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) -get_filename_component(REPOSITORY_ROOT "${SCRIPT_DIR}/.." ABSOLUTE) - -if(NOT DEFINED IOC_FILE) - set(IOC_FILE - "${REPOSITORY_ROOT}/CUBEMXTESTING/CUBEMXTESTING.ioc" - ) -endif() - -if(NOT DEFINED PROJECT_OUTPUT_DIR) - set(PROJECT_OUTPUT_DIR - "${REPOSITORY_ROOT}/CUBEMXTESTING" - ) -endif() - -if(NOT DEFINED TEMPLATE_ROOT) - set(TEMPLATE_ROOT - "${REPOSITORY_ROOT}/Lib/CubeMXTemplates" - ) -endif() - -set(TEMPLATE_RELATIVE_PATH - "Autogen/Inc/can_cfg_h.ftl" -) - -get_filename_component(IOC_FILE "${IOC_FILE}" ABSOLUTE) -get_filename_component(PROJECT_OUTPUT_DIR "${PROJECT_OUTPUT_DIR}" ABSOLUTE) -get_filename_component(TEMPLATE_ROOT "${TEMPLATE_ROOT}" ABSOLUTE) - -set(TEMPLATE_FILE - "${TEMPLATE_ROOT}/${TEMPLATE_RELATIVE_PATH}" -) - -# --------------------------------------------------------------------------- -# Validate inputs -# --------------------------------------------------------------------------- - -if(NOT EXISTS "${IOC_FILE}") - message(FATAL_ERROR - "CubeMX .ioc file was not found:\n" - " ${IOC_FILE}" - ) -endif() - -if(NOT IS_DIRECTORY "${PROJECT_OUTPUT_DIR}") - message(FATAL_ERROR - "CubeMX project output directory was not found:\n" - " ${PROJECT_OUTPUT_DIR}" - ) -endif() - -if(NOT IS_DIRECTORY "${TEMPLATE_ROOT}") - message(FATAL_ERROR - "CubeMX template root was not found:\n" - " ${TEMPLATE_ROOT}" - ) -endif() - -if(NOT EXISTS "${TEMPLATE_FILE}") - message(FATAL_ERROR - "CubeMX FreeMarker template was not found:\n" - " ${TEMPLATE_FILE}" - ) -endif() - -# --------------------------------------------------------------------------- -# Convert paths to the format expected by CubeMX's .ioc property file -# --------------------------------------------------------------------------- - -function(convert_to_cubemx_path INPUT_PATH OUTPUT_VARIABLE) - if(WIN32) - # Convert: - # C:/Users/name/Firmware - # to: - # C\:\\Users\\name\\Firmware - file(TO_NATIVE_PATH "${INPUT_PATH}" NATIVE_PATH) - string(REPLACE "\\" "\\\\" ESCAPED_PATH "${NATIVE_PATH}") - string(REPLACE ":" "\\:" ESCAPED_PATH "${ESCAPED_PATH}") - else() - # macOS/Linux paths use forward slashes and require no drive-letter - # escaping. - file(TO_CMAKE_PATH "${INPUT_PATH}" ESCAPED_PATH) - endif() - - set("${OUTPUT_VARIABLE}" "${ESCAPED_PATH}" PARENT_SCOPE) -endfunction() - -convert_to_cubemx_path( - "${PROJECT_OUTPUT_DIR}" - CUBEMX_PROJECT_OUTPUT_DIR -) - -convert_to_cubemx_path( - "${TEMPLATE_ROOT}" - CUBEMX_TEMPLATE_ROOT -) - -if(WIN32) - set(CUBEMX_TEMPLATE_LIST - "\\\\Autogen\\\\Inc\\\\can_cfg_h.ftl," - ) -else() - set(CUBEMX_TEMPLATE_LIST - "/Autogen/Inc/can_cfg_h.ftl," - ) -endif() - -set(DESTINATION_LINE - "ProjectManager.TemplateDestinationPath=${CUBEMX_PROJECT_OUTPUT_DIR}" -) - -set(SOURCE_LINE - "ProjectManager.TemplateSourcePath=${CUBEMX_TEMPLATE_ROOT}" -) - -set(TEMPLATES_LINE - "ProjectManager.TemplatesList=${CUBEMX_TEMPLATE_LIST}" -) - -# --------------------------------------------------------------------------- -# Rewrite or add the three CubeMX settings -# --------------------------------------------------------------------------- - -file(STRINGS "${IOC_FILE}" IOC_LINES ENCODING UTF-8) - -set(UPDATED_CONTENT "") -set(FOUND_DESTINATION FALSE) -set(FOUND_SOURCE FALSE) -set(FOUND_TEMPLATES FALSE) - -foreach(LINE IN LISTS IOC_LINES) - if(LINE MATCHES "^ProjectManager\\.TemplateDestinationPath=") - string(APPEND UPDATED_CONTENT "${DESTINATION_LINE}\n") - set(FOUND_DESTINATION TRUE) - - elseif(LINE MATCHES "^ProjectManager\\.TemplateSourcePath=") - string(APPEND UPDATED_CONTENT "${SOURCE_LINE}\n") - set(FOUND_SOURCE TRUE) - - elseif(LINE MATCHES "^ProjectManager\\.TemplatesList=") - string(APPEND UPDATED_CONTENT "${TEMPLATES_LINE}\n") - set(FOUND_TEMPLATES TRUE) - - else() - string(APPEND UPDATED_CONTENT "${LINE}\n") - endif() -endforeach() - -if(NOT FOUND_DESTINATION) - string(APPEND UPDATED_CONTENT "${DESTINATION_LINE}\n") -endif() - -if(NOT FOUND_SOURCE) - string(APPEND UPDATED_CONTENT "${SOURCE_LINE}\n") -endif() - -if(NOT FOUND_TEMPLATES) - string(APPEND UPDATED_CONTENT "${TEMPLATES_LINE}\n") -endif() - -# Keep a backup of the current .ioc file before modifying it. -configure_file( - "${IOC_FILE}" - "${IOC_FILE}.bak" - COPYONLY -) - -file(WRITE "${IOC_FILE}" "${UPDATED_CONTENT}") - -# --------------------------------------------------------------------------- -# Report result -# --------------------------------------------------------------------------- - -message(STATUS "") -message(STATUS "CubeMX template configuration updated successfully.") -message(STATUS "") -message(STATUS "${DESTINATION_LINE}") -message(STATUS "${SOURCE_LINE}") -message(STATUS "${TEMPLATES_LINE}") -message(STATUS "") -message(STATUS "Backup created at:") -message(STATUS " ${IOC_FILE}.bak") diff --git a/tools/configure_cubemx_paths.ps1 b/tools/configure_cubemx_paths.ps1 deleted file mode 100644 index 4144b2eba..000000000 --- a/tools/configure_cubemx_paths.ps1 +++ /dev/null @@ -1,119 +0,0 @@ -# configure_cubemx_paths.ps1 -# Updates STM32CubeMX template paths using the current repository location. -# -# Expected repository structure: -# Firmware/ -# ├── tools/configure_cubemx_paths.ps1 -# ├── CUBEMXTESTING/CUBEMXTESTING.ioc -# └── Lib/CubeMXTemplates/Autogen/Inc/can_cfg_h.ftl - -$ErrorActionPreference = "Stop" - -# Script location: Firmware/tools -$toolsDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path - -# Repository root: Firmware -$repoRoot = Split-Path -Parent $toolsDirectory - -$iocPath = Join-Path $repoRoot "CUBEMXTESTING\CUBEMXTESTING.ioc" -$projectPath = Join-Path $repoRoot "CUBEMXTESTING" -$templatePath = Join-Path $repoRoot "Lib\CubeMXTemplates" - -if (!(Test-Path -LiteralPath $iocPath)) { - Write-Error "Could not find CubeMX project file: $iocPath" - exit 1 -} - -if (!(Test-Path -LiteralPath $templatePath)) { - Write-Error "Could not find CubeMX template folder: $templatePath" - exit 1 -} - -$templateFile = Join-Path $templatePath "Autogen\Inc\can_cfg_h.ftl" -if (!(Test-Path -LiteralPath $templateFile)) { - Write-Error "Could not find CubeMX template file: $templateFile" - exit 1 -} - -# CubeMX .ioc escaping: -# C:\Users\... becomes C\:\\Users\\... -function Convert-ToCubeMXPath { - param( - [Parameter(Mandatory = $true)] - [string]$Path - ) - - return $Path.Replace("\", "\\").Replace(":", "\:") -} - -$escapedProjectPath = Convert-ToCubeMXPath -Path $projectPath -$escapedTemplatePath = Convert-ToCubeMXPath -Path $templatePath - -$desiredDestinationLine = "ProjectManager.TemplateDestinationPath=$escapedProjectPath" -$desiredSourceLine = "ProjectManager.TemplateSourcePath=$escapedTemplatePath" - -# CubeMX expects a leading escaped backslash and a trailing comma here. -$desiredTemplatesLine = "ProjectManager.TemplatesList=\\Autogen\\Inc\\can_cfg_h.ftl," - -$content = Get-Content -LiteralPath $iocPath - -function Set-OrAddLine { - param( - [Parameter(Mandatory = $true)] - [string[]]$Content, - - [Parameter(Mandatory = $true)] - [string]$Key, - - [Parameter(Mandatory = $true)] - [string]$Replacement - ) - - $pattern = "^" + [regex]::Escape($Key) + "=.*$" - $found = $false - - $updated = foreach ($line in $Content) { - if ($line -match $pattern) { - $found = $true - $Replacement - } - else { - $line - } - } - - if (!$found) { - $updated += $Replacement - } - - return ,$updated -} - -$content = Set-OrAddLine ` - -Content $content ` - -Key "ProjectManager.TemplateDestinationPath" ` - -Replacement $desiredDestinationLine - -$content = Set-OrAddLine ` - -Content $content ` - -Key "ProjectManager.TemplateSourcePath" ` - -Replacement $desiredSourceLine - -$content = Set-OrAddLine ` - -Content $content ` - -Key "ProjectManager.TemplatesList" ` - -Replacement $desiredTemplatesLine - -# Preserve a normal text encoding without adding a UTF-8 BOM. -[System.IO.File]::WriteAllLines( - $iocPath, - $content, - [System.Text.UTF8Encoding]::new($false) -) - -Write-Host "" -Write-Host "CubeMX template configuration updated successfully." -Write-Host "" -Write-Host $desiredDestinationLine -Write-Host $desiredSourceLine -Write-Host $desiredTemplatesLine \ No newline at end of file diff --git a/tools/configure_cubemx_paths_linux.sh b/tools/configure_cubemx_paths_linux.sh deleted file mode 100644 index fda034ba7..000000000 --- a/tools/configure_cubemx_paths_linux.sh +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env bash -# -# Cross-platform Unix STM32CubeMX custom-template path configurator. -# Compatible with macOS Bash 3.2+ and common Linux Bash versions. -# -# Expected repository structure: -# -# Firmware/ -# ├── tools/ -# │ └── configure_cubemx_paths_linux.sh -# ├── CUBEMXTESTING/ -# │ └── CUBEMXTESTING.ioc -# └── Lib/ -# └── CubeMXTemplates/ -# └── Autogen/ -# └── Inc/ -# └── can_cfg_h.ftl -# -# Usage: -# bash tools/configure_cubemx_paths_linux.sh -# -# Optional overrides: -# IOC_FILE=/path/project.ioc \ -# PROJECT_OUTPUT_DIR=/path/project \ -# TEMPLATE_ROOT=/path/CubeMXTemplates \ -# bash tools/configure_cubemx_paths_linux.sh -# -# Behavior: -# - validates all expected paths; -# - removes stale or duplicate CubeMX template properties; -# - writes exactly one correct copy of each property; -# - creates an .ioc.bak backup; -# - writes through a temporary file; -# - verifies the result from disk; -# - is idempotent. - -set -euo pipefail - -EXPECTED_OS="linux" - -die() { - printf 'ERROR: %s\n' "$*" >&2 - exit 1 -} - -info() { - printf '%s\n' "$*" -} - -detect_os() { - case "$(uname -s)" in - Darwin) printf '%s\n' "macos" ;; - Linux) printf '%s\n' "linux" ;; - *) printf '%s\n' "unsupported" ;; - esac -} - -CURRENT_OS="$(detect_os)" -if [ "$CURRENT_OS" != "$EXPECTED_OS" ]; then - die "This script is intended for $EXPECTED_OS, but detected $CURRENT_OS." -fi - -# Resolve the physical directory containing this script without requiring -# realpath, which is not included with older macOS installations. -SCRIPT_DIR="$( - CDPATH= cd -- "$(dirname -- "$0")" >/dev/null 2>&1 - pwd -P -)" -REPOSITORY_ROOT="$( - CDPATH= cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 - pwd -P -)" - -IOC_FILE="${IOC_FILE:-$REPOSITORY_ROOT/CUBEMXTESTING/CUBEMXTESTING.ioc}" -PROJECT_OUTPUT_DIR="${PROJECT_OUTPUT_DIR:-$REPOSITORY_ROOT/CUBEMXTESTING}" -TEMPLATE_ROOT="${TEMPLATE_ROOT:-$REPOSITORY_ROOT/Lib/CubeMXTemplates}" -TEMPLATE_FILE="$TEMPLATE_ROOT/Autogen/Inc/can_cfg_h.ftl" - -[ -f "$IOC_FILE" ] || - die "CubeMX .ioc file was not found: $IOC_FILE" - -[ -d "$PROJECT_OUTPUT_DIR" ] || - die "CubeMX project output directory was not found: $PROJECT_OUTPUT_DIR" - -[ -d "$TEMPLATE_ROOT" ] || - die "CubeMX template root was not found: $TEMPLATE_ROOT" - -[ -f "$TEMPLATE_FILE" ] || - die "CubeMX FreeMarker template was not found: $TEMPLATE_FILE" - -# Convert directories to physical absolute paths. -PROJECT_OUTPUT_DIR="$( - CDPATH= cd -- "$PROJECT_OUTPUT_DIR" >/dev/null 2>&1 - pwd -P -)" -TEMPLATE_ROOT="$( - CDPATH= cd -- "$TEMPLATE_ROOT" >/dev/null 2>&1 - pwd -P -)" - -DESTINATION_KEY='ProjectManager.TemplateDestinationPath' -SOURCE_KEY='ProjectManager.TemplateSourcePath' -TEMPLATES_KEY='ProjectManager.TemplatesList' - -DESTINATION_LINE="${DESTINATION_KEY}=${PROJECT_OUTPUT_DIR}" -SOURCE_LINE="${SOURCE_KEY}=${TEMPLATE_ROOT}" -TEMPLATES_LINE="${TEMPLATES_KEY}=/Autogen/Inc/can_cfg_h.ftl," - -IOC_DIRECTORY="$(dirname -- "$IOC_FILE")" -IOC_BASENAME="$(basename -- "$IOC_FILE")" -BACKUP_FILE="${IOC_FILE}.bak" -TEMP_FILE="$(mktemp "${IOC_DIRECTORY}/.${IOC_BASENAME}.tmp.XXXXXX")" - -cleanup() { - if [ -n "${TEMP_FILE:-}" ] && [ -f "$TEMP_FILE" ]; then - rm -f -- "$TEMP_FILE" - fi -} -trap cleanup EXIT HUP INT TERM - -# Back up the current file before any modification. -cp -p -- "$IOC_FILE" "$BACKUP_FILE" - -# Remove every existing copy of the three properties and append one stable, -# complete block. awk preserves all unrelated lines verbatim at the text level, -# including semicolons and similarly named properties. -awk \ - -v destination_key="$DESTINATION_KEY" \ - -v source_key="$SOURCE_KEY" \ - -v templates_key="$TEMPLATES_KEY" \ - -v destination_line="$DESTINATION_LINE" \ - -v source_line="$SOURCE_LINE" \ - -v templates_line="$TEMPLATES_LINE" ' -BEGIN { - destination_prefix = destination_key "=" - source_prefix = source_key "=" - templates_prefix = templates_key "=" -} -{ - # Remove a possible CR from CRLF input so Unix output is consistently LF. - sub(/\r$/, "", $0) - - if (index($0, destination_prefix) == 1) { - next - } - - if (index($0, source_prefix) == 1) { - next - } - - if (index($0, templates_prefix) == 1) { - next - } - - lines[++count] = $0 -} -END { - # Remove trailing blank lines before appending the generated block. - while (count > 0 && lines[count] == "") { - count-- - } - - for (i = 1; i <= count; i++) { - print lines[i] - } - - if (count > 0) { - print "" - } - - print destination_line - print source_line - print templates_line -} -' "$IOC_FILE" > "$TEMP_FILE" - -[ -s "$TEMP_FILE" ] || - die "Generated temporary .ioc file is empty: $TEMP_FILE" - -verify_exact_line_once() { - expected_line="$1" - description="$2" - - # grep -F treats the path as literal text. -x requires the full line. - count="$( - grep -Fxc -- "$expected_line" "$TEMP_FILE" 2>/dev/null || true - )" - - [ "$count" -eq 1 ] || - die "$description verification failed; expected exactly once, found $count." -} - -verify_key_once() { - key="$1" - description="$2" - - count="$( - awk -v prefix="${key}=" ' - index($0, prefix) == 1 { count++ } - END { print count + 0 } - ' "$TEMP_FILE" - )" - - [ "$count" -eq 1 ] || - die "$description key verification failed; expected exactly one property, found $count." -} - -verify_key_once "$DESTINATION_KEY" "Destination path" -verify_key_once "$SOURCE_KEY" "Source path" -verify_key_once "$TEMPLATES_KEY" "Template list" - -verify_exact_line_once "$DESTINATION_LINE" "Destination path" -verify_exact_line_once "$SOURCE_LINE" "Source path" -verify_exact_line_once "$TEMPLATES_LINE" "Template list" - -# Replace the original only after all temporary-file checks pass. -mv -f -- "$TEMP_FILE" "$IOC_FILE" -TEMP_FILE="" - -# Verify the file again after it has been moved into place. -verify_disk_line_once() { - expected_line="$1" - description="$2" - - count="$( - grep -Fxc -- "$expected_line" "$IOC_FILE" 2>/dev/null || true - )" - - [ "$count" -eq 1 ] || - die "Post-write $description verification failed; found $count copies." -} - -verify_disk_line_once "$DESTINATION_LINE" "destination path" -verify_disk_line_once "$SOURCE_LINE" "source path" -verify_disk_line_once "$TEMPLATES_LINE" "template list" - -info "" -info "CubeMX template configuration updated and verified." -info "" -info "$DESTINATION_LINE" -info "$SOURCE_LINE" -info "$TEMPLATES_LINE" -info "" -info "Backup:" -info " $BACKUP_FILE" diff --git a/tools/configure_cubemx_paths_macos.sh b/tools/configure_cubemx_paths_macos.sh deleted file mode 100644 index f7c0bafde..000000000 --- a/tools/configure_cubemx_paths_macos.sh +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env bash -# -# Cross-platform Unix STM32CubeMX custom-template path configurator. -# Compatible with macOS Bash 3.2+ and common Linux Bash versions. -# -# Expected repository structure: -# -# Firmware/ -# ├── tools/ -# │ └── configure_cubemx_paths_macos.sh -# ├── CUBEMXTESTING/ -# │ └── CUBEMXTESTING.ioc -# └── Lib/ -# └── CubeMXTemplates/ -# └── Autogen/ -# └── Inc/ -# └── can_cfg_h.ftl -# -# Usage: -# bash tools/configure_cubemx_paths_macos.sh -# -# Optional overrides: -# IOC_FILE=/path/project.ioc \ -# PROJECT_OUTPUT_DIR=/path/project \ -# TEMPLATE_ROOT=/path/CubeMXTemplates \ -# bash tools/configure_cubemx_paths_macos.sh -# -# Behavior: -# - validates all expected paths; -# - removes stale or duplicate CubeMX template properties; -# - writes exactly one correct copy of each property; -# - creates an .ioc.bak backup; -# - writes through a temporary file; -# - verifies the result from disk; -# - is idempotent. - -set -euo pipefail - -EXPECTED_OS="macos" - -die() { - printf 'ERROR: %s\n' "$*" >&2 - exit 1 -} - -info() { - printf '%s\n' "$*" -} - -detect_os() { - case "$(uname -s)" in - Darwin) printf '%s\n' "macos" ;; - Linux) printf '%s\n' "linux" ;; - *) printf '%s\n' "unsupported" ;; - esac -} - -CURRENT_OS="$(detect_os)" -if [ "$CURRENT_OS" != "$EXPECTED_OS" ]; then - die "This script is intended for $EXPECTED_OS, but detected $CURRENT_OS." -fi - -# Resolve the physical directory containing this script without requiring -# realpath, which is not included with older macOS installations. -SCRIPT_DIR="$( - CDPATH= cd -- "$(dirname -- "$0")" >/dev/null 2>&1 - pwd -P -)" -REPOSITORY_ROOT="$( - CDPATH= cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 - pwd -P -)" - -IOC_FILE="${IOC_FILE:-$REPOSITORY_ROOT/CUBEMXTESTING/CUBEMXTESTING.ioc}" -PROJECT_OUTPUT_DIR="${PROJECT_OUTPUT_DIR:-$REPOSITORY_ROOT/CUBEMXTESTING}" -TEMPLATE_ROOT="${TEMPLATE_ROOT:-$REPOSITORY_ROOT/Lib/CubeMXTemplates}" -TEMPLATE_FILE="$TEMPLATE_ROOT/Autogen/Inc/can_cfg_h.ftl" - -[ -f "$IOC_FILE" ] || - die "CubeMX .ioc file was not found: $IOC_FILE" - -[ -d "$PROJECT_OUTPUT_DIR" ] || - die "CubeMX project output directory was not found: $PROJECT_OUTPUT_DIR" - -[ -d "$TEMPLATE_ROOT" ] || - die "CubeMX template root was not found: $TEMPLATE_ROOT" - -[ -f "$TEMPLATE_FILE" ] || - die "CubeMX FreeMarker template was not found: $TEMPLATE_FILE" - -# Convert directories to physical absolute paths. -PROJECT_OUTPUT_DIR="$( - CDPATH= cd -- "$PROJECT_OUTPUT_DIR" >/dev/null 2>&1 - pwd -P -)" -TEMPLATE_ROOT="$( - CDPATH= cd -- "$TEMPLATE_ROOT" >/dev/null 2>&1 - pwd -P -)" - -DESTINATION_KEY='ProjectManager.TemplateDestinationPath' -SOURCE_KEY='ProjectManager.TemplateSourcePath' -TEMPLATES_KEY='ProjectManager.TemplatesList' - -DESTINATION_LINE="${DESTINATION_KEY}=${PROJECT_OUTPUT_DIR}" -SOURCE_LINE="${SOURCE_KEY}=${TEMPLATE_ROOT}" -TEMPLATES_LINE="${TEMPLATES_KEY}=/Autogen/Inc/can_cfg_h.ftl," - -IOC_DIRECTORY="$(dirname -- "$IOC_FILE")" -IOC_BASENAME="$(basename -- "$IOC_FILE")" -BACKUP_FILE="${IOC_FILE}.bak" -TEMP_FILE="$(mktemp "${IOC_DIRECTORY}/.${IOC_BASENAME}.tmp.XXXXXX")" - -cleanup() { - if [ -n "${TEMP_FILE:-}" ] && [ -f "$TEMP_FILE" ]; then - rm -f -- "$TEMP_FILE" - fi -} -trap cleanup EXIT HUP INT TERM - -# Back up the current file before any modification. -cp -p -- "$IOC_FILE" "$BACKUP_FILE" - -# Remove every existing copy of the three properties and append one stable, -# complete block. awk preserves all unrelated lines verbatim at the text level, -# including semicolons and similarly named properties. -awk \ - -v destination_key="$DESTINATION_KEY" \ - -v source_key="$SOURCE_KEY" \ - -v templates_key="$TEMPLATES_KEY" \ - -v destination_line="$DESTINATION_LINE" \ - -v source_line="$SOURCE_LINE" \ - -v templates_line="$TEMPLATES_LINE" ' -BEGIN { - destination_prefix = destination_key "=" - source_prefix = source_key "=" - templates_prefix = templates_key "=" -} -{ - # Remove a possible CR from CRLF input so Unix output is consistently LF. - sub(/\r$/, "", $0) - - if (index($0, destination_prefix) == 1) { - next - } - - if (index($0, source_prefix) == 1) { - next - } - - if (index($0, templates_prefix) == 1) { - next - } - - lines[++count] = $0 -} -END { - # Remove trailing blank lines before appending the generated block. - while (count > 0 && lines[count] == "") { - count-- - } - - for (i = 1; i <= count; i++) { - print lines[i] - } - - if (count > 0) { - print "" - } - - print destination_line - print source_line - print templates_line -} -' "$IOC_FILE" > "$TEMP_FILE" - -[ -s "$TEMP_FILE" ] || - die "Generated temporary .ioc file is empty: $TEMP_FILE" - -verify_exact_line_once() { - expected_line="$1" - description="$2" - - # grep -F treats the path as literal text. -x requires the full line. - count="$( - grep -Fxc -- "$expected_line" "$TEMP_FILE" 2>/dev/null || true - )" - - [ "$count" -eq 1 ] || - die "$description verification failed; expected exactly once, found $count." -} - -verify_key_once() { - key="$1" - description="$2" - - count="$( - awk -v prefix="${key}=" ' - index($0, prefix) == 1 { count++ } - END { print count + 0 } - ' "$TEMP_FILE" - )" - - [ "$count" -eq 1 ] || - die "$description key verification failed; expected exactly one property, found $count." -} - -verify_key_once "$DESTINATION_KEY" "Destination path" -verify_key_once "$SOURCE_KEY" "Source path" -verify_key_once "$TEMPLATES_KEY" "Template list" - -verify_exact_line_once "$DESTINATION_LINE" "Destination path" -verify_exact_line_once "$SOURCE_LINE" "Source path" -verify_exact_line_once "$TEMPLATES_LINE" "Template list" - -# Replace the original only after all temporary-file checks pass. -mv -f -- "$TEMP_FILE" "$IOC_FILE" -TEMP_FILE="" - -# Verify the file again after it has been moved into place. -verify_disk_line_once() { - expected_line="$1" - description="$2" - - count="$( - grep -Fxc -- "$expected_line" "$IOC_FILE" 2>/dev/null || true - )" - - [ "$count" -eq 1 ] || - die "Post-write $description verification failed; found $count copies." -} - -verify_disk_line_once "$DESTINATION_LINE" "destination path" -verify_disk_line_once "$SOURCE_LINE" "source path" -verify_disk_line_once "$TEMPLATES_LINE" "template list" - -info "" -info "CubeMX template configuration updated and verified." -info "" -info "$DESTINATION_LINE" -info "$SOURCE_LINE" -info "$TEMPLATES_LINE" -info "" -info "Backup:" -info " $BACKUP_FILE" From 6e7e1a62c04bc344ec4b052f6b0baec8231df5b1 Mon Sep 17 00:00:00 2001 From: Daniel Hansen Date: Fri, 31 Jul 2026 06:19:37 -0700 Subject: [PATCH 38/38] Peripheral schema rename Signed-off-by: Daniel Hansen --- CMakeLists.txt | 2 +- CUBEMXTESTING/Application/Inc/CANdler.h | 4 +- .../Application/Inc/CubeCAN_Config.h | 4 +- CUBEMXTESTING/Application/Src/CANdler.c | 6 +- CUBEMXTESTING/CMakeLists.txt | 1 + CUBEMXTESTING/Core/Src/main.c | 9 +- .../CubeCAN/Inc/{CubeMXCan.h => CubeCAN.h} | 89 ++++++++++--------- .../CubeCAN/Src/PrivateInc/internal.h | 66 ++++++-------- Lib/Peripherals/CubeCAN/Src/can_assert.c | 26 ++---- Lib/Peripherals/CubeCAN/Src/can_global.c | 4 +- Lib/Peripherals/CubeCAN/Src/can_init.c | 44 ++++----- Lib/Peripherals/CubeCAN/Src/can_rx.c | 4 +- Lib/Peripherals/CubeCAN/Src/can_tx.c | 36 ++++---- Lib/Peripherals/CubeCAN/Src/can_utils.c | 24 ++--- .../{cubemx_can.cmake => cube_can.cmake} | 0 15 files changed, 148 insertions(+), 171 deletions(-) rename Lib/Peripherals/CubeCAN/Inc/{CubeMXCan.h => CubeCAN.h} (55%) rename Lib/Peripherals/CubeCAN/{cubemx_can.cmake => cube_can.cmake} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86537662b..46b377ddb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ include("Autogen/CAN/CANfigurator.cmake") include("${lib_path}/Peripherals/USART/common.cmake") include("${lib_path}/Peripherals/TimedCAN/common.cmake") include("${lib_path}/Peripherals/CAN/common.cmake") -include("${lib_path}/Peripherals/CubeCAN/cubemx_can.cmake") +include("${lib_path}/Peripherals/CubeCAN/cube_can.cmake") include("${lib_path}/FancyLayers-RENAME/GRCAN/grcan_fancylayer.cmake") include("${lib_path}/FancyLayers-RENAME/ADC/adc.cmake") diff --git a/CUBEMXTESTING/Application/Inc/CANdler.h b/CUBEMXTESTING/Application/Inc/CANdler.h index 64739c684..bd67e5959 100644 --- a/CUBEMXTESTING/Application/Inc/CANdler.h +++ b/CUBEMXTESTING/Application/Inc/CANdler.h @@ -1,8 +1,8 @@ -#include "CubeMXCan.h" +#include "CubeCAN.h" #ifndef CANDLER_H #define CANDLER_H -void CANdler_Callback(CubeMXCan_Handle *const handle, void *const user_ctx); +void CANdler_Callback(CubeCAN_Handle *const handle, void *const user_context); #endif diff --git a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h index bd5e39a5a..db74ce3b5 100644 --- a/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h +++ b/CUBEMXTESTING/Application/Inc/CubeCAN_Config.h @@ -1,10 +1,10 @@ #ifndef CUBE_CAN_CONFIG_H #define CUBE_CAN_CONFIG_H -// TODO Add a template to the library - +#include "GRCAN_NODE_ID.h" #include "main.h" #define CUBEMX_CAN_TX_QUEUE_SIZE 32U +#define CUBEMX_SENDING_NODE_ID GRCAN_ECU #endif diff --git a/CUBEMXTESTING/Application/Src/CANdler.c b/CUBEMXTESTING/Application/Src/CANdler.c index cfae5c588..524b95617 100644 --- a/CUBEMXTESTING/Application/Src/CANdler.c +++ b/CUBEMXTESTING/Application/Src/CANdler.c @@ -1,9 +1,9 @@ #include "CANdler.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" -void CANdler_Callback(CubeMXCan_Handle *const handle, void *const user_ctx) +void CANdler_Callback(CubeCAN_Handle *const handle, void *const user_context) { - LOGOMATIC("CANdler_Callback: Received CAN message on handle %p with user context %p\n", (void *)handle, user_ctx); + LOGOMATIC("CANdler_Callback: Received CAN message on handle %p with user context %p\n", (void *)handle, user_context); // TODO } diff --git a/CUBEMXTESTING/CMakeLists.txt b/CUBEMXTESTING/CMakeLists.txt index c8fcc8050..81566a37d 100644 --- a/CUBEMXTESTING/CMakeLists.txt +++ b/CUBEMXTESTING/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources( Core/Src/gpio.c Core/Src/main.c Core/Src/stm32g4xx_it.c + Core/Src/tim.c ) target_link_libraries(${PROJECT_NAME}_USER_CODE INTERFACE VCP_LIB CUBEMX_CAN_LIB LOGOMATIC_LIB) diff --git a/CUBEMXTESTING/Core/Src/main.c b/CUBEMXTESTING/Core/Src/main.c index 9f6e59804..ab6643b56 100644 --- a/CUBEMXTESTING/Core/Src/main.c +++ b/CUBEMXTESTING/Core/Src/main.c @@ -26,8 +26,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "CANdler.h" -#include "CubeMXCan.h" -#include "CubeMXCanExt.h" +#include "CubeCAN.h" #include "Logomatic.h" #include "loop.h" #include "tim.h" @@ -132,9 +131,9 @@ int main(void) Logomatic_Init(&logomaticConfig); VCP_Init(&vcp_config); - CubeCAN_Config can_config = {.rx_callback = CANdler_Callback, .user_ctx = (void *)1}; + CubeCAN_Config can_config = {.rx_callback = CANdler_Callback, .user_context = (void *)1}; - CubeMXCan_Init(&hfdcan1, &can_config); + CubeCAN_Init(&hfdcan1, &can_config); /* USER CODE END 2 */ /* Infinite loop */ @@ -199,7 +198,7 @@ void SystemClock_Config(void) void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &CAN_TIMER_HANDLE) { - CubeMXCan_Tick(); + CubeCAN_Tick(); } } diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h b/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h similarity index 55% rename from Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h rename to Lib/Peripherals/CubeCAN/Inc/CubeCAN.h index b4adc3595..9b0eddd6e 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeMXCan.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h @@ -11,13 +11,11 @@ #ifndef CUBEMX_CAN_H #define CUBEMX_CAN_H -#pragma region Type Definitions - -/// @brief CAN handle for CubeMX CAN. @warning Do not access directly, use the provided API functions. -typedef struct CubeMXCan_Private_Handle CubeMXCan_Handle; - -/// @brief Callback function type for receiving CAN messages. @warning Do not call directly, use the provided API functions. -typedef void (*CubeCAN_RxCallback)(const void *const user_context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); +/** + * @brief CAN handle for CubeCAN CAN. + * @warning Do not access directly, use the provided API functions. + */ +typedef struct CubeCAN_Private_Handle CubeCAN_Handle; /** * @brief CAN Identifier structure @@ -35,9 +33,18 @@ typedef struct { } CAN_Identifier; /** - * @brief Configuration structure for CubeMX CAN. + * @brief Callback function type for receiving CAN messages. * - * This structure is used to configure the CubeMX CAN handle, including the receive callback function and user context. The receive callback function is called when a CAN message is received, and the + * @warning The callback function should not perform blocking operations or take too long to execute. + * @warning The callback function should not call any CubeCAN functions, as it may lead to undefined behavior. + * @warning It is the responsibility of the callback function to verify the integrity of the received data and handle any errors or null inputs. + */ +typedef void (*CubeCAN_RxCallback)(const void *const user_context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); + +/** + * @brief Configuration structure for CubeCAN CAN. + * + * This structure is used to configure the CubeCAN CAN handle, including the receive callback function and user context. The receive callback function is called when a CAN message is received, and the * user context is a pointer to user-defined data that can be passed to the callback function. * * @warning Do not edit after initialization, as it may lead to undefined behavior. @@ -51,75 +58,71 @@ typedef struct { GRCAN_NODE_ID sending_node_id; } CubeCAN_Config; -#pragma endregion - -#pragma region Function Prototypes - /** - * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration, and starts the CAN peripheral. + * @brief Initializes a CubeCAN CAN handle with the given FDCAN handle and configuration, and starts the CAN peripheral. * @param hfdcan Pointer to the FDCAN handle. * @param config Pointer to the CubeCAN configuration structure. - * @return Pointer to the initialized CubeMX CAN handle, or NULL if initialization fails. - * @note This functions wraps CubeMXCan_Init and CubeMXCan_Start into a single call. If either of those functions fails, this function will return NULL and the handle will be released. + * @return Pointer to the initialized CubeCAN CAN handle, or NULL if initialization fails. + * @note This functions wraps CubeCAN_Init and CubeCAN_Start into a single call. If either of those functions fails, this function will return NULL and the handle will be released. */ -CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); +CubeCAN_Handle *CubeCAN_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); /** - * @brief Stops the CubeMX CAN peripheral and releases the associated handle. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Stops the CubeCAN CAN peripheral and releases the associated handle. + * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. - * @note This functions wraps CubeMXCan_Stop and CubeMXCan_Release into a single call. If either of those functions fails, this function will return the error code and the handle will + * @note This functions wraps CubeCAN_Stop and CubeCAN_Release into a single call. If either of those functions fails, this function will return the error code and the handle will * not be released. - * @note This function can be used regardless of if CubeMXCan_OneShotInitStart was used to initialize the handle. + * @note This function can be used regardless of if CubeCAN_OneShotInitStart was used to initialize the handle. */ -HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle); +HAL_StatusTypeDef CubeCAN_OneShotReleaseStop(CubeCAN_Handle *handle); /** - * @brief Initializes a CubeMX CAN handle with the given FDCAN handle and configuration. + * @brief Initializes a CubeCAN CAN handle with the given FDCAN handle and configuration. * @param hfdcan Pointer to the FDCAN handle. * @param config Pointer to the CubeCAN configuration structure. - * @return Pointer to the initialized CubeMX CAN handle, or NULL if initialization fails. + * @return Pointer to the initialized CubeCAN CAN handle, or NULL if initialization fails. */ -CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); +CubeCAN_Handle *CubeCAN_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config); /** - * @brief Starts the CubeMX CAN handle, enabling message transmission and reception. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Starts the CubeCAN CAN handle, enabling message transmission and reception. + * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Start(CubeCAN_Handle *const handle); /** - * @brief Stops the CubeMX CAN handle, disabling message transmission and reception. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Stops the CubeCAN CAN handle, disabling message transmission and reception. + * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Stop(CubeCAN_Handle *const handle); /** - * @brief Releases the resources associated with the CubeMX CAN handle. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Releases the resources associated with the CubeCAN CAN handle. + * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Release(CubeCAN_Handle *const handle); /** - * @brief Adds a filter to the CubeMX CAN handle, allowing for selective message reception based on the specified filter criteria. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Adds a filter to the CubeCAN CAN handle, allowing for selective message reception based on the specified filter criteria. + * @param handle Pointer to the CubeCAN CAN handle. * @param filter Pointer to the FDCAN filter configuration structure. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *const filter); +HAL_StatusTypeDef CubeCAN_AddFilter(const CubeCAN_Handle *const handle, const FDCAN_FilterTypeDef *const filter); /** - * @brief Processes periodic tasks for the CubeMX CAN handle, such as handling timeouts and managing the transmission queue. + * @brief Processes periodic tasks for the CubeCAN CAN handle, such as handling timeouts and managing the transmission queue. * @warning This function sends one can message per configured bus per call. Not calling it will simply not send any messages. */ -void CubeMXCan_Tick(void); +void CubeCAN_Tick(void); /** - * @brief Sends a CAN message using the CubeMX CAN handle, with the specified receive node, message ID, data payload, and size. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Sends a CAN message using the CubeCAN CAN handle, with the specified receive node, message ID, data payload, and size. + * @param handle Pointer to the CubeCAN CAN handle. * @param rx_node The receive node identifier for the message. * @param msg_id The message ID for the message. * @param data Pointer to the data payload of the message. @@ -127,7 +130,7 @@ void CubeMXCan_Tick(void); * @return HAL_StatusTypeDef indicating the success or failure of the operation. * @note The size of the data payload must not exceed FDCAN_MAX_DATA_BYTES (64 bytes). If the size exceeds this limit, the function will return HAL_ERROR. */ -HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size); +HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size); /** * @brief Constructs a CAN message identifier from the given transmitting node ID, receiving node ID, and message ID. @@ -155,6 +158,4 @@ CAN_Identifier Deconstruct_CAN_Identifier(const uint32_t message_id); */ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const identifier, const uint32_t filter_index, const uint32_t fifo, FDCAN_FilterTypeDef *const filter); -#pragma endregion - #endif diff --git a/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h index e0c381632..93e15d892 100644 --- a/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h +++ b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h @@ -11,10 +11,8 @@ #ifndef PRIVATE_CUBE_MX_CAN_H #define PRIVATE_CUBE_MX_CAN_H -#pragma region Definitions - /** - * @brief Maximum number of CubeMX CAN instances supported by the library. + * @brief Maximum number of CubeCAN CAN instances supported by the library. * * This value is determined based on the available FDCAN peripherals in the STM32 microcontroller. * @@ -28,7 +26,7 @@ #elif (defined(FDCAN1) || defined(CAN1)) #define CUBEMX_CAN_MAX_INSTANCES (1U) #else -#error "No CAN or FDCAN instances defined. Please check your CubeMX configuration." +#error "No CAN or FDCAN instances defined. Please check your CubeCAN configuration." #endif #endif @@ -38,7 +36,7 @@ * Application code should not use this macro directly. It is intended for internal use only * * @warning The transmission queue size must be a power of two for this mask to work correctly - * @warning The transmission queue size must be defined as CUBEMX_CAN_TX_QUEUE_SIZE in the CubeMX CAN configuration header file + * @warning The transmission queue size must be defined as CUBEMX_CAN_TX_QUEUE_SIZE in the CubeCAN CAN configuration header file */ #define TX_QUEUE_MASK (CUBEMX_CAN_TX_QUEUE_SIZE - 1U) @@ -56,10 +54,6 @@ */ #define FDCAN_MAX_DATA_BYTES (64U) -#pragma endregion - -#pragma region Type Definitions - /** * @brief Transmission CAN message structure * @@ -74,58 +68,50 @@ typedef struct { } GRCAN_Private_TxMessage; /** - * @brief CubeMX CAN handle structure + * @brief CubeCAN CAN handle structure * - * This structure is used to represent a CubeMX CAN handle, which consists of a pointer to the FDCAN handle, a configuration structure, a transmission queue, and other relevant parameters. + * This structure is used to represent a CubeCAN CAN handle, which consists of a pointer to the FDCAN handle, a configuration structure, a transmission queue, and other relevant parameters. * - * @warning Use the provided API functions to interact with the CubeMX CAN handle. + * @warning Use the provided API functions to interact with the CubeCAN CAN handle. * @warning The structure is intended for internal use only and should not be accessed directly by user code. */ -struct CubeMXCan_Private_Handle { - /// @brief Pointer to the FDCAN handle associated with this CubeMX CAN handle. +struct CubeCAN_Private_Handle { + /// @brief Pointer to the FDCAN handle associated with this CubeCAN CAN handle. FDCAN_HandleTypeDef *hfdcan; - /// @brief Configuration structure for the CubeMX CAN handle, containing the receive callback and user context. + /// @brief Configuration structure for the CubeCAN CAN handle, containing the receive callback and user context. CubeCAN_Config config; - /// @brief Transmission queue for the CubeMX CAN handle, containing the messages to be transmitted. + /// @brief Transmission queue for the CubeCAN CAN handle, containing the messages to be transmitted. GRCAN_Private_TxMessage tx_queue[CUBEMX_CAN_TX_QUEUE_SIZE]; /// @brief Atomic head index for the transmission queue, indicating the next message to be transmitted. _Atomic uint32_t tx_head; /// @brief Atomic tail index for the transmission queue, indicating the next available slot for a new message. _Atomic uint32_t tx_tail; - /// @brief Flag indicating whether the CubeMX CAN handle has been started. + /// @brief Flag indicating whether the CubeCAN CAN handle has been started. bool started; }; -#pragma endregion - -#pragma region External Variables - /** - * @brief Array of CubeMX CAN handles, one for each supported instance. + * @brief Array of CubeCAN CAN handles, one for each supported instance. * @note The number of instances is defined by CUBEMX_CAN_MAX_INSTANCES. */ -extern struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; - -#pragma endregion - -#pragma region Function Prototypes +extern struct CubeCAN_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES]; /** - * @brief Sends a queued message from the CubeMX CAN handle. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Sends a queued message from the CubeCAN CAN handle. + * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(const CubeCAN_Handle *const handle); /** - * @brief Attempts to recover the FDCAN peripheral associated with the given CubeMX CAN handle. + * @brief Attempts to recover the FDCAN peripheral associated with the given CubeCAN CAN handle. * * Handles recovery from bus off or restricted operation mode by reinitializing the FDCAN peripheral and restoring its configuration. * - * @param handle Pointer to the CubeMX CAN handle associated with the FDCAN peripheral to be recovered. + * @param handle Pointer to the CubeCAN CAN handle associated with the FDCAN peripheral to be recovered. * @return HAL_StatusTypeDef indicating the success or failure of the recovery operation. */ -HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Private_RecoverPeripheral(const CubeCAN_Handle *const handle); /** * @brief Converts a Data Length Code (DLC) to the corresponding number of data bytes. @@ -133,15 +119,15 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *co * @return The number of data bytes corresponding to the given DLC. * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. */ -bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle); +bool CubeCAN_Private_IsDisabled(const CubeCAN_Handle *const handle); /** - * @brief Queues a transmission message for the CubeMX CAN handle, allowing for asynchronous message transmission. - * @param handle Pointer to the CubeMX CAN handle. + * @brief Queues a transmission message for the CubeCAN CAN handle, allowing for asynchronous message transmission. + * @param handle Pointer to the CubeCAN CAN handle. * @param message Pointer to the GRCAN transmission message structure. * @return HAL_StatusTypeDef if the parameters are non-null or the queue is full. */ -HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *const handle, const GRCAN_Private_TxMessage *const message); +HAL_StatusTypeDef CubeCAN_Private_QueueTx(CubeCAN_Handle *const handle, const GRCAN_Private_TxMessage *const message); /** * @brief Converts a Data Length Code (DLC) to the corresponding number of bytes. @@ -149,7 +135,7 @@ HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *const handle, cons * @return The number of bytes corresponding to the given DLC. * @warning The DLC value must be between 0 and 15, inclusive. Values outside this range will result in undefined behavior. */ -uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); +uint8_t CubeCAN_Private_DlcToBytes(const uint32_t dlc); /** * @brief Converts a number of bytes to the corresponding Data Length Code (DLC). @@ -157,8 +143,6 @@ uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc); * @return The Data Length Code corresponding to the given number of bytes. * @warning The number of bytes must be between 0 and 8, inclusive. Values outside this range will result in undefined behavior. */ -uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes); - -#pragma endregion +uint8_t CubeCAN_Private_BytesToDlc(const uint8_t bytes); #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c index 379d6df3d..05d94fa2b 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_assert.c +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -4,30 +4,22 @@ #include #include "CriticalSection.h" +#include "CubeCAN.h" #include "CubeCAN_Config.h" -#include "CubeMXCan.h" #include "PrivateInc/internal.h" #include "main.h" -#pragma region Compiler Assertions +static_assert(sizeof(((struct CubeCAN_Private_Handle *)0)->tx_head) == sizeof(uint32_t), "CubeCAN internal tx_head must be 32 bits"); +static_assert(sizeof(((struct CubeCAN_Private_Handle *)0)->tx_tail) == sizeof(uint32_t), "CubeCAN internal tx_tail must be 32 bits"); -static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_head) == sizeof(uint32_t), "CubeMXCan internal tx_head must be 32 bits"); -static_assert(sizeof(((struct CubeMXCan_Private_Handle *)0)->tx_tail) == sizeof(uint32_t), "CubeMXCan internal tx_tail must be 32 bits"); +static_assert(alignof(GRCAN_Private_TxMessage) >= 4, "CubeCAN internal GRCAN_Private_TxMessage must have at least 4-byte alignment"); +static_assert(alignof(struct CubeCAN_Private_Handle) >= 4, "CubeCAN internal CubeCAN_Private_Handle must have at least 4-byte alignment"); -static_assert(alignof(GRCAN_Private_TxMessage) >= 4, "CubeMXCan internal GRCAN_Private_TxMessage must have at least 4-byte alignment"); -static_assert(alignof(struct CubeMXCan_Private_Handle) >= 4, "CubeMXCan internal CubeMXCan_Private_Handle must have at least 4-byte alignment"); +static_assert((offsetof(struct CubeCAN_Private_Handle, tx_head) % 4U) == 0U, "CubeCAN internal atomic tx_head is unaligned"); +static_assert((offsetof(struct CubeCAN_Private_Handle, tx_tail) % 4U) == 0U, "CubeCAN internal atomic tx_tail is unaligned"); -static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_head) % 4U) == 0U, "CubeMXCan internal atomic tx_head is unaligned"); -static_assert((offsetof(struct CubeMXCan_Private_Handle, tx_tail) % 4U) == 0U, "CubeMXCan internal atomic tx_tail is unaligned"); - -static_assert(ATOMIC_INT_LOCK_FREE == 2, "CubeMXCan internal ATOMIC_INT_LOCK_FREE must be enabled for atomic operations"); -static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "CubeMXCan internal ATOMIC_BOOL_LOCK_FREE must be enabled for atomic operations"); - -#pragma endregion - -#pragma region Configuration Checks +static_assert(ATOMIC_INT_LOCK_FREE == 2, "CubeCAN internal ATOMIC_INT_LOCK_FREE must be enabled for atomic operations"); +static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "CubeCAN internal ATOMIC_BOOL_LOCK_FREE must be enabled for atomic operations"); static_assert((CUBEMX_CAN_TX_QUEUE_SIZE > 0) && !(CUBEMX_CAN_TX_QUEUE_SIZE & (CUBEMX_CAN_TX_QUEUE_SIZE - 1U)), "CUBEMX_CAN_TX_QUEUE_SIZE must be a power of two and greater than zero"); static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "CUBEMX_CAN_MAX_INSTANCES must be configured between 1 and 3 inclusive"); - -#pragma endregion diff --git a/Lib/Peripherals/CubeCAN/Src/can_global.c b/Lib/Peripherals/CubeCAN/Src/can_global.c index 90921d16c..254508f25 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_global.c +++ b/Lib/Peripherals/CubeCAN/Src/can_global.c @@ -3,7 +3,7 @@ #include #include "CriticalSection.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" #include "PrivateInc/internal.h" -struct CubeMXCan_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; +struct CubeCAN_Private_Handle handles[CUBEMX_CAN_MAX_INSTANCES] = {0}; diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index 053ca8725..469118e5a 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -4,54 +4,54 @@ #include #include "CriticalSection.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" #include "Logomatic.h" #include "PrivateInc/internal.h" #include "main.h" -CubeMXCan_Handle *CubeMXCan_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) +CubeCAN_Handle *CubeCAN_OneShotInitStart(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) { - CubeMXCan_Handle *handle = CubeMXCan_Init(hfdcan, config); + CubeCAN_Handle *handle = CubeCAN_Init(hfdcan, config); if (handle == NULL) { - LOGOMATIC("CubeMXCan_OneShotInit: failed to initialize handle\n"); + LOGOMATIC("CubeCAN_OneShotInit: failed to initialize handle\n"); return NULL; } - if (CubeMXCan_Start(handle) != HAL_OK) { - LOGOMATIC("CubeMXCan_OneShotInit: failed to start handle\n"); - CubeMXCan_Release(handle); + if (CubeCAN_Start(handle) != HAL_OK) { + LOGOMATIC("CubeCAN_OneShotInit: failed to start handle\n"); + CubeCAN_Release(handle); return NULL; } return handle; } -HAL_StatusTypeDef CubeMXCan_OneShotReleaseStop(CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeCAN_OneShotReleaseStop(CubeCAN_Handle *handle) { if (handle == NULL) { - LOGOMATIC("CubeMXCan_OneShotReleaseStop: invalid null parameter\n"); + LOGOMATIC("CubeCAN_OneShotReleaseStop: invalid null parameter\n"); return HAL_ERROR; } - HAL_StatusTypeDef status = CubeMXCan_Stop(handle); + HAL_StatusTypeDef status = CubeCAN_Stop(handle); if (status != HAL_OK) { - LOGOMATIC("CubeMXCan_OneShotReleaseStop: failed to stop FDCAN instance\n"); + LOGOMATIC("CubeCAN_OneShotReleaseStop: failed to stop FDCAN instance\n"); return status; } - return CubeMXCan_Release(handle); + return CubeCAN_Release(handle); } -CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) +CubeCAN_Handle *CubeCAN_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *config) { if (hfdcan == NULL || config == NULL) { - LOGOMATIC("CubeMXCan_Init: invalid null parameters\n"); + LOGOMATIC("CubeCAN_Init: invalid null parameters\n"); return NULL; } - CubeMXCan_Handle *handle = NULL; + CubeCAN_Handle *handle = NULL; uint8_t free_handle_index = (uint8_t)-1; CRITICAL_SECTION @@ -66,7 +66,7 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *co } if (handle != NULL) { - LOGOMATIC("CubeMXCan_Init: handle already initialized for this FDCAN instance\n"); + LOGOMATIC("CubeCAN_Init: handle already initialized for this FDCAN instance\n"); return NULL; } else if (free_handle_index != (uint8_t)-1) { handle = &handles[free_handle_index]; @@ -80,12 +80,12 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *co } if (handle == NULL) { - LOGOMATIC("CubeMXCan_Init: no free handle slots\n"); + LOGOMATIC("CubeCAN_Init: no free handle slots\n"); return NULL; } if (HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_EVENTS, 0U) != HAL_OK) { - LOGOMATIC("CubeMXCan_Init: failed to activate RX notifications\n"); + LOGOMATIC("CubeCAN_Init: failed to activate RX notifications\n"); CRITICAL_SECTION { memset(handle, 0, sizeof(*handle)); @@ -96,7 +96,7 @@ CubeMXCan_Handle *CubeMXCan_Init(FDCAN_HandleTypeDef *hfdcan, CubeCAN_Config *co return handle; } -HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) +HAL_StatusTypeDef CubeCAN_Release(CubeCAN_Handle *handle) { if (handle == NULL) { return HAL_ERROR; @@ -124,7 +124,7 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) } if (status != HAL_OK) { - LOGOMATIC("CubeMXCan_Release: peripheral deactivation failed\n"); + LOGOMATIC("CubeCAN_Release: peripheral deactivation failed\n"); CRITICAL_SECTION { @@ -142,7 +142,7 @@ HAL_StatusTypeDef CubeMXCan_Release(CubeMXCan_Handle *handle) return HAL_OK; } -HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle) +HAL_StatusTypeDef CubeCAN_Start(CubeCAN_Handle *const handle) { if (handle == NULL) { return HAL_ERROR; @@ -175,7 +175,7 @@ HAL_StatusTypeDef CubeMXCan_Start(CubeMXCan_Handle *const handle) return status; } -HAL_StatusTypeDef CubeMXCan_Stop(CubeMXCan_Handle *const handle) +HAL_StatusTypeDef CubeCAN_Stop(CubeCAN_Handle *const handle) { if (handle == NULL) { return HAL_ERROR; diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index a520b6bac..19c8f2899 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -2,7 +2,7 @@ #include #include "CriticalSection.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" #include "Logomatic.h" #include "PrivateInc/internal.h" #include "Unused.h" @@ -52,7 +52,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0U) { if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { CAN_Identifier id = Deconstruct_CAN_Identifier(rx_header.Identifier); - uint8_t size = CubeMXCan_Private_DlcToBytes(rx_header.DataLength); + uint8_t size = CubeCAN_Private_DlcToBytes(rx_header.DataLength); rx_callback(user_context, &id, rx_data, size); } else { LOGOMATIC("HAL_FDCAN_RxFifo0Callback: Failed to get Rx message from FIFO\n"); diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index 5cf78ae52..4ed3c207b 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -3,41 +3,41 @@ #include #include "CriticalSection.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" #include "Logomatic.h" #include "PrivateInc/internal.h" #include "main.h" -void CubeMXCan_Tick(void) +void CubeCAN_Tick(void) { for (uint8_t i = 0U; i < CUBEMX_CAN_MAX_INSTANCES; ++i) { - CubeMXCan_Handle *handle = &handles[i]; + CubeCAN_Handle *handle = &handles[i]; if (handle->hfdcan == NULL || !handle->started) { continue; } - if (CubeMXCan_Private_IsDisabled(handle)) { - LOGOMATIC("CubeMXCan_Tick: currently in restricted operation mode\n"); - if (CubeMXCan_Private_RecoverPeripheral(handle) != HAL_OK) { - LOGOMATIC("CubeMXCan_Tick %d: failed to recover peripheral\n", (int)i); + if (CubeCAN_Private_IsDisabled(handle)) { + LOGOMATIC("CubeCAN_Tick: currently in restricted operation mode\n"); + if (CubeCAN_Private_RecoverPeripheral(handle) != HAL_OK) { + LOGOMATIC("CubeCAN_Tick %d: failed to recover peripheral\n", (int)i); continue; } } - (void)CubeMXCan_Private_SendQueuedMessage(handle); + (void)CubeCAN_Private_SendQueuedMessage(handle); } } -HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size) +HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size) { if (handle == NULL || data == NULL || size > FDCAN_MAX_DATA_BYTES) { return HAL_ERROR; } - const uint32_t dlc = CubeMXCan_Private_BytesToDlc(size); + const uint32_t dlc = CubeCAN_Private_BytesToDlc(size); if (dlc == FDCAN_DLC_BYTES_0 && size != 0) { - LOGOMATIC("CubeMXCan_Send: invalid data length code\n"); + LOGOMATIC("CubeCAN_Send: invalid data length code\n"); return HAL_ERROR; } @@ -57,14 +57,14 @@ HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NOD brs = FDCAN_BRS_ON; break; default: - LOGOMATIC("CubeMXCan_Send: unsupported frame format\n"); + LOGOMATIC("CubeCAN_Send: unsupported frame format\n"); return HAL_ERROR; } const CAN_Identifier identifier_struct = {.tx_node_id = handle->config.sending_node_id, .rx_node_id = rx_node, .msg_id = msg_id}; const FDCAN_TxHeaderTypeDef header = {.BitRateSwitch = brs, - .DataLength = CubeMXCan_Private_BytesToDlc(size), + .DataLength = CubeCAN_Private_BytesToDlc(size), .ErrorStateIndicator = FDCAN_ESI_ACTIVE, .FDFormat = fdformat, .Identifier = Construct_CAN_Identifier(&identifier_struct), @@ -76,10 +76,10 @@ HAL_StatusTypeDef CubeMXCan_Send(CubeMXCan_Handle *const handle, const GRCAN_NOD GRCAN_Private_TxMessage message = {.tx_header = header}; memcpy(message.data, data, size); - return CubeMXCan_Private_QueueTx(handle, &message); + return CubeCAN_Private_QueueTx(handle, &message); } -HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *handle, const GRCAN_Private_TxMessage *message) +HAL_StatusTypeDef CubeCAN_Private_QueueTx(CubeCAN_Handle *handle, const GRCAN_Private_TxMessage *message) { if (handle == NULL || message == NULL) { return HAL_ERROR; @@ -105,15 +105,15 @@ HAL_StatusTypeDef CubeMXCan_Private_QueueTx(CubeMXCan_Handle *handle, const GRCA return status; } -HAL_StatusTypeDef CubeMXCan_Private_SendQueuedMessage(const CubeMXCan_Handle *const handle) +HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(const CubeCAN_Handle *const handle) { if (handle == NULL || handle->hfdcan == NULL) { - LOGOMATIC("CubeMXCan_Private_SendQueuedMessage: invalid null parameter\n"); + LOGOMATIC("CubeCAN_Private_SendQueuedMessage: invalid null parameter\n"); return HAL_ERROR; } if (HAL_FDCAN_GetTxFifoFreeLevel(handle->hfdcan) == 0U) { - LOGOMATIC("CubeMXCan_Private_SendQueuedMessage: Tx FIFO full, cannot send message\n"); + LOGOMATIC("CubeCAN_Private_SendQueuedMessage: Tx FIFO full, cannot send message\n"); return HAL_BUSY; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_utils.c b/Lib/Peripherals/CubeCAN/Src/can_utils.c index 8b66dd76e..b0233e1d6 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_utils.c +++ b/Lib/Peripherals/CubeCAN/Src/can_utils.c @@ -3,7 +3,7 @@ #include #include "CriticalSection.h" -#include "CubeMXCan.h" +#include "CubeCAN.h" #include "GRCAN_MSG_ID.h" #include "GRCAN_NODE_ID.h" #include "Logomatic.h" @@ -53,10 +53,10 @@ HAL_StatusTypeDef CubeCANExt_BuildExtendedFilter(const CAN_Identifier *const ide return HAL_OK; } -HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, const FDCAN_FilterTypeDef *filter) +HAL_StatusTypeDef CubeCAN_AddFilter(const CubeCAN_Handle *const handle, const FDCAN_FilterTypeDef *filter) { if (handle == NULL || filter == NULL) { - LOGOMATIC("CubeMXCan_AddFilter: Invalid handle or filter pointer\n"); + LOGOMATIC("CubeCAN_AddFilter: Invalid handle or filter pointer\n"); return HAL_ERROR; } @@ -72,7 +72,7 @@ HAL_StatusTypeDef CubeMXCan_AddFilter(const CubeMXCan_Handle *const handle, cons return status; } -uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes) +uint8_t CubeCAN_Private_BytesToDlc(const uint8_t bytes) { switch (bytes) { case 0U: @@ -108,12 +108,12 @@ uint8_t CubeMXCan_Private_BytesToDlc(const uint8_t bytes) case 64U: return FDCAN_DLC_BYTES_64; default: - LOGOMATIC("CubeMXCan_Private_BytesToDlc: Invalid byte count\n"); + LOGOMATIC("CubeCAN_Private_BytesToDlc: Invalid byte count\n"); return FDCAN_DLC_BYTES_0; } } -uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc) +uint8_t CubeCAN_Private_DlcToBytes(const uint32_t dlc) { switch (dlc) { case FDCAN_DLC_BYTES_0: @@ -149,12 +149,12 @@ uint8_t CubeMXCan_Private_DlcToBytes(const uint32_t dlc) case FDCAN_DLC_BYTES_64: return 64U; default: - LOGOMATIC("CubeMXCan_Private_DlcToBytes: Invalid DLC value\n"); + LOGOMATIC("CubeCAN_Private_DlcToBytes: Invalid DLC value\n"); return 0U; } } -bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle) +bool CubeCAN_Private_IsDisabled(const CubeCAN_Handle *const handle) { if (handle == NULL) { return true; @@ -181,7 +181,7 @@ bool CubeMXCan_Private_IsDisabled(const CubeMXCan_Handle *const handle) return disabled; } -HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *const handle) +HAL_StatusTypeDef CubeCAN_Private_RecoverPeripheral(const CubeCAN_Handle *const handle) { if (handle == NULL) { return HAL_ERROR; @@ -195,7 +195,7 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *co FDCAN_ProtocolStatusTypeDef protocol_status = {0}; if (HAL_FDCAN_GetProtocolStatus(handle->hfdcan, &protocol_status) == HAL_OK && protocol_status.BusOff) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: CRITICAL BUS-OFF DETECTED. Forcing instant hardware reset...\n"); + LOGOMATIC("CubeCAN_Private_RecoverPeripheral: CRITICAL BUS-OFF DETECTED. Forcing instant hardware reset...\n"); HAL_FDCAN_Stop(handle->hfdcan); @@ -210,12 +210,12 @@ HAL_StatusTypeDef CubeMXCan_Private_RecoverPeripheral(const CubeMXCan_Handle *co } if (status != HAL_OK) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: Aggressive hardware start failed!\n"); + LOGOMATIC("CubeCAN_Private_RecoverPeripheral: Aggressive hardware start failed!\n"); } } if (HAL_FDCAN_IsRestrictedOperationMode(handle->hfdcan)) { - LOGOMATIC("CubeMXCan_Private_RecoverPeripheral: Forcing exit from restricted operation mode\n"); + LOGOMATIC("CubeCAN_Private_RecoverPeripheral: Forcing exit from restricted operation mode\n"); HAL_FDCAN_ExitRestrictedOperationMode(handle->hfdcan); } } diff --git a/Lib/Peripherals/CubeCAN/cubemx_can.cmake b/Lib/Peripherals/CubeCAN/cube_can.cmake similarity index 100% rename from Lib/Peripherals/CubeCAN/cubemx_can.cmake rename to Lib/Peripherals/CubeCAN/cube_can.cmake