首页 技术 正文
技术 2022年11月17日
0 收藏 915 点赞 3,690 浏览 3772 个字

spi_device

虽然用户空间不需要直接用到spi_device结构体,但是这个结构体和用户空间的程序有密切的关系,理解它的成员有助于理解SPI设备节点的IOCTL命令,所以首先来介绍它。在内核中,每个spi_device代表一个物理的SPI设备:

struct spi_device {structdevice dev;structspi_master *master;u32 max_speed_hz; /* 通信时钟最大频率 */u8 chip_select; /* 片选号 */u8 mode; /*SPI设备的模式,下面的宏是它各bit的含义 */#define SPI_CPHA 0x01 /* 采样的时钟相位 */#define SPI_CPOL 0x02 /* 时钟信号起始相位:高或者是低电平 */#define SPI_MODE_0 (0|0)#define SPI_MODE_1 (0|SPI_CPHA)#define SPI_MODE_2 (SPI_CPOL|0)#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)#define SPI_CS_HIGH 0x04 /* 为1时片选的有效信号是高电平 */#define SPI_LSB_FIRST 0x08 /* 发送时低比特在前 */#define SPI_3WIRE 0x10 /* 输入输出信号使用同一根信号线 */#define SPI_LOOP 0x20 /* 回环模式 */u8 bits_per_word; /* 每个通信字的字长(比特数) */int irq; /*使用到的中断 */void *controller_state;void *controller_data;]; /* 设备驱动的名字 */};

spi_device的mode成员有两个比特位含义很重要:

SPI_CPHA选择对数据线采样的时机,0选择每个时钟周期的第一个沿跳变时采样数据,1选择第二个时钟沿采样数据;

SPI_CPOL选择每个时钟周期开始的极性,0表示时钟以低电平开始,1选择高电平开始。

这两个比特有四种组合,对应SPI_MODE_0~SPI_MODE_3。

另一个比较重要的成员是bits_per_word。这个成员指定每次读写的字长,单位是比特。虽然大部分SPI接口的字长是8或者16,仍然会有一些特殊的例子。需要说明的是,如果这个成员为零的话,默认使用8作为字长。

最后一个成员并不是设备的名字,而是需要绑定的驱动的名字。

spi_ioc_transfer

linux中,应用开发常用的结构体主要是struct spi_ioc_transfer:

struct spi_ioc_transfer {    __u64        tx_buf;    __u64        rx_buf;    __u32        len;    __u32        speed_hz;    __u16        delay_usecs;    __u8        bits_per_word;    __u8        cs_change;    __u32        pad;};

每个 spi_ioc_transfer都可以包含读和写的请求,其中读和写的长度必须相等。所以成员len不是tx_buf和rx_buf缓冲的长度之和,而是它们各自的长度。SPI控制器驱动会先将tx_buf写到SPI总线上,然后再读取len长度的内容到rx_buf。如果只想进行一个方向的传输,把另一个方向的缓冲置为0就可以了。

speed_hz和bits_per_word这两个成员可以为每次通信配置不同的通信速率(必须小于spi_device的max_speed_hz)和字长,如果它们为0的话就会使用spi_device中的配置。

delay_usecs可以指定两个spi_ioc_transfer之间的延时,单位是微妙。一般不用定义。

cs_change指定这个cs_change结束之后是否需要改变片选线。一般针对同一设备的连续的几个spi_ioc_transfer,只有最后一个需要将这个成员置位。这样省去了来回改变片选线的时间,有助于提高通信速率。

SPI设备的初始化

void spi_Init(){    ;    spifd = open(device, O_RDWR);    )        pabort("can't open device");    /*     * spi mode     */    ret = ioctl(spifd, SPI_IOC_WR_MODE, &mode);    )        pabort("can't set spi mode");    ret = ioctl(spifd, SPI_IOC_RD_MODE, &mode);    )        pabort("can't get spi mode");    /*     * bits per word     */    ret = ioctl(spifd, SPI_IOC_WR_BITS_PER_WORD, &bits);    )        pabort("can't set bits per word");    ret = ioctl(spifd, SPI_IOC_RD_BITS_PER_WORD, &bits);    )        pabort("can't get bits per word");    /*     * max speed hz     */    ret = ioctl(spifd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);    )        pabort("can't set max speed hz");    ret = ioctl(spifd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);    )        pabort("can't get max speed hz");}

