STM_ATEM/User/ltc2508_driver.c
zhoujie 6297f3044d feat(adc): implement comprehensive ADC data acquisition and processing system
Add complete data acquisition pipeline with LTC2508 ADC drivers, correction algorithms,
data storage, and system monitoring. Includes ARM DSP optimized matrix operations for
sensor calibration, SD card data logging with USB mass storage, and robust error handling
with validation throughout the processing chain.

- Add LTC2508 multi-channel SPI driver with DMA support and error recovery
- Implement correction module with ARM DSP matrix operations for sensor calibration
- Add data storage system with SD card logging and configurable file management
- Integrate system monitor for health tracking and error reporting
- Enhance data packet structure with CRC validation and timestamps
- Add USB mass storage interface for SD card access
- Implement comprehensive error handling and statistics collection
2026-01-25 18:15:13 +08:00

182 lines
5.2 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 uint16_t g_adc_data[NUM_LTC2508][LTC2508_DATA_LEN] = {0};
volatile uint8_t g_adc_data_ready_flag = 0;
volatile uint8_t g_dma_complete_count = 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;
memset((void*)g_adc_data, 0, sizeof(g_adc_data));
// 重置统计信息
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;
}
if (g_adc_data_ready_flag == 0 && g_dma_complete_count == 0) // 确保上次数据已处理且 DMA 未在进行
{
g_dma_complete_count = 0; // 重置计数
// SPI2 和 SPI3 作为从机只接收
if (HAL_SPI_Receive_DMA(g_hspi2, (uint8_t*)g_adc_data[1], LTC2508_DATA_LEN * 2) != HAL_OK)
{
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*)g_adc_data[2], LTC2508_DATA_LEN * 2) != HAL_OK)
{
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*)g_adc_data[0], LTC2508_DATA_LEN * 2) != HAL_OK)
{
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)
{
g_dma_complete_count++;
if (g_dma_complete_count >= NUM_LTC2508)
{
g_adc_data_ready_flag = 1;
g_dma_complete_count = 0; // 为下一次读取做准备
g_ltc2508_stats.total_samples++;
}
}
}
/**
* @brief SPI DMA 传输错误回调函数
* @param hspi: SPI 句柄指针
* @retval None
*/
void LTC2508_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if (hspi == g_hspi1 || hspi == g_hspi2 || hspi == g_hspi3)
{
g_ltc2508_stats.dma_error_count++;
g_ltc2508_stats.error_count++;
g_ltc2508_stats.last_error = LTC2508_ERROR_DMA;
// 重置DMA状态
g_dma_complete_count = 0;
g_adc_data_ready_flag = 0;
}
}
/**
* @brief 验证ADC数据有效性
* @param channel: ADC通道 (0-2)
* @retval LTC2508_StatusTypeDef
*/
LTC2508_StatusTypeDef LTC2508_ValidateData(uint8_t channel)
{
if (channel >= NUM_LTC2508) {
return LTC2508_ERROR_DATA_INVALID;
}
// 检查数据是否为全0或全1 (可能的错误状态)
uint32_t combined_data = ((uint32_t)g_adc_data[channel][0] << 16) | g_adc_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));
}