加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

FLASH 存储学习-串行SPI nor

发布时间:2020-12-15 17:53:38 所属栏目:百科 来源:网络整理
导读:分类:? 嵌入式 1.1? SST25VF080B 简介 1.1.1? 主要特性 关键点:容量、速度(时钟速度、读写速度)、功耗。 l? 容量: 8MBit ; l? 最高 SPI 时钟频率: 50MHz ; l? 低功耗模式下电流消耗: 5uA ,正常读模式电流: 15mA ;低功耗!采用不同的制造技术功耗

分类:?嵌入式

1.1? SST25VF080B 简介 1.1.1? 主要特性

关键点:容量、速度(时钟速度、读写速度)、功耗。

l?容量:8MBit

l?最高SPI时钟频率:50MHz

l?低功耗模式下电流消耗:5uA,正常读模式电流:15mA;低功耗!采用不同的制造技术功耗要低很多。

l?整片擦除:35ms;扇区/块擦除:18ms;字节编程:7us;整片擦除的速度要快很多!

1.2? 系统框图与电路 1.2.1? 系统框图

??? 关于内部存储矩阵的访问和存储结构同并行NorFlash的一致,只不过多了个串行接口,用于实现对串行数据的解码。

f908cbd1-8f4c-427c-a120-10e2b99a36d4.jpg


1.2.2? 存储组织

扇区大小4KB,块大小:32/64KB;页大小为字节或字。

3b5ed3be-3709-4650-b240-65232320db6e.jpg


1.2.3? 引脚及封装

7bfcb528-faec-4e6f-9fa1-b6d50d0d0155.jpg


引脚说明:

l?SCKSISOCE?–?SPI接口控制线

l?WP#?--?用于使能状态寄存器中的BPL位,有效时只允许锁定BPL,而不允许解锁BPL不是说明使能保护!BPL位用于锁定控制扇区保护的相应位

l?HOLD#?--?用于暂停与SPI的通信,而不需要复位器件;

1.2.4? 典型电路

使用STM32F103驱动该器件时,典型的电路如图所示。

7d4ba3d8-0809-472c-89d5-9a429d05ba2d.jpg


注意,WP为低,判定寄存器的锁定功能将启用。但不会太影响片内块的保护。

1.3? 保护机制

b73d03bc-1ede-481c-b8b4-25ec0d21d2c4.jpg


? l?软件写保护:状态寄存器中的BP3—BP0BPL提供片内块、状态寄存器的写保护。

硬件保护WP#引脚低电平,用于锁定状态寄存位7—BPL。由表2WP#为高时,可以执行状态寄存器写命令,可随时更改状态寄存器。为低时,只能将BPL置为1,而不能从1置为0,即置1后,状态寄存器将锁定不变。

WP#?àBPLBP3—BP0

BPLàBP3BP0

78dbe8b7-8266-451d-bbc7-ad997db56673.jpg


1.4? 编程接口 1.4.1? 状态寄存器

状态寄存器用于用于获取FLASH的当前工作状态。

ae4f1f2b-ed0a-4e13-87ed-4b4fe15971b5.jpg


l?BUSY位:指示是否正在编程或擦除操作;

l?WEL位:指示器件是否处理可写的状态。RESET状态(0)指示不可写,默认在上电、完成写操作后,器件自行返回到不可写状态,以保护器件不受意外的擦写。因而每次写FLASH前,都必须先清除(1),以使能器件的写。软件可控写。

l?AAI位:指示器件是否处理地址自动增加模式或者是字节编程模式。

l?BPL位:用于控制BPX是否可写。

l?BPX位:用于控制保护块的范围,属于软件保护,扇区保护如下。

??????????????????????????????????????????

916285ed-16ee-46e6-95bc-be7e6de3ca09.jpg


这里的扇区保护比较简单,更为复杂的扇区保护机制可针对每个扇区进行保护。

1.4.2? 命令接口

