0.1 基于SPI驱动框架驱动开发
RT-Thread提供了SPI类型设备的基本框架,其框架源码位于drivers/spi目录下,其中spi_core.c和spi_dev.c这两个文件是框架核心文件,其他的文件是基于SPI框架驱动的一些具体芯片的操作实现和对RT-Thread的其他组件的对接实现。
已实现的设备列表
文件名 |
所适配的设备类型 |
支持的设备 |
enc28j60.c |
以太网通信接口 |
enc28j60 |
spi_flash_at45dbxx.c |
串行FLASH存储器 |
AT45DB011D、AT45DB021D、 AT45DB041D、AT45DB081D AT45DB161D、AT45DB321D AT45DB642D |
spi_flash_gd.c |
串行FLASH存储器 |
GD25Q128 |
spi_flash_sfud.c |
串行FLASH存储器 |
理论上支持所有符合JEDEC标准的串行FLASH设备,在sfud_flash_def.h文件中末尾定义了支持列表,未支持的芯片自行添加。 |
spi_flash_sst25vfxx.c |
串行FLASH存储器 |
SST25VF020B、SST25VF040B、 SST25VF080B、SST25VF016B、 SST25VF032B、SST25VF064C |
spi_flash_w25qxx.c |
串行FLASH存储器 |
W25Q08、W25Q16、W25Q32、 W25Q64、W25Q128、W25Q256 |
spi_flash_w25qxx_mtd.c |
串行FLASH存储器 注:这个驱动会生成一个MTD设备 |
W25Q08、W25Q16、W25Q32、 W25Q64、W25Q128、W25Q256 |
spi_msd.c |
SD卡 |
SD卡 |
spi_wifi_rw009.c |
WIFI通信接口 |
RW009模块,由RT-Thread官方提供。 |
0.2 驱动设计和挂载流程
1、 实现SPI配置函数。接口原型:rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
2、 实现SPI收发函数。接口原型:rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);
3、 实现SPI 使能操作函数,这个函数需要自行定义接口。
4、 注册SPI BUS类型设备,此过程需要用到1、2两步中的函数。
5、 在SPI BUS上添加一个目标设备,此过程需要第3步中的函数。
0.3 SPI配置函数实现方法
0.3.1 入口参数:
struct rt_spi_device* device:SPI设备指针,用于判定初始化哪个SPI设备。
struct rt_spi_configuration* configuration:具体配置参数。
rt_spi_configuration结构体成员列表
成员名称 |
类型 |
作用 |
备注 |
mode |
rt_uint8_t |
设置SPI模式设定 |
需要用下表宏定义 |
data_width |
rt_uint8_t |
设置SPI数据宽度 |
一般为8和16 |
reserved |
rt_uint8_t |
保留 |
|
max_hz |
rt_uint32_t |
设置最大工作频率 |
以hz为单位,不是mhz |
mode设置需要用的宏定义
宏定义名 |
定义 |
位号 |
RT_SPI_MODE_0 |
CPOL = 0, CPHA = 0 |
bit0和bit1 |
RT_SPI_MODE_1 |
CPOL = 0, CPHA = 1 |
|
RT_SPI_MODE_2 |
CPOL = 1, CPHA = 0 |
|
RT_SPI_MODE_3 |
CPOL = 1, CPHA = 1 |
|
RT_SPI_LSB |
低位数据在前 |
bit2 |
RT_SPI_MSB |
高位数据在前 |
|
RT_SPI_MASTER |
主机模式 |
bit3 |
RT_SPI_SLAVE |
从机模式 |
使用驱动时按照位进行或即可,驱动程序需要判定mode的这些位进行设置。
例如设置CPOL=1 CPHA=0 主机模式 高位在前,
mode = RT_SPI_MODE_2 | RT_SPI_MSB | RT_SPI_MASTER;
函数实现过程:
1、 判定输入参数是否为空
if(device == RT_NULL || configuration==RT_NULL) return RT_EIO;
2、 根据configuration中的data_width成员设置数据位宽
由于STM32的SPI硬件仅支持8位和16位两种模式,其他情况直接返回RT_EIO通知错误
if(configuration->data_width!=8 &&
configuration->data_width!=16)
{return RT_EIO;}
else{//这里设置SPI硬件}
3、 根据configuration中的max_hz设置SPI工作频率
4、 根据configuration中的mode设置SPI工作模式
a) 设置CPOL
if(configuration->mode
& RT_SPI_CPOL)
{//CLK空闲时为高电平}
else
{//CLK空闲时为低电平}
b) 设置CPHA
if(configuration->mode & RT_SPI_CPHA)
{//CLK上升沿采样}
else
{//CLK下降沿采样}
c) 设置MSB/LSB
if(configuration->mode & RT_SPI_MSB)
{//高位数据在前}
else
{//低位数据在前}
d) 设置MASTER/SLAVE
if(configuration->mode & RT_SPI_SLAVE)
{//从机模式}
else
{//主机模式}
5、初始化SPI设备
0.4 SPI收发函数实现方法
0.4.1 入口参数:
struct rt_spi_device* device:SPI设备指针,用于判定使用哪个SPI设备进行收发。
struct rt_spi_message* message:SPI收发数据结构体指针。
rt_spi_message结构体成员列表
成员名称 |
类型 |
作用 |
备注 |
send_buf |
const void * |
待发送的数据指针 |
驱动中需要强转 |
recv_buf |
void * |
待接收数据的指针 |
驱动中需要强转 |
length |
rt_size_t |
收发长度 |
|
next |
struct rt_spi_message * |
链表下指针 |
驱动无需关心 |
cs_take |
unsigned |
是否使能CS引脚 |
|
cs_ release |
unsigned |
是否释放CS引脚 |
|
实现实例解释:
const uint8_t *send_p;//发送数据指针
uint8_t *rec_p;//接收数据指针
uint8_t dat ;//临时变量
rt_size_t size;//存储数据长度变量
//指针强转 取得SPI 使能操作结构体指针
struct rt_spi_cs *csP = (struct rt_spi_cs *)device->parent.user_data;
//设定发送数据指针地址
send_p = (uint8_t *)message->send_buf;
//设定接收数据指针地址
rec_p = (uint8_t *)message->recv_buf;
//设定数据长度
size = message->length;
//判定是否使能SPI设备
if(message->cs_take)
{
//判空
if(csP != RT_NULL)
{
//调用使能操作函数
csP->spi_cs_enable();
}
}
//根据数据长度进行循环
while(size--)
{
//临时变量给FF
dat = 0xff;
//判定发送指针是否为空
if(send_p != RT_NULL)
{
//获取需要发送的数据并移动发送指针
dat = *send_p++;
}
//调用SPI发送函数 并返回SPI读取到的数据
dat = SPI_FLASH_ReadWriteByte(dat);
//判定接收指针是否为空
if(rec_p != RT_NULL)
{
//将接收到的数据赋值为接收指针并移动接收指针
*rec_p++ = dat;
}
}
//判定是否需要SPI禁能操作
if(message->cs_release)
{
//判空
if(csP != RT_NULL)
{
//调用SPI禁能函数
csP->spi_cs_disable();
}
}
返回长度值
return message->length;
0.5 SPI操作实现方法
SPI设备驱动框架中没有明确指定SPI使能操作结构体,这里需要自己定义并实现SPI使能操作。
实现实例:
//声明使能操作结构体
struct rt_spi_cs
{
void (*spi_cs_enable)(void); //使能操作
void (*spi_cs_disable)(void); //禁能操作
}rt_spi_cs ;
//实现使能操作函数
void SPI_FLASH_CS_Select(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
}
//实现禁能操作函数
void SPI_FLASH_CS_Deselect(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_8);
}
//定义使能结构体实例
struct rt_spi_cs spi2_cs =
{
SPI_FLASH_CS_Select,
SPI_FLASH_CS_Deselect
};
0.6 添加设备到操作系统
添加设备至少需要两步,先注册SPI BUS总线设备,在这个总线设备上添加真正的SPI设备。
0.6.1 注册SPI BUS总线设备
//先配置SPI硬件
SPI_Init();
//建立SPI BUS设备
//定义SPI BUS结构体
struct rt_spi_bus spi2_bus;
//定义SPI BUS操作结构体
struct rt_spi_ops spi2_ops=
{
SPI2_Configure,
SPI2_xfer
};
//将SPI BUS操作结构体赋值给OPS
spi2_bus.ops = &spi2_ops;
//注册SPI BUS设备
rt_spi_bus_register(&spi2_bus,"spi2",&spi2_ops);
0.6.2 添加SPI 设备
//定义SPI设备结构体
struct rt_spi_device spi2_device;
spi2_device.bus = &spi2_bus;//将上一步的BUS设备赋值给SPI设备的BUS成员
spi2_device.user_data = RT_NULL;//user data赋值为空
//注册SPI设备 最后一个参数放SPI使能结构体指针
rt_spi_bus_attach_device(&spi2_device,"spi2flash","spi2",&spi2_cs);


回复于 2018-12-14
2#
块
导
航
举报
请选择举报类别
- 广告垃圾
- 违规内容
- 恶意灌水
- 重复发帖