提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
MCU:STM32F091CC
IDE:RT-Thread Studio 2.2.1
IO对应关系(SPI2):
功能 | IO |
---|---|
MISO | PB14 |
MOSI | PB15 |
SCK | PB13 |
CS | PB12 |
参考资料:
1.RTT官方SPI文档
2.在潘多拉上使用 SFUD 操作 Flash
一、SFUD 是什么?
SFUD (Serial Flash Universal Driver) 是一款开源的串行 SPI Flash 通用驱动库。
二、使用步骤
1.添加SPI2总线
- 打开SPI及SFUD的驱动框架
- 在Board.h中定义SPI使用
- 在stm32f0xx_hal_conf.h中打开 HAL 库对 SPI 的支持
- 初始化IO及时钟
使用CubeMX生成HAL_SPI_MspInit(),并将其复制到board.c中。
备注:NSS使用软件控制。
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}
- 下载运行
- 可以看到SPI2添加成功了。
2.W25Q128读写操作
- 挂载 SPI FLASH W25Q128 到 SPI 总线:
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);
if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi20"))
{
return -RT_ERROR;
};
return RT_EOK;
}
/* 导出到自动初始化 */
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
- 读取 SPI FLASH W25Q128的ID :
#define W25Q_SPI_DEVICE_NAME "spi20"
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_spi_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_spi_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);
读取成功如图
- 使用SFUD写/读 W25Q128 :
#include "spi_flash.h"
#include "./sfud/inc/sfud.h"
static void spi_w25q_sf_sample(int argc, char *argv[])
{
uint8_t *read_data; // 读取到的数据
uint8_t *write_data; // 将要写入的数据
sfud_flash *sfud_dev = NULL;
sfud_err ret;
sfud_dev = rt_sfud_flash_find("spi20"); // 获取 sfud_dev
// 或者 sfud_dev = rt_sfud_flash_find_by_dev_name("W25Q128");
write_data = rt_malloc(32);
rt_memset(write_data, '1', 32);
ret = sfud_erase_write(sfud_dev, 0, 32, write_data); // 将数据 32 字节的 write_data 从 0 开始写入 flash
if(ret == SFUD_SUCCESS)
{
rt_kprintf("sfud write data at 0 is:%s\n", write_data);
}
else
{
rt_kprintf("sfud write data failed\n");
}
read_data = rt_malloc(32);
ret = sfud_read(sfud_dev, 0, 32, read_data); // 读取从 0 开始的 32 字节,存入 read_data
if(ret == SFUD_SUCCESS)
{
rt_kprintf("sfud read data at 0 is:%s\n", read_data);
}
else
{
rt_kprintf("sfud read data failed\n");
}
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(spi_w25q_sf_sample, spi w25q sf sample);