关键芯片都驱动,且测试成功

This commit is contained in:
2026-07-18 16:09:06 +08:00
parent 3466c4c062
commit fe107ea9af
42 changed files with 16193 additions and 501 deletions

View File

@@ -493,6 +493,27 @@ void ch395f_set_phy(uint8_t phystat)
ch395f_spi_end();
}
/*
* 函数功能:使能/关闭 CH395 响应 PING
* 入口参数enable - 1 使能 PING 响应0 关闭
* 限定条件:芯片已初始化
* 函数说明:手册 5.37 CMD_PING_ENABLE默认关闭
*/
void ch395f_ping_enable(uint8_t enable)
{
/* 开始 SPI 事务 */
ch395f_spi_begin();
/* 发送 PING 使能命令 */
ch395f_write_cmd(CH395F_CMD_PING_ENABLE);
/* 发送使能标志 */
ch395f_write_data(enable);
/* 结束 SPI 事务 */
ch395f_spi_end();
}
/*
* 函数功能:启用/禁用 DHCP
* 入口参数enable - 1 启用0 禁用 uint8_t

View File

@@ -350,6 +350,14 @@ uint8_t ch395f_get_phy_status(void);
*/
void ch395f_set_phy(uint8_t phystat);
/*
* 函数功能:使能/关闭 CH395 响应 PING
* 入口参数enable - 1 使能 PING 响应0 关闭
* 限定条件:芯片已初始化
* 函数说明:手册 5.37 CMD_PING_ENABLE默认关闭
*/
void ch395f_ping_enable(uint8_t enable);
/*
* 函数声明区 - DHCP
*/

View File

@@ -1,35 +1,51 @@
/**
******************************************************************************
* @file fal_cfg.h
* @brief FAL 配置Flash 设备表 + 分区表
******************************************************************************
*/
#ifndef __FAL_CFG_H
#define __FAL_CFG_H
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
/*
* 模块名称FAL 配置
* 模块功能:定义 FAL Flash 设备表和分区表
* 适用平台STM32F407ZGT6
* 作者:王建锋
* 创建日期2026-07-16
* 修改记录:
* 2026-07-16 王建锋 创建初始版本
*/
#ifdef __cplusplus
extern "C" {
#endif
/* FAL 调试开关0-关闭1-开启 */
#define FAL_DEBUG 0
/* 启用分区表配置 */
#define FAL_PART_HAS_TABLE_CFG
/* ===================== Flash 设备表 ===================== */
/* ======================== Flash 设备表 ======================== */
extern const struct fal_flash_dev gd5f2gq5ue_flash;
#define FAL_FLASH_DEV_TABLE \
{ \
&gd5f2gq5ue_flash, \
#define FAL_FLASH_DEV_TABLE \
{ \
&gd5f2gq5ue_flash, \
}
/* ===================== 分区表 ===================== */
/* 分区名称 设备名称 偏移 大小 */
/* KVDB: 64MB @ 0 */
/* TSDB: 64MB @ 64MB */
/* ======================== 分区表 ======================== */
/*
* 分区名称 设备名称 偏移 大小
* KVDB: 64MB @ 0
* TSDB: 64MB @ 64MB
*/
#ifdef FAL_PART_HAS_TABLE_CFG
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \
}
#endif
#endif /* _FAL_CFG_H_ */
#ifdef __cplusplus
}
#endif
#endif /* __FAL_CFG_H */

View File

