当前位置:   article > 正文

STM32F4xx系列使用HAL库配置SPI-读写FLASH_hal_spi_mspinit

hal_spi_mspinit

SPI协议简介

SPI物理层特点

  

SPI协议层

 

 

 

 

 QSPI协议简介

 

 

 

 SPI框图

 Flash写入与EEPROM有点相似,不同的是FLASH写入需要软件手动擦除,而EEPROM不用

 SPI配置流程

1、初始化通讯使用的目标引脚及端口时钟

2、使能SPI外设的时钟

3、配置SPI外设的模式、地址、速率等参数并使能SPI外设

4、编写基本SPI按字节收发的函数

将片选信号拉低

查看数据发送完成标志,如果标志不存在

将数据写入SPI数据寄存器

5、编写对FLASH擦除及读写操作的函数

6、编写测试程序,对读写数据进行校验

HAL库读写串行FLASH(W125Q128)实验

 

 flash 0xAB指令

 flash 0x90指令

 注意FLASH地址是24位的

 这里直接放spi_flash的板级支持包,直接调用即可

可以直接将CubeMX生成的源文件spi.c和spi.h替换成下述文件即可

spi.c

  1. /**
  2. ******************************************************************************
  3. * @file spi.c
  4. * @brief This file provides code for the configuration
  5. * of the SPI instances.
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "spi.h"
  21. /* USER CODE BEGIN 0 */
  22. /* USER CODE END 0 */
  23. SPI_HandleTypeDef SpiHandle;
  24. static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
  25. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
  26. /**
  27. * @brief SPI MSP Initialization
  28. * This function configures the hardware resources used in this example:
  29. * - Peripheral's clock enable
  30. * - Peripheral's GPIO Configuration
  31. * @param hspi: SPI handle pointer
  32. * @retval None
  33. */
  34. void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
  35. {
  36. GPIO_InitTypeDef GPIO_InitStruct;
  37. /*##-1- Enable peripherals and GPIO Clocks #################################*/
  38. /* Enable GPIO TX/RX clock */
  39. SPIx_SCK_GPIO_CLK_ENABLE();
  40. SPIx_MISO_GPIO_CLK_ENABLE();
  41. SPIx_MOSI_GPIO_CLK_ENABLE();
  42. SPIx_CS_GPIO_CLK_ENABLE();
  43. /* Enable SPI clock */
  44. SPIx_CLK_ENABLE();
  45. /*##-2- Configure peripheral GPIO ##########################################*/
  46. /* SPI SCK GPIO pin configuration */
  47. GPIO_InitStruct.Pin = SPIx_SCK_PIN;
  48. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  49. GPIO_InitStruct.Pull = GPIO_PULLUP;
  50. GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
  51. GPIO_InitStruct.Alternate = SPIx_SCK_AF;
  52. HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);
  53. /* SPI MISO GPIO pin configuration */
  54. GPIO_InitStruct.Pin = SPIx_MISO_PIN;
  55. GPIO_InitStruct.Alternate = SPIx_MISO_AF;
  56. HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);
  57. /* SPI MOSI GPIO pin configuration */
  58. GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
  59. GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
  60. HAL_GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStruct);
  61. GPIO_InitStruct.Pin = FLASH_CS_PIN ;
  62. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  63. HAL_GPIO_Init(FLASH_CS_GPIO_PORT, &GPIO_InitStruct);
  64. }
  65. void SPI_FLASH_Init(void)
  66. {
  67. /*##-1- Configure the SPI peripheral #######################################*/
  68. /* Set the SPI parameters */
  69. SpiHandle.Instance = SPIx;
  70. SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  71. SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
  72. SpiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
  73. SpiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
  74. SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  75. SpiHandle.Init.CRCPolynomial = 7;
  76. SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
  77. SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
  78. SpiHandle.Init.NSS = SPI_NSS_SOFT;
  79. SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
  80. SpiHandle.Init.Mode = SPI_MODE_MASTER;
  81. HAL_SPI_Init(&SpiHandle);
  82. __HAL_SPI_ENABLE(&SpiHandle);
  83. }
  84. /**
  85. * @brief 擦除FLASH扇区
  86. * @param SectorAddr:要擦除的扇区地址
  87. * @retval 无
  88. */
  89. void SPI_FLASH_SectorErase(uint32_t SectorAddr)
  90. {
  91. /* 发送FLASH写使能命令 */
  92. SPI_FLASH_WriteEnable();
  93. SPI_FLASH_WaitForWriteEnd();
  94. /* 擦除扇区 */
  95. /* 选择FLASH: CS低电平 */
  96. SPI_FLASH_CS_LOW();
  97. /* 发送扇区擦除指令*/
  98. SPI_FLASH_SendByte(W25X_SectorErase);
  99. /*发送擦除扇区地址的高位*/
  100. SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
  101. /* 发送擦除扇区地址的中位 */
  102. SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
  103. /* 发送擦除扇区地址的低位 */
  104. SPI_FLASH_SendByte(SectorAddr & 0xFF);
  105. /* 停止信号 FLASH: CS 高电平 */
  106. SPI_FLASH_CS_HIGH();
  107. /* 等待擦除完毕*/
  108. SPI_FLASH_WaitForWriteEnd();
  109. }
  110. /**
  111. * @brief 擦除FLASH扇区,整片擦除
  112. * @param 无
  113. * @retval 无
  114. */
  115. void SPI_FLASH_BulkErase(void)
  116. {
  117. /* 发送FLASH写使能命令 */
  118. SPI_FLASH_WriteEnable();
  119. /* 整块 Erase */
  120. /* 选择FLASH: CS低电平 */
  121. SPI_FLASH_CS_LOW();
  122. /* 发送整块擦除指令*/
  123. SPI_FLASH_SendByte(W25X_ChipErase);
  124. /* 停止信号 FLASH: CS 高电平 */
  125. SPI_FLASH_CS_HIGH();
  126. /* 等待擦除完毕*/
  127. SPI_FLASH_WaitForWriteEnd();
  128. }
  129. /**
  130. * @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
  131. * @param pBuffer,要写入数据的指针
  132. * @param WriteAddr,写入地址
  133. * @param NumByteToWrite,写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
  134. * @retval 无
  135. */
  136. void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
  137. {
  138. /* 发送FLASH写使能命令 */
  139. SPI_FLASH_WriteEnable();
  140. /* 选择FLASH: CS低电平 */
  141. SPI_FLASH_CS_LOW();
  142. /* 写页写指令*/
  143. SPI_FLASH_SendByte(W25X_PageProgram);
  144. /*发送写地址的高位*/
  145. SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
  146. /*发送写地址的中位*/
  147. SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
  148. /*发送写地址的低位*/
  149. SPI_FLASH_SendByte(WriteAddr & 0xFF);
  150. if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
  151. {
  152. NumByteToWrite = SPI_FLASH_PerWritePageSize;
  153. FLASH_ERROR("SPI_FLASH_PageWrite too large!");
  154. }
  155. /* 写入数据*/
  156. while (NumByteToWrite--)
  157. {
  158. /* 发送当前要写入的字节数据 */
  159. SPI_FLASH_SendByte(*pBuffer);
  160. /* 指向下一字节数据 */
  161. pBuffer++;
  162. }
  163. /* 停止信号 FLASH: CS 高电平 */
  164. SPI_FLASH_CS_HIGH();
  165. /* 等待写入完毕*/
  166. SPI_FLASH_WaitForWriteEnd();
  167. }
  168. /**
  169. * @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
  170. * @param pBuffer,要写入数据的指针
  171. * @param WriteAddr,写入地址
  172. * @param NumByteToWrite,写入数据长度
  173. * @retval 无
  174. */
  175. void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
  176. {
  177. uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
  178. /*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
  179. Addr = WriteAddr % SPI_FLASH_PageSize;
  180. /*count个数据值,刚好可以对齐到页地址*/
  181. count = SPI_FLASH_PageSize - Addr;
  182. /*计算出要写多少整数页*/
  183. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  184. /*mod运算求余,计算出剩余不满一页的字节数*/
  185. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  186. /* Addr=0,则WriteAddr 刚好按页对齐 aligned */
  187. if (Addr == 0)
  188. {
  189. /* NumByteToWrite < SPI_FLASH_PageSize */
  190. if (NumOfPage == 0)
  191. {
  192. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  193. }
  194. else /* NumByteToWrite > SPI_FLASH_PageSize */
  195. {
  196. /*先把整数页都写了*/
  197. while (NumOfPage--)
  198. {
  199. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  200. WriteAddr += SPI_FLASH_PageSize;
  201. pBuffer += SPI_FLASH_PageSize;
  202. }
  203. /*若有多余的不满一页的数据,把它写完*/
  204. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  205. }
  206. }
  207. /* 若地址与 SPI_FLASH_PageSize 不对齐 */
  208. else
  209. {
  210. /* NumByteToWrite < SPI_FLASH_PageSize */
  211. if (NumOfPage == 0)
  212. {
  213. /*当前页剩余的count个位置比NumOfSingle小,写不完*/
  214. if (NumOfSingle > count)
  215. {
  216. temp = NumOfSingle - count;
  217. /*先写满当前页*/
  218. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  219. WriteAddr += count;
  220. pBuffer += count;
  221. /*再写剩余的数据*/
  222. SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
  223. }
  224. else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
  225. {
  226. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  227. }
  228. }
  229. else /* NumByteToWrite > SPI_FLASH_PageSize */
  230. {
  231. /*地址不对齐多出的count分开处理,不加入这个运算*/
  232. NumByteToWrite -= count;
  233. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  234. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  235. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  236. WriteAddr += count;
  237. pBuffer += count;
  238. /*把整数页都写了*/
  239. while (NumOfPage--)
  240. {
  241. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  242. WriteAddr += SPI_FLASH_PageSize;
  243. pBuffer += SPI_FLASH_PageSize;
  244. }
  245. /*若有多余的不满一页的数据,把它写完*/
  246. if (NumOfSingle != 0)
  247. {
  248. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  249. }
  250. }
  251. }
  252. }
  253. /**
  254. * @brief 读取FLASH数据
  255. * @param pBuffer,存储读出数据的指针
  256. * @param ReadAddr,读取地址
  257. * @param NumByteToRead,读取数据长度
  258. * @retval 无
  259. */
  260. void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
  261. {
  262. /* 选择FLASH: CS低电平 */
  263. SPI_FLASH_CS_LOW();
  264. /* 发送 读 指令 */
  265. SPI_FLASH_SendByte(W25X_ReadData);
  266. /* 发送 读 地址高位 */
  267. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  268. /* 发送 读 地址中位 */
  269. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  270. /* 发送 读 地址低位 */
  271. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  272. /* 读取数据 */
  273. while (NumByteToRead--)
  274. {
  275. /* 读取一个字节*/
  276. *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
  277. /* 指向下一个字节缓冲区 */
  278. pBuffer++;
  279. }
  280. /* 停止信号 FLASH: CS 高电平 */
  281. SPI_FLASH_CS_HIGH();
  282. }
  283. /**
  284. * @brief 读取FLASH ID
  285. * @param 无
  286. * @retval FLASH ID
  287. */
  288. uint32_t SPI_FLASH_ReadID(void)
  289. {
  290. uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
  291. /* 开始通讯:CS低电平 */
  292. SPI_FLASH_CS_LOW();
  293. /* 发送JEDEC指令,读取ID */
  294. SPI_FLASH_SendByte(W25X_JedecDeviceID);
  295. /* 读取一个字节数据 */
  296. Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
  297. /* 读取一个字节数据 */
  298. Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
  299. /* 读取一个字节数据 */
  300. Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
  301. /* 停止通讯:CS高电平 */
  302. SPI_FLASH_CS_HIGH();
  303. /*把数据组合起来,作为函数的返回值*/
  304. Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
  305. return Temp;
  306. }
  307. /**
  308. * @brief 读取FLASH Device ID
  309. * @param 无
  310. * @retval FLASH Device ID
  311. */
  312. uint32_t SPI_FLASH_ReadDeviceID(void)
  313. {
  314. uint32_t Temp = 0;
  315. /* Select the FLASH: Chip Select low */
  316. SPI_FLASH_CS_LOW();
  317. /* Send "RDID " instruction */
  318. SPI_FLASH_SendByte(W25X_DeviceID);
  319. SPI_FLASH_SendByte(Dummy_Byte);
  320. SPI_FLASH_SendByte(Dummy_Byte);
  321. SPI_FLASH_SendByte(Dummy_Byte);
  322. /* Read a byte from the FLASH */
  323. Temp = SPI_FLASH_SendByte(Dummy_Byte);
  324. /* Deselect the FLASH: Chip Select high */
  325. SPI_FLASH_CS_HIGH();
  326. return Temp;
  327. }
  328. /*******************************************************************************
  329. * Function Name : SPI_FLASH_StartReadSequence
  330. * Description : Initiates a read data byte (READ) sequence from the Flash.
  331. * This is done by driving the /CS line low to select the device,
  332. * then the READ instruction is transmitted followed by 3 bytes
  333. * address. This function exit and keep the /CS line low, so the
  334. * Flash still being selected. With this technique the whole
  335. * content of the Flash is read with a single READ instruction.
  336. * Input : - ReadAddr : FLASH's internal address to read from.
  337. * Output : None
  338. * Return : None
  339. *******************************************************************************/
  340. void SPI_FLASH_StartReadSequence(uint32_t ReadAddr)
  341. {
  342. /* Select the FLASH: Chip Select low */
  343. SPI_FLASH_CS_LOW();
  344. /* Send "Read from Memory " instruction */
  345. SPI_FLASH_SendByte(W25X_ReadData);
  346. /* Send the 24-bit address of the address to read from -----------------------*/
  347. /* Send ReadAddr high nibble address byte */
  348. SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  349. /* Send ReadAddr medium nibble address byte */
  350. SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  351. /* Send ReadAddr low nibble address byte */
  352. SPI_FLASH_SendByte(ReadAddr & 0xFF);
  353. }
  354. /**
  355. * @brief 使用SPI读取一个字节的数据
  356. * @param 无
  357. * @retval 返回接收到的数据
  358. */
  359. uint8_t SPI_FLASH_ReadByte(void)
  360. {
  361. return (SPI_FLASH_SendByte(Dummy_Byte));
  362. }
  363. /**
  364. * @brief 使用SPI发送一个字节的数据
  365. * @param byte:要发送的数据
  366. * @retval 返回接收到的数据
  367. */
  368. uint8_t SPI_FLASH_SendByte(uint8_t byte)
  369. {
  370. SPITimeout = SPIT_FLAG_TIMEOUT;
  371. /* 等待发送缓冲区为空,TXE事件 */
  372. while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_TXE ) == RESET)
  373. {
  374. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
  375. }
  376. /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  377. WRITE_REG(SpiHandle.Instance->DR, byte);
  378. SPITimeout = SPIT_FLAG_TIMEOUT;
  379. /* 等待接收缓冲区非空,RXNE事件 */
  380. while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_RXNE ) == RESET)
  381. {//发送缓冲区会在下一个周期将数据发送出去
  382. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
  383. }
  384. /* 读取数据寄存器,获取接收缓冲区数据 */
  385. return READ_REG(SpiHandle.Instance->DR);
  386. // static uint8_t Rx_Data[1];
  387. // static uint8_t Tx_Data[1];
  388. // Tx_Data[0]=byte;
  389. // if(HAL_SPI_TransmitReceive(&SpiHandle,Tx_Data,Rx_Data,1,1000)!=HAL_OK)
  390. // {
  391. // return 0;
  392. // }
  393. // return Rx_Data[0];
  394. }
  395. /*******************************************************************************
  396. * Function Name : SPI_FLASH_SendHalfWord
  397. * Description : Sends a Half Word through the SPI interface and return the
  398. * Half Word received from the SPI bus.
  399. * Input : Half Word : Half Word to send.
  400. * Output : None
  401. * Return : The value of the received Half Word.
  402. *******************************************************************************/
  403. uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord)
  404. {
  405. SPITimeout = SPIT_FLAG_TIMEOUT;
  406. /* Loop while DR register in not emplty */
  407. while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_TXE ) == RESET)
  408. {
  409. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
  410. }
  411. /* Send Half Word through the SPIx peripheral */
  412. WRITE_REG(SpiHandle.Instance->DR, HalfWord);
  413. SPITimeout = SPIT_FLAG_TIMEOUT;
  414. /* Wait to receive a Half Word */
  415. while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_RXNE ) == RESET)
  416. {
  417. if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
  418. }
  419. /* Return the Half Word read from the SPI bus */
  420. return READ_REG(SpiHandle.Instance->DR);
  421. }
  422. /**
  423. * @brief 向FLASH发送 写使能 命令
  424. * @param none
  425. * @retval none
  426. */
  427. void SPI_FLASH_WriteEnable(void)
  428. {
  429. /* 通讯开始:CS低 */
  430. SPI_FLASH_CS_LOW();
  431. /* 发送写使能命令*/
  432. SPI_FLASH_SendByte(W25X_WriteEnable);
  433. /*通讯结束:CS高 */
  434. SPI_FLASH_CS_HIGH();
  435. }
  436. /**
  437. * @brief 等待WIP(BUSY)标志被置0,即等待到FLASH内部数据写入完毕
  438. * @param none
  439. * @retval none
  440. */
  441. void SPI_FLASH_WaitForWriteEnd(void)
  442. {
  443. uint8_t FLASH_Status = 0;
  444. /* 选择 FLASH: CS 低 */
  445. SPI_FLASH_CS_LOW();
  446. /* 发送 读状态寄存器 命令 */
  447. SPI_FLASH_SendByte(W25X_ReadStatusReg);
  448. SPITimeout = SPIT_FLAG_TIMEOUT;
  449. /* 若FLASH忙碌,则等待 */
  450. do
  451. {
  452. /* 读取FLASH芯片的状态寄存器 */
  453. FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
  454. {
  455. if((SPITimeout--) == 0)
  456. {
  457. SPI_TIMEOUT_UserCallback(4);
  458. return;
  459. }
  460. }
  461. }
  462. while ((FLASH_Status & WIP_Flag) == SET); /* 正在写入标志 */
  463. /* 停止信号 FLASH: CS 高 */
  464. SPI_FLASH_CS_HIGH();
  465. }
  466. //进入掉电模式
  467. void SPI_Flash_PowerDown(void)
  468. {
  469. /* 选择 FLASH: CS 低 */
  470. SPI_FLASH_CS_LOW();
  471. /* 发送 掉电 命令 */
  472. SPI_FLASH_SendByte(W25X_PowerDown);
  473. /* 停止信号 FLASH: CS 高 */
  474. SPI_FLASH_CS_HIGH();
  475. }
  476. //唤醒
  477. void SPI_Flash_WAKEUP(void)
  478. {
  479. /*选择 FLASH: CS 低 */
  480. SPI_FLASH_CS_LOW();
  481. /* 发上 上电 命令 */
  482. SPI_FLASH_SendByte(W25X_ReleasePowerDown);
  483. /* 停止信号 FLASH: CS 高 */
  484. SPI_FLASH_CS_HIGH(); //等待TRES1
  485. }
  486. /**
  487. * @brief 等待超时回调函数
  488. * @param None.
  489. * @retval None.
  490. */
  491. static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
  492. {
  493. /* 等待超时后的处理,输出错误信息 */
  494. FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  495. return 0;
  496. }
  497. /*********************************************END OF FILE**********************/

