SPI 初始化结构体

  1. typedef struct
  2. {
  3. uint16_t SPI_Direction; /*设置 SPI 的单双向模式 */
  4. uint16_t SPI_Mode; /*设置 SPI 的主/从机端模式 */
  5. uint16_t SPI_DataSize; /*设置 SPI 的数据帧长度,可选 8/16 位 */
  6. uint16_t SPI_CPOL; /*设置时钟极性 CPOL,可选高/低电平*/
  7. uint16_t SPI_CPHA; /*设置时钟相位,可选奇/偶数边沿采样 */
  8. uint16_t SPI_NSS; /*设置 NSS 引脚由 SPI 硬件控制还是软件控制*/
  9. uint16_t SPI_BaudRatePrescaler; /*设置时钟分频因子, fpclk/分频数=fSCK */
  10. uint16_t SPI_FirstBit; /*设置 MSB/LSB 先行 */
  11. uint16_t SPI_CRCPolynomial; /*设置 CRC 校验的表达式 */
  12. } SPI_InitTypeDef;

SPI读写FLASH实例

bsp_spi_flash.h

  1. #ifndef __SPI_FLASH_H
  2. #define __SPI_FLASH_H
  3. #include "stm32f10x.h"
  4. #include <stdio.h>
  5. //#define sFLASH_ID 0xEF3015 //W25X16
  6. //#define sFLASH_ID 0xEF4015 //W25Q16
  7. //#define sFLASH_ID 0XEF4018 //W25Q128
  8. #define sFLASH_ID 0XEF4017 //W25Q64
  9. #define SPI_FLASH_PageSize 256
  10. #define SPI_FLASH_PerWritePageSize 256
  11. /*命令定义-开头*******************************/
  12. #define W25X_WriteEnable 0x06
  13. #define W25X_WriteDisable 0x04
  14. #define W25X_ReadStatusReg 0x05
  15. #define W25X_WriteStatusReg 0x01
  16. #define W25X_ReadData 0x03
  17. #define W25X_FastReadData 0x0B
  18. #define W25X_FastReadDual 0x3B
  19. #define W25X_PageProgram 0x02
  20. #define W25X_BlockErase 0xD8
  21. #define W25X_SectorErase 0x20
  22. #define W25X_ChipErase 0xC7
  23. #define W25X_PowerDown 0xB9
  24. #define W25X_ReleasePowerDown 0xAB
  25. #define W25X_DeviceID 0xAB
  26. #define W25X_ManufactDeviceID 0x90
  27. #define W25X_JedecDeviceID 0x9F
  28. /* WIP(busy)标志,FLASH内部正在写入 */
  29. #define WIP_Flag 0x01
  30. #define Dummy_Byte 0xFF
  31. /*命令定义-结尾*******************************/
  32. /*SPI接口定义-开头****************************/
  33. #define FLASH_SPIx SPI1
  34. #define FLASH_SPI_APBxClock_FUN RCC_APB2PeriphClockCmd
  35. #define FLASH_SPI_CLK RCC_APB2Periph_SPI1
  36. //CS(NSS)引脚 片选选普通GPIO即可
  37. #define FLASH_SPI_CS_APBxClock_FUN RCC_APB2PeriphClockCmd
  38. #define FLASH_SPI_CS_CLK RCC_APB2Periph_GPIOA
  39. #define FLASH_SPI_CS_PORT GPIOA
  40. #define FLASH_SPI_CS_PIN GPIO_Pin_4
  41. //SCK引脚
  42. #define FLASH_SPI_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
  43. #define FLASH_SPI_SCK_CLK RCC_APB2Periph_GPIOA
  44. #define FLASH_SPI_SCK_PORT GPIOA
  45. #define FLASH_SPI_SCK_PIN GPIO_Pin_5
  46. //MISO引脚
  47. #define FLASH_SPI_MISO_APBxClock_FUN RCC_APB2PeriphClockCmd
  48. #define FLASH_SPI_MISO_CLK RCC_APB2Periph_GPIOA
  49. #define FLASH_SPI_MISO_PORT GPIOA
  50. #define FLASH_SPI_MISO_PIN GPIO_Pin_6
  51. //MOSI引脚
  52. #define FLASH_SPI_MOSI_APBxClock_FUN RCC_APB2PeriphClockCmd
  53. #define FLASH_SPI_MOSI_CLK RCC_APB2Periph_GPIOA
  54. #define FLASH_SPI_MOSI_PORT GPIOA
  55. #define FLASH_SPI_MOSI_PIN GPIO_Pin_7
  56. #define SPI_FLASH_CS_LOW() GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
  57. #define SPI_FLASH_CS_HIGH() GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
  58. /*SPI接口定义-结尾****************************/
  59. /*等待超时时间*/
  60. #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
  61. #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
  62. /*信息输出*/
  63. #define FLASH_DEBUG_ON 1
  64. #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
  65. #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
  66. #define FLASH_DEBUG(fmt,arg...) do{\
  67. if(FLASH_DEBUG_ON)\
  68. printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
  69. }while(0)
  70. void SPI_FLASH_Init(void);
  71. void SPI_FLASH_SectorErase(u32 SectorAddr);
  72. void SPI_FLASH_BulkErase(void);
  73. void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
  74. void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite);
  75. void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
  76. u32 SPI_FLASH_ReadID(void);
  77. u32 SPI_FLASH_ReadDeviceID(void);
  78. void SPI_FLASH_StartReadSequence(u32 ReadAddr);
  79. void SPI_Flash_PowerDown(void);
  80. void SPI_Flash_WAKEUP(void);
  81. u8 SPI_FLASH_ReadByte(void);
  82. u8 SPI_FLASH_SendByte(u8 byte);
  83. u16 SPI_FLASH_SendHalfWord(u16 HalfWord);
  84. void SPI_FLASH_WriteEnable(void);
  85. void SPI_FLASH_WaitForWriteEnd(void);
  86. #endif /* __SPI_FLASH_H */

