SPISPI学习之SPI调试相关

Posted Evan_ZGYF丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPISPI学习之SPI调试相关相关的知识,希望对你有一定的参考价值。

关联内容:

【SPI】SPI学习之SPI硬件相关

【SPI】SPI学习之SPI驱动相关

【SPI】SPI学习之SPI调试相关


目录

spi调试方法

uboot下调试SPI

内核调试API接口

spi_read函数

spi_write函数

SPI常见错误

dts配置错误

SPI管脚复用

硬件问题

寄存器配置

时钟频率设置错误

相位配置错误

模式错误

spi驱动实例

SPI驱动开发,需要注意哪些点

dts配置

SPI控制器

SPI管脚复用


spi调试方法

uboot下调试SPI

在uboot下,有spi的调试命令“sspi”,代码在:uboot/cmd/spi.c

具体用法如下:

U_BOOT_CMD(
	sspi,	5,	1,	do_spi,
	"SPI utility command",
	"[<bus>:]<cs>[.<mode>] <bit_len> <dout> - Send and receive bits\\n"
	"<bus>     - Identifies the SPI bus\\n"
	"<cs>      - Identifies the chip select\\n"
	"<mode>    - Identifies the SPI mode to use\\n"
	"<bit_len> - Number of bits to send (base 10)\\n"
	"<dout>    - Hexadecimal string that gets sent"
);

参数解析:
bus		spi总线号
cs		片选
mode		选择传输模式(mode1...mode4),参考SPI相位和极性
bit_len		选择发送的数据长度
dout		被发送的十六进制数据

工作模式 \\ 相位

CPOL

 CPHA

 mode 0

 0

 0

 mode 1

 0

 1

 mode 2

 1

 0

 mode 3

 1

 1


内核调试API接口

spi_read函数

spi的读写操作都是初始化一个spi_transfer传输结构体,并将其添加进spi消息传输事务链表中

然后通过spi_sync来同步读写操作,接着看下spi_sync的具体代码

这里的API是内核空间使用的接口,设备驱动程序调用这些API直接操作spi的读写操作,来完成任务

static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len) 
{ 
    struct spi_transfer t = { 
            .rx_buf     = buf, 
            .len        = len, 
        }; 
    struct spi_message  m; 
    spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头) 
    spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表 
    return spi_sync(spi, &m);   //spi同步传输 
} 

spi_write函数

spi写 spi_write

static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len) 
{ 
    struct spi_transfer t = { 
            .tx_buf     = buf, 
            .len        = len, 
        }; 
    struct spi_message  m; 
    spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头) 
    spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表 
    return spi_sync(spi, &m);   //spi同步传输 
} 

SPI常见错误

dts配置错误

在“arch/xxx/boot/dts”中,对应项目的dts、dtsi文件。

有时候SPI异常就是因为这些dts设置错误 / 没有在dts中配置spi。

SPI管脚复用

 

类似这种管脚复用,需要将原理图上SPI的四个管脚:MISO,MOSI,CS,SCLK全复用成SPI功能。

硬件问题

比如时钟线和模块连接处没有焊牢,之类。

还有就是驱动电压不够,导致MISO这些信号时序并没有被识别出来(之前项目中遇到过)。

寄存器配置

SPI寄存器配置异常,也会导致SPI的传输出问题。

但一般这种情况出现概率比较小,因为这些SPI的代码都是比较完善了的,只有能保证正常的读写寄存器值。那么就不会出现问题。

时钟频率设置错误

在从器件时钟频率小于主器件时钟频率时,如果SCK的速率设得太快,将导致接收到的数据不正确(SPI接口本身难以判断收到的数据是否正确,要在软件中处理)。

整个系统的速度受三个因素影响:主器件时钟CLK主、从器件时钟CLK从和同步串行时钟SCK,其中SCK是对CLK主的分频,CLK从和 CLK主是异步的。要使SCK无差错无遗漏地被从器件所检测到,从器件的时钟CLK从必须要足够快。

相位配置错误

SPI主模块和与之通信的外设备时钟相位和极性应该一致。个人理解这句话有 2层意思:其一,主设备SPI时钟和极性的配置应该由外设来决定;其二,二者的配置应该保持一致,即主设备的SDO同从设备的SDO配置一致,主设备的 SDI同从设备的SDI配置一致。

在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。但要注意的是,由于主设备的SDO连接从设备的SDI,从设备的SDO连接主设备的SDI,从设备SDI接收的数据是主设备的SDO发送过来的,主设备 SDI接收的数据是从设备SDO发送过来的,所以主设备这边SPI时钟极性的配置(即SDO的配置)跟从设备的SDI接收数据的极性是相反的,跟从设备 SDO发送数据的极性是相同的。

时钟极性和相位配置正确后,数据才能够被准确的发送和接收。因此应该对照从设备的SPI接口时序或者Spec文档说明来正确配置主设备的时钟。

模式错误

模式错误表示的是主从模式选择的设置和引脚SS的连接不一致。

器件工作在主模式的时候(MSTR=1),它的片选信号SS引脚必须接高电平。在发送数据的过程中,如果它的SS从高电平跳至低电平,在SS的下降沿,SPI模块将检测到模式错误,对MODF位置1,强制器件从主模式转入从模式(即令MSTR=0),清空内部计数器counter,并结束正在进行的数据传输。

对从模式(MSTR=0),在没有数据传送的时候,SS高电平表示从器件未被选中,从器件不工作,MISO输出高阻;在数据传输过程中,片选信号SS必须接低电平,且SS不允许跳变。如果SS从低电平跳到高电平,在SS的上跳沿,SPI模块也将检测到模式错误,清空内部计数器counter,并结束正在进行的数据传输。直到SS恢复为低电平,重新使SPEN=1时,才重新开始工作。


spi驱动实例

SPI驱动开发,需要注意哪些点

大部分项目需要用到SPI都是因为对应项目中使用了SPI设备,因此需要在系统配置中加上SPI驱动。

SPI驱动分为两类,SPI总线(控制器)驱动、SPI设备驱动。

dts配置

大部分的spi控制器驱动、SPI设备驱动,都已经在Linux内核中支持好了,只需要通过dts配置就能使用。

SPI控制器

SPI总线(控制器)驱动对应硬件SPI控制器,所以需要先确定当前设备的SPI控制器型号,再去驱动中找到对应的代码,再去配置dts(linux3.10之前的版本需要找boot代码)。(drivers/spi/Makefile)

SPI管脚复用

还有需要注意的就是管脚复用,SPI总线有四个管脚:MISO,MOSI,CS,SCLK。在硬件芯片上,这几个引脚通常可以复用成GPIO/SPI等等,假如用到SPI功能,则必须复用成SPI。

以上是关于SPISPI学习之SPI调试相关的主要内容,如果未能解决你的问题,请参考以下文章

SPISPI学习之SPI驱动相关

SPISPI学习之SPI驱动相关

SPISPI学习之SPI硬件相关

SPISPI学习之SPI硬件相关

spi总线协议

spi总线协议