APP下载

基于MDM9607平台的SPI接口驱动解析及应用

2023-06-22姜育生梁妮贺国旗

现代信息科技 2023年2期

姜育生 梁妮 贺国旗

摘  要:文章从嵌入式Linux系统下MDM9607平台的SPI驱动程序设计出发,介绍了SPI通信流程和体系结构,分析了标准4线、扩展6线SPI驱动原理并给出了部分关键程序的代码,通过软件配置给出了可供上层调用的API函数,并分别对标准4线、扩展6线SPI驱动进行了测试验证,实验结果表明该类驱动能够精确地完成实时数据传输,对SPI外设的驱动程序设计具有较强的参考意义,可广泛应用于CPE、4G模组、5G模组、物联网等设备。

关键词:MDM9607;Linux系统;SPI总线;驱动解析

中图分类号:TN92  文献标识码:A  文章编号:2096-4706(2023)02-0149-04

Analysis and Application of SPI Interface Driver Based on MDM9607 Platform

JIANG Yusheng, LIANG Ni, HE Guoqi

(Shaanxi Open University, Xi'an  710119, China)

Abstract: Starting from the design of SPI driver for MDM9607 platform under embedded Linux system, this paper introduces the SPI communication process and architecture, analyzes the principle of standard 4-wire and extended 6-wire SPI driver, and gives the code of some key programs. Through software configuration, it gives the API functions that can be called by the upper layer, and tests and verifies the standard 4-wire and extended 6-wire SPI drivers respectively. The experimental results show that this kind of driver can accurately complete the real-time data transmission, which has strong reference significance for the driver design of SPI peripherals, and can be widely used in CPE, 4G module, 5G module, Internet of Things and other devices.

Keywords: MDM9607; Linux system; SPI bus; driver analysis

0  引  言

SPI(Serial Peripheral interface)是一種高速的、全双工、同步的通信总线。SPI采用主—从模式(Master-Slave)的控制方式,采用CS片来控制主机与从机通信,主机或从机的数据在时钟上升沿或降低沿同步,并能够同时传输数据。本文基于Linux操作系统与MDM9607平台,分别介绍标准4线、扩展6线SPI驱动设计过程,并进行功能测试验证[1]。

1  硬件电路

SPI外接1.8 V的MCU电路参考设计(实际应用中为匹配阻抗可能需要层串联电阻),标准4线SPI各数据线引脚默认1.8 V,不用则悬空。若另一端为3.3 V,则需要增加电平转换芯片。如图1所示。

SPI设备驱动,分为标准4线和扩展6线两种。4线:SPI_CS_N(SPI片选信号)、SPI_MOSI(SPI数据输出)、SPI_MISO(SPI数据输入)、SPI_CLK(SPI时钟),通常用来连接EEPROM、FLASH、LCD等,由模块发起请求。

6线SPI主要比4线的SPI多了两根控制线,主要用于通信前的握手功能,通信双方都准备好了才发送数据,通常用来与MCU通信,模块、MCU均可发起请求,相比串口通信也更高速。

相比4线SPI多出的两个数据线功能为:

(1)SPI_MRDY:引脚用户选择,模块输出信号,空闲为低;当模块要输出数据时,驱动自动拉高该PIN。

(2)SPI_SRDY:引脚用户选择,SPI Slave ready信号,空闲为低;当SPISlave准备好接收/发送数据时,拉高该PIN。

2  通信流程

2.1  SPI Master发起请求

SPI Master发起请求流程如图2所示。

SPI Master流程为:

(1)驱动自动拉高SPI_MRDY通知SPI Slave。

(2)判断SPI_SRDY是否为高,否则等待SPI_SRDY的上升沿中断。

(3)收到Slave上升沿,开始SPI传输。

(4)传输完毕,如果要继续发送数据,则保持SPI_MRDY为高,并继续第二步,否则拉低SPI_MRDY。

SPI Slave流程为:

(1)收到SPI_MRDY上升沿中断,表示SPI Master需要发送数据。

(2)准备好SPI传输,并拉高SPI_SRDY通知SPI Master开始SPI传输。

(3)等待SPI传输结束,并拉低SPI_SRDY。

(4)如果SPI_MRDY为高,再继续第二步。

2.2  SPI Slave发起请求

SPI Slave发起请求流程如图3所示。

SPI Slave流程:

(1)准备好SPI传输,并拉高SPI_SRDY。

(2)等待SPI传输结束,并拉低SPI_SRDY。

(3)如果要继续发送数据,则继续第1步。

SPI Master流程:

(1)收到SPI_SRDY上升沿中断,表示从机要发送数据。

(2)拉高SPI_MRDY,并开始SPI传输。

(3)等待传输结束,并拉低SPI_MRDY[2,3]。

3  软件配置

3.1  SPI控制器配置说明

Linux的SPI体系结构分为以下3个组成部分。

3.1.1  SPI核心

SPI核心提供了SPI总线驱动和设备驱动的注册、注销方法、SPI通信方法,以及与具体控制器无关的代码以及探测设备、检测设备地址的上层代码等。

3.1.2  SPI總线(控制器)驱动

SPI总线驱动是对SPI硬件体系控制器端的实现,控制器由CPU控制,也可以直接集成在CPU内部。

3.1.3  SPI 设备驱动

SPI设备驱动是对SPI硬件体系结构中设备端的实现,即客户的SPI从设备驱动,设备一般挂接在受CPU控制的SPI控制器上,通过SPI控制器与CPU交换数据[4,5]。

以上3个部分,一般只需要关心和修改SPI设备驱动。

SPI总线驱动:即SPI控制器,MDM9607平台使用的是设备树节点spi-qup-v2;其硬件参数配置,如所兼容的driver、引脚的选择、寄存器地址、CLK、中断号,以及系统休眠和工作时的管脚配置等都已经做好,不需要关心和修改。

3.2  SPI设备驱动

3.2.1  4线SPI设备驱动

4线SPI设备驱动位于ql-ol-kernel/drivers/spi/spidev.c,驱动不使用设备树传参方式,直接insmod带入参数更灵活,内核模块加载时支持的参数为:

(1)Busnum:SPI控制器编号为6,由下面代码配置决定,此参数必须传入,否则SPI从设备会找不到控制器而导致加载失败。

aliases

{

/* smdtty devices*/

smd7 = &smdtty_data1;

smd8 = &smdtty_data4;

smd9 = &smdtty_data2;

smd21 = &smdtty_data21;

smd36 = &smdtty_loopback;

/*spi devices,Busnum = 6*/

spi6 = &spi_6;

i2c2 = &i2c_2;

i2c4 = &i2c_4;

sdhc2 = &sdhc_2;

}

(2)chipselect:片选支持0、1、2、3,此参数必须传入,否则SPI设备会注册失败。

(3)spimode :SPI支持4种工作模式,其值为相位(CPHA 0x01)和极性(CPOL 0x02)的按位或,驱动代码默认使用SPI_MODE_3模式,用户可以在insmod时修改,时钟极性CPOL:即SPI空闲时,时钟信号SCLK的电平(1:空闲时高电平,0:空闲时低电平),时钟相位CPHA:即SPI在SCLK第几个边沿开始采样(0:第一个边沿开始,1:第二个边沿开始)[6,7]。

(4)maxspeed:可选参数,驱动默认为9.6 MHz,实际支持的最大值由SPI控制器的配置决定,与理论最大值并不冲突;支持的可选值960 000、4 800 000、9 600 000、16 000 000、19 200 000、25 000 000、50 000 000。

(5)bufsize:可选参数,设定SPI传输队列中每个transfer的大小,默认值4 096 Bytes,用户可根据自己传输每次数据量的大小来设定。

(6)加载命令:insmod /lib/modules/3.18.20/kernel/drivers/

spi/spidev.ko busnum=6 chipselect=0 spimode=0 maxspeed=

19200000。

执行lsmod查看载入系统的模块,显示:spidev 6473 0 - Live 0xbf03a000,再执行ls /dev/spidev6.0命令,显示/dev/spidev6.0,设备加载成功[8,9]。

3.2.2  6线SPI设备驱动

6线SPI设备驱动位于ql-ol-kernel/drivers/spi/quec_chn_spi.c,驱动不使用设备树传参方式,直接从insmod 命令行带入客户参数,内核模块加载时支持的参数为:

(1)Busnum数值和4线相同;chipselect片选和4线一致,可选参数,驱动默认值为0;spimode和4线一致,驱动代码默认使用SPI_MODE_0模式,用户可以在insmod时修改;speed_hz和4线相同,frame_size默认值512 Bytes。

(2)gpiomodemready设置SPI_MRDY,gpiomcuready设置SPI_SRDY,一般使用默认管脚,可传参修改。

加载命令:insmod /lib/modules/3.18.20/kernel/drivers/spi/quec_spi_chn.ko speed_hz=19200000

gpiomodemready=38 gpiomcuready=34。

执行lsmod查看载入系统的模块,显示:quec_spi_chn 9069 0 - Live 0xbf03a000,再执行ls /dev/spidev6_0_*命令,显示:/dev/spidev6_0_0到 /dev/spidev6_0_7,6线SPI驱动虚拟出了8个数据通道,设备加载成功[10]。

4  SPI API

SDK中提供了一套完整的用户编程接口,lib目录下提供API接口库,include目录是所有API的头文件,通过上面的配置,SPI设备节点已经注册成功,可以直接使用下面API进行应用层操作,4线SPI操作API需要include头文件ql_spi.h[11,12]。

4.1  Spi mode枚舉

SPI支持的工作模式:

typedef enum

{

SPIMODE0 = SPI_MODE_0,

SPIMODE1 = SPI_MODE_1,

SPIMODE2 = SPI_MODE_2,

SPIMODE3=SPI_MODE_3,

}SPI_MODE;

4.2  Spi clock枚举

SPI默认支持的时钟大小:

typedef enum

{

S_960K = 960000,

S_4_8M = 4800000,

S_9_6M = 9600000,

S_16M = 16000000,

S_19_2M = 19200000,

S_25M = 25000000,

S_50M = 50000000,

}SPI_SPEED;

4.3  SPI_Init函数

打开SPI设备并配置对应的参数。int Ql_SPI_Init(char *dev_name,SPI_MODE mode,uint8_t bits, SPI_SPEED speed);参数:dev_name(SPI设备,需要手动加载spidev.ko);SPI_MODE(SPI4种工作模式,SPI_MODE枚举值);bits(发送数据字的位数,支持4,8,16,32);Speed(SPI控制器输出时钟,SPI_SPEED枚举值)。

4.4  Ql_SPI_Write_Read函数

读写SPI数据。int Ql_SPI_Write_Read(int fd,uint8_t* write_buf,uint8_t* read_buf,uint32_t len);参数:fd(spi设备文件描述符);write_buf(SPI写数据指针);read _buf(SPI读数据指针);len(读写数据长度)。

SPI通信是全双工的,只读可以配置write_buf内容为0,只写可以丢弃read_buf内容,由于标准SPI是读写在一个transfer里面,所有操作是全双工的。向read_buf传递一个NULL,就是一次只写操作,会丢弃MISO线上的数据;同样向write_buf传递一个NULL,就是一次只读操作。

4.5  Ql_SPI_Deinit函数

关闭SPI设备。int Ql_SPI_Deinit(int fd);参数:fd(SPI设备文件描述符)。

6线SPI驱动同时虚拟出了8个数据通道留做备用,直接使用open、read、write来读写SPI设备,并使用select监听设备实现异步通知[13,14]。

5  SPI功能测试验证

因为未连接spi slave设备,这里我们可以直接短接SPI_MOSI和SPI_MISO数据线进行自发自收测试。

5.1  4线SPI功能验证

以SPI_MODE_0,8bits/word,19.2M speed 初始化设备,向设备写1 024个字节,同时读取1 024字节回,测试程序为:

#define device "/dev/spidev6.0"

int main(int argc,char *argv[])

{

int fd;

int i;

uint8_t writebuf[1024];

uint8_t readbuf[1024];

fd = QL_SPI_Init(define,SPIMODE0,8,

S_19_2M);

for(i = 0;i < 1024;I++)

writebuf[i] = i % 256;

QL_SPI_Write_Read(fd,writebuf,readbuf,

1024);

for(i = 0;i < 1024;i++)

{

if(!(i % 32))

puts("");

printf("%.2X",readbuf[i]);

}

puts("");

}

在example/spi/std_spi目录,make生成example_spi可执行程序,加载完驱动后执行./ example_spi,结果为:

spi mode:0x0

bits per word:8

max speed:19200000Hz(19200kHz)

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D

0E 0F……………………………………F0

F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

5.2  6线SPI功能验证

进入到example/spi/six_line目录,make生成example_six_line_spi可执行程序,6线SPI除了短接SPI_MOSI和SPI_MISO以外,MRDY和SRDY也要进行硬件连接,才能进行自发自收测试[15,16]。加载完驱动后执行./ example_six_line_spi,结果为:

read 25 bytes hello,I am a six line spi

read 15 bytes test process!

通过实际的验证测试,4线和6线的SPI收到的数据与发出去的一致,可以正常使用。

6  结  论

本文针对MDM9607平台的SPI驱动展开研究,重点阐述了软件的配置流程,给出了相关API调用接口,并进行了验证测试,测试结果证明性能稳定。目前几乎所有的处理器都支持SPI通信,尤其是对基于嵌入式Linux操作系统的驱动程序开发,具有一定的借鉴意义。

参考文献:

[1] 徐阳.高速SPI接口电路的设计与验证 [D].西安:西安电子科技大学,2020.

[2] 王鸣山.车联网4GLTE模块低纹波供电电源设计 [J].单片机与嵌入式系统应用,2019,19(11):47-52.

[3] 钱小东,宣浩,葛鹏.一种基于MLVDS的SPI通信链路设计 [J].数字技术与应用,2021,39(6):13-15.

[4] 阎景波,张磊,孙东亚.基于F28335的McBSP实现SPI接口的方法研究 [J].信息技术与信息化,2020(7):146-148.

[5] 陈亮,蔡声镇,卢丽婉.一种面向存储的高性能双向SPI传输机制 [J].微电子学与计算机,2021,38(3):72-76+83.

[6] 許云龙.基于APB总线的SPI接口的设计与实现 [J].电子质量,2020(7):128-132.

[7] 刘满.SPI协议接口的设计与实现 [D].西安:西安电子科技大学,2020.

[8] 陆鹏.一种从机SPI通信接口的FPGA设计与实现 [J].信息通信,2020(3):142-143.

[9] 芮正新,辛克廷.一种基于DMA方式SPI接口的通信方法 [J].仪器仪表与分析监测,2020(3):9-12.

[10] 宋风雷.基于DSP的eCAN总线与SPI总线之间数据转换器的设计与实现 [D].长沙:湖南大学,2018.

[11] 高培,何栋炜,郑潇.ESP32SPISlave总线接口驱动解析及应用 [J].单片机与嵌入式系统应用,2019,19(2):9-14.

[12] 赵冬青,梁璠,上官鹏,等.一种基于SPIFLASH的FPGA固件更新方法 [J].电子设计工程,2020,28(16):11-16.

[13] 李增科,李云鹏,席东学.基于SPI协议的双DSP通讯设计与实现 [J].电子测量技术,2020,43(19):159-164.

[14] 王俊,刘国美,李兴智,等.一种使用SPI接口的DSP间数据交叉传输技术 [J].信息技术与信息化,2021(5):206-207+210.

[15] 韩子川.28Gb/s光收发机SPI和UART的设计 [D].南京:东南大学,2019.

[16] 张拓智,孔德岐,朱恩亮,等.嵌入式Linux系统下的HI3210驱动软件设计与实现[J].航空计算技术,2019,49(3):99-102.

作者简介:姜育生(1979—),男,汉族,陕西西安人,高级工程师,硕士,研究方向:通信技术。

收稿日期:2022-08-26

基金项目:陕西哲学社会科学重点研究基地项目(22JZ019)