spi.h

  1. /**
  2. ******************************************************************************
  3. * @file spi.h
  4. * @brief This file contains all the function prototypes for
  5. * the spi.c file
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* Define to prevent recursive inclusion -------------------------------------*/
  20. #ifndef __SPI_H__
  21. #define __SPI_H__
  22. #ifdef __cplusplus
  23. extern "C" {
  24. #endif
  25. /* Includes ------------------------------------------------------------------*/
  26. #include "main.h"
  27. /* USER CODE BEGIN Includes */
  28. /* USER CODE END Includes */
  29. #define sFLASH_ID 0XEF4018 //W25Q128
  30. //#define SPI_FLASH_PageSize 4096
  31. #define SPI_FLASH_PageSize 256
  32. #define SPI_FLASH_PerWritePageSize 256
  33. /* Private define ------------------------------------------------------------*/
  34. /*命令定义-开头*******************************/
  35. #define W25X_WriteEnable 0x06
  36. #define W25X_WriteDisable 0x04
  37. #define W25X_ReadStatusReg 0x05
  38. #define W25X_WriteStatusReg 0x01
  39. #define W25X_ReadData 0x03
  40. #define W25X_FastReadData 0x0B
  41. #define W25X_FastReadDual 0x3B
  42. #define W25X_PageProgram 0x02
  43. #define W25X_BlockErase 0xD8
  44. #define W25X_SectorErase 0x20
  45. #define W25X_ChipErase 0xC7
  46. #define W25X_PowerDown 0xB9
  47. #define W25X_ReleasePowerDown 0xAB
  48. #define W25X_DeviceID 0xAB
  49. #define W25X_ManufactDeviceID 0x90
  50. #define W25X_JedecDeviceID 0x9F
  51. #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */
  52. #define Dummy_Byte 0xFF
  53. /*命令定义-结尾*******************************/
  54. //SPI号及时钟初始化函数
  55. #define SPIx SPI1
  56. #define SPIx_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
  57. #define SPIx_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
  58. #define SPIx_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
  59. #define SPIx_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
  60. #define SPIx_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
  61. #define SPIx_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET()
  62. #define SPIx_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET()
  63. //SCK引脚
  64. #define SPIx_SCK_PIN GPIO_PIN_3
  65. #define SPIx_SCK_GPIO_PORT GPIOB
  66. #define SPIx_SCK_AF GPIO_AF5_SPI1
  67. //MISO引脚
  68. #define SPIx_MISO_PIN GPIO_PIN_4
  69. #define SPIx_MISO_GPIO_PORT GPIOB
  70. #define SPIx_MISO_AF GPIO_AF5_SPI1
  71. //MOSI引脚
  72. #define SPIx_MOSI_PIN GPIO_PIN_5
  73. #define SPIx_MOSI_GPIO_PORT GPIOB
  74. #define SPIx_MOSI_AF GPIO_AF5_SPI1
  75. //CS(NSS)引脚
  76. #define FLASH_CS_PIN GPIO_PIN_6
  77. #define FLASH_CS_GPIO_PORT GPIOG
  78. //设置为高电平
  79. #define digitalHi(p,i) {p->BSRR=i;}
  80. //输出低电平
  81. #define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;}
  82. #define SPI_FLASH_CS_LOW() digitalLo(FLASH_CS_GPIO_PORT,FLASH_CS_PIN )
  83. #define SPI_FLASH_CS_HIGH() digitalHi(FLASH_CS_GPIO_PORT,FLASH_CS_PIN )
  84. /*SPI接口定义-结尾****************************/
  85. /*等待超时时间*/
  86. #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
  87. #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
  88. /*信息输出*/
  89. #define FLASH_DEBUG_ON 1
  90. #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
  91. #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
  92. #define FLASH_DEBUG(fmt,arg...) do{\
  93. if(FLASH_DEBUG_ON)\
  94. printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
  95. }while(0)
  96. void SPI_FLASH_Init(void);
  97. void SPI_FLASH_SectorErase(uint32_t SectorAddr);
  98. void SPI_FLASH_BulkErase(void);
  99. void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
  100. void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
  101. void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
  102. uint32_t SPI_FLASH_ReadID(void);
  103. uint32_t SPI_FLASH_ReadDeviceID(void);
  104. void SPI_FLASH_StartReadSequence(uint32_t ReadAddr);
  105. void SPI_Flash_PowerDown(void);
  106. void SPI_Flash_WAKEUP(void);
  107. uint8_t SPI_FLASH_ReadByte(void);
  108. uint8_t SPI_FLASH_SendByte(uint8_t byte);
  109. uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord);
  110. void SPI_FLASH_WriteEnable(void);
  111. void SPI_FLASH_WaitForWriteEnd(void);
  112. #endif /* __SPI_FLASH_H */