@@ -1,42 +1,80 @@
/**
******************************************************************************
* @file fal_flash_gd5f2gq5ue.c
* @brief FAL 端口GD5F2GQ5UE SPI NAND Flash 适配层
******************************************************************************
*/
/*
* 模块名称FAL Flash 设备适配
* 模块功能:将 GD5F2GQ5UE 驱动接口适配到 FAL 框架
* 适用平台STM32F407ZGT6
* 作者:王建锋
* 创建日期2026-07-16
* 修改记录:
* 2026-07-16 王建锋 创建初始版本
*/
/* 头文件包含区 */
#include "fal_def.h"
#include "gd5f2gq5ue.h"
/* ===================== FAL Flash 设备操作函数 ===================== */
/* ======================== FAL 操作函数适配 ======================== */
/*
* 函数功能Flash 设备初始化适配
* 入口参数:无
* 返回值0 - 成功,其他 - 错误码
* 限定条件SPI 和 GPIO 已由 CubeMX 初始化完成
* 函数说明:调用底层驱动的初始化函数
*/
static int gd5f_fal_init(void)
{
return gd5f2gq5ue_init();
}
static int gd5f_fal_read(long offset, uint8_t *buf, size_t size)
/*
* 函数功能Flash 读取适配
* 入口参数offset - 起始字节偏移 long
* p_buf - 数据缓冲区 uint8_t*
* size - 读取字节数 size_t
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f_fal_init() 已成功调用
* 函数说明:直接转发到底层驱动的读取函数
*/
static int gd5f_fal_read(long offset, uint8_t *p_buf, size_t size)
{
return gd5f2gq5ue_read(offset, buf, size);
return gd5f2gq5ue_read(offset, p_buf, size);
}
static int gd5f_fal_write(long offset, const uint8_t *buf, size_t size)
/*
* 函数功能Flash 写入适配
* 入口参数offset - 起始字节偏移 long
* p_buf - 数据缓冲区 const uint8_t*
* size - 写入字节数 size_t
* 返回值0 - 成功,其他 - 错误码
* 限定条件:目标区域已擦除
* 函数说明:直接转发到底层驱动的写入函数
*/
static int gd5f_fal_write(long offset, const uint8_t *p_buf, size_t size)
{
return gd5f2gq5ue_write(offset, buf, size);
return gd5f2gq5ue_write(offset, p_buf, size);
}
/*
* 函数功能Flash 擦除适配
* 入口参数offset - 起始字节偏移 long
* size - 擦除字节数 size_t
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f_fal_init() 已成功调用
* 函数说明:直接转发到底层驱动的擦除函数
*/
static int gd5f_fal_erase(long offset, size_t size)
{
return gd5f2gq5ue_erase(offset, size);
}
/* ===================== FAL Flash 设备定义 ===================== */
/* ======================== FAL Flash 设备定义 ======================== */
/* GD5F2GQ5UE FAL 设备实例总容量256MB块大小128KB */
const struct fal_flash_dev gd5f2gq5ue_flash = {
.name = "gd5f2gq5ue",
.addr = 0,
.len = GD5F_TOTAL_SIZE, /* 256MB */
.blk_size = GD5F_BLOCK_SIZE, /* 128KB */
.len = GD5F_TOTAL_SIZE,
.blk_size = GD5F_BLOCK_SIZE,
.ops = {
.init = gd5f_fal_init,
.read = gd5f_fal_read,

View File

@@ -1,20 +1,25 @@
/**
******************************************************************************
* @file fdb_cfg.h
* @brief FlashDB 配置文件
******************************************************************************
*/
#ifndef __FDB_CFG_H
#define __FDB_CFG_H
#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_
/*
* 模块名称FlashDB 配置
* 模块功能:配置 FlashDB 数据库功能开关和参数
* 适用平台STM32F407ZGT6
* 作者:王建锋
* 创建日期2026-07-16
* 修改记录:
* 2026-07-16 王建锋 创建初始版本
*/
#ifdef __cplusplus
extern "C" {
#endif
/* 启用 KVDB键值数据库 */
#define FDB_USING_KVDB
#ifdef FDB_USING_KVDB
/* 当 KVDB 版本号变化时自动更新到最新默认值 */
/* KVDB 版本号变化时自动更新到最新默认值(默认关闭) */
/* #define FDB_KV_AUTO_UPDATE */
#endif
/* 启用 TSDB时序数据库 */
#define FDB_USING_TSDB
@@ -22,11 +27,14 @@
/* 使用 FAL 存储模式(非文件模式) */
#define FDB_USING_FAL_MODE
/* Flash 写入粒度单位bit
* STM32F4 = 8字节可编程 */
#define FDB_WRITE_GRAN 8
/* Flash 写入粒度单位bitSTM32F4 字节可编程 = 8 */
#define FDB_WRITE_GRAN 8
/* 调试输出 */
#define FDB_DEBUG_ENABLE
/* 调试输出使能 */
/*#define FDB_DEBUG_ENABLE*/
#endif /* _FDB_CFG_H_ */
#ifdef __cplusplus
}
#endif
#endif /* __FDB_CFG_H */

View File

@@ -1,350 +1,450 @@
/**
******************************************************************************
* @file gd5f2gq5ue.c
* @brief GD5F2GQ5UE SPI NAND Flash 驱动实现
******************************************************************************
*/
/*
* 模块名称GD5F2GQ5UE SPI NAND Flash 驱动
* 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口
* 适用平台STM32F407ZGT6 + SPI1 硬件 SPI
* 作者:王建锋
* 创建日期2026-07-16
* 修改记录:
* 2026-07-16 王建锋 创建初始版本
* 2026-07-17 王建锋 切换硬件 SPI修正擦除地址参考 NuttX 驱动
*/
/* 头文件包含区 */
#include "gd5f2gq5ue.h"
#include <string.h>
/* 私有宏定义区 */
#define GD5F_SPI_TIMEOUT 100
/* 外部 SPI 句柄声明 */
extern SPI_HandleTypeDef hspi1;
/* ===================== 内部辅助函数 ===================== */
/* ======================== 私有函数声明 ======================== */
/**
* @brief SPI 发送/接收单字节
*/
static uint8_t gd5f_spi_xfer(uint8_t tx)
{
uint8_t rx;
HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 1, 100);
return rx;
}
static int gd5f_wait_busy(uint32_t timeout_ms);
static int gd5f_write_enable(void);
static int gd5f_read_status(uint8_t *p_status);
static int gd5f_page_read(uint32_t page_addr);
static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
size_t size);
static int gd5f_page_program(uint32_t page_addr, uint16_t column,
const uint8_t *p_buf, size_t size);
static int gd5f_set_feature(uint8_t addr, uint8_t data);
static int gd5f_block_erase(uint32_t block_addr);
/**
* @brief SPI 发送缓冲区
*/
static void gd5f_spi_tx(const uint8_t *buf, size_t len)
{
HAL_SPI_Transmit(&hspi1, (uint8_t *)buf, len, 100);
}
/* ======================== 私有函数定义 ======================== */
/**
* @brief SPI 接收缓冲区
*/
static void gd5f_spi_rx(uint8_t *buf, size_t len)
{
HAL_SPI_Receive(&hspi1, buf, len, 100);
}
/**
* @brief 等待操作完成OIP 位清零)
* @param timeout_ms: 超时时间(毫秒)
* @retval GD5F_OK 成功, GD5F_BUSY_TIMEOUT 超时
/*
* 函数功能:等待芯片操作完成(轮询 OIP 位)
* 入口参数timeout_ms - 超时时间 uint32_t > 0
* 返回值0 - 操作完成,-2 - 超时
* 限定条件SPI 已初始化
* 函数说明:循环读取状态寄存器直到 OIP 位清零或超时
*/
static int gd5f_wait_busy(uint32_t timeout_ms)
{
uint8_t cmd = GD5F_CMD_GET_FEATURE;
uint8_t addr = GD5F_REG_STATUS;
uint8_t status;
uint32_t tickstart = HAL_GetTick();
uint8_t status = 0;
uint32_t tick_start = HAL_GetTick();
while (1) {
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_tx(&addr, 1);
gd5f_spi_rx(&status, 1);
HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT);
HAL_SPI_Transmit(&hspi1, &addr, 1, GD5F_SPI_TIMEOUT);
HAL_SPI_Receive(&hspi1, &status, 1, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
if ((status & GD5F_STATUS_OIP) == 0) {
return GD5F_OK;
}
if ((HAL_GetTick() - tickstart) >= timeout_ms) {
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
return GD5F_BUSY_TIMEOUT;
}
}
}
/**
* @brief 写使能
/*
* 函数功能:发送写使能命令
* 入口参数:无
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明CS# 拉低后发送 06h 命令再拉高
*/
static int gd5f_write_enable(void)
{
uint8_t cmd = GD5F_CMD_WRITE_ENABLE;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 读取状态寄存器
/*
* 函数功能:读取状态寄存器
* 入口参数p_status - 状态值输出指针 uint8_t* 不为 NULL
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:发送 0Fh + C0h 地址后读取1字节状态值
*/
static int gd5f_read_status(uint8_t *status)
static int gd5f_read_status(uint8_t *p_status)
{
uint8_t cmd = GD5F_CMD_GET_FEATURE;
uint8_t addr = GD5F_REG_STATUS;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_tx(&addr, 1);
gd5f_spi_rx(status, 1);
HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT);
HAL_SPI_Transmit(&hspi1, &addr, 1, GD5F_SPI_TIMEOUT);
HAL_SPI_Receive(&hspi1, p_status, 1, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页读取到缓存Page Read to Cache
* @param page_addr: 页地址(行地址,包含 block + page
/*
* 函数功能:页读取(将数据从存储阵列加载到内部缓存
* 入口参数:page_addr - 页地址 uint32_t
* 返回值0 - 成功,其他 - 错误码
* 限定条件SPI 已初始化
* 函数说明:发送 13h + 3字节行地址等待 OIP 清零
*/
static int gd5f_page_read(uint32_t page_addr)
{
uint8_t cmd[4];
cmd[0] = GD5F_CMD_PAGE_READ;
cmd[1] = (page_addr >> 16) & 0xFF;
cmd[2] = (page_addr >> 8) & 0xFF;
cmd[3] = page_addr & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
return gd5f_wait_busy(100);
}
/**
* @brief 从缓存读取数据Read from Cache
* @param column: 列地址(页内偏移)
* @param buf: 数据缓冲区
* @param size: 读取字节数
/*
* 函数功能:从内部缓存读取数据
* 入口参数:column - 列地址(页内偏移) uint16_t 0 - 2047
* p_buf - 数据输出缓冲区 uint8_t* 不为 NULL
* size - 读取字节数 size_t > 0
* 返回值0 - 成功
* 限定条件:必须先调用 gd5f_page_read 完成数据加载
* 函数说明:发送 0Bh + 2字节列地址 +1字节 dummy 后读取数据
*/
static int gd5f_read_from_cache(uint16_t column, uint8_t *buf, size_t size)
static int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf,
size_t size)
{
uint8_t cmd[5];
uint8_t cmd[4];
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
cmd[1] = (column >> 8) & 0xFF;
cmd[2] = column & 0xFF;
cmd[3] = 0x00; /* dummy byte */
cmd[3] = 0x00;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
gd5f_spi_rx(buf, size);
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
HAL_SPI_Receive(&hspi1, p_buf, size, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页编程(从缓存写入阵列
* @param page_addr: 页地址
* @param column: 列地址
* @param buf: 数据缓冲区
* @param size: 写入字节数
/*
* 函数功能:页编程(将数据写入指定页
* 入口参数:page_addr - 页地址 uint32_t
* column - 列地址 uint16_t 0 - 2047
* p_buf - 数据缓冲区 const uint8_t*
* size - 写入字节数 size_t > 0
* 返回值0 - 成功,其他 - 错误码
* 限定条件:目标区域已擦除
* 函数说明1. 写使能 - 02h 加载数据 - 10h 执行编程 - 等待完成
* 2. 编程完成后检查 P_FAIL 位
*/
static int gd5f_page_program(uint32_t page_addr, uint16_t column, const uint8_t *buf, size_t size)
static int gd5f_page_program(uint32_t page_addr, uint16_t column,
const uint8_t *p_buf, size_t size)
{
int ret;
int ret = GD5F_OK;
uint8_t cmd[4];
uint8_t status = 0;
/* 1. 写使能 */
gd5f_write_enable();
/* 2. 数据加载到缓存 (Program Load) */
cmd[0] = GD5F_CMD_PROGRAM_LOAD;
cmd[1] = (column >> 8) & 0xFF;
cmd[2] = column & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 3);
gd5f_spi_tx(buf, size);
HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT);
HAL_SPI_Transmit(&hspi1, (uint8_t *)p_buf, size,
GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
/* 3. 编程执行 (Program Execute) */
cmd[0] = GD5F_CMD_PROGRAM_EXEC;
cmd[1] = (page_addr >> 16) & 0xFF;
cmd[2] = (page_addr >> 8) & 0xFF;
cmd[3] = page_addr & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
/* 4. 等待完成 */
ret = gd5f_wait_busy(1000);
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
/* 5. 检查编程结果 */
uint8_t status;
gd5f_read_status(&status);
if (status & GD5F_STATUS_P_FAIL) {
/* 清除 P_FAIL写使能 + 读状态 */
gd5f_write_enable();
return GD5F_PROGRAM_FAIL;
}
return GD5F_OK;
}
/**
* @brief 块擦除
* @param block_addr: 块地址 (0 ~ 2047)
/*
* 函数功能:设置 Feature 寄存器
* 入口参数addr - 寄存器地址 uint8_t
* data - 写入数据 uint8_t
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:先写使能,发送 1Fh + 地址 + 数据,等待操作完成
*/
static int gd5f_set_feature(uint8_t addr, uint8_t data)
{
uint8_t cmd[3];
gd5f_write_enable();
cmd[0] = GD5F_CMD_SET_FEATURE;
cmd[1] = addr;
cmd[2] = data;
GD5F_CS_LOW();
HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
gd5f_wait_busy(100);
return GD5F_OK;
}
/*
* 函数功能块擦除擦除128KB块
* 入口参数block_addr - 块编号 uint32_t 0 - 2047
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已调用
* 函数说明1. 写使能 - D8h + 3字节字节地址 - 等待完成
* 2. 擦除完成后检查 E_FAIL 位
*/
static int gd5f_block_erase(uint32_t block_addr)
{
int ret;
int ret = GD5F_OK;
uint8_t cmd[4];
uint8_t status = 0;
uint32_t byte_addr = block_addr * GD5F_BLOCK_SIZE;
/* 1. 写使能 */
gd5f_write_enable();
/* 2. 块擦除命令 */
cmd[0] = GD5F_CMD_BLOCK_ERASE;
cmd[1] = (block_addr >> 8) & 0xFF;
cmd[2] = block_addr & 0xFF;
cmd[3] = 0x00;
cmd[1] = (byte_addr >> 16) & 0xFF;
cmd[2] = (byte_addr >> 8) & 0xFF;
cmd[3] = byte_addr & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
/* 3. 等待完成(擦除较慢) */
ret = gd5f_wait_busy(5000);
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
/* 4. 检查擦除结果 */
uint8_t status;
gd5f_read_status(&status);
if (status & GD5F_STATUS_E_FAIL) {
gd5f_write_enable();
return GD5F_ERASE_FAIL;
}
return GD5F_OK;
}
/* ===================== 公共接口实现 ===================== */
/* ======================== 公共函数定义 ======================== */
/*
* 函数功能:初始化 GD5F2GQ5UE
* 入口参数:无
* 返回值0 - 成功,其他 - 错误码
* 限定条件SPI1 和相关 GPIO 已由 CubeMX 初始化完成
* 函数说明1. 发送复位命令并等待完成
* 2. 读取芯片 ID 并校验
* 3. 使能内部 ECC (B0h bit4)
* 4. 解除所有块保护 (A0h = 0x00)
*/
int gd5f2gq5ue_init(void)
{
int ret;
uint8_t mid, did;
int ret = GD5F_OK;
uint8_t mid = 0;
uint8_t did = 0;
/* 确保控制引脚处于非激活状态 */
GD5F_CS_HIGH();
GD5F_WP_HIGH();
GD5F_HOLD_HIGH();
/* 小延时等待上电稳定 */
HAL_Delay(10);
/* 复位芯片 */
ret = gd5f2gq5ue_reset();
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
HAL_Delay(5);
/* 读取 ID 验证通信 */
ret = gd5f2gq5ue_read_id(&mid, &did);
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) {
return GD5F_ID_MISMATCH;
}
gd5f_set_feature(0xB0, 0x10);
gd5f_wait_busy(100);
gd5f_set_feature(GD5F_REG_PROTECT, 0x00);
gd5f_wait_busy(100);
return GD5F_OK;
}
/*
* 函数功能:读取芯片 IDMID + DID
* 入口参数mid - 制造商 ID 输出指针 uint8_t* 不为 NULL
* did - 设备 ID 输出指针 uint8_t* 不为 NULL
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID
*/
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did)
{
uint8_t cmd = GD5F_CMD_READ_ID;
uint8_t id_buf[3];
uint8_t id_buf[3] = {0};
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_rx(id_buf, 3); /* dummy + MID + DID */
HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT);
HAL_SPI_Receive(&hspi1, id_buf, 3, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
*mid = id_buf[1]; /* id_buf[0] = dummy */
*mid = id_buf[1];
*did = id_buf[2];
return GD5F_OK;
}
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size)
/*
* 函数功能:从 NAND 读取数据(支持跨页)
* 入口参数offset - 起始字节偏移 long 0 ~ 总容量-1
* p_buf - 数据缓冲区 uint8_t* 不为 NULL
* size - 读取字节数 size_t > 0
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用
* 函数说明:自动处理跨页读取
*/
int gd5f2gq5ue_read(long offset, uint8_t *p_buf, size_t size)
{
int ret;
int ret = GD5F_OK;
while (size > 0) {
/* 计算页地址和列偏移 */
uint32_t page_addr = offset / GD5F_PAGE_SIZE;
uint16_t column = offset % GD5F_PAGE_SIZE;
/* 本次读取字节数(不超过当前页剩余空间) */
size_t bytes = GD5F_PAGE_SIZE - column;
if (bytes > size) bytes = size;
/* Page Read to Cache */
if (bytes > size) {
bytes = size;
}
ret = gd5f_page_read(page_addr);
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
/* Read from Cache */
ret = gd5f_read_from_cache(column, buf, bytes);
if (ret != GD5F_OK) return ret;
ret = gd5f_read_from_cache(column, p_buf, bytes);
if (ret != GD5F_OK) {
return ret;
}
offset += bytes;
buf += bytes;
p_buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size)
/*
* 函数功能:向 NAND 写入数据(支持跨页)
* 入口参数offset - 起始字节偏移 long 0 ~ 总容量-1
* p_buf - 数据缓冲区 const uint8_t* 不为 NULL
* size - 写入字节数 size_t > 0
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用,目标区域已擦除
* 函数说明:自动处理跨页写入
*/
int gd5f2gq5ue_write(long offset, const uint8_t *p_buf, size_t size)
{
int ret;
int ret = GD5F_OK;
while (size > 0) {
/* 计算页地址和列偏移 */
uint32_t page_addr = offset / GD5F_PAGE_SIZE;
uint16_t column = offset % GD5F_PAGE_SIZE;
/* 本次写入字节数(不超过当前页剩余空间) */
size_t bytes = GD5F_PAGE_SIZE - column;
if (bytes > size) bytes = size;
/* 页编程 */
ret = gd5f_page_program(page_addr, column, buf, bytes);
if (ret != GD5F_OK) return ret;
if (bytes > size) {
bytes = size;
}
ret = gd5f_page_program(page_addr, column, p_buf, bytes);
if (ret != GD5F_OK) {
return ret;
}
offset += bytes;
buf += bytes;
p_buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
/*
* 函数功能:擦除块(按块擦除,最小单位 128KB
* 入口参数offset - 起始字节偏移 long 必须块对齐
* size - 擦除字节数 size_t 必须块大小整数倍
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用
* 函数说明:擦除操作以块为单位
*/
int gd5f2gq5ue_erase(long offset, size_t size)
{
int ret;
int ret = GD5F_OK;
/* 擦除起始地址必须块对齐 */
if (offset % GD5F_BLOCK_SIZE != 0) {
return GD5F_ERROR;
}
/* 擦除大小必须为块大小的整数倍 */
if (size % GD5F_BLOCK_SIZE != 0) {
return GD5F_ERROR;
}
/* 逐块擦除 */
while (size > 0) {
uint32_t block_addr = offset / GD5F_BLOCK_SIZE;
ret = gd5f_block_erase(block_addr);
if (ret != GD5F_OK) return ret;
if (ret != GD5F_OK) {
return ret;
}
offset += GD5F_BLOCK_SIZE;
size -= GD5F_BLOCK_SIZE;
@@ -353,12 +453,19 @@ int gd5f2gq5ue_erase(long offset, size_t size)
return GD5F_OK;
}
/*
* 函数功能:复位芯片
* 入口参数:无
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:发送 FFh 复位命令后等待 5ms
*/
int gd5f2gq5ue_reset(void)
{
uint8_t cmd = GD5F_CMD_RESET;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
HAL_SPI_Transmit(&hspi1, &cmd, 1, GD5F_SPI_TIMEOUT);
GD5F_CS_HIGH();
HAL_Delay(5);

View File

@@ -1,75 +1,70 @@
/**
******************************************************************************
* @file gd5f2gq5ue.h
* @brief GD5F2GQ5UE SPI NAND Flash 驱动头文件
******************************************************************************
*/
#ifndef __GD5F2GQ5UE_H
#define __GD5F2GQ5UE_H
/*
* 模块名称GD5F2GQ5UE SPI NAND Flash 驱动
* 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口
* 适用平台STM32F407ZGT6 + SPI1 硬件 SPI
* 作者:王建锋
* 创建日期2026-07-16
* 修改记录:
* 2026-07-16 王建锋 创建初始版本
* 2026-07-17 王建锋 切换为硬件 SPI修正擦除地址参考 NuttX 驱动
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "spi.h"
/* ===================== 硬件引脚定义 ===================== */
#define GD5F_CS_LOW() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_RESET)
#define GD5F_CS_HIGH() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_SET)
#define GD5F_WP_HIGH() HAL_GPIO_WritePin(GD_WP_GPIO_Port, GD_WP_Pin, GPIO_PIN_SET)
#define GD5F_HOLD_HIGH() HAL_GPIO_WritePin(GD_HOLD_GPIO_Port, GD_HOLD_Pin, GPIO_PIN_SET)
/* ======================== 宏定义 ======================== */
/* ===================== SPI 命令码 ===================== */
/* SPI 命令码 */
#define GD5F_CMD_WRITE_ENABLE 0x06
#define GD5F_CMD_WRITE_DISABLE 0x04
#define GD5F_CMD_GET_FEATURE 0x0F
#define GD5F_CMD_SET_FEATURE 0x1F
#define GD5F_CMD_READ_ID 0x9F
#define GD5F_CMD_PAGE_READ 0x13
#define GD5F_CMD_READ_FROM_CACHE 0x0B /* Fast Read, 1 dummy byte */
#define GD5F_CMD_READ_FROM_CACHE 0x0B
#define GD5F_CMD_PROGRAM_LOAD 0x02
#define GD5F_CMD_PROGRAM_EXEC 0x10
#define GD5F_CMD_BLOCK_ERASE 0xD8
#define GD5F_CMD_RESET 0xFF
/* ===================== 寄存器地址 ===================== */
#define GD5F_REG_STATUS 0xC0
/* 寄存器地址 */
#define GD5F_REG_PROTECT 0xA0
#define GD5F_REG_FEATURE 0xB0
#define GD5F_REG_STATUS 0xC0
#define GD5F_REG_DRIVER 0xD0
/* ===================== 状态位定义 ===================== */
#define GD5F_STATUS_OIP (1 << 0) /* 操作进行中 */
#define GD5F_STATUS_WEL (1 << 1) /* 写使能锁存 */
#define GD5F_STATUS_E_FAIL (1 << 2) /* 擦除失败 */
#define GD5F_STATUS_P_FAIL (1 << 3) /* 编程失败 */
#define GD5F_STATUS_BIT4 (1 << 4)
#define GD5F_STATUS_ECCS0 (1 << 5)
#define GD5F_STATUS_ECCS1 (1 << 6)
#define GD5F_STATUS_ECCSE0 (1 << 4) /* ECC 单 bit 错误低位 */
#define GD5F_STATUS_ECCSE1 (1 << 5) /* ECC 单 bit 错误高位 */
#define GD5F_STATUS_ECCSE2 (1 << 6) /* ECC 单 bit 错误高位 */
/* 状态位定义 */
#define GD5F_STATUS_OIP (1 << 0)
#define GD5F_STATUS_WEL (1 << 1)
#define GD5F_STATUS_E_FAIL (1 << 2)
#define GD5F_STATUS_P_FAIL (1 << 3)
#define GD5F_STATUS_ECCS0 (1 << 4)
#define GD5F_STATUS_ECCS1 (1 << 5)
/* ===================== Feature 位定义 ===================== */
/* Feature 位定义 */
#define GD5F_FEATURE_ECC_EN (1 << 4)
#define GD5F_FEATURE_QE (1 << 0) /* Quad Enable, B0[0] */
#define GD5F_FEATURE_QE (1 << 0)
/* ===================== 芯片参数 ===================== */
#define GD5F_PAGE_SIZE 2048 /* 主数据区字节数 */
#define GD5F_SPARE_SIZE 64 /* ECC 启用时 spare 区 */
#define GD5F_TOTAL_PAGE_SIZE 2112 /* 2048 + 64 */
/* 芯片参数 */
#define GD5F_PAGE_SIZE 2048
#define GD5F_SPARE_SIZE 64
#define GD5F_TOTAL_PAGE_SIZE 2112
#define GD5F_PAGES_PER_BLOCK 64
#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) /* 128KB */
#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE)
#define GD5F_TOTAL_BLOCKS 2048
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 256MB */
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE)
/* 制造商 ID 和设备 ID */
#define GD5F_MANUFACTURER_ID 0xC8
#define GD5F_DEVICE_ID 0x52
/* ===================== 返回值定义 ===================== */
/* 返回值定义 */
#define GD5F_OK 0
#define GD5F_ERROR -1
#define GD5F_BUSY_TIMEOUT -2
@@ -78,51 +73,74 @@ extern "C" {
#define GD5F_ERASE_FAIL -5
#define GD5F_ID_MISMATCH -6
/* ===================== 公共接口函数 ===================== */
/* 控制引脚宏 */
#define GD5F_CS_LOW() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_RESET)
#define GD5F_CS_HIGH() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_SET)
#define GD5F_WP_HIGH() HAL_GPIO_WritePin(GD_WP_GPIO_Port, GD_WP_Pin, GPIO_PIN_SET)
#define GD5F_HOLD_HIGH() HAL_GPIO_WritePin(GD_HOLD_GPIO_Port, GD_HOLD_Pin, GPIO_PIN_SET)
/**
* @brief 初始化 GD5F2GQ5UESPI + GPIO + 读 ID 验证)
* @retval GD5F_OK 成功, 其他为错误码
/* ======================== 函数声明 ======================== */
/*
* 函数功能:初始化 GD5F2GQ5UE读 ID + 使能 ECC + 解除块保护)
* 入口参数:无
* 返回值0 - 成功,其他 - 错误码
* 限定条件SPI1 和相关 GPIO 已由 CubeMX 初始化完成
* 函数说明1. 发送复位命令并等待完成
* 2. 读取芯片 ID 并校验
* 3. 使能内部 ECC (B0h bit4)
* 4. 解除所有块保护 (A0h = 0x00)
*/
int gd5f2gq5ue_init(void);
/**
* @brief 读取芯片 IDMID + DID
* @param mid: 制造商 ID 输出指针
* @param did: 设备 ID 输出指针
* @retval GD5F_OK 成功
/*
* 函数功能:读取芯片 IDMID + DID
* 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL
* did - 设备 ID 输出指针 uint8_t* 不为 NULL
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID
*/
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did);
/**
* @brief 从 NAND 读取数据(支持跨页)
* @param offset: 起始字节偏移(相对于 Flash 起始地址)
* @param buf: 数据缓冲区
* @param size: 读取字节数
* @retval GD5F_OK 成功
/*
* 函数功能:从 NAND 读取数据(支持跨页)
* 入口参数:offset - 起始字节偏移 long 0 - GD5F_TOTAL_SIZE-1
* buf - 数据缓冲区 uint8_t* 不为 NULL
* size - 读取字节数 size_t > 0
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用
* 函数说明:自动处理跨页读取,每次读取不超过当前页剩余空间
*/
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size);
/**
* @brief 向 NAND 写入数据(支持跨页)
* @param offset: 起始字节偏移
* @param buf: 数据缓冲区
* @param size: 写入字节数
* @retval GD5F_OK 成功
/*
* 函数功能:向 NAND 写入数据(支持跨页)
* 入口参数:offset - 起始字节偏移 long 0 - GD5F_TOTAL_SIZE-1
* buf - 数据缓冲区 uint8_t* 不为 NULL
* size - 写入字节数 size_t > 0
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用,目标区域已擦除
* 函数说明:自动处理跨页写入,每次写入不超过当前页剩余空间
*/
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size);
/**
* @brief 擦除块(按块擦除,最小单位 128KB
* @param offset: 起始字节偏移(必须块对齐
* @param size: 擦除字节数(必须为块大小的整数倍
* @retval GD5F_OK 成功
/*
* 函数功能:擦除块(按块擦除,最小单位 128KB
* 入口参数:offset - 起始字节偏移 long 必须 GD5F_BLOCK_SIZE 对齐
* size - 擦除字节数 size_t 必须 GD5F_BLOCK_SIZE 整数倍
* 返回值0 - 成功,其他 - 错误码
* 限定条件gd5f2gq5ue_init() 已成功调用
* 函数说明擦除操作以块为单位offset 和 size 必须块对齐
*/
int gd5f2gq5ue_erase(long offset, size_t size);
/**
* @brief 复位芯片
* @retval GD5F_OK 成功
/*
* 函数功能:复位芯片
* 入口参数:无
* 返回值0 - 成功
* 限定条件SPI 已初始化
* 函数说明:发送 FFh 复位命令后等待 5ms
*/
int gd5f2gq5ue_reset(void);

133
Drivers/BSP/RS485/rs485.c Normal file
View File

@@ -0,0 +1,133 @@
/*
* 模块名称RS-485 半双工通信驱动
* 模块功能RS-485 半双工通信驱动实现,核心要点:
* 1. 发送前拉高 DE切换到发送态
* 2. HAL_UART_Transmit 内部已等待 TC发送完成标志
* 3. 发送完毕后拉低 DE切回接收态
* 4. 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收
* 参考ST AN3070 应用笔记、controllerstech.com RS485 教程
* 适用平台STM32F4 系列
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
* 2026-07-18 王建锋 创建初始版本
*/
#include "rs485.h"
/*
* 内部辅助宏 - 方向控制
*/
#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)
/*
* 公共函数实现
*/
/*
* 函数功能:初始化 RS-485 句柄
* 入口参数handle - RS-485 句柄指针
* huart - UART 外设句柄
* dir_port - DE 引脚 GPIO 端口
* dir_pin - DE 引脚 GPIO 编号
* 返回值:无
* 限定条件UART 和 GPIO 须先由 CubeMX 完成初始化
* 函数说明:初始化后立即将 DE 拉低,使 RS-485 收发器处于接收状态
*/
void rs485_init(rs485_handle_t *handle,
UART_HandleTypeDef *huart,
GPIO_TypeDef *dir_port,
uint16_t dir_pin)
{
handle->huart = huart;
handle->dir_port = dir_port;
handle->dir_pin = dir_pin;
handle->rx_size = 0;
/* 默认进入接收状态 */
RS485_DIR_RX(handle);
}
/*
* 函数功能:阻塞方式发送数据
* 入口参数handle - RS-485 句柄指针
* data - 待发送数据缓冲区
* len - 待发送字节数
* timeout - 发送超时ms传 0 使用默认值
* 返回值HAL_OK / HAL_TIMEOUT / HAL_ERROR
* 限定条件:须在主循环或 RTOS 任务中调用,不可在 UART 中断中调用
* 函数说明:
* 时序DE=HIGH → UART 发送 N 字节 → 等 TC → DE=LOW
* HAL_UART_Transmit 内部会等待 TXE发送寄存器空逐字节搬数据
* 最后还会等待 TC发送完成标志确保最后一字节的停止位已移出。
* 因此返回后再拉低 DE 是安全的
*/
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
const uint8_t *data,
uint16_t len,
uint32_t timeout)
{
HAL_StatusTypeDef status;
if (timeout == 0U) {
timeout = RS485_TIMEOUT_DEFAULT;
}
/* 1. 切换到发送状态 */
RS485_DIR_TX(handle);
/* 2. 阻塞发送(内部等待 TC */
status = HAL_UART_Transmit(handle->huart,
(uint8_t *)data,
len,
timeout);
/* 3. 发送完毕或超时,切回接收状态 */
RS485_DIR_RX(handle);
return status;
}
/*
* 函数功能启动中断方式接收IDLE 空闲帧检测)
* 入口参数handle - RS-485 句柄指针
* buf - 接收缓冲区
* buf_size - 缓冲区最大容量
* 返回值HAL_OK / HAL_ERROR
* 限定条件UART 须已开启全局中断NVIC 使能)
* 函数说明:
* 使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收。
* 当 UART 总线空闲超过 1 个字符时间后,硬件触发 IDLE 中断,
* 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);
}
/*
* 函数功能:缓存最近一次接收的字节数
* 入口参数handle - RS-485 句柄指针
* size - 本次接收到的字节数
* 返回值:无
* 限定条件:须在 HAL_UARTEx_RxEventCallback 中调用
*/
void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size)
{
handle->rx_size = size;
}
/*
* 函数功能:获取最近一次接收的字节数
* 入口参数handle - RS-485 句柄指针
* 返回值:字节数
*/
uint16_t rs485_rx_get_size(const rs485_handle_t *handle)
{
return handle->rx_size;
}

110
Drivers/BSP/RS485/rs485.h Normal file
View File

@@ -0,0 +1,110 @@
/*
* 模块名称RS-485 半双工通信驱动
* 模块功能RS-485 半双工通信驱动,封装任意 UART 外设实现 485 方向控制,
* 提供阻塞发送、中断接收IDLE 空闲帧检测、DMA 发送等功能。
* 参考 ST AN3070 应用笔记《IO-Link master: USART communication》
* 及 controllerstech.com RS485 教程
* 适用平台STM32F4 系列
* 作者:王建锋
* 创建日期2026-07-18
* 修改记录:
* 2026-07-18 王建锋 创建初始版本
*/
#ifndef __RS485_H
#define __RS485_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/*
* 常量定义
*/
#define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时ms */
/*
* RS-485 句柄结构体
* 将任意 UART + 任意 GPIO 组合绑定为一个 RS-485 半双工通信实例
*/
typedef struct {
UART_HandleTypeDef *huart; /* UART 外设句柄 */
GPIO_TypeDef *dir_port; /* 方向控制 GPIO 端口 */
uint16_t dir_pin; /* 方向控制 GPIO 引脚号 */
volatile uint16_t rx_size; /* 最近一次接收的字节数 */
} rs485_handle_t;
/*
* 公共函数声明
*/
/*
* 函数功能:初始化 RS-485 句柄,绑定 UART 和方向控制引脚
* 入口参数handle - RS-485 句柄指针
* huart - UART 外设句柄指针(已由 CubeMX 初始化)
* dir_port - 方向控制 GPIO 端口(如 GPIOD
* dir_pin - 方向控制 GPIO 引脚号(如 GPIO_PIN_0
* 返回值:无
* 限定条件UART 和 GPIO 须先由 CubeMX 完成初始化
* 函数说明初始化后默认处于接收状态DE 引脚拉低)
*/
void rs485_init(rs485_handle_t *handle,
UART_HandleTypeDef *huart,
GPIO_TypeDef *dir_port,
uint16_t dir_pin);
/*
* 函数功能:阻塞方式发送数据
* 入口参数handle - RS-485 句柄指针
* data - 待发送数据缓冲区
* len - 待发送字节数
* timeout - 发送超时ms传 0 使用 RS485_TIMEOUT_DEFAULT
* 返回值HAL_OK / HAL_TIMEOUT / HAL_ERROR
* 限定条件:在主循环或任务中调用,不可在 UART 中断中调用
* 函数说明:发送前自动拉高 DE发送完成后等待 TC 标志再拉低 DE
* 确保最后一字节完全移出后再切换到接收状态
*/
HAL_StatusTypeDef rs485_transmit(rs485_handle_t *handle,
const uint8_t *data,
uint16_t len,
uint32_t timeout);
/*
* 函数功能启动中断方式接收IDLE 空闲帧检测)
* 入口参数handle - RS-485 句柄指针
* buf - 接收缓冲区
* buf_size - 缓冲区大小
* 返回值HAL_OK / HAL_ERROR
* 限定条件UART 须已开启全局中断NVIC 中须使能对应 UART 中断
* 函数说明:使用 HAL_UARTEx_ReceiveToIdle_IT 实现变长帧接收,
* 收到完整帧后在 RxEventCallback 中通知用户。
* 用户须在回调中重新调用本函数重新开启接收
*/
HAL_StatusTypeDef rs485_receive_start(rs485_handle_t *handle,
uint8_t *buf,
uint16_t buf_size);
/*
* 函数功能:将 RS-485 句柄与 HAL 回调关联
* 入口参数handle - RS-485 句柄指针
* 返回值:无
* 限定条件:须在 HAL_UART_RxCpltCallback / HAL_UARTEx_RxEventCallback 中调用
* 函数说明:将 HAL 回调中接收到的数据大小回写到句柄的 rx_size 字段
*/
void rs485_rx_set_size(rs485_handle_t *handle, uint16_t size);
/*
* 函数功能:获取最近一次接收的字节数
* 入口参数handle - RS-485 句柄指针
* 返回值:最近一次接收的字节数
* 限定条件:须在 HAL_UARTEx_RxEventCallback 触发后调用
*/
uint16_t rs485_rx_get_size(const rs485_handle_t *handle);
#ifdef __cplusplus
}
#endif
#endif /* __RS485_H */

