SPI MASTER FLASH
SPI简介
SPI(Serial Peripheral Interface,串行外设接口)是一种高速、全双工、同步通信总线,常用于短距离通讯,主要应用于 EEPROM、FLASH、实时时钟、AD 转换器、还有数字信号处理器和数字信号解码器之间。
关于SPI总线介绍可详细查看RT-Thread官网的介绍:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi
驱动支持
访问SPI总线设备前,需要保证相关驱动配置已选中。
Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。
Linux环境:在代码根目录下执行scons --menuconfig进入配置。
SPI MASTER驱动所在路径如下:
RT-Thread Components -> Device Drivers -> Using SPI Bus/Device device drivers
打开驱动配置
上述配置选中后,相关的GPIO配置也需要配置,打开源码文件:board/board.h需要打开相关注释,如下所示:
#define BSP_USING_SOFTWARE_SPIM
#define BSP_SPIM_MOSI_PIN GET_PIN(A, 3)//"A3"
#define BSP_SPIM_MISO_PIN GET_PIN(A, 2)//"A2"
#define BSP_SPIM_SCK_PIN GET_PIN(A, 0)//"A0"
注:这里使用的是软件模拟SPI操作,也就是通过GPIO模拟SPI协议进行通信,有利于指定其他GPIO用以验证SPI基本读写功能。
访问FLASH
访问SPI MASTER设备,库中提供了以下接口:
函数 | 描述 |
---|---|
rt_hw_spi_device_attach() | 往SPI总线上挂载从设备 |
rt_device_find() | 根据 SPI 设备名称查找设备获取设备句柄 |
rt_spi_transfer_message() | 收发SPI MASTER数据 |
往SPI总线上挂载从设备
SPI总线可以挂载多个从设备,每多挂载一个从设备都需要先注册,绑定其CS(片选)脚,函数原型如下所示:
rt_err_t rt_hw_spi_device_attach(const char* bus_name,
const char* device_name,
GPIO_TypeDef* cs_gpiox,
uint16_t cs_gpio_pin);
-
参数
[IN]bus_name:总线设备名称,目前注册到的系统中的SPI总线名称为"spim"。
[IN]device_name:从设备名称,可以为自定义字符串,字符串长度不能大于8个字符,且不能与系统已有的其他设备名称相同。
[IN]cs_gpiox:GPIO配置控制器,由于AP板子的UC8088只有一个GPIO配置控制器,因此,这里参数不作处理,直接赋值为RT_NULL即可。
[IN]cs_gpio_pin:绑定的GPIO引脚,需要指定GPIO引脚作为CS脚。
// GPIO定义所在文件相对路径: // libraries/UC8088_HAL_Driver/inc/uc_gpio.h typedef enum { GPIO_PIN_0 = 0, GPIO_PIN_1 = 1, GPIO_PIN_2 = 2, GPIO_PIN_3 = 3, GPIO_PIN_4 = 4, GPIO_PIN_5 = 5, GPIO_PIN_6 = 6, GPIO_PIN_7 = 7, GPIO_PIN_8 = 8, GPIO_PIN_9 = 9, GPIO_PIN_10 = 10, GPIO_PIN_11 = 11, GPIO_PIN_12 = 12, GPIO_PIN_13 = 13, GPIO_PIN_14 = 14, GPIO_PIN_15 = 15, GPIO_PIN_16 = 16, GPIO_PIN_17 = 17, GPIO_PIN_18 = 18, GPIO_PIN_19 = 19, GPIO_PIN_20 = 20, GPIO_PIN_21 = 21, GPIO_PIN_22 = 22, GPIO_PIN_24 = 24, GPIO_PIN_25 = 25, GPIO_PIN_26 = 26, GPIO_PIN_27 = 27, GPIO_PIN_28 = 28, GPIO_PIN_29 = 29, } GPIO_PIN; /* pin number */
-
返回值
RT_EOK:成功
其他:错误,RT-Thread定义的错误类型
注:实际使用该函数时,可以不关心函数返回值,这是因为其内部发生错误时将产生断言,使系统停止工作。
查找SPI MASTER设备
查找SPI MASTER设备,函数原型如下所示:
rt_device_t rt_device_find(const char* name);
-
参数
[IN]name:SPI从设备名称,与往SPI总线上挂载从设备函数参数device_name保持一致。
-
返回值
RT_NULL:失败,设备不存在。
非RT_NULL:成功,该返回值是操作SPI MASTER设备的句柄,在后续的接口中作为函数入参。
收发SPI MASTER数据
收发指定SPI MASTER设备数据,函数原型如下所示:
struct rt_spi_message* rt_spi_transfer_message(
struct rt_spi_device* device,
struct rt_spi_message* message);
-
参数
[IN]device:SPI MASTER设备句柄,查找设备函数的返回值
[INOUT]message:输入/输出数据,对应结构体为 struct rt_spi_message定义如下:
// 结构体定义所在文件相对路径: // rt-thread\components\drivers\include\drivers\spi.h struct rt_spi_message { const void* send_buf; // 发送数据内容缓存,需要rt_malloc()申请空间 void* recv_buf; // 接收数据内容缓存,需要rt_malloc()申请空间 rt_size_t length; // 发送或接收字节长度 struct rt_spi_message* next; // 下一次SPI通信数据,若无置为RT_NULL unsigned cs_take : 1; // 第一个收/发数据时,置1,表示开始产生SPI时钟信号,后续数据该位置0 unsigned cs_release : 1; // 最后一个收/发数据时,置1,表示结束产生SPI时钟信号 };
-
返回值
RT_NULL,错误,message为RT_NULL。
不为空,则返回message指针。
注:执行该函数后可通过以下函数获取是否成功状态:
// 函数声明所在文件相对路径: // rt-thread/include/rtthread.h // 函数返回RT-Thread定义的错误类型 rt_err_t rt_get_errno(void);
FLASH使用示例
使用示例需要配置menuconfig打开配置(默认关闭),路径如下:
wiota APP -> open spi master, default close(_SPI_MASTER_FLASH_APP_)
以下提供SPI MASTER FLASH测试实例,测试步骤如下:
- 擦除数据。
- 写入数据。
- 读出数据。
#include <rtthread.h>
#ifdef _SPIM_FLASH_APP_
#include <rtdevice.h>
#include <stdlib.h>
#include <time.h>
#include "uc_gpio.h"
#include "drv_spi.h"
#include "uc_spim_flash_app.h"
#define SPIM_NAME ("spim0")
#define FLASH_CLK (6 * 1000 * 1000)
#define FLASH_CS_PIN (GPIO_PIN_13)
#define FLASH_DATA_ADDR (0x7D000)
#define FLASH_DATA_LEN (1024)
static struct rt_spi_device *spim_dev = RT_NULL;
static int spim_flash_app_init(void)
{
spim_dev = spim_api_init(SPIM_NAME, FLASH_CS_PIN, FLASH_CLK);
if (spim_dev)
{
return RT_EOK;
}
else
{
return RT_ERROR;
}
}
void spim_flash_app_sample(void)
{
rt_err_t ret = RT_EOK;
rt_uint8_t *wr_buf = (rt_uint8_t *)rt_calloc(1, FLASH_DATA_LEN);
rt_uint8_t *rd_buf = (rt_uint8_t *)rt_malloc(FLASH_DATA_LEN);
rt_int32_t index = 0;
rt_kprintf("enter spim_flash_app_sample()\r\n");
srand(time(0));
for (index = 0; index < FLASH_DATA_LEN; index++)
{
wr_buf[index] = rand() & 0xFF;
}
do
{
ret = spim_flash_app_init();
if (ret != RT_EOK)
{
rt_kprintf("spi flash init failed!\n");
break;
}
flash_erase(spim_dev, FLASH_DATA_ADDR, FLASH_DATA_LEN);
flash_page_program(spim_dev, FLASH_DATA_ADDR, wr_buf, FLASH_DATA_LEN, SPIM_BIG);
flash_page_read(spim_dev, rd_buf, FLASH_DATA_LEN, FLASH_DATA_ADDR, SPIM_BIG);
if (rt_memcmp(wr_buf, rd_buf, FLASH_DATA_LEN))
{
rt_kprintf("data diff!\n");
}
else
{
rt_kprintf("data same\n");
}
} while (0);
rt_free(wr_buf);
rt_free(rd_buf);
}
#endif