bsp_spi_flash.c

  1. /**
  2. ******************************************************************************
  3. * @file bsp_xxx.c
  4. * @author STMicroelectronics
  5. * @version V1.0
  6. * @date 2013-xx-xx
  7. * @brief spi flash 底层应用函数bsp
  8. ******************************************************************************
  9. * @attention
  10. *
  11. * 实验平台:野火 F103-霸道 STM32 开发板
  12. * 论坛 :http://www.firebbs.cn
  13. * 淘宝 :https://fire-stm32.taobao.com
  14. *
  15. ******************************************************************************
  16. */
  17. #include "./flash/bsp_spi_flash.h"
  18. static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
  19. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
  20. /**
  21. * @brief SPI_FLASH初始化
  22. * @param 无
  23. * @retval 无
  24. */
  25. void SPI_FLASH_Init(void)
  26. {
  27. SPI_InitTypeDef SPI_InitStructure;
  28. GPIO_InitTypeDef GPIO_InitStructure;
  29. /* 使能SPI时钟 */
  30. FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );
  31. /* 使能SPI引脚相关的时钟 */ // cs sck miso mosi引脚都是在GPIOA上,所以只需使能1个就行
  32. FLASH_SPI_CS_APBxClock_FUN( FLASH_SPI_CS_CLK, ENABLE );
  33. //FLASH_SPI_CS_APBxClock_FUN( FLASH_SPI_CS_CLK | FLASH_SPI_SCK_CLK, ENABLE ); FLASH_SPI_MISO_PIN|FLASH_SPI_MOSI_PIN, ENABLE );
  34. /* 配置SPI的 CS引脚,普通IO即可 */
  35. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
  36. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  37. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  38. GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
  39. /* 配置SPI的 SCK引脚*/
  40. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
  41. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  42. GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
  43. /* 配置SPI的 MISO引脚*/
  44. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
  45. GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
  46. /* 配置SPI的 MOSI引脚*/
  47. GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
  48. GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
  49. /* 停止信号 FLASH: CS引脚高电平*/
  50. SPI_FLASH_CS_HIGH();
  51. /* SPI 模式配置 */
  52. // FLASH芯片 支持SPI模式0及模式3,据此设置CPOL CPHA
  53. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  54. SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  55. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  56. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  57. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  58. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  59. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  60. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  61. SPI_InitStructure.SPI_CRCPolynomial = 7;
  62. SPI_Init(FLASH_SPIx , &SPI_InitStructure);
  63. /* 使能 SPI */
  64. SPI_Cmd(FLASH_SPIx , ENABLE);
  65. }
  66. /**
  67. * @brief 擦除FLASH扇区
  68. * @param SectorAddr:要擦除的扇区地址
  69. * @retval 无
  70. */
  71. void SPI_FLASH_SectorErase(u32 SectorAddr)
  72. {
  73. /* 发送FLASH写使能命令 */
  74. SPI_FLASH_WriteEnable();
  75. SPI_FLASH_WaitForWriteEnd();
  76. /* 擦除扇区 */
  77. /* 选择FLASH: CS低电平 */
  78. SPI_FLASH_CS_LOW();
  79. /* 发送扇区擦除指令*/
  80. SPI_FLASH_SendByte(W25X_SectorErase);
  81. /*发送擦除扇区地址的高位*/
  82. SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
  83. /* 发送擦除扇区地址的中位 */
  84. SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
  85. /* 发送擦除扇区地址的低位 */
  86. SPI_FLASH_SendByte(SectorAddr & 0xFF);
  87. /* 停止信号 FLASH: CS 高电平 */
  88. SPI_FLASH_CS_HIGH();
  89. /* 等待擦除完毕*/
  90. SPI_FLASH_WaitForWriteEnd();
  91. }
  92. /**
  93. * @brief 擦除FLASH扇区,整片擦除
  94. * @param 无
  95. * @retval 无
  96. */
  97. void SPI_FLASH_BulkErase(void)
  98. {
  99. /* 发送FLASH写使能命令 */
  100. SPI_FLASH_WriteEnable();
  101. /* 整块 Erase */
  102. /* 选择FLASH: CS低电平 */
  103. SPI_FLASH_CS_LOW();
  104. /* 发送整块擦除指令*/
  105. SPI_FLASH_SendByte(W25X_ChipErase);
  106. /* 停止信号 FLASH: CS 高电平 */
  107. SPI_FLASH_CS_HIGH();
  108. /* 等待擦除完毕*/
  109. SPI_FLASH_WaitForWriteEnd();
  110. }
  111. /**
  112. * @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
  113. * @param pBuffer,要写入数据的指针
  114. * @param WriteAddr,写入地址
  115. * @param NumByteToWrite,写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
  116. * @retval 无
  117. */
  118. void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
  119. {
  120. /* 发送FLASH写使能命令 */
  121. SPI_FLASH_WriteEnable();
  122. /* 选择FLASH: CS低电平 */
  123. SPI_FLASH_CS_LOW();
  124. /* 写页写指令*/
  125. SPI_FLASH_SendByte(W25X_PageProgram);
  126. /*发送写地址的高位*/
  127. SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
  128. /*发送写地址的中位*/
  129. SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
  130. /*发送写地址的低位*/
  131. SPI_FLASH_SendByte(WriteAddr & 0xFF);
  132. if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
  133. {
  134. NumByteToWrite = SPI_FLASH_PerWritePageSize;
  135. FLASH_ERROR("SPI_FLASH_PageWrite too large!");
  136. }
  137. /* 写入数据*/
  138. while (NumByteToWrite--)
  139. {
  140. /* 发送当前要写入的字节数据 */
  141. SPI_FLASH_SendByte(*pBuffer);
  142. /* 指向下一字节数据 */
  143. pBuffer++;
  144. }
  145. /* 停止信号 FLASH: CS 高电平 */
  146. SPI_FLASH_CS_HIGH();
  147. /* 等待写入完毕*/
  148. SPI_FLASH_WaitForWriteEnd();
  149. }
  150. /**
  151. * @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
  152. * @param pBuffer,要写入数据的指针
  153. * @param WriteAddr,写入地址
  154. * @param NumByteToWrite,写入数据长度
  155. * @retval 无
  156. */
  157. void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
  158. {
  159. u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
  160. /*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
  161. Addr = WriteAddr % SPI_FLASH_PageSize;
  162. /*差count个数据值,刚好可以对齐到页地址*/
  163. count = SPI_FLASH_PageSize - Addr;
  164. /*计算出要写多少整数页*/
  165. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  166. /*mod运算求余,计算出剩余不满一页的字节数*/
  167. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  168. /* Addr=0,则WriteAddr 刚好按页对齐 aligned */
  169. if (Addr == 0)
  170. {
  171. /* NumByteToWrite < SPI_FLASH_PageSize */
  172. if (NumOfPage == 0)
  173. {
  174. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  175. }
  176. else /* NumByteToWrite > SPI_FLASH_PageSize */
  177. {
  178. /*先把整数页都写了*/
  179. while (NumOfPage--)
  180. {
  181. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  182. WriteAddr += SPI_FLASH_PageSize;
  183. pBuffer += SPI_FLASH_PageSize;
  184. }
  185. /*若有多余的不满一页的数据,把它写完*/
  186. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  187. }
  188. }
  189. /* 若地址与 SPI_FLASH_PageSize 不对齐 */
  190. else
  191. {
  192. /* NumByteToWrite < SPI_FLASH_PageSize */
  193. if (NumOfPage == 0)
  194. {
  195. /*当前页剩余的count个位置比NumOfSingle小,一页写不完*/
  196. if (NumOfSingle > count)
  197. {
  198. temp = NumOfSingle - count;
  199. /*先写满当前页*/
  200. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  201. WriteAddr += count;
  202. pBuffer += count;
  203. /*再写剩余的数据*/
  204. SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
  205. }
  206. else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
  207. {
  208. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  209. }
  210. }
  211. else /* NumByteToWrite > SPI_FLASH_PageSize */
  212. {
  213. /*地址不对齐多出的count分开处理,不加入这个运算*/
  214. NumByteToWrite -= count;
  215. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  216. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  217. /* 先写完count个数据,为的是让下一次要写的地址对齐 */
  218. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  219. /* 接下来就重复地址对齐的情况 */
  220. WriteAddr += count;
  221. pBuffer += count;
  222. /*把整数页都写了*/
  223. while (NumOfPage--)
  224. {
  225. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  226. WriteAddr += SPI_FLASH_PageSize;
  227. pBuffer += SPI_FLASH_PageSize;
  228. }
  229. /*若有多余的不满一页的数据,把它写完*/
  230. if (NumOfSingle != 0)
  231. {
  232. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  233. }
  234. }
  235. }
  236. }
  237. /**
  238. * @brief 读取FLASH数据
  239. * @param pBuffer,存储读出数据的指针
  240. * @param ReadAddr,读取地址
  241. * @param NumByteToRead,读取数据长度
  242. * @retval 无
  243. */
  244. void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
  245. {
  246. /* 选择FLASH: CS低电平 */
  247. SPI_FLASH_CS_LOW();
  248. /* 发送 读 指令 */
  249. SPI_FLASH_SendByte(W25X_ReadData);
  250. /* 发送 读 地址高位 */
  251. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  252. /* 发送 读 地址中位 */
  253. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  254. /* 发送 读 地址低位 */
  255. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  256. /* 读取数据 */
  257. while (NumByteToRead--) /* while there is data to be read */
  258. {
  259. /* 读取一个字节*/
  260. *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
  261. /* 指向下一个字节缓冲区 */
  262. pBuffer++;
  263. }
  264. /* 停止信号 FLASH: CS 高电平 */
  265. SPI_FLASH_CS_HIGH();
  266. }
  267. /**
  268. * @brief 读取FLASH ID
  269. * @param 无
  270. * @retval FLASH ID
  271. */
  272. u32 SPI_FLASH_ReadID(void)
  273. {
  274. u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
  275. /* 开始通讯:CS低电平 */
  276. SPI_FLASH_CS_LOW();
  277. /* 发送JEDEC指令,读取ID */
  278. SPI_FLASH_SendByte(W25X_JedecDeviceID);
  279. /* 读取一个字节数据 */
  280. Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
  281. /* 读取一个字节数据 */
  282. Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
  283. /* 读取一个字节数据 */
  284. Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
  285. /* 停止通讯:CS高电平 */
  286. SPI_FLASH_CS_HIGH();
  287. /*把数据组合起来,作为函数的返回值*/
  288. Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
  289. return Temp;
  290. }
  291. /**
  292. * @brief 读取FLASH Device ID
  293. * @param 无
  294. * @retval FLASH Device ID
  295. */
  296. u32 SPI_FLASH_ReadDeviceID(void)
  297. {
  298. u32 Temp = 0;
  299. /* Select the FLASH: Chip Select low */
  300. SPI_FLASH_CS_LOW();
  301. /* Send "RDID " instruction */
  302. SPI_FLASH_SendByte(W25X_DeviceID);
  303. SPI_FLASH_SendByte(Dummy_Byte);
  304. SPI_FLASH_SendByte(Dummy_Byte);
  305. SPI_FLASH_SendByte(Dummy_Byte);
  306. /* Read a byte from the FLASH */
  307. Temp = SPI_FLASH_SendByte(Dummy_Byte);
  308. /* Deselect the FLASH: Chip Select high */
  309. SPI_FLASH_CS_HIGH();
  310. return Temp;
  311. }
  312. /*******************************************************************************
  313. * Function Name : SPI_FLASH_StartReadSequence
  314. * Description : Initiates a read data byte (READ) sequence from the Flash.
  315. * This is done by driving the /CS line low to select the device,
  316. * then the READ instruction is transmitted followed by 3 bytes
  317. * address. This function exit and keep the /CS line low, so the
  318. * Flash still being selected. With this technique the whole
  319. * content of the Flash is read with a single READ instruction.
  320. * Input : - ReadAddr : FLASH's internal address to read from.
  321. * Output : None
  322. * Return : None
  323. *******************************************************************************/
  324. void SPI_FLASH_StartReadSequence(u32 ReadAddr)
  325. {
  326. /* Select the FLASH: Chip Select low */
  327. SPI_FLASH_CS_LOW();
  328. /* Send "Read from Memory " instruction */
  329. SPI_FLASH_SendByte(W25X_ReadData);
  330. /* Send the 24-bit address of the address to read from -----------------------*/
  331. /* Send ReadAddr high nibble address byte */
  332. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  333. /* Send ReadAddr medium nibble address byte */
  334. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  335. /* Send ReadAddr low nibble address byte */
  336. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  337. }
  338. /**
  339. * @brief 使用SPI读取一个字节的数据
  340. * @param 无
  341. * @retval 返回接收到的数据
  342. */
  343. u8 SPI_FLASH_ReadByte(void)
  344. {
  345. return (SPI_FLASH_SendByte(Dummy_Byte));
  346. }
  347. /**
  348. * @brief 使用SPI发送一个字节的数据
  349. * @param byte:要发送的数据
  350. * @retval 返回接收到的数据
  351. */
  352. u8 SPI_FLASH_SendByte(u8 byte)
  353. {
  354. SPITimeout = SPIT_FLAG_TIMEOUT;
  355. /* 等待发送缓冲区为空,TXE事件 */
  356. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
  357. {
  358. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
  359. }
  360. /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  361. SPI_I2S_SendData(FLASH_SPIx , byte);
  362. SPITimeout = SPIT_FLAG_TIMEOUT;
  363. /* 等待接收缓冲区非空,RXNE事件 */
  364. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
  365. {
  366. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
  367. }
  368. /* 读取数据寄存器,获取接收缓冲区数据 */
  369. return SPI_I2S_ReceiveData(FLASH_SPIx );
  370. }
  371. /**
  372. * @brief 使用SPI发送两个字节的数据
  373. * @param byte:要发送的数据
  374. * @retval 返回接收到的数据
  375. */
  376. u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
  377. {
  378. SPITimeout = SPIT_FLAG_TIMEOUT;
  379. /* 等待发送缓冲区为空,TXE事件 */
  380. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_TXE) == RESET)
  381. {
  382. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
  383. }
  384. /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  385. SPI_I2S_SendData(FLASH_SPIx , HalfWord);
  386. SPITimeout = SPIT_FLAG_TIMEOUT;
  387. /* 等待接收缓冲区非空,RXNE事件 */
  388. while (SPI_I2S_GetFlagStatus(FLASH_SPIx , SPI_I2S_FLAG_RXNE) == RESET)
  389. {
  390. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
  391. }
  392. /* 读取数据寄存器,获取接收缓冲区数据 */
  393. return SPI_I2S_ReceiveData(FLASH_SPIx );
  394. }
  395. /**
  396. * @brief 向FLASH发送 写使能 命令
  397. * @param none
  398. * @retval none
  399. */
  400. void SPI_FLASH_WriteEnable(void)
  401. {
  402. /* 通讯开始:CS低 */
  403. SPI_FLASH_CS_LOW();
  404. /* 发送写使能命令*/
  405. SPI_FLASH_SendByte(W25X_WriteEnable);
  406. /*通讯结束:CS高 */
  407. SPI_FLASH_CS_HIGH();
  408. }
  409. /* WIP(busy)标志,FLASH内部正在写入 */
  410. #define WIP_Flag 0x01
  411. /**
  412. * @brief 等待WIP(BUSY)标志被置0,即等待到FLASH内部数据写入完毕
  413. * @param none
  414. * @retval none
  415. */
  416. void SPI_FLASH_WaitForWriteEnd(void)
  417. {
  418. u8 FLASH_Status = 0;
  419. /* 选择 FLASH: CS 低 */
  420. SPI_FLASH_CS_LOW();
  421. /* 发送 读状态寄存器 命令 */
  422. SPI_FLASH_SendByte(W25X_ReadStatusReg);
  423. /* 若FLASH忙碌,则等待 */
  424. do
  425. {
  426. /* 读取FLASH芯片的状态寄存器 */
  427. FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
  428. }
  429. while ((FLASH_Status & WIP_Flag) == SET); /* 正在写入标志 */
  430. /* 停止信号 FLASH: CS 高 */
  431. SPI_FLASH_CS_HIGH();
  432. }
  433. //进入掉电模式
  434. void SPI_Flash_PowerDown(void)
  435. {
  436. /* 通讯开始:CS低 */
  437. SPI_FLASH_CS_LOW();
  438. /* 发送 掉电 命令 */
  439. SPI_FLASH_SendByte(W25X_PowerDown);
  440. /*通讯结束:CS高 */
  441. SPI_FLASH_CS_HIGH();
  442. }
  443. //唤醒
  444. void SPI_Flash_WAKEUP(void)
  445. {
  446. /*选择 FLASH: CS 低 */
  447. SPI_FLASH_CS_LOW();
  448. /* 发送 上电 命令 */
  449. SPI_FLASH_SendByte(W25X_ReleasePowerDown);
  450. /* 停止信号 FLASH: CS 高 */
  451. SPI_FLASH_CS_HIGH();
  452. }
  453. /**
  454. * @brief 等待超时回调函数
  455. * @param None.
  456. * @retval None.
  457. */
  458. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
  459. {
  460. /* 等待超时后的处理,输出错误信息 */
  461. FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  462. return 0;
  463. }
  464. /*********************************************END OF FILE**********************/

