STM_ATEM/User/ltc2508_driver.c
zhoujie 2cbd4a152d feat(main): 新增性能监控和调试输出功能
- 新增性能监控模块(performance_monitor),用于实时跟踪系统性能指标
- 添加串口调试输出功能,支持系统状态和性能统计的定期输出
- 实现双缓冲机制,提升ADC数据采集和存储的实时性
- 优化数据存储模块,支持校正后数据的存储和双缓冲管理
- 增强错误处理机制,完善中断回调函数和系统错误恢复

♻️ refactor(ltc2508): 重构ADC驱动支持双缓冲

- 将ADC数据存储从单缓冲区重构为双缓冲区结构
- 新增缓冲区状态管理和自动切换机制
- 优化DMA传输完成回调,支持多缓冲区处理
- 提供缓冲区获取和释放的API接口

📝 docs(performance): 新增性能评估报告和使用指南

- 创建STM32F405性能评估报告,详细分析系统性能指标
- 编写双缓冲机制使用指南,说明实现原理和使用方法
- 添加LTC2508驱动使用示例代码

🐛 fix(dma): 调整DMA中断优先级

- 将DMA2_Stream7中断优先级从9调整为6,优化中断响应
- 更新STM32CubeMX配置文件中的中断优先级设置

🔧 chore(config): 优化系统配置和代码结构

- 添加串口调试输出控制开关和间隔配置
- 清理中断处理文件,移除重复的回调函数定义
- 增强错误处理函数,添加系统状态恢复机制
2026-01-25 20:15:47 +08:00

311 lines
9.4 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.

