外观
SPI NorFlash 读写
2025-10-29
本文将详细介绍如何通过 SPI 总线实现设备通信,以 W25Q NorFlash 为例演示读取厂商 ID 和设备 ID,帮助读者掌握 SPI 总线的标准通信流程及外设控制方法。
W25Q NorFlash
W25Q NorFlash 是一款高性能的串行闪存存储器,通过 SPI 总线接口实现高速数据传输,具备快速读写和低功耗特性。该器件采用非易失性存储技术,即使在断电情况下数据也能长期保存,适用于需要大容量、高速度数据存储的应用场景,如固件存储、多媒体数据缓存等。其内建的写保护机制和灵活的扇区/块擦除功能,进一步提升了数据的安全性和操作效率。
读取 W25Q NorFlash 设备的数据
本示例展示如何通过 SPI 总线对 W25Q NorFlash 设备进行读取厂商 ID 和设备 ID,确保 NorFlash 正常工作。
硬件连接
开发板的 SPI 与 W25Q 硬件连接,如图所示:

查手册获取 Flash 的 ID
通过查阅 W25Q128 的数据手册,可以了解到 W25Q128 芯片的 MANUFACTURER ID 和 DEVICE_ID 为 0xEF 和 0x17:

创建工程点击展开
依次点击 “文件” -> “新建” -> "RT-Thread RuiChing App 项目"。

在弹出新建向导中选择 开发版 、BSP: 、示例 、 调试器/下载器。选择好之后点击 “完成”。

点击 “完成” 后,等待工程创建完成。

创建完成。

构建工程点击展开
单击工程使工程进入 Active-Debug 模式。

点击工具栏上的构建按钮进行工程编译。

构建成功后,会显示构建成功的信息。

固件下载点击展开
固化设备树

固化 APP

核心示例代码
SPI 示例相关代码说明
rt_spi_bus_attach_device_cspin:该函数实现了 SPI 从设备的注册流程,包括设备句柄、设备的名称、挂载的总线名称和cs引脚。rt_spi_configure:该函数实现了 SPI 从设备配置流程,包括设备模式,数据宽度,支持的最大通信速率。rt_spi_transfer:该函数实现了向 w25q 设备发送 0x90 指令读取厂商 ID 和设备 ID 的命令。
spi_example.c
static rt_err_t spi_device_init(void)
{
rt_err_t ret = RT_EOK;
struct rt_spi_device *dev;
struct rt_spi_configuration cfg = {
.mode = RT_SPI_MODE_0 | RT_SPI_MSB,
.data_width = 8,
.max_hz = 400000,
};
if (rt_device_find(SPI_DEVICE_NAME) == RT_NULL)
{
dev = rt_malloc(sizeof(struct rt_spi_device));
if (dev == RT_NULL)
{
LOG_E("malloc dev failed");
ret = (-RT_ERROR);
goto dev_err;
}
ret = rt_spi_bus_attach_device_cspin(
dev, SPI_DEVICE_NAME, SPI_BUS_NAME, SPI_CS_PIN, RT_NULL);
if (ret != RT_EOK)
{
LOG_E("mount spi bus failed");
ret = (-RT_ERROR);
goto attach_err;
}
}
dev = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
if (dev == RT_NULL)
{
LOG_E("not find device %s", SPI_DEVICE_NAME);
ret = (-RT_ERROR);
goto dev_err;
}
rt_spi_configure(dev, &cfg);
...
}
static int spi_transfer(void)
{
struct rt_spi_device *spi_dev_w25q = RT_NULL;
rt_uint8_t w25x_read_id[6] = { 0x90, 0x00, 0x00, 0x00, 0x00, 0x00 };
rt_uint8_t id[6] = { 0 };
if (spi_device_init() != RT_EOK)
{
return (-RT_ERROR);
}
spi_dev_w25q = (struct rt_spi_device *)rt_device_find(SPI_DEVICE_NAME);
rt_spi_transfer(spi_dev_w25q, w25x_read_id, id, 6);
LOG_I("use rt_spi_transfer() read w25q ID is: 0x%X%X", id[4], id[5]);
return RT_EOK;
}运行程序
开发板运行程序后,在终端输入 spi_transfer 命令,结果如下:
在整个命令执行期间,系统将执行以下操作:
向
w25q设备发送0x90指令读取厂商 ID 和设备 ID;打印读取到的厂商 ID 和设备 ID。
msh />spi_transfer
[I/example.spi] use rt_spi_transfer() read w25q ID is: 0xEF17