Linux系统编程9

您所在的位置:网站首页 spi从模式接收数据错误 Linux系统编程9

Linux系统编程9

#Linux系统编程9| 来源: 网络整理| 查看: 265

序号内容链接1多进程点我访问2进程间通信点我访问3多线程点我访问4网络编程点我访问5shell点我访问6Makefile点我访问7串口通信点我访问8I2C通信点我访问9SPI通信点我访问 1 SPI通讯协议简介

SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设 备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、 LCD 等设备与 MCU 间, 要求通讯速率较高的场合学习本章时,可与 I2C 章节对比阅读,体会两种通讯总线的差异。 下面我们分别对 SPI 协议的物理层及协议层进行讲解。

SPI通讯设备之间的常用连接方式见下图。

未找到图片

SPI通讯使用3条总线及片选线,3条总线分别为SCK、MOSI、MISO,片选线为SS* ,它们的作用介绍如下:

片选线(Slave Select):从设备选择信号线,常称为片选信号线, 也称为NSS、CS,以下用NSS表示。SPI通讯以NSS线置低电平为开始信号,以NSS线被拉高作为结束信号。

SCK(Serial Clock):时钟信号线,用于通讯数据同步,它由通讯主机产生。

MOSI(Master Output,Slave Input):主设备输出/从设备输入引脚。数据方向为主机到从机。

MISO(Master Input,Slave Output):主设备输入/从设备输出引脚。数据方向为从机到主机。

SPI分成了四种模式,见下表, 主机与从机需要工作在相同的模式下才可以正常通讯,实际中采用较多的是“模式0”与“模式3”。

SPI模式CPOLCPHA空闲时SCK时钟采样时刻000低电平奇数边沿101低电平偶数边沿210高电平奇数边沿311高电平偶数边沿 2 相关函数

编写应用程序需要使用到spi_ioc_transfer结构体,如下所示

linux/spi/spidev.h

struct spi_ioc_transfer { __u64 tx_buf; //发送数据缓存 __u64 rx_buf; //接收数据缓存 __u32 len; //数据长度 __u32 speed_hz; //通讯速率 __u16 delay_usecs; //两个spi_ioc_transfer之间的延时,微秒 __u8 bits_per_word; //数据长度 __u8 cs_change; //取消选中片选 __u8 tx_nbits; //单次数据宽度(多数据线模式) __u8 rx_nbits; //单次数据宽度(多数据线模式) __u16 pad; };

在编写应用程序时还需要使用ioctl函数设置spi相关配置,其函数原型如下

#include int ioctl(int fd, unsigned long request, ...);

其中对于终端request的值常用的有以下几种

SPI_IOC_RD_MODE设置读取SPI模式SPI_IOC_WR_MODE设置写入SPI模式SPI_IOC_RD_LSB_FIRST设置SPI读取数据模式(LSB先行返回1)SPI_IOC_WR_LSB_FIRST设置SPI写入数据模式。(0:MSB,非0:LSB)SPI_IOC_RD_BITS_PER_WORD设置SPI读取设备的字长SPI_IOC_WR_BITS_PER_WORD设置SPI写入设备的字长SPI_IOC_RD_MAX_SPEED_HZ设置读取SPI设备的最大通信频率SPI_IOC_WR_MAX_SPEED_HZ设置写入SPI设备的最大通信速率SPI_IOC_MESSAGE(N)一次进行双向/多次读写操作

其中SPI的读写和写入可以设置为不同的参数。

3 SPI-OLED完整代码 #include #include #include #include #include #include #include #include #include #define spi3_oled_DEV_path "/dev/spidev2.0" /*SPI 接收 、发送 缓冲区*/ static unsigned char tx_buffer[100] = "hello the world !"; static unsigned char rx_buffer[100]; static int fd; // SPI 控制引脚的设备文件描述符 static uint32_t mode = SPI_MODE_2; //用于保存 SPI 工作模式 static uint8_t bits = 8; // 接收、发送数据位数 static uint32_t speed = 500000; // 发送速度 static uint16_t delay; //保存延时时间 //spi初始化 static int spi_init(void); //spi发送数据 static int transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len); int main(int argc,char * argv[]) { int ret; ret = spi_init(); if( -1 == ret ) { printf("spi_init error\n"); exit(-1); } ret = transfer(fd, tx_buffer, rx_buffer, sizeof(tx_buffer)); if (-1 == ret ) { printf("transfer error...\n"); } /*打印 tx_buffer 和 rx_buffer*/ printf("tx_buffer: \n %s\n ", tx_buffer); printf("rx_buffer: \n %s\n ", rx_buffer); return 0; } int transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) { int ret; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long )tx, .rx_buf = (unsigned long )rx, .len = len, .delay_usecs = delay, .speed_hz = speed, .bits_per_word =bits, }; ret = ioctl(fd,SPI_IOC_MESSAGE(1),&tr); if( ret == -1 ) { return -1; } return 0; } int spi_init(void) { int ret; fd = open(spi3_oled_DEV_path,O_RDWR); if(fd printf("SPI_IOC_RD_MODE error......\n "); goto fd_close; } ret = ioctl(fd,SPI_IOC_WR_MODE,&mode); if( ret == -1) { printf("SPI_IOC_WR_MODE error......\n "); goto fd_close; } //设置SPI通信的字长 ret = ioctl(fd,SPI_IOC_RD_BITS_PER_WORD,&bits); if( ret == -1) { printf("SPI_IOC_RD_BITS_PER_WORD error......\n "); goto fd_close; } ret = ioctl(fd,SPI_IOC_WR_BITS_PER_WORD,&bits); if( ret == -1) { printf("SPI_IOC_WR_BITS_PER_WORD error......\n "); goto fd_close; } //设置SPI最高工作频率 ret = ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ,&speed); if( ret == -1) { printf("SPI_IOC_WR_MAX_SPEED_HZ error......\n "); goto fd_close; } ret = ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ,&speed); if( ret == -1) { printf("SPI_IOC_RD_MAX_SPEED_HZ error......\n "); goto fd_close; } printf("spi mode: 0x%x\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000); return 0; fd_close: close(fd); return -1; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3