#include "ltc2508_driver.h"
#include <string.h> // For memset
// 全局变量定义 - 双缓冲区实现
volatile LTC2508_BufferTypeDef g_adc_buffers[LTC2508_BUFFER_COUNT] = {0};
volatile uint8_t g_adc_data_ready_flag = 0;
volatile uint8_t g_dma_complete_count = 0;
volatile uint8_t g_current_write_buffer = 0;
volatile uint8_t g_current_read_buffer = 0;
// 错误统计信息
LTC2508_StatsTypeDef g_ltc2508_stats = {0};
// SPI 句柄指针
static SPI_HandleTypeDef *g_hspi1 = NULL;
static SPI_HandleTypeDef *g_hspi2 = NULL;
static SPI_HandleTypeDef *g_hspi3 = NULL;
/**
* @brief 初始化 LTC2508 驱动
* @param hspi1: SPI1 句柄指针
* @param hspi2: SPI2 句柄指针
* @param hspi3: SPI3 句柄指针
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_Init(SPI_HandleTypeDef *hspi1, SPI_HandleTypeDef *hspi2, SPI_HandleTypeDef *hspi3)
{
// 参数检查
if (hspi1 == NULL || hspi2 == NULL || hspi3 == NULL) {
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_INIT;
return LTC2508_ERROR_INIT;
}
g_hspi1 = hspi1;
g_hspi2 = hspi2;
g_hspi3 = hspi3;
g_adc_data_ready_flag = 0;
g_dma_complete_count = 0;
g_current_write_buffer = 0;
g_current_read_buffer = 0;
// 初始化双缓冲区
for (int i = 0; i < LTC2508_BUFFER_COUNT; i++) {
memset((void*)&g_adc_buffers[i], 0, sizeof(LTC2508_BufferTypeDef));
g_adc_buffers[i].state = LTC2508_BUFFER_EMPTY;
g_adc_buffers[i].dma_complete_count = 0;
}
// 重置统计信息
memset(&g_ltc2508_stats, 0, sizeof(g_ltc2508_stats));
// 可以在这里添加对 LTC2508 的配置,如果需要通过 SPI 发送配置字
// 例如HAL_SPI_Transmit(g_hspi1, &config_word, 1, 100);
return LTC2508_OK;
}
/**
* @brief 触发三路 SPI 通过 DMA 读取数据
* @param None
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_TriggerDmaRead(void)
{
// 检查SPI句柄是否有效
if (g_hspi1 == NULL || g_hspi2 == NULL || g_hspi3 == NULL) {
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_INIT;
return LTC2508_ERROR_INIT;
}
// 检查当前写入缓冲区是否可用
volatile LTC2508_BufferTypeDef *current_buffer = &g_adc_buffers[g_current_write_buffer];
if (current_buffer->state == LTC2508_BUFFER_EMPTY)
{
// 设置缓冲区状态为填充中
current_buffer->state = LTC2508_BUFFER_FILLING;
current_buffer->dma_complete_count = 0;
current_buffer->timestamp = HAL_GetTick();
// SPI2 和 SPI3 作为从机只接收
if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)current_buffer->data[1], LTC2508_DATA_LEN * 2) != HAL_OK)
{
current_buffer->state = LTC2508_BUFFER_EMPTY;
g_ltc2508_stats.dma_error_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DMA;
return LTC2508_ERROR_DMA;
}
if (HAL_SPI_Receive_DMA(g_hspi3, (uint8_t*)current_buffer->data[2], LTC2508_DATA_LEN * 2) != HAL_OK)
{
current_buffer->state = LTC2508_BUFFER_EMPTY;
g_ltc2508_stats.dma_error_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DMA;
return LTC2508_ERROR_DMA;
}
// SPI1 作为主机收发,先发一个 dummy 数据触发时钟
uint16_t dummy_tx[LTC2508_DATA_LEN] = {0}; // 可以是任意值
if (HAL_SPI_TransmitReceive_DMA(g_hspi1, (uint8_t*)dummy_tx, (uint8_t*)current_buffer->data[0], LTC2508_DATA_LEN * 2) != HAL_OK)
{
current_buffer->state = LTC2508_BUFFER_EMPTY;
g_ltc2508_stats.dma_error_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DMA;
return LTC2508_ERROR_DMA;
}
return LTC2508_OK;
}
return LTC2508_ERROR_TIMEOUT; // 缓冲区不可用
}
/**
* @brief SPI DMA 传输完成回调函数
* @param hspi: SPI 句柄指针
* @retval None
*/
void LTC2508_DmaComplete_Callback(SPI_HandleTypeDef *hspi)
{
if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3)
{
volatile LTC2508_BufferTypeDef *current_buffer = &g_adc_buffers[g_current_write_buffer];
// 增加当前缓冲区的DMA完成计数
current_buffer->dma_complete_count++;
// 检查是否所有SPI的DMA传输都完成
if (current_buffer->dma_complete_count >= NUM_LTC2508)
{
// 标记当前缓冲区为准备就绪
current_buffer->state = LTC2508_BUFFER_READY;
g_ltc2508_stats.total_samples++;
// 自动切换到下一个缓冲区
LTC2508_SwapBuffers();
}
}
}
/**
* @brief SPI DMA 传输错误回调函数
* @param hspi: SPI 句柄指针
* @retval None
*/
void LTC2508_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3)
{
volatile LTC2508_BufferTypeDef *current_buffer = &g_adc_buffers[g_current_write_buffer];
g_ltc2508_stats.dma_error_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DMA;
// 重置当前缓冲区状态
current_buffer->state = LTC2508_BUFFER_EMPTY;
current_buffer->dma_complete_count = 0;
}
}
/**
* @brief 验证ADC数据有效性
* @param buffer: 缓冲区指针
* @param channel: ADC通道 (0-2)
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_ValidateData(LTC2508_BufferTypeDef *buffer, uint8_t channel)
{
if (buffer == NULL || channel >= NUM_LTC2508) {
return LTC2508_ERROR_DATA_INVALID;
}
// 检查数据是否为全0或全1 (可能的错误状态)
uint32_t combined_data = ((uint32_t)buffer->data[channel][0] << 16) | buffer->data[channel][1];
if (combined_data == 0x00000000 || combined_data == 0xFFFFFFFF) {
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DATA_INVALID;
return LTC2508_ERROR_DATA_INVALID;
}
return LTC2508_OK;
}
/**
* @brief 获取统计信息
* @param stats: 统计信息结构体指针
* @retval None
*/
void LTC2508_GetStats(LTC2508_StatsTypeDef *stats)
{
if (stats != NULL) {
memcpy(stats, &g_ltc2508_stats, sizeof(LTC2508_StatsTypeDef));
}
}
/**
* @brief 重置统计信息
* @param None
* @retval None
*/
void LTC2508_ResetStats(void)
{
memset(&g_ltc2508_stats, 0, sizeof(LTC2508_StatsTypeDef));
}
/**
* @brief 缓冲区切换函数
* @param None
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_SwapBuffers(void)
{
uint8_t next_write_buffer = (g_current_write_buffer + 1) % LTC2508_BUFFER_COUNT;
// 检查下一个写入缓冲区是否可用
if (g_adc_buffers[next_write_buffer].state == LTC2508_BUFFER_EMPTY) {
g_current_write_buffer = next_write_buffer;
return LTC2508_OK;
}
// 如果下一个缓冲区不可用,说明缓冲区溢出
g_ltc2508_stats.buffer_overflow_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_BUFFER_OVERFLOW;
return LTC2508_ERROR_BUFFER_OVERFLOW;
}
/**
* @brief 获取当前写入缓冲区索引
* @param None
* @retval uint8_t 当前写入缓冲区索引
*/
uint8_t LTC2508_GetCurrentWriteBuffer(void)
{
return g_current_write_buffer;
}
/**
* @brief 获取当前读取缓冲区索引
* @param None
* @retval uint8_t 当前读取缓冲区索引
*/
uint8_t LTC2508_GetCurrentReadBuffer(void)
{
return g_current_read_buffer;
}
/**
* @brief 检查指定缓冲区是否准备就绪
* @param buffer_index: 缓冲区索引
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_IsBufferReady(uint8_t buffer_index)
{
if (buffer_index >= LTC2508_BUFFER_COUNT) {
return LTC2508_ERROR_DATA_INVALID;
}
if (g_adc_buffers[buffer_index].state == LTC2508_BUFFER_READY) {
return LTC2508_OK;
}
return LTC2508_ERROR_TIMEOUT;
}
/**
* @brief 获取准备好的数据缓冲区
* @param buffer: 返回缓冲区指针
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_GetReadyBuffer(LTC2508_BufferTypeDef **buffer)
{
if (buffer == NULL) {
return LTC2508_ERROR_DATA_INVALID;
}
// 检查读取缓冲区是否有准备好的数据
if (g_adc_buffers[g_current_read_buffer].state == LTC2508_BUFFER_READY) {
g_adc_buffers[g_current_read_buffer].state = LTC2508_BUFFER_PROCESSING;
*buffer = (LTC2508_BufferTypeDef*)&g_adc_buffers[g_current_read_buffer];
return LTC2508_OK;
}
return LTC2508_ERROR_TIMEOUT; // 没有准备好的数据
}
/**
* @brief 释放缓冲区
* @param buffer_index: 缓冲区索引
* @retval None
*/
void LTC2508_ReleaseBuffer(uint8_t buffer_index)
{
if (buffer_index < LTC2508_BUFFER_COUNT) {
g_adc_buffers[buffer_index].state = LTC2508_BUFFER_EMPTY;
g_adc_buffers[buffer_index].dma_complete_count = 0;
// 如果释放的是当前读取缓冲区,切换到下一个
if (buffer_index == g_current_read_buffer) {
g_current_read_buffer = (g_current_read_buffer + 1) % LTC2508_BUFFER_COUNT;
}
}
}