0
0
0
主要内容:
第一步:SPI的结构
第二步:SPI的初始化
第三步:Atmega16的SPI自发自收
第四步:与SPI Flash连接
第五步:读取SPI Flash的RDID
第六步:读写SPI Flash的接口
-------------------------------------------------------------------------------------------------------------------------------------
开发环境:AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86
芯片型号:ATmega16
芯片主频:8MHz
-------------------------------------------------------------------------------------------------------------------------------------
第一步: SPI的结构
1、下面是一个主机
MASTER和一个从机
SLAVE连接时的情况:
主机和从机中都各自有一个
8bit的移位寄存器,在时钟的驱动下进行移位操作,这有点像汇编中循环移位指令的执行。
输入输出引脚:
●
SS:主机通过拉低从机的
SS引脚,来使能从机的
SPI接口;
SS引脚平时为高电平。
●
SCLK:主机发出时钟信号
SCLK,来驱动移位寄存器的数据移位,通常是一个时钟的上升沿锁存数据,下降沿移出数据。
●
MISO:主机接收 来自 从机的数据
●
MOSI:主机发送 数据 到从机,实质就是用
MISO和
MOSI两条线、将两个移位寄存器连接成一个
16bit的
循环移位寄存器。
工作过程:
1、主机拉低
SS#引脚电平,使能从机。
2、首先、在主机和从机的移位寄存器里面,分别放入各自的数据(不放入的话、里面当然也会有一个初始的随机数)。
3、
SCLK开始发送时钟信号
4、在每个时钟脉冲内、主机和从机都完成
1次数据移位,互相交换了
1bit(详细地说就是:上升沿锁存数据、下降沿移出数据)。
5、连续8个时钟脉冲后、主机和从机通过移位互换了各自的
8bit数据,通过读取各自的移位寄存器、可以得到它们交换到的数据。
6、主机拉高
CS#引脚电平,结束本次数据交换,本次共完成了
8bit数据交换,如果需要交换更多数据,连续发送
SCLK时钟即可。
● 所以说,
SPI通信的本质就是主机和从机的数据互换、通过移位的方式。
-------------------------------------------------------------------------------------------------------------------------------------
第二步: SPI的初始化
1、
SPI初始化过程主要是做如下几件事:
● 选择哪个SPI接口作为主机,哪个作为从机
● 设置SPI的
SCLK时钟的频率
● 选择是左移(先发送最高位MSB)还是右移(先发送最高位LSB)
● 设置是上升沿移位还是下降沿移位
● 选择是上升沿锁存还是下降沿锁存(数据一般是先锁存再移位,这就涉及到移位寄存器的硬件操作)
● 设置SPI引脚(MOSI和MISO引脚的方向要看数据移位的方向来定:移出就是输出引脚、移入就是输入引脚)
● 选择是否开启传输完成中断(每次完成了
8bit的数据移位锁存后、就会产生1次中断)
这里使用下面定义的初始化函数来进行初始化:
void Drv_SPI_init(const uint8_t device_mode, const uint8_t shift_mode, const uint8_t shift_first, const uint8_t clk_source);
设置参数如下:
● device_mode 主从模式选择(SPI_MODE_MSTR, SPI_MODE_SLAVE)
● shift_mode 锁存/移位模式
● shift_first 首先移出MSB(左移)还是LSB(右移)
● clk_source SCLK频率
2、根据
Atmega16的Datasheet、
SPI的初始化接口如下:
Drv_SPI.h:
// ==========================================================================================================
// Copyright (c) 2016 Chen.Chen <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ---------------------------------
// 本文定义了Atmega16下的SPI初始化
//
// ==========================================================================================================
#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Drv_IO_Port.h"
#include "config.h"
// SPI的传输模式(CPOL:时钟极性)(CPHA:采样边沿)
// ---------------------------------------------------
// mode | CPOL | CPHA | 前沿 | 后沿
// ---------------------------------------------------
// 0 | 0 | 0 | 采样锁存(↑) | 移出 (↓)
// ---------------------------------------------------
// 1 | 0 | 1 | 移出 (↑) | 采样锁存(↓)
// ---------------------------------------------------
// 2 | 1 | 0 | 采样锁存(↓) | 移出 (↑)
// ---------------------------------------------------
// 3 | 1 | 1 | 移出 (↓) | 采样锁存(↑)
// ---------------------------------------------------
typedef enum
{
SPI_SHIFT_FIRST_MSB = 0,
SPI_SHIFT_FIRST_LSB = 1,
SPI_MODE_SLAVE = 0,
SPI_MODE_MSTR = 1,
SPI_SHIFT_MODE_00 = 0, // 传输模式
SPI_SHIFT_MODE_01 = 1,
SPI_SHIFT_MODE_02 = 2,
SPI_SHIFT_MODE_03 = 3,
SPI_CLK_SOURCE_DIV_2 = 0, // SCLK频率的分频系数
SPI_CLK_SOURCE_DIV_4 = 1,
SPI_CLK_SOURCE_DIV_8 = 2,
SPI_CLK_SOURCE_DIV_16 = 3,
SPI_CLK_SOURCE_DIV_32 = 4,
SPI_CLK_SOURCE_DIV_64 = 5,
SPI_CLK_SOURCE_DIV_128 = 6
} DRV_SPI_SETTINHG;
extern volatile uint8_t SPI_shift_end;
#define SPI_SHIFT_END SPI_shift_end
void Drv_SPI_init(const uint8_t device_mode, const uint8_t shift_mode, const uint8_t shift_first, const uint8_t clk_source);
void Drv_SPI_INT_Enable(const uint8_t enable);
#endif // #ifndef __DRV_SPI_H__
Drv_SPI.c:
// ==========================================================================================================
// Copyright (c) 2016 Chen.Chen <[email protected]>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ---------------------------------
// 本文定义了Atmega16下的SPI初始化
//
// ==========================================================================================================
#include "Drv_SPI.h"
volatile uint8_t temp2017 = 0; // 调试用
volatile uint8_t temp2018 = 0;
volatile uint8_t SPI_shift_end = 1; // 0=SPI传输未完成,1=SPI传输完成
// ==========================================================================================================
// SPI初始化
//
// 参数:device_mode 主从模式(SPI_MODE_MSTR, SPI_MODE_SLAVE)
// latch_mode 锁存/移位模式
// shift_first 首先移出MSB还是LSB
// clk_source SCLK频率
//
// 说明:
// (1). 当MSTR=1 && SS引脚为输入IO时,如果SS引脚被拉低,将导致MSTR=0 && SPIF=1,使得机器变成从机模式
// (2). SPI Flash.GD25Q32支持模式0和模式3
//
// ==========================================================================================================
void Drv_SPI_init(const uint8_t device_mode, const uint8_t shift_mode, const uint8_t shift_first, const uint8_t clk_source)
{
uint8_t spr10;
uint8_t spi2x;
uint8_t cpol;
uint8_t cpha;
switch(shift_mode)
{
case SPI_SHIFT_MODE_00: cpol = 0; cpha = 0;
break;
case SPI_SHIFT_MODE_01: cpol = 0; cpha = 1;
break;
case SPI_SHIFT_MODE_02: cpol = 1; cpha = 0;
break;
case SPI_SHIFT_MODE_03: cpol = 1; cpha = 1;
break;
default : return;
}
switch(clk_source)
{
case SPI_CLK_SOURCE_DIV_2: spr10 = 0; spi2x = 1;
break;
case SPI_CLK_SOURCE_DIV_4: spr10 = 0; spi2x = 0;
break;
case SPI_CLK_SOURCE_DIV_8: spr10 = 1; spi2x = 1;
break;
case SPI_CLK_SOURCE_DIV_16: spr10 = 1; spi2x = 0;
break;
case SPI_CLK_SOURCE_DIV_32: spr10 = 2; spi2x = 1;
break;
case SPI_CLK_SOURCE_DIV_64: spr10 = 2; spi2x = 0;
break;
case SPI_CLK_SOURCE_DIV_128: spr10 = 3; spi2x = 0;
break;
default : return;
}
// IO设置
if(SPI_MODE_MSTR == device_mode)
{
Drv_IO_set_bit(PORTB, PB4);
Drv_IO_mode_bit(DDRB, PB4, IO_OUTPUT); // SS输出(拉高)、以禁止SPI从机
Drv_IO_clr_bit(PORTB, PB5);
Drv_IO_mode_bit(DDRB, PB5, IO_OUTPUT); // MOSI输出(拉低)
Drv_IO_clr_bit(PORTB, PB6);
Drv_IO_mode_bit(DDRB, PB6, IO_INPUT); // MISO输入(拉低)
Drv_IO_clr_bit(PORTB, PB7);
Drv_IO_mode_bit(DDRB, PB7, IO_OUTPUT); // SCLK输出(拉低)
}
else
{
Drv_IO_set_bit(PORTB, PB4);
Drv_IO_mode_bit(DDRB, PB4, IO_INPUT); // SS输入(拉高|如果PUD使能、将打开上拉)
Drv_IO_clr_bit(PORTB, PB5);
Drv_IO_mode_bit(DDRB, PB5, IO_INPUT); // MOSI输入(拉低)
Drv_IO_clr_bit(PORTB, PB6);
Drv_IO_mode_bit(DDRB, PB6, IO_OUTPUT); // MISO输出(拉低)
Drv_IO_clr_bit(PORTB, PB7);
Drv_IO_mode_bit(DDRB, PB7, IO_INPUT); // SCLK输入(拉低)
}
// 初始化
SPCR = ( 1 << SPE ) |
((shift_first & 0x01) << DORD) | // 先发送MSB或LSB
((device_mode & 0x01) << MSTR) | // 主从模式
((cpol & 0x01) << CPOL) | // 时钟极性
((cpha & 0x01) << CPHA) | // 前后沿
((spr10 & 0x03) << SPR0) ; // 时钟频率
SPSR &= ~(1 << SPI2X);
SPSR |= (spi2x << SPI2X); // 时钟倍频
SPI_shift_end = 1;
}
// ==========================================================================================================
// SPI传输完成中断使能
//
// 说明:
// (1). 清0 SPIF的方法:先读SPSR、在访问SPDR,可清0
// (2). 为了避免temp被优化掉,增加了volatile修饰、同时将temp的值返回
//
// ==========================================================================================================
void Drv_SPI_INT_Enable(const uint8_t enable)
{
volatile uint8_t temp;
if(DISABLE == enable)
{
SPCR &= ~(1 << SPIE);
}
else
{
SPCR |= (1 << SPIE);
}
temp = SPSR;
temp += SPDR;
}
// ==========================================================================================================
// SPI传输完成中断
//
// 说明:
// (1). 使用主机模式
//
// ==========================================================================================================
ISR(SPI_STC_vect)
{
SPI_shift_end = 1;
temp2017++;
temp2018 = SPDR;
// 主机模式下,如果SS引脚配置为输入、SS引脚收到低电平、就会导致SPI接口自动变为从机模式
// 所以这里需要检查主机模式
if(SPI_MODE_SLAVE == (SPCR & (1 << MSTR)))
{
SPCR |= (SPI_MODE_MSTR << MSTR);
return;
}
}
-------------------------------------------------------------------------------------------------------------------------------------
第三步: Atmega16的SPI自发自收
1、既然
SPI结构核心就是个移位寄存器,那么主机不必与从机连接成一个
循环移位寄存器,主机自己首尾相连、也是可以进行循环移位操作的。
也就是说、主机自己首尾相连、成为一个
8bt的
循环移位寄存器,当然也可以自发自收。
主机如下连接:
2、我们将SPI初始化如下(设置为主机模式、先发送最高位MSB、SCLK时钟的频率为主时钟的128分频=62.5KHz):
#define Drv_SPI_set_SS() Drv_IO_set_bit(PORTB, PB4)
#define Drv_SPI_clr_SS() Drv_IO_clr_bit(PORTB, PB4)
Drv_SPI_init(SPI_MODE_MSTR, SPI_SHIFT_MODE_00, SPI_SHIFT_FIRST_MSB, SPI_CLK_SOURCE_DIV_128);
Drv_SPI_INT_Enable(ENABLE);
然后、让SPI发送一个8bit数据:
Drv_SPI_clr_SS();
SPI_SHIFT_END = 0;
SPDR = 0x9F;
while(0 == SPI_SHIFT_END) {}
temp2016 = SPDR;
Drv_SPI_set_SS();
测试如下:
(1)、
CH2是SCLK信号,图中两个鼠标竖线之间的5个脉冲总共是12.38KHz,那么每个脉冲大概就是
62KHz,和设置的基本一样。
(2)、
CH1是MOSI信号,我们发送的是
0x9F=0b10011111。
在上图中、8个脉冲对应的数值正好就是
0b10011111= 0x9F。
(3)、在发送数据时、我们是需要在程序中将数据写入寄存器SPDR、SPI接口的SCLK信号就会
自动产生。
并在8bit数据发送结束后
自动停止SCLK信号。
(4)、MOSI引脚在空闲时就是高电平、也就是在发送前和发送后都是保持高电平。
在Datasheet里面虽然说MOSI的引脚方向由用户程序定义,但MOSI的电平却是由SPI接口自己决定。
在时序图中、MOSI在空闲时是高电平,而MISO是输入、电平与从机输出的电平保持一致:
(5)、在Debug下、SPDR接收到我们发送的数据0x9F:
3、我们也可以将从MOSI输出的数据
0x9F反向后、再输入MISO引脚:
确实可以得到反向后的数据(0x9F反向后、得到0x60):
(1)、反向后的波形:
(2)、Debug下可看到SPDR中接收到反向后的数值0x60:
-------------------------------------------------------------------------------------------------------------------------------------
第四步: 与SPI Flash连接
1、下面我们把SPI Flash接到Atmega16的SPI接口,让Atmega16读写SPI Flash。
电路如下:
因为我们使用的GD25Q32是一个3V驱动的SPI Flash芯片,而Atmega16是5V芯片。所以这里给出了3.3V电源,同时简单的做了一个3V-5V的转换电路。
从Atmega16输出的信号CS、MOSI、SCLK都简单的用电阻和GD25Q32连接,而从GD25Q32输出到Atmega16的MISO、使用了一个3V-5V的转换电路。
原因如下表:
(1)、GD25Q32的输入引脚接Atmega16的输出引脚的情况:
● GD25Q32的输入低电平VIL要求在0.66V以下,而Atmega16输出的低电平VOL是在0.7V以下。
然而低电平一般都可以保证接近0V,因此可以认为Atmega16输出的低电平VOL接近0V、能够满足GD25Q32的低电平VIL需要在0.66V以下的要求。
● GD25Q32的输入高电平VIH要求在2.31V以上,而Atmega16 输出的高电平VOH是在4.2V以上。
Atmega16输出的高电平、可以满足GD25Q32的高电平需要在2.31V以上的要求,只是电压过高会有损使用寿命。
(2)、GD25Q32的输出引脚接Atmega16的输入引脚的情况:
● GD25Q32的输出低电平VOL是在0.4V以下,而Atmega16的输入低电平VIL要求在1.0V以下。
GD25Q32的输出低电平、可以满足Atmega16的低电平VIL需要在1.0V以下的要求。
● GD25Q32的输出高电平是在3.1V以上,而Atmega16要求在3.0V以上。
GD25Q32的输出高电平、勉强可以满足Atmega16的高电平VIH在3.0V以上的要求。
只不过在电源波动情况下、GD25Q32的输出高电平可能会低于3.1V,所以最好加一个3V-5V的转换电路。
当然、为了保证可靠、避免因电源、器件生成工艺带来的误差,最好在每个引脚上都加上电平转换电路或转换芯片。
直接将3V-5V器件连接、波形传输过程中得不到正确的波形。
另外、Atmega16使用8MHz的主时钟、而SPI接口的SCLK最大可以到主时钟的一半、也就是4MHz。
这个频率下、S8050和S8550是否能响应,还需测试,所以一开始时使用最低频率:SCLK=主时钟的128分频=62.5KHz。
这里三极管都没有加上下拉,测试结果还可以。
-------------------------------------------------------------------------------------------------------------------------------------
第五步:读取SPI Flash的RDID
1、Atmega16连接好SPI Flash之后,我们先读取SPI Flash,看看工作情况如何。
首先选择读取SPI Flash的RDID,GD25Q32的Datasheet中描述了读取RDID的过程:
步骤如下:
(1)、主机将CS#拉低、以使能从机。
(2)、写入读RDID指令0x9F到SPDR。
(此时会自动启动SCLK时钟,开始主机和从机之间的数据移位交换)
(3)、等待SPDR中的8bit指令数据发送完毕(此时会自动停止SCLK时钟)
(指令发送完毕后、GD25Q32内部会对指令0x9F进行指令译码,并将24bit的RDID寻址到缓存里面以供读取)
(4)、向SPDR里面写入一个无意义的数值(0x00)、以启动SCLK时钟、来开始主机和从机之间的数据移位交换。
(只有向SPDR写入数据,才能启动SCLK时钟,所以需要写入并发送0x00、来和GD25Q32交换数据,而GD25Q32不会响应0x00这个数据)
(5)、等待SPDR发送完毕,此时我们完成了第一个8bit数据的交换,需要将其保存。
(6)、再联系重复第(4)步两次,交换完剩下的两个8bit数据,并保存他们。
(7)、将得到的三个8bit数据组合成最终的24bit数据。
代码如下:
指令数据(Mod_SPI_Flash.h):
// 以GD25Q32B指令集为基准建立
typedef enum
{
SPI_COMMAND_DUMMY = 0x00, // 无效数据,用于启动SCLK发送
SPI_COMMAND_WRITE_ENABLE = 0x06,
SPI_COMMAND_WRITE_DISABLE = 0x04,
SPI_COMMAND_READ_STATUS = 0x05, // 状态寄存器的低8位
SPI_COMMAND_READ_STATUS_H = 0x35, // 状态寄存器的高8位
SPI_COMMAND_WRITE_STATUS = 0x01,
SPI_COMMAND_READ = 0x03,
SPI_COMMAND_PAGE_PROGRAM = 0x02,
SPI_COMMAND_SECTOR_ERASE = 0x20,
SPI_COMMAND_BLOCK_ERASE32 = 0x52, // 块擦除(32K)
SPI_COMMAND_BLOCK_ERASE64 = 0xD8, // 块擦除(64K)
SPI_COMMAND_CHIP_ERASE = 0xC7, // 或0x60
SPI_COMMAND_READ_RDID = 0x9F, // 生产商标识(GD25Q32 = 0xC84016)
// SPI_COMMAND_READ_ID_MANU = 0x90, // 生产商ID(GD25Q32 = 0xC815)
// SPI_COMMAND_READ_ID = 0xAB, // 器件ID(GD25Q32 = 15)(同时也是唤醒指令)
// SPI_COMMAND_SLEEP = 0XB9, // 休眠
// SPI_COMMAND_CON_READ_RESET = 0xFF, // 连续读操作复位
// SPI_COMMAND_ERASE_SECURITY = 0x44, // 擦除security寄存器
// SPI_COMMAND_WRITE_SECURITY = 0x42, // 写入security寄存器
// SPI_COMMAND_READ_SECURITY = 0x48, // 读取security寄存器
// SPI_COMMAND_SUSPEND = 0x75, // 编程/擦除延迟
// SPI_COMMAND_RESUME = 0X7A, // 编程/擦除恢复
// SPI_COMMAND_HP_MODE = 0xA3, // 高性能模式
// SPI_COMMAND_READ_FAST = 0x0B,
// SPI_COMMAND_DUAL_READ_OUT = 0x3B,
// SPI_COMMAND_DUAL_READ_IO = 0xBB,
// SPI_COMMAND_QUAD_READ_OUT = 0x6B,
// SPI_COMMAND_QUAD_READ_IO = 0xEB,
// SPI_COMMAND_QUAD_READ_WORD = 0xE7,
// SPI_COMMAND_QUAD_PAGE_PROGRAM = 0x32,
}FLASH_COMMAND_SET;
读取函数(
Mod_SPI_Flash.c):
// ==========================================================================================================
// 读器件ID(GD25Q32的RDID是一个24bit数值)
//
// ==========================================================================================================
uint32_t SPI_Flash_read_RDID(void)
{
uint32_t data = 0;
Drv_SPI_clr_SS();
SPI_SHIFT_END = 0;
SPDR = SPI_COMMAND_READ_RDID; // 读取RDID的指令
while(0 == SPI_SHIFT_END) {}
temp2016 = SPDR;
SPI_SHIFT_END = 0;
SPDR = SPI_COMMAND_DUMMY; // 重新发出SCLK(发送无意义数据0x00)、以读取第一个8bit数据
while(0 == SPI_SHIFT_END) {}
data = SPDR;
temp2016 = data;
SPI_SHIFT_END = 0;
SPDR = SPI_COMMAND_DUMMY;
while(0 == SPI_SHIFT_END) {}
data = (data << 8) | SPDR;
temp2016 = data;
SPI_SHIFT_END = 0;
SPDR = SPI_COMMAND_DUMMY;
while(0 == SPI_SHIFT_END) {}
data = (data << 8) | SPDR;
temp2016 = data;
Drv_SPI_set_SS();
temp2016 = (~temp2016)&0x00FFFFFF;
return (~data)&0x00FFFFFF;
}
其中、变量SPI_SHIFT_END会在中断中设置(当然也可以直接检测SPIF位、然后在发送前清除SPIF位):
// ==========================================================================================================
// SPI传输完成中断
//
// 说明:
// (1). 使用主机模式
//
// ==========================================================================================================
ISR(SPI_STC_vect)
{
SPI_SHIFT_END = 1;
temp2017++;
temp2018 = SPDR;
// 主机模式下,如果SS引脚配置为输入、SS引脚收到低电平、就会导致SPI接口自动变为从机模式
// 所以这里需要检查主机模式
if(SPI_MODE_SLAVE == (SPCR & (1 << MSTR)))
{
SPCR |= (SPI_MODE_MSTR << MSTR);
return;
}
}
在Debug下可以得到这个24bit的RDID=0x00C84016:
这和GD25Q32的Datasheet里面给出的数值一致:
这表明我们读取SPI Flash的步骤是对的。
而测试到的波形也印证了这一点:
在图中、在发送完0x9F的指令后,连续对GD25Q32进行了7次读取,读到的都是0xC84016这个数值:
这说明、在GD25Q32对指令数据0x9F译码后,RDID的数值(0xC84016)被寻址到缓存。
我们每次都去、都会在缓存里面得到相同的一个数值。
-------------------------------------------------------------------------------------------------------------------------------------
第六步:读写SPI Flash的接口
1、最后给出读写SPI Flash的接口
0
0