main.c

 /**
  ******************************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   华邦 8M串行flash测试,并将测试信息通过串口1在电脑的超级终端中打印出来
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火 F103-霸道 STM32 开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./flash/bsp_spi_flash.h"


typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;

/* 获取缓冲区的长度 */
#define TxBufferSize1   (countof(TxBuffer1) - 1)
#define RxBufferSize1   (countof(TxBuffer1) - 1)
#define countof(a)      (sizeof(a) / sizeof(*(a)))
#define  BufferSize (countof(Tx_Buffer)-1)

#define  FLASH_WriteAddress     0x00000
#define  FLASH_ReadAddress      FLASH_WriteAddress
#define  FLASH_SectorToErase    FLASH_WriteAddress



/* 发送缓冲区初始化 */
uint8_t Tx_Buffer[] = "感谢您选用野火stm32开发板\r\n";
uint8_t Rx_Buffer[BufferSize];

__IO uint32_t DeviceID = 0;
__IO uint32_t FlashID = 0;
__IO TestStatus TransferStatus1 = FAILED;

// 函数原型声明
void Delay(__IO uint32_t nCount);
TestStatus Buffercmp(uint8_t* pBuffer1,uint8_t* pBuffer2, uint16_t BufferLength);

/*
 * 函数名:main
 * 描述  :主函数
 * 输入  :无
 * 输出  :无
 */
