前言
1.环境搭建 Zephyr开发环境搭建记录(Clion)
-
使用的开发板为正点原子的探索者:mcu使用的是STM32F407ZGT6
-
本篇参考示例spi_flash
-
开发环境使用Clion
参考说明
W25Q128部分原理图

W25Q128资料信息

DMA通道映射

参考示例

打开测试项目

项目配置编写(启用FLASH)
c
CONFIG_LOG=y
CONFIG_FLASH=y
CONFIG_FLASH_LOG_LEVEL_INF=y

设备树覆盖文件编写

- 完整overlay文件配置
c
/*
探索者开发板LED灯驱动
LED0 PF9
LED1 PF10
===================w25q128(SPI1)===================
SPI1_MISO == PB4
SPI1_SCK == PB3
SPI1_MOSI == PB5
SPI1_CS == PB14
*/
// 定义根节点,包含整个设备树的主要配置
/ {
// 配置系统选择项,指定控制台和shell使用的UART接口
chosen {
// 指定系统控制台使用USART1
zephyr,console = &usart1;
// 指定shell命令行使用USART1
zephyr,shell-uart = &usart1;
};
// 定义LED设备节点,配置GPIO控制的LED
leds {
// 设置兼容性字符串,表示使用GPIO LED驱动
compatible = "gpio-leds";
// 定义第一个LED设备,别名为led_0
led_0: led_0 {
// 配置GPIO引脚为PF9(GPIOF端口第9号引脚),高电平有效
gpios = <&gpiof 9 GPIO_ACTIVE_HIGH>; // PF9
// 设置LED的标签名称
label = "User LED0";
};
// 定义第二个LED设备,别名为led_1
led_1: led_1 {
// 配置GPIO引脚为PF10(GPIOF端口第10号引脚),高电平有效
gpios = <&gpiof 10 GPIO_ACTIVE_HIGH>; // PF10
// 设置LED的标签名称
label = "User LED1";
};
};
// 定义别名节点,为设备树中的节点提供简短的别名引用
aliases {
// 将"led0"别名指向led_0节点
led0 = &led_0;
// 将"led1"别名指向led_1节点
led1 = &led_1;
usart1 = &usart1;
// 将"w25q128"别名指向w25q128节点
w25q128 = &w25q128;
};
};
&spi1 {
dmas = <&dma2 3 3 STM32_DMA_PERIPH_TX STM32_DMA_FIFO_FULL>,
<&dma2 3 2 STM32_DMA_PERIPH_RX STM32_DMA_FIFO_FULL>;
dma-names = "tx", "rx";
status = "okay";
// clk、mosi、miso
pinctrl-0 = <&spi1_sck_pb3 &spi1_miso_pb4 &spi1_mosi_pb5>;
pinctrl-names = "default";
cs-gpios = <&gpiob 14 GPIO_ACTIVE_LOW>;
w25q128: w25q128@0 {
compatible = "jedec,spi-nor";
size = <0x8000000>;
reg = <0>;
spi-max-frequency = <4000000>;
status = "okay";
jedec-id = [ef 40 18];
};
};
&dma2 {
status = "okay";
};
// 引用并修改预定义的usart1节点
&usart1 {
// 配置USART1的引脚控制,TX连接到PA9,RX连接到PA10
pinctrl-0 = <&usart1_tx_pa9>, <&usart1_rx_pa10>;
// 定义引脚控制配置的名称
pinctrl-names = "default";
// 设置串口通信波特率为115200
current-speed = <115200>;
// 启用此UART外设
status = "okay";
};
测试主函数编写
c
/*
* Copyright (c) 2025 Embeint Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/net_buf.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/flash.h>
#include <stdio.h>
#include <string.h>
// SPI测试
LOG_MODULE_REGISTER(test, LOG_LEVEL_DBG);
#define SPI_FLASH_TEST_REGION_OFFSET 0xff000
#define SPI_FLASH_SECTOR_SIZE 4096
const uint8_t erased[] = { 0xff, 0xff, 0xff, 0xff };
void single_sector_test(const struct device *flash_dev)
{
const uint8_t expected[] = { 0x55, 0xaa, 0x66, 0x99 };
const size_t len = sizeof(expected);
uint8_t buf[sizeof(expected)];
int rc;
LOG_DBG("\nPerform test on single sector");
/* Write protection needs to be disabled before each write or
* erase, since the flash component turns on write protection
* automatically after completion of write and erase
* operations.
*/
LOG_DBG("\nTest 1: Flash erase\n");
/* Full flash erase if SPI_FLASH_TEST_REGION_OFFSET = 0 and
* SPI_FLASH_SECTOR_SIZE = flash size
*/
rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET,
SPI_FLASH_SECTOR_SIZE);
if (rc != 0) {
LOG_DBG("Flash erase failed! %d\n", rc);
} else {
/* Check erased pattern */
memset(buf, 0, len);
rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
if (rc != 0) {
LOG_DBG("Flash read failed! %d\n", rc);
return;
}
if (memcmp(erased, buf, len) != 0) {
LOG_DBG("Flash erase failed at offset 0x%x got 0x%x\n",
SPI_FLASH_TEST_REGION_OFFSET, *(uint32_t *)buf);
return;
}
LOG_DBG("Flash erase succeeded!\n");
}
LOG_DBG("\nTest 2: Flash write\n");
LOG_DBG("Attempting to write %zu bytes\n", len);
rc = flash_write(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, expected, len);
if (rc != 0) {
LOG_DBG("Flash write failed! %d\n", rc);
return;
}
memset(buf, 0, len);
rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
if (rc != 0) {
LOG_DBG("Flash read failed! %d\n", rc);
return;
}
if (memcmp(expected, buf, len) == 0) {
LOG_DBG("Data read matches data written. Good!!\n");
} else {
const uint8_t *wp = expected;
const uint8_t *rp = buf;
const uint8_t *rpe = rp + len;
LOG_DBG("Data read does not match data written!!\n");
while (rp < rpe) {
LOG_DBG("%08x wrote %02x read %02x %s\n",
(uint32_t)(SPI_FLASH_TEST_REGION_OFFSET + (rp - buf)),
*wp, *rp, (*rp == *wp) ? "match" : "MISMATCH");
++rp;
++wp;
}
}
}
int main(void)
{
const struct device *flash_dev = DEVICE_DT_GET(DT_ALIAS(w25q128));
if (!device_is_ready(flash_dev)) {
LOG_ERR("%s: device not ready.\n", flash_dev->name);
return 0;
}
LOG_DBG("\n%s SPI flash testing\n", flash_dev->name);
LOG_DBG("==========================\n");
single_sector_test(flash_dev);
return 0;
}
测试结果
