1.SPI基础
SPI是串行外围接口的意思,一般用来接一些低速的外围设备,比如eeprom,flash,ad传感器,rtc等。硬件上,SPI有四根线,SDI/SDO/CS/SCLK,具体的协议可以参看手册。
从主设备的角度
SDI:数据输入接口
SDO:数据输出接口
SCLK:时钟信号输出,控制数据交换的实际和速率
CS:片选信号,因为一个
那么通过这四根线,就可以控制数据在cpu和外围设备之间传输,能够使用SPI接口的设备,硬件上也需要符合SPI接口标准。
2.POWERPC的eSPI
下面的图是P1020RDB-PD开发板的参考手册给出的eSPI的结构框图:
counter:移位寄存器的计数器
shift register:移位寄存器
spibrg:SPI的时钟配置寄存器
eSPI mode register:配置spi工作模式的寄存器
FIFO:用于在cpu外围总线和移位寄存器之间缓存数据的Buffer
transmitter/receive register:发送和接收寄存器
spi_clk:时钟信号
大致上就是这样一个结构,cpu通过外围总线和eSPI模块进行设置和数据交换,eSPI再数据接口和外围设备进行通信。
3.eSPI Mode Register
SPI有四种模式,各个模式的主要区别在于,是在时钟的高电平空闲还是低电平空闲1和0,是在时钟的上升沿传输数据还是下降沿传输数据1和0。
这个在mode寄存器当中可以设置,同时需要注意flash所支持的模式,比如板子上这款flash支持的模式为:mode 0和mode 3.
4.硬件信息
硬件信息在调试的时候首先要关注的,包括flash的型号,整片大小,sector大小,一个读写缓冲区的大小。
CS:spi接口一般有多个片选信号,首先确定该设备挂载在哪个片选上
WP#:硬件写保护,该位会配合flash的一个rdsr寄存器的最高位,对flash进行写保护,原理图上要先确认这一位是否被拉低,否则硬件上被保护了,是不能读写的。
SCLK:时钟信号的来源,是sysclk还是ccb,时钟是第一步需要配置的。
5.eSPI的时钟配置
时钟配置正确了,部件才能正常工作,原理图和手册上都有对应的时钟部分的图,第一是确认时钟来源,第二是确认分频系数,第三确认输出时钟频率。
6.spi数据读写
SPIRF寄存器,读取一次的大小是1< SPITF写寄存器,写和读有些不一样,写之前要区分是写命令还是写数据,写的时候只允许4个字节一起写,一次都是写32位。 大致的流程下: 调试过程: 选择可移植的版本:参考来源为首选vxworks,其次linux和u-boot源码 这里从vx移植spi接口驱动和spi flash驱动,有一个有源代码且与当前板子上flash型号对应的版本,这样可以降低移植难度 问题1:编译通过后,初始化运行,FLASH不通,读取不到ID 解决过程:确认flash在硬件上挂接到SPI接口的哪一个CS上,手册中可知,SPI有四个CS,挂接在CS0上,调用probe接口去读取,返回不是0xff说明这里有设备,其于三个cs读出来均为0xff没有挂接设备 能够探测到设备,确认硬件连接是第一步。 关注时钟,flash型号手册上表明最大时钟建议为25MHZ,spi的初始化函数,busfrq给的是200MHZ,一开始理解为是CCB的总线速率,查看源码,这里的busfreq应该是要设置的spi的时钟速率,咋根据clock_freq两者计算得到一个div分频系数,写到SPMODE寄存器。更改时钟为25MHZ,重新初始化,发现能够读到ID,show出来的信息与链表中信息匹配。 问题2:擦写sector报错:status wrong,try ro recover----被写保护 flash的状态不对,在进行擦写之前,需要判断flash是否有写保护,是否写使能,是否处于busy状态,是否有sector被保护。读取RDSR寄存器的值,状态不对,所以一直循环recover。 解决方法: 对WRSR寄存器写0清除操作,在shell中调用没有用,无法清零 查看原理图手册,确认没有硬件保护WP#拉高 查看datasheet,阅读关于flash保护部分,手册给出的解锁方法是由status的最高位控制是否可写,由bp0到bp2控制保护的sector 查看linux源代码和stm32的裸机代码,发现在解锁前,需要先读出寄存器状态,并对相应位进行写1,然后再全部清除,中间需要有延时等待 解锁成功,可以对flash擦写,但是偶尔只能擦不能写,偶尔写进去了,只有一部分写进去,其于位没有改变。 问题3:擦写状态下,waity ready失败返回,program状态下数据不能完全写入 擦写时在第一步需要进行写使能,写使能状态下需要先将RDSR的WEL位置一,然后等待flash的状态变为空闲,在等待空闲状态的时候超时 program写数据后读出来,发现末尾和中间会有连续几个字节没有被写入 解决方法: 等待空闲状态超时,初步处理办法是将Timeout的数值改大,发现整个擦写过程变得特别慢,因为在等待,而且还是会有等待超时的情况,判断,SR_WIP硬件上就没有清零,查看SR_WIP清零的条件是前一步已经进行了写使能。 前一步确实已经进行了写使能,怀疑写使能没有写进去 关注函数sysSpiWriteData,注释当中的udelay(2)是在p4平台上的,性能速度要比p系列块,最后有一个I/O和CACHE的同步指令asm("eieio; sync") ,将delay时间延长,等待spiI/O将指令和数据写到flash当中去, 可以擦除,可以写。 #define EIEIO_SYNC asm("eieio; sync") eieio是POWERPC架构强制I/O操作顺序执行指令,例如需要访问spi状态寄存器,当状态位0的时候,发送char1,当发送完之后继续访问spi的data状态寄存器,再为0的时候继续发送char2,如果这段代码段中不加eieio的话,会导致优化问题,只写进去最后一个char2. sync是强制同步指令,确保编译进程序的,在sync指令之前的所有指令都被执行完毕之后才继续执行后续指令。这里为了确保数据全部写进去,还在sync之前加上了udelay进行延时。