Merge pull request 'Implement CAN read RTOS' (#14) from j1939 into main

This commit is contained in:
2026-06-15 10:30:34 +02:00
8 changed files with 708 additions and 1021 deletions
+3 -1
View File
@@ -8,4 +8,6 @@
.metadata .metadata
Core/Src/Backup/ Core/Src/Backup/
Core/Inc/Backup/ Core/Inc/Backup/
Debug .bak
.gitignore
can_logger Debug.launch
+49
View File
@@ -1,7 +1,53 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : canlog.h
* @brief : Header for canlog.c file.
* This file contains the defines related to SAE J1939 CAN.
******************************************************************************
* @attention
*
* Copyright (c) 2026 Erick Ahmed.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef CANLOG_H #ifndef CANLOG_H
#define CANLOG_H #define CANLOG_H
#include "main.h" #include "main.h"
#include "cmsis_os.h"
extern osMessageQueueId_t xCAN1RxQueue;
extern osMessageQueueId_t xCAN2RxQueue;
extern osSemaphoreId_t xSemaphoreCAN1;
extern osSemaphoreId_t xSemaphoreCAN2;
/* USER CODE BEGIN PTD */
typedef struct {
GPIO_TypeDef* port;
uint16_t pin;
} LED_Config;
typedef struct {
uint32_t id;
uint8_t payload[8];
uint8_t dlc;
uint8_t isExtended;
//uint32_t timestamp; //Enable TIM2: 42 MHz / (41+1) = 1 MHz → 1 µs tick; 32bit autoreload freerunning
// this is for getting timestamps on can messages
} CanMessage_t;
typedef struct {
LED_Config *led;
osSemaphoreId_t semaphore;
osTimerId_t timer;
} LEDContext;
/* USER CODE END PTD */
/** /**
* @brief Initializes the CAN logger modules, OS threads, queues, and hardware. * @brief Initializes the CAN logger modules, OS threads, queues, and hardware.
@@ -9,5 +55,8 @@
* @param hcan2 Pointer to the CAN2 handle * @param hcan2 Pointer to the CAN2 handle
*/ */
void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2); void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
void vCANLoggerListen(void *argument);
void vLEDHeartbeat(void *argument);
#endif /* CANLOG_H */ #endif /* CANLOG_H */
+3 -4
View File
@@ -8,11 +8,9 @@
* @attention * @attention
* *
* Copyright (c) 2026 STMicroelectronics. * Copyright (c) 2026 STMicroelectronics.
* All rights reserved. * Copyright (c) 2026 Erick Ahmed.
* *
* This software is licensed under terms that can be found in the LICENSE file * SPDX-License-Identifier: GPL-3.0-or-later
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
* *
****************************************************************************** ******************************************************************************
*/ */
@@ -28,6 +26,7 @@ extern "C" {
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h" #include "stm32f4xx_hal.h"
#include "canlog.h"
/* Private includes ----------------------------------------------------------*/ /* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */ /* USER CODE BEGIN Includes */
-435
View File
@@ -1,435 +0,0 @@
/**
******************************************************************************
* @file newlib_lock_glue.c
* @author STMicroelectronics
* @brief Implementation of newlib lock interface
*
* @details This file implements locking glue necessary to protect C library
* functions and initialization of local static objects in C++.
* Lock strategies are defined in stm32_lock.h that implements
* different level of thread-safety.
*
* For more information about which C functions need which of these
* low level functions, please consult the newlib libc manual,
* see https://sourceware.org/newlib/libc.html
*
* For more information about the one-time construction API for C++,
* see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
*
******************************************************************************
* @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.
*
******************************************************************************
*/
#if !defined (__GNUC__) || defined (__CC_ARM)
#error "newlib_lock_glue.c" should be used with GNU Compilers only
#endif /* !defined (__GNUC__) || defined (__CC_ARM) */
/* Includes ------------------------------------------------------------------*/
#include <cmsis_compiler.h>
/* Private functions prototypes ----------------------------------------------*/
__WEAK void Error_Handler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Global Error_Handler
*/
__WEAK void Error_Handler(void)
{
/* Not used if it exists in project */
while (1);
}
#ifdef __SINGLE_THREAD__
#warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts
#else
/* Includes ------------------------------------------------------------------*/
#include <newlib.h>
#include <stdatomic.h>
#include "stm32_lock.h"
/**
* @defgroup _newlib_lock_functions newlib library locks
* @see https://sourceware.org/newlib/libc.html
* @{
*/
#if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING)
#include <errno.h>
#include <stdlib.h>
#include <sys/lock.h>
/* Private macros ------------------------------------------------------------*/
/** See struct __lock definition */
#define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data)
/* shared variables for bare metal allow lock ------------------------------------------------------*/
#if defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0)
uint32_t gflag = 0;
uint32_t call_counter = 0;
#endif /* defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0) */
/* Private variables ---------------------------------------------------------*/
struct __lock
{
LockingData_t lock_data; /**< The STM32 lock instance */
};
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT };
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initialize lock
* @param lock The lock
*/
void __retarget_lock_init(_LOCK_T *lock)
{
__retarget_lock_init_recursive(lock);
}
/**
* @brief Initialize recursive lock
* @param lock The lock
*/
void __retarget_lock_init_recursive(_LOCK_T *lock)
{
if (lock == NULL)
{
errno = EINVAL;
return;
}
*lock = (_LOCK_T)malloc(sizeof(struct __lock));
if (*lock != NULL)
{
stm32_lock_init(STM32_LOCK_PARAMETER(*lock));
return;
}
/* Unable to allocate memory */
STM32_LOCK_BLOCK();
}
/**
* @brief Close lock
* @param lock The lock
*/
void __retarget_lock_close(_LOCK_T lock)
{
__retarget_lock_close_recursive(lock);
}
/**
* @brief Close recursive lock
* @param lock The lock
*/
void __retarget_lock_close_recursive(_LOCK_T lock)
{
free(lock);
}
/**
* @brief Acquire lock
* @param lock The lock
*/
void __retarget_lock_acquire(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Acquire recursive lock
* @param lock The lock
*/
void __retarget_lock_acquire_recursive(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Try acquire lock
* @param lock The lock
* @return 0 always
*/
int __retarget_lock_try_acquire(_LOCK_T lock)
{
__retarget_lock_acquire(lock);
return 0;
}
/**
* @brief Try acquire recursive lock
* @param lock The lock
* @return 0 always
*/
int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
{
__retarget_lock_acquire_recursive(lock);
return 0;
}
/**
* @brief Release lock
* @param lock The lock
*/
void __retarget_lock_release(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_release(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Release recursive lock
* @param lock The lock
*/
void __retarget_lock_release_recursive(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_release(STM32_LOCK_PARAMETER(lock));
}
#else
#warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib
/* Includes ------------------------------------------------------------------*/
#include <reent.h>
/* Private variables ---------------------------------------------------------*/
/** Mutex used in __malloc_lock and __malloc_unlock */
static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT;
/** Mutex used in __env_lock and __env_unlock */
static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT;
/** Mutex used in __tz_lock and __tz_unlock */
static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT;
/* Private functions ---------------------------------------------------------*/
#if __STD_C
/**
* @brief Acquire malloc lock
* @param reent The reentrance struct
*/
void __malloc_lock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_acquire(&__lock___malloc_recursive_mutex);
}
/**
* @brief Release malloc lock
* @param reent The reentrance struct
*/
void __malloc_unlock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_release(&__lock___malloc_recursive_mutex);
}
#else
/**
* @brief Acquire malloc lock
*/
void __malloc_lock()
{
stm32_lock_acquire(&__lock___malloc_recursive_mutex);
}
/**
* @brief Release malloc lock
*/
void __malloc_unlock()
{
stm32_lock_release(&__lock___malloc_recursive_mutex);
}
#endif /* __STD_C */
/**
* @brief Acquire env lock
* @param reent The reentrance struct
*/
void __env_lock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_acquire(&__lock___env_recursive_mutex);
}
/**
* @brief Release env lock
* @param reent The reentrance struct
*/
void __env_unlock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_release(&__lock___env_recursive_mutex);
}
/**
* @brief Acquire tz lock
*/
void __tz_lock()
{
stm32_lock_acquire(&__lock___tz_mutex);
}
/**
* @brief Release tz lock
*/
void __tz_unlock()
{
stm32_lock_release(&__lock___tz_mutex);
}
#endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */
/**
* @}
*/
/**
* @defgroup __cxa_guard_ GNU C++ one-time construction API
* @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
*
* When building for C++, please make sure that <tt>-fno-threadsafe-statics</tt> is not passed to the compiler
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */
typedef struct
{
atomic_uchar initialized; /**< Indicate if object is initialized */
uint8_t acquired; /**< Ensure non-recursive lock */
uint16_t unused; /**< Padding */
} __attribute__((packed)) CxaGuardObject_t;
/* Private variables ---------------------------------------------------------*/
/** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */
static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT;
/* Private functions prototype ---------------------------------------------------------*/
int __cxa_guard_acquire(CxaGuardObject_t *guard_object);
void __cxa_guard_abort(CxaGuardObject_t *guard_object);
void __cxa_guard_release(CxaGuardObject_t *guard_object);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Acquire __cxa_guard mutex
* @param guard_object Guard object
* @return 0 if object is initialized, else initialization of object required
*/
int __cxa_guard_acquire(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
if (atomic_load(&guard_object->initialized) == 0)
{
/* Object needs initialization, lock threading context */
stm32_lock_acquire(&__cxa_guard_mutex);
if (atomic_load(&guard_object->initialized) == 0)
{
/* Object needs initialization */
if (guard_object->acquired)
{
/* Object initialization already in progress */
STM32_LOCK_BLOCK();
}
/* Lock acquired */
guard_object->acquired = 1;
return 1;
}
else
{
/* Object initialized in another thread */
stm32_lock_release(&__cxa_guard_mutex);
}
}
/* Object already initialized */
return 0;
}
/**
* @brief Abort __cxa_guard mutex
* @param guard_object Guard object
*/
void __cxa_guard_abort(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
if (guard_object->acquired)
{
/* Release lock */
guard_object->acquired = 0;
stm32_lock_release(&__cxa_guard_mutex);
}
else
{
/* Trying to release non-acquired lock */
STM32_LOCK_BLOCK();
}
}
/**
* @brief Release __cxa_guard mutex
* @param guard_object Guard object
*/
void __cxa_guard_release(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
/* Object initialized */
atomic_store(&guard_object->initialized, 1);
/* Release lock */
__cxa_guard_abort(guard_object);
}
/**
* @}
*/
#endif /* __SINGLE_THREAD__ */
+127 -24
View File
@@ -1,40 +1,143 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : canlog.c
* @brief : SAE J1939 CAN Real Time listening and decoding
******************************************************************************
* @attention
*
* Copyright (c) 2026 Erick Ahmed.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "canlog.h" #include "canlog.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h" #include "cmsis_os.h"
#include <string.h> #include <string.h>
/* USER CODE END Includes */
/* Definitions for canBus1Listen */ extern CAN_HandleTypeDef hcan1;
osThreadId_t canBus1ListenHandle; extern CAN_HandleTypeDef hcan2;
const osThreadAttr_t canBus1Listen_attributes = {
.name = "canBus1Listen",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityRealtime1,
};
/* Definitions for canBus2Listen */
osThreadId_t canBus2ListenHandle;
const osThreadAttr_t canBus2Listen_attributes = {
.name = "canBus2Listen",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityRealtime,
};
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2){} /* USER CODE BEGIN FunctionPrototypes */
static void CAN_Listen(void *argument){} /* BEGIN CAN_Logger_Init */
/* BEGIN Header_CAN_Listen */
/** /**
* @brief Function implementing the canBus0Listen thread. * @brief Initialize CAN bus logger.
* @param argument: hcan1, hcan2
* @retval None
*/
void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2)
{
CAN_FilterTypeDef filter = {0};
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterIdHigh = 0x0000;
filter.FilterMaskIdHigh = 0x0000;
filter.FilterIdLow = 0x0000;
filter.FilterMaskIdLow = 0x0000;
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
filter.FilterActivation = ENABLE;
filter.SlaveStartFilterBank = 14;
filter.FilterBank = 0;
if (HAL_CAN_ConfigFilter(hcan1, &filter) != HAL_OK) Error_Handler();
filter.FilterBank = 14;
if (HAL_CAN_ConfigFilter(hcan2, &filter) != HAL_OK) Error_Handler();
if (HAL_CAN_Start(hcan1) != HAL_OK) Error_Handler();
if (HAL_CAN_Start(hcan2) != HAL_OK) Error_Handler();
if (HAL_CAN_ActivateNotification(hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) Error_Handler();
if (HAL_CAN_ActivateNotification(hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) Error_Handler();
}
/* END CAN_Logger_Init */
/* BEGIN HAL_CAN_RxFifo0MsgPendingCallback */
/**
* @brief ISR for CAN message pending in FIFO0
* @param argument: Can handle hcan (hcan1 or hcan2)
* @retval None
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
/* CODE BEGIN */
CanMessage_t message;
CAN_RxHeaderTypeDef rxHeader;
uint8_t data[8];
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, data) != HAL_OK) Error_Handler();
message.id = rxHeader.ExtId;
message.dlc = rxHeader.DLC;
message.isExtended = (rxHeader.IDE == CAN_ID_EXT);
memcpy(message.payload, data, rxHeader.DLC);
osMessageQueueId_t queue = (hcan->Instance == CAN1) ? xCAN1RxQueue : xCAN2RxQueue;
if (osMessageQueuePut(queue, &message, 0U, 0U) != osOK)
{
// TODO: better handling: flash error_led on osTimeout, call Error_Handler() when other errors
// send errors like queue full via UART
}
/* CODE END */
}
/* END HAL_CAN_RxFifo0MsgPendingCallback */
/* BEGIN vCANLoggerListen */
/**
* @brief Log incoming CAN bus traffic in FIFO buffer
* @param argument: Not used * @param argument: Not used
* @retval None * @retval None
*/ */
/* END Header_CAN_Listen */ void vCANLoggerListen(void *argument)
void CAN_Listen(void *argument) {
/* CODE BEGIN */
CAN_HandleTypeDef *hcan = (CAN_HandleTypeDef*)argument;
osMessageQueueId_t queue;
CanMessage_t message;
queue = (hcan->Instance == CAN1) ? xCAN1RxQueue : xCAN2RxQueue;
for (;;)
{
if (osMessageQueueGet(queue, &message, NULL, osWaitForever) == osOK)
{
osSemaphoreRelease( (hcan->Instance == CAN1) ? xSemaphoreCAN1 : xSemaphoreCAN2 );
// TODO: use this semaphore
}
}
/* CODE END */
}
/* END vCANLoggerListen */
/* BEGIN vLEDHeartbeat */
/**
* @brief Blink a LED in heartbeat mode when CAN traffic is detected
* @param argument: LED GPIO (port and pin)
* @retval None
*/
void vLEDHeartbeat(void *argument)
{ {
/* CODE BEGIN */ /* CODE BEGIN */
/* Infinite loop */ LEDContext *context = (LEDContext*)argument;
for(;;)
if (osSemaphoreAcquire(context->semaphore, 0U) == osOK)
{ {
osDelay(1); HAL_GPIO_WritePin(context->led->port, context->led->pin, GPIO_PIN_SET);
osTimerStart(context->timer, 25U);
}
else
{
HAL_GPIO_WritePin(context->led->port, context->led->pin, GPIO_PIN_RESET);
} }
/* CODE END */ /* CODE END */
} }
/* END vLEDHeartbeat */
/* USER CODE END FunctionPrototypes */
-59
View File
@@ -1,59 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @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 "FreeRTOS.h"
#include "task.h"
#include "main.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 ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
+526 -460
View File
@@ -1,460 +1,526 @@
/* USER CODE BEGIN Header */ /* USER CODE BEGIN Header */
/** /**
****************************************************************************** ******************************************************************************
* @file : main.c * @file : main.c
* @brief : Main program body * @brief : Main program body
****************************************************************************** ******************************************************************************
* @attention * @attention
* * Copyright (c) 2026 STMicroelectronics.
* Copyright (c) 2026 STMicroelectronics. * Copyright (c) 2026 Erick Ahmed.
* All rights reserved. *
* * SPDX-License-Identifier: GPL-3.0-or-later
* 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 END Header */ #include "cmsis_os.h"
/* Includes ------------------------------------------------------------------*/
#include "main.h" /* Private includes ----------------------------------------------------------*/
#include "canlog.h" /* USER CODE BEGIN Includes */
#include "cmsis_os.h" #include "canlog.h"
/* USER CODE END Includes */
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */ /* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END Includes */ /* USER CODE END PTD */
/* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PTD */ /* USER CODE BEGIN PD */
/* USER CODE END PTD */ /* USER CODE END PD */
/* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PD */ /* USER CODE BEGIN PM */
/* USER CODE END PD */ /* USER CODE END PM */
/* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PM */ CAN_HandleTypeDef hcan1;
CAN_HandleTypeDef hcan2;
/* USER CODE END PM */
SD_HandleTypeDef hsd;
/* Private variables ---------------------------------------------------------*/ DMA_HandleTypeDef hdma_sdio_rx;
CAN_HandleTypeDef hcan1; DMA_HandleTypeDef hdma_sdio_tx;
CAN_HandleTypeDef hcan2;
/* USER CODE BEGIN PV */
SD_HandleTypeDef hsd; LED_Config led_can1 = {GPIOB, GPIO_PIN_2};
DMA_HandleTypeDef hdma_sdio_rx; LED_Config led_can2 = {GPIOB, GPIO_PIN_5};
DMA_HandleTypeDef hdma_sdio_tx; LED_Config led_error = {GPIOB, GPIO_PIN_3};
/* USER CODE BEGIN PV */ LEDContext ledContextCAN1;
LEDContext ledContextCAN2;
/* USER CODE END PV */
osSemaphoreId_t xSemaphoreCAN1;
/* Private function prototypes -----------------------------------------------*/ osSemaphoreId_t xSemaphoreCAN2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void); osTimerId_t xHeartbeatTimerCAN1;
static void MX_DMA_Init(void); osTimerId_t xHeartbeatTimerCAN2;
static void MX_CAN1_Init(void);
static void MX_CAN2_Init(void); osMessageQueueId_t xCAN1RxQueue;
static void MX_SDIO_SD_Init(void); osMessageQueueId_t xCAN2RxQueue;
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */ void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* Private user code ---------------------------------------------------------*/ static void MX_DMA_Init(void);
/* USER CODE BEGIN 0 */ static void MX_CAN1_Init(void);
static void MX_CAN2_Init(void);
/* USER CODE END 0 */ static void MX_SDIO_SD_Init(void);
/** /* USER CODE BEGIN PFP */
* @brief The application entry point. /* USER CODE END PFP */
* @retval int
*/ /* Private user code ---------------------------------------------------------*/
int main(void) /* USER CODE BEGIN 0 */
{
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
/**
/* USER CODE END 1 */ * @brief The application entry point.
* @retval int
/* MCU Configuration--------------------------------------------------------*/ */
int main(void)
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */ {
HAL_Init();
/* USER CODE BEGIN 1 */
/* USER CODE BEGIN Init */
/* USER CODE END 1 */
/* USER CODE END Init */
/* MCU Configuration--------------------------------------------------------*/
/* Configure the system clock */
SystemClock_Config(); /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN SysInit */
/* USER CODE BEGIN Init */
/* USER CODE END SysInit */
/* USER CODE END Init */
/* Initialize all configured peripherals */
MX_GPIO_Init(); /* Configure the system clock */
MX_DMA_Init(); SystemClock_Config();
MX_CAN1_Init();
MX_CAN2_Init(); /* USER CODE BEGIN SysInit */
MX_SDIO_SD_Init();
/* USER CODE BEGIN 2 */ /* USER CODE END SysInit */
// Initialize CAN1 and CAN2 /* Initialize all configured peripherals */
CAN_Logger_Init(&hcan1, &hcan2); MX_GPIO_Init();
MX_DMA_Init();
/* USER CODE END 2 */ MX_CAN1_Init();
MX_CAN2_Init();
/* Init scheduler */ MX_SDIO_SD_Init();
osKernelInitialize();
/* USER CODE BEGIN 2 */
/* USER CODE BEGIN RTOS_MUTEX */ CAN_Logger_Init(&hcan1, &hcan2);
/* add mutexes, ... */ /* USER CODE END 2 */
/* USER CODE END RTOS_MUTEX */
/* Init scheduler */
/* USER CODE BEGIN RTOS_SEMAPHORES */ osKernelInitialize();
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TASKS */
osThreadId_t xCAN1rx;
/* USER CODE BEGIN RTOS_TIMERS */ const osThreadAttr_t CAN1rxAttributes = {
/* start timers, add new ones, ... */ .name = "CAN1rx",
/* USER CODE END RTOS_TIMERS */ .stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityRealtime1,
/* USER CODE BEGIN RTOS_QUEUES */ };
/* add queues, ... */ osThreadId_t xCAN2rx;
/* USER CODE END RTOS_QUEUES */ const osThreadAttr_t CAN2rxAttributes = {
.name = "CAN2rx",
/* USER CODE BEGIN RTOS_THREADS */ .stack_size = 128 * 4,
/* add threads, ... */ .priority = (osPriority_t) osPriorityRealtime,
/* USER CODE END RTOS_THREADS */ };
/* USER END RTOS_TASKS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */ /* USER CODE BEGIN RTOS_MUTEX */
/* USER CODE END RTOS_EVENTS */ /* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* Start scheduler */
osKernelStart(); /* USER CODE BEGIN RTOS_SEMAPHORES */
xSemaphoreCAN1 = osSemaphoreNew(10, 0, NULL);
/* We should never get here as control is now taken by the scheduler */ xSemaphoreCAN2 = osSemaphoreNew(10, 0, NULL);
/* Infinite loop */ if (xSemaphoreCAN1 == NULL || xSemaphoreCAN2 == NULL) Error_Handler();
/* USER CODE BEGIN WHILE */
while (1) ledContextCAN1.led = &led_can1;
{ ledContextCAN1.semaphore = xSemaphoreCAN1;
/* USER CODE END WHILE */ ledContextCAN2.led = &led_can2;
ledContextCAN2.semaphore = xSemaphoreCAN2;
/* USER CODE BEGIN 3 */ /* USER CODE END RTOS_SEMAPHORES */
}
/* USER CODE END 3 */ /* USER CODE BEGIN RTOS_TIMERS */
} xHeartbeatTimerCAN1 = osTimerNew(vLEDHeartbeat, osTimerOnce, &ledContextCAN1, NULL);
xHeartbeatTimerCAN2 = osTimerNew(vLEDHeartbeat, osTimerOnce, &ledContextCAN2, NULL);
/**
* @brief System Clock Configuration osTimerStart(xHeartbeatTimerCAN1, 25U);
* @retval None osTimerStart(xHeartbeatTimerCAN2, 25U);
*/
void SystemClock_Config(void) if (xHeartbeatTimerCAN1 == NULL || xHeartbeatTimerCAN2 == NULL) Error_Handler();
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; ledContextCAN1.timer = xHeartbeatTimerCAN1;
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; ledContextCAN2.timer = xHeartbeatTimerCAN2;
/* USER CODE END RTOS_TIMERS */
/** Configure the main internal regulator output voltage
*/ /* USER CODE BEGIN RTOS_QUEUES */
__HAL_RCC_PWR_CLK_ENABLE(); xCAN1RxQueue = osMessageQueueNew(32, sizeof(CanMessage_t), NULL);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); xCAN2RxQueue = osMessageQueueNew(32, sizeof(CanMessage_t), NULL);
/** Initializes the RCC Oscillators according to the specified parameters if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL) Error_Handler();
* in the RCC_OscInitTypeDef structure. /* USER CODE END RTOS_QUEUES */
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; /* USER CODE BEGIN RTOS_THREADS */
RCC_OscInitStruct.HSIState = RCC_HSI_ON; xCAN1rx = osThreadNew(vCANLoggerListen, &hcan1, &CAN1rxAttributes);
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; xCAN2rx = osThreadNew(vCANLoggerListen, &hcan2, &CAN2rxAttributes);
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; /* USER CODE END RTOS_THREADS */
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16; /* USER CODE BEGIN RTOS_EVENTS */
RCC_OscInitStruct.PLL.PLLN = 336; /* add events, ... */
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; /* USER CODE END RTOS_EVENTS */
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) /* USER CODE BEGIN 3 */
{ ledContextCAN1.led = &led_can1;
Error_Handler(); ledContextCAN1.semaphore = xSemaphoreCAN1;
} ledContextCAN1.timer = xHeartbeatTimerCAN1;
/** Initializes the CPU, AHB and APB buses clocks ledContextCAN2.led = &led_can2;
*/ ledContextCAN2.semaphore = xSemaphoreCAN2;
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK ledContextCAN2.timer = xHeartbeatTimerCAN2;
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; /* USER CODE END 3 */
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; /* Start scheduler */
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; osKernelStart();
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
/* We should never get here as control is now taken by the scheduler */
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{ /* Infinite loop */
Error_Handler(); /* USER CODE BEGIN WHILE */
} while (1)
} {
/* USER CODE END WHILE */
/**
* @brief CAN1 Initialization Function /* USER CODE BEGIN 4 */
* @param None }
* @retval None /* USER CODE END 4 */
*/ }
static void MX_CAN1_Init(void)
{ /**
* @brief System Clock Configuration
/* USER CODE BEGIN CAN1_Init 0 */ * @retval None
*/
/* USER CODE END CAN1_Init 0 */ void SystemClock_Config(void)
{
/* USER CODE BEGIN CAN1_Init 1 */ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1; /** Configure the main internal regulator output voltage
hcan1.Init.Prescaler = 4; */
hcan1.Init.Mode = CAN_MODE_SILENT; __HAL_RCC_PWR_CLK_ENABLE();
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
hcan1.Init.TimeSeg1 = CAN_BS1_16TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; /** Initializes the RCC Oscillators according to the specified parameters
hcan1.Init.TimeTriggeredMode = DISABLE; * in the RCC_OscInitTypeDef structure.
hcan1.Init.AutoBusOff = DISABLE; */
hcan1.Init.AutoWakeUp = DISABLE; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
hcan1.Init.AutoRetransmission = DISABLE; RCC_OscInitStruct.HSIState = RCC_HSI_ON;
hcan1.Init.ReceiveFifoLocked = DISABLE; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
hcan1.Init.TransmitFifoPriority = DISABLE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
if (HAL_CAN_Init(&hcan1) != HAL_OK) RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
{ RCC_OscInitStruct.PLL.PLLM = 16;
Error_Handler(); RCC_OscInitStruct.PLL.PLLN = 336;
} RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
/* USER CODE BEGIN CAN1_Init 2 */ RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
/* USER CODE END CAN1_Init 2 */ {
Error_Handler();
} }
/** /** Initializes the CPU, AHB and APB buses clocks
* @brief CAN2 Initialization Function */
* @param None RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
* @retval None |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
*/ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
static void MX_CAN2_Init(void) RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
{ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
/* USER CODE BEGIN CAN2_Init 0 */
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
/* USER CODE END CAN2_Init 0 */ {
Error_Handler();
/* USER CODE BEGIN CAN2_Init 1 */ }
}
/* USER CODE END CAN2_Init 1 */
hcan2.Instance = CAN2; /**
hcan2.Init.Prescaler = 8; * @brief CAN1 Initialization Function
hcan2.Init.Mode = CAN_MODE_SILENT; * @param None
hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; * @retval None
hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; */
hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; static void MX_CAN1_Init(void)
hcan2.Init.TimeTriggeredMode = DISABLE; {
hcan2.Init.AutoBusOff = DISABLE;
hcan2.Init.AutoWakeUp = DISABLE; /* USER CODE BEGIN CAN1_Init 0 */
hcan2.Init.AutoRetransmission = DISABLE;
hcan2.Init.ReceiveFifoLocked = DISABLE; /* USER CODE END CAN1_Init 0 */
hcan2.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan2) != HAL_OK) /* USER CODE BEGIN CAN1_Init 1 */
{
Error_Handler(); /* USER CODE END CAN1_Init 1 */
} hcan1.Instance = CAN1;
/* USER CODE BEGIN CAN2_Init 2 */ hcan1.Init.Prescaler = 4;
hcan1.Init.Mode = CAN_MODE_SILENT;
/* USER CODE END CAN2_Init 2 */ hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_16TQ;
} hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
/** hcan1.Init.AutoBusOff = DISABLE;
* @brief SDIO Initialization Function hcan1.Init.AutoWakeUp = ENABLE;
* @param None hcan1.Init.AutoRetransmission = DISABLE;
* @retval None hcan1.Init.ReceiveFifoLocked = DISABLE;
*/ hcan1.Init.TransmitFifoPriority = DISABLE;
static void MX_SDIO_SD_Init(void) if (HAL_CAN_Init(&hcan1) != HAL_OK)
{ {
Error_Handler();
/* USER CODE BEGIN SDIO_Init 0 */ }
/* USER CODE BEGIN CAN1_Init 2 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE END CAN1_Init 2 */
/* USER CODE BEGIN SDIO_Init 1 */
}
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO; /**
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; * @brief CAN2 Initialization Function
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; * @param None
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; * @retval None
hsd.Init.BusWide = SDIO_BUS_WIDE_1B; */
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; static void MX_CAN2_Init(void)
hsd.Init.ClockDiv = 0; {
if (HAL_SD_Init(&hsd) != HAL_OK)
{ /* USER CODE BEGIN CAN2_Init 0 */
Error_Handler();
} /* USER CODE END CAN2_Init 0 */
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{ /* USER CODE BEGIN CAN2_Init 1 */
Error_Handler();
} /* USER CODE END CAN2_Init 1 */
/* USER CODE BEGIN SDIO_Init 2 */ hcan2.Instance = CAN2;
hcan2.Init.Prescaler = 8;
/* USER CODE END SDIO_Init 2 */ hcan2.Init.Mode = CAN_MODE_SILENT;
hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
} hcan2.Init.TimeSeg1 = CAN_BS1_16TQ;
hcan2.Init.TimeSeg2 = CAN_BS2_4TQ;
/** hcan2.Init.TimeTriggeredMode = DISABLE;
* Enable DMA controller clock hcan2.Init.AutoBusOff = DISABLE;
*/ hcan2.Init.AutoWakeUp = ENABLE;
static void MX_DMA_Init(void) hcan2.Init.AutoRetransmission = DISABLE;
{ hcan2.Init.ReceiveFifoLocked = DISABLE;
hcan2.Init.TransmitFifoPriority = DISABLE;
/* DMA controller clock enable */ if (HAL_CAN_Init(&hcan2) != HAL_OK)
__HAL_RCC_DMA2_CLK_ENABLE(); {
Error_Handler();
/* DMA interrupt init */ }
/* DMA2_Stream3_IRQn interrupt configuration */ /* USER CODE BEGIN CAN2_Init 2 */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); /* USER CODE END CAN2_Init 2 */
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); }
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
/**
} * @brief SDIO Initialization Function
* @param None
/** * @retval None
* @brief GPIO Initialization Function */
* @param None static void MX_SDIO_SD_Init(void)
* @retval None {
*/
static void MX_GPIO_Init(void) /* USER CODE BEGIN SDIO_Init 0 */
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END MX_GPIO_Init_1 */
/* USER CODE END SDIO_Init 1 */
/* GPIO Ports Clock Enable */ hsd.Instance = SDIO;
__HAL_RCC_GPIOC_CLK_ENABLE(); hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
__HAL_RCC_GPIOH_CLK_ENABLE(); hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
__HAL_RCC_GPIOA_CLK_ENABLE(); hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
__HAL_RCC_GPIOB_CLK_ENABLE(); hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
__HAL_RCC_GPIOD_CLK_ENABLE(); hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 0;
/*Configure GPIO pin Output Level */ if (HAL_SD_Init(&hsd) != HAL_OK)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET); {
Error_Handler();
/*Configure GPIO pins : PC13 PC14 PC15 PC0 }
PC1 PC2 PC3 PC4 if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
PC5 PC6 PC7 */ {
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0 Error_Handler();
|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4 }
|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; /* USER CODE BEGIN SDIO_Init 2 */
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL; /* USER CODE END SDIO_Init 2 */
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/*Configure GPIO pins : PH0 PH1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; /**
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; * Enable DMA controller clock
GPIO_InitStruct.Pull = GPIO_NOPULL; */
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); static void MX_DMA_Init(void)
{
/*Configure GPIO pins : PA0 PA1 PA2 PA3
PA4 PA5 PA6 PA7 /* DMA controller clock enable */
PA8 PA9 PA10 PA11 __HAL_RCC_DMA2_CLK_ENABLE();
PA12 PA13 PA14 PA15 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 /* DMA interrupt init */
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7 /* DMA2_Stream3_IRQn interrupt configuration */
|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; /* DMA2_Stream6_IRQn interrupt configuration */
GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0);
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
/*Configure GPIO pins : PB0 PB1 PB2 PB10 }
PB11 PB14 PB15 PB6
PB7 */ /**
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10 * @brief GPIO Initialization Function
|GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_6 * @param None
|GPIO_PIN_7; * @retval None
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; */
GPIO_InitStruct.Pull = GPIO_NOPULL; static void MX_GPIO_Init(void)
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*Configure GPIO pins : PB3 PB4 PB5 */ /* USER CODE BEGIN MX_GPIO_Init_1 */
GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; /* USER CODE END MX_GPIO_Init_1 */
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; /* GPIO Ports Clock Enable */
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); __HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
/* USER CODE BEGIN MX_GPIO_Init_2 */ __HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* USER CODE END MX_GPIO_Init_2 */ __HAL_RCC_GPIOD_CLK_ENABLE();
}
/*Configure GPIO pin Output Level */
/* USER CODE BEGIN 4 */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET);
/* USER CODE END 4 */ /*Configure GPIO pins : PC13 PC14 PC15 PC0
PC1 PC2 PC3 PC4
PC5 PC6 PC7 */
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0
/** |GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
* @brief Period elapsed callback in non blocking mode |GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
* @note This function is called when TIM6 interrupt took place, inside GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment GPIO_InitStruct.Pull = GPIO_NOPULL;
* a global variable "uwTick" used as application time base. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
* @param htim : TIM handle
* @retval None /*Configure GPIO pins : PH0 PH1 */
*/ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
{ GPIO_InitStruct.Pull = GPIO_NOPULL;
/* USER CODE BEGIN Callback 0 */ HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/* USER CODE END Callback 0 */ /*Configure GPIO pins : PA0 PA1 PA2 PA3
if (htim->Instance == TIM6) PA4 PA5 PA6 PA7
{ PA8 PA9 PA10 PA11
HAL_IncTick(); PA12 PA13 PA14 PA15 */
} GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
/* USER CODE BEGIN Callback 1 */ |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
/* USER CODE END Callback 1 */ |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
} GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
/** HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
* @brief This function is executed in case of error occurrence.
* @retval None /*Configure GPIO pins : PB0 PB1 PB2 PB10
*/ PB11 PB14 PB15 PB6
void Error_Handler(void) PB7 */
{ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
/* USER CODE BEGIN Error_Handler_Debug */ |GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_6
/* User can add his own implementation to report the HAL error return state */ |GPIO_PIN_7;
__disable_irq(); GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
while (1) GPIO_InitStruct.Pull = GPIO_NOPULL;
{ HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE END Error_Handler_Debug */ /*Configure GPIO pins : PB3 PB4 PB5 */
} GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
#ifdef USE_FULL_ASSERT GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
/** GPIO_InitStruct.Pull = GPIO_NOPULL;
* @brief Reports the name of the source file and the source line number GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
* where the assert_param error has occurred. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
* @param file: pointer to the source file name
* @param line: assert_param error line source number /* USER CODE BEGIN MX_GPIO_Init_2 */
* @retval None
*/ /* USER CODE END MX_GPIO_Init_2 */
void assert_failed(uint8_t *file, uint32_t line) }
{
/* USER CODE BEGIN 6 */ /* USER CODE BEGIN 5 */
/* 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 5 */
/* USER CODE END 6 */
} /**
#endif /* USE_FULL_ASSERT */ * @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM6 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6)
{
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @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();
//TODO: check if it is necessary to stop FreeRTOS
uint32_t error_code_can1;
uint32_t error_code_can2;
if (HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY) error_code_can1 = HAL_CAN_GetError(&hcan1);
if (HAL_CAN_GetState(&hcan2) != HAL_CAN_STATE_READY) error_code_can2 = HAL_CAN_GetError(&hcan2);
// TODO: write error to SD and/or serial
HAL_GPIO_WritePin(led_can1.port, led_can1.pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(led_can2.port, led_can2.pin, GPIO_PIN_RESET);
while (1)
{
HAL_GPIO_TogglePin(led_error.port, led_error.pin);
HAL_Delay(250);
}
/* 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 */
-38
View File
@@ -1,38 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.