通信过程中,仅仅只有读ID、读数据、读状态寄存器需要在可保护CS不变而继续写数据。其它的则需要写完后接CS线。

cf703fe9-2f56-4a34-a275-9e02b6f631a9.jpg


1.5? 通信时序 1.? 单字 SPI 通信时序

无论SPI总线空闲时SCK为高或为低,保证在上升沿采样数据,下降沿输出数据。先传送高位,每次传送8位。

5b5e4aa8-2827-4a9d-8aaa-698246c365b3.jpg


2.? 读命令

81ce36f2-eaf9-48d8-a32f-4bdfd4e392ed.jpg


3.? 快速读模式

有可能内部使用了缓冲模式,可在更高的时钟速度(50MHz下读数据。

57e6ffbf-2702-4255-ae0c-02e7507637ef.jpg


4.? 写使能

该命令可设置状态寄存器中的WEL位,使得可执行擦除和编程命令。

7d98eb1f-db2f-4297-b0a3-3c16de7bb647.jpg


5.? 写禁能

1463099b-3294-4a4a-a981-432e4a795a3f.jpg


6.? 字节编程

eea22af1-623c-4633-8ff8-238ae3bb3617.jpg


7.? AAI 编程

即自动地址增量的编程,每个周期写1个字。

bdd8b701-619a-4903-aae0-a5aba42b6eb1.jpg


在最后,通过WRDI返回来正常模式。在每写完两个字后,需查询害怕状态。

在写字的过程中,有三种方式检测是否完成字编程。其中硬件检测:读SO的状态。可在写AAI命令之前,通过命令配置SO口为RD/BY#状态。或者也可通过读取状态寄存器来检测是否完成写操作。

ab211f0b-3e3e-443a-9b3c-7d30c8f7d942.jpg


ee6ce252-01d8-4e12-8961-a163ddebb31a.jpg


8.? 4KB 的扇区擦除

ec41671d-eddc-4cbf-a1e7-f845e0d93f0c.jpg


9.? 32K 块擦除

438305ca-3e36-4a1e-a99b-160c87082fcd.jpg


10.? 64K 块擦除


11.? 整片擦除

2c68747f-b720-4391-9abf-fe0a120374f7.jpg

12.? 读状态寄存器

347abe8c-28c5-46cf-a05d-92037c581eca.jpg

13.? 使能写状态寄存器和写状态寄存器

两条命令必须连续写,不允许被打断?以避免意外写状态寄存器。

l?WP#为低电平时,BPL只能写1,不可写0.;此时位为高时,写状态寄存器命令将被忽略即此时,状态寄存器只能被锁定,而不能再解锁0)锁定后将不能再任意改高保护方式,相当于将当前的保护方式给固定下来!

l?而若WP#为高电平,BPL位失效,状态寄存器不再被锁定,此时BPLBPX可被更改。BPL位可设置为1,也可设置为0。可任意更改保护方式。

WP#的作用,锁定BPL1。一旦BPL锁定为1,则BPX将不可再更改,即软件保护将被锁定。当WP#无效时,BPL可随时、任意更改,同时更改软件保护。

8c131337-ba12-4b87-93e0-91974822a930.jpg


14.? JEDEC ?Read-ID

获取SST制造商的IDSST?FLASH器件的ID

af1e3af4-0b89-4e77-a8e5-04c4c678d8c1.jpg


1.6? 驱动设计

驱动框架如下图:

93afb61e-a596-454f-aaec-33482e5ee30a.jpg


算法编写原则:

(1)?可以为每一种SPI?Flash针对性的写一份驱动源码,但是当更换Flash时,需要修改的地方很多;当系统中有多个设备时,显示这不够用,因而最好的方法是实现面向对像的封装,将与Flash设备相关的信息封装在一个结构体内,具体的算法根据结构体中相关的数据来决定如何访问硬件,做到过程可以不依赖于实际的硬件;

(2)?尽量按标准的初始化、读写、关闭、控制接口设计API,这样可统一抽像出相应的结构,也易于使用和理解。留给最终用户调用的API应该尽量的少和易于理解;

(3)?SPI?Flash接口为SPI,操作方法与并行接口致,但其扇区组织类似,从最大到最小区域分为芯片--扇区-页。编程算法则也是通过写命令序列的方式,如发送命令字-发送字节-发送数据-查询状态寄存器。保护方式是通过存储器中的一些非易失性的位置0或置1选择性地以扇区或块为保护单位。

1.7? 驱动代码

点击(此处)折叠或打开

  1. //?SST25VF080B驱动接口
  2. /?By:lstzixing At ZLG
  3. /?Date:?2011-1
  4. #include?"STM32Libstm32f10x.h"
  5. #include?"hal.h"

  6. typedef unsigned long uint32;
  7. typedef unsigned short uint16;
  8. typedef unsigned char uint8;

  9. #define SPI_FLASH_SIZE?(1024*1024*2)?/?SPI Flash容量
  10. #define SPI_FLASH_OK 0?
  11. #define SPI_FLASH_ERR_PARA 3?/?SPI Flash参数错误

  12. /?SPI Flash擦除操作码
  13. #define SPI_FLASH_ERASE_CHIP 0?/?整片擦除
  14. #define SPI_FLASH_ERASE_SECTOR 1?/?扇区擦除
  15. #define SPI_FLASH_ERASE_BLOCK 2?/?块擦除

  16. /?SPI状态寄存器和位
  17. #define SPI_FLASH_REG_BIT_BUSY?(1?<<?0)
  18. #define SPI_FLASH_REG_BIT_WEL?<?1)
  19. #define SPI_FLASH_REG_BIT_BPX?(0xF?<?2)
  20. #define SPI_FLASH_REG_BIT_AAI?<?6)
  21. #define SPI_FLASH_REG_BIT_BPL?<?7)

  22. #define SPIFlashSelect()???????? GPIO_ResetBits(GPIOC,?GPIO_Pin_13*?SST CS?=?L?*/?
  23. #define SPIFlashDeSelect)???????? GPIO_SetBits=?H?/

  24. *
  25. *?Function?name:?SPIFlashInit
  26. *?Descriptions:?初始化SPI硬件,设置相关的GPIO口、SPI控制器
  27. *?Input parameters:?none
  28. *?Output parameters:?None
  29. *?Returned value/
  30. void SPIFlashInit(void)
  31. {
  32. ????/?打开SPI1和GPIO时钟?
  33. ????RCC->APB2ENR?|=?RCC_APB2ENR_SPI1EN?|
  34. ????????????????????RCC_APB2ENR_IOPAEN?|
  35. ????????????????????RCC_APB2ENR_IOPBEN?|
  36. ????????????????????RCC_APB2ENR_IOPCEN?|
  37. ????????????????????RCC_APB2ENR_IOPDEN?|
  38. ????????????????????RCC_APB2ENR_IOPEEN?|
  39. ????????????????????RCC_APB2ENR_IOPFEN;

  40. ????/?PA5/6/7为复用模式, 50MHZ
  41. ????GPIOA>CRL?&=?~(GPIO_CRL_CNF5?|?GPIO_CRL_CNF6?|?GPIO_CRL_CNF7?|
  42. ????????????????????GPIO_CRL_MODE5?|?GPIO_CRL_MODE6?|?GPIO_CRL_MODE7);
  43. ????GPIOA=?GPIO_CRL_MODE5?|?GPIO_CRL_MODE7?|
  44. ??????????????????GPIO_CRL_CNF5_1?|?GPIO_CRL_CNF6_1?|?GPIO_CRL_CNF7_1/?配置PC.13为输出片选线
  45. ????GPIOC>CRH?(GPIO_CRH_CNF13?|?GPIO_CRH_MODE13;
  46. ????GPIOC=?GPIO_CRH_MODE13/?配置SPI1
  47. ????SPI1>CR1?/SPI_CR1_CPHA?|?
  48. ????????????????SPI_CR1_MSTR?|
  49. ????????????????/SPI_CR1_BR?|
  50. ????????????????SPI_CR1_SSI?|?
  51. ????????????????SPI_CR1_SPE?|
  52. ????????????????SPI_CR1_SSM;?

  53. ????SPI1>CR2?=?0;

  54. ????SPIFlashDeSelect;
  55. }

  56. :?SPIWriteReadByte
  57. :?向SPI发送并读取一数据
  58. :?data 要发送的数据
  59. :?uint16 读取的数据
  60. /
  61. static uint16 SPIWriteReadByte(uint16 data/?发送一字节
  62. ????while(SPI1>SR?&?SPI_I2S_FLAG_TXE==?RESET;
  63. ????SPI1>DR?=?data/?接收一字节
  64. ????&?SPI_I2S_FLAG_RXNE;
  65. ????return>DR:?SPIFlashReadstatusReg
  66. :?读状态寄存器
  67. :?当前状态寄存器的值
  68. *?BIT0?-?BUSY位,写忙标志?
  69. *?BIT1?-?WEL位,FLASH处于写保护状态
  70. *?BIT6[5..2]-BP?[3.0
  71. *?BIT6?-?指示正在自动自境编程中
  72. *?BIT7?-?BPL,BPX的保护位
  73. /
  74. static uint8 SPIFlashReadstatusReg?{
  75. ????uint8 uByte/?发送读状态寄存器命令
  76. ????SPIFlashSelect;
  77. ????{
  78. ????????SPIWriteReadByte(0x5;
  79. ????????uByte?=?SPIWriteReadByte(0xFF}
  80. ????SPIFlashDeSelect;

  81. ????return uByte;?
  82. :?SPIFlashWritestatusReg
  83. :?写状态寄存器
  84. :?status 要写入的值
  85. /
  86. static void SPIFlashWritestatusReg?(uint8 status/?发送使能状态寄存器写命令
  87. ????SPIFlashSelect(0x50;
  88. ????
  89. ????/?写命令和状态值
  90. ????SPIFlashSelect(0x1;
  91. ????????SPIWriteReadByte(status:?SPIFlashReadID
  92. :?读SPI FLASH的JEDEC ID
  93. :?读的ID,从最高字节到最低字节:制造商ID(1B-存储类型-存储容量/
  94. uint32 SPIFlashReadID?{
  95. ????uint32 spiID/?发送低速读命令0x9F,3字节地址
  96. ????SPIFlashSelect(0x9F;
  97. ????????spiID?(0xff<?16<?8;

  98. ????return spiID}


  99. :?SPIFlashRead
  100. :?以低速方式=25MHZ)从SPI FLASH读数据
  101. :?readBuf 读数据存储的缓冲区首址
  102. *?readCnt 要读取的数据量
  103. :?uint32 实际读得的数据量。当读地址超出芯片容量时,将只读在芯片地址范围内
  104. *?的数据
  105. /
  106. uint32 SPIFlashRead?(uint32 readAddr*?readBuf{
  107. ????uint32 i;
  108. ????uint8 addr/?检查参数
  109. ????if?(readAddr?>=?SPI_FLASH_SIZE?|?
  110. ????????readBuf?=?0?|
  111. ????????readCnt?{
  112. ????????return SPI_FLASH_ERR_PARA}

  113. ????/?校正要读的数据总量
  114. ????+?readCnt?=?SPI_FLASH_SIZE{
  115. ????????readCnt?-?readAddr/?将地址转换为字节数组
  116. ????addr[0]?(uint8>?16;
  117. ????addr[1>?8[2&?0xff/?等待SPI Flash完成写操作
  118. ????while?(SPIFlashReadstatusReg&?SPI_FLASH_REG_BIT_BUSY?;

  119. ????SPIFlashSelect{
  120. ????????/?发送低速读命令0x3,3字节地址
  121. ????????SPIWriteReadByte(0x3(addr;
  122. ????
  123. ????????/?依次读readCnt个数据
  124. ????????for?(i?;?i?<?readCnt;?i+{
  125. ????????????readBuf[i;
  126. ????????}
  127. ????;

  128. ????return i:?SPIFlashFastRead
  129. :?以高速方式=50MHZ/
  130. uint32 SPIFlashFastRead?/?发送低速读命令0x3,3字节地址
  131. ????????SPIWriteReadByte(0xB:?SPIFlashWriteByte
  132. :?向SPI Flash指定地址处写一字节数据
  133. :?writeAddr 写入的地址
  134. *?udata 写入的值
  135. *?Notes:?写之前必须注意到写保护的存储影响
  136. /
  137. uint32 SPIFlashWriteByte?(uint32 writeAddr{
  138. ????uint8 addr/?检查写地址是否越界
  139. ????(writeAddr?/?发送写使能命令
  140. ????SPIFlashSelect(0x06/?写入实际要写入的数据
  141. ????SPIFlashSelect
  142. ????????SPIWriteReadByte(0x2(uByte;

  143. ????return SPI_FLASH_OK:?SPIFlashFastWrite
  144. :?以地址自增方式向指定FLASH地址处连续写字数据
  145. :?writeAddr 写入的起始地址
  146. *?writeBuferr 写数据存储的缓冲区
  147. *?uWord 写入的数据量,以字为单位
  148. /
  149. uint32 SPIFlashFastWrite?*?writeBuferr{
  150. ????uint16 i;

  151. ?????|?
  152. ????????writeBuferr?|
  153. ????????uWord?+?(uWord?{
  154. ????????uWord?(SPI_FLASH_SIZE?-?writeAddr>?1;?
  155. ????/?发送低速读命令0xAD,3字节地址(0xAD(writeBuferr>?0x08&?0xFF/?发送其它字节
  156. ????=?1<?uWord/?等待SPI Flash完成写操作
  157. ????????;
  158. ????
  159. ????????SPIFlashSelect{
  160. ???????????/?发送引导命令和编程字数据
  161. ????????????SPIWriteReadByte;
  162. ????????????SPIWriteReadByte;?
  163. ????????}
  164. ????????SPIFlashDeSelect;
  165. ???}?

  166. ????/?发送写禁能命令,退出该模式
  167. ????SPIFlashSelect(0x04:?SPIFlashChipErase
  168. :?擦除整块芯片
  169. *?Note:?如果sectorAaddr
  170. /
  171. void SPIFlashErase?(uint8 eraseType/?根据类型选择擦除方式
  172. ????switch?(eraseType/?选择整片擦除方式
  173. ????????case?SPI_FLASH_ERASE_CHIP:
  174. ????????????SPIFlashSelect;
  175. ????????????{
  176. ????????????????SPIWriteReadByte(0x60}
  177. ????????????SPIFlashDeSelect;
  178. ????????????break;
  179. ????????
  180. ????????/?扇区擦除方式
  181. ????????case?SPI_FLASH_ERASE_SECTOR:
  182. ????????????(eraseAddr?<?SPI_FLASH_SIZE{
  183. ????????????????/?将地址转换为字节数组
  184. ????????????????addr;
  185. ????????????????addr;
  186. ????????????
  187. ????????????????/?发送扇区擦除命令,擦除的扇区地址?
  188. ????????????????SPIFlashSelect;
  189. ????????????????{
  190. ????????????????????SPIWriteReadByte(0x20;
  191. ????????????????????SPIWriteReadByte}
  192. ????????????????SPIFlashDeSelect}
  193. ????????????break;

  194. ????????/?32K块擦除方式
  195. ????????case?SPI_FLASH_ERASE_BLOCK/?发送块擦除命令,擦除的块地址?
  196. ????????????????SPIFlashSelect(0x52;

  197. ????????default:
  198. ????????????break:?SPIFlashSetProtection
  199. :?设定SPI存储器的保护模式,加保护或解保护
  200. :?isProtect 保护的模式,1-加保护, 0?-?解保护
  201. *?startAddr 保护区域的起始地址
  202. *?stopAddr 保护区域的结束地址
  203. :?0?-?操作成功, 1?-?操作失败(当为解保护时,硬件保护阻止了解保护)
  204. /
  205. uint32 SPIFlashSetProtection?(uint8 isProtect?uint32 stopAddr{
  206. ????uint8 BPXMask;
  207. ????uint8 status(isProtect/?清除所有的保护位
  208. ????????SPIFlashWritestatusReg(0/?如果BPL只读,即不可更改BPX位
  209. ????????&?SPI_FLASH_REG_BIT_BPL{

  210. ????????????/?当该区域已经加保护时,正确返回
  211. ????????????(status?&?SPI_FLASH_REG_BIT_BPX>?BPXMask{
  212. ????????????????return 0}?else?/?当未加保护时
  213. ????????????????return 1}
  214. ????????????
  215. ????????{?
  216. ????????????/?计算保护模式位
  217. ????????????(startAddr?>?SPI_FLASH_SIZE=?0xF0000{
  218. ????????????????BPXMask?=?0x1?;?
  219. ????????????=?0xE0000=?0x2?=?0xC0000=?0x3?=?0x80000=?0x4?=?0x5?}

  220. ????????????/?BPL写读写,此时加上保护位即可,但不锁定BPL,以妨不可恢复?
  221. ????????????SPIFlashWritestatusReg(BPXMask;

  222. ????????????return 0/?解除保护
  223. ????????SPIFlashWritestatusReg/?读保护位,如果值不为全0,则可能硬件加保护,解保护失败
  224. ????????{
  225. ????????????return 1{
  226. ????????????return 0}
  227. -?测试代码?/
  228. uint32 id;
  229. uint8 writeBuffer[1024;
  230. uint8 readBuffer;
  231. uint8 status;

  232. #define SPI_FLASH_SECTOR_SIZE?*4)
  233. #define SPI_FLASH_BLOCK_SIZE?*32)

  234. void SPIFlashTest?/?初始化SPI控制器
  235. ????SPIFlashInit/?读ID测试,值应为0x00BF258E
  236. ????id?=?SPIFlashReadID(id?!=?0x00BF258E{
  237. ????????return/?先解除保护才可写
  238. ????SPIFlashSetProtection?0xFFFFF/?整片擦除测试
  239. ????SPIFlashErase(SPI_FLASH_ERASE_CHIP<?SPI_FLASH_SIZE?/?sizeof(readBuffer{
  240. ????????SPIFlashRead*?sizeof?sizeof(j?;?j?<?sizeof;?j{
  241. ????????????[j=?0xff{
  242. ????????????????return}
  243. ????????}?
  244. ????}
  245. ????
  246. ????/?字节写和读测试
  247. ????{
  248. ????????SPIFlashWriteByte(i;?
  249. ????????SPIFlashRead?if(?readBuffer{
  250. ????????????return/?扇区擦除测试
  251. ????/?(4{
  252. ????????SPIFlashErase(SPI_FLASH_ERASE_SECTOR/?快速写测试
  253. ????(writeBuffer{
  254. ????????????writeBuffer=?j}
  255. ????????SPIFlashFastWrite(?i?(uint16?)writeBuffer;
  256. ????????SPIFlashFastRead?(uint8?)readBuffer/?交换字节顺序再比较
  257. ????????{
  258. ????????????uint16?*?ptr?&readBuffer[j?*ptr?|?(?memcmp(?writeBuffer(32(SPI_FLASH_ERASE_BLOCK/?保护测试
  259. ????SPIFlashSetProtection(1;
  260. ????SPIFlashSetProtection}

阅读(1141) | 评论(0) | 转发(3) |

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读