网络通,测试flash

This commit is contained in:
2026-07-17 15:16:29 +08:00
parent c8c7ec0992
commit 3466c4c062
19 changed files with 4411 additions and 26 deletions

67
AGENTS.md Normal file
View File

@@ -0,0 +1,67 @@
# STM32F4-Base
## 项目概述
STM32F407ZGTx (Cortex-M4 FPU) 基础固件项目,集成 CH395F 以太网控制器 SPI 驱动CH395F 自带 MAC+PHY 及 TCP/IP 协议栈固件)。
## 关键文件
| 路径 | 说明 |
|---|---|
| `Src/main.c` | 程序入口,初始化序列及主循环 |
| `Src/ch395f.c` / `Inc/ch395f.h` | CH395F 以太网芯片 SPI 驱动(核心自定义代码) |
| `MDK-ARM/STM32F407-Demo.uvprojx` | Keil MDK 项目文件 |
| `STM32F407-Demo.ioc` | STM32CubeMX 项目源文件 |
## 构建
仅支持 Keil MDK-ARM v5 (ARMCC)。打开 `MDK-ARM/STM32F407-Demo.uvprojx` 编译。
- 编译器ARMCC V5.06 update 7
- 优化等级:`-O4` (项目级)`spi.c`/`usart.c` / HAL 源文件使用 `-O0`
- C 标准C99
- 全局宏定义:`USE_HAL_DRIVER, STM32F407xx`
## 硬件配置
- **主频:** HSE 25MHz → PLL 168MHz (4/168/2)
- **6 个 LED** PC4, PC5, PB1, PB2, PF11, PF12低电平点亮
- **CH395F** SPI2 (PB12 CS, PB13 SCK, PB14 SDO, PB15 SDI)
- **USART1** PA9 TX, PA10 RX (115200bps)
## 启动顺序
```
HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_USART1_UART_Init() → MX_SPI2_Init() → ch395f_reset() → ch395f_init()
```
## 代码规范
参考 `嵌入式C语言代码规范V1.0.md`,关键要点:
- 缩进4 空格,禁止 Tab
- 命名:小写字母+下划线;全局变量 `g_` 前缀,静态 `s_`,指针 `p_`,数组 `a_`
- 函数注释块需包含:函数功能、入口参数、返回值、限定条件、函数说明
- 大括号K&R 风格(左大括号不换行)
## 注意
- `Inc/``Src/` 中 CubeMX 生成的文件gpio, spi, usart, stm32f4xx_it, main 的骨架)带有 `USER CODE BEGIN`/`END` 标记,自定义代码应写在这些区域之间以免被 CubeMX 重新生成时覆盖
- `ch395f.c`/`ch395f.h` 为纯手工代码,不受 CubeMX 保护
- 每次 SPI 事务需调用 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹
- CH395F 命令执行时序参考 `ch395f.h` 中命令码注释及 `CH395F.md`
## 已知问题
### CH395F 与 RTL8305NBI 自动协商不兼容
CH395F 与 RTL8305NBI-CG 直连(经网络变压器)时,自动协商始终失败(返回 `PHY_DISCONN`),但强制 100M 全双工工作正常。强制 10M 全双工同样失败。
**诊断结果:**
- Auto-Neg: `0x01 (DISCONNECTED)`
- Force 100M-FULL: `0x08 (LINK OK)`
- Force 10M-FULL: `0x01 (DISCONNECTED)`
**解决方案:** 初始化协议栈后调用 `ch395f_set_phy(CH395F_PHY_100M_FULL)` 跳过自动协商。
**推测根因:** 不同厂家 PHY 直连时的自动协商实现差异CH395F WCH 固件 vs RTL8305NBI Realtek 硬件),物理层正常。

View File

