Zephyr学习之spi flash驱动记录(w25q128)

前言

1.环境搭建 Zephyr开发环境搭建记录(Clion)

  1. 使用的开发板为正点原子的探索者:mcu使用的是STM32F407ZGT6

  2. 本篇参考示例spi_flash

  3. 开发环境使用Clion

参考说明

W25Q128部分原理图

W25Q128资料信息

DMA通道映射

参考示例

打开测试项目

项目配置编写(启用FLASH)

c 复制代码
CONFIG_LOG=y
CONFIG_FLASH=y
CONFIG_FLASH_LOG_LEVEL_INF=y

设备树覆盖文件编写

  1. 完整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;
}

测试结果

相关推荐
yanyu-yaya2 小时前
速学兼复习之vue3章节3
前端·javascript·vue.js·学习·前端框架
沉默-_-3 小时前
微信小程序网络请求 wx.request 详解
网络·学习·微信小程序·小程序
嗯嗯=3 小时前
STM32单片机学习篇5
stm32·单片机·学习
头疼的程序员4 小时前
计算机网络:自顶向下方法(第七版)第二章 学习分享(二)
学习·计算机网络
沉默-_-5 小时前
微信小程序页面配置详解
学习·微信小程序·apache·微信开发者工具
北京云帆互联科技5 小时前
云帆学习考试系统更新说明v8.8.0
学习·考试系统·高校考试系统
Quintus五等升5 小时前
深度学习③|分类任务—AlexNet
人工智能·经验分享·深度学习·神经网络·学习·机器学习·cnn
张心独酌5 小时前
学习Rust:实现RESTful 任务管理 API(Todo API)
学习·rust·restful
反向跟单策略6 小时前
如何正确看待期货反向跟单策略?
大数据·人工智能·学习·数据分析·区块链