- 新增VSCode编辑器配置,启用保存时自动格式化 - 新增DMA2_Stream5和USART1中断处理函数,优化SPI传输性能 - 移除TIM1相关配置和性能监控模块,简化系统架构 - 优化GPIO配置,将ADC_SYNC和PA8引脚合并配置 - 简化系统监控模块,仅保留采样计数和数据溢出统计 - 优化SPI配置,使用16位数据宽度并提高DMA优先级 - 提高USART波特率(USART1:2Mbps, USART3:921600bps) - 优化LTC2508驱动,增加初始化状态检查和缓冲区大小 - 修正数据存储模块,使用校正数据包而非校正结果结构体 - 优化RS485驱动,使用中断传输并添加传输完成回调 - 更新IOC配置文件,移除TIM1并调整中断优先级配置 - 新增系统监控简化说明文档,详细记录架构变更
322 lines
9.5 KiB
C
322 lines
9.5 KiB
C
#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;
|
||
}
|
||
}
|
||
}
|