Files
STM32F4-Base/Drivers/BSP/TPAFE5160/tpafe5160.c
2026-07-19 15:27:49 +08:00

315 lines
11 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.
/*
* 模块名称TPAFE5160 16<31>?通道同步采样ADC驱动
* 模块功能<EFBC9A>?TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接<E58F96>? * 适用平台STM32F407ZGT6<EFBC8C>?6位数据总线<E680BB>?GPIOG[15:0]
* 作者王建<E78E8B>? * 创建日期<E697A5>?026-07-17
* 修改记录<E8AEB0>? * 2026-07-17 王建<E78E8B>? 创建初始版本<EFBC8C>?AD7606 并行驱动<E9A9B1>?TPAFE5160 手册
* 2026-07-17 王建<E78E8B>? 增加 EXTI 中断读取模式
*/
/* 头文件包含区 */
#include "tpafe5160.h"
#include "main.h"
/*
* 调试输出配置
*/
#define DBG_TAG "[ADC]"
#include "dbg_log.h"
/* ======================== 私有宏定<E5AE8F>?======================== */
/*
* 并行读取时序延时 (168MHz 主频<E4B8BB>? NOP <20>?5.95ns)
*
* TPAFE5160 并行时序要求 (VDRIVE > 2.7V)<29>? * t10 (RD 低脉<E4BD8E>? <20>?22ns
* t11 (RD 高脉<E9AB98>? <20>?10ns
* t14 (数据访问时间) <20>?21ns (<28>?RD 下降沿算<E6B2BF>?
* t15 (数据保持时间) <20>?6ns (<28>?RD 下降沿算<E6B2BF>?
*
* GPIO 写操作本身约 1 <20>?AHB 周期 (~6ns)<29>? * 加上端口延迟 (~12-18ns)<EFBC8C>?RD 引脚翻转滞后<E6BB9E>?18-24ns<6E>? * 因此 NOP 延时只需覆盖数据建立时间即可<E58DB3>? */
#define TPAFE5160_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP()
/* RD 低脉宽延时GPIO<49>?~6ns) + 5NOP(~30ns) > 22ns */
#define TPAFE5160_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TPAFE5160_NOP_5(); } while (0)
/* RD 高脉宽延时GPIO<49>?~6ns) + 3NOP(~18ns) > 10ns */
#define TPAFE5160_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0)
/* CONVST 脉冲延时上升沿前需保证低电平5NOP 覆盖 t5 <20>?20ns */
#define TPAFE5160_CONVST_PULSE() do { \
TPAFE5160_CONVST_LOW(); \
TPAFE5160_NOP_5(); \
TPAFE5160_CONVST_HIGH(); \
TPAFE5160_NOP_5(); \
} while (0)
/* ======================== 私有函数声明 ======================== */
static void tpafe5160_read_channels(uint8_t count, int16_t *buf);
/* ======================== 公共函数定义 ======================== */
/*
* 函数功能:初始化 TPAFE5160设置过采样、等待就绪
* 入口参数:无
* 返回值0 - 成功<E68890>?2 - BUSY 超时
* 限定条件CubeMX 已完<E5B7B2>?GPIO 初始<E5889D>? * 函数说明<E8AFB4>?. 设置过采样为无过采样 (000)
* 2. 确保 RD 为高、CONVST 为低
* 3. 等待 BUSY 释放(转换空闲)
*/
int tpafe5160_init(void) {
/* 设置默认过采样:无过采样 (OS[2:0] = 000) */
tpafe5160_set_os(TPAFE5160_OS_NONE);
/* 确保控制引脚处于空闲状<E997B2>?*/
TPAFE5160_RD_HIGH();
TPAFE5160_CONVST_LOW();
/* 等待 BUSY 释放确保上电后无残留转<E79599>?*/
int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
if (ret != TPAFE5160_OK) {
DBG_ERROR("Init wait BUSY timeout");
} else {
DBG_INFO("Init OK");
}
return ret;
}
/*
* 函数功能设置过采样<E98787>? * 入口参数os - 过采样率枚举<E69E9A>? tpafe5160_os_t
* 返回值<E580BC>? * 限定条件GPIO 已初始化
* 函数说明:通过 OS[2:0] 引脚设置过采样率在下一<E4B88B>?BUSY 下降沿锁存生<E5AD98>? */
void tpafe5160_set_os(tpafe5160_os_t os) {
TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */
TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */
TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */
}
/*
* 函数功能启动一次转换CONVST 上升沿触发)
* 入口参数:无
* 返回值<E580BC>? * 限定条件GPIO 已初始化
* 函数说明<EFBC9A>?CONVST 脉冲上升沿启动全部8通道同步采样与转<E4B88E>? */
void tpafe5160_start_conv(void) {
TPAFE5160_CONVST_PULSE();
}
/*
* 函数功能等待转换完<E68DA2>? * 入口参数timeout_ms - 超时时间 uint32_t > 0
* 返回值0 - 转换完成<E5AE8C>?2 - 超时
* 限定条件:已调用 tpafe5160_start_conv()
* 函数说明<EFBC9A>?BUSY 引脚等待下降<E4B88B>? */
int tpafe5160_wait_busy(uint32_t timeout_ms) {
uint32_t tick_start = HAL_GetTick();
/* 等待 BUSY 释放低电平表示空闲<E7A9BA>?*/
while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) {
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
return TPAFE5160_BUSY_TIMEOUT;
}
}
return TPAFE5160_OK;
}
/*
* 函数功能查询当前是否正在转<E59CA8>? * 入口参数:无
* 返回值1 - 正在转换<E8BDAC>? - 空闲
* 限定条件GPIO 已初始化
* 函数说明<EFBC9A>?BUSY 引脚电平
*/
uint8_t tpafe5160_is_busy(void) {
return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0;
}
/*
* 函数功能读取全<E58F96>?通道转换结果
* 入口参数buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
* 返回值0 - 成功<E68890>?2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明<E8AFB4>?. 启动转换并等<E5B9B6>?BUSY 释放
* 2. 连续8次拉低RD读取各通道数据
* 3. 通过 FRSTDATA 验证第一通道
*/
int tpafe5160_read_all(int16_t *buf) {
int ret = 0;
/* 启动转换 */
tpafe5160_start_conv();
/* 等待转换完成 */
ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
if (ret != TPAFE5160_OK) {
DBG_ERROR("read_all BUSY timeout");
return ret;
}
/* 连续读取8个通道 */
tpafe5160_read_channels(TPAFE5160_CH_NUM, buf);
return TPAFE5160_OK;
}
/*
* 函数功能读取指定通道的转换结<E68DA2>? * 入口参数channel - 通道<E9809A>? uint8_t 0 - 7
* value - 输出指针 int16_t* 不为 NULL
* 返回值0 - 成功<E68890>?1 - 通道号无效,-2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明:启动转换并等待完成后,连续读取至指定通道
*/
int tpafe5160_read_channel(uint8_t channel, int16_t *value) {
int ret = 0;
int16_t buf[TPAFE5160_CH_NUM] = {0};
if (channel >= TPAFE5160_CH_NUM || value == NULL) {
return TPAFE5160_ERROR;
}
ret = tpafe5160_read_all(buf);
if (ret != TPAFE5160_OK) {
return ret;
}
*value = buf[channel];
return TPAFE5160_OK;
}
/*
* 函数功能原始ADC值转电压<E794B5>? * 入口参数raw - ADC原始<E58E9F>? int16_t 有符号补<E58FB7>? * 返回值电压<E794B5>? float 单位 V
* 限定条件:无
* 函数说明<E6988E>?V量程<E9878F>?LSB = 10V / 65536 <20>?152.59μV
* ±10V量程<E9878F>?LSB = 20V / 65536 <20>?305.18μV
* 硬件 RANGE 引脚<E5BC95>?GND<EFBC8C>?±5V 量程
*/
float tpafe5160_to_voltage(int16_t raw) {
/* RANGE <20>?GND <20>?±5V 量程,满量程 10V */
return (float)raw * (10.0f / 65536.0f);
}
/*
* 函数功能直接读取并行数据总线不启动转换<E8BDAC>? * 入口参数:无
* 返回值16位原始数<E5A78B>? uint16_t
* 限定条件RD 为低<E4B8BA>?CS <20>?RD 已拉<E5B7B2>? * 函数说明<EFBC9A>?GPIOG->IDR <20>?6位对应 DB[15:0]
*/
uint16_t tpafe5160_read_bus(void) {
return TPAFE5160_READ_BUS();
}
/* ======================== 私有函数定义 ======================== */
/*
* 函数功能:通过 RD 脉冲连续读取多个通道数据
* 入口参数count - 要读取的通道<E9809A>? uint8_t 1 - 8
* buf - 输出缓冲<E7BC93>? int16_t* 不为 NULL
* 返回值<E580BC>? * 限定条件转换已完成BUSY 为低RD 初始为高
* 函数说明<EFBC9A>?RD 下降沿输出一个通道数据按通道1~8顺序输出
* DB[15:0] 直接<E79BB4>?GPIOG[15:0],通过 IDR 寄存器一次读<E6ACA1>? *
* 时序关键<E585B3>?(VDRIVE > 2.7V, 168MHz 主频)<29>? * GPIO 写操<E58699>?~6ns + 端口延迟 ~18ns <20>?RD 引脚实际翻转<E7BFBB>?24ns <20>? * t14 数据建立 <20>?21ns <20>?数据<E695B0>?RD 下降沿后 21ns 内有<E58685>? * 5 <20>?NOP (~30ns) 覆盖建立时间
*/
static void tpafe5160_read_channels(uint8_t count, int16_t *buf) {
uint8_t i;
for (i = 0; i < count; i++) {
/* RD 下降沿ADC 输出当前通道数据<E695B0>?DB[15:0] */
TPAFE5160_RD_LOW_DLY();
/* 读取16位并行数<E8A18C>?*/
buf[i] = (int16_t)TPAFE5160_READ_BUS();
/* RD 上升沿:准备下一通道 */
TPAFE5160_RD_HIGH_DLY();
}
}
/* ======================== 中断模式实现 ======================== */
/* 双缓冲区ISR <20>?s_buf_b主循环<E5BEAA>?s_buf_a */
static int16_t s_buf_a[TPAFE5160_CH_NUM];
static int16_t s_buf_b[TPAFE5160_CH_NUM];
static volatile uint8_t s_ready = 0;
static volatile uint8_t s_buf_sel = 0; /* 0 = <20>?B / <20>?A, 1 = <20>?A / <20>?B */
/*
* 函数功能使<EFBC9A>?BUSY EXTI 中断运行时重使能用<E883BD>? * 入口参数:无
* 返回值<E580BC>? * 限定条件CubeMX 已完<E5B7B2>?GPIO <20>?NVIC 配置
* 函数说明正常启动流程无需调用<EFBC8C>?irq_disable() 后需要重新使能时使用
*/
void tpafe5160_irq_enable(void) {
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
/*
* 函数功能<EFBC9A>?BUSY EXTI 中断
* 入口参数:无
* 返回值<E580BC>? * 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明:仅禁用 NVIC 中断GPIO 配置保持 CubeMX 设定
*/
void tpafe5160_irq_disable(void) {
HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
}
/*
* 函数功能启动转换中断模式<E6A8A1>? * 入口参数:无
* 返回值<E580BC>? * 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明<EFBC9A>?CONVST 脉冲转换完成后<E68890>?EXTI 中断自动读取 8 通道数据
*/
void tpafe5160_start_conv_irq(void) {
s_ready = 0;
TPAFE5160_CONVST_PULSE();
}
/*
* 函数功能:检查是否有新的转换数据
* 入口参数:无
* 返回值1 - 数据就绪<E5B0B1>? - 无新数据
* 限定条件:中断模式已启用
* 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除
*/
uint8_t tpafe5160_data_ready(void) {
return s_ready;
}
/*
* 函数功能清除数据就绪标<E7BBAA>? * 入口参数:无
* 返回值<E580BC>? * 限定条件:中断模式已启用
* 函数说明:主循环处理完数据后调用
*/
void tpafe5160_clear_ready(void) {
s_ready = 0;
}
/*
* 函数功能:获取数据缓冲区指针
* 入口参数:无
* 返回值int16_t[8] 数据缓冲区的 const 指针
* 限定条件tpafe5160_data_ready() 返回 1 时调<E697B6>? * 函数说明双缓冲切换ISR 写另一个缓冲区主循环安全读取当前缓冲<E7BC93>? */
const int16_t* tpafe5160_get_buf(void) {
return (s_buf_sel == 0) ? s_buf_a : s_buf_b;
}
/*
* 函数功能BUSY 下降<E4B88B>?EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用<E8B083>? * 入口参数GPIO_Pin - 触发中断的引脚号
* 返回值<E580BC>? * 限定条件BUSY EXTI 已使<E5B7B2>? * 函数说明:转换完成后自动读取 8 通道数据到缓冲区耗时<E88097>?0.5µs (168MHz)
*/
void tpafe5160_exti_handler(uint16_t GPIO_Pin) {
if (GPIO_Pin != TP_BUSY_Pin) {
return;
}
/* 双缓冲切换ISR 写与主循环读不同的缓冲区 */
int16_t *p_wr = (s_buf_sel == 0) ? s_buf_b : s_buf_a;
/* 连续读取8个通道约 0.5µs @ 168MHz */
uint8_t i;
for (i = 0; i < TPAFE5160_CH_NUM; i++) {
TPAFE5160_RD_LOW_DLY();
p_wr[i] = (int16_t)TPAFE5160_READ_BUS();
TPAFE5160_RD_HIGH_DLY();
}
/* 切换缓冲区并标记就绪 */
s_buf_sel ^= 1;
s_ready = 1;
}