@@ -0,0 +1,35 @@
/**
******************************************************************************
* @file fal_cfg.h
* @brief FAL 配置Flash 设备表 + 分区表
******************************************************************************
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#define FAL_DEBUG 0
#define FAL_PART_HAS_TABLE_CFG
/* ===================== Flash 设备表 ===================== */
extern const struct fal_flash_dev gd5f2gq5ue_flash;
#define FAL_FLASH_DEV_TABLE \
{ \
&gd5f2gq5ue_flash, \
}
/* ===================== 分区表 ===================== */
/* 分区名称 设备名称 偏移 大小 */
/* 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}, \
}
#endif
#endif /* _FAL_CFG_H_ */

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* @file fal_flash_gd5f2gq5ue.c
* @brief FAL 端口GD5F2GQ5UE SPI NAND Flash 适配层
******************************************************************************
*/
#include "fal_def.h"
#include "gd5f2gq5ue.h"
/* ===================== FAL Flash 设备操作函数 ===================== */
static int gd5f_fal_init(void)
{
return gd5f2gq5ue_init();
}
static int gd5f_fal_read(long offset, uint8_t *buf, size_t size)
{
return gd5f2gq5ue_read(offset, buf, size);
}
static int gd5f_fal_write(long offset, const uint8_t *buf, size_t size)
{
return gd5f2gq5ue_write(offset, buf, size);
}
static int gd5f_fal_erase(long offset, size_t size)
{
return gd5f2gq5ue_erase(offset, size);
}
/* ===================== FAL Flash 设备定义 ===================== */
const struct fal_flash_dev gd5f2gq5ue_flash = {
.name = "gd5f2gq5ue",
.addr = 0,
.len = GD5F_TOTAL_SIZE, /* 256MB */
.blk_size = GD5F_BLOCK_SIZE, /* 128KB */
.ops = {
.init = gd5f_fal_init,
.read = gd5f_fal_read,
.write = gd5f_fal_write,
.erase = gd5f_fal_erase,
},
.write_gran = 8,
};

View File

@@ -0,0 +1,32 @@
/**
******************************************************************************
* @file fdb_cfg.h
* @brief FlashDB 配置文件
******************************************************************************
*/
#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_
/* 启用 KVDB键值数据库 */
#define FDB_USING_KVDB
#ifdef FDB_USING_KVDB
/* 当 KVDB 版本号变化时自动更新到最新默认值 */
/* #define FDB_KV_AUTO_UPDATE */
#endif
/* 启用 TSDB时序数据库 */
#define FDB_USING_TSDB
/* 使用 FAL 存储模式(非文件模式) */
#define FDB_USING_FAL_MODE
/* Flash 写入粒度单位bit
* STM32F4 = 8字节可编程 */
#define FDB_WRITE_GRAN 8
/* 调试输出 */
#define FDB_DEBUG_ENABLE
#endif /* _FDB_CFG_H_ */

View File