int main(void)
{     
    LED_GPIO_Config();
    LED_BLUE;

    /* 配置串口为:115200 8-N-1 */
    USART_Config();
    printf("\r\n 这是一个8Mbyte串行flash(W25Q64)实验 \r\n");

    /* 8M串行flash W25Q64初始化 */
    SPI_FLASH_Init();

    /* 获取 Flash Device ID */
    DeviceID = SPI_FLASH_ReadDeviceID();    
    Delay( 200 );

    /* 获取 SPI Flash ID */
    FlashID = SPI_FLASH_ReadID();    
    printf("\r\n FlashID is 0x%X,\
    Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);

    /* 检验 SPI Flash ID */
    if (FlashID == sFLASH_ID)
    {    
        printf("\r\n 检测到串行flash W25Q64 !\r\n");

        /* 擦除将要写入的 SPI FLASH 扇区,FLASH写入前要先擦除 */
        // 这里擦除4K,即一个扇区,擦除的最小单位是扇区
        SPI_FLASH_SectorErase(FLASH_SectorToErase);          

        /* 将发送缓冲区的数据写到flash中 */
        // 这里写一页,一页的大小为256个字节
        SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);        
        printf("\r\n 写入的数据为:%s \r\t", Tx_Buffer);

        /* 将刚刚写入的数据读出来放到接收缓冲区中 */
        SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
        printf("\r\n 读出的数据为:%s \r\n", Rx_Buffer);

        /* 检查写入的数据与读出的数据是否相等 */
        TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);

        if( PASSED == TransferStatus1 )
        { 
            LED_GREEN;
            printf("\r\n 8M串行flash(W25Q64)测试成功!\n\r");
        }
        else
        {        
            LED_RED;
            printf("\r\n 8M串行flash(W25Q64)测试失败!\n\r");
        }
    }// if (FlashID == sFLASH_ID)
    else// if (FlashID == sFLASH_ID)
    { 
        LED_RED;
        printf("\r\n 获取不到 W25Q64 ID!\n\r");
    }

    while(1);  
}

/*
 * 函数名:Buffercmp
 * 描述  :比较两个缓冲区中的数据是否相等
 * 输入  :-pBuffer1     src缓冲区指针
 *         -pBuffer2     dst缓冲区指针
 *         -BufferLength 缓冲区长度
 * 输出  :无
 * 返回  :-PASSED pBuffer1 等于   pBuffer2
 *         -FAILED pBuffer1 不同于 pBuffer2
 */
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
  while(BufferLength--)
  {
    if(*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }
  return PASSED;
}

void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}
/*********************************************END OF FILE**********************/

程序文件1-W25Q64.zip

W25Q64存储小数和整数

2-W25Q64存储小数和整数.zip