dw ssi(spi)驱动调试

2023-10-27 18:50
文章标签 驱动 调试 dw spi ssi

本文主要是介绍dw ssi(spi)驱动调试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.芯片简介

1.1 模块与接口

1.2 非DMA传输

 1.3 DMA传输

1.3.1 DMA寄存器

1.3.3 DMA水线设置

2.调试问题

2.1 uboot

2.1.1 Read Flash ID失败

 2.1.2 一次只能读出27B有效内容

 2.2 kernel

2.2.1 spi访问读取内容无效

2.2.2 dma传输rx超时

3. 内核SPI驱动

3.1 SPI框架

3.2 spi-dw驱动

4.调试命令

4.1 uboot

4.2 kernel

4.2.1 mtd_debug

4.2.2 debugfs

4.2.3 module parameter


1.芯片简介

1.1 模块与接口

      dw_apb_ssi支持全双工的master和slave模式,支持dma传输,支持SPI(Motorola Serial Peripheral Interface),SSP(Texas Instruments Serial Protocol),National Semiconductor Microwire三种接口类型。支持Transmit and Receive,Transmit Only,Receive Only,EEPROM Read四种传输模式。

APB Interface用于寄存器访问和数据收发。

DMA Interface用于跟DMA控制器通信,进行握手/传输请求/传输应答等控制信号的交互。

1.2 非DMA传输

master模式数据传输流程流程如下:

      (1) 软件配置控制寄存器设置传输模式,分频系数,FIFO收发门限,中断使能,选择device片选,然后使能控制器,发起传输。

      (2) 软件写Tx FIFO,SPI传输的特点决定了有发送才有接收,发送多少数据,接收多少数据。如果传输数据较长,那么要考虑根据FIFO的长度将数据分片。如果只是发送数据,那么直接发送有效的数据内容即可。接收数据时一般配置为Transmit and Receive模式,此时为了接收数据,需要持续在发送方向发送dummy数据。

      (3) 软件持续从Rx FIFO中读出数据。

非DMA传输可以采取轮询或者中断方式,uboot下采用轮询模式,内核驱动两种方式都支持。

 1.3 DMA传输

1.3.1 DMA寄存器

DMA传输方式需要通用DMA控制器驱动配合。dw ssi引出一组dma控制信号与DMAC交互。

dma_tx_req/dma_rx_req/dma_tx_single/dma_rx_single 是ssi发给dmac的请求信号。

dma_tx_ack/dma_rx_ack 是dmac发给ssi的应答信号。

此外,dw ssi还提供了3个DMA相关的寄存器用于使能DMA收发和设置DMA水线。

      DMACR用于使能DMA传输,DMATDLR配置tx fifo水线,DMARDLR配置rx fifo水线。

      当tx fifo中的待发数据个数向下减少到水线值时,ssi向dmac发起dma_tx_req,此时dmac应该往tx fifo中注入数据,使得待发数据个数重新达到水线之上。

      然后随着ssi逐步发出数据,待发数据个数又开始减少到达水线,于是再次发起dma_tx_req,提示dmac再次注入数据,如此循环。

      水线设置低,一次burst发送的数据个数较多,ssi向dmac发起dma_tx_req的频率相对较低;水线设置高,一次burst发送的数据个数较少,ssi向dmac发起dma_tx_req的频率相对较高。

      dmac应该及时注入数据,如果水线设置较低,tx fifo很快就会将fifo中剩余的数据发完,而dmac还没来得及注入足够的数据,就会发生下溢(ssi无数据可发)。

      当rx fifo中的待收数据个数向上增长到水线值时,发起dma_rx_req,此时dmac应该从rx fifo中取走数据,使得待收数据个数降到水线之下。

      然后随着ssi逐步接收数据,待收数据个数又开始增长到达水线,于是再次发起dma_rx_req,提示dmac再次取走数据,如此循环。

      水线设置低,一次burst接收的数据个数较少,ssi向dmac发起dma_rx_req的频率相对较高;水线设置高,一次burst接收的数据个数较多,ssi向dmac发起dma_rx_req的频率相对较低。

      dmac应该及时取走数据,如果水线设置较高,rx fifo空闲空间很快将被耗尽,而dmac还没来得及取走数据,就会发生上溢(ssi无空间保存新接收的数据)。

 1.3.2 DMA传输分片

