修复多连接的问题
This commit is contained in:
42
App/app_cfg.h
Normal file
42
App/app_cfg.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Application Configuration
|
||||||
|
* 模块功能:应用层全局配置宏,控制功能模块的编译开关
|
||||||
|
* 适用平台:STM32F407ZGTx
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __APP_CFG_H
|
||||||
|
#define __APP_CFG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 系统时钟源选择
|
||||||
|
* 0 - DWT CYCCNT(默认,0 外设开销)
|
||||||
|
* 1 - TIM2(32-bit 定时器,独立于 DWT)
|
||||||
|
*/
|
||||||
|
#define APP_SYS_TIME_SRC 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 时间戳输出使能
|
||||||
|
* 定义后在日志行首自动追加 [T ssssss.uuuuuu] 微秒时间戳
|
||||||
|
*/
|
||||||
|
#define APP_TIMESTAMP_ENABLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 功能模块使能开关
|
||||||
|
*/
|
||||||
|
#define APP_NET_ENABLE
|
||||||
|
#define APP_ADC_ENABLE
|
||||||
|
#define APP_RS485_ENABLE
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __APP_CFG_H */
|
||||||
47
App/app_main.c
Normal file
47
App/app_main.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Application Main Entry
|
||||||
|
* 模块功能:应用初始化流程编排、各模块启动、主循环
|
||||||
|
* 适用平台:STM32F407ZGTx
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "app_main.h"
|
||||||
|
#include "app_cfg.h"
|
||||||
|
#include "sys_time.h"
|
||||||
|
|
||||||
|
#define DBG_TAG "[APP]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:应用层初始化
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:0 - 成功,-1 - 失败
|
||||||
|
* 限定条件:CubeMX 外设初始化已完成
|
||||||
|
* 函数说明:在 CubeMX 外设初始化之后、FreeRTOS 调度器启动之前调用
|
||||||
|
*/
|
||||||
|
int app_main_init(void)
|
||||||
|
{
|
||||||
|
if (sys_time_init() != 0) {
|
||||||
|
DBG_ERROR("sys_time_init failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DBG_INFO("App init OK");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:应用主循环
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:无
|
||||||
|
* 限定条件:FreeRTOS 调度器启动后不再返回
|
||||||
|
* 函数说明:空闲任务可调用的应用层处理入口
|
||||||
|
*/
|
||||||
|
void app_main_run(void)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
/* 应用层空闲处理 */
|
||||||
|
}
|
||||||
|
}
|
||||||
27
App/app_main.h
Normal file
27
App/app_main.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Application Main Entry
|
||||||
|
* 模块功能:应用层入口,由 main.c 调用完成所有应用初始化与启动
|
||||||
|
* 适用平台:STM32F407ZGTx
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __APP_MAIN_H
|
||||||
|
#define __APP_MAIN_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int app_main_init(void);
|
||||||
|
void app_main_run(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __APP_MAIN_H */
|
||||||
0
App/protocol/.gitkeep
Normal file
0
App/protocol/.gitkeep
Normal file
107
App/sys_time.c
Normal file
107
App/sys_time.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:System Timer
|
||||||
|
* 模块功能:DWT CYCCNT 实现 64-bit 微秒级时间戳
|
||||||
|
* 在 SysTick 中断中检测 CYCCNT 溢出以扩展至 64-bit
|
||||||
|
* 适用平台:STM32F407ZGTx (168MHz)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
*
|
||||||
|
* 限定条件:
|
||||||
|
* - CPU 主频 168MHz(若更改须同步 SYS_TIME_CYCLE_PER_US 宏)
|
||||||
|
* - 须在 FreeRTOS 启动前调用 sys_time_init()
|
||||||
|
* - sys_time_systick_hook() 须在 SysTick 中断中调用
|
||||||
|
*
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sys_time.h"
|
||||||
|
#include "app_cfg.h"
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 每微秒 CPU 周期数(168MHz → 168 cycles/µs)
|
||||||
|
*/
|
||||||
|
#define SYS_TIME_CYCLE_PER_US 168UL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CYCCNT 每溢出一次代表的微秒数(2^32 / 168 ≈ 25,564,904 µs ≈ 25.56s)
|
||||||
|
*/
|
||||||
|
#define SYS_TIME_OVERFLOW_US (uint64_t)(((uint64_t)1 << 32) / SYS_TIME_CYCLE_PER_US)
|
||||||
|
|
||||||
|
static volatile uint32_t s_overflow_cnt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:初始化 DWT CYCCNT
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:0 - 成功
|
||||||
|
* 限定条件:须在 FreeRTOS 启动前调用
|
||||||
|
* 函数说明:启用 DWT 和 CYCCNT 计数器,计数器从 0 开始
|
||||||
|
*/
|
||||||
|
int sys_time_init(void)
|
||||||
|
{
|
||||||
|
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||||
|
DWT->CYCCNT = 0;
|
||||||
|
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||||
|
|
||||||
|
s_overflow_cnt = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取微秒级时间戳
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:64 位微秒时间戳
|
||||||
|
* 函数说明:由当前 CYCCNT 值与溢出计数合成 64-bit 周期数再转换
|
||||||
|
*/
|
||||||
|
uint64_t sys_time_us(void)
|
||||||
|
{
|
||||||
|
uint32_t cyccnt = 0;
|
||||||
|
uint64_t ticks = 0;
|
||||||
|
uint32_t ov = 0;
|
||||||
|
uint32_t ov2 = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 原子读取溢出计数与 CYCCNT,处理潜在的读取竞争
|
||||||
|
* 若两次读取溢出计数不一致则重读 CYCCNT
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
ov = s_overflow_cnt;
|
||||||
|
cyccnt = DWT->CYCCNT;
|
||||||
|
ov2 = s_overflow_cnt;
|
||||||
|
} while (ov != ov2);
|
||||||
|
|
||||||
|
ticks = ((uint64_t)ov << 32) | cyccnt;
|
||||||
|
return ticks / SYS_TIME_CYCLE_PER_US;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取毫秒级时间戳
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:64 位毫秒时间戳
|
||||||
|
* 限定条件:sys_time_init() 已成功调用
|
||||||
|
* 函数说明:通过对 sys_time_us() 取整实现
|
||||||
|
*/
|
||||||
|
uint64_t sys_time_ms(void)
|
||||||
|
{
|
||||||
|
return sys_time_us() / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:SysTick 中断钩子,检测 CYCCNT 溢出
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:无
|
||||||
|
* 函数说明:必须在 SysTick_Handler() 中调用
|
||||||
|
* 每 1ms 检查一次 CYCCNT 是否已回绕
|
||||||
|
*/
|
||||||
|
void sys_time_systick_hook(void)
|
||||||
|
{
|
||||||
|
static uint32_t s_last_cyccnt = 0;
|
||||||
|
uint32_t cyccnt = DWT->CYCCNT;
|
||||||
|
|
||||||
|
if (cyccnt < s_last_cyccnt) {
|
||||||
|
s_overflow_cnt++;
|
||||||
|
}
|
||||||
|
s_last_cyccnt = cyccnt;
|
||||||
|
}
|
||||||
29
App/sys_time.h
Normal file
29
App/sys_time.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:System Timer
|
||||||
|
* 模块功能:基于 DWT CYCCNT + SysTick 溢出的 64 位微秒级时间戳
|
||||||
|
* 适用平台:STM32F407ZGTx (Cortex-M4 FPU)
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SYS_TIME_H
|
||||||
|
#define __SYS_TIME_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int sys_time_init(void);
|
||||||
|
uint64_t sys_time_us(void);
|
||||||
|
uint64_t sys_time_ms(void);
|
||||||
|
void sys_time_systick_hook(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __SYS_TIME_H */
|
||||||
45
App/task/adc_task.c
Normal file
45
App/task/adc_task.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:ADC Sampling Task
|
||||||
|
* 模块功能:TPAFE5160 8 通道同步采样,数据缓存与通知
|
||||||
|
* 适用平台:STM32F407ZGTx + TPAFE5160
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "adc_task.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
#include "tpafe5160.h"
|
||||||
|
|
||||||
|
#define DBG_TAG "[ADC_TASK]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:ADC 任务初始化
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:0 - 成功,-1 - 失败
|
||||||
|
* 限定条件:TPAFE5160 硬件已上电
|
||||||
|
* 函数说明:配置采样参数,准备数据缓冲区
|
||||||
|
*/
|
||||||
|
int adc_task_init(void)
|
||||||
|
{
|
||||||
|
DBG_INFO("adc_task_init");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:ADC 任务主函数
|
||||||
|
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
||||||
|
* 返 回 值:无
|
||||||
|
* 限定条件:adc_task_init() 已成功调用
|
||||||
|
* 函数说明:定时触发 TPAFE5160 同步采样并处理数据
|
||||||
|
*/
|
||||||
|
void adc_task_func(void const *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
osDelay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
App/task/adc_task.h
Normal file
25
App/task/adc_task.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:ADC Sampling Task
|
||||||
|
* 模块功能:TPAFE5160 8 通道同步采样,数据缓存与通知
|
||||||
|
* 适用平台:STM32F407ZGTx + TPAFE5160
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ADC_TASK_H
|
||||||
|
#define __ADC_TASK_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int adc_task_init(void);
|
||||||
|
void adc_task_func(void const *arg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ADC_TASK_H */
|
||||||
78
App/task/net_task.c
Normal file
78
App/task/net_task.c
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Application Task
|
||||||
|
* 模块功能:CH395F 协议栈轮询 + TCP/UDP 业务处理
|
||||||
|
* 与 net_socket.h 配合,在 FreeRTOS 独立任务中运行
|
||||||
|
* 适用平台:STM32F407ZGTx + CH395F
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
* v1.1 2026-07-19 王建锋 migrate from freertos.c StartNetTask
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "net_task.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
#include "net_socket.h"
|
||||||
|
#include "net_select.h"
|
||||||
|
#include "ch395f_test.h"
|
||||||
|
|
||||||
|
#define DBG_TAG "[NET_TASK]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
|
static uint8_t s_net_buf[1500];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:网络任务初始化
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:0 - 成功,-1 - 失败
|
||||||
|
* 限定条件:CH395F 协议栈已初始化
|
||||||
|
* 函数说明:创建 TCP Server 监听 Socket,注册回调等
|
||||||
|
*/
|
||||||
|
int net_task_init(void)
|
||||||
|
{
|
||||||
|
DBG_INFO("net_task_init");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:网络任务主函数
|
||||||
|
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
||||||
|
* 返 回 值:无
|
||||||
|
* 函数说明:FreeRTOS 任务函数,启动后先等待 2 秒再进入轮询循环
|
||||||
|
* 依次处理 net_poll、TCP echo、UDP/Select 测试
|
||||||
|
*/
|
||||||
|
void net_task_func(void const *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
osDelay(2000);
|
||||||
|
DBG_INFO("netTask: started");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
net_poll();
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
net_sock_t *p_sk = net_get_sock(i);
|
||||||
|
if (p_sk == NULL || p_sk->state != NET_SOCK_STATE_ESTABLISHED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT);
|
||||||
|
if (n > 0) {
|
||||||
|
net_send(i, s_net_buf, n, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
|
ch395f_phase5_tests();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PHASE7_TESTS
|
||||||
|
ch395f_phase7_tests();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
osDelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
App/task/net_task.h
Normal file
25
App/task/net_task.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Network Application Task
|
||||||
|
* 模块功能:网络协议栈轮询、TCP/UDP 业务处理
|
||||||
|
* 适用平台:STM32F407ZGTx + CH395F
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_TASK_H
|
||||||
|
#define __NET_TASK_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int net_task_init(void);
|
||||||
|
void net_task_func(void const *arg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __NET_TASK_H */
|
||||||
45
App/task/rs485_task.c
Normal file
45
App/task/rs485_task.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:RS485 Communication Task
|
||||||
|
* 模块功能:RS-485 轮询收发、协议帧解析与响应
|
||||||
|
* 适用平台:STM32F407ZGTx
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rs485_task.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
#include "rs485.h"
|
||||||
|
|
||||||
|
#define DBG_TAG "[RS485_TASK]"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:RS485 任务初始化
|
||||||
|
* 入口参数:无
|
||||||
|
* 返 回 值:0 - 成功,-1 - 失败
|
||||||
|
* 限定条件:UART 和 GPIO 已由 CubeMX 初始化
|
||||||
|
* 函数说明:配置 RS-485 通信参数,注册接收回调
|
||||||
|
*/
|
||||||
|
int rs485_task_init(void)
|
||||||
|
{
|
||||||
|
DBG_INFO("rs485_task_init");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:RS485 任务主函数
|
||||||
|
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
||||||
|
* 返 回 值:无
|
||||||
|
* 限定条件:rs485_task_init() 已成功调用
|
||||||
|
* 函数说明:轮询接收缓冲区并解析协议帧
|
||||||
|
*/
|
||||||
|
void rs485_task_func(void const *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
osDelay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
App/task/rs485_task.h
Normal file
25
App/task/rs485_task.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:RS485 Communication Task
|
||||||
|
* 模块功能:RS-485 数据收发与协议解析
|
||||||
|
* 适用平台:STM32F407ZGTx
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RS485_TASK_H
|
||||||
|
#define __RS485_TASK_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int rs485_task_init(void);
|
||||||
|
void rs485_task_func(void const *arg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __RS485_TASK_H */
|
||||||
122
App/util/crc.c
Normal file
122
App/util/crc.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:CRC Utility
|
||||||
|
* 模块功能:CRC-16 Modbus (poly=0x8005, init=0xFFFF, refin=true, refout=true, xorout=0x0000)
|
||||||
|
* CRC-8 (poly=0x07, init=0x00, refin=false, refout=false, xorout=0x00)
|
||||||
|
* 适用平台:通用嵌入式平台
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
|
static const uint16_t s_crc16_table[256] = {
|
||||||
|
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||||
|
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||||
|
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||||
|
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||||
|
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||||
|
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||||
|
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||||
|
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||||
|
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||||
|
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||||
|
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||||
|
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||||
|
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||||
|
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||||
|
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||||
|
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||||
|
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||||
|
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||||
|
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||||
|
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||||
|
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||||
|
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||||
|
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||||
|
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||||
|
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||||
|
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||||
|
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||||
|
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||||
|
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||||
|
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||||
|
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||||
|
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t s_crc8_table[256] = {
|
||||||
|
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
|
||||||
|
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
|
||||||
|
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||||
|
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
|
||||||
|
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
|
||||||
|
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
|
||||||
|
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
|
||||||
|
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
|
||||||
|
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
|
||||||
|
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
|
||||||
|
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
|
||||||
|
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
|
||||||
|
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
|
||||||
|
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
|
||||||
|
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
|
||||||
|
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
|
||||||
|
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
|
||||||
|
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
|
||||||
|
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
|
||||||
|
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
|
||||||
|
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
|
||||||
|
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
|
||||||
|
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
|
||||||
|
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
|
||||||
|
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
|
||||||
|
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
|
||||||
|
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
|
||||||
|
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
|
||||||
|
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
|
||||||
|
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
|
||||||
|
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
|
||||||
|
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:计算 CRC-16 Modbus
|
||||||
|
* 入口参数:data - 数据指针
|
||||||
|
* len - 数据长度
|
||||||
|
* 返 回 值:16 位 CRC 值
|
||||||
|
* 限定条件:data 为非空指针
|
||||||
|
* 函数说明:多项式 0x8005,初始值 0xFFFF,结果异或 0x0000
|
||||||
|
*/
|
||||||
|
uint16_t crc16_modbus(const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
uint16_t crc = 0xFFFF;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
crc = (crc >> 8) ^ s_crc16_table[(crc ^ data[i]) & 0xFF];
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:计算 CRC-8
|
||||||
|
* 入口参数:data - 数据指针
|
||||||
|
* len - 数据长度
|
||||||
|
* 返 回 值:8 位 CRC 值
|
||||||
|
* 限定条件:data 为非空指针
|
||||||
|
* 函数说明:多项式 0x07,初始值 0x00
|
||||||
|
*/
|
||||||
|
uint8_t crc8(const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t crc = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
crc = s_crc8_table[crc ^ data[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
28
App/util/crc.h
Normal file
28
App/util/crc.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:CRC Utility
|
||||||
|
* 模块功能:CRC-16 Modbus & CRC-8 查表计算
|
||||||
|
* 适用平台:通用嵌入式平台
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CRC_H
|
||||||
|
#define __CRC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
uint16_t crc16_modbus(const uint8_t *data, size_t len);
|
||||||
|
uint8_t crc8(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CRC_H */
|
||||||
164
App/util/ringbuf.c
Normal file
164
App/util/ringbuf.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Ring Buffer
|
||||||
|
* 模块功能:字节环形缓冲区实现,head == tail 为空,head + 1 == tail 为满
|
||||||
|
* 适用平台:通用嵌入式平台
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ringbuf.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:初始化环形缓冲区
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* pool - 存储池指针
|
||||||
|
* size - 存储池大小(字节)
|
||||||
|
* 返 回 值:无
|
||||||
|
* 限定条件:rb 和 pool 均为非空指针
|
||||||
|
* 函数说明:size 保留一个空位用于区分空/满状态
|
||||||
|
*/
|
||||||
|
void ringbuf_init(ringbuf_t *rb, uint8_t *pool, size_t size)
|
||||||
|
{
|
||||||
|
rb->buf = pool;
|
||||||
|
rb->size = size;
|
||||||
|
rb->head = 0;
|
||||||
|
rb->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:写入数据到环形缓冲区
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* data - 源数据指针
|
||||||
|
* len - 待写入长度
|
||||||
|
* 返 回 值:实际写入字节数
|
||||||
|
* 限定条件:rb 和 data 均为非空指针
|
||||||
|
* 函数说明:空间不足时写入能容纳的最大字节数
|
||||||
|
*/
|
||||||
|
size_t ringbuf_put(ringbuf_t *rb, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
size_t cap = 0;
|
||||||
|
size_t n = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
cap = rb->size - 1 - ringbuf_avail(rb);
|
||||||
|
n = (len < cap) ? len : cap;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
rb->buf[rb->head] = data[i];
|
||||||
|
rb->head = (rb->head + 1) % rb->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:从环形缓冲区读取数据
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* data - 目标数据指针
|
||||||
|
* len - 期望读取长度
|
||||||
|
* 返 回 值:实际读取字节数
|
||||||
|
* 限定条件:rb 和 data 均为非空指针
|
||||||
|
* 函数说明:读取后数据从缓冲区移除
|
||||||
|
*/
|
||||||
|
size_t ringbuf_get(ringbuf_t *rb, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
n = ringbuf_avail(rb);
|
||||||
|
n = (n < len) ? n : len;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
data[i] = rb->buf[rb->tail];
|
||||||
|
rb->tail = (rb->tail + 1) % rb->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:预读取数据(不移除)
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* data - 目标数据指针
|
||||||
|
* len - 期望读取长度
|
||||||
|
* 返 回 值:实际可读取字节数
|
||||||
|
* 限定条件:rb 和 data 均为非空指针
|
||||||
|
* 函数说明:与 ringbuf_get 的区别是不移动 tail 指针
|
||||||
|
*/
|
||||||
|
size_t ringbuf_peek(const ringbuf_t *rb, uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
size_t idx = 0;
|
||||||
|
|
||||||
|
n = ringbuf_avail(rb);
|
||||||
|
n = (n < len) ? n : len;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
idx = (rb->tail + i) % rb->size;
|
||||||
|
data[i] = rb->buf[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取缓冲区中有效数据长度
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* 返 回 值:有效数据字节数
|
||||||
|
* 限定条件:rb 为非空指针
|
||||||
|
*/
|
||||||
|
size_t ringbuf_avail(const ringbuf_t *rb)
|
||||||
|
{
|
||||||
|
if (rb->head >= rb->tail) {
|
||||||
|
return rb->head - rb->tail;
|
||||||
|
}
|
||||||
|
return rb->size - rb->tail + rb->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:获取缓冲区剩余空间
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* 返 回 值:剩余空间字节数(保留一个空位)
|
||||||
|
* 限定条件:rb 为非空指针
|
||||||
|
*/
|
||||||
|
size_t ringbuf_space(const ringbuf_t *rb)
|
||||||
|
{
|
||||||
|
return rb->size - 1 - ringbuf_avail(rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:判断缓冲区是否为空
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* 返 回 值:1 - 空,0 - 非空
|
||||||
|
* 限定条件:rb 为非空指针
|
||||||
|
*/
|
||||||
|
int ringbuf_is_empty(const ringbuf_t *rb)
|
||||||
|
{
|
||||||
|
return (rb->head == rb->tail) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:判断缓冲区是否为满
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* 返 回 值:1 - 满,0 - 非满
|
||||||
|
* 限定条件:rb 为非空指针
|
||||||
|
*/
|
||||||
|
int ringbuf_is_full(const ringbuf_t *rb)
|
||||||
|
{
|
||||||
|
return (ringbuf_avail(rb) == rb->size - 1) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 函数功能:重置缓冲区
|
||||||
|
* 入口参数:rb - 缓冲区控制块指针
|
||||||
|
* 返 回 值:无
|
||||||
|
* 限定条件:rb 为非空指针
|
||||||
|
*/
|
||||||
|
void ringbuf_reset(ringbuf_t *rb)
|
||||||
|
{
|
||||||
|
rb->head = 0;
|
||||||
|
rb->tail = 0;
|
||||||
|
}
|
||||||
42
App/util/ringbuf.h
Normal file
42
App/util/ringbuf.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 模块名称:Ring Buffer
|
||||||
|
* 模块功能:线程安全的字节环形缓冲区(单生产者-单消费者模型)
|
||||||
|
* 适用平台:通用嵌入式平台
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-19
|
||||||
|
* 修改记录:
|
||||||
|
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RINGBUF_H
|
||||||
|
#define __RINGBUF_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t size;
|
||||||
|
size_t head;
|
||||||
|
size_t tail;
|
||||||
|
} ringbuf_t;
|
||||||
|
|
||||||
|
void ringbuf_init(ringbuf_t *rb, uint8_t *pool, size_t size);
|
||||||
|
size_t ringbuf_put(ringbuf_t *rb, const uint8_t *data, size_t len);
|
||||||
|
size_t ringbuf_get(ringbuf_t *rb, uint8_t *data, size_t len);
|
||||||
|
size_t ringbuf_peek(const ringbuf_t *rb, uint8_t *data, size_t len);
|
||||||
|
size_t ringbuf_avail(const ringbuf_t *rb);
|
||||||
|
size_t ringbuf_space(const ringbuf_t *rb);
|
||||||
|
int ringbuf_is_empty(const ringbuf_t *rb);
|
||||||
|
int ringbuf_is_full(const ringbuf_t *rb);
|
||||||
|
void ringbuf_reset(ringbuf_t *rb);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __RINGBUF_H */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,26 +2,23 @@
|
|||||||
* 模å<C2A1>—å<E28094><C3A5>称:CH395F Driver Test Suite
|
* 模å<C2A1>—å<E28094><C3A5>称:CH395F Driver Test Suite
|
||||||
* 模å<C2A1>—功能:CH395F 驱动å<C2A8>„功能模å<C2A1>—的测试入å<C2A5>£ï¼Œåˆ†é˜¶æ®µç»„织测试用例
|
* 模å<C2A1>—功能:CH395F 驱动å<C2A8>„功能模å<C2A1>—的测试入å<C2A5>£ï¼Œåˆ†é˜¶æ®µç»„织测试用例
|
||||||
* 适用平å<C2B3>°ï¼šSTM32F4 系列(CH395F 以太网芯片)
|
* 适用平å<C2B3>°ï¼šSTM32F4 系列(CH395F 以太网芯片)
|
||||||
* 作者:王建锋
|
* 作者:王建� * 创建日期�026-07-19
|
||||||
* 创建日期:2026-07-19
|
* 修改记录� * 2026-07-19 Phase 1/2/3 implemented
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-19 Phase 1/2/3 implemented
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 头文件包å<E280A6>«åŒº */
|
/* 头文件包å<E280A6>«åŒº */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "ch395f_test.h"
|
#include "ch395f_test.h"
|
||||||
#include "ch395f.h"
|
#include "ch395f.h"
|
||||||
#include "net_socket.h"
|
#include "net_socket.h"
|
||||||
#define DBG_TAG "[CH395T]"
|
#define DBG_TAG "[CH395T]"
|
||||||
#include "dbg_log.h"
|
#include "dbg_log.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
test_stats_t g_test_stats;
|
test_stats_t g_test_stats;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phase 2 配置默认值
|
* Phase 2 é…<EFBFBD>置默认ï¿? */
|
||||||
*/
|
|
||||||
#ifndef PHASE2_REMOTE_IP
|
#ifndef PHASE2_REMOTE_IP
|
||||||
#define PHASE2_REMOTE_IP "192.168.1.2"
|
#define PHASE2_REMOTE_IP "192.168.1.2"
|
||||||
#endif
|
#endif
|
||||||
@@ -39,8 +36,7 @@ test_stats_t g_test_stats;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phase 3 配置默认值
|
* Phase 3 é…<EFBFBD>置默认ï¿? */
|
||||||
*/
|
|
||||||
#ifndef PHASE3_REMOTE_IP
|
#ifndef PHASE3_REMOTE_IP
|
||||||
#define PHASE3_REMOTE_IP "192.168.1.2"
|
#define PHASE3_REMOTE_IP "192.168.1.2"
|
||||||
#endif
|
#endif
|
||||||
@@ -58,13 +54,12 @@ test_stats_t g_test_stats;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 恢复 TCP Server 多连接模式的数据 Socket 配置
|
* 函数功能:æ<EFBFBD>¢ï¿?TCP Server 多连接模å¼<C3A5>的数æ<C2B0>® Socket é…<EFBFBD>ç½®
|
||||||
*/
|
* å…¥å<C2A5>£å<C2A3>‚数:port - TCP æº<C3A6>端å<C2AF>£å<C2A3>·
|
||||||
static void restore_data_sockets(uint16_t port)
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šCH395F å<><C3A5>è®®æ ˆå·²åˆ<C3A5>å§‹ï¿? * 函数说明:é‡<C3A9>新设置数ï¿?Socket çš„å<E2809E><C3A5>议类型和æº<C3A6>端ï¿? */
|
||||||
{
|
static void restore_data_sockets(uint16_t port) {
|
||||||
int i;
|
int i = 0;
|
||||||
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
for (i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) {
|
||||||
{
|
|
||||||
ch395f_set_proto_type((uint8_t)i, CH395F_PROTO_TYPE_TCP);
|
ch395f_set_proto_type((uint8_t)i, CH395F_PROTO_TYPE_TCP);
|
||||||
ch395f_set_sour_port((uint8_t)i, port);
|
ch395f_set_sour_port((uint8_t)i, port);
|
||||||
}
|
}
|
||||||
@@ -73,12 +68,14 @@ static void restore_data_sockets(uint16_t port)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 1 ============================
|
* ============================ Phase 1 ============================
|
||||||
*/
|
* 函数功能:寄å˜å™¨è¯»å†™ + 䏿–一致性基础测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šCH395F 芯片æ£å¸¸åº”ç”
|
||||||
|
* 函数说明:包�GET_VERSION / GET_CMD_STATUS / GET_IP_INF �9 � */
|
||||||
|
|
||||||
void ch395f_phase1_tests(void)
|
void ch395f_phase1_tests(void) {
|
||||||
{
|
uint8_t i = 0;
|
||||||
uint8_t i;
|
int ver = 0;
|
||||||
int ver;
|
|
||||||
|
|
||||||
DBG_INFO("=== CH395F Phase 1 Tests ===");
|
DBG_INFO("=== CH395F Phase 1 Tests ===");
|
||||||
|
|
||||||
@@ -115,7 +112,7 @@ void ch395f_phase1_tests(void)
|
|||||||
"GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)",
|
"GINT_STATUS_ALL: 0x%04X (lo=0x%02X hi=0x%02X)",
|
||||||
gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF);
|
gint_all, gint_all & 0xFF, (gint_all >> 8) & 0xFF);
|
||||||
|
|
||||||
/* Test 5: GINT_STATUS (1-byte version) — read-clear check */
|
/* Test 5: GINT_STATUS (1-byte version) ï¿?read-clear check */
|
||||||
uint8_t gint_1b = ch395f_get_glob_int_status();
|
uint8_t gint_1b = ch395f_get_glob_int_status();
|
||||||
TEST_CHECK(gint_1b == 0x00,
|
TEST_CHECK(gint_1b == 0x00,
|
||||||
"GINT_STATUS_1byte: 0x%02X (expect 0x00 after read-clear)", gint_1b);
|
"GINT_STATUS_1byte: 0x%02X (expect 0x00 after read-clear)", gint_1b);
|
||||||
@@ -139,8 +136,7 @@ void ch395f_phase1_tests(void)
|
|||||||
/* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */
|
/* Test 9: CLEAR_RECV_BUF + SOCK_INT poll */
|
||||||
ch395f_clear_recv_buf(0);
|
ch395f_clear_recv_buf(0);
|
||||||
TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK");
|
TEST_CHECK(1, "CLEAR_RECV_BUF(sock=0): OK");
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++) {
|
||||||
{
|
|
||||||
uint8_t si = ch395f_get_sock_int_status(i);
|
uint8_t si = ch395f_get_sock_int_status(i);
|
||||||
TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si);
|
TEST_CHECK(si == 0x00, "SOCK_INT(%d): 0x%02X", i, si);
|
||||||
}
|
}
|
||||||
@@ -150,17 +146,17 @@ void ch395f_phase1_tests(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 2 ============================
|
* ============================ Phase 2 ============================
|
||||||
*/
|
* 函数功能:TCP Client æ”¶å<C2B6>‘ + å…³é—é‡<C3A9>连 ×3 ï¿? * å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šPC 端已å<C2B2>¯åЍ TCP Server(默ï¿?192.168.1.2:8081ï¿? * 函数说明:æ¯<C3A6>轮连接→å<E28099>‘é€<C3A9>→接收→关é—ï¼Œè¿žç» 3 ï¿? */
|
||||||
|
|
||||||
void ch395f_phase2_tests(void)
|
void ch395f_phase2_tests(void) {
|
||||||
{
|
uint8_t sock = 0;
|
||||||
uint8_t sock;
|
uint8_t sock_int = 0;
|
||||||
uint8_t sock_int;
|
uint8_t rx_buf[300] = {0};
|
||||||
uint8_t rx_buf[300];
|
int i = 0;
|
||||||
int i;
|
uint32_t tick = 0;
|
||||||
uint32_t tick;
|
uint16_t int_st = 0;
|
||||||
uint16_t int_st;
|
int iter_pass = 0;
|
||||||
int iter_pass;
|
|
||||||
|
|
||||||
DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ===");
|
DBG_INFO("=== CH395F Phase 2 Tests (TCP Client - Direct Driver) ===");
|
||||||
|
|
||||||
@@ -178,15 +174,14 @@ void ch395f_phase2_tests(void)
|
|||||||
|
|
||||||
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
||||||
|
|
||||||
/* 一次性配置 */
|
/* 一次性é…<EFBFBD>ï¿?*/
|
||||||
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP);
|
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_TCP);
|
||||||
ch395f_set_send_buf(sock, 28, 2);
|
ch395f_set_send_buf(sock, 28, 2);
|
||||||
ch395f_set_recv_buf(sock, 30, 2);
|
ch395f_set_recv_buf(sock, 30, 2);
|
||||||
ch395f_set_des_ip(sock, ip_arr);
|
ch395f_set_des_ip(sock, ip_arr);
|
||||||
ch395f_set_des_port(sock, PHASE2_REMOTE_PORT);
|
ch395f_set_des_port(sock, PHASE2_REMOTE_PORT);
|
||||||
|
|
||||||
for (i = 0; i < PHASE2_LOOP_COUNT; i++)
|
for (i = 0; i < PHASE2_LOOP_COUNT; i++) {
|
||||||
{
|
|
||||||
DBG_INFO("--- Iteration %d/%d ---", i + 1, PHASE2_LOOP_COUNT);
|
DBG_INFO("--- Iteration %d/%d ---", i + 1, PHASE2_LOOP_COUNT);
|
||||||
iter_pass = 1;
|
iter_pass = 1;
|
||||||
|
|
||||||
@@ -197,11 +192,9 @@ void ch395f_phase2_tests(void)
|
|||||||
|
|
||||||
/* ç‰å¾… CONNECT */
|
/* ç‰å¾… CONNECT */
|
||||||
tick = HAL_GetTick();
|
tick = HAL_GetTick();
|
||||||
while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS)
|
while (HAL_GetTick() - tick < PHASE2_TIMEOUT_MS) {
|
||||||
{
|
|
||||||
int_st = ch395f_get_glob_int_status_all();
|
int_st = ch395f_get_glob_int_status_all();
|
||||||
if (int_st & (1U << (sock + 4)))
|
if (int_st & (1U << (sock + 4))) {
|
||||||
{
|
|
||||||
sock_int = ch395f_get_sock_int_status(sock);
|
sock_int = ch395f_get_sock_int_status(sock);
|
||||||
if (sock_int & CH395F_SINT_STAT_CONNECT) break;
|
if (sock_int & CH395F_SINT_STAT_CONNECT) break;
|
||||||
}
|
}
|
||||||
@@ -211,9 +204,9 @@ void ch395f_phase2_tests(void)
|
|||||||
|
|
||||||
HAL_Delay(100);
|
HAL_Delay(100);
|
||||||
|
|
||||||
/* 发送测试数据 */
|
/* å<EFBFBD>‘é€<EFBFBD>测试数ï¿?*/
|
||||||
{
|
{
|
||||||
uint8_t test_buf[64];
|
uint8_t test_buf[64] = {0};
|
||||||
const char *msg = "HelloFromCH395F_TCP_Client! This is a 64-byte test message.";
|
const char *msg = "HelloFromCH395F_TCP_Client! This is a 64-byte test message.";
|
||||||
int p, mlen = (int)strlen(msg);
|
int p, mlen = (int)strlen(msg);
|
||||||
memcpy(test_buf, msg, mlen);
|
memcpy(test_buf, msg, mlen);
|
||||||
@@ -221,15 +214,13 @@ void ch395f_phase2_tests(void)
|
|||||||
ch395f_write_send_buf(sock, test_buf, 64);
|
ch395f_write_send_buf(sock, test_buf, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Echo 循环:收数据 → 回发 */
|
/* Echo 循环:收数æ<EFBFBD>® ï¿?回å<C5BE>‘ */
|
||||||
{
|
{
|
||||||
int got_echo = 0;
|
int got_echo = 0;
|
||||||
tick = HAL_GetTick();
|
tick = HAL_GetTick();
|
||||||
while (HAL_GetTick() - tick < 10000)
|
while (HAL_GetTick() - tick < 10000) {
|
||||||
{
|
|
||||||
uint16_t rlen = ch395f_get_recv_len(sock);
|
uint16_t rlen = ch395f_get_recv_len(sock);
|
||||||
if (rlen > 0)
|
if (rlen > 0) {
|
||||||
{
|
|
||||||
uint16_t read_len = (rlen > sizeof(rx_buf)) ? (uint16_t)sizeof(rx_buf) : rlen;
|
uint16_t read_len = (rlen > sizeof(rx_buf)) ? (uint16_t)sizeof(rx_buf) : rlen;
|
||||||
memset(rx_buf, 0, sizeof(rx_buf));
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
ch395f_read_recv_buf(sock, rx_buf, read_len);
|
ch395f_read_recv_buf(sock, rx_buf, read_len);
|
||||||
@@ -239,8 +230,7 @@ void ch395f_phase2_tests(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int_st = ch395f_get_glob_int_status_all();
|
int_st = ch395f_get_glob_int_status_all();
|
||||||
if (int_st & (1U << (sock + 4)))
|
if (int_st & (1U << (sock + 4))) {
|
||||||
{
|
|
||||||
sock_int = ch395f_get_sock_int_status(sock);
|
sock_int = ch395f_get_sock_int_status(sock);
|
||||||
if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); break; }
|
if (sock_int & CH395F_SINT_STAT_DISCONNECT) { DBG_INFO("DISCONNECT"); break; }
|
||||||
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); break; }
|
if (sock_int & CH395F_SINT_STAT_SOCK_TIMEOUT) { DBG_INFO("SOCK_TIMEOUT"); break; }
|
||||||
@@ -258,8 +248,7 @@ phase2_iter_done:
|
|||||||
{
|
{
|
||||||
uint8_t st[2];
|
uint8_t st[2];
|
||||||
uint32_t wait = HAL_GetTick();
|
uint32_t wait = HAL_GetTick();
|
||||||
while (HAL_GetTick() - wait < 5000)
|
while (HAL_GetTick() - wait < 5000) {
|
||||||
{
|
|
||||||
ch395f_get_socket_status(sock, st);
|
ch395f_get_socket_status(sock, st);
|
||||||
if (st[0] == CH395F_SOCKET_CLOSED) break;
|
if (st[0] == CH395F_SOCKET_CLOSED) break;
|
||||||
HAL_Delay(50);
|
HAL_Delay(50);
|
||||||
@@ -275,21 +264,22 @@ phase2_iter_done:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 3 ============================
|
* ============================ Phase 3 ============================
|
||||||
*/
|
* 函数功能:UDP Server Echo + PING + 大包测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šPC 端已å<C2B2>¯åЍ UDP Client(默ï¿?192.168.1.2:8082ï¿? * 函数说明:包ï¿?20 次回显�? ï¿?PINGï¿?0 次大包收ï¿? */
|
||||||
|
|
||||||
void ch395f_phase3_tests(void)
|
void ch395f_phase3_tests(void) {
|
||||||
{
|
uint8_t sock = 0;
|
||||||
uint8_t sock;
|
uint8_t rx_buf[300] = {0};
|
||||||
uint8_t rx_buf[300];
|
uint32_t tick = 0;
|
||||||
uint32_t tick;
|
int i = 0;
|
||||||
int i;
|
int echo_ok = 0;
|
||||||
int echo_ok;
|
|
||||||
|
|
||||||
DBG_INFO("=== CH395F Phase 3 Tests (UDP) ===");
|
DBG_INFO("=== CH395F Phase 3 Tests (UDP) ===");
|
||||||
|
|
||||||
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
sock = (uint8_t)(NET_MAX_SOCKETS - 1);
|
||||||
|
|
||||||
/* UDP Server 模式:DesIP=0xFFFFFFFF → 接受任意来源 */
|
/* UDP Server 模å¼<EFBFBD>:DesIP=0xFFFFFFFF ï¿?接å<C2A5>—ä»»æ„<C3A6>æ<EFBFBD>¥æº<C3A6> */
|
||||||
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_UDP);
|
ch395f_set_proto_type(sock, CH395F_PROTO_TYPE_UDP);
|
||||||
ch395f_set_send_buf(sock, 28, 2);
|
ch395f_set_send_buf(sock, 28, 2);
|
||||||
ch395f_set_recv_buf(sock, 30, 2);
|
ch395f_set_recv_buf(sock, 30, 2);
|
||||||
@@ -305,16 +295,13 @@ void ch395f_phase3_tests(void)
|
|||||||
|
|
||||||
HAL_Delay(200);
|
HAL_Delay(200);
|
||||||
|
|
||||||
/* Echo 循环:收到 → 解析来源 → 回显 */
|
/* Echo 循环:收ï¿?ï¿?è§£æž<C3A6>æ<EFBFBD>¥æº<C3A6> ï¿?回显 */
|
||||||
for (i = 0; i < PHASE3_ECHO_COUNT; i++)
|
for (i = 0; i < PHASE3_ECHO_COUNT; i++) {
|
||||||
{
|
|
||||||
tick = HAL_GetTick();
|
tick = HAL_GetTick();
|
||||||
echo_ok = 0;
|
echo_ok = 0;
|
||||||
while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS)
|
while (HAL_GetTick() - tick < PHASE3_TIMEOUT_MS) {
|
||||||
{
|
|
||||||
uint16_t rlen = ch395f_get_recv_len(sock);
|
uint16_t rlen = ch395f_get_recv_len(sock);
|
||||||
if (rlen > 8)
|
if (rlen > 8) {
|
||||||
{
|
|
||||||
memset(rx_buf, 0, sizeof(rx_buf));
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
ch395f_read_recv_buf(sock, rx_buf, rlen);
|
ch395f_read_recv_buf(sock, rx_buf, rlen);
|
||||||
|
|
||||||
@@ -334,11 +321,9 @@ void ch395f_phase3_tests(void)
|
|||||||
|
|
||||||
{
|
{
|
||||||
uint32_t swait = HAL_GetTick();
|
uint32_t swait = HAL_GetTick();
|
||||||
while (HAL_GetTick() - swait < 2000)
|
while (HAL_GetTick() - swait < 2000) {
|
||||||
{
|
|
||||||
uint16_t gs = ch395f_get_glob_int_status_all();
|
uint16_t gs = ch395f_get_glob_int_status_all();
|
||||||
if (gs & (1U << (sock + 4)))
|
if (gs & (1U << (sock + 4))) {
|
||||||
{
|
|
||||||
if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -363,27 +348,28 @@ void ch395f_phase3_tests(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 4 ============================
|
* ============================ Phase 4 ============================
|
||||||
* NET 层 TCP Echo:在主循环中调用,用 net_recv + net_send 回显
|
* NET ï¿?TCP Echo:在主循环ä¸è°ƒç”¨ï¼Œç”¨ net_recv + net_send 回显
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef ENABLE_PHASE4_TESTS
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
static char s_phase4_buf[2048];
|
static char s_phase4_buf[2048];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ch395f_phase4_tests(void)
|
/*
|
||||||
{
|
* 函数功能:NET �TCP Echo 测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完ï¿? * 函数说明:在 netTask ä¸è¿<C3A8>行,轮询 Socket 1~7 回显接收数æ<C2B0>®
|
||||||
|
*/
|
||||||
|
void ch395f_phase4_tests(void) {
|
||||||
#ifdef ENABLE_PHASE4_TESTS
|
#ifdef ENABLE_PHASE4_TESTS
|
||||||
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) {
|
||||||
{
|
|
||||||
net_sock_t *sk = net_get_sock(i);
|
net_sock_t *sk = net_get_sock(i);
|
||||||
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = net_recv(i, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT);
|
int n = net_recv(i, s_phase4_buf, sizeof(s_phase4_buf), NET_MSG_DONTWAIT);
|
||||||
if (n > 0)
|
if (n > 0) {
|
||||||
{
|
|
||||||
net_send(i, s_phase4_buf, n, 0);
|
net_send(i, s_phase4_buf, n, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,7 +378,7 @@ void ch395f_phase4_tests(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 5 ============================
|
* ============================ Phase 5 ============================
|
||||||
* NET 层 UDP Echo:netTask 中运行,用 net_recvfrom + net_sendto 回显
|
* NET ï¿?UDP Echo:netTask ä¸è¿<EFBFBD>行,ï¿?net_recvfrom + net_sendto 回显
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PHASE5_LOCAL_PORT
|
#ifndef PHASE5_LOCAL_PORT
|
||||||
@@ -405,14 +391,15 @@ static char s_phase5_buf[2048];
|
|||||||
static uint32_t s_phase5_count = 0;
|
static uint32_t s_phase5_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ch395f_phase5_init(void)
|
/*
|
||||||
{
|
* 函数功能:NET ï¿?UDP Echo åˆ<C3A5>å§‹ï¿? * å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完ï¿? * 函数说明:创ï¿?UDP Socket 并绑定本地端ï¿? */
|
||||||
|
void ch395f_phase5_init(void) {
|
||||||
#ifdef ENABLE_PHASE5_TESTS
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
struct net_sockaddr_in addr;
|
struct net_sockaddr_in addr;
|
||||||
|
|
||||||
s_phase5_sock = net_socket(NET_AF_INET, NET_SOCK_DGRAM, 0);
|
s_phase5_sock = net_socket(NET_AF_INET, NET_SOCK_DGRAM, 0);
|
||||||
if (s_phase5_sock < 0)
|
if (s_phase5_sock < 0) {
|
||||||
{
|
|
||||||
DBG_ERROR("Phase5: net_socket failed");
|
DBG_ERROR("Phase5: net_socket failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -421,8 +408,7 @@ void ch395f_phase5_init(void)
|
|||||||
addr.sin_family = NET_AF_INET;
|
addr.sin_family = NET_AF_INET;
|
||||||
addr.sin_port = net_htons(PHASE5_LOCAL_PORT);
|
addr.sin_port = net_htons(PHASE5_LOCAL_PORT);
|
||||||
|
|
||||||
if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0)
|
if (net_bind(s_phase5_sock, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
{
|
|
||||||
DBG_ERROR("Phase5: net_bind failed");
|
DBG_ERROR("Phase5: net_bind failed");
|
||||||
net_close(s_phase5_sock);
|
net_close(s_phase5_sock);
|
||||||
s_phase5_sock = -1;
|
s_phase5_sock = -1;
|
||||||
@@ -434,8 +420,12 @@ void ch395f_phase5_init(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ch395f_phase5_tests(void)
|
/*
|
||||||
{
|
* 函数功能:NET �UDP Echo 测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šch395f_phase5_init å·²æˆ<C3A6>功调ï¿? * 函数说明:在 netTask ä¸è¿<C3A8>行,回显 UDP 接收数æ<C2B0>®
|
||||||
|
*/
|
||||||
|
void ch395f_phase5_tests(void) {
|
||||||
#ifdef ENABLE_PHASE5_TESTS
|
#ifdef ENABLE_PHASE5_TESTS
|
||||||
if (s_phase5_sock < 0) return;
|
if (s_phase5_sock < 0) return;
|
||||||
|
|
||||||
@@ -445,8 +435,7 @@ void ch395f_phase5_tests(void)
|
|||||||
int n = net_recvfrom(s_phase5_sock, s_phase5_buf, sizeof(s_phase5_buf),
|
int n = net_recvfrom(s_phase5_sock, s_phase5_buf, sizeof(s_phase5_buf),
|
||||||
NET_MSG_DONTWAIT,
|
NET_MSG_DONTWAIT,
|
||||||
(struct net_sockaddr *)&src, &addrlen);
|
(struct net_sockaddr *)&src, &addrlen);
|
||||||
if (n > 0)
|
if (n > 0) {
|
||||||
{
|
|
||||||
net_sendto(s_phase5_sock, s_phase5_buf, n, 0,
|
net_sendto(s_phase5_sock, s_phase5_buf, n, 0,
|
||||||
(struct net_sockaddr *)&src, sizeof(src));
|
(struct net_sockaddr *)&src, sizeof(src));
|
||||||
s_phase5_count++;
|
s_phase5_count++;
|
||||||
@@ -456,8 +445,7 @@ void ch395f_phase5_tests(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phase 6 配置默认值
|
* Phase 6 é…<EFBFBD>置默认ï¿? */
|
||||||
*/
|
|
||||||
#ifndef PHASE6_ANNOUNCE_PORT
|
#ifndef PHASE6_ANNOUNCE_PORT
|
||||||
#define PHASE6_ANNOUNCE_PORT 60001
|
#define PHASE6_ANNOUNCE_PORT 60001
|
||||||
#endif
|
#endif
|
||||||
@@ -467,15 +455,17 @@ void ch395f_phase5_tests(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 6 ============================
|
* ============================ Phase 6 ============================
|
||||||
* DHCP 自动获取 IP 测试
|
* 函数功能:DHCP 自动获å<C2B7>– IP 测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šå±€åŸŸç½‘内å˜ï¿?DHCP Server
|
||||||
|
* 函数说明:å<C5A1>¯ï¿?DHCP ï¿?轮询ç‰å¾… IP ï¿?打å<E2809C>°ç»“æžœ ï¿?广æ’宣告 ï¿?HELLO 回显
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ch395f_phase6_tests(void)
|
void ch395f_phase6_tests(void) {
|
||||||
{
|
|
||||||
#ifdef ENABLE_PHASE6_TESTS
|
#ifdef ENABLE_PHASE6_TESTS
|
||||||
uint8_t status;
|
uint8_t status = 0;
|
||||||
uint8_t ip_info[20];
|
uint8_t ip_info[20] = {0};
|
||||||
uint32_t tick;
|
uint32_t tick = 0;
|
||||||
|
|
||||||
DBG_INFO("=== CH395F Phase 6 Tests (DHCP) ===");
|
DBG_INFO("=== CH395F Phase 6 Tests (DHCP) ===");
|
||||||
|
|
||||||
@@ -486,17 +476,14 @@ void ch395f_phase6_tests(void)
|
|||||||
/* 2. 轮询ç‰å¾… DHCP 完æˆ<C3A6> */
|
/* 2. 轮询ç‰å¾… DHCP 完æˆ<C3A6> */
|
||||||
HAL_Delay(500);
|
HAL_Delay(500);
|
||||||
tick = HAL_GetTick();
|
tick = HAL_GetTick();
|
||||||
while (HAL_GetTick() - tick < 30000)
|
while (HAL_GetTick() - tick < 30000) {
|
||||||
{
|
|
||||||
uint16_t gint = ch395f_get_glob_int_status_all();
|
uint16_t gint = ch395f_get_glob_int_status_all();
|
||||||
if (gint & CH395F_GINT_STAT_DHCP)
|
if (gint & CH395F_GINT_STAT_DHCP) {
|
||||||
{
|
|
||||||
DBG_INFO("DHCP interrupt");
|
DBG_INFO("DHCP interrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ch395f_get_dhcp_status();
|
status = ch395f_get_dhcp_status();
|
||||||
if (status == 0x00)
|
if (status == 0x00) {
|
||||||
{
|
|
||||||
TEST_CHECK(1, "DHCP: SUCCESS");
|
TEST_CHECK(1, "DHCP: SUCCESS");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -507,12 +494,11 @@ void ch395f_phase6_tests(void)
|
|||||||
TEST_CHECK(HAL_GetTick() - tick < 30000,
|
TEST_CHECK(HAL_GetTick() - tick < 30000,
|
||||||
"DHCP completed within 30s (status=0x%02X)", status);
|
"DHCP completed within 30s (status=0x%02X)", status);
|
||||||
|
|
||||||
if (HAL_GetTick() - tick >= 30000)
|
if (HAL_GetTick() - tick >= 30000) {
|
||||||
{
|
|
||||||
goto phase6_end;
|
goto phase6_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. 读取获取的 IP */
|
/* 3. 读å<EFBFBD>–获å<EFBFBD>–ï¿?IP */
|
||||||
ch395f_get_ip_inf(ip_info);
|
ch395f_get_ip_inf(ip_info);
|
||||||
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
DBG_INFO(" IP: %d.%d.%d.%d", ip_info[0], ip_info[1], ip_info[2], ip_info[3]);
|
||||||
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
|
DBG_INFO(" GW: %d.%d.%d.%d", ip_info[4], ip_info[5], ip_info[6], ip_info[7]);
|
||||||
@@ -527,9 +513,9 @@ void ch395f_phase6_tests(void)
|
|||||||
#define PHASE6_HELLO_PORT 60000
|
#define PHASE6_HELLO_PORT 60000
|
||||||
uint8_t anno_sock = PHASE6_ANNOUNCE_SOCK;
|
uint8_t anno_sock = PHASE6_ANNOUNCE_SOCK;
|
||||||
uint8_t bcast_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
uint8_t bcast_ip[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
uint8_t rx_buf[64];
|
uint8_t rx_buf[64] = {0};
|
||||||
|
|
||||||
/* UDP Server 模式:本地端口 60000(接收 HELLO),DesIP=0xFFFFFFFF */
|
/* UDP Server 模å¼<EFBFBD>:本地端ï¿?60000(接ï¿?HELLO),DesIP=0xFFFFFFFF */
|
||||||
ch395f_set_proto_type(anno_sock, CH395F_PROTO_TYPE_UDP);
|
ch395f_set_proto_type(anno_sock, CH395F_PROTO_TYPE_UDP);
|
||||||
ch395f_set_send_buf(anno_sock, 24, 2);
|
ch395f_set_send_buf(anno_sock, 24, 2);
|
||||||
ch395f_set_recv_buf(anno_sock, 26, 2);
|
ch395f_set_recv_buf(anno_sock, 26, 2);
|
||||||
@@ -537,9 +523,8 @@ void ch395f_phase6_tests(void)
|
|||||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
ch395f_set_des_port(anno_sock, 0);
|
ch395f_set_des_port(anno_sock, 0);
|
||||||
|
|
||||||
if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS)
|
if (ch395f_open_socket(anno_sock) == CH395F_ERR_SUCCESS) {
|
||||||
{
|
/* å<>‘é€<C3A9>广æ’宣告(宣告端å<C2AF>£ = 60001,æ<C592>¥æº<C3A6>端ï¿?= 60000ï¿?*/
|
||||||
/* 发送广播宣告(宣告端口 = 60001,来源端口 = 60000) */
|
|
||||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
ch395f_set_des_port(anno_sock, PHASE6_ANNOUNCE_PORT);
|
ch395f_set_des_port(anno_sock, PHASE6_ANNOUNCE_PORT);
|
||||||
ch395f_write_send_buf(anno_sock, ip_info, 4);
|
ch395f_write_send_buf(anno_sock, ip_info, 4);
|
||||||
@@ -547,11 +532,9 @@ void ch395f_phase6_tests(void)
|
|||||||
/* ç‰å¾… SENDBUF_FREE(手册è¦<C3A8>求:æ¯<C3A6>次 write_send_buf å<>Žå¿…é¡»ç‰å¾…) */
|
/* ç‰å¾… SENDBUF_FREE(手册è¦<C3A8>求:æ¯<C3A6>次 write_send_buf å<>Žå¿…é¡»ç‰å¾…) */
|
||||||
{
|
{
|
||||||
uint32_t swait = HAL_GetTick();
|
uint32_t swait = HAL_GetTick();
|
||||||
while (HAL_GetTick() - swait < 2000)
|
while (HAL_GetTick() - swait < 2000) {
|
||||||
{
|
|
||||||
uint16_t gs = ch395f_get_glob_int_status_all();
|
uint16_t gs = ch395f_get_glob_int_status_all();
|
||||||
if (gs & (1U << (anno_sock + 4)))
|
if (gs & (1U << (anno_sock + 4))) {
|
||||||
{
|
|
||||||
if (ch395f_get_sock_int_status(anno_sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
if (ch395f_get_sock_int_status(anno_sock) & CH395F_SINT_STAT_SENBUF_FREE)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -563,26 +546,23 @@ void ch395f_phase6_tests(void)
|
|||||||
PHASE6_HELLO_PORT, PHASE6_ANNOUNCE_PORT);
|
PHASE6_HELLO_PORT, PHASE6_ANNOUNCE_PORT);
|
||||||
TEST_CHECK(1, "DHCP announcement sent");
|
TEST_CHECK(1, "DHCP announcement sent");
|
||||||
|
|
||||||
/* 重置 Server 模式,等待 PC 发送 HELLO */
|
/* é‡<EFBFBD>ç½® Server 模å¼<EFBFBD>,ç‰ï¿?PC å<>‘�?HELLO */
|
||||||
ch395f_set_des_ip(anno_sock, bcast_ip);
|
ch395f_set_des_ip(anno_sock, bcast_ip);
|
||||||
ch395f_set_des_port(anno_sock, 0);
|
ch395f_set_des_port(anno_sock, 0);
|
||||||
|
|
||||||
uint32_t wait = HAL_GetTick();
|
uint32_t wait = HAL_GetTick();
|
||||||
uint8_t hello_ok = 0;
|
uint8_t hello_ok = 0;
|
||||||
while (HAL_GetTick() - wait < 5000)
|
while (HAL_GetTick() - wait < 5000) {
|
||||||
{
|
/* 读å<C2BB>–免局䏿–(刷ï¿?socket 䏿–状æ€<C3A6>) */
|
||||||
/* 读取全局中断(刷新 socket 中断状态) */
|
|
||||||
ch395f_get_glob_int_status_all();
|
ch395f_get_glob_int_status_all();
|
||||||
uint16_t rlen = ch395f_get_recv_len(anno_sock);
|
uint16_t rlen = ch395f_get_recv_len(anno_sock);
|
||||||
if (rlen > 8)
|
if (rlen > 8) {
|
||||||
{
|
|
||||||
memset(rx_buf, 0, sizeof(rx_buf));
|
memset(rx_buf, 0, sizeof(rx_buf));
|
||||||
ch395f_read_recv_buf(anno_sock, rx_buf, rlen);
|
ch395f_read_recv_buf(anno_sock, rx_buf, rlen);
|
||||||
uint16_t payload_len = rlen - 8;
|
uint16_t payload_len = rlen - 8;
|
||||||
uint8_t *payload = &rx_buf[8];
|
uint8_t *payload = &rx_buf[8];
|
||||||
|
|
||||||
if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0)
|
if (payload_len == 5 && memcmp(payload, "HELLO", 5) == 0) {
|
||||||
{
|
|
||||||
uint8_t *src_ip = &rx_buf[4];
|
uint8_t *src_ip = &rx_buf[4];
|
||||||
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
uint16_t src_port = (uint16_t)rx_buf[2] | ((uint16_t)rx_buf[3] << 8);
|
||||||
ch395f_set_des_ip(anno_sock, src_ip);
|
ch395f_set_des_ip(anno_sock, src_ip);
|
||||||
@@ -601,9 +581,7 @@ void ch395f_phase6_tests(void)
|
|||||||
TEST_CHECK(hello_ok, "HELLO echo within 5s");
|
TEST_CHECK(hello_ok, "HELLO echo within 5s");
|
||||||
|
|
||||||
ch395f_close_socket(anno_sock);
|
ch395f_close_socket(anno_sock);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
TEST_CHECK(0, "DHCP announcement: open socket failed");
|
TEST_CHECK(0, "DHCP announcement: open socket failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,7 +593,7 @@ phase6_end:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ============================ Phase 7 ============================
|
* ============================ Phase 7 ============================
|
||||||
* Select/Poll I/O 多路复用测试 — net_select() + net_recv/send echo
|
* Select/Poll I/O 多路å¤<EFBFBD>用测试 ï¿?net_select() + net_recv/send echo
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "net_select.h"
|
#include "net_select.h"
|
||||||
@@ -624,20 +602,23 @@ phase6_end:
|
|||||||
static char s_phase7_buf[2048];
|
static char s_phase7_buf[2048];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ch395f_phase7_tests(void)
|
/*
|
||||||
{
|
* 函数功能:Select/Poll I/O 多路å¤<C3A5>用测试
|
||||||
|
* å…¥å<C2A5>£å<C2A3>‚数:æ—
|
||||||
|
* ï¿?ï¿?值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šnet_init 已完æˆ<C3A6>,多连ï¿?TCP Server å·²å<C2B2>¯ï¿? * 函数说明:在 netTask ä¸è¿<C3A8>行,验è¯<C3A8> select/poll æ£ç¡®è¿”回读写事件
|
||||||
|
*/
|
||||||
|
void ch395f_phase7_tests(void) {
|
||||||
#ifdef ENABLE_PHASE7_TESTS
|
#ifdef ENABLE_PHASE7_TESTS
|
||||||
static uint32_t s_phase7_count = 0;
|
static uint32_t s_phase7_count = 0;
|
||||||
net_fd_set readfds;
|
net_fd_set readfds;
|
||||||
net_timeval tv;
|
net_timeval tv;
|
||||||
|
FD_ZERO
|
||||||
|
|
||||||
NET_FD_ZERO(&readfds);
|
NET_FD_ZERO(&readfds);
|
||||||
|
|
||||||
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++)
|
for (int i = NET_TCP_SERVER_DATA_SOCK_START; i < NET_MAX_SOCKETS; i++) {
|
||||||
{
|
|
||||||
net_sock_t *sk = net_get_sock(i);
|
net_sock_t *sk = net_get_sock(i);
|
||||||
if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED)
|
if (sk && sk->in_use && sk->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||||
{
|
|
||||||
NET_FD_SET(i, &readfds);
|
NET_FD_SET(i, &readfds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -648,13 +629,11 @@ void ch395f_phase7_tests(void)
|
|||||||
int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv);
|
int n = net_select(NET_MAX_SOCKETS, &readfds, NULL, NULL, &tv);
|
||||||
if (n <= 0) return;
|
if (n <= 0) return;
|
||||||
|
|
||||||
for (int i = 0; i < NET_MAX_SOCKETS; i++)
|
for (int i = 0; i < NET_MAX_SOCKETS; i++) {
|
||||||
{
|
|
||||||
if (!NET_FD_ISSET(i, &readfds)) continue;
|
if (!NET_FD_ISSET(i, &readfds)) continue;
|
||||||
|
|
||||||
int len = net_recv(i, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT);
|
int len = net_recv(i, s_phase7_buf, sizeof(s_phase7_buf), NET_MSG_DONTWAIT);
|
||||||
if (len > 0)
|
if (len > 0) {
|
||||||
{
|
|
||||||
net_send(i, s_phase7_buf, len, 0);
|
net_send(i, s_phase7_buf, len, 0);
|
||||||
s_phase7_count++;
|
s_phase7_count++;
|
||||||
TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len);
|
TEST_CHECK(1, "Phase7: select echo #%lu (sock=%d, %d bytes)", s_phase7_count, i, len);
|
||||||
@@ -662,3 +641,4 @@ void ch395f_phase7_tests(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,12 +60,12 @@ extern test_stats_t g_test_stats;
|
|||||||
g_test_stats.failed++; \
|
g_test_stats.failed++; \
|
||||||
DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \
|
DBG_ERROR("[FAIL] " fmt, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define TEST_REPORT(name) do { \
|
#define TEST_REPORT(name) do { \
|
||||||
DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \
|
DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \
|
||||||
name, g_test_stats.passed, g_test_stats.total, g_test_stats.failed); \
|
name, g_test_stats.passed, g_test_stats.total, g_test_stats.failed); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phase 1: 底层寄存器测试
|
* Phase 1: 底层寄存器测试
|
||||||
|
|||||||
@@ -3,34 +3,31 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 模å<C2A1>—å<E28094><C3A5>称:FAL é…<C3A9>ç½®
|
* 模å<C2A1>—å<E28094><C3A5>称:FAL é…<C3A9>ç½®
|
||||||
* 模块功能:定义 FAL Flash 设备表和分区表
|
* 模å<EFBFBD>—功能:定ä¹?FAL Flash 设备表和分区è¡? * 适用平å<C2B3>°ï¼šSTM32F407ZGT6
|
||||||
* 适用平台:STM32F407ZGT6
|
* 作者:王建� * 创建日期�026-07-16
|
||||||
* 作者:王建锋
|
* 修改记录ï¼? * 2026-07-16 王建é”? 创建åˆ<C3A5>始版本
|
||||||
* 创建日期:2026-07-16
|
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-16 王建锋 创建初始版本
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* FAL 调试开关:0-关闭,1-开启 */
|
/* FAL 调试开关:0-å…³é—ï¼?-å¼€å<E282AC>?*/
|
||||||
#define FAL_DEBUG 0
|
#define FAL_DEBUG 0
|
||||||
|
|
||||||
/* 启用分区表配置 */
|
/* å<EFBFBD>¯ç”¨åˆ†åŒºè¡¨é…<EFBFBD>ç½?*/
|
||||||
#define FAL_PART_HAS_TABLE_CFG
|
#define FAL_PART_HAS_TABLE_CFG
|
||||||
|
|
||||||
/* ======================== Flash 设备表 ======================== */
|
/* ======================== Flash 设备�======================== */
|
||||||
|
|
||||||
extern const struct fal_flash_dev gd5f2gq5ue_flash;
|
extern const struct fal_flash_dev g_gd5f2gq5ue_flash;
|
||||||
|
|
||||||
#define FAL_FLASH_DEV_TABLE \
|
#define FAL_FLASH_DEV_TABLE \
|
||||||
{ \
|
{ \
|
||||||
&gd5f2gq5ue_flash, \
|
&g_gd5f2gq5ue_flash, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================== 分区表 ======================== */
|
/* ======================== 分区�======================== */
|
||||||
/*
|
/*
|
||||||
* 分区å<C2BA><C3A5>ç§° 设备å<E280A1><C3A5>ç§° å<><C3A5>ç§» 大å°<C3A5>
|
* 分区å<C2BA><C3A5>ç§° 设备å<E280A1><C3A5>ç§° å<><C3A5>ç§» 大å°<C3A5>
|
||||||
* KVDB: 64MB @ 0
|
* KVDB: 64MB @ 0
|
||||||
@@ -49,3 +46,4 @@ extern const struct fal_flash_dev gd5f2gq5ue_flash;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __FAL_CFG_H */
|
#endif /* __FAL_CFG_H */
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* 讓。蝮怜錐遘ー<E98198>哥AL Flash 隶セ螟<EFBDBE>る<C280>
|
* 讓。蝮怜錐遘ー<E98198>哥AL Flash 隶セ螟<EFBDBE>る<C280>
|
||||||
* 模块功能:将 GD5F2GQ5UE 驱动接口适配到 FAL 框架
|
* 讓。蝮怜粥閭ス<EFBFBD>壼ー<EFBFBD> GD5F2GQ5UE 鬩ア蜉ィ謗・蜿」騾る<EFBFBD><EFBFBD>?FAL 譯<EFBFBD>楔
|
||||||
* 騾ら畑蟷ウ蜿ー<E89CBF>售TM32F407ZGT6
|
* 騾ら畑蟷ウ蜿ー<E89CBF>售TM32F407ZGT6
|
||||||
* 作者:王建锋
|
* 菴懆<EFBFBD>シ夂視蟒コ<EFBFBD>? * 蛻帛サコ譌・譛滂ソ?026-07-16
|
||||||
* 创建日期:2026-07-16
|
* 菫ョ謾ケ隶ー蠖包ソ? * 2026-07-16 邇句サコ<EFBDBB>? 蛻帛サコ蛻晏ァ狗沿譛ャ
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-16 王建锋 创建初始版本
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 螟エ譁<EFBDB4>サカ蛹<EFBDB6>性蛹コ */
|
/* 螟エ譁<EFBDB4>サカ蛹<EFBDB6>性蛹コ */
|
||||||
@@ -17,60 +15,45 @@
|
|||||||
/*
|
/*
|
||||||
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 隶セ螟<EFBDBE><E89E9F>蟋句喧騾る<E9A8BE>
|
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 隶セ螟<EFBDBE><E89E9F>蟋句喧騾る<E9A8BE>
|
||||||
* 蜈・蜿」蜿よ焚<E38288>壽裏
|
* 蜈・蜿」蜿よ焚<E38288>壽裏
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 霑泌屓蛟シ<EFBFBD><EFBFBD>0 - 謌仙粥<E4BB99>悟<EFBFBD><E6829F>?- 髞呵ッッ<EFBDAF>? * 髯仙ョ壽擅莉カ<E88E89>售PI <20>?GPIO 蟾イ逕ア CubeMX 蛻晏ァ句喧螳鯉ソ? * 蜃ス謨ー隸エ譏趣シ夊ー<E5A48A>畑蠎募アるゥア蜉ィ逧<EFBDA8><E980A7>蟋句喧蜃ス<E89C83>? */
|
||||||
* 限定条件:SPI 和 GPIO 已由 CubeMX 初始化完成
|
static int gd5f_fal_init(void) {
|
||||||
* 函数说明:调用底层驱动的初始化函数
|
|
||||||
*/
|
|
||||||
static int gd5f_fal_init(void)
|
|
||||||
{
|
|
||||||
return gd5f2gq5ue_init();
|
return gd5f2gq5ue_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 隸サ蜿夜る<C280>
|
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 隸サ蜿夜る<C280>
|
||||||
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
||||||
* p_buf - 数据缓冲区 uint8_t*
|
* p_buf - 謨ー謐ョ郛灘<EFBFBD><EFBFBD>? uint8_t*
|
||||||
* size - 读取字节数 size_t
|
* size - 隸サ蜿門ュ苓鰍<EFBFBD>? size_t
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 霑泌屓蛟シ<EFBFBD><EFBFBD>0 - 謌仙粥<E4BB99>悟<EFBFBD><E6829F>?- 髞呵ッッ<EFBDAF>? * 髯仙ョ壽擅莉カ<E88E89>喩d5f_fal_init() 蟾イ謌仙粥隹<E7B2A5>ソ? * 蜃ス謨ー隸エ譏趣シ夂峩謗・霓ャ蜿大芦蠎募アるゥア蜉ィ逧<EFBDA8>ッサ蜿門<E89CBF><E99680>? */
|
||||||
* 限定条件:gd5f_fal_init() 已成功调用
|
static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size) {
|
||||||
* 函数说明:直接转发到底层驱动的读取函数
|
|
||||||
*/
|
|
||||||
static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size)
|
|
||||||
{
|
|
||||||
return gd5f2gq5ue_read(offset, p_buf, size);
|
return gd5f2gq5ue_read(offset, p_buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 蜀吝<E89C80>騾る<E9A8BE>
|
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 蜀吝<E89C80>騾る<E9A8BE>
|
||||||
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
||||||
* p_buf - 数据缓冲区 const uint8_t*
|
* p_buf - 謨ー謐ョ郛灘<EFBFBD><EFBFBD>? const uint8_t*
|
||||||
* size - 写入字节数 size_t
|
* size - 蜀吝<EFBFBD>蟄苓鰍<EFBFBD>? size_t
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 霑泌屓蛟シ<EFBFBD><EFBFBD>0 - 謌仙粥<E4BB99>悟<EFBFBD><E6829F>?- 髞呵ッッ<EFBDAF>? * 髯仙ョ壽擅莉カ<E88E89>夂岼譬<E5B2BC>玄蝓溷キイ謫ヲ髯、
|
||||||
* 限定条件:目标区域已擦除
|
* 蜃ス謨ー隸エ譏趣シ夂峩謗・霓ャ蜿大芦蠎募アるゥア蜉ィ逧<EFBFBD><EFBFBD>蜈・蜃ス<EFBFBD>? */
|
||||||
* 函数说明:直接转发到底层驱动的写入函数
|
static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size) {
|
||||||
*/
|
|
||||||
static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size)
|
|
||||||
{
|
|
||||||
return gd5f2gq5ue_write(offset, p_buf, size);
|
return gd5f2gq5ue_write(offset, p_buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 謫ヲ髯、騾る<E9A8BE>
|
* 蜃ス謨ー蜉溯<E89C89><E6BAAF>哥lash 謫ヲ髯、騾る<E9A8BE>
|
||||||
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
* 蜈・蜿」蜿よ焚<E38288>嗤ffset - 襍キ蟋句ュ苓鰍蛛冗ァサ long
|
||||||
* size - 擦除字节数 size_t
|
* size - 謫ヲ髯、蟄苓鰍<EFBFBD>? size_t
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 霑泌屓蛟シ<EFBFBD><EFBFBD>0 - 謌仙粥<E4BB99>悟<EFBFBD><E6829F>?- 髞呵ッッ<EFBDAF>? * 髯仙ョ壽擅莉カ<E88E89>喩d5f_fal_init() 蟾イ謌仙粥隹<E7B2A5>ソ? * 蜃ス謨ー隸エ譏趣シ夂峩謗・霓ャ蜿大芦蠎募アるゥア蜉ィ逧<EFBDA8>逃髯、蜃ス<E89C83>? */
|
||||||
* 限定条件:gd5f_fal_init() 已成功调用
|
static int gd5f_fal_erase(long offset, size_t size) {
|
||||||
* 函数说明:直接转发到底层驱动的擦除函数
|
|
||||||
*/
|
|
||||||
static int gd5f_fal_erase(long offset, size_t size)
|
|
||||||
{
|
|
||||||
return gd5f2gq5ue_erase(offset, size);
|
return gd5f2gq5ue_erase(offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================== FAL Flash 隶セ螟<EFBDBE>ョ壻ケ<E5A3BB> ======================== */
|
/* ======================== FAL Flash 隶セ螟<EFBDBE>ョ壻ケ<E5A3BB> ======================== */
|
||||||
|
|
||||||
/* GD5F2GQ5UE FAL 设备实例,总容量256MB,块大小128KB */
|
/* GD5F2GQ5UE FAL 隶セ螟<EFBFBD>ョ樔セ具シ梧サ螳ケ<EFBFBD>?56MB<4D>悟摎螟ァ蟆<EFBDA7>128KB */
|
||||||
const struct fal_flash_dev gd5f2gq5ue_flash = {
|
const struct fal_flash_dev g_gd5f2gq5ue_flash = {
|
||||||
.name = "gd5f2gq5ue",
|
.name = "gd5f2gq5ue",
|
||||||
.addr = 0,
|
.addr = 0,
|
||||||
.len = GD5F_TOTAL_SIZE,
|
.len = GD5F_TOTAL_SIZE,
|
||||||
@@ -83,3 +66,4 @@ const struct fal_flash_dev gd5f2gq5ue_flash = {
|
|||||||
},
|
},
|
||||||
.write_gran = 8,
|
.write_gran = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* 妯″潡鍚嶇О锛欸D5F2GQ5UE SPI NAND Flash 椹卞姩
|
* 妯″潡鍚嶇О锛欸D5F2GQ5UE SPI NAND Flash 椹卞姩
|
||||||
* 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口
|
* 妯″潡鍔熻兘锛氭彁锟?GD5F2GQ5UE SPI NAND Flash 鐨勫垵濮嬪寲銆佽<EFBFBD>銆佸啓銆佹摝闄ゆ帴锟? * 閫傜敤骞冲彴锛歋TM32F407ZGT6 + SPI1 纭<>欢 SPI
|
||||||
* 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI
|
* 浣滆€咃細鐜嬪缓锟? * 鍒涘缓鏃ユ湡锟?026-07-16
|
||||||
* 作者:王建锋
|
* 淇<EFBFBD>敼璁板綍锟? * 2026-07-16 鐜嬪缓锟? 鍒涘缓鍒濆<E98D92>鐗堟湰
|
||||||
* 创建日期:2026-07-16
|
* 2026-07-17 鐜嬪缓锟? 鍒囨崲纭<E5B4B2>欢 SPI锛屼慨姝f摝闄ゅ湴鍧€锛屽弬锟?NuttX 椹卞姩
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-16 王建锋 创建初始版本
|
|
||||||
* 2026-07-17 王建锋 切换硬件 SPI,修正擦除地址,参考 NuttX 驱动
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 澶存枃浠跺寘鍚<E5AF98>尯 */
|
/* 澶存枃浠跺寘鍚<E5AF98>尯 */
|
||||||
#include "gd5f2gq5ue.h"
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "gd5f2gq5ue.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 璋冭瘯杈撳嚭閰嶇疆
|
* 璋冭瘯杈撳嚭閰嶇疆
|
||||||
@@ -43,12 +40,11 @@ static int gd5f_block_erase(uint32_t block_addr);
|
|||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氱瓑寰呰姱鐗囨搷浣滃畬鎴愶紙杞<E7B499><E69D9E> OIP 浣嶏級
|
* 鍑芥暟鍔熻兘锛氱瓑寰呰姱鐗囨搷浣滃畬鎴愶紙杞<E7B499><E69D9E> OIP 浣嶏級
|
||||||
* 鍏ュ彛鍙傛暟锛歵imeout_ms - 瓒呮椂鏃堕棿 uint32_t > 0
|
* 鍏ュ彛鍙傛暟锛歵imeout_ms - 瓒呮椂鏃堕棿 uint32_t > 0
|
||||||
* 返回值:0 - 操作完成,-2 - 超时
|
* 杩斿洖鍊硷細0 - 鎿嶄綔瀹屾垚锟?2 - 瓒呮椂
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 鍑芥暟璇存槑锛氬惊鐜<E6838A><E9909C>鍙栫姸鎬佸瘎瀛樺櫒鐩村埌 OIP 浣嶆竻闆舵垨瓒呮椂
|
* 鍑芥暟璇存槑锛氬惊鐜<E6838A><E9909C>鍙栫姸鎬佸瘎瀛樺櫒鐩村埌 OIP 浣嶆竻闆舵垨瓒呮椂
|
||||||
*/
|
*/
|
||||||
static int gd5f_wait_busy(uint32_t timeout_ms)
|
static int gd5f_wait_busy(uint32_t timeout_ms) {
|
||||||
{
|
|
||||||
uint8_t cmd = GD5F_CMD_GET_FEATURE;
|
uint8_t cmd = GD5F_CMD_GET_FEATURE;
|
||||||
uint8_t addr = GD5F_REG_STATUS;
|
uint8_t addr = GD5F_REG_STATUS;
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
@@ -75,10 +71,8 @@ static int gd5f_wait_busy(uint32_t timeout_ms)
|
|||||||
* 鍏ュ彛鍙傛暟锛氭棤
|
* 鍏ュ彛鍙傛暟锛氭棤
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 函数说明:CS# 拉低后发送 06h 命令再拉高
|
* 鍑芥暟璇存槑锛欳S# 鎷変綆鍚庡彂锟?06h 鍛戒护鍐嶆媺锟? */
|
||||||
*/
|
static int gd5f_write_enable(void) {
|
||||||
static int gd5f_write_enable(void)
|
|
||||||
{
|
|
||||||
uint8_t cmd = GD5F_CMD_WRITE_ENABLE;
|
uint8_t cmd = GD5F_CMD_WRITE_ENABLE;
|
||||||
|
|
||||||
GD5F_CS_LOW();
|
GD5F_CS_LOW();
|
||||||
@@ -90,13 +84,11 @@ static int gd5f_write_enable(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氳<E9949B>鍙栫姸鎬佸瘎瀛樺櫒
|
* 鍑芥暟鍔熻兘锛氳<E9949B>鍙栫姸鎬佸瘎瀛樺櫒
|
||||||
* 入口参数:p_status - 状态值输出指针 uint8_t* 不为 NULL
|
* 鍏ュ彛鍙傛暟锛歱_status - 鐘舵€佸€艰緭鍑烘寚锟? uint8_t* 涓嶄负 NULL
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 函数说明:发送 0Fh + C0h 地址后读取1字节状态值
|
* 鍑芥暟璇存槑锛氬彂锟?0Fh + C0h 鍦板潃鍚庤<E98D9A>锟?瀛楄妭鐘舵€侊拷? */
|
||||||
*/
|
static int gd5f_read_status(uint8_t *p_status) {
|
||||||
static int gd5f_read_status(uint8_t *p_status)
|
|
||||||
{
|
|
||||||
uint8_t cmd = GD5F_CMD_GET_FEATURE;
|
uint8_t cmd = GD5F_CMD_GET_FEATURE;
|
||||||
uint8_t addr = GD5F_REG_STATUS;
|
uint8_t addr = GD5F_REG_STATUS;
|
||||||
|
|
||||||
@@ -110,15 +102,12 @@ static int gd5f_read_status(uint8_t *p_status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:页读取(将数据从存储阵列加载到内部缓存)
|
* 鍑芥暟鍔熻兘锛氶〉璇诲彇锛堝皢鏁版嵁浠庡瓨鍌ㄩ樀鍒楀姞杞藉埌鍐呴儴缂撳瓨锟? * 鍏ュ彛鍙傛暟锛歱age_addr - 椤靛湴鍧€ uint32_t
|
||||||
* 入口参数:page_addr - 页地址 uint32_t
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 鍑芥暟璇存槑锛氬彂锟?13h + 3瀛楄妭琛屽湴鍧€锛岀瓑锟?OIP 娓呴浂
|
||||||
* 限定条件:SPI 已初始化
|
|
||||||
* 函数说明:发送 13h + 3字节行地址,等待 OIP 清零
|
|
||||||
*/
|
*/
|
||||||
static int gd5f_page_read(uint32_t page_addr)
|
static int gd5f_page_read(uint32_t page_addr) {
|
||||||
{
|
uint8_t cmd[4] = {0};
|
||||||
uint8_t cmd[4];
|
|
||||||
|
|
||||||
cmd[0] = GD5F_CMD_PAGE_READ;
|
cmd[0] = GD5F_CMD_PAGE_READ;
|
||||||
cmd[1] = (page_addr >> 16) & 0xFF;
|
cmd[1] = (page_addr >> 16) & 0xFF;
|
||||||
@@ -135,16 +124,14 @@ static int gd5f_page_read(uint32_t page_addr)
|
|||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氫粠鍐呴儴缂撳瓨璇诲彇鏁版嵁
|
* 鍑芥暟鍔熻兘锛氫粠鍐呴儴缂撳瓨璇诲彇鏁版嵁
|
||||||
* 鍏ュ彛鍙傛暟锛歝olumn - 鍒楀湴鍧€锛堥〉鍐呭亸绉伙級 uint16_t 0 - 2047
|
* 鍏ュ彛鍙傛暟锛歝olumn - 鍒楀湴鍧€锛堥〉鍐呭亸绉伙級 uint16_t 0 - 2047
|
||||||
* p_buf - 数据输出缓冲区 uint8_t* 不为 NULL
|
* p_buf - 鏁版嵁杈撳嚭缂撳啿锟? uint8_t* 涓嶄负 NULL
|
||||||
* size - 读取字节数 size_t > 0
|
* size - 璇诲彇瀛楄妭锟? size_t > 0
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛氬繀椤诲厛璋冪敤 gd5f_page_read 瀹屾垚鏁版嵁鍔犺浇
|
* 闄愬畾鏉′欢锛氬繀椤诲厛璋冪敤 gd5f_page_read 瀹屾垚鏁版嵁鍔犺浇
|
||||||
* 函数说明:发送 0Bh + 2字节列地址 +1字节 dummy 后读取数据
|
* 鍑芥暟璇存槑锛氬彂锟?0Bh + 2瀛楄妭鍒楀湴鍧€ +1瀛楄妭 dummy 鍚庤<E98D9A>鍙栨暟锟? */
|
||||||
*/
|
|
||||||
static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
|
static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
|
||||||
size_t size)
|
size_t size) {
|
||||||
{
|
uint8_t cmd[4] = {0};
|
||||||
uint8_t cmd[4];
|
|
||||||
|
|
||||||
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
|
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
|
||||||
cmd[1] = (column >> 8) & 0xFF;
|
cmd[1] = (column >> 8) & 0xFF;
|
||||||
@@ -163,16 +150,13 @@ static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
|
|||||||
* 鍑芥暟鍔熻兘锛氶〉缂栫▼锛堝皢鏁版嵁鍐欏叆鎸囧畾椤碉級
|
* 鍑芥暟鍔熻兘锛氶〉缂栫▼锛堝皢鏁版嵁鍐欏叆鎸囧畾椤碉級
|
||||||
* 鍏ュ彛鍙傛暟锛歱age_addr - 椤靛湴鍧€ uint32_t
|
* 鍏ュ彛鍙傛暟锛歱age_addr - 椤靛湴鍧€ uint32_t
|
||||||
* column - 鍒楀湴鍧€ uint16_t 0 - 2047
|
* column - 鍒楀湴鍧€ uint16_t 0 - 2047
|
||||||
* p_buf - 数据缓冲区 const uint8_t*
|
* p_buf - 鏁版嵁缂撳啿锟? const uint8_t*
|
||||||
* size - 写入字节数 size_t > 0
|
* size - 鍐欏叆瀛楄妭锟? size_t > 0
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛氱洰鏍囧尯鍩熷凡鎿﹂櫎
|
||||||
* 限定条件:目标区域已擦除
|
* 鍑芥暟璇存槑锟?. 鍐欎娇锟?- 02h 鍔犺浇鏁版嵁 - 10h 鎵ц<E98EB5>缂栫▼ - 绛夊緟瀹屾垚
|
||||||
* 函数说明:1. 写使能 - 02h 加载数据 - 10h 执行编程 - 等待完成
|
* 2. 缂栫▼瀹屾垚鍚庢<E98D9A>锟?P_FAIL 锟? */
|
||||||
* 2. 编程完成后检查 P_FAIL 位
|
|
||||||
*/
|
|
||||||
static int gd5f_page_program(uint32_t page_addr, uint16_t column,
|
static int gd5f_page_program(uint32_t page_addr, uint16_t column,
|
||||||
const uint8_t *p_buf, size_t size)
|
const uint8_t *p_buf, size_t size) {
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
uint8_t cmd[4];
|
uint8_t cmd[4];
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
@@ -212,15 +196,12 @@ static int gd5f_page_program(uint32_t page_addr, uint16_t column,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置 Feature 寄存器
|
* 鍑芥暟鍔熻兘锛氳<EFBFBD>锟?Feature 瀵勫瓨锟? * 鍏ュ彛鍙傛暟锛歛ddr - 瀵勫瓨鍣ㄥ湴鍧€ uint8_t
|
||||||
* 入口参数:addr - 寄存器地址 uint8_t
|
|
||||||
* data - 鍐欏叆鏁版嵁 uint8_t
|
* data - 鍐欏叆鏁版嵁 uint8_t
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 函数说明:先写使能,发送 1Fh + 地址 + 数据,等待操作完成
|
* 鍑芥暟璇存槑锛氬厛鍐欎娇鑳斤紝鍙戯拷?1Fh + 鍦板潃 + 鏁版嵁锛岀瓑寰呮搷浣滃畬锟? */
|
||||||
*/
|
static int gd5f_set_feature(uint8_t addr, uint8_t data) {
|
||||||
static int gd5f_set_feature(uint8_t addr, uint8_t data)
|
|
||||||
{
|
|
||||||
uint8_t cmd[3];
|
uint8_t cmd[3];
|
||||||
|
|
||||||
gd5f_write_enable();
|
gd5f_write_enable();
|
||||||
@@ -239,15 +220,11 @@ static int gd5f_set_feature(uint8_t addr, uint8_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:块擦除(擦除128KB块)
|
* 鍑芥暟鍔熻兘锛氬潡鎿﹂櫎锛堟摝锟?28KB鍧楋級
|
||||||
* 入口参数:block_addr - 块编号 uint32_t 0 - 2047
|
* 鍏ュ彛鍙傛暟锛歜lock_addr - 鍧楃紪锟? uint32_t 0 - 2047
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歡d5f2gq5ue_init() 宸茶皟锟? * 鍑芥暟璇存槑锟?. 鍐欎娇锟?- D8h + 3瀛楄妭瀛楄妭鍦板潃 - 绛夊緟瀹屾垚
|
||||||
* 限定条件:gd5f2gq5ue_init() 已调用
|
* 2. 鎿﹂櫎瀹屾垚鍚庢<E98D9A>锟?E_FAIL 锟? */
|
||||||
* 函数说明:1. 写使能 - D8h + 3字节字节地址 - 等待完成
|
static int gd5f_block_erase(uint32_t block_addr) {
|
||||||
* 2. 擦除完成后检查 E_FAIL 位
|
|
||||||
*/
|
|
||||||
static int gd5f_block_erase(uint32_t block_addr)
|
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
uint8_t cmd[4];
|
uint8_t cmd[4];
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
@@ -282,15 +259,11 @@ static int gd5f_block_erase(uint32_t block_addr)
|
|||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氬垵濮嬪寲 GD5F2GQ5UE
|
* 鍑芥暟鍔熻兘锛氬垵濮嬪寲 GD5F2GQ5UE
|
||||||
* 鍏ュ彛鍙傛暟锛氭棤
|
* 鍏ュ彛鍙傛暟锛氭棤
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歋PI1 鍜岀浉锟?GPIO 宸茬敱 CubeMX 鍒濆<E98D92>鍖栧畬锟? * 鍑芥暟璇存槑锟?. 鍙戦€佸<E282AC>浣嶅懡浠ゅ苟绛夊緟瀹屾垚
|
||||||
* 限定条件:SPI1 和相关 GPIO 已由 CubeMX 初始化完成
|
* 2. 璇诲彇鑺<E5BD87>墖 ID 骞舵牎锟? * 3. 浣胯兘鍐呴儴 ECC (B0h bit4)
|
||||||
* 函数说明:1. 发送复位命令并等待完成
|
|
||||||
* 2. 读取芯片 ID 并校验
|
|
||||||
* 3. 使能内部 ECC (B0h bit4)
|
|
||||||
* 4. 瑙i櫎鎵€鏈夊潡淇濇姢 (A0h = 0x00)
|
* 4. 瑙i櫎鎵€鏈夊潡淇濇姢 (A0h = 0x00)
|
||||||
*/
|
*/
|
||||||
int gd5f2gq5ue_init(void)
|
int gd5f2gq5ue_init(void) {
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
uint8_t mid = 0;
|
uint8_t mid = 0;
|
||||||
uint8_t did = 0;
|
uint8_t did = 0;
|
||||||
@@ -338,15 +311,13 @@ int gd5f2gq5ue_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取芯片 ID(MID + DID)
|
* 鍑芥暟鍔熻兘锛氳<EFBFBD>鍙栬姱锟?ID锛圡ID + DID锟? * 鍏ュ彛鍙傛暟锛歮id - 鍒堕€犲晢 ID 杈撳嚭鎸囬拡 uint8_t* 涓嶄负 NULL
|
||||||
* 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL
|
|
||||||
* did - 璁惧<E79281> ID 杈撳嚭鎸囬拡 uint8_t* 涓嶄负 NULL
|
* did - 璁惧<E79281> ID 杈撳嚭鎸囬拡 uint8_t* 涓嶄负 NULL
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID
|
* 鍑芥暟璇存槑锛氬彂锟?9Fh 鍛戒护鍚庢帴锟?锟?dummy + MID + DID
|
||||||
*/
|
*/
|
||||||
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did)
|
int gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did) {
|
||||||
{
|
|
||||||
uint8_t cmd = GD5F_CMD_READ_ID;
|
uint8_t cmd = GD5F_CMD_READ_ID;
|
||||||
uint8_t id_buf[3] = {0};
|
uint8_t id_buf[3] = {0};
|
||||||
|
|
||||||
@@ -355,23 +326,19 @@ int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did)
|
|||||||
HAL_SPI_Receive(&hspi1, id_buf, 3, GD5F_SPI_TIMEOUT);
|
HAL_SPI_Receive(&hspi1, id_buf, 3, GD5F_SPI_TIMEOUT);
|
||||||
GD5F_CS_HIGH();
|
GD5F_CS_HIGH();
|
||||||
|
|
||||||
*mid = id_buf[1];
|
*p_mid = id_buf[1];
|
||||||
*did = id_buf[2];
|
*p_did = id_buf[2];
|
||||||
|
|
||||||
return GD5F_OK;
|
return GD5F_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氫粠 NAND 璇诲彇鏁版嵁锛堟敮鎸佽法椤碉級
|
* 鍑芥暟鍔熻兘锛氫粠 NAND 璇诲彇鏁版嵁锛堟敮鎸佽法椤碉級
|
||||||
* 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1
|
* 鍏ュ彛鍙傛暟锛歰ffset - 璧峰<E792A7>瀛楄妭鍋忕Щ long 0 ~ 鎬诲<EFBFBD>锟?1
|
||||||
* p_buf - 数据缓冲区 uint8_t* 不为 NULL
|
* p_buf - 鏁版嵁缂撳啿锟? uint8_t* 涓嶄负 NULL
|
||||||
* size - 读取字节数 size_t > 0
|
* size - 璇诲彇瀛楄妭锟? size_t > 0
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歡d5f2gq5ue_init() 宸叉垚鍔熻皟锟? * 鍑芥暟璇存槑锛氳嚜鍔ㄥ<E98D94>鐞嗚法椤佃<E6A4A4>锟? */
|
||||||
* 限定条件:gd5f2gq5ue_init() 已成功调用
|
int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size) {
|
||||||
* 函数说明:自动处理跨页读取
|
|
||||||
*/
|
|
||||||
int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size)
|
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
@@ -403,15 +370,11 @@ int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 鍑芥暟鍔熻兘锛氬悜 NAND 鍐欏叆鏁版嵁锛堟敮鎸佽法椤碉級
|
* 鍑芥暟鍔熻兘锛氬悜 NAND 鍐欏叆鏁版嵁锛堟敮鎸佽法椤碉級
|
||||||
* 入口参数:offset - 起始字节偏移 long 0 ~ 总容量-1
|
* 鍏ュ彛鍙傛暟锛歰ffset - 璧峰<E792A7>瀛楄妭鍋忕Щ long 0 ~ 鎬诲<EFBFBD>锟?1
|
||||||
* p_buf - 数据缓冲区 const uint8_t* 不为 NULL
|
* p_buf - 鏁版嵁缂撳啿锟? const uint8_t* 涓嶄负 NULL
|
||||||
* size - 写入字节数 size_t > 0
|
* size - 鍐欏叆瀛楄妭锟? size_t > 0
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
* 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歡d5f2gq5ue_init() 宸叉垚鍔熻皟鐢<E79A9F>紝鐩<E7B49D>爣鍖哄煙宸叉摝锟? * 鍑芥暟璇存槑锛氳嚜鍔ㄥ<E98D94>鐞嗚法椤靛啓锟? */
|
||||||
* 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦除
|
int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size) {
|
||||||
* 函数说明:自动处理跨页写入
|
|
||||||
*/
|
|
||||||
int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size)
|
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
@@ -437,15 +400,9 @@ int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:擦除块(按块擦除,最小单位 128KB)
|
* 鍑芥暟鍔熻兘锛氭摝闄ゅ潡锛堟寜鍧楁摝闄わ紝鏈€灏忓崟锟?128KB锟? * 鍏ュ彛鍙傛暟锛歰ffset - 璧峰<E792A7>瀛楄妭鍋忕Щ long 蹇呴』鍧楀<E98DA7>锟? * size - 鎿﹂櫎瀛楄妭锟? size_t 蹇呴』鍧楀ぇ灏忔暣鏁帮拷? * 杩斿洖鍊硷細0 - 鎴愬姛锛屽叾锟?- 閿欒<E996BF>锟? * 闄愬畾鏉′欢锛歡d5f2gq5ue_init() 宸叉垚鍔熻皟锟? * 鍑芥暟璇存槑锛氭摝闄ゆ搷浣滀互鍧椾负鍗曚綅
|
||||||
* 入口参数:offset - 起始字节偏移 long 必须块对齐
|
|
||||||
* size - 擦除字节数 size_t 必须块大小整数倍
|
|
||||||
* 返回值:0 - 成功,其他 - 错误码
|
|
||||||
* 限定条件:gd5f2gq5ue_init() 已成功调用
|
|
||||||
* 函数说明:擦除操作以块为单位
|
|
||||||
*/
|
*/
|
||||||
int gd5f2gq5ue_erase(long offset, size_t size)
|
int gd5f2gq5ue_erase(long offset, size_t size) {
|
||||||
{
|
|
||||||
int ret = GD5F_OK;
|
int ret = GD5F_OK;
|
||||||
|
|
||||||
if (offset % GD5F_BLOCK_SIZE != 0) {
|
if (offset % GD5F_BLOCK_SIZE != 0) {
|
||||||
@@ -471,14 +428,12 @@ int gd5f2gq5ue_erase(long offset, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:复位芯片
|
* 鍑芥暟鍔熻兘锛氬<EFBFBD>浣嶈姱锟? * 鍏ュ彛鍙傛暟锛氭棤
|
||||||
* 入口参数:无
|
|
||||||
* 杩斿洖鍊硷細0 - 鎴愬姛
|
* 杩斿洖鍊硷細0 - 鎴愬姛
|
||||||
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
* 闄愬畾鏉′欢锛歋PI 宸插垵濮嬪寲
|
||||||
* 函数说明:发送 FFh 复位命令后等待 5ms
|
* 鍑芥暟璇存槑锛氬彂锟?FFh 澶嶄綅鍛戒护鍚庣瓑锟?5ms
|
||||||
*/
|
*/
|
||||||
int gd5f2gq5ue_reset(void)
|
int gd5f2gq5ue_reset(void) {
|
||||||
{
|
|
||||||
uint8_t cmd = GD5F_CMD_RESET;
|
uint8_t cmd = GD5F_CMD_RESET;
|
||||||
|
|
||||||
GD5F_CS_LOW();
|
GD5F_CS_LOW();
|
||||||
@@ -489,3 +444,4 @@ int gd5f2gq5ue_reset(void)
|
|||||||
|
|
||||||
return GD5F_OK;
|
return GD5F_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ int gd5f2gq5ue_init(void);
|
|||||||
* 限定条件:SPI 已初始化
|
* 限定条件:SPI 已初始化
|
||||||
* 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID
|
* 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID
|
||||||
*/
|
*/
|
||||||
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did);
|
int gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:从 NAND 读取数据(支持跨页)
|
* 函数功能:从 NAND 读取数据(支持跨页)
|
||||||
|
|||||||
@@ -1,34 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* 模块名称:Network Select Implementation
|
* 模块名称:Network Select Implementation
|
||||||
* 模块功能:I/O 多路复用实现,包括 select 和 poll 模式,
|
* 模块功能:I/O 多路复用实现,包<EFBFBD>?select <EFBFBD>?poll 模式<EFBFBD>? * 用于同时监控多个 Socket 的读写事<E58699>? * 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||||||
* 用于同时监控多个 Socket 的读写事件
|
* 作者:王建<EFBFBD>? * 创建日期<E697A5>?026-07-18
|
||||||
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
* 修改记录<EFBFBD>? */
|
||||||
* 作者:王建锋
|
|
||||||
* 创建日期:2026-07-18
|
|
||||||
* 修改记录:
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "net_select.h"
|
#include "net_select.h"
|
||||||
#include "net_socket.h"
|
#include "net_socket.h"
|
||||||
#include "ch395f.h"
|
#include "ch395f.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有函数声明区
|
* 私有函数声明<EFBFBD>? */
|
||||||
*/
|
|
||||||
static int check_socket_readable(int sockfd);
|
static int check_socket_readable(int sockfd);
|
||||||
static int check_socket_writable(int sockfd);
|
static int check_socket_writable(int sockfd);
|
||||||
static int check_socket_error(int sockfd);
|
static int check_socket_error(int sockfd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 公共函数实现区
|
* 公共函数实现<EFBFBD>? */
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:I/O 多路复用(select 模式)
|
* 函数功能:I/O 多路复用(select 模式<EFBFBD>? */
|
||||||
*/
|
|
||||||
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||||||
net_fd_set *exceptfds, net_timeval *timeout)
|
net_fd_set *exceptfds, net_timeval *timeout) {
|
||||||
{
|
|
||||||
uint32_t start_tick;
|
uint32_t start_tick;
|
||||||
uint32_t timeout_ms = 0;
|
uint32_t timeout_ms = 0;
|
||||||
net_fd_set result_read = {0};
|
net_fd_set result_read = {0};
|
||||||
@@ -38,56 +30,46 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* 计算超时时间 */
|
/* 计算超时时间 */
|
||||||
if (timeout != NULL)
|
if (timeout != NULL) {
|
||||||
{
|
|
||||||
timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
|
timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
|
||||||
(uint32_t)(timeout->tv_usec / 1000);
|
(uint32_t)(timeout->tv_usec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
start_tick = HAL_GetTick();
|
start_tick = HAL_GetTick();
|
||||||
|
|
||||||
while (1)
|
while (1) {
|
||||||
{
|
/* 轮询所<E8AFA2>?Socket */
|
||||||
/* 轮询所有 Socket */
|
|
||||||
net_poll();
|
net_poll();
|
||||||
|
|
||||||
ready_count = 0;
|
ready_count = 0;
|
||||||
|
|
||||||
/* 检查哪些 Socket 有事件 */
|
/* 检查哪<EFBFBD>?Socket 有事<EFBFBD>?*/
|
||||||
for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++)
|
for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++) {
|
||||||
{
|
net_sock_t *p_sock = net_get_sock(i);
|
||||||
net_sock_t *sock = net_get_sock(i);
|
|
||||||
|
|
||||||
if (sock == NULL)
|
if (p_sock == NULL) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查可读事件 */
|
/* 检查可读事<EFBFBD>?*/
|
||||||
if (readfds != NULL && NET_FD_ISSET(i, readfds))
|
if (readfds != NULL && NET_FD_ISSET(i, readfds)) {
|
||||||
{
|
if (check_socket_readable(i)) {
|
||||||
if (check_socket_readable(i))
|
|
||||||
{
|
|
||||||
NET_FD_SET(i, &result_read);
|
NET_FD_SET(i, &result_read);
|
||||||
ready_count++;
|
ready_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查可写事件 */
|
/* 检查可写事<EFBFBD>?*/
|
||||||
if (writefds != NULL && NET_FD_ISSET(i, writefds))
|
if (writefds != NULL && NET_FD_ISSET(i, writefds)) {
|
||||||
{
|
if (check_socket_writable(i)) {
|
||||||
if (check_socket_writable(i))
|
|
||||||
{
|
|
||||||
NET_FD_SET(i, &result_write);
|
NET_FD_SET(i, &result_write);
|
||||||
ready_count++;
|
ready_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查异常事件 */
|
/* 检查异常事<EFBFBD>?*/
|
||||||
if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds))
|
if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds)) {
|
||||||
{
|
if (check_socket_error(i)) {
|
||||||
if (check_socket_error(i))
|
|
||||||
{
|
|
||||||
NET_FD_SET(i, &result_except);
|
NET_FD_SET(i, &result_except);
|
||||||
ready_count++;
|
ready_count++;
|
||||||
}
|
}
|
||||||
@@ -95,17 +77,14 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 有事件就绪,返回 */
|
/* 有事件就绪,返回 */
|
||||||
if (ready_count > 0)
|
if (ready_count > 0) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 超时检查 */
|
/* 超时检<EFBFBD>?*/
|
||||||
if (timeout != NULL)
|
if (timeout != NULL) {
|
||||||
{
|
|
||||||
if (timeout_ms > 0 &&
|
if (timeout_ms > 0 &&
|
||||||
(HAL_GetTick() - start_tick) >= timeout_ms)
|
(HAL_GetTick() - start_tick) >= timeout_ms) {
|
||||||
{
|
|
||||||
break; /* 超时返回 0 */
|
break; /* 超时返回 0 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,16 +94,13 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 复制结果 */
|
/* 复制结果 */
|
||||||
if (readfds != NULL)
|
if (readfds != NULL) {
|
||||||
{
|
|
||||||
readfds->fd_bits = result_read.fd_bits;
|
readfds->fd_bits = result_read.fd_bits;
|
||||||
}
|
}
|
||||||
if (writefds != NULL)
|
if (writefds != NULL) {
|
||||||
{
|
|
||||||
writefds->fd_bits = result_write.fd_bits;
|
writefds->fd_bits = result_write.fd_bits;
|
||||||
}
|
}
|
||||||
if (exceptfds != NULL)
|
if (exceptfds != NULL) {
|
||||||
{
|
|
||||||
exceptfds->fd_bits = result_except.fd_bits;
|
exceptfds->fd_bits = result_except.fd_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,95 +108,79 @@ int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:I/O 多路复用(poll 模式)
|
* 函数功能:I/O 多路复用(poll 模式<EFBFBD>? */
|
||||||
*/
|
int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
|
||||||
int net_poll_events(net_pollfd *fds, int nfds, int timeout)
|
|
||||||
{
|
|
||||||
uint32_t start_tick;
|
uint32_t start_tick;
|
||||||
int ready = 0;
|
int ready = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (fds == NULL || nfds <= 0)
|
if (fds == NULL || nfds <= 0) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_tick = HAL_GetTick();
|
start_tick = HAL_GetTick();
|
||||||
|
|
||||||
while (1)
|
while (1) {
|
||||||
{
|
|
||||||
/* 轮询 */
|
/* 轮询 */
|
||||||
net_poll();
|
net_poll();
|
||||||
|
|
||||||
ready = 0;
|
ready = 0;
|
||||||
|
|
||||||
for (i = 0; i < nfds; i++)
|
for (i = 0; i < nfds; i++) {
|
||||||
{
|
|
||||||
fds[i].revents = 0;
|
fds[i].revents = 0;
|
||||||
|
|
||||||
/* 检查 fd 有效性 */
|
/* 检<EFBFBD>?fd 有效<EFBFBD>?*/
|
||||||
if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS)
|
if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS) {
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLNVAL;
|
fds[i].revents |= NET_POLLNVAL;
|
||||||
ready++;
|
ready++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_sock_t *sock = net_get_sock(fds[i].fd);
|
net_sock_t *p_sock = net_get_sock(fds[i].fd);
|
||||||
|
|
||||||
if (sock == NULL)
|
if (p_sock == NULL) {
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLNVAL;
|
fds[i].revents |= NET_POLLNVAL;
|
||||||
ready++;
|
ready++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查可读 */
|
/* 检查可<EFBFBD>?*/
|
||||||
if (fds[i].events & NET_POLLIN)
|
if (fds[i].events & NET_POLLIN) {
|
||||||
{
|
if (check_socket_readable(fds[i].fd)) {
|
||||||
if (check_socket_readable(fds[i].fd))
|
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLIN;
|
fds[i].revents |= NET_POLLIN;
|
||||||
ready++;
|
ready++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查可写 */
|
/* 检查可<EFBFBD>?*/
|
||||||
if (fds[i].events & NET_POLLOUT)
|
if (fds[i].events & NET_POLLOUT) {
|
||||||
{
|
if (check_socket_writable(fds[i].fd)) {
|
||||||
if (check_socket_writable(fds[i].fd))
|
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLOUT;
|
fds[i].revents |= NET_POLLOUT;
|
||||||
ready++;
|
ready++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查错误 */
|
/* 检查错<EFBFBD>?*/
|
||||||
if (check_socket_error(fds[i].fd))
|
if (check_socket_error(fds[i].fd)) {
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLERR;
|
fds[i].revents |= NET_POLLERR;
|
||||||
ready++;
|
ready++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检查挂起(连接断开) */
|
/* 检查挂起(连接断开<EFBFBD>?*/
|
||||||
if (sock->state == NET_SOCK_STATE_TCP_ACCEPT ||
|
if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT ||
|
||||||
sock->state == NET_SOCK_STATE_CLOSED)
|
p_sock->state == NET_SOCK_STATE_CLOSED) {
|
||||||
{
|
|
||||||
fds[i].revents |= NET_POLLHUP;
|
fds[i].revents |= NET_POLLHUP;
|
||||||
ready++;
|
ready++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ready > 0)
|
if (ready > 0) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 超时检查 */
|
/* 超时检<EFBFBD>?*/
|
||||||
if (timeout >= 0)
|
if (timeout >= 0) {
|
||||||
{
|
if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout) {
|
||||||
if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,36 +192,29 @@ int net_poll_events(net_pollfd *fds, int nfds, int timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 私有函数实现区
|
* 私有函数实现<EFBFBD>? */
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:检查 Socket 是否可读
|
* 函数功能:检<EFBFBD>?Socket 是否可读
|
||||||
* 返回值:1 可读,0 不可读
|
* 返回值:1 可读<EFBFBD>? 不可<EFBFBD>? */
|
||||||
*/
|
static int check_socket_readable(int sockfd) {
|
||||||
static int check_socket_readable(int sockfd)
|
net_sock_t *p_sock;
|
||||||
{
|
|
||||||
net_sock_t *sock;
|
|
||||||
uint16_t recv_len;
|
uint16_t recv_len;
|
||||||
|
|
||||||
sock = net_get_sock(sockfd);
|
p_sock = net_get_sock(sockfd);
|
||||||
if (sock == NULL)
|
if (p_sock == NULL) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 监听 Socket 有新连接时可读 */
|
/* 监听 Socket 有新连接时可<EFBFBD>?*/
|
||||||
if (sock->state == NET_SOCK_STATE_LISTENING)
|
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 已建立连接的 Socket 有数据可读 */
|
/* 已建立连接的 Socket 有数据可<EFBFBD>?*/
|
||||||
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||||
{
|
|
||||||
recv_len = ch395f_get_recv_len(sockfd);
|
recv_len = ch395f_get_recv_len(sockfd);
|
||||||
if (recv_len > 0)
|
if (recv_len > 0) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,24 +223,19 @@ static int check_socket_readable(int sockfd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:检查 Socket 是否可写
|
* 函数功能:检<EFBFBD>?Socket 是否可写
|
||||||
* 返回值:1 可写,0 不可写
|
* 返回值:1 可写<EFBFBD>? 不可<EFBFBD>? */
|
||||||
*/
|
static int check_socket_writable(int sockfd) {
|
||||||
static int check_socket_writable(int sockfd)
|
net_sock_t *p_sock;
|
||||||
{
|
|
||||||
net_sock_t *sock;
|
|
||||||
|
|
||||||
sock = net_get_sock(sockfd);
|
p_sock = net_get_sock(sockfd);
|
||||||
if (sock == NULL)
|
if (p_sock == NULL) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 已建立连接的 Socket 发送缓冲区空闲时可写 */
|
/* 已建立连接的 Socket 发送缓冲区空闲时可<EFBFBD>?*/
|
||||||
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||||
{
|
if (p_sock->send_ready) {
|
||||||
if (sock->send_ready)
|
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,22 +244,17 @@ static int check_socket_writable(int sockfd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:检查 Socket 是否有错误
|
* 函数功能:检<EFBFBD>?Socket 是否有错<EFBFBD>? * 返回值:1 有错误,0 无错<E697A0>? */
|
||||||
* 返回值:1 有错误,0 无错误
|
static int check_socket_error(int sockfd) {
|
||||||
*/
|
net_sock_t *p_sock;
|
||||||
static int check_socket_error(int sockfd)
|
|
||||||
{
|
|
||||||
net_sock_t *sock;
|
|
||||||
|
|
||||||
/* 无效 fd 视为错误 */
|
/* 无效 fd 视为错误 */
|
||||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
|
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock = net_get_sock(sockfd);
|
p_sock = net_get_sock(sockfd);
|
||||||
if (sock == NULL)
|
if (p_sock == NULL) {
|
||||||
{
|
|
||||||
return 1; /* 未使用的 Socket 视为错误 */
|
return 1; /* 未使用的 Socket 视为错误 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@ int net_poll(void);
|
|||||||
* protocol - 通常为 0
|
* protocol - 通常为 0
|
||||||
* 返回值:socket 描述符 (0~7),失败返回 -1
|
* 返回值:socket 描述符 (0~7),失败返回 -1
|
||||||
* 限定条件:net_init() 已调用
|
* 限定条件:net_init() 已调用
|
||||||
|
* 函数说明:自动分配空闲 Socket 控制块
|
||||||
*/
|
*/
|
||||||
int net_socket(int domain, int type, int protocol);
|
int net_socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ int net_socket(int domain, int type, int protocol);
|
|||||||
* addr - 本地地址结构体指针
|
* addr - 本地地址结构体指针
|
||||||
* addrlen - 地址结构体长度
|
* addrlen - 地址结构体长度
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:socket 已创建且未绑定
|
||||||
|
* 函数说明:设置 CH395F 源端口
|
||||||
*/
|
*/
|
||||||
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
||||||
|
|
||||||
@@ -70,6 +73,7 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
|||||||
* backlog - 最大等待连接数(多连接模式下为数据 Socket 数量)
|
* backlog - 最大等待连接数(多连接模式下为数据 Socket 数量)
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
* 限定条件:socket 已绑定
|
* 限定条件:socket 已绑定
|
||||||
|
* 函数说明:内部调用 ch395f_tcp_listen,多连接模式自动配置数据 Socket
|
||||||
*/
|
*/
|
||||||
int net_listen(int sockfd, int backlog);
|
int net_listen(int sockfd, int backlog);
|
||||||
|
|
||||||
@@ -104,7 +108,8 @@ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
|||||||
* len - 数据长度
|
* len - 数据长度
|
||||||
* flags - 通常为 0
|
* flags - 通常为 0
|
||||||
* 返回值:实际发送字节数,失败返回 -1
|
* 返回值:实际发送字节数,失败返回 -1
|
||||||
* 限定条件:TCP 连接已建立
|
* 限定条件:TCP 连接已建立,指针非空
|
||||||
|
* 函数说明:阻塞等待发送缓冲区空闲,拷贝数据后触发发送
|
||||||
*/
|
*/
|
||||||
int net_send(int sockfd, const void *buf, int len, int flags);
|
int net_send(int sockfd, const void *buf, int len, int flags);
|
||||||
|
|
||||||
@@ -131,6 +136,8 @@ int net_recv(int sockfd, void *buf, int len, int flags);
|
|||||||
* dest_addr - 目标地址
|
* dest_addr - 目标地址
|
||||||
* addrlen - 地址长度
|
* addrlen - 地址长度
|
||||||
* 返回值:实际发送字节数,失败返回 -1
|
* 返回值:实际发送字节数,失败返回 -1
|
||||||
|
* 限定条件:socket 已创建,指针非空
|
||||||
|
* 函数说明:设置目标地址后调用 CH395F 发送
|
||||||
*/
|
*/
|
||||||
int net_sendto(int sockfd, const void *buf, int len, int flags,
|
int net_sendto(int sockfd, const void *buf, int len, int flags,
|
||||||
const struct net_sockaddr *dest_addr, int addrlen);
|
const struct net_sockaddr *dest_addr, int addrlen);
|
||||||
@@ -144,6 +151,8 @@ int net_sendto(int sockfd, const void *buf, int len, int flags,
|
|||||||
* src_addr - 输出:发送方地址
|
* src_addr - 输出:发送方地址
|
||||||
* addrlen - 输入输出:地址长度
|
* addrlen - 输入输出:地址长度
|
||||||
* 返回值:实际接收字节数,失败返回 -1
|
* 返回值:实际接收字节数,失败返回 -1
|
||||||
|
* 限定条件:socket 已创建,指针非空
|
||||||
|
* 函数说明:读取 CH395F 接收缓冲区,获取对端地址
|
||||||
*/
|
*/
|
||||||
int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
||||||
struct net_sockaddr *src_addr, int *addrlen);
|
struct net_sockaddr *src_addr, int *addrlen);
|
||||||
@@ -152,6 +161,8 @@ int net_recvfrom(int sockfd, void *buf, int len, int flags,
|
|||||||
* 函数功能:关闭 socket
|
* 函数功能:关闭 socket
|
||||||
* 入口参数:sockfd - socket 描述符
|
* 入口参数:sockfd - socket 描述符
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:socket 已打开
|
||||||
|
* 函数说明:释放 Socket 控制块,TCP 先断开连接
|
||||||
*/
|
*/
|
||||||
int net_close(int sockfd);
|
int net_close(int sockfd);
|
||||||
|
|
||||||
@@ -165,6 +176,8 @@ int net_close(int sockfd);
|
|||||||
* cb - 回调函数
|
* cb - 回调函数
|
||||||
* arg - 用户参数
|
* arg - 用户参数
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
|
* 限定条件:socket 已创建
|
||||||
|
* 函数说明:回调在 net_poll 上下文中触发
|
||||||
*/
|
*/
|
||||||
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
|
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);
|
||||||
|
|
||||||
@@ -181,7 +194,9 @@ int net_get_errno(void);
|
|||||||
/*
|
/*
|
||||||
* 函数功能:将 IP 地址字符串转为网络字节序
|
* 函数功能:将 IP 地址字符串转为网络字节序
|
||||||
* 入口参数:cp - 点分十进制字符串 "192.168.1.100"
|
* 入口参数:cp - 点分十进制字符串 "192.168.1.100"
|
||||||
* 返回值:网络字节序 IP
|
* 返回值:网络字节序 IP,失败返回 0
|
||||||
|
* 限定条件:cp 指针非空
|
||||||
|
* 函数说明:不支持域名解析
|
||||||
*/
|
*/
|
||||||
uint32_t net_inet_addr(const char *cp);
|
uint32_t net_inet_addr(const char *cp);
|
||||||
|
|
||||||
@@ -190,26 +205,43 @@ uint32_t net_inet_addr(const char *cp);
|
|||||||
* 入口参数:addr - 网络字节序 IP
|
* 入口参数:addr - 网络字节序 IP
|
||||||
* buf - 输出缓冲区(至少 16 字节)
|
* buf - 输出缓冲区(至少 16 字节)
|
||||||
* 返回值:buf 指针
|
* 返回值:buf 指针
|
||||||
|
* 限定条件:buf 指针非空
|
||||||
*/
|
*/
|
||||||
char *net_inet_ntoa(uint32_t addr, char *buf);
|
char *net_inet_ntoa(uint32_t addr, char *buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:端口字节序转换(主机序 -> 网络序)
|
* 函数功能:端口字节序转换(主机序 -> 网络序)
|
||||||
|
* 入口参数:hostshort - 主机序端口
|
||||||
|
* 返回值:网络序端口
|
||||||
|
* 限定条件:无
|
||||||
|
* 函数说明:小端 → 大端
|
||||||
*/
|
*/
|
||||||
uint16_t net_htons(uint16_t hostshort);
|
uint16_t net_htons(uint16_t hostshort);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:端口字节序转换(网络序 -> 主机序)
|
* 函数功能:端口字节序转换(网络序 -> 主机序)
|
||||||
|
* 入口参数:netshort - 网络序端口
|
||||||
|
* 返回值:主机序端口
|
||||||
|
* 限定条件:无
|
||||||
|
* 函数说明:大端 → 小端
|
||||||
*/
|
*/
|
||||||
uint16_t net_ntohs(uint16_t netshort);
|
uint16_t net_ntohs(uint16_t netshort);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:IP 地址字节序转换(主机序 -> 网络序)
|
* 函数功能:IP 地址字节序转换(主机序 -> 网络序)
|
||||||
|
* 入口参数:hostlong - 主机序 IP
|
||||||
|
* 返回值:网络序 IP
|
||||||
|
* 限定条件:无
|
||||||
|
* 函数说明:小端 → 大端
|
||||||
*/
|
*/
|
||||||
uint32_t net_htonl(uint32_t hostlong);
|
uint32_t net_htonl(uint32_t hostlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:IP 地址字节序转换(网络序 -> 主机序)
|
* 函数功能:IP 地址字节序转换(网络序 -> 主机序)
|
||||||
|
* 入口参数:netlong - 网络序 IP
|
||||||
|
* 返回值:主机序 IP
|
||||||
|
* 限定条件:无
|
||||||
|
* 函数说明:大端 → 小端
|
||||||
*/
|
*/
|
||||||
uint32_t net_ntohl(uint32_t netlong);
|
uint32_t net_ntohl(uint32_t netlong);
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,18 @@
|
|||||||
* 模å<C2A1>—å<E28094><C3A5>称:RS-485 å<>Šå<C5A0>Œå·¥é€šä¿¡é©±åЍ
|
* 模å<C2A1>—å<E28094><C3A5>称:RS-485 å<>Šå<C5A0>Œå·¥é€šä¿¡é©±åЍ
|
||||||
* 模å<C2A1>—功能:RS-485 å<>Šå<C5A0>Œå·¥é€šä¿¡é©±åŠ¨å®žçŽ°ï¼Œæ ¸å¿ƒè¦<C3A8>点:
|
* 模å<C2A1>—功能:RS-485 å<>Šå<C5A0>Œå·¥é€šä¿¡é©±åŠ¨å®žçŽ°ï¼Œæ ¸å¿ƒè¦<C3A8>点:
|
||||||
* 1. å<>‘é€<C3A9>å‰<C3A5>拉高 DE(切æ<E280A1>¢åˆ°å<C2B0>‘é€<C3A9>æ€<C3A6>)
|
* 1. å<>‘é€<C3A9>å‰<C3A5>拉高 DE(切æ<E280A1>¢åˆ°å<C2B0>‘é€<C3A9>æ€<C3A6>)
|
||||||
* 2. HAL_UART_Transmit 内部已等待 TC(发送完成)标志
|
* 2. HAL_UART_Transmit 内部已ç‰ï¿?TC(å<CB86>‘é€<C3A9>完æˆ<C3A6>ï¼‰æ ‡å¿—
|
||||||
* 3. å<>‘é€<C3A9>完毕å<E280A2>Žæ‹‰ä½Ž DE(切回接收æ€<C3A6>)
|
* 3. å<>‘é€<C3A9>完毕å<E280A2>Žæ‹‰ä½Ž DE(切回接收æ€<C3A6>)
|
||||||
* 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收
|
* 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现å<EFBFBD>˜é•¿å¸§æŽ¥ï¿? * å<>‚考:ST AN3070 应用笔记ã€<C3A3>controllerstech.com RS485 教程
|
||||||
* 参考:ST AN3070 应用笔记、controllerstech.com RS485 教程
|
|
||||||
* 适用平å<C2B3>°ï¼šSTM32F4 系列
|
* 适用平å<C2B3>°ï¼šSTM32F4 系列
|
||||||
* 作者:王建锋
|
* 作者:王建� * 创建日期�026-07-18
|
||||||
* 创建日期:2026-07-18
|
* 修改记录ï¿? * 2026-07-18 王建ï¿? 创建åˆ<C3A5>始版本
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-18 王建锋 创建初始版本
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 内部辅助宏 - 方向控制
|
* 内部辅助ï¿?- æ–¹å<C2B9>‘控制
|
||||||
*/
|
*/
|
||||||
#define RS485_DIR_TX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_SET)
|
#define RS485_DIR_TX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_SET)
|
||||||
#define RS485_DIR_RX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_RESET)
|
#define RS485_DIR_RX(h) HAL_GPIO_WritePin((h)->dir_port, (h)->dir_pin, GPIO_PIN_RESET)
|
||||||
@@ -31,60 +28,49 @@
|
|||||||
* huart - UART 外设å<C2BE>¥æŸ„
|
* huart - UART 外设å<C2BE>¥æŸ„
|
||||||
* dir_port - DE 引脚 GPIO 端å<C2AF>£
|
* dir_port - DE 引脚 GPIO 端å<C2AF>£
|
||||||
* dir_pin - DE 引脚 GPIO ç¼–å<E28093>·
|
* dir_pin - DE 引脚 GPIO ç¼–å<E28093>·
|
||||||
* 返回值:无
|
* 返回值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šUART ï¿?GPIO 须先ï¿?CubeMX 完æˆ<C3A6>åˆ<C3A5>å§‹ï¿? * 函数说明:åˆ<C3A5>始化å<E28093>Žç«‹å<E280B9>³å°† DE 拉低,使 RS-485 æ”¶å<C2B6>‘器处于接收状ï¿? */
|
||||||
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
|
void rs485_init(rs485_handle_t *p_handle,
|
||||||
* 函数说明:初始化后立即将 DE 拉低,使 RS-485 收发器处于接收状态
|
UART_HandleTypeDef *p_huart,
|
||||||
*/
|
GPIO_TypeDef *p_dir_port,
|
||||||
void rs485_init(rs485_handle_t *handle,
|
uint16_t dir_pin) {
|
||||||
UART_HandleTypeDef *huart,
|
p_handle->huart = p_huart;
|
||||||
GPIO_TypeDef *dir_port,
|
p_handle->dir_port = p_dir_port;
|
||||||
uint16_t dir_pin)
|
p_handle->dir_pin = dir_pin;
|
||||||
{
|
p_handle->rx_size = 0;
|
||||||
handle->huart = huart;
|
|
||||||
handle->dir_port = dir_port;
|
|
||||||
handle->dir_pin = dir_pin;
|
|
||||||
handle->rx_size = 0;
|
|
||||||
|
|
||||||
/* 默认进入接收状态 */
|
/* 默认进入接收状�?*/
|
||||||
RS485_DIR_RX(handle);
|
RS485_DIR_RX(p_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:阻塞方式发送数据
|
* 函数功能:阻塞方å¼<EFBFBD>å<EFBFBD>‘é€<EFBFBD>æ•°ï¿? * å…¥å<C2A5>£å<C2A3>‚数:handle - RS-485 å<>¥æŸ„指针
|
||||||
* 入口参数:handle - RS-485 句柄指针
|
|
||||||
* data - å¾…å<E280A6>‘é€<C3A9>æ•°æ<C2B0>®ç¼“冲区
|
* data - å¾…å<E280A6>‘é€<C3A9>æ•°æ<C2B0>®ç¼“冲区
|
||||||
* len - å¾…å<E280A6>‘é€<C3A9>å—节数
|
* len - å¾…å<E280A6>‘é€<C3A9>å—节数
|
||||||
* timeout - 发送超时(ms),传 0 使用默认值
|
* timeout - å<EFBFBD>‘é€<EFBFBD>超时(ms),ï¿?0 使用默认ï¿? * 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR
|
||||||
* 返回值:HAL_OK / HAL_TIMEOUT / HAL_ERROR
|
* é™<EFBFBD>定æ<EFBFBD>¡ä»¶ï¼šé¡»åœ¨ä¸»å¾ªçޝï¿?RTOS 任务ä¸è°ƒç”¨ï¼Œä¸<C3A4>å<EFBFBD>¯ï¿?UART 䏿–ä¸è°ƒï¿? * 函数说明ï¿? * æ—¶åº<C3A5>:DE=HIGH ï¿?UART å<>‘�?N å—节 ï¿?ï¿?TC ï¿?DE=LOW
|
||||||
* 限定条件:须在主循环或 RTOS 任务中调用,不可在 UART 中断中调用
|
* HAL_UART_Transmit 内部会ç‰ï¿?TXE(å<CB86>‘é€<C3A9>寄å˜å™¨ç©ºï¼‰é€<C3A9>å—节æ<E2809A>¬æ•°æ<C2B0>®ï¿? * 最å<E282AC>Žè¿˜ä¼šç‰ï¿?TC(å<CB86>‘é€<C3A9>完æˆ<C3A6>ï¼‰æ ‡å¿—ï¼Œç¡®ä¿<C3A4>最å<E282AC>Žä¸€å—节的å<E2809E>œæ¢ä½<C3A4>已移出�? * å› æ¤è¿”回å<C5BE>Žå†<C3A5>拉低 DE 是安全的
|
||||||
* 函数说明:
|
|
||||||
* 时序:DE=HIGH → UART 发送 N 字节 → 等 TC → DE=LOW
|
|
||||||
* HAL_UART_Transmit 内部会等待 TXE(发送寄存器空)逐字节搬数据,
|
|
||||||
* 最后还会等待 TC(发送完成)标志,确保最后一字节的停止位已移出。
|
|
||||||
* 因此返回后再拉低 DE 是安全的
|
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
|
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||||
const uint8_t *data,
|
const uint8_t *p_data,
|
||||||
uint16_t len,
|
uint16_t len,
|
||||||
uint32_t timeout)
|
uint32_t timeout) {
|
||||||
{
|
HAL_StatusTypeDef status = HAL_OK;
|
||||||
HAL_StatusTypeDef status;
|
|
||||||
|
|
||||||
if (timeout == 0U) {
|
if (timeout == 0U) {
|
||||||
timeout = RS485_TIMEOUT_DEFAULT;
|
timeout = RS485_TIMEOUT_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1. 切换到发送状态 */
|
/* 1. 切æ<EFBFBD>¢åˆ°å<EFBFBD>‘é€<EFBFBD>状ï¿?*/
|
||||||
RS485_DIR_TX(handle);
|
RS485_DIR_TX(p_handle);
|
||||||
|
|
||||||
/* 2. 阻塞发送(内部等待 TC) */
|
/* 2. 阻塞å<EFBFBD>‘é€<EFBFBD>(内部ç‰å¾… TCï¿?*/
|
||||||
status = HAL_UART_Transmit(handle->huart,
|
status = HAL_UART_Transmit(p_handle->huart,
|
||||||
(uint8_t *)data,
|
(uint8_t *)p_data,
|
||||||
len,
|
len,
|
||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
/* 3. 发送完毕或超时,切回接收状态 */
|
/* 3. å<EFBFBD>‘é€<EFBFBD>完毕或超时,切回接收状ï¿?*/
|
||||||
RS485_DIR_RX(handle);
|
RS485_DIR_RX(p_handle);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -92,42 +78,27 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
|
|||||||
/*
|
/*
|
||||||
* 函数功能:å<C5A1>¯åЍ䏿–æ–¹å¼<C3A5>接收(IDLE 空闲帧检测)
|
* 函数功能:å<C5A1>¯åЍ䏿–æ–¹å¼<C3A5>接收(IDLE 空闲帧检测)
|
||||||
* å…¥å<C2A5>£å<C2A3>‚数:handle - RS-485 å<>¥æŸ„指针
|
* å…¥å<C2A5>£å<C2A3>‚数:handle - RS-485 å<>¥æŸ„指针
|
||||||
* buf - 接收缓冲区
|
* buf - 接收缓冲� * buf_size - 缓冲区最大容� * 返回值:HAL_OK / HAL_ERROR
|
||||||
* buf_size - 缓冲区最大容量
|
* é™<EFBFBD>定æ<EFBFBD>¡ä»¶ï¼šUART 须已开å<E282AC>¯å…¨å±€ä¸æ–(NVIC 使能ï¿? * 函数说明ï¿? * 使用 HAL_UARTEx_ReceiveToIdle_IT 实现å<C2B0>˜é•¿å¸§æŽ¥æ”¶ï¿½? * ï¿?UART 总线空闲超过 1 个å—符时间å<C2B4>Žï¼Œç¡¬ä»¶è§¦ï¿?IDLE 䏿–ï¿? * HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收å—节数�? * 用户须在该回调ä¸é‡<C3A9>新调用本函数é‡<C3A9>æ–°å¼€å<E282AC>¯æŽ¥ï¿? */
|
||||||
* 返回值:HAL_OK / HAL_ERROR
|
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle,
|
||||||
* 限定条件:UART 须已开启全局中断(NVIC 使能)
|
uint8_t *p_buf,
|
||||||
* 函数说明:
|
uint16_t buf_size) {
|
||||||
* 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。
|
p_handle->rx_size = 0;
|
||||||
* 当 UART 总线空闲超过 1 个字符时间后,硬件触发 IDLE 中断,
|
return HAL_UARTEx_ReceiveToIdle_IT(p_handle->huart, p_buf, buf_size);
|
||||||
* HAL 自动调用 HAL_UARTEx_RxEventCallback 并返回已接收字节数。
|
|
||||||
* 用户须在该回调中重新调用本函数重新开启接收
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle,
|
|
||||||
uint8_t *buf,
|
|
||||||
uint16_t buf_size)
|
|
||||||
{
|
|
||||||
handle->rx_size = 0;
|
|
||||||
return HAL_UARTEx_ReceiveToIdle_IT(handle->huart, buf, buf_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:缓存最近一次接收的字节数
|
* å‡½æ•°åŠŸèƒ½ï¼šç¼“å˜æœ€è¿‘一次接收的å—节ï¿? * å…¥å<C2A5>£å<C2A3>‚数:handle - RS-485 å<>¥æŸ„指针
|
||||||
* 入口参数:handle - RS-485 句柄指针
|
* size - 本次接收到的å—节ï¿? * 返回值:ï¿? * é™<C3A9>定æ<C5A1>¡ä»¶ï¼šé¡»ï¿?HAL_UARTEx_RxEventCallback ä¸è°ƒï¿? */
|
||||||
* size - 本次接收到的字节数
|
void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size) {
|
||||||
* 返回值:无
|
p_handle->rx_size = size;
|
||||||
* 限定条件:须在 HAL_UARTEx_RxEventCallback 中调用
|
|
||||||
*/
|
|
||||||
void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size)
|
|
||||||
{
|
|
||||||
handle->rx_size = size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取最近一次接收的字节数
|
* 函数功能:获å<EFBFBD>–最近一次接收的å—节ï¿? * å…¥å<C2A5>£å<C2A3>‚数:handle - RS-485 å<>¥æŸ„指针
|
||||||
* 入口参数:handle - RS-485 句柄指针
|
* 返回值:å—节ï¿? */
|
||||||
* 返回值:字节数
|
uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle) {
|
||||||
*/
|
return p_handle->rx_size;
|
||||||
uint16_t rs485_rx_get_size(const rs485_handle_t *handle)
|
|
||||||
{
|
|
||||||
return handle->rx_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ typedef struct {
|
|||||||
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
|
* 限定条件:UART 和 GPIO 须先由 CubeMX 完成初始化
|
||||||
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低)
|
* 函数说明:初始化后默认处于接收状态(DE 引脚拉低)
|
||||||
*/
|
*/
|
||||||
void rs485_init(rs485_handle_t *handle,
|
void rs485_init(rs485_handle_t *p_handle,
|
||||||
UART_HandleTypeDef *huart,
|
UART_HandleTypeDef *p_huart,
|
||||||
GPIO_TypeDef *dir_port,
|
GPIO_TypeDef *p_dir_port,
|
||||||
uint16_t dir_pin);
|
uint16_t dir_pin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -66,8 +66,8 @@ void rs485_init(rs485_handle_t *handle,
|
|||||||
* 函数说明:发送前自动拉高 DE,发送完成后等待 TC 标志再拉低 DE,
|
* 函数说明:发送前自动拉高 DE,发送完成后等待 TC 标志再拉低 DE,
|
||||||
* 确保最后一字节完全移出后再切换到接收状态
|
* 确保最后一字节完全移出后再切换到接收状态
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
|
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
|
||||||
const uint8_t *data,
|
const uint8_t *p_data,
|
||||||
uint16_t len,
|
uint16_t len,
|
||||||
uint32_t timeout);
|
uint32_t timeout);
|
||||||
|
|
||||||
@@ -82,8 +82,8 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
|
|||||||
* 收到完整帧后在 RxEventCallback 中通知用户。
|
* 收到完整帧后在 RxEventCallback 中通知用户。
|
||||||
* 用户须在回调中重新调用本函数重新开启接收
|
* 用户须在回调中重新调用本函数重新开启接收
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle,
|
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *p_handle,
|
||||||
uint8_t *buf,
|
uint8_t *p_buf,
|
||||||
uint16_t buf_size);
|
uint16_t buf_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -93,7 +93,7 @@ HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle,
|
|||||||
* 限定条件:须在 HAL_UART_RxCpltCallback / HAL_UARTEx_RxEventCallback 中调用
|
* 限定条件:须在 HAL_UART_RxCpltCallback / HAL_UARTEx_RxEventCallback 中调用
|
||||||
* 函数说明:将 HAL 回调中接收到的数据大小回写到句柄的 rx_size 字段
|
* 函数说明:将 HAL 回调中接收到的数据大小回写到句柄的 rx_size 字段
|
||||||
*/
|
*/
|
||||||
void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size);
|
void rs485_rx_set_size(rs485_handle_t *p_handle, uint16_t size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:获取最近一次接收的字节数
|
* 函数功能:获取最近一次接收的字节数
|
||||||
@@ -101,7 +101,7 @@ void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size);
|
|||||||
* 返回值:最近一次接收的字节数
|
* 返回值:最近一次接收的字节数
|
||||||
* 限定条件:须在 HAL_UARTEx_RxEventCallback 触发后调用
|
* 限定条件:须在 HAL_UARTEx_RxEventCallback 触发后调用
|
||||||
*/
|
*/
|
||||||
uint16_t rs485_rx_get_size(const rs485_handle_t *handle);
|
uint16_t rs485_rx_get_size(const rs485_handle_t *p_handle);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* 模块名称:SD2506API-G RTC 实时时钟驱动
|
* 模块名称:SD2506API-G RTC 实时时钟驱动
|
||||||
* 模块功能:SD2506API-G 高精度温补实时时钟模块 I2C 驱动
|
* 模块功能:SD2506API-G 高精度温补实时时钟模<EFBFBD>?I2C 驱动
|
||||||
* 适用平台:STM32F407ZGT6,I2C1 接口 (PB6-SCL, PB7-SDA)
|
* 适用平台:STM32F407ZGT6,I2C1 接口 (PB6-SCL, PB7-SDA)
|
||||||
* 作者:王建锋
|
* 作者:王建<EFBFBD>? * 创建日期<E697A5>?026-07-17
|
||||||
* 创建日期:2026-07-17
|
* 修改记录<EFBFBD>? * 2026-07-17 王建<E78E8B>? 创建初始版本,参<EFBC8C>?SD2506API-G Ver2.0 手册
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "sd2506.h"
|
#include "sd2506.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern I2C_HandleTypeDef hi2c1;
|
extern I2C_HandleTypeDef hi2c1;
|
||||||
|
|
||||||
/* ======================== 内部辅助函数 ======================== */
|
/* ======================== 内部辅助函数 ======================== */
|
||||||
|
|
||||||
uint8_t sd2506_bcd_to_dec(uint8_t bcd)
|
/*
|
||||||
{
|
* 函数功能:BCD 码转十进<E58D81>? * 入口参数:bcd - BCD 编码<E7BC96>? uint8_t 0x00 - 0x99
|
||||||
|
* <20>?<3F>?值:十进制数<E588B6>? * 限定条件:输入为合法 BCD <20>? * 函数说明:高 4 位为十位,低 4 位为个位
|
||||||
|
*/
|
||||||
|
uint8_t sd2506_bcd_to_dec(uint8_t bcd) {
|
||||||
return ((bcd >> 4) * 10) + (bcd & 0x0FU);
|
return ((bcd >> 4) * 10) + (bcd & 0x0FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sd2506_dec_to_bcd(uint8_t dec)
|
/*
|
||||||
{
|
* 函数功能:十进制<E8BF9B>?BCD <20>? * 入口参数:dec - 十进制数<E588B6>? uint8_t 0 - 99
|
||||||
|
* <20>?<3F>?值:BCD 编码<E7BC96>? * 限定条件:输入值在 0 - 99 范围<E88C83>? * 函数说明:十位存入高 4 位,个位存入<E5AD98>?4 <20>? */
|
||||||
|
uint8_t sd2506_dec_to_bcd(uint8_t dec) {
|
||||||
return ((dec / 10) << 4) | (dec % 10);
|
return ((dec / 10) << 4) | (dec % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 写单字节寄存器
|
* 函数功能:写单字节寄存器
|
||||||
* reg: 寄存器地址 (00H~79H)
|
* 入口参数:reg - 寄存器地址 uint8_t 00H - 79H
|
||||||
* val: 写入值
|
* val - 写入<EFBFBD>? uint8_t 0x00 - 0xFF
|
||||||
* 返回: 0=成功, -2=I2C错误
|
* <EFBFBD>?<3F>?值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化
|
||||||
|
* 函数说明:通过 I2C 向指定地址写入 1 字节
|
||||||
*/
|
*/
|
||||||
static int sd2506_write_reg(uint8_t reg, uint8_t val)
|
static int sd2506_write_reg(uint8_t reg, uint8_t val) {
|
||||||
{
|
|
||||||
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
|
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
|
||||||
I2C_MEMADD_SIZE_8BIT, &val, 1,
|
I2C_MEMADD_SIZE_8BIT, &val, 1,
|
||||||
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
||||||
@@ -43,15 +47,15 @@ static int sd2506_write_reg(uint8_t reg, uint8_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 读单字节寄存器
|
* 函数功能:读单字节寄存器
|
||||||
* reg: 寄存器地址 (00H~79H)
|
* 入口参数:reg - 寄存器地址 uint8_t 00H - 79H
|
||||||
* val: 读取值指针
|
* val - 读取值指<EFBFBD>? uint8_t*
|
||||||
* 返回: 0=成功, -2=I2C错误
|
* <EFBFBD>?<3F>?值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化,val 为非空指<E7A9BA>? * 函数说明:通过 I2C 从指定地址读取 1 字节
|
||||||
*/
|
*/
|
||||||
static int sd2506_read_reg(uint8_t reg, uint8_t *val)
|
static int sd2506_read_reg(uint8_t reg, uint8_t *p_val) {
|
||||||
{
|
|
||||||
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
|
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
|
||||||
I2C_MEMADD_SIZE_8BIT, val, 1,
|
I2C_MEMADD_SIZE_8BIT, p_val, 1,
|
||||||
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
||||||
return SD2506_I2C_ERROR;
|
return SD2506_I2C_ERROR;
|
||||||
}
|
}
|
||||||
@@ -59,16 +63,16 @@ static int sd2506_read_reg(uint8_t reg, uint8_t *val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 写多字节寄存器 (从 reg 开始连续写入 len 字节)
|
* 函数功能:写多字节寄存器
|
||||||
* reg: 起始寄存器地址
|
* 入口参数:reg - 起始寄存器地址 uint8_t 00H - 79H
|
||||||
* data: 数据缓冲区
|
* data - 数据缓冲区指<EFBFBD>? uint8_t*
|
||||||
* len: 数据长度
|
* len - 数据长度 uint8_t 1 - N
|
||||||
* 返回: 0=成功, -2=I2C错误
|
* <EFBFBD>?<3F>?值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化,data 为非空指<E7A9BA>? * 函数说明:从 reg 开始连续写<E7BBAD>?len 字节
|
||||||
*/
|
*/
|
||||||
static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len)
|
static int sd2506_write_regs(uint8_t reg, const uint8_t *p_data, uint8_t len) {
|
||||||
{
|
|
||||||
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
|
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
|
||||||
I2C_MEMADD_SIZE_8BIT, (uint8_t *)data, len,
|
I2C_MEMADD_SIZE_8BIT, (uint8_t *)p_data, len,
|
||||||
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
||||||
return SD2506_I2C_ERROR;
|
return SD2506_I2C_ERROR;
|
||||||
}
|
}
|
||||||
@@ -76,16 +80,16 @@ static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 读多字节寄存器 (从 reg 开始连续读取 len 字节)
|
* 函数功能:读多字节寄存器
|
||||||
* reg: 起始寄存器地址
|
* 入口参数:reg - 起始寄存器地址 uint8_t 00H - 79H
|
||||||
* data: 数据缓冲区
|
* data - 数据缓冲区指<EFBFBD>? uint8_t*
|
||||||
* len: 数据长度
|
* len - 数据长度 uint8_t 1 - N
|
||||||
* 返回: 0=成功, -2=I2C错误
|
* <EFBFBD>?<3F>?值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化,data 为非空指<E7A9BA>? * 函数说明:从 reg 开始连续读<E7BBAD>?len 字节
|
||||||
*/
|
*/
|
||||||
static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len)
|
static int sd2506_read_regs(uint8_t reg, uint8_t *p_data, uint8_t len) {
|
||||||
{
|
|
||||||
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
|
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
|
||||||
I2C_MEMADD_SIZE_8BIT, data, len,
|
I2C_MEMADD_SIZE_8BIT, p_data, len,
|
||||||
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
|
||||||
return SD2506_I2C_ERROR;
|
return SD2506_I2C_ERROR;
|
||||||
}
|
}
|
||||||
@@ -93,14 +97,16 @@ static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 开启写保护 (允许写入 00H~71H 寄存器)
|
* 函数功能:开启写保护(允许写<EFBFBD>?00H~71H 寄存器)
|
||||||
* 顺序: 先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1
|
* 入口参数:无
|
||||||
|
* 返回值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化
|
||||||
|
* 函数说明:顺序:先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1
|
||||||
*/
|
*/
|
||||||
static int sd2506_write_enable(void)
|
static int sd2506_write_enable(void) {
|
||||||
{
|
int ret = 0;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* 先置 WRTC1=1 (bit6=1), 其它位参考手册: 0x84 */
|
/* 先置 WRTC1=1 (bit6=1), 其它位参考手<EFBFBD>? 0x84 */
|
||||||
ret = sd2506_write_reg(SD2506_REG_CTR1, 0x84U);
|
ret = sd2506_write_reg(SD2506_REG_CTR1, 0x84U);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
@@ -112,12 +118,14 @@ static int sd2506_write_enable(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 关闭写保护 (禁止写入 00H~71H 寄存器)
|
* 函数功能:关闭写保护(禁止写<EFBFBD>?00H~71H 寄存器)
|
||||||
* 顺序: 先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0
|
* 入口参数:无
|
||||||
|
* 返回值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:I2C 外设已初始化
|
||||||
|
* 函数说明:顺序:先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0
|
||||||
*/
|
*/
|
||||||
static int sd2506_write_disable(void)
|
static int sd2506_write_disable(void) {
|
||||||
{
|
int ret = 0;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* 先清 WRTC2=0, WRTC3=0: 0x00 */
|
/* 先清 WRTC2=0, WRTC3=0: 0x00 */
|
||||||
ret = sd2506_write_reg(SD2506_REG_CTR2, 0x00U);
|
ret = sd2506_write_reg(SD2506_REG_CTR2, 0x00U);
|
||||||
@@ -132,28 +140,36 @@ static int sd2506_write_disable(void)
|
|||||||
|
|
||||||
/* ======================== 公共 API 实现 ======================== */
|
/* ======================== 公共 API 实现 ======================== */
|
||||||
|
|
||||||
int sd2506_init(void)
|
/*
|
||||||
{
|
* 函数功能:初始化 SD2506API-G RTC
|
||||||
int ret;
|
* 入口参数:无
|
||||||
uint8_t id[8];
|
* 返回值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:CubeMX 已完<E5B7B2>?I2C1 初始<E5889D>?
|
||||||
|
* 函数说明<E8AFB4>?. 读取芯片 ID 验证通信
|
||||||
|
* 2. 上电重置充电寄存<E5AF84>?18H=82H
|
||||||
|
* 3. 配置 24 小时制、开自动复位
|
||||||
|
*/
|
||||||
|
int sd2506_init(void) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t a_id[8] = {0};
|
||||||
|
|
||||||
/* 验证 I2C 通信: 尝试读取 8 字节 ID */
|
/* 验证 I2C 通信: 尝试读取 8 字节 ID */
|
||||||
ret = sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE);
|
ret = sd2506_read_regs(SD2506_REG_ID_START, a_id, SD2506_ID_SIZE);
|
||||||
if (ret != SD2506_OK) {
|
if (ret != SD2506_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 上电重置充电寄存器 18H = 82H (开启充电, 5K电阻)
|
/* 上电重置充电寄存<EFBFBD>?18H = 82H (开启充<EFBFBD>? 5K电阻)
|
||||||
* 手册强烈建议每次上电时重置此值 */
|
* 手册强烈建议每次上电时重置此<EFBFBD>?*/
|
||||||
ret = sd2506_write_reg(SD2506_REG_CHARGE, 0x82U);
|
ret = sd2506_write_reg(SD2506_REG_CHARGE, 0x82U);
|
||||||
if (ret != SD2506_OK) {
|
if (ret != SD2506_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 配置: 24小时制, 自动复位使能
|
/* 配置: 24小时<EFBFBD>? 自动复位使能
|
||||||
* 0FH = 0x20 (bit5=ARST=1, 其它标志位清零)
|
* 0FH = 0x20 (bit5=ARST=1, 其它标志位清<EFBFBD>?
|
||||||
* 写入时需注意: 写允许状态下 0FH 的 WRTC 位必须为1
|
* 写入时需注意: 写允许状态下 0FH <EFBFBD>?WRTC 位必须为1
|
||||||
* 此处直接写入 0x20 即可 (ARST=1, 无 WRTC 位) */
|
* 此处直接写入 0x20 即可 (ARST=1, <EFBFBD>?WRTC <EFBFBD>? */
|
||||||
ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF);
|
ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF);
|
||||||
if (ret != SD2506_OK) {
|
if (ret != SD2506_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -162,73 +178,91 @@ int sd2506_init(void)
|
|||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_set_time(const sd2506_time_t *time)
|
/*
|
||||||
{
|
* 函数功能:设<EFBC9A>?RTC 时间日期
|
||||||
int ret;
|
* 入口参数:p_time - 时间结构体指针,包含要设置的时间
|
||||||
uint8_t buf[7];
|
* 返回值:0 - 成功<E68890>?2 - I2C 错误
|
||||||
|
* 限定条件:sd2506_init() 已调<E5B7B2>?
|
||||||
|
* 函数说明<E8AFB4>?. 先开写保<E58699>?
|
||||||
|
* 2. 一次性写<E680A7>?7 字节时间数据 (00H~06H)
|
||||||
|
* 3. 关闭写保<E58699>?
|
||||||
|
*/
|
||||||
|
int sd2506_set_time(const sd2506_time_t *p_time) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[7] = {0};
|
||||||
|
|
||||||
if (time == NULL) {
|
if (p_time == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 组装 7 字节时间数据 (BCD 码) */
|
/* 组装 7 字节时间数据 (BCD <EFBFBD>? */
|
||||||
buf[0] = sd2506_dec_to_bcd(time->second); /* 00H: 秒 */
|
buf[0] = sd2506_dec_to_bcd(p_time->second); /* 00H: <EFBFBD>?*/
|
||||||
buf[1] = sd2506_dec_to_bcd(time->minute); /* 01H: 分 */
|
buf[1] = sd2506_dec_to_bcd(p_time->minute); /* 01H: <EFBFBD>?*/
|
||||||
buf[2] = sd2506_dec_to_bcd(time->hour) | 0x80U; /* 02H: 时 (bit7=1, 24小时制) */
|
buf[2] = sd2506_dec_to_bcd(p_time->hour) | 0x80U; /* 02H: <EFBFBD>?(bit7=1, 24小时<EFBFBD>? */
|
||||||
buf[3] = sd2506_dec_to_bcd(time->week); /* 03H: 星期 */
|
buf[3] = sd2506_dec_to_bcd(p_time->week); /* 03H: 星期 */
|
||||||
buf[4] = sd2506_dec_to_bcd(time->day); /* 04H: 日 */
|
buf[4] = sd2506_dec_to_bcd(p_time->day); /* 04H: <EFBFBD>?*/
|
||||||
buf[5] = sd2506_dec_to_bcd(time->month); /* 05H: 月 */
|
buf[5] = sd2506_dec_to_bcd(p_time->month); /* 05H: <EFBFBD>?*/
|
||||||
buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 06H: 年 */
|
buf[6] = sd2506_dec_to_bcd(p_time->year - 2000U); /* 06H: <EFBFBD>?*/
|
||||||
|
|
||||||
/* 开启写保护 */
|
/* 开启写保护 */
|
||||||
ret = sd2506_write_enable();
|
ret = sd2506_write_enable();
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 一次性写入 7 字节时间数据 (00H~06H)
|
/* 一次性写<EFBFBD>?7 字节时间数据 (00H~06H)
|
||||||
* 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进位 */
|
* 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进<EFBFBD>?*/
|
||||||
ret = sd2506_write_regs(SD2506_REG_SEC, buf, 7);
|
ret = sd2506_write_regs(SD2506_REG_SEC, buf, 7);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 关闭写保护 */
|
/* 关闭写保<EFBFBD>?*/
|
||||||
ret = sd2506_write_disable();
|
ret = sd2506_write_disable();
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_get_time(sd2506_time_t *time)
|
/*
|
||||||
{
|
* function: read RTC time
|
||||||
int ret;
|
* param: p_time - output time struct
|
||||||
uint8_t buf[7];
|
* return: 0=OK, -2=I2C error
|
||||||
|
* note: sd2506_init() must be called first
|
||||||
|
*/
|
||||||
|
int sd2506_get_time(sd2506_time_t *p_time) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[7] = {0};
|
||||||
|
|
||||||
if (time == NULL) {
|
if (p_time == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 一次读取 7 字节时间数据 (00H~06H)
|
/* 一次读<EFBFBD>?7 字节时间数据 (00H~06H)
|
||||||
* 手册说明: 读取时所有实时数据被锁存,避免错读 */
|
* 手册说明: 读取时所有实时数据被锁存,避免错<EFBFBD>?*/
|
||||||
ret = sd2506_read_regs(SD2506_REG_SEC, buf, 7);
|
ret = sd2506_read_regs(SD2506_REG_SEC, buf, 7);
|
||||||
if (ret != SD2506_OK) {
|
if (ret != SD2506_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: 秒 */
|
p_time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: <EFBFBD>?*/
|
||||||
time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: 分 */
|
p_time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: <EFBFBD>?*/
|
||||||
time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */
|
p_time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */
|
||||||
time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */
|
p_time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */
|
||||||
time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: 日 */
|
p_time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: <EFBFBD>?*/
|
||||||
time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: 月 */
|
p_time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: <EFBFBD>?*/
|
||||||
time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: 年 */
|
p_time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: <EFBFBD>?*/
|
||||||
|
|
||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_get_temperature(int8_t *temp)
|
/*
|
||||||
{
|
* function: read internal temperature
|
||||||
int ret;
|
* param: p_temp - output temperature
|
||||||
uint8_t val;
|
* return: 0=OK, -2=I2C error
|
||||||
|
* note: reads register 0x16
|
||||||
|
*/
|
||||||
|
int sd2506_get_temperature(int8_t *p_temp) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t val = 0;
|
||||||
|
|
||||||
if (temp == NULL) {
|
if (p_temp == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,54 +271,72 @@ int sd2506_get_temperature(int8_t *temp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bit7 为符号位, 其余为温度值 */
|
/* bit7 为符号位, 其余为温度<EFBFBD>?*/
|
||||||
if (val & 0x80U) {
|
if (val & 0x80U) {
|
||||||
/* 负温度: 取补码 */
|
/* 负温<EFBFBD>? 取补<EFBFBD>?*/
|
||||||
*temp = (int8_t)(val | 0xF0U);
|
*p_temp = (int8_t)(val | 0xF0U);
|
||||||
} else {
|
} else {
|
||||||
/* 正温度 */
|
/* 正温<EFBFBD>?*/
|
||||||
*temp = (int8_t)(val & 0x7FU);
|
*p_temp = (int8_t)(val & 0x7FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_get_battery_voltage(uint16_t *voltage)
|
/*
|
||||||
{
|
* function: read battery voltage (mV)
|
||||||
int ret;
|
* param: p_voltage - output voltage
|
||||||
uint8_t val_high, val_low;
|
* return: 0=OK, -2=I2C error
|
||||||
|
* note: combines 9-bit value
|
||||||
|
*/
|
||||||
|
int sd2506_get_battery_voltage(uint16_t *p_voltage) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t val_high = 0;
|
||||||
|
uint8_t val_low = 0;
|
||||||
|
|
||||||
if (voltage == NULL) {
|
if (p_voltage == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) */
|
/* 读取 1AH bit7 (BAT8_VAL) <EFBFBD>?1BH (BAT_VL) */
|
||||||
ret = sd2506_read_reg(SD2506_REG_CTR5, &val_high);
|
ret = sd2506_read_reg(SD2506_REG_CTR5, &val_high);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
ret = sd2506_read_reg(SD2506_REG_BAT_VAL, &val_low);
|
ret = sd2506_read_reg(SD2506_REG_BAT_VAL, &val_low);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 组合 9 位: bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH)
|
/* 组合 9 <EFBFBD>? bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH)
|
||||||
* 如 1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */
|
* <EFBFBD>?1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */
|
||||||
uint16_t raw = ((val_high & 0x80U) << 1) | val_low;
|
uint16_t raw = ((val_high & 0x80U) << 1) | val_low;
|
||||||
*voltage = raw * 10; /* 转换为毫伏 (raw 单位 0.01V) */
|
*p_voltage = raw * 10; /* 转换为毫<EFBFBD>?(raw 单位 0.01V) */
|
||||||
|
|
||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_get_id(uint8_t id[8])
|
/*
|
||||||
{
|
* function: read 8-byte chip ID
|
||||||
if (id == NULL) {
|
* param: p_id - 8-byte output buffer
|
||||||
|
* return: 0=OK, -2=I2C error
|
||||||
|
* note: reads registers 0x72-0x79
|
||||||
|
*/
|
||||||
|
int sd2506_get_id(uint8_t p_id[8]) {
|
||||||
|
if (p_id == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE);
|
return sd2506_read_regs(SD2506_REG_ID_START, p_id, SD2506_ID_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len)
|
/*
|
||||||
{
|
* function: read SRAM data
|
||||||
if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
|
* param: addr - start address (0-69)
|
||||||
|
* p_buf - output buffer
|
||||||
|
* len - read length
|
||||||
|
* return: 0=OK, -1=param err, -2=I2C err
|
||||||
|
* note: SRAM range 0x2C-0x71
|
||||||
|
*/
|
||||||
|
int sd2506_read_sram(uint8_t addr, uint8_t *p_buf, uint8_t len) {
|
||||||
|
if (p_buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,12 +344,18 @@ int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len)
|
|||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd2506_read_regs(SD2506_REG_SRAM_START + addr, buf, len);
|
return sd2506_read_regs(SD2506_REG_SRAM_START + addr, p_buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len)
|
/*
|
||||||
{
|
* function: write SRAM data
|
||||||
if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
|
* param: addr - start address (0-69)
|
||||||
|
* p_buf - input data
|
||||||
|
* len - write length
|
||||||
|
* return: 0=OK, -1=param err, -2=I2C err
|
||||||
|
*/
|
||||||
|
int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len) {
|
||||||
|
if (p_buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,64 +363,74 @@ int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len)
|
|||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SRAM 无需开写保护即可写入 (写保护仅对 00H~71H 有效, SRAM 是 2CH~71H)
|
/* SRAM 无需开写保护即可写<EFBFBD>?(写保护仅<EFBFBD>?00H~71H 有效, SRAM <EFBFBD>?2CH~71H)
|
||||||
* 但为安全起见, SRAM 写入也走写保护流程 */
|
* 但为安全起见, SRAM 写入也走写保护流<EFBFBD>?*/
|
||||||
int ret;
|
int ret = 0;
|
||||||
ret = sd2506_write_enable();
|
ret = sd2506_write_enable();
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, buf, len);
|
ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, p_buf, len);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
ret = sd2506_write_disable();
|
ret = sd2506_write_disable();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask)
|
/*
|
||||||
{
|
* function: set alarm interrupt
|
||||||
int ret;
|
* param: p_time - alarm time struct
|
||||||
uint8_t buf[8];
|
* mask - alarm match mask
|
||||||
|
* return: 0=OK, -2=I2C error
|
||||||
|
*/
|
||||||
|
int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[8] = {0};
|
||||||
|
|
||||||
if (time == NULL) {
|
if (p_time == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 组装 8 字节报警数据 (07H~0EH) */
|
/* 组装 8 字节报警数据 (07H~0EH) */
|
||||||
buf[0] = sd2506_dec_to_bcd(time->second) & 0x7FU; /* 07H: 秒报警 */
|
buf[0] = sd2506_dec_to_bcd(p_time->second) & 0x7FU; /* 07H: 秒报<EFBFBD>?*/
|
||||||
buf[1] = sd2506_dec_to_bcd(time->minute) & 0x7FU; /* 08H: 分报警 */
|
buf[1] = sd2506_dec_to_bcd(p_time->minute) & 0x7FU; /* 08H: 分报<EFBFBD>?*/
|
||||||
buf[2] = sd2506_dec_to_bcd(time->hour) & 0x3FU; /* 09H: 时报警 (最高位始终为0) */
|
buf[2] = sd2506_dec_to_bcd(p_time->hour) & 0x3FU; /* 09H: 时报<EFBFBD>?(最高位始终<EFBFBD>?) */
|
||||||
buf[3] = 0x00U; /* 0AH: 星期报警 */
|
buf[3] = 0x00U; /* 0AH: 星期报警 */
|
||||||
buf[4] = sd2506_dec_to_bcd(time->day) & 0x3FU; /* 0BH: 日报警 */
|
buf[4] = sd2506_dec_to_bcd(p_time->day) & 0x3FU; /* 0BH: 日报<EFBFBD>?*/
|
||||||
buf[5] = sd2506_dec_to_bcd(time->month) & 0x1FU; /* 0CH: 月报警 */
|
buf[5] = sd2506_dec_to_bcd(p_time->month) & 0x1FU; /* 0CH: 月报<EFBFBD>?*/
|
||||||
buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 0DH: 年报警 */
|
buf[6] = sd2506_dec_to_bcd(p_time->year - 2000U); /* 0DH: 年报<EFBFBD>?*/
|
||||||
buf[7] = mask; /* 0EH: 报警允许 */
|
buf[7] = mask; /* 0EH: 报警允许 */
|
||||||
|
|
||||||
/* 开启写保护 */
|
/* 开启写保护 */
|
||||||
ret = sd2506_write_enable();
|
ret = sd2506_write_enable();
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 写入报警寄存器 (07H~0EH) */
|
/* 写入报警寄存<EFBFBD>?(07H~0EH) */
|
||||||
ret = sd2506_write_regs(SD2506_REG_AL_SEC, buf, 8);
|
ret = sd2506_write_regs(SD2506_REG_AL_SEC, buf, 8);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 使能报警中断: CTR2 的 INTAE=1, INTS1=0, INTS0=1, IM=1 (周期性) */
|
/* 使能报警中断: CTR2 <EFBFBD>?INTAE=1, INTS1=0, INTS0=1, IM=1 (周期<EFBFBD>? */
|
||||||
ret = sd2506_write_reg(SD2506_REG_CTR2,
|
ret = sd2506_write_reg(SD2506_REG_CTR2,
|
||||||
SD2506_CTR2_INTAE | SD2506_CTR2_INTS0 | SD2506_CTR2_IM);
|
SD2506_CTR2_INTAE | SD2506_CTR2_INTS0 | SD2506_CTR2_IM);
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
/* 关闭写保护 */
|
/* 关闭写保<EFBFBD>?*/
|
||||||
ret = sd2506_write_disable();
|
ret = sd2506_write_disable();
|
||||||
if (ret != SD2506_OK) return ret;
|
if (ret != SD2506_OK) return ret;
|
||||||
|
|
||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_clear_alarm(void)
|
/*
|
||||||
{
|
* function: clear alarm interrupt flag
|
||||||
int ret;
|
* param: none
|
||||||
uint8_t val;
|
* return: 0=OK, -2=I2C error
|
||||||
|
* note: reading CTR1 clears INTAF
|
||||||
|
*/
|
||||||
|
int sd2506_clear_alarm(void) {
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t val = 0;
|
||||||
|
|
||||||
/* 读取 CTR1, ARST=1 时自动清除 INTAF */
|
/* 读取 CTR1, ARST=1 时自动清<EFBFBD>?INTAF */
|
||||||
ret = sd2506_read_reg(SD2506_REG_CTR1, &val);
|
ret = sd2506_read_reg(SD2506_REG_CTR1, &val);
|
||||||
if (ret != SD2506_OK) {
|
if (ret != SD2506_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -371,11 +439,16 @@ int sd2506_clear_alarm(void)
|
|||||||
return SD2506_OK;
|
return SD2506_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd2506_read_ctr1(uint8_t *val)
|
/*
|
||||||
{
|
* function: read control register 1
|
||||||
if (val == NULL) {
|
* param: p_val - output value
|
||||||
|
* return: 0=OK, -2=I2C error
|
||||||
|
*/
|
||||||
|
int sd2506_read_ctr1(uint8_t *p_val) {
|
||||||
|
if (p_val == NULL) {
|
||||||
return SD2506_ERROR;
|
return SD2506_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd2506_read_reg(SD2506_REG_CTR1, val);
|
return sd2506_read_reg(SD2506_REG_CTR1, p_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ int sd2506_init(void);
|
|||||||
* 3. 关闭写保护
|
* 3. 关闭写保护
|
||||||
* 注意:不可单独写某一个时间寄存器
|
* 注意:不可单独写某一个时间寄存器
|
||||||
*/
|
*/
|
||||||
int sd2506_set_time(const sd2506_time_t *time);
|
int sd2506_set_time(const sd2506_time_t *p_time);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取 RTC 时间日期
|
* 函数功能:读取 RTC 时间日期
|
||||||
@@ -191,7 +191,7 @@ int sd2506_set_time(const sd2506_time_t *time);
|
|||||||
* 2. BCD 转十进制
|
* 2. BCD 转十进制
|
||||||
* 3. 屏蔽小时 bit7 (12/24标志位)
|
* 3. 屏蔽小时 bit7 (12/24标志位)
|
||||||
*/
|
*/
|
||||||
int sd2506_get_time(sd2506_time_t *time);
|
int sd2506_get_time(sd2506_time_t *p_time);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取芯片内部温度
|
* 函数功能:读取芯片内部温度
|
||||||
@@ -200,7 +200,7 @@ int sd2506_get_time(sd2506_time_t *time);
|
|||||||
* 限定条件:sd2506_init() 已调用
|
* 限定条件:sd2506_init() 已调用
|
||||||
* 函数说明:读取 16H 寄存器,bit7 为符号位,范围 -40~+85
|
* 函数说明:读取 16H 寄存器,bit7 为符号位,范围 -40~+85
|
||||||
*/
|
*/
|
||||||
int sd2506_get_temperature(int8_t *temp);
|
int sd2506_get_temperature(int8_t *p_temp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取电池电压 (毫伏)
|
* 函数功能:读取电池电压 (毫伏)
|
||||||
@@ -210,7 +210,7 @@ int sd2506_get_temperature(int8_t *temp);
|
|||||||
* 函数说明:1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL)
|
* 函数说明:1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL)
|
||||||
* 2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V)
|
* 2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V)
|
||||||
*/
|
*/
|
||||||
int sd2506_get_battery_voltage(uint16_t *voltage);
|
int sd2506_get_battery_voltage(uint16_t *p_voltage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取芯片 8 字节 ID
|
* 函数功能:读取芯片 8 字节 ID
|
||||||
@@ -219,7 +219,7 @@ int sd2506_get_battery_voltage(uint16_t *voltage);
|
|||||||
* 限定条件:sd2506_init() 已调用
|
* 限定条件:sd2506_init() 已调用
|
||||||
* 函数说明:读取 72H~79H 共 8 字节唯一 ID
|
* 函数说明:读取 72H~79H 共 8 字节唯一 ID
|
||||||
*/
|
*/
|
||||||
int sd2506_get_id(uint8_t id[8]);
|
int sd2506_get_id(uint8_t p_id[8]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取用户 SRAM 数据
|
* 函数功能:读取用户 SRAM 数据
|
||||||
@@ -230,7 +230,7 @@ int sd2506_get_id(uint8_t id[8]);
|
|||||||
* 限定条件:sd2506_init() 已调用
|
* 限定条件:sd2506_init() 已调用
|
||||||
* 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H
|
* 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H
|
||||||
*/
|
*/
|
||||||
int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len);
|
int sd2506_read_sram(uint8_t addr, uint8_t *p_buf, uint8_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:写入用户 SRAM 数据
|
* 函数功能:写入用户 SRAM 数据
|
||||||
@@ -242,7 +242,7 @@ int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len);
|
|||||||
* 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H
|
* 函数说明:SRAM 地址范围 0~69,对应寄存器 2CH~71H
|
||||||
* SRAM 无需开写保护即可写入
|
* SRAM 无需开写保护即可写入
|
||||||
*/
|
*/
|
||||||
int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len);
|
int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置报警中断
|
* 函数功能:设置报警中断
|
||||||
@@ -255,7 +255,7 @@ int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len);
|
|||||||
* 3. 使能报警中断 INTAE
|
* 3. 使能报警中断 INTAE
|
||||||
* 4. 关写保护
|
* 4. 关写保护
|
||||||
*/
|
*/
|
||||||
int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask);
|
int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:清除报警中断标志
|
* 函数功能:清除报警中断标志
|
||||||
@@ -271,7 +271,7 @@ int sd2506_clear_alarm(void);
|
|||||||
* 入口参数:val - 输出值指针
|
* 入口参数:val - 输出值指针
|
||||||
* 返回值:0 - 成功,-2 - I2C 通信错误
|
* 返回值:0 - 成功,-2 - I2C 通信错误
|
||||||
*/
|
*/
|
||||||
int sd2506_read_ctr1(uint8_t *val);
|
int sd2506_read_ctr1(uint8_t *p_val);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:BCD 码转十进制
|
* 函数功能:BCD 码转十进制
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* 模块名称:TPAFE5160 16位8通道同步采样ADC驱动
|
* 模块名称:TPAFE5160 16<EFBFBD>?通道同步采样ADC驱动
|
||||||
* 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口
|
* 模块功能:提<EFBFBD>?TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接<EFBFBD>? * 适用平台:STM32F407ZGT6,并<EFBC8C>?6位数据总线<E680BB>?GPIOG[15:0]
|
||||||
* 适用平台:STM32F407ZGT6,并行16位数据总线接 GPIOG[15:0]
|
* 作者:王建<EFBFBD>? * 创建日期<E697A5>?026-07-17
|
||||||
* 作者:王建锋
|
* 修改记录<EFBFBD>? * 2026-07-17 王建<E78E8B>? 创建初始版本,参<EFBC8C>?AD7606 并行驱动<E9A9B1>?TPAFE5160 手册
|
||||||
* 创建日期:2026-07-17
|
* 2026-07-17 王建<E78E8B>? 增加 EXTI 中断读取模式
|
||||||
* 修改记录:
|
|
||||||
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
|
|
||||||
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 头文件包含区 */
|
/* 头文件包含区 */
|
||||||
@@ -19,35 +16,31 @@
|
|||||||
#define DBG_TAG "[ADC]"
|
#define DBG_TAG "[ADC]"
|
||||||
#include "dbg_log.h"
|
#include "dbg_log.h"
|
||||||
|
|
||||||
/* ======================== 私有宏定义 ======================== */
|
/* ======================== 私有宏定<EFBFBD>?======================== */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 并行读取时序延时 (168MHz 主频,1 NOP ≈ 5.95ns)
|
* 并行读取时序延时 (168MHz 主频<EFBFBD>? NOP <EFBFBD>?5.95ns)
|
||||||
*
|
*
|
||||||
* TPAFE5160 并行时序要求 (VDRIVE > 2.7V):
|
* TPAFE5160 并行时序要求 (VDRIVE > 2.7V)<EFBFBD>? * t10 (RD 低脉<E4BD8E>? <20>?22ns
|
||||||
* t10 (RD 低脉宽) ≥ 22ns
|
* t11 (RD 高脉<EFBFBD>? <20>?10ns
|
||||||
* t11 (RD 高脉宽) ≥ 10ns
|
* t14 (数据访问时间) <20>?21ns (<28>?RD 下降沿算<E6B2BF>?
|
||||||
* t14 (数据访问时间) ≤ 21ns (从 RD 下降沿算起)
|
* t15 (数据保持时间) <EFBFBD>?6ns (<EFBFBD>?RD 下降沿算<EFBFBD>?
|
||||||
* t15 (数据保持时间) ≥ 6ns (从 RD 下降沿算起)
|
|
||||||
*
|
*
|
||||||
* GPIO 写操作本身约 1 个 AHB 周期 (~6ns),
|
* GPIO 写操作本身约 1 <EFBFBD>?AHB 周期 (~6ns)<EFBFBD>? * 加上端口延迟 (~12-18ns),实<EFBC8C>?RD 引脚翻转滞后<E6BB9E>?18-24ns<6E>? * 因此 NOP 延时只需覆盖数据建立时间即可<E58DB3>? */
|
||||||
* 加上端口延迟 (~12-18ns),实际 RD 引脚翻转滞后约 18-24ns。
|
#define TPAFE5160_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP()
|
||||||
* 因此 NOP 延时只需覆盖数据建立时间即可。
|
|
||||||
*/
|
|
||||||
#define TP_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP()
|
|
||||||
|
|
||||||
/* RD 低脉宽延时:GPIO写(~6ns) + 5NOP(~30ns) > 22ns */
|
/* RD 低脉宽延时:GPIO<EFBFBD>?~6ns) + 5NOP(~30ns) > 22ns */
|
||||||
#define TP_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TP_NOP_5(); } while (0)
|
#define TPAFE5160_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TPAFE5160_NOP_5(); } while (0)
|
||||||
|
|
||||||
/* RD 高脉宽延时:GPIO写(~6ns) + 3NOP(~18ns) > 10ns */
|
/* RD 高脉宽延时:GPIO<EFBFBD>?~6ns) + 3NOP(~18ns) > 10ns */
|
||||||
#define TP_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0)
|
#define TPAFE5160_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0)
|
||||||
|
|
||||||
/* CONVST 脉冲延时:上升沿前需保证低电平,5NOP 覆盖 t5 ≥ 20ns */
|
/* CONVST 脉冲延时:上升沿前需保证低电平,5NOP 覆盖 t5 <EFBFBD>?20ns */
|
||||||
#define TP_CONVST_PULSE() do { \
|
#define TPAFE5160_CONVST_PULSE() do { \
|
||||||
TPAFE5160_CONVST_LOW(); \
|
TPAFE5160_CONVST_LOW(); \
|
||||||
TP_NOP_5(); \
|
TPAFE5160_NOP_5(); \
|
||||||
TPAFE5160_CONVST_HIGH(); \
|
TPAFE5160_CONVST_HIGH(); \
|
||||||
TP_NOP_5(); \
|
TPAFE5160_NOP_5(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* ======================== 私有函数声明 ======================== */
|
/* ======================== 私有函数声明 ======================== */
|
||||||
@@ -59,22 +52,20 @@ static void tpafe5160_read_channels(uint8_t count, int16_t *buf);
|
|||||||
/*
|
/*
|
||||||
* 函数功能:初始化 TPAFE5160(设置过采样、等待就绪)
|
* 函数功能:初始化 TPAFE5160(设置过采样、等待就绪)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:0 - 成功,-2 - BUSY 超时
|
* 返回值:0 - 成功<EFBFBD>?2 - BUSY 超时
|
||||||
* 限定条件:CubeMX 已完成 GPIO 初始化
|
* 限定条件:CubeMX 已完<EFBFBD>?GPIO 初始<EFBFBD>? * 函数说明<E8AFB4>?. 设置过采样为无过采样 (000)
|
||||||
* 函数说明:1. 设置过采样为无过采样 (000)
|
|
||||||
* 2. 确保 RD 为高、CONVST 为低
|
* 2. 确保 RD 为高、CONVST 为低
|
||||||
* 3. 等待 BUSY 释放(转换空闲)
|
* 3. 等待 BUSY 释放(转换空闲)
|
||||||
*/
|
*/
|
||||||
int tpafe5160_init(void)
|
int tpafe5160_init(void) {
|
||||||
{
|
|
||||||
/* 设置默认过采样:无过采样 (OS[2:0] = 000) */
|
/* 设置默认过采样:无过采样 (OS[2:0] = 000) */
|
||||||
tpafe5160_set_os(TP_OS_NONE);
|
tpafe5160_set_os(TPAFE5160_OS_NONE);
|
||||||
|
|
||||||
/* 确保控制引脚处于空闲状态 */
|
/* 确保控制引脚处于空闲状<EFBFBD>?*/
|
||||||
TPAFE5160_RD_HIGH();
|
TPAFE5160_RD_HIGH();
|
||||||
TPAFE5160_CONVST_LOW();
|
TPAFE5160_CONVST_LOW();
|
||||||
|
|
||||||
/* 等待 BUSY 释放,确保上电后无残留转换 */
|
/* 等待 BUSY 释放,确保上电后无残留转<EFBFBD>?*/
|
||||||
int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
int ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
|
||||||
if (ret != TPAFE5160_OK) {
|
if (ret != TPAFE5160_OK) {
|
||||||
DBG_ERROR("Init wait BUSY timeout");
|
DBG_ERROR("Init wait BUSY timeout");
|
||||||
@@ -85,14 +76,10 @@ int tpafe5160_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:设置过采样率
|
* 函数功能:设置过采样<EFBFBD>? * 入口参数:os - 过采样率枚举<E69E9A>? tpafe5160_os_t
|
||||||
* 入口参数:os - 过采样率枚举值 tpafe5160_os_t
|
* 返回值:<EFBFBD>? * 限定条件:GPIO 已初始化
|
||||||
* 返回值:无
|
* 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一<E4B88B>?BUSY 下降沿锁存生<E5AD98>? */
|
||||||
* 限定条件:GPIO 已初始化
|
void tpafe5160_set_os(tpafe5160_os_t os) {
|
||||||
* 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次 BUSY 下降沿锁存生效
|
|
||||||
*/
|
|
||||||
void tpafe5160_set_os(tpafe5160_os_t os)
|
|
||||||
{
|
|
||||||
TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */
|
TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */
|
||||||
TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */
|
TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */
|
||||||
TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */
|
TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */
|
||||||
@@ -101,27 +88,22 @@ void tpafe5160_set_os(tpafe5160_os_t os)
|
|||||||
/*
|
/*
|
||||||
* 函数功能:启动一次转换(CONVST 上升沿触发)
|
* 函数功能:启动一次转换(CONVST 上升沿触发)
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:无
|
* 返回值:<EFBFBD>? * 限定条件:GPIO 已初始化
|
||||||
* 限定条件:GPIO 已初始化
|
* 函数说明:产<EFBFBD>?CONVST 脉冲上升沿,启动全部8通道同步采样与转<E4B88E>? */
|
||||||
* 函数说明:产生 CONVST 脉冲上升沿,启动全部8通道同步采样与转换
|
void tpafe5160_start_conv(void) {
|
||||||
*/
|
TPAFE5160_CONVST_PULSE();
|
||||||
void tpafe5160_start_conv(void)
|
|
||||||
{
|
|
||||||
TP_CONVST_PULSE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:等待转换完成
|
|
||||||
* 入口参数:timeout_ms - 超时时间 uint32_t > 0
|
* 函数功能:等待转换完<E68DA2>? * 入口参数:timeout_ms - 超时时间 uint32_t > 0
|
||||||
* 返回值:0 - 转换完成,-2 - 超时
|
* 返回值:0 - 转换完成<EFBFBD>?2 - 超时
|
||||||
* 限定条件:已调用 tpafe5160_start_conv()
|
* 限定条件:已调用 tpafe5160_start_conv()
|
||||||
* 函数说明:轮询 BUSY 引脚等待下降沿
|
* 函数说明:轮<EFBFBD>?BUSY 引脚等待下降<EFBFBD>? */
|
||||||
*/
|
int tpafe5160_wait_busy(uint32_t timeout_ms) {
|
||||||
int tpafe5160_wait_busy(uint32_t timeout_ms)
|
|
||||||
{
|
|
||||||
uint32_t tick_start = HAL_GetTick();
|
uint32_t tick_start = HAL_GetTick();
|
||||||
|
|
||||||
/* 等待 BUSY 释放(低电平表示空闲) */
|
/* 等待 BUSY 释放(低电平表示空闲<EFBFBD>?*/
|
||||||
while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) {
|
while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) {
|
||||||
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
|
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
|
||||||
return TPAFE5160_BUSY_TIMEOUT;
|
return TPAFE5160_BUSY_TIMEOUT;
|
||||||
@@ -132,29 +114,26 @@ int tpafe5160_wait_busy(uint32_t timeout_ms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:查询当前是否正在转换
|
* 函数功能:查询当前是否正在转<EFBFBD>? * 入口参数:无
|
||||||
* 入口参数:无
|
* 返回值:1 - 正在转换<E8BDAC>? - 空闲
|
||||||
* 返回值:1 - 正在转换,0 - 空闲
|
|
||||||
* 限定条件:GPIO 已初始化
|
* 限定条件:GPIO 已初始化
|
||||||
* 函数说明:读取 BUSY 引脚电平
|
* 函数说明:读<EFBFBD>?BUSY 引脚电平
|
||||||
*/
|
*/
|
||||||
uint8_t tpafe5160_is_busy(void)
|
uint8_t tpafe5160_is_busy(void) {
|
||||||
{
|
|
||||||
return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0;
|
return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取全部8通道转换结果
|
* 函数功能:读取全<EFBFBD>?通道转换结果
|
||||||
* 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
|
* 入口参数:buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
|
||||||
* 返回值:0 - 成功,-2 - BUSY 超时
|
* 返回值:0 - 成功<EFBFBD>?2 - BUSY 超时
|
||||||
* 限定条件:GPIO 已初始化
|
* 限定条件:GPIO 已初始化
|
||||||
* 函数说明:1. 启动转换并等待 BUSY 释放
|
* 函数说明<EFBFBD>?. 启动转换并等<EFBFBD>?BUSY 释放
|
||||||
* 2. 连续8次拉低RD读取各通道数据
|
* 2. 连续8次拉低RD读取各通道数据
|
||||||
* 3. 通过 FRSTDATA 验证第一通道
|
* 3. 通过 FRSTDATA 验证第一通道
|
||||||
*/
|
*/
|
||||||
int tpafe5160_read_all(int16_t *buf)
|
int tpafe5160_read_all(int16_t *buf) {
|
||||||
{
|
int ret = 0;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* 启动转换 */
|
/* 启动转换 */
|
||||||
tpafe5160_start_conv();
|
tpafe5160_start_conv();
|
||||||
@@ -173,17 +152,15 @@ int tpafe5160_read_all(int16_t *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:读取指定通道的转换结果
|
* 函数功能:读取指定通道的转换结<EFBFBD>? * 入口参数:channel - 通道<E9809A>? uint8_t 0 - 7
|
||||||
* 入口参数:channel - 通道号 uint8_t 0 - 7
|
|
||||||
* value - 输出指针 int16_t* 不为 NULL
|
* value - 输出指针 int16_t* 不为 NULL
|
||||||
* 返回值:0 - 成功,-1 - 通道号无效,-2 - BUSY 超时
|
* 返回值:0 - 成功<EFBFBD>?1 - 通道号无效,-2 - BUSY 超时
|
||||||
* 限定条件:GPIO 已初始化
|
* 限定条件:GPIO 已初始化
|
||||||
* 函数说明:启动转换并等待完成后,连续读取至指定通道
|
* 函数说明:启动转换并等待完成后,连续读取至指定通道
|
||||||
*/
|
*/
|
||||||
int tpafe5160_read_channel(uint8_t channel, int16_t *value)
|
int tpafe5160_read_channel(uint8_t channel, int16_t *value) {
|
||||||
{
|
int ret = 0;
|
||||||
int ret;
|
int16_t buf[TPAFE5160_CH_NUM] = {0};
|
||||||
int16_t buf[TPAFE5160_CH_NUM];
|
|
||||||
|
|
||||||
if (channel >= TPAFE5160_CH_NUM || value == NULL) {
|
if (channel >= TPAFE5160_CH_NUM || value == NULL) {
|
||||||
return TPAFE5160_ERROR;
|
return TPAFE5160_ERROR;
|
||||||
@@ -199,29 +176,23 @@ int tpafe5160_read_channel(uint8_t channel, int16_t *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:原始ADC值转电压值
|
* 函数功能:原始ADC值转电压<EFBFBD>? * 入口参数:raw - ADC原始<E58E9F>? int16_t 有符号补<E58FB7>? * 返回值:电压<E794B5>? float 单位 V
|
||||||
* 入口参数:raw - ADC原始值 int16_t 有符号补码
|
|
||||||
* 返回值:电压值 float 单位 V
|
|
||||||
* 限定条件:无
|
* 限定条件:无
|
||||||
* 函数说明:±5V量程时 LSB = 10V / 65536 ≈ 152.59μV
|
* 函数说明:<EFBFBD>?V量程<EFBFBD>?LSB = 10V / 65536 <EFBFBD>?152.59μV
|
||||||
* ±10V量程时 LSB = 20V / 65536 ≈ 305.18μV
|
* ±10V量程<EFBFBD>?LSB = 20V / 65536 <EFBFBD>?305.18μV
|
||||||
* 硬件 RANGE 引脚接 GND,默认 ±5V 量程
|
* 硬件 RANGE 引脚<EFBFBD>?GND,默<EFBFBD>?±5V 量程
|
||||||
*/
|
*/
|
||||||
float tpafe5160_to_voltage(int16_t raw)
|
float tpafe5160_to_voltage(int16_t raw) {
|
||||||
{
|
/* RANGE <20>?GND <20>?±5V 量程,满量程 10V */
|
||||||
/* RANGE 接 GND → ±5V 量程,满量程 10V */
|
|
||||||
return (float)raw * (10.0f / 65536.0f);
|
return (float)raw * (10.0f / 65536.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:直接读取并行数据总线(不启动转换)
|
* 函数功能:直接读取并行数据总线(不启动转换<EFBFBD>? * 入口参数:无
|
||||||
* 入口参数:无
|
* 返回值:16位原始数<EFBFBD>? uint16_t
|
||||||
* 返回值:16位原始数据 uint16_t
|
* 限定条件:RD 为低<E4B8BA>?CS <20>?RD 已拉<E5B7B2>? * 函数说明:读<EFBC9A>?GPIOG->IDR <20>?6位,对应 DB[15:0]
|
||||||
* 限定条件:RD 为低或 CS 与 RD 已拉低
|
|
||||||
* 函数说明:读取 GPIOG->IDR 低16位,对应 DB[15:0]
|
|
||||||
*/
|
*/
|
||||||
uint16_t tpafe5160_read_bus(void)
|
uint16_t tpafe5160_read_bus(void) {
|
||||||
{
|
|
||||||
return TPAFE5160_READ_BUS();
|
return TPAFE5160_READ_BUS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,100 +200,82 @@ uint16_t tpafe5160_read_bus(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:通过 RD 脉冲连续读取多个通道数据
|
* 函数功能:通过 RD 脉冲连续读取多个通道数据
|
||||||
* 入口参数:count - 要读取的通道数 uint8_t 1 - 8
|
* 入口参数:count - 要读取的通道<EFBFBD>? uint8_t 1 - 8
|
||||||
* buf - 输出缓冲区 int16_t* 不为 NULL
|
* buf - 输出缓冲<EFBFBD>? int16_t* 不为 NULL
|
||||||
* 返回值:无
|
* 返回值:<EFBFBD>? * 限定条件:转换已完成(BUSY 为低),RD 初始为高
|
||||||
* 限定条件:转换已完成(BUSY 为低),RD 初始为高
|
* 函数说明:每<EFBFBD>?RD 下降沿输出一个通道数据,按通道1~8顺序输出
|
||||||
* 函数说明:每次 RD 下降沿输出一个通道数据,按通道1~8顺序输出
|
* DB[15:0] 直接<E79BB4>?GPIOG[15:0],通过 IDR 寄存器一次读<E6ACA1>? *
|
||||||
* DB[15:0] 直接接 GPIOG[15:0],通过 IDR 寄存器一次读取
|
* 时序关键<EFBFBD>?(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) 覆盖建立时间
|
||||||
*
|
|
||||||
* 时序关键点 (VDRIVE > 2.7V, 168MHz 主频):
|
|
||||||
* GPIO 写操作 ~6ns + 端口延迟 ~18ns → RD 引脚实际翻转约 24ns 后
|
|
||||||
* t14 数据建立 ≤ 21ns → 数据在 RD 下降沿后 21ns 内有效
|
|
||||||
* 5 个 NOP (~30ns) 覆盖建立时间
|
|
||||||
*/
|
*/
|
||||||
static void tpafe5160_read_channels(uint8_t count, int16_t *buf)
|
static void tpafe5160_read_channels(uint8_t count, int16_t *buf) {
|
||||||
{
|
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
/* RD 下降沿:ADC 输出当前通道数据到 DB[15:0] */
|
/* RD 下降沿:ADC 输出当前通道数据<EFBFBD>?DB[15:0] */
|
||||||
TP_RD_LOW_DLY();
|
TPAFE5160_RD_LOW_DLY();
|
||||||
|
|
||||||
/* 读取16位并行数据 */
|
/* 读取16位并行数<EFBFBD>?*/
|
||||||
buf[i] = (int16_t)TPAFE5160_READ_BUS();
|
buf[i] = (int16_t)TPAFE5160_READ_BUS();
|
||||||
|
|
||||||
/* RD 上升沿:准备下一通道 */
|
/* RD 上升沿:准备下一通道 */
|
||||||
TP_RD_HIGH_DLY();
|
TPAFE5160_RD_HIGH_DLY();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================== 中断模式实现 ======================== */
|
/* ======================== 中断模式实现 ======================== */
|
||||||
|
|
||||||
/* 双缓冲区:ISR 写 s_buf_b,主循环读 s_buf_a */
|
/* 双缓冲区:ISR <EFBFBD>?s_buf_b,主循环<EFBFBD>?s_buf_a */
|
||||||
static int16_t s_buf_a[TPAFE5160_CH_NUM];
|
static int16_t s_buf_a[TPAFE5160_CH_NUM];
|
||||||
static int16_t s_buf_b[TPAFE5160_CH_NUM];
|
static int16_t s_buf_b[TPAFE5160_CH_NUM];
|
||||||
static volatile uint8_t s_ready = 0;
|
static volatile uint8_t s_ready = 0;
|
||||||
static volatile uint8_t s_buf_sel = 0; /* 0 = 写 B / 读 A, 1 = 写 A / 读 B */
|
static volatile uint8_t s_buf_sel = 0; /* 0 = <EFBFBD>?B / <EFBFBD>?A, 1 = <EFBFBD>?A / <EFBFBD>?B */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:使能 BUSY EXTI 中断(运行时重使能用)
|
* 函数功能:使<EFBFBD>?BUSY EXTI 中断(运行时重使能用<EFBFBD>? * 入口参数:无
|
||||||
* 入口参数:无
|
* 返回值:<EFBFBD>? * 限定条件:CubeMX 已完<E5B7B2>?GPIO <20>?NVIC 配置
|
||||||
* 返回值:无
|
* 函数说明:正常启动流程无需调用,仅<EFBFBD>?irq_disable() 后需要重新使能时使用
|
||||||
* 限定条件:CubeMX 已完成 GPIO 和 NVIC 配置
|
|
||||||
* 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用
|
|
||||||
*/
|
*/
|
||||||
void tpafe5160_irq_enable(void)
|
void tpafe5160_irq_enable(void) {
|
||||||
{
|
|
||||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:关闭 BUSY EXTI 中断
|
* 函数功能:关<EFBFBD>?BUSY EXTI 中断
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:无
|
* 返回值:<EFBFBD>? * 限定条件:已调用 tpafe5160_irq_enable()
|
||||||
* 限定条件:已调用 tpafe5160_irq_enable()
|
|
||||||
* 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定
|
* 函数说明:仅禁用 NVIC 中断,GPIO 配置保持 CubeMX 设定
|
||||||
*/
|
*/
|
||||||
void tpafe5160_irq_disable(void)
|
void tpafe5160_irq_disable(void) {
|
||||||
{
|
|
||||||
HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
|
HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:启动转换(中断模式)
|
* 函数功能:启动转换(中断模式<EFBFBD>? * 入口参数:无
|
||||||
* 入口参数:无
|
* 返回值:<EFBFBD>? * 限定条件:已调用 tpafe5160_irq_enable()
|
||||||
* 返回值:无
|
* 函数说明:产<EFBFBD>?CONVST 脉冲,转换完成后<E68890>?EXTI 中断自动读取 8 通道数据
|
||||||
* 限定条件:已调用 tpafe5160_irq_enable()
|
|
||||||
* 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据
|
|
||||||
*/
|
*/
|
||||||
void tpafe5160_start_conv_irq(void)
|
void tpafe5160_start_conv_irq(void) {
|
||||||
{
|
|
||||||
s_ready = 0;
|
s_ready = 0;
|
||||||
TP_CONVST_PULSE();
|
TPAFE5160_CONVST_PULSE();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:检查是否有新的转换数据
|
* 函数功能:检查是否有新的转换数据
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:1 - 数据就绪,0 - 无新数据
|
* 返回值:1 - 数据就绪<EFBFBD>? - 无新数据
|
||||||
* 限定条件:中断模式已启用
|
* 限定条件:中断模式已启用
|
||||||
* 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除
|
* 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除
|
||||||
*/
|
*/
|
||||||
uint8_t tpafe5160_data_ready(void)
|
uint8_t tpafe5160_data_ready(void) {
|
||||||
{
|
|
||||||
return s_ready;
|
return s_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:清除数据就绪标志
|
* 函数功能:清除数据就绪标<EFBFBD>? * 入口参数:无
|
||||||
* 入口参数:无
|
* 返回值:<EFBFBD>? * 限定条件:中断模式已启用
|
||||||
* 返回值:无
|
|
||||||
* 限定条件:中断模式已启用
|
|
||||||
* 函数说明:主循环处理完数据后调用
|
* 函数说明:主循环处理完数据后调用
|
||||||
*/
|
*/
|
||||||
void tpafe5160_clear_ready(void)
|
void tpafe5160_clear_ready(void) {
|
||||||
{
|
|
||||||
s_ready = 0;
|
s_ready = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,23 +283,16 @@ void tpafe5160_clear_ready(void)
|
|||||||
* 函数功能:获取数据缓冲区指针
|
* 函数功能:获取数据缓冲区指针
|
||||||
* 入口参数:无
|
* 入口参数:无
|
||||||
* 返回值:int16_t[8] 数据缓冲区的 const 指针
|
* 返回值:int16_t[8] 数据缓冲区的 const 指针
|
||||||
* 限定条件:tpafe5160_data_ready() 返回 1 时调用
|
* 限定条件:tpafe5160_data_ready() 返回 1 时调<EFBFBD>? * 函数说明:双缓冲切换,ISR 写另一个缓冲区,主循环安全读取当前缓冲<E7BC93>? */
|
||||||
* 函数说明:双缓冲切换,ISR 写另一个缓冲区,主循环安全读取当前缓冲区
|
const int16_t* tpafe5160_get_buf(void) {
|
||||||
*/
|
|
||||||
const int16_t* tpafe5160_get_buf(void)
|
|
||||||
{
|
|
||||||
return (s_buf_sel == 0) ? s_buf_a : s_buf_b;
|
return (s_buf_sel == 0) ? s_buf_a : s_buf_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:BUSY 下降沿 EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用)
|
* 函数功能:BUSY 下降<EFBFBD>?EXTI 处理(由 HAL_GPIO_EXTI_Callback 调用<EFBFBD>? * 入口参数:GPIO_Pin - 触发中断的引脚号
|
||||||
* 入口参数:GPIO_Pin - 触发中断的引脚号
|
* 返回值:<EFBFBD>? * 限定条件:BUSY EXTI 已使<E5B7B2>? * 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时<E88097>?0.5µs (168MHz)
|
||||||
* 返回值:无
|
|
||||||
* 限定条件:BUSY EXTI 已使能
|
|
||||||
* 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz)
|
|
||||||
*/
|
*/
|
||||||
void tpafe5160_exti_handler(uint16_t GPIO_Pin)
|
void tpafe5160_exti_handler(uint16_t GPIO_Pin) {
|
||||||
{
|
|
||||||
if (GPIO_Pin != TP_BUSY_Pin) {
|
if (GPIO_Pin != TP_BUSY_Pin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -357,9 +303,9 @@ void tpafe5160_exti_handler(uint16_t GPIO_Pin)
|
|||||||
/* 连续读取8个通道,约 0.5µs @ 168MHz */
|
/* 连续读取8个通道,约 0.5µs @ 168MHz */
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < TPAFE5160_CH_NUM; i++) {
|
for (i = 0; i < TPAFE5160_CH_NUM; i++) {
|
||||||
TP_RD_LOW_DLY();
|
TPAFE5160_RD_LOW_DLY();
|
||||||
p_wr[i] = (int16_t)TPAFE5160_READ_BUS();
|
p_wr[i] = (int16_t)TPAFE5160_READ_BUS();
|
||||||
TP_RD_HIGH_DLY();
|
TPAFE5160_RD_HIGH_DLY();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 切换缓冲区并标记就绪 */
|
/* 切换缓冲区并标记就绪 */
|
||||||
|
|||||||
@@ -48,20 +48,20 @@ extern "C" {
|
|||||||
|
|
||||||
/* 过采样率枚举 (OS[2:0] 编码,OS2为MSB, OS0为LSB) */
|
/* 过采样率枚举 (OS[2:0] 编码,OS2为MSB, OS0为LSB) */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TP_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */
|
TPAFE5160_OS_NONE = 0, /* 000 — 无过采样,350 kSPS */
|
||||||
TP_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */
|
TPAFE5160_OS_X2 = 1, /* 001 — 2倍过采样,175 kSPS */
|
||||||
TP_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */
|
TPAFE5160_OS_X4 = 2, /* 010 — 4倍过采样,87.5 kSPS */
|
||||||
TP_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */
|
TPAFE5160_OS_X8 = 3, /* 011 — 8倍过采样,43.75 kSPS */
|
||||||
TP_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */
|
TPAFE5160_OS_X16 = 4, /* 100 — 16倍过采样,21.875 kSPS */
|
||||||
TP_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */
|
TPAFE5160_OS_X32 = 5, /* 101 — 32倍过采样,10.94 kSPS */
|
||||||
TP_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */
|
TPAFE5160_OS_X64 = 6, /* 110 — 64倍过采样,5.47 kSPS */
|
||||||
TP_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */
|
TPAFE5160_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz),350 kSPS */
|
||||||
} tpafe5160_os_t;
|
} tpafe5160_os_t;
|
||||||
|
|
||||||
/* 输入量程枚举 */
|
/* 输入量程枚举 */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TP_RANGE_5V = 0, /* ±5V (RANGE = LOW) */
|
TPAFE5160_RANGE_5V = 0, /* ±5V (RANGE = LOW) */
|
||||||
TP_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */
|
TPAFE5160_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */
|
||||||
} tpafe5160_range_t;
|
} tpafe5160_range_t;
|
||||||
|
|
||||||
/* 返回值定义 */
|
/* 返回值定义 */
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
* - 两者都不定义:所有 DBG_* 宏为空操作(release 版本)
|
* - 两者都不定义:所有 DBG_* 宏为空操作(release 版本)
|
||||||
*
|
*
|
||||||
* 用户可在本文件中直接控制,也可在编译器预定义中覆盖
|
* 用户可在本文件中直接控制,也可在编译器预定义中覆盖
|
||||||
|
* 适用平台:所有 BSP 驱动
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
* 2026-07-18 王建锋 创建初始版本
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DBG_CFG_H
|
#ifndef __DBG_CFG_H
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
* #define DBG_TAG "[CH395]"
|
* #define DBG_TAG "[CH395]"
|
||||||
* #include "dbg_log.h"
|
* #include "dbg_log.h"
|
||||||
* 适用平台:所有 BSP 驱动
|
* 适用平台:所有 BSP 驱动
|
||||||
|
* 作者:王建锋
|
||||||
|
* 创建日期:2026-07-18
|
||||||
|
* 修改记录:
|
||||||
|
* 2026-07-18 王建锋 创建初始版本
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DBG_LOG_H
|
#ifndef __DBG_LOG_H
|
||||||
@@ -49,14 +53,14 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define DBG_ERROR(fmt, ...) do { \
|
#define DBG_ERROR(fmt, ...) do { \
|
||||||
DBG_PRINT("[ERR]" DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
DBG_PRINT("[ERR]" DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DBG_INFO - 信息输出,受 DBG_ENABLE 控制
|
* DBG_INFO - 信息输出,受 DBG_ENABLE 控制
|
||||||
*/
|
*/
|
||||||
#define DBG_INFO(fmt, ...) do { \
|
#define DBG_INFO(fmt, ...) do { \
|
||||||
DBG_PRINT(DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
DBG_PRINT(DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE 同时定义
|
* DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE 同时定义
|
||||||
@@ -64,7 +68,7 @@ extern "C" {
|
|||||||
#ifdef DBG_DEBUG_ENABLE
|
#ifdef DBG_DEBUG_ENABLE
|
||||||
#define DBG_DEBUG(fmt, ...) do { \
|
#define DBG_DEBUG(fmt, ...) do { \
|
||||||
DBG_PRINT(DBG_TAG "(%s:%d) " fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); \
|
DBG_PRINT(DBG_TAG "(%s:%d) " fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); \
|
||||||
} while(0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define DBG_DEBUG(fmt, ...)
|
#define DBG_DEBUG(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -340,7 +340,7 @@
|
|||||||
<MiscControls></MiscControls>
|
<MiscControls></MiscControls>
|
||||||
<Define>USE_HAL_DRIVER,STM32F407xx</Define>
|
<Define>USE_HAL_DRIVER,STM32F407xx</Define>
|
||||||
<Undefine></Undefine>
|
<Undefine></Undefine>
|
||||||
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485;../Drivers/BSP/NET;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F</IncludePath>
|
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc;../Drivers/BSP/TPAFE5160;../Drivers/BSP/SD2506;../Drivers/BSP/RS485;../Drivers/BSP/NET;../App;../App/task;../App/util;../Middlewares/Third_Party/FreeRTOS/Source/include;../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2;../Middlewares/Third_Party/FreeRTOS/Source/portable/RVDS/ARM_CM4F</IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
<Aads>
|
||||||
@@ -752,6 +752,46 @@
|
|||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<GroupName>App</GroupName>
|
||||||
|
<Files>
|
||||||
|
<File>
|
||||||
|
<FileName>app_main.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\app_main.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>sys_time.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\sys_time.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>net_task.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\task\net_task.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>adc_task.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\task\adc_task.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>rs485_task.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\task\rs485_task.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>ringbuf.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\util\ringbuf.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>crc.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\App\util\crc.c</FilePath>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
<GroupName>Drivers/STM32F4xx_HAL_Driver</GroupName>
|
<GroupName>Drivers/STM32F4xx_HAL_Driver</GroupName>
|
||||||
<Files>
|
<Files>
|
||||||
|
|||||||
@@ -1,4 +1,71 @@
|
|||||||
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
||||||
Build target 'STM32F407-Demo'
|
Rebuild target 'STM32F407-Demo'
|
||||||
|
assembling startup_stm32f407xx.s...
|
||||||
|
compiling net_task.c...
|
||||||
|
compiling app_main.c...
|
||||||
|
compiling crc.c...
|
||||||
|
compiling ringbuf.c...
|
||||||
|
compiling dma.c...
|
||||||
|
compiling stm32f4xx_hal_flash_ex.c...
|
||||||
|
compiling sys_time.c...
|
||||||
|
compiling stm32f4xx_hal_msp.c...
|
||||||
|
compiling stm32f4xx_hal_timebase_tim.c...
|
||||||
|
compiling stm32f4xx_hal_flash_ramfunc.c...
|
||||||
|
compiling i2c.c...
|
||||||
|
compiling spi.c...
|
||||||
|
compiling gpio.c...
|
||||||
|
compiling stm32f4xx_it.c...
|
||||||
|
compiling stm32f4xx_hal_rcc_ex.c...
|
||||||
|
compiling usart.c...
|
||||||
|
compiling stm32f4xx_hal_dma.c...
|
||||||
|
compiling stm32f4xx_hal_gpio.c...
|
||||||
|
compiling freertos.c...
|
||||||
|
compiling stm32f4xx_hal_flash.c...
|
||||||
|
compiling rs485_task.c...
|
||||||
|
compiling stm32f4xx_hal_rcc.c...
|
||||||
|
compiling adc_task.c...
|
||||||
|
compiling main.c...
|
||||||
|
compiling stm32f4xx_hal_dma_ex.c...
|
||||||
|
compiling stm32f4xx_hal_tim_ex.c...
|
||||||
|
compiling stm32f4xx_hal_tim.c...
|
||||||
|
compiling fdb.c...
|
||||||
|
compiling fdb_utils.c...
|
||||||
|
compiling fdb_tsdb.c...
|
||||||
|
compiling fal.c...
|
||||||
|
compiling fdb_kvdb.c...
|
||||||
|
compiling fal_flash.c...
|
||||||
|
compiling croutine.c...
|
||||||
|
compiling fal_partition.c...
|
||||||
|
compiling list.c...
|
||||||
|
compiling event_groups.c...
|
||||||
|
compiling stream_buffer.c...
|
||||||
|
compiling queue.c...
|
||||||
|
compiling timers.c...
|
||||||
|
compiling tasks.c...
|
||||||
|
compiling port.c...
|
||||||
|
compiling heap_4.c...
|
||||||
|
compiling stm32f4xx_hal_pwr.c...
|
||||||
|
compiling stm32f4xx_hal_i2c_ex.c...
|
||||||
|
compiling stm32f4xx_hal_pwr_ex.c...
|
||||||
|
compiling system_stm32f4xx.c...
|
||||||
|
compiling stm32f4xx_hal_exti.c...
|
||||||
|
compiling fal_flash_gd5f2gq5ue.c...
|
||||||
|
compiling stm32f4xx_hal.c...
|
||||||
|
compiling stm32f4xx_hal_cortex.c...
|
||||||
|
compiling rs485.c...
|
||||||
|
compiling sd2506.c...
|
||||||
|
compiling tpafe5160.c...
|
||||||
|
compiling net_select.c...
|
||||||
|
compiling ch395f_test.c...
|
||||||
|
compiling ch395f.c...
|
||||||
|
compiling gd5f2gq5ue.c...
|
||||||
|
compiling stm32f4xx_hal_spi.c...
|
||||||
|
compiling net_socket.c...
|
||||||
|
compiling stm32f4xx_hal_uart.c...
|
||||||
|
compiling stm32f4xx_hal_i2c.c...
|
||||||
|
compiling cmsis_os2.c...
|
||||||
|
linking...
|
||||||
|
Program Size: Code=29372 RO-data=888 RW-data=180 ZI-data=41420
|
||||||
|
FromELF: creating hex file...
|
||||||
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
||||||
Build Time Elapsed: 00:00:00
|
Build Time Elapsed: 00:00:16
|
||||||
|
|||||||
@@ -25,10 +25,8 @@
|
|||||||
|
|
||||||
/* Private includes ----------------------------------------------------------*/
|
/* Private includes ----------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
#include "net_socket.h"
|
#include "net_task.h"
|
||||||
#include "net_select.h"
|
|
||||||
#include "ch395f.h"
|
#include "ch395f.h"
|
||||||
#include "ch395f_test.h"
|
|
||||||
#include "dbg_log.h"
|
#include "dbg_log.h"
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
@@ -49,9 +47,7 @@
|
|||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
/* Private variables ---------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Variables */
|
/* USER CODE BEGIN Variables */
|
||||||
#ifdef ENABLE_PHASE4_TESTS
|
|
||||||
static uint8_t s_net_buf[1500];
|
|
||||||
#endif
|
|
||||||
/* USER CODE END Variables */
|
/* USER CODE END Variables */
|
||||||
/* Definitions for defaultTask */
|
/* Definitions for defaultTask */
|
||||||
osThreadId_t defaultTaskHandle;
|
osThreadId_t defaultTaskHandle;
|
||||||
@@ -64,7 +60,7 @@ const osThreadAttr_t defaultTask_attributes = {
|
|||||||
osThreadId_t netTaskHandle;
|
osThreadId_t netTaskHandle;
|
||||||
const osThreadAttr_t netTask_attributes = {
|
const osThreadAttr_t netTask_attributes = {
|
||||||
.name = "netTask",
|
.name = "netTask",
|
||||||
.stack_size = 1024 * 4,
|
.stack_size = 1024 * 8,
|
||||||
.priority = (osPriority_t) osPriorityNormal,
|
.priority = (osPriority_t) osPriorityNormal,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,40 +145,7 @@ void StartDefaultTask(void *argument)
|
|||||||
void StartNetTask(void *argument)
|
void StartNetTask(void *argument)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN StartNetTask */
|
/* USER CODE BEGIN StartNetTask */
|
||||||
osDelay(2000);
|
net_task_func(argument);
|
||||||
|
|
||||||
DBG_INFO("netTask: started");
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
net_poll();
|
|
||||||
|
|
||||||
#ifdef ENABLE_PHASE4_TESTS
|
|
||||||
for (int i = 1; i < 8; i++)
|
|
||||||
{
|
|
||||||
net_sock_t *sk = net_get_sock(i);
|
|
||||||
if (sk == NULL || !sk->in_use || sk->state != NET_SOCK_STATE_ESTABLISHED)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT);
|
|
||||||
if (n > 0)
|
|
||||||
{
|
|
||||||
net_send(i, s_net_buf, n, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_PHASE5_TESTS
|
|
||||||
ch395f_phase5_tests();
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_PHASE7_TESTS
|
|
||||||
ch395f_phase7_tests();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
osDelay(10);
|
|
||||||
}
|
|
||||||
/* USER CODE END StartNetTask */
|
/* USER CODE END StartNetTask */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -525,40 +525,69 @@ def udp_echo_server_test(args):
|
|||||||
|
|
||||||
# ==================== 压力测试 ====================
|
# ==================== 压力测试 ====================
|
||||||
|
|
||||||
def stress_test_thread(client_id, args, results):
|
def stress_test_thread(client_id, args, results, barrier):
|
||||||
"""压力测试线程"""
|
"""压力测试线程"""
|
||||||
thread_name = f"Client-{client_id}"
|
thread_name = f"Client-{client_id}"
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.settimeout(10)
|
sock.settimeout(5)
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
t0 = time.time()
|
||||||
sock.connect((args.ip, args.port))
|
sock.connect((args.ip, args.port))
|
||||||
log_success(f"[{thread_name}] 连接成功")
|
local = sock.getsockname()
|
||||||
|
remote = sock.getpeername()
|
||||||
|
t_conn = (time.time() - t0) * 1000
|
||||||
|
log_success(f"[{thread_name}] 连接成功 "
|
||||||
|
f"(local={local[0]}:{local[1]}, "
|
||||||
|
f"remote={remote[0]}:{remote[1]}, "
|
||||||
|
f"{t_conn:.0f}ms)")
|
||||||
|
|
||||||
|
barrier.wait()
|
||||||
|
|
||||||
success_count = 0
|
success_count = 0
|
||||||
fail_count = 0
|
fail_count = 0
|
||||||
|
|
||||||
for i in range(args.count):
|
for i in range(args.count):
|
||||||
try:
|
try:
|
||||||
# 发送
|
|
||||||
test_data = f"T{client_id:02d}_{i:04d}".encode()
|
test_data = f"T{client_id:02d}_{i:04d}".encode()
|
||||||
|
t_send = time.time()
|
||||||
sock.send(test_data)
|
sock.send(test_data)
|
||||||
|
|
||||||
# 接收
|
|
||||||
data = sock.recv(100)
|
data = sock.recv(100)
|
||||||
if data and data == test_data:
|
t_rtt = (time.time() - t_send) * 1000
|
||||||
|
if data:
|
||||||
|
if data == test_data:
|
||||||
success_count += 1
|
success_count += 1
|
||||||
|
log_info(f"[{thread_name}] #{i}: OK ({t_rtt:.0f}ms)")
|
||||||
else:
|
else:
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
|
log_warn(f"[{thread_name}] #{i}: MISMATCH "
|
||||||
|
f"want={len(test_data)}B/{test_data[:20].decode(errors='replace')!r} "
|
||||||
|
f"got={len(data)}B/{data[:20].decode(errors='replace')!r}"
|
||||||
|
f" ({t_rtt:.0f}ms)")
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
log_warn(f"[{thread_name}] #{i}: recv returned empty ({t_rtt:.0f}ms)")
|
||||||
|
|
||||||
|
except socket.timeout:
|
||||||
|
fail_count += 1
|
||||||
|
t_elapsed = (time.time() - t_send) * 1000
|
||||||
|
log_error(f"[{thread_name}] #{i}: TIMEOUT ({t_elapsed:.0f}ms)")
|
||||||
|
except ConnectionResetError:
|
||||||
|
fail_count += 1
|
||||||
|
t_elapsed = (time.time() - t_send) * 1000
|
||||||
|
log_error(f"[{thread_name}] #{i}: RESET by peer ({t_elapsed:.0f}ms)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
|
t_elapsed = (time.time() - t_send) * 1000
|
||||||
|
log_error(f"[{thread_name}] #{i}: {type(e).__name__}: {e} ({t_elapsed:.0f}ms)")
|
||||||
|
|
||||||
results[client_id] = (success_count, fail_count)
|
results[client_id] = (success_count, fail_count)
|
||||||
log_info(f"[{thread_name}] 完成: 成功 {success_count}, 失败 {fail_count}")
|
t_total = (time.time() - t0) * 1000
|
||||||
|
log_info(f"[{thread_name}] 完成: 成功 {success_count}, 失败 {fail_count} ({t_total:.0f}ms)")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_error(f"[{thread_name}] 错误: {e}")
|
log_error(f"[{thread_name}] 连接失败: {type(e).__name__}: {e}")
|
||||||
results[client_id] = (0, args.count)
|
results[client_id] = (0, args.count)
|
||||||
finally:
|
finally:
|
||||||
sock.close()
|
sock.close()
|
||||||
@@ -575,12 +604,13 @@ def stress_test(args):
|
|||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
threads = []
|
threads = []
|
||||||
|
barrier = threading.Barrier(num_clients)
|
||||||
|
|
||||||
# 创建并启动线程
|
# 创建并启动线程
|
||||||
for i in range(num_clients):
|
for i in range(num_clients):
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=stress_test_thread,
|
target=stress_test_thread,
|
||||||
args=(i, args, results)
|
args=(i, args, results, barrier)
|
||||||
)
|
)
|
||||||
threads.append(thread)
|
threads.append(thread)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user