obj_hal_w25qxx.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #include "obj_hal_w25qxx.h"
  2. #ifdef USE_OBJ_HAL_W25QXX
  3. #include <stdint.h>
  4. #include <stdbool.h>
  5. #include "main.h"
  6. #include "sys_delay.h"
  7. #include "dev_spi_w25qxx.h"
  8. #if 0
  9. #define W25QXX_CS_GPIO GPIOD //GPIOB
  10. #define W25QXX_CS_PIN GPIO_PIN_8 //GPIO_PIN_8
  11. #else
  12. #define W25QXX_CS_GPIO GPIOB
  13. #define W25QXX_CS_PIN GPIO_PIN_12
  14. #endif
  15. extern void delay_us(uint32_t us);
  16. w25qxx_object_t w25qxx_obj =
  17. {
  18. .W25Q_TYPE = W25Q256, //默认是W25Q256
  19. .W25Q_OK = false,
  20. };
  21. void W25QXX_Init_info(void);
  22. //4Kbytes为一个Sector
  23. //16个扇区为1个Block
  24. //W25Q256
  25. //容量为32M字节,共有512个Block,8192个Sector
  26. void W25QXX_CS_HIGH(void)
  27. {
  28. if(WATCH_DOG_ON)
  29. {
  30. HAL_GPIO_TogglePin(GPIOC, DWI_Pin); //看门狗sp706
  31. }
  32. HAL_GPIO_WritePin(W25QXX_CS_GPIO, W25QXX_CS_PIN, GPIO_PIN_SET);
  33. //delay_us(1);
  34. }
  35. void W25QXX_CS_LOW(void)
  36. {
  37. if(WATCH_DOG_ON)
  38. {
  39. HAL_GPIO_TogglePin(GPIOC, DWI_Pin); //看门狗sp706
  40. }
  41. HAL_GPIO_WritePin(W25QXX_CS_GPIO, W25QXX_CS_PIN, GPIO_PIN_RESET);
  42. //delay_us(1);
  43. }
  44. void W25QXX_CS_INIT(void)
  45. {
  46. __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
  47. GPIO_InitTypeDef GPIO_Initure;
  48. //PD8
  49. GPIO_Initure.Pin=W25QXX_CS_PIN; //PD8
  50. GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
  51. GPIO_Initure.Pull=GPIO_PULLUP; //上拉
  52. GPIO_Initure.Speed=GPIO_SPEED_HIGH; //快速
  53. HAL_GPIO_Init(W25QXX_CS_GPIO,&GPIO_Initure); //初始化
  54. }
  55. //初始化SPI FLASH的IO口
  56. void W25QXX_Init(void)
  57. {
  58. uint8_t temp;
  59. W25QXX_CS_INIT();
  60. W25QXX_CS_HIGH(); //SPI FLASH不选中
  61. SPI_W25Q_Init(); //初始化SPI
  62. SPI_W25Q_SetSpeed(SPI_BAUDRATEPRESCALER_256); //设置为45M时钟,高速模式
  63. w25qxx_obj.W25Q_TYPE=W25QXX_ReadID(); //读取FLASH ID.
  64. if(w25qxx_obj.W25Q_TYPE>=W25Q256) //SPI FLASH为W25Q256
  65. {
  66. temp=W25QXX_ReadSR(3); //读取状态寄存器3,判断地址模式
  67. if((temp&0X01)==0) //如果不是4字节地址模式,则进入4字节地址模式
  68. {
  69. W25QXX_CS_LOW(); //选中
  70. SPI_W25Q_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令
  71. W25QXX_CS_HIGH(); //取消片选
  72. }
  73. }
  74. W25QXX_Init_info();
  75. W25QXX_ID_OK();
  76. }
  77. void W25QXX_Init_info(void)
  78. {
  79. switch(w25qxx_obj.W25Q_TYPE&0x0000FFFF)
  80. {
  81. case W25Q512: // w25q512
  82. w25qxx_obj.BlockCount=1024;
  83. #if (_W25QXX_DEBUG==1)
  84. printf("w25qxx Chip: w25q512\r\n");
  85. #endif
  86. break;
  87. case W25Q256: // w25q256
  88. w25qxx_obj.BlockCount=512;
  89. #if (_W25QXX_DEBUG==1)
  90. printf("w25qxx Chip: w25q256\r\n");
  91. #endif
  92. break;
  93. case W25Q128: // w25q128
  94. w25qxx_obj.BlockCount=256;
  95. #if (_W25QXX_DEBUG==1)
  96. printf("w25qxx Chip: w25q128\r\n");
  97. #endif
  98. break;
  99. case W25Q64: // w25q64
  100. w25qxx_obj.BlockCount=128;
  101. #if (_W25QXX_DEBUG==1)
  102. printf("w25qxx Chip: w25q64\r\n");
  103. #endif
  104. break;
  105. case W25Q32: // w25q32
  106. w25qxx_obj.BlockCount=64;
  107. #if (_W25QXX_DEBUG==1)
  108. printf("w25qxx Chip: w25q32\r\n");
  109. #endif
  110. break;
  111. case W25Q16: // w25q16
  112. w25qxx_obj.BlockCount=32;
  113. #if (_W25QXX_DEBUG==1)
  114. printf("w25qxx Chip: w25q16\r\n");
  115. #endif
  116. break;
  117. case W25Q80: // w25q80
  118. w25qxx_obj.BlockCount=16;
  119. #if (_W25QXX_DEBUG==1)
  120. printf("w25qxx Chip: w25q80\r\n");
  121. #endif
  122. break;
  123. case W25Q40: // w25q40
  124. w25qxx_obj.BlockCount=8;
  125. #if (_W25QXX_DEBUG==1)
  126. printf("w25qxx Chip: w25q40\r\n");
  127. #endif
  128. break;
  129. case W25Q20: // w25q20
  130. w25qxx_obj.BlockCount=4;
  131. #if (_W25QXX_DEBUG==1)
  132. printf("w25qxx Chip: w25q20\r\n");
  133. #endif
  134. break;
  135. case W25Q10: // w25q10
  136. w25qxx_obj.BlockCount=2;
  137. #if (_W25QXX_DEBUG==1)
  138. printf("w25qxx Chip: w25q10\r\n");
  139. #endif
  140. break;
  141. default:
  142. w25qxx_obj.BlockCount=0;
  143. #if (_W25QXX_DEBUG==1)
  144. printf("w25qxx Unknown ID\r\n");
  145. #endif
  146. break;
  147. }
  148. w25qxx_obj.PageSize=256;
  149. w25qxx_obj.SectorSize=0x1000;
  150. w25qxx_obj.SectorCount=w25qxx_obj.BlockCount*16;
  151. w25qxx_obj.PageCount=(w25qxx_obj.SectorCount*w25qxx_obj.SectorSize)/w25qxx_obj.PageSize;
  152. w25qxx_obj.BlockSize=w25qxx_obj.SectorSize*16;
  153. w25qxx_obj.CapacityInKiloByte=(w25qxx_obj.SectorCount*w25qxx_obj.SectorSize)/1024;
  154. return;
  155. }
  156. uint16_t W25QXX_ID_OK(void)
  157. {
  158. w25qxx_obj.W25Q_TYPE=W25QXX_ReadID();
  159. if((w25qxx_obj.W25Q_TYPE<=W25Q512)&&(w25qxx_obj.W25Q_TYPE>=W25Q16))
  160. {
  161. w25qxx_obj.W25Q_OK = true;
  162. }
  163. else
  164. {
  165. w25qxx_obj.W25Q_OK = false;
  166. }
  167. return w25qxx_obj.W25Q_OK;
  168. }
  169. //读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器
  170. //状态寄存器1:
  171. //BIT7 6 5 4 3 2 1 0
  172. //SPR RV TB BP2 BP1 BP0 WEL BUSY
  173. //SPR:默认0,状态寄存器保护位,配合WP使用
  174. //TB,BP2,BP1,BP0:FLASH区域写保护设置
  175. //WEL:写使能锁定
  176. //BUSY:忙标记位(1,忙;0,空闲)
  177. //默认:0x00
  178. //状态寄存器2:
  179. //BIT7 6 5 4 3 2 1 0
  180. //SUS CMP LB3 LB2 LB1 (R) QE SRP1
  181. //状态寄存器3:
  182. //BIT7 6 5 4 3 2 1 0
  183. //HOLD/RST DRV1 DRV0 (R) (R) WPS ADP ADS
  184. //regno:状态寄存器号,范:1~3
  185. //返回值:状态寄存器值
  186. uint8_t W25QXX_ReadSR(uint8_t regno)
  187. {
  188. uint8_t byte=0,command=0;
  189. switch(regno)
  190. {
  191. case 1:
  192. command=W25X_ReadStatusReg1; //读状态寄存器1指令
  193. break;
  194. case 2:
  195. command=W25X_ReadStatusReg2; //读状态寄存器2指令
  196. break;
  197. case 3:
  198. command=W25X_ReadStatusReg3; //读状态寄存器3指令
  199. break;
  200. default:
  201. regno = 1;
  202. command=W25X_ReadStatusReg1;
  203. break;
  204. }
  205. W25QXX_CS_LOW(); //使能器件
  206. SPI_W25Q_ReadWriteByte(command); //发送读取状态寄存器命令
  207. byte=SPI_W25Q_ReadWriteByte(0Xff); //读取一个字节
  208. W25QXX_CS_HIGH(); //取消片选
  209. if((regno > 0)&&(regno <= 3))
  210. {
  211. w25qxx_obj.StatusRegister[regno-1] = byte;
  212. }
  213. return byte;
  214. }
  215. //写W25QXX状态寄存器
  216. void W25QXX_Write_SR(uint8_t regno,uint8_t sr)
  217. {
  218. uint8_t command=0;
  219. switch(regno)
  220. {
  221. case 1:
  222. command=W25X_WriteStatusReg1; //写状态寄存器1指令
  223. break;
  224. case 2:
  225. command=W25X_WriteStatusReg2; //写状态寄存器2指令
  226. break;
  227. case 3:
  228. command=W25X_WriteStatusReg3; //写状态寄存器3指令
  229. break;
  230. default:
  231. command=W25X_WriteStatusReg1;
  232. break;
  233. }
  234. W25QXX_CS_LOW(); //使能器件
  235. SPI_W25Q_ReadWriteByte(command); //发送写取状态寄存器命令
  236. SPI_W25Q_ReadWriteByte(sr); //写入一个字节
  237. W25QXX_CS_HIGH(); //取消片选
  238. }
  239. //W25QXX写使能
  240. //将WEL置位
  241. void W25QXX_Write_Enable(void)
  242. {
  243. W25QXX_CS_LOW(); //使能器件
  244. SPI_W25Q_ReadWriteByte(W25X_WriteEnable); //发送写使能
  245. W25QXX_CS_HIGH(); //取消片选
  246. }
  247. //W25QXX写禁止
  248. //将WEL清零
  249. void W25QXX_Write_Disable(void)
  250. {
  251. W25QXX_CS_LOW(); //使能器件
  252. SPI_W25Q_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
  253. W25QXX_CS_HIGH(); //取消片选
  254. }
  255. //读取芯片ID
  256. //返回值如下:
  257. //0XEF13,表示芯片型号为W25Q80
  258. //0XEF14,表示芯片型号为W25Q16
  259. //0XEF15,表示芯片型号为W25Q32
  260. //0XEF16,表示芯片型号为W25Q64
  261. //0XEF17,表示芯片型号为W25Q128
  262. //0XEF18,表示芯片型号为W25Q256
  263. uint16_t W25QXX_ReadID(void)
  264. {
  265. uint16_t Temp = 0;
  266. W25QXX_CS_LOW();
  267. SPI_W25Q_ReadWriteByte(0x90);//发送读取ID命令
  268. SPI_W25Q_ReadWriteByte(0x00);
  269. SPI_W25Q_ReadWriteByte(0x00);
  270. SPI_W25Q_ReadWriteByte(0x00);
  271. Temp|=SPI_W25Q_ReadWriteByte(0xFF)<<8;
  272. Temp|=SPI_W25Q_ReadWriteByte(0xFF);
  273. W25QXX_CS_HIGH();
  274. return Temp;
  275. }
  276. //读取SPI FLASH
  277. //在指定地址开始读取指定长度的数据
  278. //pBuffer:数据存储区
  279. //ReadAddr:开始读取的地址(24bit)
  280. //NumByteToRead:要读取的字节数(最大65535)
  281. void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
  282. {
  283. uint16_t i;
  284. W25QXX_CS_LOW(); //使能器件
  285. SPI_W25Q_ReadWriteByte(W25X_ReadData); //发送读取命令
  286. if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位
  287. {
  288. SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>24));
  289. }
  290. SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址
  291. SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>8));
  292. SPI_W25Q_ReadWriteByte((uint8_t)ReadAddr);
  293. for(i=0;i<NumByteToRead;i++)
  294. {
  295. pBuffer[i]=SPI_W25Q_ReadWriteByte(0XFF); //循环读数
  296. }
  297. W25QXX_CS_HIGH();
  298. }
  299. //SPI在一页(0~65535)内写入少于256个字节的数据
  300. //在指定地址开始写入最大256字节的数据
  301. //pBuffer:数据存储区
  302. //WriteAddr:开始写入的地址(24bit)
  303. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
  304. void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
  305. {
  306. uint16_t i;
  307. W25QXX_Write_Enable(); //SET WEL
  308. W25QXX_CS_LOW(); //使能器件
  309. SPI_W25Q_ReadWriteByte(W25X_PageProgram); //发送写页命令
  310. if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位
  311. {
  312. SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>24));
  313. }
  314. SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址
  315. SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>8));
  316. SPI_W25Q_ReadWriteByte((uint8_t)WriteAddr);
  317. for(i=0;i<NumByteToWrite;i++)SPI_W25Q_ReadWriteByte(pBuffer[i]);//循环写数
  318. W25QXX_CS_HIGH(); //取消片选
  319. W25QXX_Wait_Busy(); //等待写入结束
  320. }
  321. //无检验写SPI FLASH
  322. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
  323. //具有自动换页功能
  324. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
  325. //pBuffer:数据存储区
  326. //WriteAddr:开始写入的地址(24bit)
  327. //NumByteToWrite:要写入的字节数(最大65535)
  328. //CHECK OK
  329. void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
  330. {
  331. uint16_t pageremain;
  332. pageremain=256-WriteAddr%256; //单页剩余的字节数
  333. if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
  334. while(1)
  335. {
  336. W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
  337. if(NumByteToWrite==pageremain)break;//写入结束了
  338. else //NumByteToWrite>pageremain
  339. {
  340. pBuffer+=pageremain;
  341. WriteAddr+=pageremain;
  342. NumByteToWrite-=pageremain; //减去已经写入了的字节数
  343. if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
  344. else pageremain=NumByteToWrite; //不够256个字节了
  345. }
  346. };
  347. }
  348. //写SPI FLASH
  349. //在指定地址开始写入指定长度的数据
  350. //该函数带擦除操作!
  351. //pBuffer:数据存储区
  352. //WriteAddr:开始写入的地址(24bit)
  353. //NumByteToWrite:要写入的字节数(最大65535)
  354. uint8_t W25QXX_BUFFER[4096];
  355. void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
  356. {
  357. uint32_t secpos;
  358. uint16_t secoff;
  359. uint16_t secremain;
  360. uint16_t i;
  361. uint8_t * W25QXX_BUF;
  362. W25QXX_BUF=W25QXX_BUFFER;
  363. secpos=WriteAddr/4096;//扇区地址
  364. secoff=WriteAddr%4096;//在扇区内的偏移
  365. secremain=4096-secoff;//扇区剩余空间大小
  366. //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
  367. if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
  368. while(1)
  369. {
  370. W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
  371. for(i=0;i<secremain;i++)//校验数据
  372. {
  373. if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除
  374. }
  375. if(i<secremain)//需要擦除
  376. {
  377. W25QXX_Erase_Sector(secpos);//擦除这个扇区
  378. for(i=0;i<secremain;i++) //复制
  379. {
  380. W25QXX_BUF[i+secoff]=pBuffer[i];
  381. }
  382. W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区
  383. }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
  384. if(NumByteToWrite==secremain)break;//写入结束了
  385. else//写入未结束
  386. {
  387. secpos++;//扇区地址增1
  388. secoff=0;//偏移位置为0
  389. pBuffer+=secremain; //指针偏移
  390. WriteAddr+=secremain;//写地址偏移
  391. NumByteToWrite-=secremain; //字节数递减
  392. if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完
  393. else secremain=NumByteToWrite; //下一个扇区可以写完了
  394. }
  395. };
  396. }
  397. //擦除整个芯片
  398. //等待时间超长...
  399. void W25QXX_Erase_Chip(void)
  400. {
  401. W25QXX_Write_Enable(); //SET WEL
  402. W25QXX_Wait_Busy();
  403. W25QXX_CS_LOW(); //使能器件
  404. SPI_W25Q_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
  405. W25QXX_CS_HIGH(); //取消片选
  406. W25QXX_Wait_Busy(); //等待芯片擦除结束
  407. }
  408. //擦除一个扇区
  409. //Dst_Addr:扇区地址 根据实际容量设置
  410. //擦除一个扇区的最少时间:150ms
  411. void W25QXX_Erase_Sector(uint32_t Dst_Addr)
  412. {
  413. //监视falsh擦除情况,测试用
  414. //printf("fe:%x\r\n",Dst_Addr);
  415. Dst_Addr*=4096;
  416. W25QXX_Write_Enable(); //SET WEL
  417. W25QXX_Wait_Busy();
  418. W25QXX_CS_LOW(); //使能器件
  419. SPI_W25Q_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令
  420. if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位
  421. {
  422. SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>24));
  423. }
  424. SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>16)); //发送24bit地址
  425. SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>8));
  426. SPI_W25Q_ReadWriteByte((uint8_t)Dst_Addr);
  427. W25QXX_CS_HIGH(); //取消片选
  428. W25QXX_Wait_Busy(); //等待擦除完成
  429. }
  430. //等待空闲
  431. void W25QXX_Wait_Busy(void)
  432. {
  433. while((W25QXX_ReadSR(1)&0x01)==0x01); // 等待BUSY位清空
  434. }
  435. //进入掉电模式
  436. void W25QXX_PowerDown(void)
  437. {
  438. W25QXX_CS_LOW(); //使能器件
  439. SPI_W25Q_ReadWriteByte(W25X_PowerDown); //发送掉电命令
  440. W25QXX_CS_HIGH(); //取消片选
  441. delay_us(3); //等待TPD
  442. }
  443. //唤醒
  444. void W25QXX_WAKEUP(void)
  445. {
  446. W25QXX_CS_LOW(); //使能器件
  447. SPI_W25Q_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
  448. W25QXX_CS_HIGH(); //取消片选
  449. delay_us(3); //等待TRES1
  450. }
  451. #endif //--------------------USE_OBJ_HAL_W25QXX-------------------//