一次block传输12个data item,分为3次burst,每次burst传输4个data item。

       一次block传输15个data item,分为3次burst和3次single,每次burst传输4个data item,每次single传输1个data item。

1.3.3 DMA水线设置

dw_ssi通常用于MEM <-> DEVICE 这种对接场景,发送方向DST device侧发送速率较低,接收方向SRC device侧接收速率较低。以下是手册建议的水线配置:

DMA.CTLx.DEST_MSIZE = FIFO_DEPTH - SSI.DMATDLR

DMA.CTLx.SRC_MSIZE = SSI.DMARDLR + 1

2.调试问题

2.1 uboot

2.1.1 Read Flash ID失败

【问题现象】

uboot命令行视图执行sf probe命令,未读到有效数据。

      先确认SPI相关引脚的复用配置,确认为SPI模式。

      然后对比A53验证代码,可以读到ID,说明硬件没问题。不同在于收发数据流程:A53中将opcode和dummy data合并在一起,在一个transfer里发送到device,但uboot没有这样的处理。

【问题原因】

      使用dw ssi控制device片选信号时,包括READ ID在内的read reg/read data流程要求

      opcode/addr/dummy一起发给device,如果是读取数据,tx方向需要继续发送dummy数据,接收方向在接收数据后需要过滤掉无效数据(对应opcode/addr/dummy收到的内容)。

 2.1.2 一次只能读出27B有效内容

【问题现象】

从offset=0开始连续读取37B,只有前面27B有效,后面10B内容为0xff。

从offset=0开始读0x25(37B)数据,因为fifo为32B,所以软件中读操作拆分成2段:

第一段:tx opcode=0bh, addr=0x000000, dummy=0xff, tx padding 27B, 同时rx 27B data

第二段:tx opcode=0bh, addr=0x00001b, dummy=0xff, tx padding 10B, 同时rx 10B data

但从实际结果看,第一段读到的内容是正确的,从0x00 - 0x1a;

第二段读到的内容是全FF,正确的数据应该是0x1b - 0x24。

【问题原因】

      Read data使用的address必须以小端方式发送给device,offset=0x00时,大小端都一样,所以可以读到正确的内容,offset=0x1b时,实际发送的addr是0x1b0000,该地址实际上未被写入内容,读到的就是0xff。正确的做法是将地址转成小端。

 

 2.2 kernel

2.2.1 spi访问读取内容无效

【问题现象】

      内核spi框架传输opcode/addr/dummy与后面的data传输,分成2次transfer完成,这样无法得到正确的数据。像uboot那样将2次transfer拼接成一个,可以得到正确的结果。但是这样一来在spi访问前后增加了2次内存拷贝,开销很大。

      抓波形可以看到,分2次传输时,cs中间自动拉高了,接下来opcode=0x9f对应的接收内容是0x00。

      而合并成1次transfer时,只出一次片选,opcode=0x9f读到的内容确实是FLASH的JEDEC ID。

 【问题原因】

      控制器驱动cs时,2次transfer中间cs自动拉高,相当于中断了完整的SPI访问流程,导致得不到正确的数据。将cs引脚配置为gpio模式,由软件控制,2次tranfer过程全程使能cs不拉高,可以得到正确的数据内容。

 对应的dts新增cs-gpios配置项:

spi0: spi@f0da0000 {compatible = "snps,dw-apb-ssi";pinctrl-names = "default";pinctrl-0 = <&PA26_pinctrl>;cs-gpios = <&porta 26 GPIO_ACTIVE_LOW>;
};

2.2.2 dma传输rx超时

【问题现象】

dma方式从flash读48 byte内容,dma tx结束,dma rx超时。

【问题原因】

      dw DMAC控制器的硬件实现限制最大发送/接收的Burst Len为4,而dw ssi DMARDLR配置接收水线为16,大于DMA通道的Burst Len,使得传输过程最后rx fifo存有数据,但是因为达不到水线,无法触发dma_rx_req,导致数据残留在rx fifo中未被软件接收,dma rx超时。

      修改dts中DMAC的burst能力,限制为4,这样相应的dw ssi rx fifo接收水线DMARDLR也配置为4,可以保证rx fifo中数据被完整接收。

 