381
Drivers/BSP/SD2506/sd2506.c Normal file
View File

@@ -0,0 +1,381 @@
/*
* 模块名称SD2506API-G RTC 实时时钟驱动
* 模块功能SD2506API-G 高精度温补实时时钟模块 I2C 驱动
* 适用平台STM32F407ZGT6I2C1 接口 (PB6-SCL, PB7-SDA)
* 作者:王建锋
* 创建日期2026-07-17
* 修改记录:
* 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册
*/
#include "sd2506.h"
#include "i2c.h"
#include <string.h>
extern I2C_HandleTypeDef hi2c1;
/* ======================== 内部辅助函数 ======================== */
uint8_t sd2506_bcd_to_dec(uint8_t bcd)
{
return ((bcd >> 4) * 10) + (bcd & 0x0FU);
}
uint8_t sd2506_dec_to_bcd(uint8_t dec)
{
return ((dec / 10) << 4) | (dec % 10);
}
/*
* 写单字节寄存器
* reg: 寄存器地址 (00H~79H)
* val: 写入值
* 返回: 0=成功, -2=I2C错误
*/
static int sd2506_write_reg(uint8_t reg, uint8_t val)
{
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
I2C_MEMADD_SIZE_8BIT, &val, 1,
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
return SD2506_I2C_ERROR;
}
return SD2506_OK;
}
/*
* 读单字节寄存器
* reg: 寄存器地址 (00H~79H)
* val: 读取值指针
* 返回: 0=成功, -2=I2C错误
*/
static int sd2506_read_reg(uint8_t reg, uint8_t *val)
{
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
I2C_MEMADD_SIZE_8BIT, val, 1,
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
return SD2506_I2C_ERROR;
}
return SD2506_OK;
}
/*
* 写多字节寄存器 (从 reg 开始连续写入 len 字节)
* reg: 起始寄存器地址
* data: 数据缓冲区
* len: 数据长度
* 返回: 0=成功, -2=I2C错误
*/
static int sd2506_write_regs(uint8_t reg, const uint8_t *data, uint8_t len)
{
if (HAL_I2C_Mem_Write(&hi2c1, SD2506_I2C_ADDR_WRITE, reg,
I2C_MEMADD_SIZE_8BIT, (uint8_t *)data, len,
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
return SD2506_I2C_ERROR;
}
return SD2506_OK;
}
/*
* 读多字节寄存器 (从 reg 开始连续读取 len 字节)
* reg: 起始寄存器地址
* data: 数据缓冲区
* len: 数据长度
* 返回: 0=成功, -2=I2C错误
*/
static int sd2506_read_regs(uint8_t reg, uint8_t *data, uint8_t len)
{
if (HAL_I2C_Mem_Read(&hi2c1, SD2506_I2C_ADDR_READ, reg,
I2C_MEMADD_SIZE_8BIT, data, len,
SD2506_I2C_TIMEOUT_MS) != HAL_OK) {
return SD2506_I2C_ERROR;
}
return SD2506_OK;
}
/*
* 开启写保护 (允许写入 00H~71H 寄存器)
* 顺序: 先写 WRTC1=1, 再写 WRTC2=1 + WRTC3=1
*/
static int sd2506_write_enable(void)
{
int ret;
/* 先置 WRTC1=1 (bit6=1), 其它位参考手册: 0x84 */
ret = sd2506_write_reg(SD2506_REG_CTR1, 0x84U);
if (ret != SD2506_OK) return ret;
/* 再置 WRTC2=1(bit5) + WRTC3=1(bit4): 0x8C */
ret = sd2506_write_reg(SD2506_REG_CTR2, 0x8CU);
if (ret != SD2506_OK) return ret;
return SD2506_OK;
}
/*
* 关闭写保护 (禁止写入 00H~71H 寄存器)
* 顺序: 先写 WRTC2=0 + WRTC3=0, 再写 WRTC1=0
*/
static int sd2506_write_disable(void)
{
int ret;
/* 先清 WRTC2=0, WRTC3=0: 0x00 */
ret = sd2506_write_reg(SD2506_REG_CTR2, 0x00U);
if (ret != SD2506_OK) return ret;
/* 再清 WRTC1=0, 同时 ARST=1 使能自动复位: 0x20 */
ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF);
if (ret != SD2506_OK) return ret;
return SD2506_OK;
}
/* ======================== 公共 API 实现 ======================== */
int sd2506_init(void)
{
int ret;
uint8_t id[8];
/* 验证 I2C 通信: 尝试读取 8 字节 ID */
ret = sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE);
if (ret != SD2506_OK) {
return ret;
}
/* 上电重置充电寄存器 18H = 82H (开启充电, 5K电阻)
* 手册强烈建议每次上电时重置此值 */
ret = sd2506_write_reg(SD2506_REG_CHARGE, 0x82U);
if (ret != SD2506_OK) {
return ret;
}
/* 配置: 24小时制, 自动复位使能
* 0FH = 0x20 (bit5=ARST=1, 其它标志位清零)
* 写入时需注意: 写允许状态下 0FH 的 WRTC 位必须为1
* 此处直接写入 0x20 即可 (ARST=1, 无 WRTC 位) */
ret = sd2506_write_reg(SD2506_REG_CTR1, SD2506_CTR1_WRITE_OFF);
if (ret != SD2506_OK) {
return ret;
}
return SD2506_OK;
}
int sd2506_set_time(const sd2506_time_t *time)
{
int ret;
uint8_t buf[7];
if (time == NULL) {
return SD2506_ERROR;
}
/* 组装 7 字节时间数据 (BCD 码) */
buf[0] = sd2506_dec_to_bcd(time->second); /* 00H: 秒 */
buf[1] = sd2506_dec_to_bcd(time->minute); /* 01H: 分 */
buf[2] = sd2506_dec_to_bcd(time->hour) | 0x80U; /* 02H: 时 (bit7=1, 24小时制) */
buf[3] = sd2506_dec_to_bcd(time->week); /* 03H: 星期 */
buf[4] = sd2506_dec_to_bcd(time->day); /* 04H: 日 */
buf[5] = sd2506_dec_to_bcd(time->month); /* 05H: 月 */
buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 06H: 年 */
/* 开启写保护 */
ret = sd2506_write_enable();
if (ret != SD2506_OK) return ret;
/* 一次性写入 7 字节时间数据 (00H~06H)
* 手册要求: 不可单独写某一个时间寄存器,否则可能引起错误进位 */
ret = sd2506_write_regs(SD2506_REG_SEC, buf, 7);
if (ret != SD2506_OK) return ret;
/* 关闭写保护 */
ret = sd2506_write_disable();
if (ret != SD2506_OK) return ret;
return SD2506_OK;
}
int sd2506_get_time(sd2506_time_t *time)
{
int ret;
uint8_t buf[7];
if (time == NULL) {
return SD2506_ERROR;
}
/* 一次读取 7 字节时间数据 (00H~06H)
* 手册说明: 读取时所有实时数据被锁存,避免错读 */
ret = sd2506_read_regs(SD2506_REG_SEC, buf, 7);
if (ret != SD2506_OK) {
return ret;
}
time->second = sd2506_bcd_to_dec(buf[0] & 0x7FU); /* 00H: 秒 */
time->minute = sd2506_bcd_to_dec(buf[1] & 0x7FU); /* 01H: 分 */
time->hour = sd2506_bcd_to_dec(buf[2] & 0x7FU); /* 02H: 屏蔽 bit7 (12/24标志) */
time->week = sd2506_bcd_to_dec(buf[3] & 0x07U); /* 03H: 星期 */
time->day = sd2506_bcd_to_dec(buf[4] & 0x3FU); /* 04H: 日 */
time->month = sd2506_bcd_to_dec(buf[5] & 0x1FU); /* 05H: 月 */
time->year = sd2506_bcd_to_dec(buf[6]) + 2000U; /* 06H: 年 */
return SD2506_OK;
}
int sd2506_get_temperature(int8_t *temp)
{
int ret;
uint8_t val;
if (temp == NULL) {
return SD2506_ERROR;
}
ret = sd2506_read_reg(SD2506_REG_TEMP, &val);
if (ret != SD2506_OK) {
return ret;
}
/* bit7 为符号位, 其余为温度值 */
if (val & 0x80U) {
/* 负温度: 取补码 */
*temp = (int8_t)(val | 0xF0U);
} else {
/* 正温度 */
*temp = (int8_t)(val & 0x7FU);
}
return SD2506_OK;
}
int sd2506_get_battery_voltage(uint16_t *voltage)
{
int ret;
uint8_t val_high, val_low;
if (voltage == NULL) {
return SD2506_ERROR;
}
/* 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL) */
ret = sd2506_read_reg(SD2506_REG_CTR5, &val_high);
if (ret != SD2506_OK) return ret;
ret = sd2506_read_reg(SD2506_REG_BAT_VAL, &val_low);
if (ret != SD2506_OK) return ret;
/* 组合 9 位: bit8=BAT8_VAL(1AH bit7), bit7~0=BAT_VL(1BH)
* 如 1AH=80H, 1BH=30H => 电压 = 0x130 = 304 => 3.04V => 3040mV */
uint16_t raw = ((val_high & 0x80U) << 1) | val_low;
*voltage = raw * 10; /* 转换为毫伏 (raw 单位 0.01V) */
return SD2506_OK;
}
int sd2506_get_id(uint8_t id[8])
{
if (id == NULL) {
return SD2506_ERROR;
}
return sd2506_read_regs(SD2506_REG_ID_START, id, SD2506_ID_SIZE);
}
int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len)
{
if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
return SD2506_ERROR;
}
if (addr + len > SD2506_SRAM_SIZE) {
return SD2506_ERROR;
}
return sd2506_read_regs(SD2506_REG_SRAM_START + addr, buf, len);
}
int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len)
{
if (buf == NULL || len == 0 || addr >= SD2506_SRAM_SIZE) {
return SD2506_ERROR;
}
if (addr + len > SD2506_SRAM_SIZE) {
return SD2506_ERROR;
}
/* SRAM 无需开写保护即可写入 (写保护仅对 00H~71H 有效, SRAM 是 2CH~71H)
* 但为安全起见, SRAM 写入也走写保护流程 */
int ret;
ret = sd2506_write_enable();
if (ret != SD2506_OK) return ret;
ret = sd2506_write_regs(SD2506_REG_SRAM_START + addr, buf, len);
if (ret != SD2506_OK) return ret;
ret = sd2506_write_disable();
return ret;
}
int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask)
{
int ret;
uint8_t buf[8];
if (time == NULL) {
return SD2506_ERROR;
}
/* 组装 8 字节报警数据 (07H~0EH) */
buf[0] = sd2506_dec_to_bcd(time->second) & 0x7FU; /* 07H: 秒报警 */
buf[1] = sd2506_dec_to_bcd(time->minute) & 0x7FU; /* 08H: 分报警 */
buf[2] = sd2506_dec_to_bcd(time->hour) & 0x3FU; /* 09H: 时报警 (最高位始终为0) */
buf[3] = 0x00U; /* 0AH: 星期报警 */
buf[4] = sd2506_dec_to_bcd(time->day) & 0x3FU; /* 0BH: 日报警 */
buf[5] = sd2506_dec_to_bcd(time->month) & 0x1FU; /* 0CH: 月报警 */
buf[6] = sd2506_dec_to_bcd(time->year - 2000U); /* 0DH: 年报警 */
buf[7] = mask; /* 0EH: 报警允许 */
/* 开启写保护 */
ret = sd2506_write_enable();
if (ret != SD2506_OK) return ret;
/* 写入报警寄存器 (07H~0EH) */
ret = sd2506_write_regs(SD2506_REG_AL_SEC, buf, 8);
if (ret != SD2506_OK) return ret;
/* 使能报警中断: CTR2 的 INTAE=1, INTS1=0, INTS0=1, IM=1 (周期性) */
ret = sd2506_write_reg(SD2506_REG_CTR2,
SD2506_CTR2_INTAE | SD2506_CTR2_INTS0 | SD2506_CTR2_IM);
if (ret != SD2506_OK) return ret;
/* 关闭写保护 */
ret = sd2506_write_disable();
if (ret != SD2506_OK) return ret;
return SD2506_OK;
}
int sd2506_clear_alarm(void)
{
int ret;
uint8_t val;
/* 读取 CTR1, ARST=1 时自动清除 INTAF */
ret = sd2506_read_reg(SD2506_REG_CTR1, &val);
if (ret != SD2506_OK) {
return ret;
}
return SD2506_OK;
}
int sd2506_read_ctr1(uint8_t *val)
{
if (val == NULL) {
return SD2506_ERROR;
}
return sd2506_read_reg(SD2506_REG_CTR1, val);
}