main.c

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"
  22. #include "spi.h"
  23. #include "usart.h"
  24. #include "gpio.h"
  25. #include <stdio.h>
  26. void SystemClock_Config(void);
  27. typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
  28. /* 获取缓冲区的长度 */
  29. #define TxBufferSize1 (countof(TxBuffer1) - 1)
  30. #define RxBufferSize1 (countof(TxBuffer1) - 1)
  31. #define countof(a) (sizeof(a) / sizeof(*(a)))
  32. #define BufferSize (countof(Tx_Buffer)-1)
  33. #define FLASH_WriteAddress 0x00000
  34. #define FLASH_ReadAddress FLASH_WriteAddress
  35. #define FLASH_SectorToErase FLASH_WriteAddress
  36. /* 发送缓冲区初始化 */
  37. uint8_t Tx_Buffer[] = "hello world!";
  38. uint8_t Rx_Buffer[BufferSize];
  39. //读取的ID存储位置
  40. __IO uint32_t DeviceID = 0;
  41. __IO uint32_t FlashID = 0;
  42. __IO TestStatus TransferStatus1 = FAILED;
  43. TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
  44. /**
  45. * @brief The application entry point.
  46. * @retval int
  47. */
  48. int main(void)
  49. {
  50. HAL_Init();
  51. SystemClock_Config();
  52. MX_GPIO_Init();
  53. /* 16M串行flash W25Q128初始化 */
  54. SPI_FLASH_Init();
  55. MX_USART1_UART_Init();
  56. printf("\r\n这是一个16M串行flash(W25Q128)实验(QSPI驱动) \r\n");
  57. /* 16M串行flash W25Q128初始化 */
  58. /* 获取 Flash Device ID */
  59. DeviceID = SPI_FLASH_ReadDeviceID();
  60. HAL_Delay( 200 );
  61. /* 获取 SPI Flash ID */
  62. FlashID = SPI_FLASH_ReadID();
  63. printf("\r\nFlashID is 0x%X, Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);
  64. /* 检验 SPI Flash ID */
  65. if (FlashID == sFLASH_ID)
  66. {
  67. printf("\r\n检测到SPI FLASH W25Q128 !\r\n");
  68. /* 擦除将要写入的 SPI FLASH 扇区,FLASH写入前要先擦除 */
  69. SPI_FLASH_SectorErase(FLASH_SectorToErase);
  70. /* 将发送缓冲区的数据写到flash中 */
  71. SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
  72. printf("\r\n写入的数据为:\r\n%s", Tx_Buffer);
  73. /* 将刚刚写入的数据读出来放到接收缓冲区中 */
  74. SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
  75. printf("\r\n读出的数据为:\r\n%s", Rx_Buffer);
  76. /* 检查写入的数据与读出的数据是否相等 */
  77. TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
  78. if( PASSED == TransferStatus1 )
  79. {
  80. LED_ALLON;
  81. printf("\r\n16M串行flash(W25Q128)测试成功!\n\r");
  82. }
  83. else
  84. {
  85. LED2_ON;
  86. printf("\r\n16M串行flash(W25Q128)测试失败!\n\r");
  87. }
  88. }// if (FlashID == sFLASH_ID)
  89. else
  90. {
  91. LED2_ON;
  92. printf("\r\n获取不到 W25Q128 ID!\n\r");
  93. }
  94. SPI_Flash_PowerDown();
  95. while (1)
  96. {
  97. }
  98. }
  99. TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
  100. {
  101. while(BufferLength--)
  102. {
  103. if(*pBuffer1 != *pBuffer2)
  104. {
  105. return FAILED;
  106. }
  107. pBuffer1++;
  108. pBuffer2++;
  109. }
  110. return PASSED;
  111. }
  112. /**
  113. * @brief System Clock Configuration
  114. * @retval None
  115. */
  116. void SystemClock_Config(void)
  117. {
  118. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  119. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  120. /** Configure the main internal regulator output voltage
  121. */
  122. __HAL_RCC_PWR_CLK_ENABLE();
  123. __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  124. /** Initializes the RCC Oscillators according to the specified parameters
  125. * in the RCC_OscInitTypeDef structure.
  126. */
  127. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  128. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  129. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  130. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  131. RCC_OscInitStruct.PLL.PLLM = 25;
  132. RCC_OscInitStruct.PLL.PLLN = 336;
  133. RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  134. RCC_OscInitStruct.PLL.PLLQ = 4;
  135. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  136. {
  137. Error_Handler();
  138. }
  139. /** Initializes the CPU, AHB and APB buses clocks
  140. */
  141. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  142. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  143. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  144. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  145. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  146. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  147. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  148. {
  149. Error_Handler();
  150. }
  151. }
  152. /* USER CODE BEGIN 4 */
  153. /* USER CODE END 4 */
  154. /**
  155. * @brief This function is executed in case of error occurrence.
  156. * @retval None
  157. */
  158. void Error_Handler(void)
  159. {
  160. /* USER CODE BEGIN Error_Handler_Debug */
  161. /* User can add his own implementation to report the HAL error return state */
  162. __disable_irq();
  163. while (1)
  164. {
  165. }
  166. /* USER CODE END Error_Handler_Debug */
  167. }
  168. #ifdef USE_FULL_ASSERT
  169. /**
  170. * @brief Reports the name of the source file and the source line number
  171. * where the assert_param error has occurred.
  172. * @param file: pointer to the source file name
  173. * @param line: assert_param error line source number
  174. * @retval None
  175. */
  176. void assert_failed(uint8_t *file, uint32_t line)
  177. {
  178. /* USER CODE BEGIN 6 */
  179. /* User can add his own implementation to report the file name and line number,
  180. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  181. /* USER CODE END 6 */
  182. }
  183. #endif /* USE_FULL_ASSERT */
  184. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

LED和串口UART配置这里就不过多介绍了,感谢大家的阅读!^_^

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/50684
推荐阅读
相关标签
  

闽ICP备14008679号