• 正文
  • 相关推荐
申请入驻 产业图谱

飞凌嵌入式ElfBoard-spi编程示例之spi编写程序

08/01 16:26
178
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

7.3.2.1 构建参数结构体

spi.h中同样是构建了一个结构体,用来对spi进行配置:

/*spi参数结构体 */

typedef struct

{

unsigned long speed;     /*最大速率 */

unsigned char mode;      /*模式 0 : CPOL=0,CPHA=0  1 : CPOL=0,CPHA=1 2 : CPOL=1,CPHA=0 3 : CPOL=1,CPHA=1 */

unsigned char data_bit;  /*8位、16位 */

unsigned char lsb_first; /*低位先发 msb是高位先发*/

unsigned char cs_high; /*片选高有效*/

unsigned char no_cs;   /*不使用片选*/

unsigned char delay; /*延时*/

unsigned char dual_spi; /*半双工 两线制 */

unsigned char quad_spi; /*半双工 四线制*/

} struct_spi_param;

spi部分对于需要的配置同样是构建了一个结构体spi_param,便于对spi的最大速率,极性、相位,四线制还是两线制等参数做详细配置。

7.3.2.2 spi配置

struct_spi_param spi_param = {500000, 0, 8, 0, 0, 0, 0, 0, 0, 0}; /*外设参数初始化*/

int func_set_opt(int fd, struct_spi_param param)

{

int ret = 0;

/*设置工作模式为CPHA=0 CPOL=0;*/

param.set_mode |= SPI_MODE_0;

/*设置每字8位*/

param.data_bit = 8;

/*设置工作频率 hz*/

param.speed = 500000;

/*spi mode 设置SPI 工作模式*/

ret = ioctl(fd, SPI_IOC_WR_MODE, &param.set_mode);

if (ret == -1)

printf("can't set spi mode");

ret = ioctl(fd, SPI_IOC_RD_MODE, &param.set_mode);

if (ret == -1)

printf("can't get spi mode");

/*bits per word  设置一个字节的位数*/

ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &param.data_bit);

if (ret == -1)

printf("can't set bits per word");

ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &param.data_bit);

if (ret == -1)

printf("can't get bits per word");

/*max speed hz  设置SPI 最高工作频率*/

ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &param.speed);

if (ret == -1)

printf("can't set max speed hz");

return 0;

}

这部分代码结合前面构建的spi_param结构体,对结构体成员进行了设置,即完成了spi初始化。设置了SPI 工作模式。根据之前讲解,SPI根据相位和极性的不同分为四 种工作模式,在这里四种工作模式为SPI_MODE_x (x = 0、1、2、3)。这里是回环测试,所以设置为任意一种工作模式都可以。需要注意的是我们可以分开设置SPI的读、写工作模式。

设置SPI通信过程中一个字节所占的位数。默认情况下设置为8即可。同样,这里的读、写是分开设置的。设置SPI通信的波特率,这里设置为500k。经过以上的配置,SPI已经可以通信了。

7.3.2.3 spi收发函数

int func_transfer(int fd, unsigned char *tx, unsigned char *rx, unsigned int lens, struct_spi_param param)

{

int ret;

struct spi_ioc_transfer tr = {

.tx_buf = (unsigned long)tx,

.rx_buf = (unsigned long)rx,

.len = lens,

.delay_usecs = param.delay,

.speed_hz = param.speed,

.bits_per_word = param.data_bit,

};

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

if (ret < 1)

printf("can't send spi message");

}

SPI传输结构体的完整定义如下所示:

结合注释很容易理解,简单说明如下:

1)tx_buf为发送缓冲区地址;

2)rx_buf接收缓冲区地址为0,数据类型为“__u64”,兼容64位系统,64位或32位 由系统自动处理,我们不必关心。

3)len,一次传输的数据长度;

4)speed_hz,指定SPI通信的比特率

5)delay_usecs,如果不为零则用于设置两次传输之间的时间延迟;

6)bits_per_word,指定字节长度,既一个字节占用多少比特;

7)cs_change,取消选中,如果设置为真,则在下次传输之前会取消选中当前的SPI设备,更新片选;

8)tx_nbits,指定“写”数据宽度,SPI 支持 1、2、4位宽度,不过我们使用的SPI3只支持1位数据宽度,该值应当设置为1或0(设置为0表示使用默认的宽度既宽度为1)。

9)pad参数我们没有用到,不用设置;

调用ioctl执行发送,参数fd,是SPI设备文件描述符,参数SPI_IOC_MESSAGE(1)用于指定执行传输次数,我们这里只定义并初始化了一个传输结构体tr,所以传输次数为1。tr是第一部分设置的传输结构体变量。

7.3.2.4 主体逻辑

int main()

{

/*SPI 接收 、发送 缓冲区*/

unsigned char transfer_tx[3] = {0x01, 0x02, 0x03};

unsigned char transfer_rx[3] = {0};

int fd = open("/dev/spidev4.0", O_RDWR);

/*初始化SPI */

func_set_opt(fd, spi_param);

/*执行发送*/

func_transfer(fd, transfer_tx, transfer_rx, 3, spi_param);

/*打印transfer_tx 和transfer_rx*/

printf("Sent: ");

for (int i = 0; i < sizeof(transfer_tx); i++) {

printf("0x%02X ", transfer_tx[i]);

}

printf("\nReceived: ");

for (int i = 0; i < sizeof(transfer_rx); i++) {

printf("0x%02X ", transfer_rx[i]);

}

printf("\n");

close(fd);

return 0;

}

transfer_tx是发送缓冲区,transfer_rx是接收缓冲区。

在main函数中依次调用函数func_set_opt初始化SPI、调用函数transfer执行发送。最后分别打印transfer_tx和transfer_rx的内容,正常情况下,程序运行后我们可以在控制终端发现transfer_tx和transfer_rx的内容一致。

相关推荐