STM_ATEM/User/ltc2508_driver.c
zhoujie fee2e96eaa feat(system): 优化系统性能并简化监控模块
- 新增VSCode编辑器配置,启用保存时自动格式化
- 新增DMA2_Stream5和USART1中断处理函数,优化SPI传输性能
- 移除TIM1相关配置和性能监控模块,简化系统架构
- 优化GPIO配置,将ADC_SYNC和PA8引脚合并配置
- 简化系统监控模块,仅保留采样计数和数据溢出统计
- 优化SPI配置,使用16位数据宽度并提高DMA优先级
- 提高USART波特率(USART1:2Mbps, USART3:921600bps)
- 优化LTC2508驱动,增加初始化状态检查和缓冲区大小
- 修正数据存储模块,使用校正数据包而非校正结果结构体
- 优化RS485驱动,使用中断传输并添加传输完成回调
- 更新IOC配置文件,移除TIM1并调整中断优先级配置
- 新增系统监控简化说明文档,详细记录架构变更
2026-02-06 22:45:25 +08:00

322 lines
9.5 KiB
C
Raw Permalink 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 是否初始化
* @retval 0-未初始化 1-已初始化
*/
uint32_t LTC2508_IsInited()
{
return (g_hspi1 != NULL && g_hspi2 != NULL && 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) != 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) != 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) != 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;
}
}
}