@@ -0,0 +1,367 @@
/**
******************************************************************************
* @file gd5f2gq5ue.c
* @brief GD5F2GQ5UE SPI NAND Flash 驱动实现
******************************************************************************
*/
#include "gd5f2gq5ue.h"
#include <string.h>
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;
}
/**
* @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 超时
*/
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();
while (1) {
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_tx(&addr, 1);
gd5f_spi_rx(&status, 1);
GD5F_CS_HIGH();
if ((status & GD5F_STATUS_OIP) == 0) {
return GD5F_OK;
}
if ((HAL_GetTick() - tickstart) >= timeout_ms) {
return GD5F_BUSY_TIMEOUT;
}
}
}
/**
* @brief 写使能
*/
static int gd5f_write_enable(void)
{
uint8_t cmd = GD5F_CMD_WRITE_ENABLE;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 读取状态寄存器
*/
static int gd5f_read_status(uint8_t *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);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页读取到缓存Page Read to Cache
* @param page_addr: 页地址(行地址,包含 block + page
*/
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);
GD5F_CS_HIGH();
return gd5f_wait_busy(100);
}
/**
* @brief 从缓存读取数据Read from Cache
* @param column: 列地址(页内偏移)
* @param buf: 数据缓冲区
* @param size: 读取字节数
*/
static int gd5f_read_from_cache(uint16_t column, uint8_t *buf, size_t size)
{
uint8_t cmd[5];
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
cmd[1] = (column >> 8) & 0xFF;
cmd[2] = column & 0xFF;
cmd[3] = 0x00; /* dummy byte */
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
gd5f_spi_rx(buf, size);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页编程(从缓存写入阵列)
* @param page_addr: 页地址
* @param column: 列地址
* @param buf: 数据缓冲区
* @param size: 写入字节数
*/
static int gd5f_page_program(uint32_t page_addr, uint16_t column, const uint8_t *buf, size_t size)
{
int ret;
uint8_t cmd[4];
/* 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);
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);
GD5F_CS_HIGH();
/* 4. 等待完成 */
ret = gd5f_wait_busy(1000);
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)
*/
static int gd5f_block_erase(uint32_t block_addr)
{
int ret;
uint8_t cmd[4];
/* 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;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
GD5F_CS_HIGH();
/* 3. 等待完成(擦除较慢) */
ret = gd5f_wait_busy(5000);
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;
}
/* ===================== 公共接口实现 ===================== */
int gd5f2gq5ue_init(void)
{
int ret;
uint8_t mid, did;
/* 确保控制引脚处于非激活状态 */
GD5F_CS_HIGH();
GD5F_WP_HIGH();
GD5F_HOLD_HIGH();
/* 小延时等待上电稳定 */
HAL_Delay(10);
/* 复位芯片 */
ret = gd5f2gq5ue_reset();
if (ret != GD5F_OK) return ret;
HAL_Delay(5);
/* 读取 ID 验证通信 */
ret = gd5f2gq5ue_read_id(&mid, &did);
if (ret != GD5F_OK) return ret;
if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) {
return GD5F_ID_MISMATCH;
}
return GD5F_OK;
}
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did)
{
uint8_t cmd = GD5F_CMD_READ_ID;
uint8_t id_buf[3];
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_rx(id_buf, 3); /* dummy + MID + DID */
GD5F_CS_HIGH();
*mid = id_buf[1]; /* id_buf[0] = dummy */
*did = id_buf[2];
return GD5F_OK;
}
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size)
{
int ret;
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 */
ret = gd5f_page_read(page_addr);
if (ret != GD5F_OK) return ret;
/* Read from Cache */
ret = gd5f_read_from_cache(column, buf, bytes);
if (ret != GD5F_OK) return ret;
offset += bytes;
buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size)
{
int ret;
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;
offset += bytes;
buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
int gd5f2gq5ue_erase(long offset, size_t size)
{
int ret;
/* 擦除起始地址必须块对齐 */
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;
offset += GD5F_BLOCK_SIZE;
size -= GD5F_BLOCK_SIZE;
}
return GD5F_OK;
}
int gd5f2gq5ue_reset(void)
{
uint8_t cmd = GD5F_CMD_RESET;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
GD5F_CS_HIGH();
HAL_Delay(5);
return GD5F_OK;
}

View File

@@ -0,0 +1,133 @@
/**
******************************************************************************
* @file gd5f2gq5ue.h
* @brief GD5F2GQ5UE SPI NAND Flash 驱动头文件
******************************************************************************
*/
#ifndef __GD5F2GQ5UE_H
#define __GD5F2GQ5UE_H
#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 命令码 ===================== */
#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_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_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 错误高位 */
/* ===================== Feature 位定义 ===================== */
#define GD5F_FEATURE_ECC_EN (1 << 4)
#define GD5F_FEATURE_QE (1 << 0) /* Quad Enable, B0[0] */
/* ===================== 芯片参数 ===================== */
#define GD5F_PAGE_SIZE 2048 /* 主数据区字节数 */
#define GD5F_SPARE_SIZE 64 /* ECC 启用时 spare 区 */
#define GD5F_TOTAL_PAGE_SIZE 2112 /* 2048 + 64 */
#define GD5F_PAGES_PER_BLOCK 64
#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) /* 128KB */
#define GD5F_TOTAL_BLOCKS 2048
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 256MB */
/* 制造商 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
#define GD5F_ECC_ERROR -3
#define GD5F_PROGRAM_FAIL -4
#define GD5F_ERASE_FAIL -5
#define GD5F_ID_MISMATCH -6
/* ===================== 公共接口函数 ===================== */
/**
* @brief 初始化 GD5F2GQ5UESPI + GPIO + 读 ID 验证)
* @retval GD5F_OK 成功, 其他为错误码
*/
int gd5f2gq5ue_init(void);
/**
* @brief 读取芯片 IDMID + DID
* @param mid: 制造商 ID 输出指针
* @param did: 设备 ID 输出指针
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did);
/**
* @brief 从 NAND 读取数据(支持跨页)
* @param offset: 起始字节偏移(相对于 Flash 起始地址)
* @param buf: 数据缓冲区
* @param size: 读取字节数
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size);
/**
* @brief 向 NAND 写入数据(支持跨页)
* @param offset: 起始字节偏移
* @param buf: 数据缓冲区
* @param size: 写入字节数
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size);
/**
* @brief 擦除块(按块擦除,最小单位 128KB
* @param offset: 起始字节偏移(必须块对齐)
* @param size: 擦除字节数(必须为块大小的整数倍)
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_erase(long offset, size_t size);
/**
* @brief 复位芯片
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_reset(void);
#ifdef __cplusplus
}
#endif
#endif /* __GD5F2GQ5UE_H */

