[资料] 【填坑】【RT-Thread驱动开发】SPI设备
1087 查看
5 回复
 楼主 | 发布于 2018-12-02 | 只看楼主
分享到:

0.1   基于SPI驱动框架驱动开发

RT-Thread提供了SPI类型设备的基本框架,其框架源码位于drivers/spi目录下,其中spi_core.cspi_dev.c这两个文件是框架核心文件,其他的文件是基于SPI框架驱动的一些具体芯片的操作实现和对RT-Thread的其他组件的对接实现。

 

已实现的设备列表

文件名

所适配的设备类型

支持的设备

enc28j60.c

以太网通信接口

enc28j60

spi_flash_at45dbxx.c

串行FLASH存储器

AT45DB011DAT45DB021D

AT45DB041DAT45DB081D

AT45DB161DAT45DB321D

AT45DB642D

spi_flash_gd.c

串行FLASH存储器

GD25Q128

spi_flash_sfud.c

串行FLASH存储器

理论上支持所有符合JEDEC标准的串行FLASH设备,在sfud_flash_def.h文件中末尾定义了支持列表,未支持的芯片自行添加。

spi_flash_sst25vfxx.c

串行FLASH存储器

SST25VF020BSST25VF040B

SST25VF080BSST25VF016B

SST25VF032BSST25VF064C

spi_flash_w25qxx.c

串行FLASH存储器

W25Q08W25Q16W25Q32

W25Q64W25Q128W25Q256

spi_flash_w25qxx_mtd.c

串行FLASH存储器

注:这个驱动会生成一个MTD设备

W25Q08W25Q16W25Q32

W25Q64W25Q128W25Q256

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类型设备,此过程需要用到12两步中的函数。

5、 SPI BUS上添加一个目标设备,此过程需要第3步中的函数。

 

0.3   SPI配置函数实现方法

0.3.1       入口参数:

struct rt_spi_device* deviceSPI设备指针,用于判定初始化哪个SPI设备。

struct rt_spi_configuration* configuration:具体配置参数。

 

rt_spi_configuration结构体成员列表

成员名称

类型

作用

备注

mode

rt_uint8_t

设置SPI模式设定

需要用下表宏定义

data_width

rt_uint8_t

设置SPI数据宽度

一般为816

reserved

rt_uint8_t

保留

 

max_hz

rt_uint32_t

设置最大工作频率

hz为单位,不是mhz

mode设置需要用的宏定义

宏定义名

定义

位号

RT_SPI_MODE_0

CPOL = 0, CPHA = 0

bit0bit1

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成员设置数据位宽

由于STM32SPI硬件仅支持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* deviceSPI设备指针,用于判定使用哪个SPI设备进行收发。

struct rt_spi_message* messageSPI收发数据结构体指针。

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);

本帖有更多资源,需 登录 才可以下载,没有帐号?立即 注册

(0 ) (0 )
回复 举报

回复于 2018-12-03 沙发

感谢分享
(0 )
评论 (0) 举报

回复于 2018-12-14 2#

感谢分享!!需要机器人(工业,服务)的设计方案;自动化设备改造(螺丝机,点胶机等)以及个电子相关的新产品研发(微信调控暖手宝温度等)。
(0 )
评论 (0) 举报

回复于 2020-02-05 3#

感谢分享
(0 )
评论 (0) 举报

回复于 2020-02-08 4#

感谢分享
(0 )
评论 (0) 举报

回复于 2020-02-08 5#

感谢分享
(0 )
评论 (0) 举报
  • 发表回复
    0/3000





    举报

    请选择举报类别

    • 广告垃圾
    • 违规内容
    • 恶意灌水
    • 重复发帖

    全部板块

    返回顶部