注意:虽然ssi DR的宽度为32bits,但一次只能收发8bit数据。

      tx方向,传输一个data item意味着从DDR取8bit数据,填入ssi fifo 32bits entry(DR寄存器)的低8位,一次burst传4个data item,也就是4B;

      rx方向,传输一个data item意味着ssi fifo 32bits entry(DR寄存器)读入32位数据,取低8位填入DDR,一次burst传4个data item,也就是4B。

      DMA的DST和SRC虽然数据宽度不同,但是一次传输的有效数据都是4B,所以dma_tx_req和dma_rx_req最终的次数也是一致的。

下面分析软件从FLASH offset = 0处读取48B数据的dma流程。

有问题的配置对应的DMA处理流程。

发送方向:

      (1) ssi tx fifo空,ssi发起dma_tx_req,dmac响应请求,发起一次tx burst,注入DEST_MSIZE个数据(4个),一共写入4*8bits = 4B。

      (2)此时仍然tx fifo有效数据仍低于DMATDLR水线,于是ssi再次发起若干次dma_tx_req,dmac响应请求,每次都注入DEST_MSIZE个数据,直到tx fifo中数据个数高于DMATDLR水线。

      (3) 随着ssi发送数据,当tx fifo中数据个数下降到DMATDLR水线,ssi再次发起dma_tx_req,dmac响应请求,发起一次tx burst,再注入DEST_MSIZE个数据。

      下面重复步骤(3)直到所有数据均写入tx fifo,等待ssi陆续发完。

接收方向:

      (1) 由于tx方向持续发送数据,在接收方向上也会持续接收数据。

       当ssi rx fifo中数据上涨到达(DMARDLR + 1)水线,ssi发起dma_rx_req,dmac响应请求,发起一次rx burst,读出SRC_MSIZE个数据(4个),一共读出4*8bits = 4B。

      (2) 如果此时ssi rx fifo中数据个数仍高于(DMARDLR + 1)水线,那么ssi仍会持续发起dma_rx_req,dmac也会持续读出数据,直到ssi rx fifo中数据个数低于(DMARDLR + 1)水线。

      (3) 这里DMARDLR + 1 = 16,而SRC_MSIZE = 4,这就使得ssi rx fifo中会残留12B数据,因为达不到水线,无法通知dmac取走,于是导致rx方向最终超时失败。

 正确的配置对应的DMA处理流程。

发送方向:跟之前相同

接收方向:DMARDLR + 1 = SRC_MSIZE = 4,保证了一次rx burst读走rx fifo中所有的数据,没有残留,所以rx 方向可以顺利结束。

      残留数据的验证:dma超时后读取RXFLR,确认此时rx fifo中是否有数据,有的话直接dump DR寄存器内容,确认正好就是最后12B数据内容。   

3. 内核SPI驱动

3.1 SPI框架

Linux SPI 驱动结构中,将 SPI 相关的驱动分为了几部分:

     (1) SPI 主机以及主机驱动:SoC 的 SPI Controller 部分的驱动

     (2) SPI 外设驱动描述:比如 SPI Flash 驱动

     (3) SPI 从设备描述:比如 SPI Flash 设备

     (4) SPI 传输层描述:spi_transfer 和 spi_message 组成

      SPI 主机控制器部分是整个 SPI 系统的核心存在,它并不属于 SPI 下的 bus、device、drvier 这一组结构,因为他并不是挂接到 bus 上的 device,更不是对应挂接在 bus 上 device 的 driver,而是相对独立的一个存在,所以 SPI 控制器部分,是连接到 platform 下的,并执行 platform 的 probe。 

       在数据发送的结构部分,内核将其抽象如下,一次传输封装为message,一个message包含一个或多个transfer。

3.2 spi-dw驱动

      spi读写流程,device驱动封装读写接口,调用spi框架的传输API spi_sync(),执行device所属的控制器驱动挂接的transfer_one()接口,实现总线层面的数据访问,传输完成后,spi_sync()返回阻塞的读写进程,得到spi访问的结果。