296
Drivers/BSP/SD2506/sd2506.h Normal file
View File

@@ -0,0 +1,296 @@
/*
* 模块名称SD2506API-G RTC 实时时钟驱动
* 模块功能SD2506API-G 高精度温补实时时钟模块 I2C 驱动,提供时间读写、
* 温度读取、电池电压检测、ID 读取等功能
* 适用平台STM32F407ZGT6I2C1 接口 (PB6-SCL, PB7-SDA)
* 作者:王建锋
* 创建日期2026-07-17
* 修改记录:
* 2026-07-17 王建锋 创建初始版本,参考 SD2506API-G Ver2.0 手册
*/
#ifndef __SD2506_H
#define __SD2506_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/* ======================== I2C 地址 ======================== */
/*
* SD2506API-G 7位器件地址: 0x32
* HAL库使用8位地址: 写 0x64, 读 0x65
*/
#define SD2506_I2C_ADDR 0x32U
#define SD2506_I2C_ADDR_WRITE 0x64U
#define SD2506_I2C_ADDR_READ 0x65U
/* ======================== 寄存器地址定义 ======================== */
/* 实时时钟寄存器 (00H~06H) */
#define SD2506_REG_SEC 0x00U /* 秒 00~59 BCD */
#define SD2506_REG_MIN 0x01U /* 分 00~59 BCD */
#define SD2506_REG_HOUR 0x02U /* 时 00~23 BCD, bit7=12/24 */
#define SD2506_REG_WEEK 0x03U /* 星期 00~06 BCD */
#define SD2506_REG_DAY 0x04U /* 日 01~31 BCD */
#define SD2506_REG_MON 0x05U /* 月 01~12 BCD */
#define SD2506_REG_YEAR 0x06U /* 年 00~99 BCD */
/* 报警寄存器 (07H~0EH) */
#define SD2506_REG_AL_SEC 0x07U /* 秒报警 */
#define SD2506_REG_AL_MIN 0x08U /* 分报警 */
#define SD2506_REG_AL_HOUR 0x09U /* 时报警 */
#define SD2506_REG_AL_WEEK 0x0AU /* 星期报警 */
#define SD2506_REG_AL_DAY 0x0BU /* 日报警 */
#define SD2506_REG_AL_MON 0x0CU /* 月报警 */
#define SD2506_REG_AL_YEAR 0x0DU /* 年报警 */
#define SD2506_REG_AL_EN 0x0EU /* 报警允许寄存器 */
/* 控制寄存器 */
#define SD2506_REG_CTR1 0x0FH /* 控制寄存器1 */
#define SD2506_REG_CTR2 0x10U /* 控制寄存器2 */
#define SD2506_REG_CTR3 0x11U /* 控制寄存器3 */
/* 倒计时寄存器 (13H~15H) */
#define SD2506_REG_CNT0 0x13U /* 倒计时字节0 (LSB) */
#define SD2506_REG_CNT1 0x14U /* 倒计时字节1 */
#define SD2506_REG_CNT2 0x15U /* 倒计时字节2 (MSB) */
/* 温度寄存器 */
#define SD2506_REG_TEMP 0x16U /* 温度值 (bit7=符号位) */
#define SD2506_REG_AGTC 0x17U /* IIC控制寄存器 AGTC */
#define SD2506_REG_CHARGE 0x18U /* 充电选择寄存器 */
#define SD2506_REG_CTR4 0x19U /* 扩展控制寄存器 CTR4 */
#define SD2506_REG_CTR5 0x1AU /* 控制寄存器 CTR5 */
#define SD2506_REG_BAT_VAL 0x1BU /* 电池电压低8位 */
/* 温度报警及历史 */
#define SD2506_REG_TEMP_AL 0x1CU /* 低温报警温度值 */
#define SD2506_REG_TEMP_AH 0x1DU /* 高温报警温度值 */
#define SD2506_REG_TEMP_HIS_L 0x1EU /* 历史低温 */
#define SD2506_REG_TEMP_HIS_H 0x1FU /* 历史高温 */
/* 用户 SRAM (2CH~71H) */
#define SD2506_REG_SRAM_START 0x2CU
#define SD2506_REG_SRAM_END 0x71U
#define SD2506_SRAM_SIZE 70U /* 70字节 */
/* ID 码 (72H~79H) */
#define SD2506_REG_ID_START 0x72U
#define SD2506_REG_ID_END 0x79U
#define SD2506_ID_SIZE 8U /* 8字节 */
/* ======================== 控制位定义 ======================== */
/* 控制寄存器 1 (0FH) */
#define SD2506_CTR1_ARST (1U << 5) /* 自动复位使能 */
#define SD2506_CTR1_INTAF (1U << 3) /* 报警中断标志 */
#define SD2506_CTR1_INTDF (1U << 2) /* 倒计时中断标志 */
#define SD2506_CTR1_BLF (1U << 0) /* 电池欠压标志 */
/* 控制寄存器 2 (10H) */
#define SD2506_CTR2_INTAE (1U << 5) /* 报警中断允许 */
#define SD2506_CTR2_INTFE (1U << 4) /* 频率中断允许 */
#define SD2506_CTR2_INTDE (1U << 3) /* 倒计时中断允许 */
#define SD2506_CTR2_IM (1U << 2) /* 中断模式: 0=单事件, 1=周期 */
#define SD2506_CTR2_INTS1 (1U << 1) /* INT输出选择 bit1 */
#define SD2506_CTR2_INTS0 (1U << 0) /* INT输出选择 bit0 */
/* 报警允许寄存器 (0EH) */
#define SD2506_AL_EN_EAY (1U << 6) /* 年报警允许 */
#define SD2506_AL_EN_EAMO (1U << 5) /* 月报警允许 */
#define SD2506_AL_EN_EAD (1U << 4) /* 日报警允许 */
#define SD2506_AL_EN_EAW (1U << 3) /* 星期报警允许 */
#define SD2506_AL_EN_EAH (1U << 2) /* 时报警允许 */
#define SD2506_AL_EN_EAMN (1U << 1) /* 分报警允许 */
#define SD2506_AL_EN_EAS (1U << 0) /* 秒报警允许 */
/* 24/12小时制位 */
#define SD2506_HOUR_24 (1U << 7) /* bit7=1 表示24小时制 */
/* ======================== 充电配置 ======================== */
/* 充电寄存器 (18H) 建议上电写入值: 0x82 (开启充电, 断开) */
#define SD2506_CHARGE_EN (1U << 7) /* 充电允许位 */
#define SD2506_CHARGE_2K (0U << 0) /* 2K电阻 */
#define SD2506_CHARGE_5K (1U << 0) /* 5K电阻 */
/* ======================== 写保护配置 ======================== */
/* 写允许时 0FH 寄存器建议值: 0xFF (WRTC1=1, WRTC2=1, WRTC3=1) */
#define SD2506_CTR1_WRITE_ON 0xFFU
/* 写禁止时 0FH 寄存器建议值: 0x7B (WRTC1=0, WRTC2=0, WRTC3=0, ARST=1) */
#define SD2506_CTR1_WRITE_OFF 0x7BU
/* ======================== 返回值定义 ======================== */
#define SD2506_OK 0
#define SD2506_ERROR -1
#define SD2506_I2C_ERROR -2
/* ======================== 超时时间 ======================== */
#define SD2506_I2C_TIMEOUT_MS 100
/* ======================== 数据结构 ======================== */
/*
* RTC 时间日期结构体
* year: 2000~2099
* month: 1~12
* day: 1~31
* hour: 0~23 (24小时制)
* minute: 0~59
* second: 0~59
* week: 0~6 (0=星期天, 1=星期一, ..., 6=星期六)
*/
typedef struct {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t week;
} sd2506_time_t;
/* ======================== 函数声明 ======================== */
/*
* 函数功能:初始化 SD2506API-G RTC
* 入口参数:无
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件CubeMX 已完成 I2C1 初始化
* 函数说明1. 读取芯片 ID 验证通信
* 2. 上电重置充电寄存器 18H=82H
* 3. 配置 24 小时制、开自动复位
*/
int sd2506_init(void);
/*
* 函数功能:设置 RTC 时间日期
* 入口参数time - 时间结构体指针,包含要设置的时间
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明1. 先开写保护
* 2. 一次性写入 7 字节时间数据 (00H~06H)
* 3. 关闭写保护
* 注意:不可单独写某一个时间寄存器
*/
int sd2506_set_time(const sd2506_time_t *time);
/*
* 函数功能:读取 RTC 时间日期
* 入口参数time - 时间结构体指针,用于存储读取结果
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明1. 一次读取 7 字节时间数据 (00H~06H)
* 2. BCD 转十进制
* 3. 屏蔽小时 bit7 (12/24标志位)
*/
int sd2506_get_time(sd2506_time_t *time);
/*
* 函数功能:读取芯片内部温度
* 入口参数temp - 温度输出指针 (整数部分, 有符号)
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明:读取 16H 寄存器bit7 为符号位,范围 -40~+85
*/
int sd2506_get_temperature(int8_t *temp);
/*
* 函数功能:读取电池电压 (毫伏)
* 入口参数voltage - 电压输出指针 (单位: mV)
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL)
* 2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V)
*/
int sd2506_get_battery_voltage(uint16_t *voltage);
/*
* 函数功能:读取芯片 8 字节 ID
* 入口参数id - 8 字节输出缓冲区
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明:读取 72H~79H 共 8 字节唯一 ID
*/
int sd2506_get_id(uint8_t id[8]);
/*
* 函数功能:读取用户 SRAM 数据
* 入口参数addr - SRAM 起始地址 (0~69)
* buf - 数据输出缓冲区
* len - 读取长度 (1~70)
* 返回值0 - 成功,-2 - I2C 通信错误,-1 - 参数错误
* 限定条件sd2506_init() 已调用
* 函数说明SRAM 地址范围 0~69对应寄存器 2CH~71H
*/
int sd2506_read_sram(uint8_t addr, uint8_t *buf, uint8_t len);
/*
* 函数功能:写入用户 SRAM 数据
* 入口参数addr - SRAM 起始地址 (0~69)
* buf - 数据输入缓冲区
* len - 写入长度 (1~70)
* 返回值0 - 成功,-2 - I2C 通信错误,-1 - 参数错误
* 限定条件sd2506_init() 已调用
* 函数说明SRAM 地址范围 0~69对应寄存器 2CH~71H
* SRAM 无需开写保护即可写入
*/
int sd2506_write_sram(uint8_t addr, const uint8_t *buf, uint8_t len);
/*
* 函数功能:设置报警中断
* 入口参数time - 报警时间结构体
* mask - 报警匹配掩码 (SD2506_AL_EN_xxx 位或组合)
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明1. 开写保护
* 2. 写入报警寄存器 (07H~0EH)
* 3. 使能报警中断 INTAE
* 4. 关写保护
*/
int sd2506_set_alarm(const sd2506_time_t *time, uint8_t mask);
/*
* 函数功能:清除报警中断标志
* 入口参数:无
* 返回值0 - 成功,-2 - I2C 通信错误
* 限定条件sd2506_init() 已调用
* 函数说明:读取 CTR1 自动清除 INTAF (ARST=1 时)
*/
int sd2506_clear_alarm(void);
/*
* 函数功能:读取当前 0FH 控制寄存器1 状态
* 入口参数val - 输出值指针
* 返回值0 - 成功,-2 - I2C 通信错误
*/
int sd2506_read_ctr1(uint8_t *val);
/*
* 函数功能BCD 码转十进制
* 入口参数bcd - BCD 码值
* 返回值:十进制值
* 函数说明:内部辅助函数
*/
uint8_t sd2506_bcd_to_dec(uint8_t bcd);
/*
* 函数功能:十进制转 BCD 码
* 入口参数dec - 十进制值
* 返回值BCD 码值
* 函数说明:内部辅助函数
*/
uint8_t sd2506_dec_to_bcd(uint8_t dec);
#ifdef __cplusplus
}
#endif
#endif /* __SD2506_H */

