SPI编程1:用户空间的读写操作
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();
}
SPI编程1:用户空间的读写操作的更多相关文章
- SPI 用户空间的读写操作
spi_device 虽然用户空间不需要直接用到spi_device结构体,但是这个结构体和用户空间的程序有密切的关系,理解它的成员有助于理解SPI设备节点的IOCTL命令,所以首先来介绍它.在内核中 ...
- Socket编程——客户端,服务器端的读写操作
URL网络编程,最大的特征就是一对一的响应! 1:客户端“写”,服务器端用于“读” package coreBookSocket2; import java.io.InputStreamReader; ...
- linux下在用户空间访问I/O端口的ioperm和iopl函数
1.ioperm函数 功能描述:为调用进程设置I/O端口访问权能.ioperm的使用需要具有超级用户的权限,只有低端的[0-0x3ff] I/O端口可被设置,要想指定更多端口的权能,可使用i ...
- Linux块设备驱动(二) _MTD驱动及其用户空间编程
MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...
- OpenCV 编程简单介绍(矩阵/图像/视频的基本读写操作)
PS. 因为csdn博客文章长度有限制,本文有部分内容被截掉了.在OpenCV中文站点的wiki上有可读性更好.而且是完整的版本号,欢迎浏览. OpenCV Wiki :<OpenCV 编程简单 ...
- linux驱动开发:用户空间操作LCD显示简单的图片【转】
转自:http://blog.csdn.net/changliang7731/article/details/53074616 上一章我们简单介绍了LCD的一些基本原理.当然更深奥的还有,比如gamm ...
- alsa 用户空间编程【转】
本文转载自:http://blog.csdn.net/sjin_1314/article/details/12872581 /**alsa play test *ALSA用户空间编译,ALSA驱动的声 ...
- 在linux的用户空间操作gpio
1. 使能linux内核选项CONFIG_GPIO_SYSFS CONFIG_GPIO_SYSFS=y 2. 测试方法 2.1 关注/sys/class/gpio下的文件 --export/unexp ...
- CK:User mode Bus Error(用户空间操作内核地址导致的异常)
关键词:VEC_ACCESS.coredump.LR.PC等. CK中存在一种VEC_ACCESS异常,可能原因是用户空间访问了内核空间,还有一种是内核访问不存在的总线地址. 下面简单构造VEC_AC ...
随机推荐
- 表单元素disabled禁用后不能自动提交到服务器
表单元素disabled禁用后不能自动提交到服务器,项目中需要一个元素只展示不修改,所以把一个input元素设置成了disabled="disabled",但是提交的时候改数据值是 ...
- UITableViewCell使用时注意事项
1,注意使用重用机制(有利于提高效率) 2,做到通过改变模型去间接改变UI样式(做到永久改变,无论怎样拖动刷新,都不会恢复改变) 3,在通过传递模型给Cell控件布局时,记得完全覆盖(嗯,不好解释,主 ...
- centos 源码安装php5.5
系统环境: CentOS 6.5 / 7.0 x86_64 Fedora 20 x86_64下载 PHP 源码包 # wget http://cn2.php.net/distributions/php ...
- 利用paramiko获取上传下载远程服务器的资源信息
# -*- coding: utf-8 -*- import paramikohostname='192.168.76.10'username='root'password='123456'param ...
- Complex social network Partition for Balanced Subnetworks---Hao Lan Zhang,Jiming Liu,Chunyu Feng,Chaoyi Pang,Tongliang Li,Jing He阅读
摘要:Abstract—Complex social network analysis methods have been applied extensively in various domains ...
- PhotoShopCs5启动 需要使用Adobe Application Manager 启动试用版
解决办法:下载Application Manager 7.0 地址:http://download.adobe.com/pub/adobe/creativesuite/cs/win/Applicati ...
- MYSQL数据库字段命名及设计规范
1.设计原则 1) 标准化和规范化数据的标准化有助于消除数据库中的数据冗余.标准化有好几种形式,但 Third Normal Form(3NF)通常被认为在性能.扩展性和数据完整性方面达到了最好平衡. ...
- Codeforces Round #386 (Div. 2) C D E G
一场比较简单的题 比较脑洞 C 如果坐车比较快的话 先走不如等车 所以最后的ans是min(纯走路,纯坐车) 讨论一下坐车时间 D 因为k一定是>=1的 所以当a=b的时候 GBGBGB这样间隔 ...
- 获取浏览器的相关信息(navigator)
* 智能机浏览器版本信息: * */ var browser = { versions: function() { var u = navigator.userAgent + navigator.ap ...
- numpy中的matrix与array的区别
Numpy matrices必须是2维的,但是 numpy arrays (ndarrays) 可以是多维的(1D,2D,3D····ND). Matrix是Array的一个小的分支,包含于Array ...