以SPI FLASH驱动m25p80为例:

read流程

(1) mtd_debug 或者其它应用程序 -> m25p80_read_reg()

-> spi_sync(spi, &message)

-> spi_transfer_one_message() -> dw_spi_transfer_one()

-> wait_for_completion_timeout() 阻塞

(2) dw ssi控制器spi传输

dw_spi_irq() -> dw_reader() -> complete() 通知阻塞流程继续往下执行

(3) mtd_debug 或者其它应用程序得到spi访问数据。

其中dw ssi控制器的传输接口dw_spi_transfer_one()支持三种传输方式:轮询,中断,dma。

(1)轮询

调用dw_spi_poll_transfer(dws, transfer)完成传输,边发边收。

函数返回0。

(2)中断

调用dw_spi_irq_setup(dws)设置中断,后续数据收发在ssi中断处理中完成。

函数返回1。

(3)dma

调用dw_spi_dma_transfer()触发dma传输,后续传输由dma完成,dma中断确认完成状态。spi-dw驱动在初始化时需要事先从通用dma申请通道资源。

  1. spi框架中先map buf,再传输message,提交dma描述符,挂接回调,传输发起后阻塞等待completion;
  2. dma传输,dma中断处理确认通道传输完成,调度vchan tasklet;
  3. vchan tasklet调用dma描述符的callback回调,complete传输;
  4. spi框架从阻塞处继续执行,unmap buf,message传输完成。

函数返回0。

4.调试命令

4.1 uboot

(1) sf 相关命令

(2) sspi [<bus>:]<cs>[.<mode>][@<freq>] <bit_len> <dout>

4.2 kernel

4.2.1 mtd_debug

SPI FLASH读/擦/写。

mtd_debug                                                                                                                         

usage: mtd_debug info <device>                                                                                                      

       mtd_debug read <device> <offset> <len> <dest-filename>                                                                       

       mtd_debug write <device> <offset> <len> <source-filename>                                                                    

       mtd_debug erase <device> <offset> <len>

4.2.2 debugfs

查看ssi寄存器内容。

mount -t debugfs none /sys/kernel/debug                                                                                           

cat /sys/kernel/debug/dw_spi0/registers                                                                                           

CTRLR0        = 0x00070000       

.........................                                                                                                                                  

4.2.3 module parameter

使能/去使能dma传输。

echo 1 > /sys/module/spi_dw/parameters/dma_enable

echo 0 > /sys/module/spi_dw/parameters/dma_enable

这篇关于dw ssi(spi)驱动调试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/287664

相关文章

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

IDEA如何实现远程断点调试jar包

《IDEA如何实现远程断点调试jar包》:本文主要介绍IDEA如何实现远程断点调试jar包的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录问题步骤总结问题以jar包的形式运行Spring Boot项目时报错,但是在IDEA开发环境javascript下编译

一文彻底搞懂Java 中的 SPI 是什么

《一文彻底搞懂Java中的SPI是什么》:本文主要介绍Java中的SPI是什么,本篇文章将通过经典题目、实战解析和面试官视角,帮助你从容应对“SPI”相关问题,赢得技术面试的加分项,需要的朋... 目录一、面试主题概述二、高频面试题汇总三、重点题目详解✅ 面试题1:Java 的 SPI 是什么?如何实现一个

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

如何在Ubuntu上安装NVIDIA显卡驱动? Ubuntu安装英伟达显卡驱动教程

《如何在Ubuntu上安装NVIDIA显卡驱动?Ubuntu安装英伟达显卡驱动教程》Windows系统不同,Linux系统通常不会自动安装专有显卡驱动,今天我们就来看看Ubuntu系统安装英伟达显卡... 对于使用NVIDIA显卡的Ubuntu用户来说,正确安装显卡驱动是获得最佳图形性能的关键。与Windo

Python MCPInspector调试思路详解

《PythonMCPInspector调试思路详解》:本文主要介绍PythonMCPInspector调试思路详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录python-MCPInspector调试1-核心知识点2-思路整理1-核心思路2-核心代码3-参考网址

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模