View File

@@ -0,0 +1,354 @@
/*
* 模块名称TPAFE5160 16位8通道同步采样ADC驱动
* 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口
* 适用平台STM32F407ZGT6并行16位数据总线接 GPIOG[15:0]
* 作者:王建锋
* 创建日期2026-07-17
* 修改记录:
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
*/
/* 头文件包含区 */
#include "tpafe5160.h"
/* ======================== 私有宏定义 ======================== */
/*
* 并行读取时序延时 (168MHz 主频1 NOP ≈ 5.95ns)
*
* TPAFE5160 并行时序要求 (VDRIVE > 2.7V)
* t10 (RD 低脉宽) ≥ 22ns
* t11 (RD 高脉宽) ≥ 10ns
* t14 (数据访问时间) ≤ 21ns (从 RD 下降沿算起)
* t15 (数据保持时间) ≥ 6ns (从 RD 下降沿算起)
*
* GPIO 写操作本身约 1 个 AHB 周期 (~6ns)
* 加上端口延迟 (~12-18ns),实际 RD 引脚翻转滞后约 18-24ns。
* 因此 NOP 延时只需覆盖数据建立时间即可。
*/
#define TP_NOP_5() __NOP(); __NOP(); __NOP(); __NOP(); __NOP()
/* RD 低脉宽延时GPIO写(~6ns) + 5NOP(~30ns) > 22ns */
#define TP_RD_LOW_DLY() do { TPAFE5160_RD_LOW(); TP_NOP_5(); } while (0)
/* RD 高脉宽延时GPIO写(~6ns) + 3NOP(~18ns) > 10ns */
#define TP_RD_HIGH_DLY() do { TPAFE5160_RD_HIGH(); __NOP(); __NOP(); __NOP(); } while (0)
/* CONVST 脉冲延时上升沿前需保证低电平5NOP 覆盖 t5 ≥ 20ns */
#define TP_CONVST_PULSE() do { \
TPAFE5160_CONVST_LOW(); \
TP_NOP_5(); \
TPAFE5160_CONVST_HIGH(); \
TP_NOP_5(); \
} while (0)
/* ======================== 私有函数声明 ======================== */
static void tpafe5160_read_channels(uint8_t count, int16_t *buf);
/* ======================== 公共函数定义 ======================== */
/*
* 函数功能:初始化 TPAFE5160设置过采样、等待就绪
* 入口参数:无
* 返回值0 - 成功,-2 - BUSY 超时
* 限定条件CubeMX 已完成 GPIO 初始化
* 函数说明1. 设置过采样为无过采样 (000)
* 2. 确保 RD 为高、CONVST 为低
* 3. 等待 BUSY 释放(转换空闲)
*/
int tpafe5160_init(void)
{
/* 设置默认过采样:无过采样 (OS[2:0] = 000) */
tpafe5160_set_os(TP_OS_NONE);
/* 确保控制引脚处于空闲状态 */
TPAFE5160_RD_HIGH();
TPAFE5160_CONVST_LOW();
/* 等待 BUSY 释放,确保上电后无残留转换 */
return tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
}
/*
* 函数功能:设置过采样率
* 入口参数os - 过采样率枚举值 tpafe5160_os_t
* 返回值:无
* 限定条件GPIO 已初始化
* 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次 BUSY 下降沿锁存生效
*/
void tpafe5160_set_os(tpafe5160_os_t os)
{
TPAFE5160_OS0(os & 0x01); /* OS0 = bit0 */
TPAFE5160_OS1((os >> 1) & 0x01); /* OS1 = bit1 */
TPAFE5160_OS2((os >> 2) & 0x01); /* OS2 = bit2 */
}
/*
* 函数功能启动一次转换CONVST 上升沿触发)
* 入口参数:无
* 返回值:无
* 限定条件GPIO 已初始化
* 函数说明:产生 CONVST 脉冲上升沿启动全部8通道同步采样与转换
*/
void tpafe5160_start_conv(void)
{
TP_CONVST_PULSE();
}
/*
* 函数功能:等待转换完成
* 入口参数timeout_ms - 超时时间 uint32_t > 0
* 返回值0 - 转换完成,-2 - 超时
* 限定条件:已调用 tpafe5160_start_conv()
* 函数说明:轮询 BUSY 引脚等待下降沿
*/
int tpafe5160_wait_busy(uint32_t timeout_ms)
{
uint32_t tick_start = HAL_GetTick();
/* 等待 BUSY 释放(低电平表示空闲) */
while (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) {
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
return TPAFE5160_BUSY_TIMEOUT;
}
}
return TPAFE5160_OK;
}
/*
* 函数功能:查询当前是否正在转换
* 入口参数:无
* 返回值1 - 正在转换0 - 空闲
* 限定条件GPIO 已初始化
* 函数说明:读取 BUSY 引脚电平
*/
uint8_t tpafe5160_is_busy(void)
{
return (TPAFE5160_BUSY_READ() == GPIO_PIN_SET) ? 1 : 0;
}
/*
* 函数功能读取全部8通道转换结果
* 入口参数buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
* 返回值0 - 成功,-2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明1. 启动转换并等待 BUSY 释放
* 2. 连续8次拉低RD读取各通道数据
* 3. 通过 FRSTDATA 验证第一通道
*/
int tpafe5160_read_all(int16_t *buf)
{
int ret;
/* 启动转换 */
tpafe5160_start_conv();
/* 等待转换完成 */
ret = tpafe5160_wait_busy(TPAFE5160_CONV_TIMEOUT_MS);
if (ret != TPAFE5160_OK) {
return ret;
}
/* 连续读取8个通道 */
tpafe5160_read_channels(TPAFE5160_CH_NUM, buf);
return TPAFE5160_OK;
}
/*
* 函数功能:读取指定通道的转换结果
* 入口参数channel - 通道号 uint8_t 0 - 7
* value - 输出指针 int16_t* 不为 NULL
* 返回值0 - 成功,-1 - 通道号无效,-2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明:启动转换并等待完成后,连续读取至指定通道
*/
int tpafe5160_read_channel(uint8_t channel, int16_t *value)
{
int ret;
int16_t buf[TPAFE5160_CH_NUM];
if (channel >= TPAFE5160_CH_NUM || value == NULL) {
return TPAFE5160_ERROR;
}
ret = tpafe5160_read_all(buf);
if (ret != TPAFE5160_OK) {
return ret;
}
*value = buf[channel];
return TPAFE5160_OK;
}
/*
* 函数功能原始ADC值转电压值
* 入口参数raw - ADC原始值 int16_t 有符号补码
* 返回值:电压值 float 单位 V
* 限定条件:无
* 函数说明±5V量程时 LSB = 10V / 65536 ≈ 152.59μV
* ±10V量程时 LSB = 20V / 65536 ≈ 305.18μV
* 硬件 RANGE 引脚接 GND默认 ±5V 量程
*/
float tpafe5160_to_voltage(int16_t raw)
{
/* RANGE 接 GND → ±5V 量程,满量程 10V */
return (float)raw * (10.0f / 65536.0f);
}
/*
* 函数功能:直接读取并行数据总线(不启动转换)
* 入口参数:无
* 返回值16位原始数据 uint16_t
* 限定条件RD 为低或 CS 与 RD 已拉低
* 函数说明:读取 GPIOG->IDR 低16位对应 DB[15:0]
*/
uint16_t tpafe5160_read_bus(void)
{
return TPAFE5160_READ_BUS();
}
/* ======================== 私有函数定义 ======================== */
/*
* 函数功能:通过 RD 脉冲连续读取多个通道数据
* 入口参数count - 要读取的通道数 uint8_t 1 - 8
* buf - 输出缓冲区 int16_t* 不为 NULL
* 返回值:无
* 限定条件转换已完成BUSY 为低RD 初始为高
* 函数说明:每次 RD 下降沿输出一个通道数据按通道1~8顺序输出
* DB[15:0] 直接接 GPIOG[15:0],通过 IDR 寄存器一次读取
*
* 时序关键点 (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)
{
uint8_t i;
for (i = 0; i < count; i++) {
/* RD 下降沿ADC 输出当前通道数据到 DB[15:0] */
TP_RD_LOW_DLY();
/* 读取16位并行数据 */
buf[i] = (int16_t)TPAFE5160_READ_BUS();
/* RD 上升沿:准备下一通道 */
TP_RD_HIGH_DLY();
}
}
/* ======================== 中断模式实现 ======================== */
/* 双缓冲区ISR 写 s_buf_b主循环读 s_buf_a */
static int16_t s_buf_a[TPAFE5160_CH_NUM];
static int16_t s_buf_b[TPAFE5160_CH_NUM];
static volatile uint8_t s_ready = 0;
static volatile uint8_t s_buf_sel = 0; /* 0 = 写 B / 读 A, 1 = 写 A / 读 B */
/*
* 函数功能:使能 BUSY EXTI 中断(运行时重使能用)
* 入口参数:无
* 返回值:无
* 限定条件CubeMX 已完成 GPIO 和 NVIC 配置
* 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用
*/
void tpafe5160_irq_enable(void)
{
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
/*
* 函数功能:关闭 BUSY EXTI 中断
* 入口参数:无
* 返回值:无
* 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明:仅禁用 NVIC 中断GPIO 配置保持 CubeMX 设定
*/
void tpafe5160_irq_disable(void)
{
HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
}
/*
* 函数功能:启动转换(中断模式)
* 入口参数:无
* 返回值:无
* 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据
*/
void tpafe5160_start_conv_irq(void)
{
s_ready = 0;
TP_CONVST_PULSE();
}
/*
* 函数功能:检查是否有新的转换数据
* 入口参数:无
* 返回值1 - 数据就绪0 - 无新数据
* 限定条件:中断模式已启用
* 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除
*/
uint8_t tpafe5160_data_ready(void)
{
return s_ready;
}
/*
* 函数功能:清除数据就绪标志
* 入口参数:无
* 返回值:无
* 限定条件:中断模式已启用
* 函数说明:主循环处理完数据后调用
*/
void tpafe5160_clear_ready(void)
{
s_ready = 0;
}
/*
* 函数功能:获取数据缓冲区指针
* 入口参数:无
* 返回值int16_t[8] 数据缓冲区的 const 指针
* 限定条件tpafe5160_data_ready() 返回 1 时调用
* 函数说明双缓冲切换ISR 写另一个缓冲区,主循环安全读取当前缓冲区
*/
const int16_t* tpafe5160_get_buf(void)
{
return (s_buf_sel == 0) ? s_buf_a : s_buf_b;
}
/*
* 函数功能BUSY 下降沿 EXTI 回调(由 HAL_GPIO_EXTI_IRQHandler 调用)
* 入口参数GPIO_Pin - 触发中断的引脚号
* 返回值:无
* 限定条件BUSY EXTI 已使能
* 函数说明:转换完成后自动读取 8 通道数据到缓冲区,耗时约 0.5µs (168MHz)
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin != TP_BUSY_Pin) {
return;
}
/* 双缓冲切换ISR 写与主循环读不同的缓冲区 */
int16_t *p_wr = (s_buf_sel == 0) ? s_buf_b : s_buf_a;
/* 连续读取8个通道约 0.5µs @ 168MHz */
uint8_t i;
for (i = 0; i < TPAFE5160_CH_NUM; i++) {
TP_RD_LOW_DLY();
p_wr[i] = (int16_t)TPAFE5160_READ_BUS();
TP_RD_HIGH_DLY();
}
/* 切换缓冲区并标记就绪 */
s_buf_sel ^= 1;
s_ready = 1;
}

