读懂时序图
前言
读时序图之前,首先要明确几个概念
- 引脚
首先,时序图一般指同步时序图,异步时序例如串口(UART/SCI)不在讨论之列
判断同步时序的方法很简单,就是看是否存在专门的Clock信号引脚,其次看I/O引脚上的边沿是否和Clock同步,一般常见的同步时序串行接口有SPI、SDIO、I2C、I2S、USART等
本文档由W25Q64(华邦电子出品,NOR Flash,SPI/QSPI接口)中的一个简单I/O指令的执行,解释如何读懂时序图 - 端序
一般存储顺序分为两种,大端和小端
- 大端:一串数据的高字节存储在低地址,低字节存储在高地址
- 小端:高低字节按照高低地址顺序排列,和大端相反
尤其注意是字节的存储顺序,而非数据位的顺序
就目前看到过的各种芯片的串行时序,多字节指令(≥2Byte)一般是大端序,而常见单片机例如ARM却是小端序,这部分尤其需要注意区分
- 数据顺序
指I/O数据的存储顺序
- 如果是存储芯片,那么无论如何,按照顺序写入和读出可以保证数据的完整性
- 其他芯片就看时序图中给定的端序,然后整理成单片机的端序即可
- 单片机相关
一般单片机的串行通信接口的硬件buffer均为一个字节,但是受限于驱动库(软件限制),多用小端序读写此buffer
直接操作硬件的话,可以避开驱动库的限制,自由地配置为大端或者小端
W25Q64的Fast Read指令
- W25Qxxx系列是使用SPI接口的NOR Flash,使用24位地址宽度
- 通信格式为:指令——地址(大端序)——I/O数据
- SPI通信开始的标志是CS/NSS被主机拉低,从设备被选中
- SPI总线的I/O在空闲时处于High-Impedance(高阻)状态
- 一般时序图上会标注时钟的周期号,可以据此判断时序图的先后
对于上述的时序图,可以这样解读:
- CS拉低,开始通信
- CLK引脚上出现脉冲,在脉冲的边沿上,I/O引脚开始脱离高阻态,最多占用一个时钟周期
- MOSI引脚发送指令0x0Bh,MISO引脚处于高阻态,占用八个时钟周期
- MOSI引脚按照大端序发送24位地址,先发送高字节,MISO引脚处于高阻态共占用24个时钟周期
- MOSI和MISO均进入高阻态,等待八个时钟周期(也可以将该Dummy Byte读出并舍去)
- MOSI进入空闲(非高阻态,且无需关心),MISO上开始出现数据脉冲,在该芯片上,数据按照写入的顺序读出,读出N个字节,占用N*8个时钟周期
- CS拉高,MOSI/MOSI进入高阻态,CLK引脚回到空闲电平,通信结束
综上,同步时序逻辑的理解,大致分为几步:
- 找到通信开始和结束的标志,找到时钟脉冲
- 对时钟脉冲分段,找到每一段传输的数据是什么,是否有空闲时钟脉冲(这很重要)
- 分好数据段后,确定端序,并在程序中做出相应处理
- 根据上述信息,即可整理成代码,进行下一步调试
该指令对应的伪代码如下(C语言)
/* Fake Functions Declerations */
void SPI_Transmit(uint8_t* pTxData, uint16_t pTxSize);
void SPI_Receive(uint8_t* pRxData, uint16_t pRxSize);
/* Command Function */
void W25Qxx_FastRead(uint8_t* pReadData, uint16_t pReadSize, uint32_t Addr)
{
/* Variables Definitions */
uint8_t command_buff = 0x0Bu, dummy_buff = 0u, addr_buff[3] = {0};
/* Address Processing */
addr_buff[0] = (Addr & 0x00FF0000ul) >> 16u;
addr_buff[1] = (Addr & 0x0000FF00ul) >> 8u;
addr_buff[2] = Addr & 0x000000FFul;
/* Instruction Transmitting */
SPI_Transmit(&command_buff, 1u);
/* Address Transmitting */
SPI_Transmit(addr_buff, 3u);
/* Dummy Reading */
SPI_Receive(&dummy_buff, 1u);
/* Data Reading */
SPI_Receive(pReadData, pReadSize);
}