1、基于芯片创建工程
2、QSPI配置
2.1、RTThing_setting 设置组件
2.2、配置board.h 文件
2.3、cubemx生成QSPI的硬件初始化代码;HAL_QSPI_MapInit;
这里注意:你所买的开发板对应的qspi 连接的是否是cubemx 上边显示的,如果不是你需要将引脚复用为你的开发板上原理图的引脚;
比如:正点原子潘多拉 stm32l475vet6的原理图
我们就需要找到运力图的引脚将其复用;
将QSPI使能之后保存工程,并生成代码;
然后打开RTThread Studio 刷新工程后找到 cubx 目录下生成的代码,打开stm32l4xx_hal_map.c文件,将 HAL_QSPI_MapInit() 和HAL_QSPI_DeMapInit()这两个函数复制到 board.c 即可;
这两个函数是HAL 库中的弱回调函数,drv_qspi.c 函数会调用这两个函数;如果想了解具体的流程
可以了解一下hal 库的弱回调函数;
2.4、配置stm32l4_hal_conf.h
加入#define HAL_QSPI_MODULE_ENABLED,(这个在配置第一步后好像自动生成了宏定义,但是官方还是给了第四部的操作;)
2.5重新启动程序
这里cubemx 目录下会提示报错,右键将其排除构建即可;
3、W25Q128测试应用程序编写;
在application 下新建test_w25q128.c 文件;
3.1、挂载与初始化SPI设备;
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-04-07 29232 the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define QSPI_BUS_NAME "qspi1"
#define QSPI_DEVICE_NAME "qspi10"
#define W25Q_FLASH_NAME "W25Q128FV"
#define QSPI_CS_PIN GET_PIN(E,11)
static int rt_hw_qspi_flash_with_sfud_init(void)
{
stm32_qspi_bus_attach_device(QSPI_BUS_NAME , QSPI_DEVICE_NAME, (uint32_t)GET_PIN(E,11), 4,RT_NULL, RT_NULL);
/* init w25q128 */
if (RT_NULL == rt_sfud_flash_probe(W25Q_FLASH_NAME, QSPI_DEVICE_NAME))
{
rt_kprintf("init_failed\n");
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_qspi_flash_with_sfud_init);
启动代码 查看是否挂载 初始化成功;
3.3、查看ID
新建 sample_qspi.c
编写以下代码:
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-15 misonyo first implementation.
*/
/*
* 程序清单:这是一个 QSPI 设备使用例程
* 例程导出了 spi_w25q_sample 命令到控制终端
* 命令调用格式:spi_w25q_sample spi10
* 命令解释:命令第二个参数是要使用的SPI设备名称,为空则使用默认的SPI设备
* 程序功能:通过SPI设备读取 w25q 的 ID 数据
*/
#include <rtthread.h>
#include <rtdevice.h>
#define W25Q_SPI_DEVICE_NAME "qspi10"
static void spi_w25q_sample(int argc, char *argv[])
{
struct rt_spi_device *spi_dev_w25q;
char name[RT_NAME_MAX];
rt_uint8_t w25x_read_id = 0x90;
rt_uint8_t id[5] = {0};
if (argc == 2)
{
rt_strncpy(name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX);
}
/* 查找 spi 设备获取设备句柄 */
spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name);
if (!spi_dev_w25q)
{
rt_kprintf("spi sample run failed! can't find %s device!\n", name);
}
else
{
/* 方式1:使用 rt_spi_send_then_recv()发送命令读取ID */
rt_qspi_send_then_recv(spi_dev_w25q, &w25x_read_id, 1, id, 5);
rt_kprintf("use rt_spi_send_then_recv() read w25q ID is:%x%x\n", id[3], id[4]);
/* 方式2:使用 rt_spi_transfer_message()发送命令读取ID */
struct rt_spi_message msg1, msg2;
msg1.send_buf = &w25x_read_id;
msg1.recv_buf = RT_NULL;
msg1.length = 1;
msg1.cs_take = 1;
msg1.cs_release = 0;
msg1.next = &msg2;
msg2.send_buf = RT_NULL;
msg2.recv_buf = id;
msg2.length = 5;
msg2.cs_take = 0;
msg2.cs_release = 1;
msg2.next = RT_NULL;
rt_qspi_transfer_message(spi_dev_w25q, &msg1);
rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]);
}
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(spi_w25q_sample, spi w25q sample);
这里需要注意 如果你是使用的QSPI的主设备,函数要使用QSPI的接口读写函数,不能使用SPI的读写函数,否则回报 read data error;