View File

@@ -0,0 +1,224 @@
#ifndef __TPAFE5160_H
#define __TPAFE5160_H
/*
* 模块名称TPAFE5160 16位8通道同步采样ADC驱动
* 模块功能:提供 TPAFE5160 并行接口模式下的初始化、过采样设置、转换启动、数据读取接口
* 适用平台STM32F407ZGT6并行16位数据总线接 GPIOG[15:0]
* 作者:王建锋
* 创建日期2026-07-17
* 修改记录:
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/* ======================== 宏定义 ======================== */
/* 通道数量 */
#define TPAFE5160_CH_NUM 8
/* 控制引脚操作宏 —— RD (PD3) */
#define TPAFE5160_RD_LOW() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_RESET)
#define TPAFE5160_RD_HIGH() HAL_GPIO_WritePin(TP_RD_GPIO_Port, TP_RD_Pin, GPIO_PIN_SET)
/* 控制引脚操作宏 —— CONVST (PD4) */
#define TPAFE5160_CONVST_LOW() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_RESET)
#define TPAFE5160_CONVST_HIGH() HAL_GPIO_WritePin(TP_CONVST_GPIO_Port, TP_CONVST_Pin, GPIO_PIN_SET)
/* 状态引脚读取宏 */
#define TPAFE5160_BUSY_READ() HAL_GPIO_ReadPin(TP_BUSY_GPIO_Port, TP_BUSY_Pin)
#define TPAFE5160_FRSTDATA_READ() HAL_GPIO_ReadPin(TP_FRSTDATA_GPIO_Port, TP_FRSTDATA_Pin)
/* 过采样引脚操作宏 —— OS0 (PF13), OS1 (PF14), OS2 (PF15) */
#define TPAFE5160_OS0(val) HAL_GPIO_WritePin(TP_OS0_GPIO_Port, TP_OS0_Pin, \
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
#define TPAFE5160_OS1(val) HAL_GPIO_WritePin(TP_OS1_GPIO_Port, TP_OS1_Pin, \
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
#define TPAFE5160_OS2(val) HAL_GPIO_WritePin(TP_OS2_GPIO_Port, TP_OS2_Pin, \
(val) ? GPIO_PIN_SET : GPIO_PIN_RESET)
/* 并行数据总线读取 —— DB[15:0] 接 GPIOG[15:0]单次读取16位 */
#define TPAFE5160_READ_BUS() ((uint16_t)GPIOG->IDR)
/* 过采样率枚举 (OS[2:0] 编码OS2为MSB, OS0为LSB) */
typedef enum {
TP_OS_NONE = 0, /* 000 — 无过采样350 kSPS */
TP_OS_X2 = 1, /* 001 — 2倍过采样175 kSPS */
TP_OS_X4 = 2, /* 010 — 4倍过采样87.5 kSPS */
TP_OS_X8 = 3, /* 011 — 8倍过采样43.75 kSPS */
TP_OS_X16 = 4, /* 100 — 16倍过采样21.875 kSPS */
TP_OS_X32 = 5, /* 101 — 32倍过采样10.94 kSPS */
TP_OS_X64 = 6, /* 110 — 64倍过采样5.47 kSPS */
TP_OS_HBW = 7 /* 111 — 高带宽模式 (~30kHz)350 kSPS */
} tpafe5160_os_t;
/* 输入量程枚举 */
typedef enum {
TP_RANGE_5V = 0, /* ±5V (RANGE = LOW) */
TP_RANGE_10V = 1 /* ±10V (RANGE = HIGH) */
} tpafe5160_range_t;
/* 返回值定义 */
#define TPAFE5160_OK 0
#define TPAFE5160_ERROR -1
#define TPAFE5160_BUSY_TIMEOUT -2
/* 默认超时时间 (ms) */
#define TPAFE5160_CONV_TIMEOUT_MS 10
/* ======================== 函数声明 ======================== */
/*
* 函数功能:初始化 TPAFE5160设置过采样、等待就绪
* 入口参数:无
* 返回值0 - 成功,-2 - BUSY 超时
* 限定条件CubeMX 已完成 GPIO 初始化
* 函数说明1. 设置过采样为无过采样 (000)
* 2. 确保 RD 为高、CONVST 为低
* 3. 等待 BUSY 释放(转换空闲)
*/
int tpafe5160_init(void);
/*
* 函数功能:设置过采样率
* 入口参数os - 过采样率枚举值 tpafe5160_os_t
* 返回值:无
* 限定条件GPIO 已初始化
* 函数说明:通过 OS[2:0] 引脚设置过采样率,在下一次转换时生效
*/
void tpafe5160_set_os(tpafe5160_os_t os);
/*
* 函数功能启动一次转换CONVST 上升沿触发)
* 入口参数:无
* 返回值:无
* 限定条件GPIO 已初始化
* 函数说明:产生 CONVST 脉冲上升沿启动全部8通道同步采样与转换
*/
void tpafe5160_start_conv(void);
/*
* 函数功能:等待转换完成
* 入口参数timeout_ms - 超时时间 uint32_t > 0
* 返回值0 - 转换完成,-2 - 超时
* 限定条件:已调用 tpafe5160_start_conv()
* 函数说明:轮询 BUSY 引脚等待下降沿
*/
int tpafe5160_wait_busy(uint32_t timeout_ms);
/*
* 函数功能:查询当前是否正在转换
* 入口参数:无
* 返回值1 - 正在转换0 - 空闲
* 限定条件GPIO 已初始化
* 函数说明:读取 BUSY 引脚电平
*/
uint8_t tpafe5160_is_busy(void);
/*
* 函数功能读取全部8通道转换结果
* 入口参数buf - 8个int16_t的输出缓冲区 int16_t* 不为 NULL
* 返回值0 - 成功,-2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明1. 启动转换并等待 BUSY 释放
* 2. 连续8次拉低RD读取各通道数据
* 3. 通过 FRSTDATA 验证第一通道
*/
int tpafe5160_read_all(int16_t *buf);
/*
* 函数功能:读取指定通道的转换结果
* 入口参数channel - 通道号 uint8_t 0 - 7
* value - 输出指针 int16_t* 不为 NULL
* 返回值0 - 成功,-1 - 通道号无效,-2 - BUSY 超时
* 限定条件GPIO 已初始化
* 函数说明:启动转换并等待完成后,连续读取至指定通道
*/
int tpafe5160_read_channel(uint8_t channel, int16_t *value);
/*
* 函数功能原始ADC值转电压值
* 入口参数raw - ADC原始值 int16_t 有符号补码
* 返回值:电压值 float 单位 V
* 限定条件:无
* 函数说明±5V量程时 LSB=152.59μV±10V量程时 LSB=305.18μV
* 默认使用 ±5V 量程 (RANGE 接 GND)
*/
float tpafe5160_to_voltage(int16_t raw);
/*
* 函数功能:直接读取并行数据总线(不启动转换)
* 入口参数:无
* 返回值16位原始数据 uint16_t
* 限定条件RD 为低或CS与RD已拉低
* 函数说明用于读取当前总线上的数据需自行控制RD时序
*/
uint16_t tpafe5160_read_bus(void);
/* ======================== 中断模式 API ======================== */
/*
* 函数功能:使能 BUSY EXTI 中断(运行时重使能用)
* 入口参数:无
* 返回值:无
* 限定条件CubeMX 已完成 GPIO 和 NVIC 配置
* 函数说明:正常启动流程无需调用,仅在 irq_disable() 后需要重新使能时使用
*/
void tpafe5160_irq_enable(void);
/*
* 函数功能:关闭 BUSY EXTI 中断
* 入口参数:无
* 返回值:无
* 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明:仅禁用 NVIC 中断GPIO 配置保持 CubeMX 设定
*/
void tpafe5160_irq_disable(void);
/*
* 函数功能:启动转换(中断模式)
* 入口参数:无
* 返回值:无
* 限定条件:已调用 tpafe5160_irq_enable()
* 函数说明:产生 CONVST 脉冲,转换完成后由 EXTI 中断自动读取 8 通道数据
*/
void tpafe5160_start_conv_irq(void);
/*
* 函数功能:检查是否有新的转换数据
* 入口参数:无
* 返回值1 - 数据就绪0 - 无新数据
* 限定条件:中断模式已启用
* 函数说明:在 EXTI 回调中置位,主循环读取后需调用 tpafe5160_clear_ready() 清除
*/
uint8_t tpafe5160_data_ready(void);
/*
* 函数功能:清除数据就绪标志
* 入口参数:无
* 返回值:无
* 限定条件:中断模式已启用
* 函数说明:主循环处理完数据后调用
*/
void tpafe5160_clear_ready(void);
/*
* 函数功能:获取数据缓冲区指针
* 入口参数:无
* 返回值int16_t[8] 数据缓冲区的 const 指针
* 限定条件tpafe5160_data_ready() 返回 1 时调用
* 函数说明:缓冲区由 EXTI 回调写入,主循环只读
*/
const int16_t* tpafe5160_get_buf(void);
#ifdef __cplusplus
}
#endif
#endif /* __TPAFE5160_H */

View File