首先open打开SPI的设备,然后通过ioctl函数进行数据位、速率、模式进行配置。

IOCTL命令

用户空间对spidev设备节点使用IOCTL命令失败会返回-1。

SPI_IOC_RD_MODE

读取SPI设备对应的spi_device.mode,使用的方法如下:

ioctl(fd,SPI_IOC_RD_MODE, &mode);

其中第三个参数是一个uint8_t类型的变量

SPI_IOC_WR_MODE

设置SPI设备对应的spi_device.mode。使用的方式如下:

ioctl(fd,SPI_IOC_WR_MODE, &mode);

SPI_IOC_RD_LSB_FIRST

查看设备传输的时候是否先传输低比特位。如果是的话,返回1。使用的方式如下:

ioctl(fd,SPI_IOC_RD_LSB_FIRST, &lsb);

其中lsb是一个uint8_t类型的变量。返回的结果存在lsb中。

SPI_IOC_WR_LSB_FIRST

设置设备传输的时候是否先传输低比特位。当传入非零的时候,低比特在前,当传入0的时候高比特在前(默认)。使用的方式如下:

ioctl(fd,SPI_IOC_WR_LSB_FIRST, &lsb);

SPI_IOC_RD_BITS_PER_WORD

读取SPI设备的字长。使用的方式如下:

ioctl(fd,SPI_IOC_RD_BITS_PER_WORD, &bits);

其中bits是一个uibt8_t类型的变量。返回的结果保存在bits中。

SPI_IOC_WR_BITS_PER_WORD

设置SPI通信的字长。使用的方式如下:

ioctl(fd,SPI_IOC_WR_BITS_PER_WORD, &bits);

SPI_IOC_RD_MAX_SPEED_HZ

读取SPI设备的通信的最大时钟频率。使用的方式如下:

ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ, &speed);

其中speed是一个uint32_t类型的变量。返回的结果保存在speed中。

SPI_IOC_WR_MAX_SPEED_HZ

设置SPI设备的通信的最大时钟频率。使用的方式如下:

ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ, &speed);

SPI_IOC_MESSAGE(N)

一次进行双向/多次读写操作。使用的方式如下:

structspi_ioc_transfer xfer[];......status= ioctl(fd, SPI_IOC_MESSAGE(), xfer);

其中N是本次通信中xfer的数组长度。

SPI的读写

int spi_read(){    bt_devide_msg msg;    unsigned char ucRegVal;    int ret,i;    unsigned ];    ;i<;i++)    {        tx[i] = 0xda;    }    unsigned , };    struct spi_ioc_transfer tr = {        .tx_buf = (unsigned long)tx,        .rx_buf = (unsigned long)rx,        .len = ARRAY_SIZE(tx),        .delay_usecs = udelay,        .speed_hz = speed,        .bits_per_word = bits,    };    ret = ioctl(fd, SPI_IOC_MESSAGE(), &tr);    )    {        printf("can't read spi message\n");        ;    }    ] !=0xAA)    {        printf("read spi data: ");        ; ret < ARRAY_SIZE(tx); ret++)        {            printf("%02X ", rx[ret]);        }        printf("\n");    }    ucRegVal = rx[ARRAY_SIZE(tx)-];    get_data_process(rx);  ;

write函数和这类似。

测试函数

void main(){    spi_init();    spi_read();}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,077
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,552
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,400
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,176
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,813
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,895