STM_ATEM/Core/Src/main.c
zhoujie 4598f8f34f feat(main): 为系统监控和性能监控功能添加宏开关控制
- 新增 ENABLE_SYSTEM_MONITOR 和 ENABLE_PERFORMANCE_MONITOR 宏定义,用于控制监控功能的编译开关
- 在 StartRecording、StopRecording、ProcessAdcData、main 等函数中,使用条件编译包裹所有 SystemMonitor 和 PerformanceMonitor 相关的函数调用
- 在 DebugOutput_PrintSystemStats 和 DebugOutput_PrintPerformanceStats 函数中,使用条件编译包裹整个函数体,确保在宏关闭时不生成调试输出代码
- 在 HAL_GPIO_EXTI_Callback、HAL_SPI_ErrorCallback 和 Error_Handler 等中断和错误处理函数中,同样添加条件编译保护,提高代码的灵活性和可配置性
2026-01-25 21:31:39 +08:00

731 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 "dma.h"
#include "fatfs.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ltc2508_driver.h"
#include "rs485_driver.h"
#include "data_packet.h"
#include "correction.h"
#include "data_storage.h"
#include "system_monitor.h"
#include "performance_monitor.h"
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
// 串口输出控制开关
#define ENABLE_UART_DEBUG_OUTPUT 1
#define DEBUG_OUTPUT_INTERVAL_MS 1000 // 调试输出间隔(毫秒)
// 监控功能宏开关
#define ENABLE_SYSTEM_MONITOR 1 // 系统监控开关
#define ENABLE_PERFORMANCE_MONITOR 1 // 性能监控开关
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
// 外部SPI句柄声明
extern SPI_HandleTypeDef hspi1;
extern SPI_HandleTypeDef hspi2;
extern SPI_HandleTypeDef hspi3;
extern TIM_HandleTypeDef htim2;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart3;
// 校正参数
CorrectionParams_t g_correction_params;
// 数据包
DataPacket_t g_data_packet;
CorrectedDataPacket_t g_corrected_packet;
// 数据存储句柄
DataStorageHandle_t g_data_storage;
// 系统状态
static uint32_t g_last_monitor_update = 0;
static uint8_t g_recording_enabled = 0;
static uint32_t g_sample_count = 0;
// 性能监控和调试输出
static uint32_t g_last_debug_output = 0;
static uint8_t g_debug_output_enabled = ENABLE_UART_DEBUG_OUTPUT;
static SystemPerfStats_t g_perf_stats;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static void StartRecording(void);
static void StopRecording(void);
static void ProcessAdcData(void);
static void DebugOutput_Init(void);
static void DebugOutput_SendString(const char* str);
static void DebugOutput_PrintSystemStats(void);
static void DebugOutput_PrintPerformanceStats(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/**
* @brief 开始数据记录
* @retval None
*/
static void StartRecording(void)
{
if (!g_recording_enabled) {
if (DataStorage_StartRecording(&g_data_storage) == HAL_OK) {
g_recording_enabled = 1;
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_RECORDING);
#endif
} else {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE);
#endif
}
}
}
/**
* @brief 停止数据记录
* @retval None
*/
static void StopRecording(void)
{
if (g_recording_enabled) {
g_recording_enabled = 0;
DataStorage_StopRecording(&g_data_storage);
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_IDLE);
#endif
}
}
/**
* @brief 处理ADC数据
* @retval None
*/
static void ProcessAdcData(void)
{
// 检查ADC数据是否准备就绪
LTC2508_BufferTypeDef *ready_buffer = NULL;
if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL)
{
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_ADC_PROCESSING);
#endif
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_SAMPLING);
#endif
g_sample_count++;
// 1. 从双缓冲区获取数据并合并 (高位16位在前)
int32_t raw_adc[NUM_LTC2508];
for (uint8_t i = 0; i < NUM_LTC2508; i++) {
raw_adc[i] = (int32_t)(((uint32_t)ready_buffer->data[i][0] << 16) | ready_buffer->data[i][1]);
}
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_ADC_PROCESSING);
#endif
// 2. 验证数据有效性
uint8_t data_valid = 1;
for (uint8_t i = 0; i < NUM_LTC2508; i++) {
if (LTC2508_ValidateData(ready_buffer, i) != LTC2508_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_ADC);
#endif
data_valid = 0;
break; // 如果有任何通道数据无效,跳过整个样本
}
}
if (!data_valid) {
// 释放缓冲区并返回
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_IDLE);
#endif
return;
}
// 3. 应用校正算法
CorrectionResult_t correction_result;
uint8_t correction_applied = 0;
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_CORRECTION);
#endif
if (g_correction_params.params_valid &&
Apply_Correction(raw_adc[0], raw_adc[1], raw_adc[2],
&correction_result, &g_correction_params) == HAL_OK) {
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_CORRECTION);
#endif
// 4a. 打包校正后的数据
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_DATA_PACKET);
#endif
PackCorrectedData(&g_corrected_packet,
correction_result.corrected_x,
correction_result.corrected_y,
correction_result.corrected_z);
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_DATA_PACKET);
#endif
correction_applied = 1;
// 发送校正后的数据包
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_RS485_TX);
#endif
if (RS485_SendData((uint8_t*)&g_corrected_packet, sizeof(CorrectedDataPacket_t)) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_COMMUNICATION);
#endif
}
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_RS485_TX);
#endif
} else {
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_CORRECTION);
#endif
// 4b. 校正失败或未启用,使用原始数据
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_DATA_PACKET);
#endif
PackData(&g_data_packet, raw_adc[0], raw_adc[1], raw_adc[2]);
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_DATA_PACKET);
#endif
// 发送原始数据包
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_RS485_TX);
#endif
if (RS485_SendData((uint8_t*)&g_data_packet, sizeof(DataPacket_t)) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_COMMUNICATION);
#endif
}
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_RS485_TX);
#endif
}
// 6. 存储数据到SD卡 (如果启用记录)
if (g_recording_enabled) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_RECORDING);
#endif
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_FATFS_WRITE);
#endif
if (correction_applied) {
// 存储校正后的数据
if (DataStorage_WriteCorrectedData(&g_data_storage, &correction_result) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE);
#endif
}
} else {
// 存储原始数据
if (DataStorage_WriteData(&g_data_storage, &g_data_packet) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE);
#endif
}
}
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskEnd(PERF_TASK_FATFS_WRITE);
#endif
}
// 7. 释放已处理的缓冲区
LTC2508_ReleaseBuffer(LTC2508_GetCurrentReadBuffer());
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_IDLE);
#endif
}
}
/**
* @brief 初始化调试输出
* @retval None
*/
static void DebugOutput_Init(void)
{
// USART3已在MX_USART3_UART_Init()中初始化
if (g_debug_output_enabled) {
DebugOutput_SendString("\r\n=== System Debug Output Initialized ===\r\n");
}
}
/**
* @brief 通过USART3发送字符串
* @param str: 要发送的字符串
* @retval None
*/
static void DebugOutput_SendString(const char* str)
{
if (!g_debug_output_enabled || str == NULL) {
return;
}
HAL_UART_Transmit(&huart3, (uint8_t*)str, strlen(str), 100);
}
/**
* @brief 输出系统监控统计信息
* @retval None
*/
static void DebugOutput_PrintSystemStats(void)
{
#if ENABLE_SYSTEM_MONITOR
if (!g_debug_output_enabled) {
return;
}
char buffer[256];
SystemMonitorStats_t sys_stats;
SystemMonitor_GetStats(&sys_stats);
snprintf(buffer, sizeof(buffer),
"\r\n=== System Monitor Stats ===\r\n"
"State: %d, Uptime: %lu s\r\n"
"Total Samples: %lu, Errors: %lu\r\n"
"Memory Usage: %lu bytes\r\n"
"CPU Usage: %d%%, Temp: %d°C\r\n",
sys_stats.current_state,
sys_stats.uptime_seconds,
sys_stats.total_samples,
sys_stats.error_count,
sys_stats.memory_usage,
sys_stats.cpu_usage_percent,
sys_stats.temperature_celsius);
DebugOutput_SendString(buffer);
#endif
}
/**
* @brief 输出性能监控统计信息
* @retval None
*/
static void DebugOutput_PrintPerformanceStats(void)
{
#if ENABLE_PERFORMANCE_MONITOR
if (!g_debug_output_enabled) {
return;
}
char buffer[512];
PerformanceMonitor_GetStats(&g_perf_stats);
snprintf(buffer, sizeof(buffer),
"\r\n=== Performance Monitor Stats ===\r\n"
"Total CPU Usage: %lu%%\r\n"
"Free Heap: %lu bytes (Min: %lu)\r\n"
"Stack Usage: %lu%%\r\n",
g_perf_stats.total_cpu_usage_percent,
g_perf_stats.free_heap_size,
g_perf_stats.min_free_heap_size,
g_perf_stats.stack_usage_percent);
DebugOutput_SendString(buffer);
// 输出各任务性能统计
for (int i = 0; i < PERF_MON_MAX_TASKS; i++) {
if (g_perf_stats.tasks[i].call_count > 0) {
snprintf(buffer, sizeof(buffer),
"Task[%d]: Calls=%lu, Avg=%lu us, Max=%lu us, CPU=%.1f%%\r\n",
i,
g_perf_stats.tasks[i].call_count,
g_perf_stats.tasks[i].avg_time_us,
g_perf_stats.tasks[i].max_time_us,
g_perf_stats.tasks[i].cpu_usage_percent);
DebugOutput_SendString(buffer);
}
}
#endif
}
/* 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_DMA_Init();
MX_SDIO_SD_Init();
MX_SPI1_Init();
MX_SPI2_Init();
MX_SPI3_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
MX_USB_DEVICE_Init();
MX_USART3_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
// 初始化系统监控
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_Init();
SystemMonitor_SetState(SYSTEM_STATE_INIT);
#endif
// 初始化性能监控
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_Init();
#endif
// 初始化调试输出
DebugOutput_Init();
// 初始化LTC2508驱动
if (LTC2508_Init(&hspi1, &hspi2, &hspi3) != LTC2508_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_ADC);
#endif
Error_Handler();
}
// 初始化RS485通信
RS485_Init(&huart1, RS485_DE_RE_PORT, RS485_DE_RE_PIN);
// 初始化校正参数
Init_CorrectionParams(&g_correction_params);
Load_CorrectionParams_FromFlash(&g_correction_params);
// 初始化数据存储
if (DataStorage_Init(&g_data_storage) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_STORAGE);
#endif
}
// 开始数据记录
StartRecording();
// 系统初始化完成
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_IDLE);
#endif
// 启动TIM2定时器用于1ms周期的ADC数据处理
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_CRITICAL);
#endif
Error_Handler();
}
// 触发信号引脚初始化
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 系统监控更新 (每100ms更新一次)
uint32_t current_tick = HAL_GetTick();
if (current_tick - g_last_monitor_update >= 100) {
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_TaskStart(PERF_TASK_SYSTEM_MONITOR);
#endif
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_Update();
#endif
#if ENABLE_PERFORMANCE_MONITOR
PerformanceMonitor_Update();
PerformanceMonitor_TaskEnd(PERF_TASK_SYSTEM_MONITOR);
#endif
g_last_monitor_update = current_tick;
}
// ADC数据处理已移至1ms定时器中断中处理
// 处理数据存储后台任务 (轮询方式)
if (g_recording_enabled) {
DataStorage_ProcessBackgroundTasks(&g_data_storage);
}
// 定期输出调试信息 (每1秒输出一次)
if (g_debug_output_enabled && (current_tick - g_last_debug_output >= DEBUG_OUTPUT_INTERVAL_MS)) {
DebugOutput_PrintSystemStats();
DebugOutput_PrintPerformanceStats();
g_last_debug_output = current_tick;
}
// ADC采样由PA1外部中断触发不在主循环中触发
// 可以在这里添加其他低优先级任务
}
// 停止数据记录
StopRecording();
/* 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_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/**
* @brief 外部中断回调函数 - ADC数据就绪信号
* @param GPIO_Pin: 触发中断的GPIO引脚
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == ADC_DRY_Pin) {
// ADC数据就绪触发DMA读取
if (LTC2508_TriggerDmaRead() != LTC2508_OK) {
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_ADC);
#endif
}
}
}
/**
* @brief SPI DMA传输完成回调函数
* @param hspi: SPI句柄指针
* @retval None
*/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的DMA完成回调
LTC2508_DmaComplete_Callback(hspi);
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的DMA完成回调
LTC2508_DmaComplete_Callback(hspi);
}
/**
* @brief SPI错误回调函数
* @param hspi: SPI句柄指针
* @retval None
*/
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
// 调用LTC2508驱动的错误回调
LTC2508_ErrorCallback(hspi);
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_ReportError(SYSTEM_ERROR_ADC);
#endif
}
/**
* @brief TIM2回调函数 - 1ms定时器中断处理ADC数据
* @param htim: TIM句柄指针
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
// ADC是4KHz采样率定时器是1KHz需要在每次1ms中断中处理多个ADC数据
// 循环处理所有可用的ADC数据直到没有新数据为止
uint8_t processed_count = 0;
const uint8_t max_process_per_interrupt = 8; // 限制每次中断最多处理的数据量,避免中断时间过长
while (processed_count < max_process_per_interrupt) {
LTC2508_BufferTypeDef *ready_buffer = NULL;
if (LTC2508_GetReadyBuffer(&ready_buffer) == LTC2508_OK && ready_buffer != NULL) {
ProcessAdcData();
processed_count++;
} else {
break; // 没有更多数据可处理
}
}
}
}
/**
* @brief UART传输完成回调函数
* @param huart: UART句柄指针
* @retval None
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart1) {
// RS485传输完成回调
RS485_TxCpltCallback(huart);
}
}
/* 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 */
// 设置系统状态为错误状态
#if ENABLE_SYSTEM_MONITOR
SystemMonitor_SetState(SYSTEM_STATE_ERROR);
SystemMonitor_ReportError(SYSTEM_ERROR_CRITICAL);
#endif
// 停止所有DMA传输
HAL_SPI_DMAStop(&hspi1);
HAL_SPI_DMAStop(&hspi2);
HAL_SPI_DMAStop(&hspi3);
// 停止数据记录
g_recording_enabled = 0;
DataStorage_StopRecording(&g_data_storage);
// 禁用中断并进入无限循环
__disable_irq();
while (1)
{
// 可以在这里添加LED指示或其他错误指示
HAL_Delay(500);
}
/* 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 */