@@ -0,0 +1,741 @@
/**
******************************************************************************
* @file stm32f4xx_hal_i2c.h
* @author MCD Application Team
* @brief Header file of I2C HAL module.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_I2C_H
#define __STM32F4xx_HAL_I2C_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal_def.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @addtogroup I2C
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup I2C_Exported_Types I2C Exported Types
* @{
*/
/** @defgroup I2C_Configuration_Structure_definition I2C Configuration Structure definition
* @brief I2C Configuration Structure definition
* @{
*/
typedef struct
{
uint32_t ClockSpeed; /*!< Specifies the clock frequency.
This parameter must be set to a value lower than 400kHz */
uint32_t DutyCycle; /*!< Specifies the I2C fast mode duty cycle.
This parameter can be a value of @ref I2C_duty_cycle_in_fast_mode */
uint32_t OwnAddress1; /*!< Specifies the first device own address.
This parameter can be a 7-bit or 10-bit address. */
uint32_t AddressingMode; /*!< Specifies if 7-bit or 10-bit addressing mode is selected.
This parameter can be a value of @ref I2C_addressing_mode */
uint32_t DualAddressMode; /*!< Specifies if dual addressing mode is selected.
This parameter can be a value of @ref I2C_dual_addressing_mode */
uint32_t OwnAddress2; /*!< Specifies the second device own address if dual addressing mode is selected
This parameter can be a 7-bit address. */
uint32_t GeneralCallMode; /*!< Specifies if general call mode is selected.
This parameter can be a value of @ref I2C_general_call_addressing_mode */
uint32_t NoStretchMode; /*!< Specifies if nostretch mode is selected.
This parameter can be a value of @ref I2C_nostretch_mode */
} I2C_InitTypeDef;
/**
* @}
*/
/** @defgroup HAL_state_structure_definition HAL state structure definition
* @brief HAL State structure definition
* @note HAL I2C State value coding follow below described bitmap :
* b7-b6 Error information
* 00 : No Error
* 01 : Abort (Abort user request on going)
* 10 : Timeout
* 11 : Error
* b5 Peripheral initialization status
* 0 : Reset (Peripheral not initialized)
* 1 : Init done (Peripheral initialized and ready to use. HAL I2C Init function called)
* b4 (not used)
* x : Should be set to 0
* b3
* 0 : Ready or Busy (No Listen mode ongoing)
* 1 : Listen (Peripheral in Address Listen Mode)
* b2 Intrinsic process state
* 0 : Ready
* 1 : Busy (Peripheral busy with some configuration or internal operations)
* b1 Rx state
* 0 : Ready (no Rx operation ongoing)
* 1 : Busy (Rx operation ongoing)
* b0 Tx state
* 0 : Ready (no Tx operation ongoing)
* 1 : Busy (Tx operation ongoing)
* @{
*/
typedef enum
{
HAL_I2C_STATE_RESET = 0x00U, /*!< Peripheral is not yet Initialized */
HAL_I2C_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use */
HAL_I2C_STATE_BUSY = 0x24U, /*!< An internal process is ongoing */
HAL_I2C_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing */
HAL_I2C_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */
HAL_I2C_STATE_LISTEN = 0x28U, /*!< Address Listen Mode is ongoing */
HAL_I2C_STATE_BUSY_TX_LISTEN = 0x29U, /*!< Address Listen Mode and Data Transmission
process is ongoing */
HAL_I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /*!< Address Listen Mode and Data Reception
process is ongoing */
HAL_I2C_STATE_ABORT = 0x60U, /*!< Abort user request ongoing */
HAL_I2C_STATE_TIMEOUT = 0xA0U, /*!< Timeout state */
HAL_I2C_STATE_ERROR = 0xE0U /*!< Error */
} HAL_I2C_StateTypeDef;
/**
* @}
*/
/** @defgroup HAL_mode_structure_definition HAL mode structure definition
* @brief HAL Mode structure definition
* @note HAL I2C Mode value coding follow below described bitmap :\n
* b7 (not used)\n
* x : Should be set to 0\n
* b6\n
* 0 : None\n
* 1 : Memory (HAL I2C communication is in Memory Mode)\n
* b5\n
* 0 : None\n
* 1 : Slave (HAL I2C communication is in Slave Mode)\n
* b4\n
* 0 : None\n
* 1 : Master (HAL I2C communication is in Master Mode)\n
* b3-b2-b1-b0 (not used)\n
* xxxx : Should be set to 0000
* @{
*/
typedef enum
{
HAL_I2C_MODE_NONE = 0x00U, /*!< No I2C communication on going */
HAL_I2C_MODE_MASTER = 0x10U, /*!< I2C communication is in Master Mode */
HAL_I2C_MODE_SLAVE = 0x20U, /*!< I2C communication is in Slave Mode */
HAL_I2C_MODE_MEM = 0x40U /*!< I2C communication is in Memory Mode */
} HAL_I2C_ModeTypeDef;
/**
* @}
*/
/** @defgroup I2C_Error_Code_definition I2C Error Code definition
* @brief I2C Error Code definition
* @{
*/
#define HAL_I2C_ERROR_NONE 0x00000000U /*!< No error */
#define HAL_I2C_ERROR_BERR 0x00000001U /*!< BERR error */
#define HAL_I2C_ERROR_ARLO 0x00000002U /*!< ARLO error */
#define HAL_I2C_ERROR_AF 0x00000004U /*!< AF error */
#define HAL_I2C_ERROR_OVR 0x00000008U /*!< OVR error */
#define HAL_I2C_ERROR_DMA 0x00000010U /*!< DMA transfer error */
#define HAL_I2C_ERROR_TIMEOUT 0x00000020U /*!< Timeout Error */
#define HAL_I2C_ERROR_SIZE 0x00000040U /*!< Size Management error */
#define HAL_I2C_ERROR_DMA_PARAM 0x00000080U /*!< DMA Parameter Error */
#define HAL_I2C_WRONG_START 0x00000200U /*!< Wrong start Error */
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
#define HAL_I2C_ERROR_INVALID_CALLBACK 0x00000100U /*!< Invalid Callback error */
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup I2C_handle_Structure_definition I2C handle Structure definition
* @brief I2C handle Structure definition
* @{
*/
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
typedef struct __I2C_HandleTypeDef
#else
typedef struct
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
{
I2C_TypeDef *Instance; /*!< I2C registers base address */
I2C_InitTypeDef Init; /*!< I2C communication parameters */
uint8_t *pBuffPtr; /*!< Pointer to I2C transfer buffer */
uint16_t XferSize; /*!< I2C transfer size */
__IO uint16_t XferCount; /*!< I2C transfer counter */
__IO uint32_t XferOptions; /*!< I2C transfer options */
__IO uint32_t PreviousState; /*!< I2C communication Previous state and mode
context for internal usage */
DMA_HandleTypeDef *hdmatx; /*!< I2C Tx DMA handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< I2C Rx DMA handle parameters */
HAL_LockTypeDef Lock; /*!< I2C locking object */
__IO HAL_I2C_StateTypeDef State; /*!< I2C communication state */
__IO HAL_I2C_ModeTypeDef Mode; /*!< I2C communication mode */
__IO uint32_t ErrorCode; /*!< I2C Error code */
__IO uint32_t Devaddress; /*!< I2C Target device address */
__IO uint32_t Memaddress; /*!< I2C Target memory address */
__IO uint32_t MemaddSize; /*!< I2C Target memory address size */
__IO uint32_t EventCount; /*!< I2C Event counter */
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
void (* MasterTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Master Tx Transfer completed callback */
void (* MasterRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Master Rx Transfer completed callback */
void (* SlaveTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Slave Tx Transfer completed callback */
void (* SlaveRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Slave Rx Transfer completed callback */
void (* ListenCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Listen Complete callback */
void (* MemTxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Memory Tx Transfer completed callback */
void (* MemRxCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Memory Rx Transfer completed callback */
void (* ErrorCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Error callback */
void (* AbortCpltCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Abort callback */
void (* AddrCallback)(struct __I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); /*!< I2C Slave Address Match callback */
void (* MspInitCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Msp Init callback */
void (* MspDeInitCallback)(struct __I2C_HandleTypeDef *hi2c); /*!< I2C Msp DeInit callback */
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
} I2C_HandleTypeDef;
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
/**
* @brief HAL I2C Callback ID enumeration definition
*/
typedef enum
{
HAL_I2C_MASTER_TX_COMPLETE_CB_ID = 0x00U, /*!< I2C Master Tx Transfer completed callback ID */
HAL_I2C_MASTER_RX_COMPLETE_CB_ID = 0x01U, /*!< I2C Master Rx Transfer completed callback ID */
HAL_I2C_SLAVE_TX_COMPLETE_CB_ID = 0x02U, /*!< I2C Slave Tx Transfer completed callback ID */
HAL_I2C_SLAVE_RX_COMPLETE_CB_ID = 0x03U, /*!< I2C Slave Rx Transfer completed callback ID */
HAL_I2C_LISTEN_COMPLETE_CB_ID = 0x04U, /*!< I2C Listen Complete callback ID */
HAL_I2C_MEM_TX_COMPLETE_CB_ID = 0x05U, /*!< I2C Memory Tx Transfer callback ID */
HAL_I2C_MEM_RX_COMPLETE_CB_ID = 0x06U, /*!< I2C Memory Rx Transfer completed callback ID */
HAL_I2C_ERROR_CB_ID = 0x07U, /*!< I2C Error callback ID */
HAL_I2C_ABORT_CB_ID = 0x08U, /*!< I2C Abort callback ID */
HAL_I2C_MSPINIT_CB_ID = 0x09U, /*!< I2C Msp Init callback ID */
HAL_I2C_MSPDEINIT_CB_ID = 0x0AU /*!< I2C Msp DeInit callback ID */
} HAL_I2C_CallbackIDTypeDef;
/**
* @brief HAL I2C Callback pointer definition
*/
typedef void (*pI2C_CallbackTypeDef)(I2C_HandleTypeDef *hi2c); /*!< pointer to an I2C callback function */
typedef void (*pI2C_AddrCallbackTypeDef)(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); /*!< pointer to an I2C Address Match callback function */
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
/**
* @}
*/
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup I2C_Exported_Constants I2C Exported Constants
* @{
*/
/** @defgroup I2C_duty_cycle_in_fast_mode I2C duty cycle in fast mode
* @{
*/
#define I2C_DUTYCYCLE_2 0x00000000U
#define I2C_DUTYCYCLE_16_9 I2C_CCR_DUTY
/**
* @}
*/
/** @defgroup I2C_addressing_mode I2C addressing mode
* @{
*/
#define I2C_ADDRESSINGMODE_7BIT 0x00004000U
#define I2C_ADDRESSINGMODE_10BIT (I2C_OAR1_ADDMODE | 0x00004000U)
/**
* @}
*/
/** @defgroup I2C_dual_addressing_mode I2C dual addressing mode
* @{
*/
#define I2C_DUALADDRESS_DISABLE 0x00000000U
#define I2C_DUALADDRESS_ENABLE I2C_OAR2_ENDUAL
/**
* @}
*/
/** @defgroup I2C_general_call_addressing_mode I2C general call addressing mode
* @{
*/
#define I2C_GENERALCALL_DISABLE 0x00000000U
#define I2C_GENERALCALL_ENABLE I2C_CR1_ENGC
/**
* @}
*/
/** @defgroup I2C_nostretch_mode I2C nostretch mode
* @{
*/
#define I2C_NOSTRETCH_DISABLE 0x00000000U
#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH
/**
* @}
*/
/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size
* @{
*/
#define I2C_MEMADD_SIZE_8BIT 0x00000001U
#define I2C_MEMADD_SIZE_16BIT 0x00000010U
/**
* @}
*/
/** @defgroup I2C_XferDirection_definition I2C XferDirection definition
* @{
*/
#define I2C_DIRECTION_RECEIVE 0x00000000U
#define I2C_DIRECTION_TRANSMIT 0x00000001U
/**
* @}
*/
/** @defgroup I2C_XferOptions_definition I2C XferOptions definition
* @{
*/
#define I2C_FIRST_FRAME 0x00000001U
#define I2C_FIRST_AND_NEXT_FRAME 0x00000002U
#define I2C_NEXT_FRAME 0x00000004U
#define I2C_FIRST_AND_LAST_FRAME 0x00000008U
#define I2C_LAST_FRAME_NO_STOP 0x00000010U
#define I2C_LAST_FRAME 0x00000020U
/* List of XferOptions in usage of :
* 1- Restart condition in all use cases (direction change or not)
*/
#define I2C_OTHER_FRAME (0x00AA0000U)
#define I2C_OTHER_AND_LAST_FRAME (0xAA000000U)
/**
* @}
*/
/** @defgroup I2C_Interrupt_configuration_definition I2C Interrupt configuration definition
* @brief I2C Interrupt definition
* Elements values convention: 0xXXXXXXXX
* - XXXXXXXX : Interrupt control mask
* @{
*/
#define I2C_IT_BUF I2C_CR2_ITBUFEN
#define I2C_IT_EVT I2C_CR2_ITEVTEN
#define I2C_IT_ERR I2C_CR2_ITERREN
/**
* @}
*/
/** @defgroup I2C_Flag_definition I2C Flag definition
* @{
*/
#define I2C_FLAG_OVR 0x00010800U
#define I2C_FLAG_AF 0x00010400U
#define I2C_FLAG_ARLO 0x00010200U
#define I2C_FLAG_BERR 0x00010100U
#define I2C_FLAG_TXE 0x00010080U
#define I2C_FLAG_RXNE 0x00010040U
#define I2C_FLAG_STOPF 0x00010010U
#define I2C_FLAG_ADD10 0x00010008U
#define I2C_FLAG_BTF 0x00010004U
#define I2C_FLAG_ADDR 0x00010002U
#define I2C_FLAG_SB 0x00010001U
#define I2C_FLAG_DUALF 0x00100080U
#define I2C_FLAG_GENCALL 0x00100010U
#define I2C_FLAG_TRA 0x00100004U
#define I2C_FLAG_BUSY 0x00100002U
#define I2C_FLAG_MSL 0x00100001U
/**
* @}
*/
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup I2C_Exported_Macros I2C Exported Macros
* @{
*/
/** @brief Reset I2C handle state.
* @param __HANDLE__ specifies the I2C Handle.
* @retval None
*/
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) do{ \
(__HANDLE__)->State = HAL_I2C_STATE_RESET; \
(__HANDLE__)->MspInitCallback = NULL; \
(__HANDLE__)->MspDeInitCallback = NULL; \
} while(0)
#else
#define __HAL_I2C_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_I2C_STATE_RESET)
#endif
/** @brief Enable or disable the specified I2C interrupts.
* @param __HANDLE__ specifies the I2C Handle.
* @param __INTERRUPT__ specifies the interrupt source to enable or disable.
* This parameter can be one of the following values:
* @arg I2C_IT_BUF: Buffer interrupt enable
* @arg I2C_IT_EVT: Event interrupt enable
* @arg I2C_IT_ERR: Error interrupt enable
* @retval None
*/
#define __HAL_I2C_ENABLE_IT(__HANDLE__, __INTERRUPT__) SET_BIT((__HANDLE__)->Instance->CR2,(__INTERRUPT__))
#define __HAL_I2C_DISABLE_IT(__HANDLE__, __INTERRUPT__) CLEAR_BIT((__HANDLE__)->Instance->CR2, (__INTERRUPT__))
/** @brief Checks if the specified I2C interrupt source is enabled or disabled.
* @param __HANDLE__ specifies the I2C Handle.
* @param __INTERRUPT__ specifies the I2C interrupt source to check.
* This parameter can be one of the following values:
* @arg I2C_IT_BUF: Buffer interrupt enable
* @arg I2C_IT_EVT: Event interrupt enable
* @arg I2C_IT_ERR: Error interrupt enable
* @retval The new state of __INTERRUPT__ (TRUE or FALSE).
*/
#define __HAL_I2C_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->CR2 & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)
/** @brief Checks whether the specified I2C flag is set or not.
* @param __HANDLE__ specifies the I2C Handle.
* @param __FLAG__ specifies the flag to check.
* This parameter can be one of the following values:
* @arg I2C_FLAG_OVR: Overrun/Underrun flag
* @arg I2C_FLAG_AF: Acknowledge failure flag
* @arg I2C_FLAG_ARLO: Arbitration lost flag
* @arg I2C_FLAG_BERR: Bus error flag
* @arg I2C_FLAG_TXE: Data register empty flag
* @arg I2C_FLAG_RXNE: Data register not empty flag
* @arg I2C_FLAG_STOPF: Stop detection flag
* @arg I2C_FLAG_ADD10: 10-bit header sent flag
* @arg I2C_FLAG_BTF: Byte transfer finished flag
* @arg I2C_FLAG_ADDR: Address sent flag
* Address matched flag
* @arg I2C_FLAG_SB: Start bit flag
* @arg I2C_FLAG_DUALF: Dual flag
* @arg I2C_FLAG_GENCALL: General call header flag
* @arg I2C_FLAG_TRA: Transmitter/Receiver flag
* @arg I2C_FLAG_BUSY: Bus busy flag
* @arg I2C_FLAG_MSL: Master/Slave flag
* @retval The new state of __FLAG__ (TRUE or FALSE).
*/
#define __HAL_I2C_GET_FLAG(__HANDLE__, __FLAG__) ((((uint8_t)((__FLAG__) >> 16U)) == 0x01U) ? \
(((((__HANDLE__)->Instance->SR1) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET) : \
(((((__HANDLE__)->Instance->SR2) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET))
/** @brief Clears the I2C pending flags which are cleared by writing 0 in a specific bit.
* @param __HANDLE__ specifies the I2C Handle.
* @param __FLAG__ specifies the flag to clear.
* This parameter can be any combination of the following values:
* @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode)
* @arg I2C_FLAG_AF: Acknowledge failure flag
* @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode)
* @arg I2C_FLAG_BERR: Bus error flag
* @retval None
*/
#define __HAL_I2C_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR1 = ~((__FLAG__) & I2C_FLAG_MASK))
/** @brief Clears the I2C ADDR pending flag.
* @param __HANDLE__ specifies the I2C Handle.
* This parameter can be I2C where x: 1, 2, or 3 to select the I2C peripheral.
* @retval None
*/
#define __HAL_I2C_CLEAR_ADDRFLAG(__HANDLE__) \
do{ \
__IO uint32_t tmpreg = 0x00U; \
tmpreg = (__HANDLE__)->Instance->SR1; \
tmpreg = (__HANDLE__)->Instance->SR2; \
UNUSED(tmpreg); \
} while(0)
/** @brief Clears the I2C STOPF pending flag.
* @param __HANDLE__ specifies the I2C Handle.
* @retval None
*/
#define __HAL_I2C_CLEAR_STOPFLAG(__HANDLE__) \
do{ \
__IO uint32_t tmpreg = 0x00U; \
tmpreg = (__HANDLE__)->Instance->SR1; \
SET_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE); \
UNUSED(tmpreg); \
} while(0)
/** @brief Enable the specified I2C peripheral.
* @param __HANDLE__ specifies the I2C Handle.
* @retval None
*/
#define __HAL_I2C_ENABLE(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE)
/** @brief Disable the specified I2C peripheral.
* @param __HANDLE__ specifies the I2C Handle.
* @retval None
*/
#define __HAL_I2C_DISABLE(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CR1, I2C_CR1_PE)
/**
* @}
*/
/* Include I2C HAL Extension module */
#include "stm32f4xx_hal_i2c_ex.h"
/* Exported functions --------------------------------------------------------*/
/** @addtogroup I2C_Exported_Functions
* @{
*/
/** @addtogroup I2C_Exported_Functions_Group1 Initialization and de-initialization functions
* @{
*/
/* Initialization and de-initialization functions******************************/
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c);
/* Callbacks Register/UnRegister functions ***********************************/
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
HAL_StatusTypeDef HAL_I2C_RegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID, pI2C_CallbackTypeDef pCallback);
HAL_StatusTypeDef HAL_I2C_UnRegisterCallback(I2C_HandleTypeDef *hi2c, HAL_I2C_CallbackIDTypeDef CallbackID);
HAL_StatusTypeDef HAL_I2C_RegisterAddrCallback(I2C_HandleTypeDef *hi2c, pI2C_AddrCallbackTypeDef pCallback);
HAL_StatusTypeDef HAL_I2C_UnRegisterAddrCallback(I2C_HandleTypeDef *hi2c);
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
/**
* @}
*/
/** @addtogroup I2C_Exported_Functions_Group2 Input and Output operation functions
* @{
*/
/* IO operation functions ****************************************************/
/******* Blocking mode: Polling */
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout);
/******* Non-Blocking mode: Interrupt */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress);
/******* Non-Blocking mode: DMA */
HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
/**
* @}
*/
/** @addtogroup I2C_IRQ_Handler_and_Callbacks IRQ Handler and Callbacks
* @{
*/
/******* I2C IRQHandler and Callbacks used in non blocking modes (Interrupt and DMA) */
void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c);
void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode);
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c);
/**
* @}
*/
/** @addtogroup I2C_Exported_Functions_Group3 Peripheral State, Mode and Error functions
* @{
*/
/* Peripheral State, Mode and Error functions *********************************/
HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c);
HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c);
uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup I2C_Private_Constants I2C Private Constants
* @{
*/
#define I2C_FLAG_MASK 0x0000FFFFU
#define I2C_MIN_PCLK_FREQ_STANDARD 2000000U /*!< 2 MHz */
#define I2C_MIN_PCLK_FREQ_FAST 4000000U /*!< 4 MHz */
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup I2C_Private_Macros I2C Private Macros
* @{
*/
#define I2C_MIN_PCLK_FREQ(__PCLK__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD) : ((__PCLK__) < I2C_MIN_PCLK_FREQ_FAST))
#define I2C_CCR_CALCULATION(__PCLK__, __SPEED__, __COEFF__) (((((__PCLK__) - 1U)/((__SPEED__) * (__COEFF__))) + 1U) & I2C_CCR_CCR)
#define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U)
#define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U))
#define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) ((I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U) < 4U)? 4U:I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U))
#define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 3U) : (I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 25U) | I2C_DUTYCYCLE_16_9))
#define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \
((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \
((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS))
#define I2C_7BIT_ADD_WRITE(__ADDRESS__) ((uint8_t)((__ADDRESS__) & (uint8_t)(~I2C_OAR1_ADD0)))
#define I2C_7BIT_ADD_READ(__ADDRESS__) ((uint8_t)((__ADDRESS__) | I2C_OAR1_ADD0))
#define I2C_10BIT_ADDRESS(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF)))
#define I2C_10BIT_HEADER_WRITE(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)0x00F0)))
#define I2C_10BIT_HEADER_READ(__ADDRESS__) ((uint8_t)((uint16_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0x0300)) >> 7) | (uint16_t)(0x00F1))))
#define I2C_MEM_ADD_MSB(__ADDRESS__) ((uint8_t)((uint16_t)(((uint16_t)((__ADDRESS__) & (uint16_t)0xFF00)) >> 8)))
#define I2C_MEM_ADD_LSB(__ADDRESS__) ((uint8_t)((uint16_t)((__ADDRESS__) & (uint16_t)0x00FF)))
/** @defgroup I2C_IS_RTC_Definitions I2C Private macros to check input parameters
* @{
*/
#define IS_I2C_DUTY_CYCLE(CYCLE) (((CYCLE) == I2C_DUTYCYCLE_2) || \
((CYCLE) == I2C_DUTYCYCLE_16_9))
#define IS_I2C_ADDRESSING_MODE(ADDRESS) (((ADDRESS) == I2C_ADDRESSINGMODE_7BIT) || \
((ADDRESS) == I2C_ADDRESSINGMODE_10BIT))
#define IS_I2C_DUAL_ADDRESS(ADDRESS) (((ADDRESS) == I2C_DUALADDRESS_DISABLE) || \
((ADDRESS) == I2C_DUALADDRESS_ENABLE))
#define IS_I2C_GENERAL_CALL(CALL) (((CALL) == I2C_GENERALCALL_DISABLE) || \
((CALL) == I2C_GENERALCALL_ENABLE))
#define IS_I2C_NO_STRETCH(STRETCH) (((STRETCH) == I2C_NOSTRETCH_DISABLE) || \
((STRETCH) == I2C_NOSTRETCH_ENABLE))
#define IS_I2C_MEMADD_SIZE(SIZE) (((SIZE) == I2C_MEMADD_SIZE_8BIT) || \
((SIZE) == I2C_MEMADD_SIZE_16BIT))
#define IS_I2C_CLOCK_SPEED(SPEED) (((SPEED) > 0U) && ((SPEED) <= 400000U))
#define IS_I2C_OWN_ADDRESS1(ADDRESS1) (((ADDRESS1) & 0xFFFFFC00U) == 0U)
#define IS_I2C_OWN_ADDRESS2(ADDRESS2) (((ADDRESS2) & 0xFFFFFF01U) == 0U)
#define IS_I2C_TRANSFER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_FIRST_FRAME) || \
((REQUEST) == I2C_FIRST_AND_NEXT_FRAME) || \
((REQUEST) == I2C_NEXT_FRAME) || \
((REQUEST) == I2C_FIRST_AND_LAST_FRAME) || \
((REQUEST) == I2C_LAST_FRAME) || \
((REQUEST) == I2C_LAST_FRAME_NO_STOP) || \
IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(REQUEST))
#define IS_I2C_TRANSFER_OTHER_OPTIONS_REQUEST(REQUEST) (((REQUEST) == I2C_OTHER_FRAME) || \
((REQUEST) == I2C_OTHER_AND_LAST_FRAME))
#define I2C_CHECK_FLAG(__ISR__, __FLAG__) ((((__ISR__) & ((__FLAG__) & I2C_FLAG_MASK)) == ((__FLAG__) & I2C_FLAG_MASK)) ? SET : RESET)
#define I2C_CHECK_IT_SOURCE(__CR1__, __IT__) ((((__CR1__) & (__IT__)) == (__IT__)) ? SET : RESET)
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup I2C_Private_Functions I2C Private Functions
* @{
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_HAL_I2C_H */

View File

@@ -0,0 +1,115 @@
/**
******************************************************************************
* @file stm32f4xx_hal_i2c_ex.h
* @author MCD Application Team
* @brief Header file of I2C HAL Extension module.
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_I2C_EX_H
#define __STM32F4xx_HAL_I2C_EX_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF)
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal_def.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @addtogroup I2CEx
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup I2CEx_Exported_Constants I2C Exported Constants
* @{
*/
/** @defgroup I2CEx_Analog_Filter I2C Analog Filter
* @{
*/
#define I2C_ANALOGFILTER_ENABLE 0x00000000U
#define I2C_ANALOGFILTER_DISABLE I2C_FLTR_ANOFF
/**
* @}
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup I2CEx_Exported_Functions
* @{
*/
/** @addtogroup I2CEx_Exported_Functions_Group1
* @{
*/
/* Peripheral Control functions ************************************************/
HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter);
HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter);
/**
* @}
*/
/**
* @}
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup I2CEx_Private_Constants I2C Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup I2CEx_Private_Macros I2C Private Macros
* @{
*/
#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_ANALOGFILTER_ENABLE) || \
((FILTER) == I2C_ANALOGFILTER_DISABLE))
#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000FU)
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_HAL_I2C_EX_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
/**
******************************************************************************
* @file stm32f4xx_hal_i2c_ex.c
* @author MCD Application Team
* @brief I2C Extension HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of I2C extension peripheral:
* + Extension features functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### I2C peripheral extension features #####
==============================================================================
[..] Comparing to other previous devices, the I2C interface for STM32F427xx/437xx/
429xx/439xx devices contains the following additional features :
(+) Possibility to disable or enable Analog Noise Filter
(+) Use of a configured Digital Noise Filter
##### How to use this driver #####
==============================================================================
[..] This driver provides functions to configure Noise Filter
(#) Configure I2C Analog noise filter using the function HAL_I2C_AnalogFilter_Config()
(#) Configure I2C Digital noise filter using the function HAL_I2C_DigitalFilter_Config()
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/** @addtogroup STM32F4xx_HAL_Driver
* @{
*/
/** @defgroup I2CEx I2CEx
* @brief I2C HAL module driver
* @{
*/
#ifdef HAL_I2C_MODULE_ENABLED
#if defined(I2C_FLTR_ANOFF)&&defined(I2C_FLTR_DNF)
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup I2CEx_Exported_Functions I2C Exported Functions
* @{
*/
/** @defgroup I2CEx_Exported_Functions_Group1 Extension features functions
* @brief Extension features functions
*
@verbatim
===============================================================================
##### Extension features functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Configure Noise Filters
@endverbatim
* @{
*/
/**
* @brief Configures I2C Analog noise filter.
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2Cx peripheral.
* @param AnalogFilter new state of the Analog filter.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter)
{
/* Check the parameters */
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter));
if (hi2c->State == HAL_I2C_STATE_READY)
{
hi2c->State = HAL_I2C_STATE_BUSY;
/* Disable the selected I2C peripheral */
__HAL_I2C_DISABLE(hi2c);
/* Reset I2Cx ANOFF bit */
hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF);
/* Disable the analog filter */
hi2c->Instance->FLTR |= AnalogFilter;
__HAL_I2C_ENABLE(hi2c);
hi2c->State = HAL_I2C_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Configures I2C Digital noise filter.
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2Cx peripheral.
* @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter)
{
uint16_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter));
if (hi2c->State == HAL_I2C_STATE_READY)
{
hi2c->State = HAL_I2C_STATE_BUSY;
/* Disable the selected I2C peripheral */
__HAL_I2C_DISABLE(hi2c);
/* Get the old register value */
tmpreg = hi2c->Instance->FLTR;
/* Reset I2Cx DNF bit [3:0] */
tmpreg &= ~(I2C_FLTR_DNF);
/* Set I2Cx DNF coefficient */
tmpreg |= DigitalFilter;
/* Store the new register value */
hi2c->Instance->FLTR = tmpreg;
__HAL_I2C_ENABLE(hi2c);
hi2c->State = HAL_I2C_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @}
*/
/**
* @}
*/
#endif
#endif /* HAL_I2C_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/