1843
GD5F2GQ5UExxG.md Normal file

File diff suppressed because one or more lines are too long

View File

@@ -81,6 +81,18 @@ void Error_Handler(void);
#define ST_TX0_GPIO_Port GPIOA
#define ST_RX0_Pin GPIO_PIN_10
#define ST_RX0_GPIO_Port GPIOA
#define GD_SCLK_Pin GPIO_PIN_3
#define GD_SCLK_GPIO_Port GPIOB
#define GD_SO_Pin GPIO_PIN_4
#define GD_SO_GPIO_Port GPIOB
#define GD_SI_Pin GPIO_PIN_5
#define GD_SI_GPIO_Port GPIOB
#define GD_WP_Pin GPIO_PIN_8
#define GD_WP_GPIO_Port GPIOB
#define GD_CS_Pin GPIO_PIN_0
#define GD_CS_GPIO_Port GPIOE
#define GD_HOLD_Pin GPIO_PIN_1
#define GD_HOLD_GPIO_Port GPIOE
/* USER CODE BEGIN Private defines */

View File

@@ -32,12 +32,15 @@ extern "C" {
/* USER CODE END Includes */
extern SPI_HandleTypeDef hspi1;
extern SPI_HandleTypeDef hspi2;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_SPI1_Init(void);
void MX_SPI2_Init(void);
/* USER CODE BEGIN Prototypes */

1
Lib/FlashDB Submodule

Submodule Lib/FlashDB added at 8236571f6e

1
Lib/fal Submodule

Submodule Lib/fal added at aa02112186

View File

@@ -340,7 +340,7 @@
<MiscControls></MiscControls>
<Define>USE_HAL_DRIVER,STM32F407xx</Define>
<Undefine></Undefine>
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include</IncludePath>
<IncludePath>../Inc;../Drivers/STM32F4xx_HAL_Driver/Inc;../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F4xx/Include;../Drivers/CMSIS/Include;../Drivers/BSP/CH395F;../Drivers/BSP/GD5F2GQ5UE;../Lib/FlashDB/port/fal/inc;../Lib/FlashDB/inc</IncludePath>
</VariousControls>
</Cads>
<Aads>
@@ -516,11 +516,6 @@
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>ch395f.c</FileName>
<FileType>1</FileType>
<FilePath>../Src/ch395f.c</FilePath>
</File>
<File>
<FileName>stm32f4xx_it.c</FileName>
<FileType>1</FileType>
@@ -725,6 +720,66 @@
</File>
</Files>
</Group>
<Group>
<GroupName>Drivers/BSP</GroupName>
<Files>
<File>
<FileName>ch395f.c</FileName>
<FileType>1</FileType>
<FilePath>..\Drivers\BSP\CH395F\ch395f.c</FilePath>
</File>
<File>
<FileName>fal_flash_gd5f2gq5ue.c</FileName>
<FileType>1</FileType>
<FilePath>..\Drivers\BSP\GD5F2GQ5UE\fal_flash_gd5f2gq5ue.c</FilePath>
</File>
<File>
<FileName>gd5f2gq5ue.c</FileName>
<FileType>1</FileType>
<FilePath>..\Drivers\BSP\GD5F2GQ5UE\gd5f2gq5ue.c</FilePath>
</File>
</Files>
</Group>
<Group>
<GroupName>lib/FlashDB</GroupName>
<Files>
<File>
<FileName>fdb.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\src\fdb.c</FilePath>
</File>
<File>
<FileName>fdb_kvdb.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\src\fdb_kvdb.c</FilePath>
</File>
<File>
<FileName>fdb_tsdb.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\src\fdb_tsdb.c</FilePath>
</File>
<File>
<FileName>fdb_utils.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\src\fdb_utils.c</FilePath>
</File>
<File>
<FileName>fal.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\port\fal\src\fal.c</FilePath>
</File>
<File>
<FileName>fal_flash.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\port\fal\src\fal_flash.c</FilePath>
</File>
<File>
<FileName>fal_partition.c</FileName>
<FileType>1</FileType>
<FilePath>..\Lib\FlashDB\port\fal\src\fal_partition.c</FilePath>
</File>
</Files>
</Group>
<Group>
<GroupName>::CMSIS</GroupName>
</Group>
@@ -745,4 +800,13 @@
<files/>
</RTE>
<LayerInfo>
<Layers>
<Layer>
<LayName>STM32F407-Demo</LayName>
<LayPrjMark>1</LayPrjMark>
</Layer>
</Layers>
</LayerInfo>
</Project>

1549
RTL8305NBI-CG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,11 @@ Mcu.CPN=STM32F407ZGT6
Mcu.Family=STM32F4
Mcu.IP0=NVIC
Mcu.IP1=RCC
Mcu.IP2=SPI2
Mcu.IP3=SYS
Mcu.IP4=USART1
Mcu.IPNb=5
Mcu.IP2=SPI1
Mcu.IP3=SPI2
Mcu.IP4=SYS
Mcu.IP5=USART1
Mcu.IPNb=6
Mcu.Name=STM32F407Z(E-G)Tx
Mcu.Package=LQFP144
Mcu.Pin0=PH0-OSC_IN
@@ -23,8 +24,14 @@ Mcu.Pin12=PA9
Mcu.Pin13=PA10
Mcu.Pin14=PA13
Mcu.Pin15=PA14
Mcu.Pin16=VP_SYS_VS_Systick
Mcu.Pin16=PB3
Mcu.Pin17=PB4
Mcu.Pin18=PB5
Mcu.Pin19=PB8
Mcu.Pin2=PC4
Mcu.Pin20=PE0
Mcu.Pin21=PE1
Mcu.Pin22=VP_SYS_VS_Systick
Mcu.Pin3=PC5
Mcu.Pin4=PB1
Mcu.Pin5=PB2
@@ -32,7 +39,7 @@ Mcu.Pin6=PF11
Mcu.Pin7=PF12
Mcu.Pin8=PB12
Mcu.Pin9=PB13
Mcu.PinsNb=17
Mcu.PinsNb=23
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F407ZGTx
@@ -99,6 +106,31 @@ PB2.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
PB2.Locked=true
PB2.PinState=GPIO_PIN_SET
PB2.Signal=GPIO_Output
PB3.GPIOParameters=GPIO_PuPd,GPIO_Label
PB3.GPIO_Label=GD_SCLK
PB3.GPIO_PuPd=GPIO_PULLUP
PB3.Locked=true
PB3.Mode=Full_Duplex_Master
PB3.Signal=SPI1_SCK
PB4.GPIOParameters=GPIO_PuPd,GPIO_Label
PB4.GPIO_Label=GD_SO
PB4.GPIO_PuPd=GPIO_PULLUP
PB4.Locked=true
PB4.Mode=Full_Duplex_Master
PB4.Signal=SPI1_MISO
PB5.GPIOParameters=GPIO_PuPd,GPIO_Label
PB5.GPIO_Label=GD_SI
PB5.GPIO_PuPd=GPIO_PULLUP
PB5.Locked=true
PB5.Mode=Full_Duplex_Master
PB5.Signal=SPI1_MOSI
PB8.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
PB8.GPIO_Label=GD_WP
PB8.GPIO_PuPd=GPIO_PULLUP
PB8.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
PB8.Locked=true
PB8.PinState=GPIO_PIN_SET
PB8.Signal=GPIO_Output
PC4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
PC4.GPIO_Label=LED1
PC4.GPIO_PuPd=GPIO_PULLUP
@@ -121,6 +153,20 @@ PCC.PartNumber=STM32F407ZGTx
PCC.Series=STM32F4
PCC.Temperature=25
PCC.Vdd=3.3
PE0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
PE0.GPIO_Label=GD_CS
PE0.GPIO_PuPd=GPIO_PULLUP
PE0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
PE0.Locked=true
PE0.PinState=GPIO_PIN_SET
PE0.Signal=GPIO_Output
PE1.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
PE1.GPIO_Label=GD_HOLD
PE1.GPIO_PuPd=GPIO_PULLUP
PE1.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
PE1.Locked=true
PE1.PinState=GPIO_PIN_SET
PE1.Signal=GPIO_Output
PF11.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
PF11.GPIO_Label=LED5
PF11.GPIO_PuPd=GPIO_PULLUP
@@ -172,7 +218,7 @@ ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_SPI2_Init-SPI2-false-HAL-true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_SPI2_Init-SPI2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true
RCC.48MHZClocksFreq_Value=84000000
RCC.AHBFreq_Value=168000000
RCC.APB1CLKDivider=RCC_HCLK_DIV4
@@ -206,6 +252,11 @@ RCC.VCOI2SOutputFreq_Value=384000000
RCC.VCOInputFreq_Value=2000000
RCC.VCOOutputFreq_Value=336000000
RCC.VcooutputI2S=192000000
SPI1.CalculateBaudRate=42.0 MBits/s
SPI1.Direction=SPI_DIRECTION_2LINES
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate
SPI1.Mode=SPI_MODE_MASTER
SPI1.VirtualType=VM_MASTER
SPI2.CalculateBaudRate=21.0 MBits/s
SPI2.Direction=SPI_DIRECTION_2LINES
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate

View File

@@ -50,16 +50,20 @@ void MX_GPIO_Init(void)
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, LED1_Pin|LED2_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LED3_Pin|LED4_Pin|CH395_SCS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, LED3_Pin|LED4_Pin|CH395_SCS_Pin|GD_WP_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOF, LED5_Pin|LED6_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GD_CS_Pin|GD_HOLD_Pin, GPIO_PIN_SET);
/*Configure GPIO pins : LED1_Pin LED2_Pin */
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
@@ -88,6 +92,20 @@ void MX_GPIO_Init(void)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(CH395_SCS_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : GD_WP_Pin */
GPIO_InitStruct.Pin = GD_WP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GD_WP_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : GD_CS_Pin GD_HOLD_Pin */
GPIO_InitStruct.Pin = GD_CS_Pin|GD_HOLD_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
/* USER CODE BEGIN 2 */

View File

@@ -27,6 +27,8 @@
#include <string.h>
#include <stdio.h>
#include "ch395f.h"
#include "gd5f2gq5ue.h"
#include "flashdb.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -92,10 +94,93 @@ int main(void)
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_SPI2_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
/* CH395F 初始化 */
char dbg[64];
uint8_t mac[6];
ch395f_reset();
ch395f_init();
/* [1/5] SPI 通信检测 */
sprintf(dbg, "[1/5] CH395F %s\r\n",
(ch395f_check_exist() == CH395F_STATUS_OK) ? "detected" : "ERROR: not detected");
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
/* [2/5] 芯片版本 */
sprintf(dbg, "[2/5] CH395F version: 0x%02X\r\n", ch395f_get_version());
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
/* 配置 IP/网关/掩码 */
{
uint8_t ip[4] = {192, 168, 1, 100};
uint8_t gw[4] = {192, 168, 1, 1};
uint8_t mask[4] = {255, 255, 255, 0};
ch395f_set_ip_addr(ip);
ch395f_set_gwip_addr(gw);
ch395f_set_mask_addr(mask);
}
/* [3/5] 协议栈初始化 */
sprintf(dbg, "[3/5] Protocol stack init %s\r\n",
(ch395f_init() == CH395F_STATUS_OK) ? "OK" : "ERROR");
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
/* [4/5] MAC 地址 */
ch395f_get_mac_addr(mac);
sprintf(dbg, "[4/5] MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
/* [5/5] 强制 100M 全双工后检测 PHY */
ch395f_set_phy(CH395F_PHY_100M_FULL);
HAL_Delay(3000);
{
uint8_t s = ch395f_get_phy_status();
const char *desc = (s == CH395F_PHY_DISCONN) ? "DISCONNECTED" :
(s == CH395F_PHY_100M_FULL) ? "100M FULL" :
(s == CH395F_PHY_100M_HALF) ? "100M HALF" :
(s == CH395F_PHY_10M_FULL) ? "10M FULL" :
(s == CH395F_PHY_10M_HALF) ? "10M HALF" : "RESERVED";
sprintf(dbg, "[5/5] PHY: 0x%02X (%s)\r\n", s, desc);
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
}
/* ===================== FlashDB KVDB 测试 ===================== */
{
uint8_t gd_mid, gd_did;
int ret;
/* 检测 GD5F2GQ5UE */
ret = gd5f2gq5ue_read_id(&gd_mid, &gd_did);
sprintf(dbg, "[GD5F] ID: MID=0x%02X DID=0x%02X %s\r\n",
gd_mid, gd_did,
(ret == GD5F_OK && gd_mid == 0xC8 && gd_did == 0x52) ? "OK" : "FAIL");
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
/* 初始化 FlashDB KVDB */
{
static struct fdb_kvdb kvdb;
ret = fdb_kvdb_init(&kvdb, "db", "fdb_kvdb1", NULL, NULL);
sprintf(dbg, "[FlashDB] KVDB init: %s\r\n",
(ret == FDB_NO_ERR) ? "OK" : "FAIL");
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
if (ret == FDB_NO_ERR) {
/* 写入测试 KV */
fdb_kv_set(&kvdb, "test_key", "hello_flashdb");
HAL_UART_Transmit(&huart1, (uint8_t*)"[FlashDB] KV set OK\r\n", 21, 1000);
/* 读取测试 KV */
char *val = fdb_kv_get(&kvdb, "test_key");
if (val) {
sprintf(dbg, "[FlashDB] KV get: %s\r\n", val);
} else {
sprintf(dbg, "[FlashDB] KV get: NULL\r\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)dbg, strlen(dbg), 1000);
}
}
}
/* USER CODE END 2 */
/* Infinite loop */
@@ -111,7 +196,7 @@ int main(void)
HAL_GPIO_TogglePin(LED4_GPIO_Port, LED4_Pin);
HAL_GPIO_TogglePin(LED5_GPIO_Port, LED5_Pin);
HAL_GPIO_TogglePin(LED6_GPIO_Port, LED6_Pin);
HAL_UART_Transmit(&huart1, str, strlen((char*)str), 1000);
//HAL_UART_Transmit(&huart1, str, strlen((char*)str), 1000);
HAL_Delay(500);
}
/* USER CODE END 3 */

View File

@@ -24,8 +24,41 @@
/* USER CODE END 0 */
SPI_HandleTypeDef hspi1;
SPI_HandleTypeDef hspi2;
/* SPI1 init function */
void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
/* SPI2 init function */
void MX_SPI2_Init(void)
{
@@ -41,10 +74,10 @@ void MX_SPI2_Init(void)
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
@@ -63,7 +96,32 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(spiHandle->Instance==SPI2)
if(spiHandle->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/* SPI1 clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PB3 ------> SPI1_SCK
PB4 ------> SPI1_MISO
PB5 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GD_SCLK_Pin|GD_SO_Pin|GD_SI_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
else if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
@@ -100,7 +158,26 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
if(spiHandle->Instance==SPI2)
if(spiHandle->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspDeInit 0 */
/* USER CODE END SPI1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
/**SPI1 GPIO Configuration
PB3 ------> SPI1_SCK
PB4 ------> SPI1_MISO
PB5 ------> SPI1_MOSI
*/
HAL_GPIO_DeInit(GPIOB, GD_SCLK_Pin|GD_SO_Pin|GD_SI_Pin);
/* USER CODE BEGIN SPI1_MspDeInit 1 */
/* USER CODE END SPI1_MspDeInit 1 */
}
else if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspDeInit 0 */