FBB_WS63 SFC SPI/QSPI 模式深度分析
📋 目录
- [SPI vs QSPI 模式对比](#SPI vs QSPI 模式对比 "#spi-vs-qspi-%E6%A8%A1%E5%BC%8F%E5%AF%B9%E6%AF%94")
- [GPIO Pin 映射](#GPIO Pin 映射 "#gpio-pin-%E6%98%A0%E5%B0%84")
- 编译配置开关
- [GPIO 重新布线修改清单](#GPIO 重新布线修改清单 "#gpio-%E9%87%8D%E6%96%B0%E5%B8%83%E7%BA%BF%E4%BF%AE%E6%94%B9%E6%B8%85%E5%8D%95")
- 代码路径汇总
1️⃣ SPI vs QSPI 模式对比
📊 模式概览
| 特性 | SPI 模式 | QSPI 模式 |
|---|---|---|
| 通讯模式 | 标准 SPI | 四线 SPI |
| GPIO pin 数量 | 4 条 | 6 条 |
| 数据线 | MOSI(1线) + MISO(1线) | IO0 + IO1 + IO2 + IO3(4线) |
| 传输速度 | 正常 | 4x 更快 |
| 应用场景 | 通用 Flash | 高速 Flash、存储器 |
| Flash 支持 | 所有现代 Flash | 大多数新型 Flash |
🔌 两种模式的 GPIO 需求对比
SPI 模式(标准4线)
scss
┌─── SFC 硬件模块 ───┐
│ WS63 SFC 控制器 │
│ (0x48000000) │
└───────┬────────────┘
│
├─→ GPIO_19 (SFC_CLK) - 时钟信号,CLK
├─→ GPIO_20 (SFC_CSN) - 片选信号,CS(低有效)
├─→ GPIO_21 (SFC_IO0) - 数据线 0,MOSI(Master Out)
└─→ GPIO_22 (SFC_IO1) - 数据线 1,MISO(Master In)
QSPI 模式(四线增强)
scss
┌─── SFC 硬件模块 ───┐
│ WS63 SFC 控制器 │
│ (0x48000000) │
└───────┬────────────┘
│
├─→ GPIO_19 (SFC_CLK) - 时钟信号
├─→ GPIO_20 (SFC_CSN) - 片选信号
├─→ GPIO_21 (SFC_IO0) - 数据线 0,MOSI
├─→ GPIO_22 (SFC_IO1) - 数据线 1,MISO
├─→ GPIO_23 (SFC_IO2) - 数据线 2,WP(写保护,低有效)
└─→ GPIO_24 (SFC_IO3) - 数据线 3,HOLD(保持,低有效)
📌 关键差异说明
| 项目 | SPI 模式 | QSPI 模式 | 说明 |
|---|---|---|---|
| CLK | GPIO_19 | GPIO_19 | 始终需要(硬固定) |
| CSN | GPIO_20 | GPIO_20 | 始终需要(硬固定) |
| MOSI(IO0) | GPIO_21 | GPIO_21 | 始终需要(硬固定) |
| MISO(IO1) | GPIO_22 | GPIO_22 | 始终需要(硬固定) |
| WP(IO2) | ❌ 不需要 | GPIO_23 | ⚠️ QSPI 必需 |
| HOLD(IO3) | ❌ 不需要 | GPIO_24 | ⚠️ QSPI 必需 |
| 总 Pin 数 | 4 | 6 | +2 pin |
2️⃣ GPIO Pin 映射
🎯 GPIO Pin 定义位置
文件 1 :src/drivers/chips/ws63/include/platform_core_rom.h
位置:第 50-54 行
c
typedef enum {
GPIO_00 = 0,
// ... GPIO_01 到 GPIO_18 ...
GPIO_18 = 18,
SFC_CLK = 19, // ✅ Flash 时钟
SFC_CSN = 20, // ✅ 片选(CS#)
SFC_IO0 = 21, // ✅ MOSI 数据线 0
SFC_IO1 = 22, // ✅ MISO 数据线 1
SFC_IO2 = 23, // ⚠️ 数据线 2(WP,仅 QSPI)
SFC_IO3 = 24, // ⚠️ 数据线 3(HOLD,仅 QSPI)
PIN_NONE = 25,
} pin_t;
说明:
- 这些是 enum 枚举定义,映射到具体的 GPIO 号(19-24)
- GPIO_19-22 是硬件固定分配的 SFC 引脚
- GPIO_23-24 是可选的 QSPI 扩展引脚
- 这是硬件级别的固定连接,不能改变
文件 2 :src/drivers/chips/ws63/porting/soc/soc_porting.c
位置:第 64-79 行
c
// PAD 寄存器地址(硬件 Pad Control)
#define PAD_SFC_CLK_CTRL 0x4400d868 // GPIO_19 的 Pad 控制寄存器
#define PAD_SFC_CSN_CTRL 0x4400d86C // GPIO_20 的 Pad 控制寄存器
#define PAD_SFC_IO0_CTRL 0x4400d870 // GPIO_21 的 Pad 控制寄存器
#define PAD_SFC_IO1_CTRL 0x4400d874 // GPIO_22 的 Pad 控制寄存器
#define PAD_SFC_IO2_CTRL 0x4400d878 // GPIO_23 的 Pad 控制寄存器(QSPI)
#define PAD_SFC_IO3_CTRL 0x4400d87C // GPIO_24 的 Pad 控制寄存器(QSPI)
// 驱动强度 (Drive Strength) 设置
#define SFC_CLK_DS_VALUE 0x3 // CLK 驱动强度
#define SFC_CSN_DS_VALUE 0x2 // CSN 驱动强度
#define SFC_DATA_DS_VALUE 0x2 // 数据线驱动强度
void config_sfc_ctrl_ds(void)
{
reg_setbits(PAD_SFC_CLK_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CLK_DS_VALUE);
reg_setbits(PAD_SFC_CSN_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CSN_DS_VALUE);
reg_setbits(PAD_SFC_IO0_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO1_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO2_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO3_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
}
说明:
- 这是芯片 Pad 控制的硬件寄存器地址
- 配置了每条线的驱动强度(Drive Strength)
- 这些地址是芯片级别的固定值(SOC 级别)
- 不建议修改这些地址,除非硬件重新设计
文件 3 :src/drivers/drivers/hal/pinmux/ws63/hal_pinctrl_ws63.c
位置:第 20-27 行(基地址定义)、第 109-140 行(pin 配置组)
c
#define HAL_IO_CFG_BASE_ADDR 0x4400D000
#define HAL_PIN_GPIO_SEL_START_OFFSET 0x000
#define HAL_PIN_UART_SEL_START_OFFSET 0x03C
#define HAL_PIN_GPIO_CTRL_START_OFFSET 0x800
#define HAL_PIN_SFC_CTRL_START_OFFSET 0x868 // ✅ SFC pin 控制起始地址
#define HAL_PIN_GPIO_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_SEL_START_OFFSET)
#define HAL_PIN_UART_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_UART_SEL_START_OFFSET)
#define HAL_PIN_GPIO_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_CTRL_START_OFFSET)
#define HAL_PIN_SFC_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_SFC_CTRL_START_OFFSET)
Pin 配置组(第 109-140 行):
c
static hal_pin_config_group_t const g_pin_pull_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
// ... GPIO_00~14 的上拉/下拉配置 ...
},
{
SFC_CLK, // GPIO_19
SFC_IO3, // GPIO_24
HAL_PIN_SFC_CTRL_START_ADDR, // 0x4400D868
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
}
};
static hal_pin_config_group_t const g_pin_ds_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
// ... GPIO_00~14 的驱动强度配置 ...
},
{
SFC_CLK, // GPIO_19
SFC_IO3, // GPIO_24
HAL_PIN_SFC_CTRL_START_ADDR, // 0x4400D868
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_DS_START_BIT,
HAL_PIN_DS_BITS_NUM
}
};
// IE(输入使能)配置
static hal_pin_config_group_t const g_pin_ie_map[] = {
{
SFC_CLK, // GPIO_19
SFC_IO3, // GPIO_24
HAL_PIN_SFC_CTRL_START_ADDR,
// ...
}
};
// ST(Schmitt Trigger)配置
static hal_pin_config_group_t const g_pin_st_map[] = {
{
SFC_CLK, // GPIO_19
SFC_IO3, // GPIO_24
HAL_PIN_SFC_CTRL_START_ADDR,
// ...
}
};
说明:
- 定义了 SFC 的 pin 控制寄存器基地址
- GPIO_19-24 都统一在
HAL_PIN_SFC_CTRL_START_ADDR配置组中 - 配置项包括:上拉/下拉、驱动强度、输入使能、施密特触发器
🔄 GPIO Pin 使用流程
scss
┌─────────────────────────────────────────────────────┐
│ 硬启动/烧录(BootLoader) │
├─────────────────────────────────────────────────────┤
│ 1. SFC 硬件自动使用 GPIO_19-22(SPI 模式) │
│ 2. soc_porting.c 配置 Pad 驱动强度 │
│ └─ config_sfc_ctrl_ds() │
└──────────┬──────────────────────────────────────────┘
│
┌──────────▼──────────────────────────────────────────┐
│ 应用启动(APP 阶段) │
├─────────────────────────────────────────────────────┤
│ 1. sfc.c 调用 hal_sfc_init() │
│ 2. hal_pinctrl_ws63.c 配置 pin 属性 │
│ └─ 拉高/拉低、驱动强度等 │
│ 3. SFC 驱动初始化完成 │
└─────────────────────────────────────────────────────┘
3️⃣ 编译配置开关
📚 Kconfig 配置文件位置
文件 1 :src/drivers/drivers/Kconfig
位置:第 387-403 行
kconfig
config DRIVER_SUPPORT_SFC
bool
prompt "SFC"
default y
help
This option means support SFC.
if DRIVER_SUPPORT_SFC
menu "SFC Configuration"
comment "Config SFC"
osource "drivers/drivers/driver/sfc/Kconfig"
osource "drivers/drivers/hal/sfc/Kconfig"
endmenu
endif
config DRIVER_SUPPORT_SPI
bool
prompt "SPI"
default n
help
This option means support SPI.
if DRIVER_SUPPORT_SPI
menu "SPI Configuration"
comment "Config SPI"
osource "drivers/drivers/driver/spi/Kconfig"
osource "drivers/drivers/hal/spi/Kconfig"
endmenu
endif
说明:
CONFIG_DRIVER_SUPPORT_SFC- SFC 驱动总开关(默认启用)CONFIG_DRIVER_SUPPORT_SPI- 通用 SPI 驱动总开关(默认禁用)- 关键点:SFC 和 SPI 是分别的驱动,不会直接冲突
文件 2 :src/drivers/chips/ws63/rom/drivers/drivers/driver/sfc/Kconfig
位置:完整内容
kconfig
#===============================================================================
# @brief Kconfig file.
# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
#===============================================================================
config SFC_SUPPORT_DMA
bool
prompt "SFC Support DMA"
default y
depends on DRIVER_SUPPORT_SFC
config SFC_ALLOW_ERASE_WRITEBACK
bool
prompt "Allows Erase at Any Address, needs 4KB RAM at least"
default n
depends on DRIVER_SUPPORT_SFC
config SFC_ALREADY_INIT
bool
prompt "SFC has been inited, need not to set reg in init/deinit func."
default n
depends on DRIVER_SUPPORT_SFC
SFC 相关配置:
| 配置项 | 说明 | 默认值 | 用途 |
|---|---|---|---|
CONFIG_SFC_SUPPORT_DMA |
启用 DMA 传输 | y(启用) |
提高传输速度 |
CONFIG_SFC_ALLOW_ERASE_WRITEBACK |
允许任意地址擦除 | n(禁用) |
需要额外 4KB RAM |
CONFIG_SFC_ALREADY_INIT |
Skip 初始化 | n(禁用) |
BootLoader 已初始化时 |
⚠️ 重要:
- 这些配置中没有 QSPI/SPI 模式选择开关
- QSPI 模式是由 Flash 芯片本身决定的(Flash 支持 QSPI 就自动启用)
文件 3 :src/application/samples/peripheral/spi/Kconfig
位置:第 49-77 行(SPI Master QSPI 支持)
kconfig
config SPI_MASTER_SUPPORT_QSPI
bool
prompt "SPI master support QSPI."
depends on SAMPLE_SUPPORT_SPI_MASTER
default n
config SPI_MASTER_D3_PIN_MODE
int
prompt "Choose QSPI master D3 pin mode."
depends on SPI_MASTER_SUPPORT_QSPI
default 1
config SPI_MASTER_D2_PIN_MODE
int
prompt "Choose QSPI master D2 pin mode."
depends on SPI_MASTER_SUPPORT_QSPI
default 1
config SPI_MASTER_D3_PIN
int
prompt "Choose QSPI master D3 pin."
depends on SPI_MASTER_SUPPORT_QSPI
default 40
config SPI_MASTER_D2_PIN
int
prompt "Choose QSPI master D2 pin."
depends on SPI_MASTER_SUPPORT_QSPI
default 41
说明:
- 这是 通用 SPI 模块(不是 SFC)的 QSPI 配置
- 支持用户自定义 D2/D3 pin(GPIO_40、GPIO_41 等)
- 这不影响 SFC 的 GPIO_23-24
📊 当前项目配置状态
文件 :src/build/config/target_config/ws63/menuconfig/acore/ws63_liteos_app.config
位置:第 357-383 行
config
#
# SFC Configuration
#
#
# Config SFC
#
# CONFIG_SFC_SUPPORT_DMA is not set
# CONFIG_SFC_ALLOW_ERASE_WRITEBACK is not set
# CONFIG_SFC_ALREADY_INIT is not set
# CONFIG_SFC_SUPPORT_LPM is not set
# CONFIG_SFC_SUPPORT_SFC_LOCK is not set
# CONFIG_SFC_SUPPORT_DATA_CACHE is not set
# CONFIG_SFC_SUPPORT_RWE_INDEPENDENT is not set
# CONFIG_SFC_SUPPORT_WRITE_PROTECT is not set
# CONFIG_SFC_USE_CUSTOMIZED_DEVICE_INFO is not set
# CONFIG_SFC_DEBUG is not set
# end of SFC Configuration
CONFIG_DRIVER_SUPPORT_SPI=y
#
# SPI Configuration
#
#
# Config SPI
#
# CONFIG_SPI_SUPPORT_MASTER is not set
# CONFIG_SPI_SUPPORT_SLAVE is not set
# CONFIG_SPI_SUPPORT_DMA is not set
# CONFIG_SPI_SUPPORT_INTERRUPT is not set
# CONFIG_SPI_SUPPORT_CONCURRENCY is not set
# CONFIG_SPI_SUPPORT_LOOPBACK is not set
# CONFIG_SPI_SUPPORT_CRC is not set
当前配置分析:
arduino
✅ 启用的配置:
└─ CONFIG_DRIVER_SUPPORT_SFC=y (SFC 驱动启用)
└─ CONFIG_DRIVER_SUPPORT_SPI=y (SPI 驱动启用)
❌ 禁用的配置:
└─ CONFIG_SFC_SUPPORT_DMA (DMA 禁用 - 仅寄存器模式)
└─ CONFIG_SPI_SUPPORT_MASTER (通用 SPI Master 禁用)
└─ CONFIG_SPI_SUPPORT_SLAVE (通用 SPI Slave 禁用)
└─ CONFIG_SPI_SUPPORT_DMA (SPI DMA 禁用)
⚠️ 关键发现:
• SFC 没有显式的 SPI/QSPI 模式开关
• QSPI 模式由 Flash 芯片自动检测和启用
• 当前使用的是寄存器模式(非 DMA),较低效率
🔍 模式配置决策流程
arduino
硬件检测 Flash 芯片
│
├─→ 识别 Flash ID
│ └─ sfc.c line 151
│ build_cmds(flash_id, ...)
│
└─→ 查询 Flash 支持的模式
└─ flash_config_info.c
flash_spi_info_t 中的 quad_mode
├─ quad_mode != NULL
│ └─→ 此 Flash 支持 QSPI
│ ├─ 自动启用 GPIO_23-24
│ └─ 配置 QSPI 指令
│
└─ quad_mode == NULL
└─→ 此 Flash 仅支持 SPI
├─ 仅使用 GPIO_19-22
└─ 配置 SPI 指令
4️⃣ GPIO 重新布线修改清单
⚠️ 硬件GPIO固定性警告
markdown
❌ 【不可修改】硬件固定的 GPIO 映射:
GPIO_19 ←→ SFC_CLK(硬线连接)
GPIO_20 ←→ SFC_CSN(硬线连接)
GPIO_21 ←→ SFC_IO0/MOSI(硬线连接)
GPIO_22 ←→ SFC_IO1/MISO(硬线连接)
GPIO_23 ←→ SFC_IO2/WP(硬线连接)
GPIO_24 ←→ SFC_IO3/HOLD(硬线连接)
这些是芯片设计阶段的硬连接,无法通过软件修改。
📝 若硬件重新设计需要修改GPIO
假设新硬件使用了不同的 GPIO 引脚,需要修改以下位置:
1️⃣ platform_core_rom.h
文件位置 :src/drivers/chips/ws63/include/platform_core_rom.h
原内容(第 50-54 行):
c
SFC_CLK = 19,
SFC_CSN = 20,
SFC_IO0 = 21,
SFC_IO1 = 22,
SFC_IO2 = 23,
SFC_IO3 = 24,
修改示例(假设新硬件用不同 GPIO):
c
SFC_CLK = 25, // 改为 GPIO_25
SFC_CSN = 26, // 改为 GPIO_26
SFC_IO0 = 27, // 改为 GPIO_27
SFC_IO1 = 28, // 改为 GPIO_28
SFC_IO2 = 29, // 改为 GPIO_29(QSPI)
SFC_IO3 = 30, // 改为 GPIO_30(QSPI)
修改步骤:
- 确定新的 GPIO 号(需要硬件原理图确认)
- 修改 enum 中的数值
- 确保新 GPIO 号在有效范围内(0-45 以内)
2️⃣ soc_porting.c(Pad 控制寄存器地址)
文件位置 :src/drivers/chips/ws63/porting/soc/soc_porting.c
原内容(第 64-67 行):
c
#define PAD_SFC_CLK_CTRL 0x4400d868
#define PAD_SFC_CSN_CTRL 0x4400d86C
#define PAD_SFC_IO0_CTRL 0x4400d870
#define PAD_SFC_IO1_CTRL 0x4400d874
#define PAD_SFC_IO2_CTRL 0x4400d878
#define PAD_SFC_IO3_CTRL 0x4400d87C
修改说明:
- 这些寄存器地址来自 WS63 芯片设计文档
- 每个新 GPIO 号对应新的寄存器地址
- 需要查阅 WS63 数据手册获取新地址
修改示例(假设新 GPIO 的 Pad 地址):
c
#define PAD_SFC_CLK_CTRL 0x4400d880 // 新地址
#define PAD_SFC_CSN_CTRL 0x4400d884
#define PAD_SFC_IO0_CTRL 0x4400d888
#define PAD_SFC_IO1_CTRL 0x4400d88C
#define PAD_SFC_IO2_CTRL 0x4400d890
#define PAD_SFC_IO3_CTRL 0x4400d894
3️⃣ hal_pinctrl_ws63.c
文件位置 :src/drivers/drivers/hal/pinmux/ws63/hal_pinctrl_ws63.c
原内容(第 109-140 行):
c
static hal_pin_config_group_t const g_pin_pull_map[] = {
{
GPIO_00,
GPIO_14,
// ... GPIO_00~14 ...
},
{
SFC_CLK, // = 19
SFC_IO3, // = 24
HAL_PIN_SFC_CTRL_START_ADDR,
// ...
}
};
修改说明:
- 如果新 GPIO 号仍在连续范围内(如 25-30),只需修改 begin 和 end
- 如果分散在不同范围,可能需要新增配置组
修改示例(假设新 GPIO 为 25-30):
c
{
SFC_CLK, // 新定义为 GPIO_25
SFC_IO3, // 新定义为 GPIO_30
HAL_PIN_SFC_CTRL_START_ADDR, // 使用新的基地址
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
}
🚫 Kconfig 中无需修改的内容
bash
✅ Kconfig 文件:
• src/drivers/drivers/Kconfig
• src/drivers/chips/ws63/rom/drivers/drivers/driver/sfc/Kconfig
• src/application/samples/peripheral/spi/Kconfig
为什么?
├─ GPIO pin 号不在 Kconfig 中硬编码
├─ Kconfig 只控制功能启用/禁用开关
└─ Pin 映射在源代码中定义,不在配置中
✅ 完整修改检查清单
如果只是普通项目(不改硬件GPIO):
✅ 检查项:
☐ 确认当前 GPIO_19-24 在硬件上连接正确
☐ 检查原理图中 Flash pin 的物理连接
☐ 验证电源和 GND 连接
☐ 确保 Flash 芯片规格书中支持当前固件
❌ 无需修改任何代码
如果需要硬件gpio重新布线:
markdown
✅ 修改步骤:
1. 获取硬件原理图
2. 确定新 GPIO 号和 Pad 寄存器地址
3. 修改 platform_core_rom.h(GPIO 号)
4. 修改 soc_porting.c(Pad 控制地址)
5. 修改 hal_pinctrl_ws63.c(pin 配置范围)
6. 编译验证
7. 烧录 BootLoader 执行初始化
🔧 工具需求:
• WS63 数据手册(获取 Pad 地址)
• FlashTool 重新烧录 BootLoader
• 硬件测试工具(示波器、逻辑分析仪)
5️⃣ 代码路径汇总
📁 文件结构图
erlang
fbb_ws63-master/
├── src/drivers/
│ ├── chips/ws63/
│ │ ├── include/
│ │ │ ├── platform_core_rom.h ⭐ GPIO 枚举定义
│ │ │ └── ...
│ │ ├── porting/
│ │ │ ├── soc/
│ │ │ │ └── soc_porting.c ⭐ Pad 寄存器地址
│ │ │ ├── sfc/
│ │ │ │ ├── sfc_porting.h 📋 SFC 配置结构体
│ │ │ │ ├── porting/
│ │ │ │ │ └── sfc_porting.c ⭐ SFC 寄存器基地址
│ │ │ │ ├── driver/
│ │ │ │ │ └── sfc.c 💻 SFC 驱动核心
│ │ │ │ └── flash_config/
│ │ │ │ └── flash_config_info.c 📊 Flash 芯片配置
│ │ │ └── ...
│ │ └── ...
│ ├── drivers/
│ │ ├── hal/
│ │ │ ├── pinmux/ws63/
│ │ │ │ └── hal_pinctrl_ws63.c ⭐ Pin 控制配置
│ │ │ ├── sfc/
│ │ │ │ └── hal_sfc_v150.c 💻 SFC HAL 层
│ │ │ └── ...
│ │ ├── Kconfig 📝 驱动配置开关
│ │ └── ...
│ └── ...
├── src/application/
│ └── samples/
│ └── peripheral/
│ ├── spi/
│ │ ├── Kconfig 📝 SPI 配置开关
│ │ └── spi_master_demo.c 📜 SPI Master 示例
│ └── sfc/
│ └── sfc_demo.c 📜 SFC 使用示例
├── src/build/
│ ├── config/
│ │ └── target_config/ws63/menuconfig/acore/
│ │ ├── ws63_liteos_app.config ⚙️ APP 配置
│ │ ├── ws63_flashboot.config ⚙️ BootLoader 配置
│ │ └── ws63_liteos_testsuite.config ⚙️ 测试套件配置
│ └── ...
└── ...
🔑 核心文件详解
| # | 文件名 | 路径 | 功能 | 修改频率 |
|---|---|---|---|---|
| 1 | platform_core_rom.h | src/drivers/chips/ws63/include/ |
GPIO 枚举定义(GPIO_19-24) | 🔴 极少修改 |
| 2 | soc_porting.c | src/drivers/chips/ws63/porting/soc/ |
Pad 寄存器地址 & 驱动强度配置 | 🔴 极少修改 |
| 3 | hal_pinctrl_ws63.c | src/drivers/drivers/hal/pinmux/ws63/ |
Pin 控制配置映射表 | 🟡 如果改GPIO |
| 4 | sfc_porting.h | src/drivers/chips/ws63/porting/sfc/ |
SFC 配置结构体定义 | 🟢 可配置 |
| 5 | sfc_porting.c | src/drivers/chips/ws63/porting/sfc/porting/ |
SFC 寄存器基地址 | 🔴 固定 |
| 6 | sfc.c | src/drivers/chips/ws63/porting/sfc/driver/ |
SFC 驱动实现 | 🟢 按需配置 |
| 7 | flash_config_info.c | src/drivers/chips/ws63/porting/sfc/flash_config/ |
Flash 芯片数据库 | 🟢 新芯片需添加 |
| 8 | hal_sfc_v150.c | src/drivers/drivers/hal/sfc/ |
SFC 硬件抽象层 | 🔴 极少修改 |
| 9 | Kconfig | src/drivers/drivers/ |
驱动功能开关 | 🟡 按项目需求 |
| 10 | .config | src/build/config/target_config/ws63/ |
当前编译配置 | 🟢 频繁修改 |
图例:
- 🔴 红色:硬件固定,极少改动
- 🟡 黄色:特定场景修改
- 🟢 绿色:常规配置和定制
🔍 功能追踪
"如何启用 QSPI 模式?"追踪
markdown
1. 硬件检测阶段
└─ sfc.c:151
uapi_sfc_init() 入口
↓
build_cmds(flash_id, ...)
↓
2. Flash 芯片查询
└─ flash_config_info.c
查询 flash_spi_info_t 数组
找到匹配的 flash_id
↓
3. 模式自动选择
└─ sfc.c:67
if (spi_info->quad_mode != NULL)
├─ QSPI 支持
│ ├─ 自动启用 GPIO_23-24
│ ├─ 加载 QSPI 指令序列
│ └─ 配置 Quad SPI 模式
└─ SPI 仅支持
├─ 仅使用 GPIO_19-22
├─ 加载 SPI 指令
└─ 配置标准 SPI 模式
4. HAL 层初始化
└─ hal_sfc_v150.c
hal_sfc_init()
根据 quad_mode 参数配置硬件
↓
5. 完成
└─ 驱动自动运行于最优模式
"如何修改 Flash 配置?"追踪
ini
1. 找到使用的 Flash 芯片型号
└─ 硬件原理图 → Flash 芯片手册
2. 检查 flash_config_info.c
└─ 查找对应的 FLASH_XXX ID 定义
是否存在该芯片配置
3. 如果已有配置
└─ sfc.c 会自动使用
└─ 无需修改代码
4. 如果无该配置
└─ flash_config_info.c
仿照现有格式添加该 Flash 配置
├─ .chip_id = 0xXXXXXX
├─ .read_cmds[] = { ... }
├─ .write_cmds[] = { ... }
├─ .erase_cmds[] = { ... }
└─ .quad_mode = &cmd_seq (如果支持)
5. 重新编译烧录
🎯 快速查找表
我想要配置...
| 需求 | 文件 | 行号 | 说明 |
|---|---|---|---|
| 查看 GPIO 定义 | platform_core_rom.h | 50-54 | enum GPIO 编号 |
| 改变 GPIO 号 | platform_core_rom.h | 50-54 | 修改枚举值 |
| 调整驱动强度 | soc_porting.c | 70-71 | SFC_CLK_DS_VALUE 等 |
| 启用 DMA | Kconfig | 配置菜单 | CONFIG_SFC_SUPPORT_DMA |
| 添加新 Flash | flash_config_info.c | 全文 | 仿照现有条目添加 |
| 启用 Quad 模式 | 自动 | - | Flash 自动检测 |
| 查看 SFC 初始化 | sfc.c | 145-170 | uapi_sfc_init() 函数 |
| 查看 Pin 配置 | hal_pinctrl_ws63.c | 109-140 | g_pin_xxx_map 数组 |
| 禁用 SFC | Kconfig | 驱动菜单 | CONFIG_DRIVER_SUPPORT_SFC |
🎓 总结对比表
SPI vs QSPI 模式:硬件视角
scss
┌──────────────┬─────────────────┬─────────────────┐
│ 特性 │ SPI 模式 │ QSPI 模式 │
├──────────────┼─────────────────┼─────────────────┤
│ GPIO pin │ GPIO_19~22 │ GPIO_19~24 │
│ 总数 │ 4 条 │ 6 条 │
│ CLK │ GPIO_19 │ GPIO_19 │
│ CSN │ GPIO_20 │ GPIO_20 │
│ MOSI(IO0) │ GPIO_21 │ GPIO_21 │
│ MISO(IO1) │ GPIO_22 │ GPIO_22 │
│ WP(IO2) │ ❌ 不需要 │ GPIO_23 │
│ HOLD(IO3) │ ❌ 不需要 │ GPIO_24 │
│ 驱动强度 │ 在 soc_porting.c 中配置 | 同左 │
│ Pad 寄存器 │ 0x4400d868-74 │ 0x4400d868-7C │
│ 数据线数 │ 1(收) + 1(发) │ 4 线双向 │
│ 传输速率 │ 基线 │ ~4x 快速 │
│ Pin 配置文件 │ hal_pinctrl_ws63.c (统一) │
└──────────────┴─────────────────┴─────────────────┘
编译配置:当前项目状态
ini
├─ CONFIG_DRIVER_SUPPORT_SFC=y ✅ SFC 驱动启用
├─ CONFIG_DRIVER_SUPPORT_SPI=y ✅ 通用 SPI 启用(但无 Master)
├─ CONFIG_SFC_SUPPORT_DMA 未设 ❌ 禁用 DMA(低性能)
│
└─ 当前模式自动检测:
Flash 支持 QUAD → 自动启用 QSPI(GPIO_19-24)
Flash 仅支持 SPI → 使用 SPI 模式(GPIO_19-22)
修改需求清单
arduino
场景 1:仅使用现有硬件(GPIO_19-24)
修改文件:无
重编译:仅需更新 .config(如启用 DMA)
场景 2:更换不同 Flash 芯片(同 GPIO)
修改文件:可能需要 flash_config_info.c
重编译:仅驱动代码
场景 3:重新设计硬件(不同 GPIO)
修改文件:
✏️ platform_core_rom.h(GPIO 枚举)
✏️ soc_porting.c(Pad 地址)
✏️ hal_pinctrl_ws63.c(Pin 配置)
重编译:整个驱动 + BootLoader
烧录:重新初始化硬件
📚 参考资源
| 资源 | 位置 | 用途 |
|---|---|---|
| WS63 数据手册 | (硬件文档) | Pad 地址、GPIO 定义 |
| GPIO_LITTLEFS_ANALYSIS.md | 项目根目录 | GPIO 配置详解 |
| SFC_GPIO_PIN_MAPPING.md | AI/ 文件夹 | Pin 映射参考 |
| NOR_FLASH_CONFIG_PARAMETER_GUIDE.md | AI/ 文件夹 | Flash 配置指南 |
❓ 常见问题解答
Q1:能否改变 GPIO_19-24 的引脚号?
A:不能。这是硬件级别的固定连接。SFC 硬件内部已直接连接到这些 GPIO,改需要重新设计芯片。
Q2:SPI 和 QSPI 是否可以同时启用?
A:在 SFC 驱动中,Flash 自动选择一种模式。但通用 SPI 模块可独立使用不同 GPIO(如 GPIO_40-41),与 SFC 无冲突。
Q3:为什么配置中没有 QSPI 开关?
A:因为 QSPI 模式由 Flash 芯片决定。SFC 驱动自动检测 Flash 是否支持 Quad 模式,无需手动开关。
Q4:修改了 GPIO 定义后编译不过怎么办?
A:
- 检查新 GPIO 号是否超出有效范围(0-45)
- 更新所有涉及的文件(platform_core_rom.h、soc_porting.c、hal_pinctrl_ws63.c)
- 清理编译缓存:
rm -rf src/build/cmake_build - 重新编译
Q5:GPIO_23-24 可以用于其他功能吗?
A:如果 Flash 不支持 QSPI,这两个 GPIO 理论上可复用。但不建议:
- 硬件设计通常已连接到 Flash
- 会使代码维护复杂化
- 可用的 GPIO 有其他选项(GPIO_0-18, GPIO_25+)
文档更新时间 :2025-02 | FBB_WS63 版本 :最新 | 适用范围:SPI/QSPI 配置
FBB_WS63 SFC GPIO 修改代码示例
🎯 使用场景:假设需要改变 GPIO 映射
假定原硬件使用 GPIO_19-24,现在需要改为 GPIO_25-30(仅作示例)
模板 1:platform_core_rom.h 修改示例
原始代码
文件 :src/drivers/chips/ws63/include/platform_core_rom.h 行号:45-60
c
/**
* @brief Definition of pin.
*/
typedef enum {
GPIO_00 = 0,
GPIO_01 = 1,
GPIO_02 = 2,
GPIO_03 = 3,
GPIO_04 = 4,
GPIO_05 = 5,
GPIO_06 = 6,
GPIO_07 = 7,
GPIO_08 = 8,
GPIO_09 = 9,
GPIO_10 = 10,
GPIO_11 = 11,
GPIO_12 = 12,
GPIO_13 = 13,
GPIO_14 = 14,
GPIO_15 = 15,
GPIO_16 = 16,
GPIO_17 = 17,
GPIO_18 = 18,
SFC_CLK = 19, // ← 原值
SFC_CSN = 20, // ← 原值
SFC_IO0 = 21, // ← 原值
SFC_IO1 = 22, // ← 原值
SFC_IO2 = 23, // ← 原值
SFC_IO3 = 24, // ← 原值
PIN_NONE = 25, // used as invalid/unused PIN number
} pin_t;
修改后的代码
c
/**
* @brief Definition of pin.
*/
typedef enum {
GPIO_00 = 0,
GPIO_01 = 1,
GPIO_02 = 2,
GPIO_03 = 3,
GPIO_04 = 4,
GPIO_05 = 5,
GPIO_06 = 6,
GPIO_07 = 7,
GPIO_08 = 8,
GPIO_09 = 9,
GPIO_10 = 10,
GPIO_11 = 11,
GPIO_12 = 12,
GPIO_13 = 13,
GPIO_14 = 14,
GPIO_15 = 15,
GPIO_16 = 16,
GPIO_17 = 17,
GPIO_18 = 18,
GPIO_19 = 19, // 现在作为普通 GPIO
GPIO_20 = 20, // 现在作为普通 GPIO
GPIO_21 = 21, // 现在作为普通 GPIO
GPIO_22 = 22, // 现在作为普通 GPIO
GPIO_23 = 23, // 现在作为普通 GPIO
GPIO_24 = 24, // 现在作为普通 GPIO
SFC_CLK = 25, // ← 新值(改到 GPIO_25)
SFC_CSN = 26, // ← 新值(改到 GPIO_26)
SFC_IO0 = 27, // ← 新值(改到 GPIO_27)
SFC_IO1 = 28, // ← 新值(改到 GPIO_28)
SFC_IO2 = 29, // ← 新值(改到 GPIO_29)
SFC_IO3 = 30, // ← 新值(改到 GPIO_30)
PIN_NONE = 31, // 更新为 31(之前的 PIN_NONE 值也要顺延)
} pin_t;
#define PIN_MAX_NUMBER PIN_NONE // 保留这一行
修改要点
✏️ 改动清单:
☐ SFC_CLK 从 19 改为 25
☐ SFC_CSN 从 20 改为 26
☐ SFC_IO0 从 21 改为 27
☐ SFC_IO1 从 22 改为 28
☐ SFC_IO2 从 23 改为 29
☐ SFC_IO3 从 24 改为 30
☐ PIN_NONE 从 25 改为 31
☐ 添加 GPIO_19-24 的普通定义(可选)
模板 2:soc_porting.c 修改示例
原始代码
文件 :src/drivers/chips/ws63/porting/soc/soc_porting.c 行号:64-79
c
#define PAD_SFC_CLK_CTRL 0x4400d868 // GPIO_19
#define PAD_SFC_CSN_CTRL 0x4400d86C // GPIO_20
#define PAD_SFC_IO0_CTRL 0x4400d870 // GPIO_21
#define PAD_SFC_IO1_CTRL 0x4400d874 // GPIO_22
#define PAD_SFC_IO2_CTRL 0x4400d878 // GPIO_23
#define PAD_SFC_IO3_CTRL 0x4400d87C // GPIO_24
#define SFC_CLK_DS_VALUE 0x3
#define SFC_CSN_DS_VALUE 0x2
#define SFC_DATA_DS_VALUE 0x2
void config_sfc_ctrl_ds(void)
{
reg_setbits(PAD_SFC_CLK_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CLK_DS_VALUE);
reg_setbits(PAD_SFC_CSN_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CSN_DS_VALUE);
reg_setbits(PAD_SFC_IO0_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO1_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO2_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO3_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
}
修改后的代码
⚠️ 关键:需要从 WS63 数据手册查询新 GPIO 对应的 Pad 控制寄存器地址
假设新地址从 0x4400d880 开始(按顺序递增 0x4):
c
// 新 GPIO 的 Pad 控制寄存器地址(需从芯片手册查询)
// GPIO_25 → GPIO_30 的 Pad 地址(假设)
#define PAD_SFC_CLK_CTRL 0x4400d880 // GPIO_25 对应的 Pad 地址
#define PAD_SFC_CSN_CTRL 0x4400d884 // GPIO_26 对应的 Pad 地址
#define PAD_SFC_IO0_CTRL 0x4400d888 // GPIO_27 对应的 Pad 地址
#define PAD_SFC_IO1_CTRL 0x4400d88C // GPIO_28 对应的 Pad 地址
#define PAD_SFC_IO2_CTRL 0x4400d890 // GPIO_29 对应的 Pad 地址
#define PAD_SFC_IO3_CTRL 0x4400d894 // GPIO_30 对应的 Pad 地址
// 驱动强度值保持不变(除非需要微调)
#define SFC_CLK_DS_VALUE 0x3 // 时钟强驱动
#define SFC_CSN_DS_VALUE 0x2 // 片选中等驱动
#define SFC_DATA_DS_VALUE 0x2 // 数据线中等驱动
void config_sfc_ctrl_ds(void)
{
// 配置逻辑完全相同,只是使用了新的寄存器地址
reg_setbits(PAD_SFC_CLK_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CLK_DS_VALUE);
reg_setbits(PAD_SFC_CSN_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_CSN_DS_VALUE);
reg_setbits(PAD_SFC_IO0_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO1_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO2_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
reg_setbits(PAD_SFC_IO3_CTRL, 0, POS_4, DTRL_DS_LEN, SFC_DATA_DS_VALUE);
}
修改要点
scss
✏️ 改动清单:
☐ PAD_SFC_CLK_CTRL 地址更新(从芯片手册查表)
☐ PAD_SFC_CSN_CTRL 地址更新
☐ PAD_SFC_IO0_CTRL 地址更新
☐ PAD_SFC_IO1_CTRL 地址更新
☐ PAD_SFC_IO2_CTRL 地址更新
☐ PAD_SFC_IO3_CTRL 地址更新
☐ 驱动强度值保持或微调(可选)
☐ config_sfc_ctrl_ds() 函数逻辑不变
⚠️ 重要:
• 所有地址都必须从 WS63 数据手册查询
• 地址通常是按顺序排列,间隔 0x4 字节
• 务必确保地址准确无误
模板 3:hal_pinctrl_ws63.c 修改示例
原始代码
文件 :src/drivers/drivers/hal/pinmux/ws63/hal_pinctrl_ws63.c 行号:93-140
c
static hal_pin_config_group_t const g_pin_mode_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_SEL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_GPIO_SEL_START_BIT,
HAL_PIN_GPIO_SEL_BITS_NUM
},
{
GPIO_15,
GPIO_18,
HAL_PIN_UART_SEL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_UART_SEL_START_BIT,
HAL_PIN_UART_SEL_BITS_NUM
}
// ⚠️ 原来没有 SFC_CLK 的条目
};
static hal_pin_config_group_t const g_pin_pull_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
},
{
SFC_CLK, // = 19(原值)
SFC_IO3, // = 24(原值)
HAL_PIN_SFC_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
}
};
static hal_pin_config_group_t const g_pin_ds_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_DS_START_BIT,
HAL_PIN_DS_BITS_NUM
},
{
SFC_CLK, // = 19(原值)
SFC_IO3, // = 24(原值)
HAL_PIN_SFC_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_DS_START_BIT,
HAL_PIN_DS_BITS_NUM
}
};
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
static hal_pin_config_group_t const g_pin_ie_map[] = {
{
GPIO_00,
GPIO_18,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_IE_START_BIT,
HAL_PIN_IE_BITS_NUM
},
{
SFC_CLK, // = 19(原值)
SFC_IO3, // = 24(原值)
HAL_PIN_SFC_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_IE_START_BIT,
HAL_PIN_IE_BITS_NUM
}
};
#endif
#if defined(CONFIG_PINCTRL_SUPPORT_ST)
static hal_pin_config_group_t const g_pin_st_map[] = {
{
GPIO_00,
GPIO_18,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_ST_START_BIT,
HAL_PIN_ST_BITS_NUM
},
{
SFC_CLK, // = 19(原值)
SFC_IO3, // = 24(原值)
HAL_PIN_SFC_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_ST_START_BIT,
HAL_PIN_ST_BITS_NUM
}
};
#endif
修改后的代码
假设新的 SFC GPIO 为 GPIO_25-30,仍在连续范围内:
c
static hal_pin_config_group_t const g_pin_mode_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_SEL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_GPIO_SEL_START_BIT,
HAL_PIN_GPIO_SEL_BITS_NUM
},
{
GPIO_15,
GPIO_18,
HAL_PIN_UART_SEL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_UART_SEL_START_BIT,
HAL_PIN_UART_SEL_BITS_NUM
}
// SFC 的 GPIO_25-30 可能不需要在 mode_map 中配置
};
static hal_pin_config_group_t const g_pin_pull_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
},
{
SFC_CLK, // 现在等于 25(新值从 platform_core_rom.h 自动获得)
SFC_IO3, // 现在等于 30(新值从 platform_core_rom.h 自动获得)
HAL_PIN_SFC_CTRL_START_ADDR, // 这个地址可能也需要更新
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_PULL_START_BIT,
HAL_PIN_PULL_BITS_NUM
}
};
static hal_pin_config_group_t const g_pin_ds_map[] = {
{
GPIO_00,
GPIO_14,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_DS_START_BIT,
HAL_PIN_DS_BITS_NUM
},
{
SFC_CLK, // 自动从 enum 获取新值 25
SFC_IO3, // 自动从 enum 获取新值 30
HAL_PIN_SFC_CTRL_START_ADDR, // 可能需要更新
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_DS_START_BIT,
HAL_PIN_DS_BITS_NUM
}
};
#if defined(CONFIG_PINCTRL_SUPPORT_IE)
static hal_pin_config_group_t const g_pin_ie_map[] = {
{
GPIO_00,
GPIO_18,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_IE_START_BIT,
HAL_PIN_IE_BITS_NUM
},
{
SFC_CLK, // 自动获取新值 25
SFC_IO3, // 自动获取新值 30
HAL_PIN_SFC_CTRL_START_ADDR, // 可能需要更新
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_IE_START_BIT,
HAL_PIN_IE_BITS_NUM
}
};
#endif
#if defined(CONFIG_PINCTRL_SUPPORT_ST)
static hal_pin_config_group_t const g_pin_st_map[] = {
{
GPIO_00,
GPIO_18,
HAL_PIN_GPIO_CTRL_START_ADDR,
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_ST_START_BIT,
HAL_PIN_ST_BITS_NUM
},
{
SFC_CLK, // 自动获取新值 25
SFC_IO3, // 自动获取新值 30
HAL_PIN_SFC_CTRL_START_ADDR, // 可能需要更新
HAL_PIN_CONFIG_PER_NUM,
HAL_PIN_ST_START_BIT,
HAL_PIN_ST_BITS_NUM
}
};
#endif
修改说明
关键要点:
arduino
☑️ 自动适配:
• 由于使用了 SFC_CLK 和 SFC_IO3 的枚举名
• platform_core_rom.h 改了后自动应用
• hal_pinctrl_ws63.c 中用枚举名的地方自动更新
❌ 需要手动改的:
• HAL_PIN_SFC_CTRL_START_ADDR
• 所有 GPIO 配置组的数据结构范围
✏️ 改动方式:
方案 A(最简单):
• 只改 platform_core_rom.h 中的 enum
• 如果新 GPIO 范围仍然连续,其他文件可能无需改
方案 B(彻底):
• 改 platform_core_rom.h(enum)
• 改 soc_porting.c(Pad 地址)
• 改 hal_pinctrl_ws63.c(配置组)
• 改 HAL_PIN_SFC_CTRL_START_OFFSET 基地址
模板 4:HAL_PIN_SFC_CTRL_START_OFFSET 基地址更新
原始定义
文件 :src/drivers/drivers/hal/pinmux/ws63/hal_pinctrl_ws63.c 行号:20-27
c
#define HAL_IO_CFG_BASE_ADDR 0x4400D000
#define HAL_PIN_GPIO_SEL_START_OFFSET 0x000
#define HAL_PIN_UART_SEL_START_OFFSET 0x03C
#define HAL_PIN_GPIO_CTRL_START_OFFSET 0x800
#define HAL_PIN_SFC_CTRL_START_OFFSET 0x868 // ← 原值(用于 GPIO_19-24)
#define HAL_PIN_GPIO_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_SEL_START_OFFSET)
#define HAL_PIN_UART_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_UART_SEL_START_OFFSET)
#define HAL_PIN_GPIO_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_CTRL_START_OFFSET)
#define HAL_PIN_SFC_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_SFC_CTRL_START_OFFSET)
修改后(如果 GPIO 改到 25-30)
c
#define HAL_IO_CFG_BASE_ADDR 0x4400D000
#define HAL_PIN_GPIO_SEL_START_OFFSET 0x000
#define HAL_PIN_UART_SEL_START_OFFSET 0x03C
#define HAL_PIN_GPIO_CTRL_START_OFFSET 0x800
#define HAL_PIN_SFC_CTRL_START_OFFSET 0x880 // ← 新值(从芯片手册查询)
#define HAL_PIN_GPIO_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_SEL_START_OFFSET)
#define HAL_PIN_UART_SEL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_UART_SEL_START_OFFSET)
#define HAL_PIN_GPIO_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_GPIO_CTRL_START_OFFSET)
#define HAL_PIN_SFC_CTRL_START_ADDR (HAL_IO_CFG_BASE_ADDR + HAL_PIN_SFC_CTRL_START_OFFSET)
模板 5:flash_config_info.c 添加新 Flash
场景:添加新的 Flash 芯片(如 GD25Q256)
原有 Flash 条目示例
c
#define FLASH_GD25Q32 0x1640C8
// ... 在某个数组中 ...
{
.chip_id = FLASH_GD25Q32,
.chip_size = 0x400000, // 4MB
.read_cmds = {
{
.cmd = 0x0B, .cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24, .addr_support = 1,
.dummy_cycles = 1,
.cmd_type = STANDARD_READ, .size = 0x04
},
// ... 其他读命令 ...
},
.read_cmd_num = 3,
.write_cmds = { ... },
.write_cmd_num = 2,
.erase_cmds = { ... },
.erase_cmd_num = 4,
.quad_mode = &gd25_quad_mode_cmd, // QSPI 支持
},
新增 Flash GD25Q256
c
// 1. 首先添加 Flash ID 定义(在宏定义部分)
#define FLASH_GD25Q256 0x1940C8 // 256Mbit
// 2. 定义 QSPI 模式的使能命令(如果支持 Quad)
static flash_cmd_execute_t gd25q256_quad_mode_cmd = {
{
.cmd = 0x35, // 写状态寄存器 2
.cmd_support = 1,
.addr_support = 0,
.dummy_cycles = 0,
.cmd_type = FLASH_CMD_WRITE,
.size = 1,
},
{
.cmd = 0x15, // 读状态寄存器 2
.cmd_support = 1,
.addr_support = 0,
.dummy_cycles = 0,
.cmd_type = FLASH_CMD_READ,
.size = 1,
},
{
.cmd_support = 0, // 其他命令可选
}
};
// 3. 在 Flash 配置数组中追加新条目
{
.chip_id = FLASH_GD25Q256,
.chip_size = 0x2000000, // 32MB(256Mbit)
.read_cmds = {
{
.cmd = 0x0B, // Standard Read
.cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24,
.addr_support = 1,
.dummy_cycles = 1,
.cmd_type = STANDARD_READ,
.size = 0x04
},
{
.cmd = 0x3B, // Fast Read
.cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24,
.addr_support = 1,
.dummy_cycles = 1,
.cmd_type = STANDARD_READ,
.size = 0x04
},
{
.cmd = 0xEB, // Quad Fast Read
.cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24,
.addr_support = 1,
.dummy_cycles = 3,
.cmd_type = QUAD_READ,
.size = 0x04
},
},
.read_cmd_num = 3,
.write_cmds = {
{
.cmd = 0x02, // Page Program
.cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24,
.addr_support = 1,
.dummy_cycles = 0,
.cmd_type = PAGE_PROGRAM,
.size = 256
},
{
.cmd = 0x32, // Quad Page Program
.cmd_support = 1,
.addr_len = SPI_ADDR_LEN_24,
.addr_support = 1,
.dummy_cycles = 0,
.cmd_type = PAGE_PROGRAM,
.size = 256
},
},
.write_cmd_num = 2,
.erase_cmds = {
{
.cmd = 0x20, // Sector Erase (4KB)
.cmd_support = 1,
.addr_support = 1,
.cmd_type = ERASE_SECTOR,
.size = 0x1000
},
{
.cmd = 0x52, // 32KB Erase
.cmd_support = 1,
.addr_support = 1,
.cmd_type = ERASE_32K,
.size = 0x8000
},
{
.cmd = 0xD8, // 64KB Erase (Block)
.cmd_support = 1,
.addr_support = 1,
.cmd_type = ERASE_BLOCK,
.size = 0x10000
},
{
.cmd = 0xC7, // Chip Erase
.cmd_support = 1,
.addr_support = 0,
.cmd_type = ERASE_CHIP,
.size = 0x2000000 // 全容量
},
},
.erase_cmd_num = 4,
.quad_mode = &gd25q256_quad_mode_cmd, // 支持 QSPI
},
修改清单
arduino
☑️ 添加 Flash 的步骤:
1. 从 Flash 数据手册获取:
□ Flash ID(3 字节)
□ 容量(byte)
□ 各种读命令的 opcode
□ 编程命令 opcode
□ 擦除命令 opcode(通常 4 种)
□ QSPI 使能序列(如支持)
2. 修改 flash_config_info.c:
□ 添加 #define FLASH_XXXXX ID
□ 如果支持 QSPI,定义 quad_mode 结构
□ 创建 flash_spi_info_t 条目
□ 填充读/写/擦命令数组
3. 编译验证:
□ 固件编译成功
□ 烧录并测试 Flash 识别
□ 验证 SPI 模式读写
□ 验证 QSPI 模式读写(如支持)
模板 6:编译配置修改
启用 DMA 模式
文件 :ws63_liteos_app.config 修改:
diff
#
# SFC Configuration
#
#
# Config SFC
#
- # CONFIG_SFC_SUPPORT_DMA is not set
+ CONFIG_SFC_SUPPORT_DMA=y
# CONFIG_SFC_ALLOW_ERASE_WRITEBACK is not set
# CONFIG_SFC_ALREADY_INIT is not set
启用通用 SPI Master
文件 :ws63_liteos_app.config 修改:
diff
CONFIG_DRIVER_SUPPORT_SPI=y
#
# SPI Configuration
#
#
# Config SPI
#
- # CONFIG_SPI_SUPPORT_MASTER is not set
+ CONFIG_SPI_SUPPORT_MASTER=y
🔍 编译验证步骤
步骤 1:清理旧编译
bash
cd fbb_ws63-master
rm -rf src/build/cmake_build
rm -rf src/build/output
步骤 2:重新编译
bash
cd src
python build.py
步骤 3:检查编译错误
arduino
常见错误:
• "undefined reference to SFC_CLK"
→ 检查 platform_core_rom.h enum 定义
• "SFC initialization failed"
→ 检查 Pad 寄存器地址是否正确
• "Flash not detected"
→ 检查 GPIO 硬件连接
→ 检查 flash_config_info.c Flash ID
步骤 4:烧录和测试
bash
# 烧录新固件
./flashtool --boot src/build/output/bin/out.bin
# 通过串口观察 SFC 初始化日志
# 应看到类似:
# SFC: Identifying flash...
# SFC: Flash ID = 0x1640C8
# SFC: QSPI mode enabled
# SFC: Initialization success
⚠️ 常见陷阱
陷阱 1:忘记同时改多个文件
❌ 错误做法:
只改 platform_core_rom.h,没改 soc_porting.c
✅ 正确做法:
同时改:
• platform_core_rom.h(GPIO 号)
• soc_porting.c(Pad 地址)
• hal_pinctrl_ws63.c(配置范围)
陷阱 2:Pad 寄存器地址假设
ini
❌ 错误做法:
简单地加偏移:0x4400d868 + 8 = 0x4400d870
(实际可能不是线性关系)
✅ 正确做法:
从 WS63 数据手册查表获取准确地址
陷阱 3:Flash ID 匹配失败
arduino
❌ 错误现象:
Flash ID = 0xFFFFFF
✅ 排查步骤:
1. 用逻辑分析仪捕获 SPI 通信
2. 检查 GPIO_19-22 波形
3. 用 Flash 数据手册验证 read ID 命令
4. 检查 flash_config_info.c 中是否有该 ID
陷阱 4:QSPI 模式无法启用
markdown
❌ 错误现象:
始终运行在 SPI 而非 QSPI 模式
✅ 排查步骤:
1. 确认 Flash 数据手册支持 QSPI
2. 检查 flash_config_info.c 中 quad_mode 指针是否为 NULL
3. 验证 GPIO_23-24 的连接(仅 QSPI 用)
4. 检查 QSPI 使能命令是否正确
📚 参考资源
| 资源 | 说明 |
|---|---|
| WS63 数据手册 | Pad 地址查表、GPIO 功能 |
| Flash 数据手册 | 命令集、QSPI 支持、ID |
| GPIO_LITTLEFS_ANALYSIS.md | GPIO 配置原理 |
| SFC_GPIO_PIN_MAPPING.md | Pin 映射完整表 |
示例文档完成 | 用于学习和参考 | 实际使用需按硬件定制