w25qxx.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. #include "includes.h"
  2. #include "trace.h"
  3. #include "w25qxx.h"
  4. //w25Q128
  5. static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
  6. /*
  7. 容量 16页/扇区 128页/半块(32kB) 256页/块(64kB)
  8. w25q16 16M-bit 2MByte 8192编程页/256B 512扇区 64半块 32块
  9. */
  10. static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
  11. /**
  12. * @brief SPII/O配置
  13. * @param 无
  14. * @retval 无
  15. */
  16. static void SPI_GPIO_Config(void)
  17. {
  18. GPIO_InitTypeDef GPIO_InitStructure;
  19. /* 使能与SPI 有关的时钟 */
  20. FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
  21. FLASH_SPI_GPIO_APBxClock_FUN ( FLASH_SPI_GPIO_CLK, ENABLE );
  22. /* MISO MOSI SCK*/
  23. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
  24. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  25. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  26. GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
  27. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
  28. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  29. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  30. GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
  31. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
  32. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  33. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  34. GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
  35. //初始化CS引脚,使用软件控制,所以直接设置成推挽输出
  36. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
  37. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  38. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  39. GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
  40. FLASH_SPI_CS_HIGH;
  41. }
  42. /**
  43. * @brief SPI 工作模式配置
  44. * @param 无
  45. * @retval 无
  46. */
  47. static void SPI_Mode_Config(void)
  48. {
  49. SPI_InitTypeDef SPI_InitStructure;
  50. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ;
  51. //SPI 使用模式3
  52. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge ;
  53. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High ;
  54. SPI_InitStructure.SPI_CRCPolynomial = 0;//不使用CRC功能,数值随便写
  55. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  56. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;//双线全双工
  57. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;
  58. SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
  59. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;
  60. SPI_Init(FLASH_SPIx,&SPI_InitStructure); //写入配置到寄存器
  61. SPI_Cmd(FLASH_SPIx,ENABLE);//使能SPI
  62. }
  63. /**
  64. * @brief SPI 初始化
  65. * @param 无
  66. * @retval 无
  67. */
  68. void SPI_USER_Init(void)
  69. {
  70. SPI_GPIO_Config();
  71. SPI_Mode_Config();
  72. }
  73. //发送并接收一个字节
  74. uint8_t SPI_USER_Send_Byte(uint8_t data)
  75. {
  76. SPITimeout = SPIT_FLAG_TIMEOUT;
  77. //检查并等待至TX缓冲区为空
  78. while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_TXE) == RESET)
  79. {
  80. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
  81. }
  82. //程序执行到此处,TX缓冲区已空
  83. SPI_I2S_SendData (FLASH_SPIx,data);
  84. SPITimeout = SPIT_FLAG_TIMEOUT;
  85. //检查并等待至RX缓冲区为非空
  86. while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_RXNE) == RESET)
  87. {
  88. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
  89. }
  90. //程序执行到此处,说明数据发送完毕,并接收到一字字节
  91. return SPI_I2S_ReceiveData(FLASH_SPIx);
  92. }
  93. uint8_t SPI_USER_Read_Byte(void)
  94. {
  95. return SPI_USER_Send_Byte(DUMMY);
  96. }
  97. //读取ID号
  98. uint32_t SPI_FLASH_Read_ID(void)
  99. {
  100. uint32_t flash_id;
  101. //片选使能
  102. FLASH_SPI_CS_LOW;
  103. SPI_USER_Send_Byte(READ_JEDEC_ID);
  104. flash_id = SPI_USER_Send_Byte(DUMMY);
  105. flash_id <<= 8;
  106. flash_id |= SPI_USER_Send_Byte(DUMMY);
  107. flash_id <<= 8;
  108. flash_id |= SPI_USER_Send_Byte(DUMMY);
  109. FLASH_SPI_CS_HIGH;
  110. return flash_id;
  111. }
  112. //FLASH写入使能
  113. void SPI_FLASH_Write_Enable(void)
  114. {
  115. //片选使能
  116. FLASH_SPI_CS_LOW;
  117. SPI_USER_Send_Byte(WRITE_ENABLE);
  118. FLASH_SPI_CS_HIGH;
  119. }
  120. //擦除FLASH指定扇区
  121. void SPI_FLASH_Erase_Sector(uint32_t addr)
  122. {
  123. SPI_FLASH_Write_Enable();
  124. //片选使能
  125. FLASH_SPI_CS_LOW;
  126. SPI_USER_Send_Byte(ERASE_SECTOR);
  127. SPI_USER_Send_Byte((addr>>16)&0xff);
  128. SPI_USER_Send_Byte((addr>>8)&0xff);
  129. SPI_USER_Send_Byte(addr&0xff);
  130. FLASH_SPI_CS_HIGH;
  131. SPI_FLASH_WaitForWriteEnd();
  132. }
  133. //读取FLASH的内容
  134. void SPI_FLASH_Read_Data(uint32_t addr,uint8_t *readBuff,uint32_t numByteToRead)
  135. {
  136. //片选使能
  137. FLASH_SPI_CS_LOW;
  138. SPI_USER_Send_Byte(READ_DATA);
  139. SPI_USER_Send_Byte((addr>>16)&0xff);
  140. SPI_USER_Send_Byte((addr>>8)&0xff);
  141. SPI_USER_Send_Byte(addr&0xff);
  142. while(numByteToRead--)
  143. {
  144. *readBuff = SPI_USER_Send_Byte(DUMMY);
  145. readBuff++;
  146. }
  147. FLASH_SPI_CS_HIGH;
  148. }
  149. //向FLASH写入内容
  150. void SPI_FLASH_Write_Data(uint32_t addr,uint8_t *writeBuff,uint32_t numByteToWrite)
  151. {
  152. SPI_FLASH_Write_Enable();
  153. //片选使能
  154. FLASH_SPI_CS_LOW;
  155. SPI_USER_Send_Byte(WRITE_DATA);
  156. SPI_USER_Send_Byte((addr>>16)&0xff);
  157. SPI_USER_Send_Byte((addr>>8)&0xff);
  158. SPI_USER_Send_Byte(addr&0xff);
  159. while(numByteToWrite--)
  160. {
  161. SPI_USER_Send_Byte(*writeBuff);
  162. writeBuff++;
  163. }
  164. FLASH_SPI_CS_HIGH;
  165. SPI_FLASH_WaitForWriteEnd();
  166. }
  167. //连续写入多字节:不用考虑是否达到边界的问题,写入字节数也没有限制(当然要小于FLASH容量)
  168. void SPI_FLASH_Write_Datas(uint32_t addr,uint8_t *writeBuff,uint32_t numByteToWrite)
  169. {
  170. uint32_t page_offset = 0; //距离下一个页地址边界的偏移(距离)
  171. uint32_t write_len = 0; //每次要写入的字节数量
  172. int page_size = 256; //页大小
  173. SPI_FLASH_Write_Enable();
  174. //片选使能
  175. FLASH_SPI_CS_LOW;
  176. while(numByteToWrite > 0)
  177. {
  178. page_offset = page_size - (numByteToWrite % page_size); //计算页偏移
  179. write_len = numByteToWrite>page_offset ? page_offset : numByteToWrite; //选择较小的作为本次写入的数据字节长度
  180. SPI_FLASH_Write_Data( addr,writeBuff,write_len);
  181. //if(numByteToWrite)
  182. //改变相应参数
  183. numByteToWrite = numByteToWrite - write_len; //减少写入数量
  184. writeBuff = writeBuff + write_len; //增加写入缓冲地址
  185. addr = addr+write_len; //增加FLASH写入的地址
  186. }
  187. FLASH_SPI_CS_HIGH;
  188. }
  189. //等待FLASH内部时序操作完成
  190. void SPI_FLASH_WaitForWriteEnd(void)
  191. {
  192. uint8_t status_reg = 0;
  193. //片选使能
  194. FLASH_SPI_CS_LOW;
  195. SPI_USER_Send_Byte(READ_STATUS);
  196. do
  197. {
  198. status_reg = SPI_USER_Send_Byte(DUMMY);
  199. }
  200. while((status_reg & 0x01) == 1);
  201. FLASH_SPI_CS_HIGH;
  202. }
  203. /**
  204. * @brief Basic management of the timeout situation.
  205. * @param errorCode:错误代码,可以用来定位是哪个环节出错.
  206. * @retval 返回0,表示SPI读取失败.
  207. */
  208. static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
  209. {
  210. /* Block communication and all processes */
  211. FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  212. return 0;
  213. }
  214. static u8 Spi_Buf_Write[256], Spi_Buf_Read[256];
  215. uint8_t SPI_FLASH_Test(void)
  216. {
  217. u16 i;
  218. u32 id;
  219. SPI_USER_Init();
  220. id = SPI_FLASH_Read_ID();
  221. memset(Spi_Buf_Write, 0, 256);
  222. for ( i=0; i<=255; i++ ) {//填充缓冲
  223. Spi_Buf_Write[i] = i+50;
  224. }
  225. data_dump("Flash Write", Spi_Buf_Write, sizeof(Spi_Buf_Write));
  226. SPI_FLASH_Erase_Sector(0);
  227. //字节写入方式
  228. SPI_FLASH_Write_Data(0, Spi_Buf_Write, 128);
  229. //将 EEPROM 读出数据顺序保持到 I2c_Buf_Read 中
  230. memset(Spi_Buf_Read, 0, 256);
  231. SPI_FLASH_Read_Data(0, Spi_Buf_Read, 128);
  232. //将 I2c_Buf_Read 中的数据通过串口打印
  233. data_dump("Flash Read", Spi_Buf_Read, sizeof(Spi_Buf_Read));
  234. printf("\r\nSPI(W25qxx, id = %d)rw success\r\n", id);
  235. return 1;
  236. }