Merge pull request 'Implement CAN read RTOS' (#14) from j1939 into main
This commit is contained in:
+3
-1
@@ -8,4 +8,6 @@
|
||||
.metadata
|
||||
Core/Src/Backup/
|
||||
Core/Inc/Backup/
|
||||
Debug
|
||||
.bak
|
||||
.gitignore
|
||||
can_logger Debug.launch
|
||||
|
||||
@@ -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
|
||||
#define CANLOG_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.
|
||||
@@ -9,5 +55,8 @@
|
||||
* @param hcan2 Pointer to the CAN2 handle
|
||||
*/
|
||||
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 */
|
||||
|
||||
+3
-4
@@ -8,11 +8,9 @@
|
||||
* @attention
|
||||
*
|
||||
* 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
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -28,6 +26,7 @@ extern "C" {
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "canlog.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
@@ -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__ */
|
||||
+128
-25
@@ -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"
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "cmsis_os.h"
|
||||
#include <string.h>
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Definitions for canBus1Listen */
|
||||
osThreadId_t canBus1ListenHandle;
|
||||
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,
|
||||
};
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern CAN_HandleTypeDef hcan2;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2){}
|
||||
static void CAN_Listen(void *argument){}
|
||||
|
||||
/* BEGIN Header_CAN_Listen */
|
||||
/* USER CODE BEGIN FunctionPrototypes */
|
||||
/* BEGIN CAN_Logger_Init */
|
||||
/**
|
||||
* @brief Function implementing the canBus0Listen thread.
|
||||
* @param argument: Not used
|
||||
* @brief Initialize CAN bus logger.
|
||||
* @param argument: hcan1, hcan2
|
||||
* @retval None
|
||||
*/
|
||||
/* END Header_CAN_Listen */
|
||||
void CAN_Listen(void *argument)
|
||||
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 */
|
||||
/* Infinite loop */
|
||||
for(;;)
|
||||
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)
|
||||
{
|
||||
osDelay(1);
|
||||
// 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
|
||||
* @retval None
|
||||
*/
|
||||
void vCANLoggerListen(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 */
|
||||
LEDContext *context = (LEDContext*)argument;
|
||||
|
||||
if (osSemaphoreAcquire(context->semaphore, 0U) == osOK)
|
||||
{
|
||||
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 */
|
||||
}
|
||||
/* END vLEDHeartbeat */
|
||||
/* USER CODE END FunctionPrototypes */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+90
-24
@@ -5,30 +5,25 @@
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 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
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "canlog.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "canlog.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
@@ -50,7 +45,21 @@ DMA_HandleTypeDef hdma_sdio_rx;
|
||||
DMA_HandleTypeDef hdma_sdio_tx;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
LED_Config led_can1 = {GPIOB, GPIO_PIN_2};
|
||||
LED_Config led_can2 = {GPIOB, GPIO_PIN_5};
|
||||
LED_Config led_error = {GPIOB, GPIO_PIN_3};
|
||||
|
||||
LEDContext ledContextCAN1;
|
||||
LEDContext ledContextCAN2;
|
||||
|
||||
osSemaphoreId_t xSemaphoreCAN1;
|
||||
osSemaphoreId_t xSemaphoreCAN2;
|
||||
|
||||
osTimerId_t xHeartbeatTimerCAN1;
|
||||
osTimerId_t xHeartbeatTimerCAN2;
|
||||
|
||||
osMessageQueueId_t xCAN1RxQueue;
|
||||
osMessageQueueId_t xCAN2RxQueue;
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
@@ -62,7 +71,6 @@ static void MX_CAN2_Init(void);
|
||||
static void MX_SDIO_SD_Init(void);
|
||||
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
@@ -103,40 +111,84 @@ int main(void)
|
||||
MX_CAN1_Init();
|
||||
MX_CAN2_Init();
|
||||
MX_SDIO_SD_Init();
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
// Initialize CAN1 and CAN2
|
||||
CAN_Logger_Init(&hcan1, &hcan2);
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Init scheduler */
|
||||
osKernelInitialize();
|
||||
|
||||
/* USER CODE BEGIN RTOS_TASKS */
|
||||
osThreadId_t xCAN1rx;
|
||||
const osThreadAttr_t CAN1rxAttributes = {
|
||||
.name = "CAN1rx",
|
||||
.stack_size = 128 * 4,
|
||||
.priority = (osPriority_t) osPriorityRealtime1,
|
||||
};
|
||||
osThreadId_t xCAN2rx;
|
||||
const osThreadAttr_t CAN2rxAttributes = {
|
||||
.name = "CAN2rx",
|
||||
.stack_size = 128 * 4,
|
||||
.priority = (osPriority_t) osPriorityRealtime,
|
||||
};
|
||||
/* USER END RTOS_TASKS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_MUTEX */
|
||||
/* add mutexes, ... */
|
||||
/* USER CODE END RTOS_MUTEX */
|
||||
|
||||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||||
/* add semaphores, ... */
|
||||
xSemaphoreCAN1 = osSemaphoreNew(10, 0, NULL);
|
||||
xSemaphoreCAN2 = osSemaphoreNew(10, 0, NULL);
|
||||
|
||||
if (xSemaphoreCAN1 == NULL || xSemaphoreCAN2 == NULL) Error_Handler();
|
||||
|
||||
ledContextCAN1.led = &led_can1;
|
||||
ledContextCAN1.semaphore = xSemaphoreCAN1;
|
||||
ledContextCAN2.led = &led_can2;
|
||||
ledContextCAN2.semaphore = xSemaphoreCAN2;
|
||||
/* USER CODE END RTOS_SEMAPHORES */
|
||||
|
||||
/* USER CODE BEGIN RTOS_TIMERS */
|
||||
/* start timers, add new ones, ... */
|
||||
xHeartbeatTimerCAN1 = osTimerNew(vLEDHeartbeat, osTimerOnce, &ledContextCAN1, NULL);
|
||||
xHeartbeatTimerCAN2 = osTimerNew(vLEDHeartbeat, osTimerOnce, &ledContextCAN2, NULL);
|
||||
|
||||
osTimerStart(xHeartbeatTimerCAN1, 25U);
|
||||
osTimerStart(xHeartbeatTimerCAN2, 25U);
|
||||
|
||||
if (xHeartbeatTimerCAN1 == NULL || xHeartbeatTimerCAN2 == NULL) Error_Handler();
|
||||
|
||||
ledContextCAN1.timer = xHeartbeatTimerCAN1;
|
||||
ledContextCAN2.timer = xHeartbeatTimerCAN2;
|
||||
/* USER CODE END RTOS_TIMERS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_QUEUES */
|
||||
/* add queues, ... */
|
||||
xCAN1RxQueue = osMessageQueueNew(32, sizeof(CanMessage_t), NULL);
|
||||
xCAN2RxQueue = osMessageQueueNew(32, sizeof(CanMessage_t), NULL);
|
||||
|
||||
if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL) Error_Handler();
|
||||
/* USER CODE END RTOS_QUEUES */
|
||||
|
||||
/* USER CODE BEGIN RTOS_THREADS */
|
||||
/* add threads, ... */
|
||||
xCAN1rx = osThreadNew(vCANLoggerListen, &hcan1, &CAN1rxAttributes);
|
||||
xCAN2rx = osThreadNew(vCANLoggerListen, &hcan2, &CAN2rxAttributes);
|
||||
/* USER CODE END RTOS_THREADS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_EVENTS */
|
||||
/* add events, ... */
|
||||
/* USER CODE END RTOS_EVENTS */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
ledContextCAN1.led = &led_can1;
|
||||
ledContextCAN1.semaphore = xSemaphoreCAN1;
|
||||
ledContextCAN1.timer = xHeartbeatTimerCAN1;
|
||||
|
||||
ledContextCAN2.led = &led_can2;
|
||||
ledContextCAN2.semaphore = xSemaphoreCAN2;
|
||||
ledContextCAN2.timer = xHeartbeatTimerCAN2;
|
||||
/* USER CODE END 3 */
|
||||
|
||||
/* Start scheduler */
|
||||
osKernelStart();
|
||||
|
||||
@@ -148,9 +200,9 @@ int main(void)
|
||||
{
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
/* USER CODE BEGIN 4 */
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
/* USER CODE END 4 */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,7 +274,7 @@ static void MX_CAN1_Init(void)
|
||||
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
|
||||
hcan1.Init.TimeTriggeredMode = DISABLE;
|
||||
hcan1.Init.AutoBusOff = DISABLE;
|
||||
hcan1.Init.AutoWakeUp = DISABLE;
|
||||
hcan1.Init.AutoWakeUp = ENABLE;
|
||||
hcan1.Init.AutoRetransmission = DISABLE;
|
||||
hcan1.Init.ReceiveFifoLocked = DISABLE;
|
||||
hcan1.Init.TransmitFifoPriority = DISABLE;
|
||||
@@ -259,7 +311,7 @@ static void MX_CAN2_Init(void)
|
||||
hcan2.Init.TimeSeg2 = CAN_BS2_4TQ;
|
||||
hcan2.Init.TimeTriggeredMode = DISABLE;
|
||||
hcan2.Init.AutoBusOff = DISABLE;
|
||||
hcan2.Init.AutoWakeUp = DISABLE;
|
||||
hcan2.Init.AutoWakeUp = ENABLE;
|
||||
hcan2.Init.AutoRetransmission = DISABLE;
|
||||
hcan2.Init.ReceiveFifoLocked = DISABLE;
|
||||
hcan2.Init.TransmitFifoPriority = DISABLE;
|
||||
@@ -400,11 +452,9 @@ static void MX_GPIO_Init(void)
|
||||
/* USER CODE END MX_GPIO_Init_2 */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/* USER CODE BEGIN 5 */
|
||||
|
||||
/* USER CODE END 5 */
|
||||
|
||||
/**
|
||||
* @brief Period elapsed callback in non blocking mode
|
||||
@@ -437,8 +487,24 @@ 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 */
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user