flash.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #include "flash.h"
  2. //#include "spi.h"
  3. #include "SPI_DMA.h"
  4. #include "delay.h"
  5. //4Kbytes为一个Sector
  6. //16个扇区为1个Block
  7. //W25X16
  8. //容量为2M字节,共有32个Block,512个Sector
  9. //初始化SPI FLASH的IO口
  10. uint8_t SPI_Flash_Init(void)
  11. {
  12. //SPIx_Init(); //初始化SPI
  13. return 0;
  14. }
  15. //读取SPI_FLASH的状态寄存器
  16. //BIT7 6 5 4 3 2 1 0
  17. //SPR RV TB BP2 BP1 BP0 WEL BUSY
  18. //SPR:默认0,状态寄存器保护位,配合WP使用
  19. //TB,BP2,BP1,BP0:FLASH区域写保护设置
  20. //WEL:写使能锁定
  21. //BUSY:忙标记位(1,忙;0,空闲)
  22. //默认:0x00
  23. u8 SPI_Flash_ReadSR(void)
  24. {
  25. u8 byte=0;
  26. SPI_FLASH_CS=0; //使能器件
  27. SPIx_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
  28. byte=SPIx_ReadWriteByte(0Xff); //读取一个字节
  29. SPI_FLASH_CS=1; //取消片选
  30. return byte;
  31. }
  32. //写SPI_FLASH状态寄存器
  33. //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
  34. void SPI_FLASH_Write_SR(u8 sr)
  35. {
  36. SPI_FLASH_CS=0; //使能器件
  37. SPIx_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令
  38. SPIx_ReadWriteByte(sr); //写入一个字节
  39. SPI_FLASH_CS=1; //取消片选
  40. }
  41. //SPI_FLASH写使能
  42. //将WEL置位
  43. void SPI_FLASH_Write_Enable(void)
  44. {
  45. SPI_FLASH_CS=0; //使能器件
  46. SPIx_ReadWriteByte(W25X_WriteEnable); //发送写使能
  47. SPI_FLASH_CS=1; //取消片选
  48. }
  49. //SPI_FLASH写禁止
  50. //将WEL清零
  51. void SPI_FLASH_Write_Disable(void)
  52. {
  53. SPI_FLASH_CS=0; //使能器件
  54. SPIx_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
  55. SPI_FLASH_CS=1; //取消片选
  56. }
  57. //读取芯片ID W25X16的ID:0XEF14
  58. u16 SPI_Flash_ReadID(void)
  59. {
  60. u16 Temp = 0;
  61. SPI_FLASH_CS=0;
  62. SPIx_ReadWriteByte(0x90);//发送读取ID命令
  63. SPIx_ReadWriteByte(0x00);
  64. SPIx_ReadWriteByte(0x00);
  65. SPIx_ReadWriteByte(0x00);
  66. Temp|=SPIx_ReadWriteByte(0xFF)<<8;
  67. Temp|=SPIx_ReadWriteByte(0xFF);
  68. SPI_FLASH_CS=1;
  69. return Temp;
  70. }
  71. //读取SPI FLASH
  72. //在指定地址开始读取指定长度的数据
  73. //pBuffer:数据存储区
  74. //ReadAddr:开始读取的地址(24bit)
  75. //NumByteToRead:要读取的字节数(最大65535)
  76. void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
  77. {
  78. u16 i;
  79. SPI_FLASH_CS=0; //使能器件
  80. SPIx_ReadWriteByte(W25X_ReadData); //发送读取命令
  81. SPIx_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址
  82. SPIx_ReadWriteByte((u8)((ReadAddr)>>8));
  83. SPIx_ReadWriteByte((u8)ReadAddr);
  84. for(i=0;i<NumByteToRead;i++)
  85. {
  86. pBuffer[i]=SPIx_ReadWriteByte(0XFF); //循环读数
  87. }
  88. SPI_FLASH_CS=1; //取消片选
  89. }
  90. //SPI在一页(0~65535)内写入少于256个字节的数据
  91. //在指定地址开始写入最大256字节的数据
  92. //pBuffer:数据存储区
  93. //WriteAddr:开始写入的地址(24bit)
  94. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
  95. void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
  96. {
  97. u16 i;
  98. SPI_FLASH_Write_Enable(); //SET WEL
  99. SPI_FLASH_CS=0; //使能器件
  100. SPIx_ReadWriteByte(W25X_PageProgram); //发送写页命令
  101. SPIx_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址
  102. SPIx_ReadWriteByte((u8)((WriteAddr)>>8));
  103. SPIx_ReadWriteByte((u8)WriteAddr);
  104. for(i=0;i<NumByteToWrite;i++)SPIx_ReadWriteByte(pBuffer[i]);//循环写数
  105. SPI_FLASH_CS=1; //取消片选
  106. SPI_Flash_Wait_Busy(); //等待写入结束
  107. }
  108. //无检验写SPI FLASH
  109. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
  110. //具有自动换页功能
  111. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
  112. //pBuffer:数据存储区
  113. //WriteAddr:开始写入的地址(24bit)
  114. //NumByteToWrite:要写入的字节数(最大65535)
  115. //CHECK OK
  116. void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
  117. {
  118. u16 pageremain;
  119. pageremain=256-WriteAddr%256; //单页剩余的字节数
  120. if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
  121. while(1)
  122. {
  123. SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);
  124. if(NumByteToWrite==pageremain)break;//写入结束了
  125. else //NumByteToWrite>pageremain
  126. {
  127. pBuffer+=pageremain;
  128. WriteAddr+=pageremain;
  129. NumByteToWrite-=pageremain; //减去已经写入了的字节数
  130. if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
  131. else pageremain=NumByteToWrite; //不够256个字节了
  132. }
  133. };
  134. }
  135. //写SPI FLASH
  136. //在指定地址开始写入指定长度的数据
  137. //该函数带擦除操作!
  138. //pBuffer:数据存储区
  139. //WriteAddr:开始写入的地址(24bit)
  140. //NumByteToWrite:要写入的字节数(最大65535)
  141. u8 SPI_FLASH_BUF[4096];
  142. void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
  143. {
  144. u32 secpos;
  145. u16 secoff;
  146. u16 secremain;
  147. u16 i;
  148. secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16
  149. secoff=WriteAddr%4096;//在扇区内的偏移
  150. secremain=4096-secoff;//扇区剩余空间大小
  151. if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
  152. while(1)
  153. {
  154. SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
  155. for(i=0;i<secremain;i++)//校验数据
  156. {
  157. if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除
  158. }
  159. if(i<secremain)//需要擦除
  160. {
  161. SPI_Flash_Erase_Sector(secpos);//擦除这个扇区
  162. for(i=0;i<secremain;i++) //复制
  163. {
  164. SPI_FLASH_BUF[i+secoff]=pBuffer[i];
  165. }
  166. SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区
  167. }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
  168. if(NumByteToWrite==secremain)break;//写入结束了
  169. else//写入未结束
  170. {
  171. secpos++;//扇区地址增1
  172. secoff=0;//偏移位置为0
  173. pBuffer+=secremain; //指针偏移
  174. WriteAddr+=secremain;//写地址偏移
  175. NumByteToWrite-=secremain; //字节数递减
  176. if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完
  177. else secremain=NumByteToWrite; //下一个扇区可以写完了
  178. }
  179. };
  180. }
  181. //擦除整个芯片
  182. //整片擦除时间:
  183. //W25X16:25s
  184. //W25X32:40s
  185. //W25X64:40s
  186. //等待时间超长...
  187. void SPI_Flash_Erase_Chip(void)
  188. {
  189. SPI_FLASH_Write_Enable(); //SET WEL
  190. SPI_Flash_Wait_Busy();
  191. SPI_FLASH_CS=0; //使能器件
  192. SPIx_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
  193. SPI_FLASH_CS=1; //取消片选
  194. SPI_Flash_Wait_Busy(); //等待芯片擦除结束
  195. }
  196. //擦除一个扇区
  197. //Dst_Addr:扇区地址 0~511 for w25x16
  198. //擦除一个山区的最少时间:150ms
  199. void SPI_Flash_Erase_Sector(u32 Dst_Addr)
  200. {
  201. Dst_Addr*=FLASH_SECTOR_SIZE;
  202. SPI_FLASH_Write_Enable(); //SET WEL
  203. SPI_Flash_Wait_Busy();
  204. SPI_FLASH_CS=0; //使能器件
  205. SPIx_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
  206. SPIx_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址
  207. SPIx_ReadWriteByte((u8)((Dst_Addr)>>8));
  208. SPIx_ReadWriteByte((u8)Dst_Addr);
  209. SPI_FLASH_CS=1; //取消片选
  210. SPI_Flash_Wait_Busy(); //等待擦除完成
  211. }
  212. //等待空闲
  213. void SPI_Flash_Wait_Busy(void)
  214. {
  215. while ((SPI_Flash_ReadSR()&0x01)==0x01); // 等待BUSY位清空
  216. }
  217. //进入掉电模式
  218. void SPI_Flash_PowerDown(void)
  219. {
  220. SPI_FLASH_CS=0; //使能器件
  221. SPIx_ReadWriteByte(W25X_PowerDown); //发送掉电命令
  222. SPI_FLASH_CS=1; //取消片选
  223. delay_us(3); //等待TPD
  224. }
  225. //唤醒
  226. void SPI_Flash_WAKEUP(void)
  227. {
  228. SPI_FLASH_CS=0; //使能器件
  229. SPIx_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
  230. SPI_FLASH_CS=1; //取消片选
  231. delay_us(3); //等待TRES1
  232. }
  233. //Sector Read
  234. void W25X_Read_Sector(uint32_t nSector, u8* pBuffer)
  235. {
  236. uint16_t i;
  237. //扇区号转为地址
  238. nSector *= FLASH_SECTOR_SIZE;
  239. SPI_FLASH_CS=0;
  240. SPIx_ReadWriteByte(W25X_ReadData);
  241. SPIx_ReadWriteByte(((nSector & 0xFFFFFF) >> 16));
  242. SPIx_ReadWriteByte(((nSector & 0xFFFF) >> 8));
  243. SPIx_ReadWriteByte(nSector & 0xFF);
  244. for(i=0;i<FLASH_SECTOR_SIZE;i++)
  245. {
  246. pBuffer[i] = SPIx_ReadWriteByte(0xFF);
  247. }
  248. SPI_FLASH_CS=1;
  249. SPI_Flash_Wait_Busy();
  250. }
  251. //Sector Write
  252. void W25X_Write_Sector(uint32_t nSector, u8* pBuffer)
  253. {
  254. int i,j;
  255. //扇区号转为地址
  256. nSector *= FLASH_SECTOR_SIZE;
  257. //一个扇区需要几个页
  258. for(j=0;j<FLASH_PAGES_PER_SECTOR;j++)
  259. {
  260. SPI_FLASH_Write_Enable(); //SET WEL
  261. SPI_FLASH_CS=0;
  262. SPIx_ReadWriteByte(W25X_PageProgram);
  263. SPIx_ReadWriteByte(((nSector & 0xFFFFFF) >> 16));
  264. SPIx_ReadWriteByte(((nSector & 0xFFFF) >> 8));
  265. SPIx_ReadWriteByte(nSector & 0xFF);
  266. for(i=0;i<FLASH_PAGE_SIZE;i++)
  267. SPIx_ReadWriteByte(pBuffer[i]);
  268. pBuffer += FLASH_PAGE_SIZE;
  269. nSector += FLASH_PAGE_SIZE;
  270. SPI_FLASH_CS=1;
  271. SPI_Flash_Wait_Busy();
  272. }
  273. }