[APM32F4] APM32F402 驱动 SPI Flash Demo

[复制链接]
 楼主| Peixu 发表于 2025-6-16 16:22 | 显示全部楼层 |阅读模式
本帖最后由 Peixu 于 2025-6-16 16:29 编辑

一、引言:嵌入式存储解决方案概述
APM32F402 作为一款高性能 ARM Cortex-M4 微控制器,搭配SPI Flash 存储芯片,能够为各类嵌入式应用提供稳定可靠的大容量数据存储解决方案。
本文将从硬件设计、驱动开发、功能测试实现基于 APM32F402 的 SPI Flash 通信完整实现方案。

二、硬件设计:APM32F402 与 SPI Flash的电路连接
2.1 引脚连接方案
APM32F402 与 SPI Flash 通信需要以下关键引脚连接:

APM32F402 引脚
SPI Flash 引脚
功能说明
PA4(GPIO_PIN_4)
CS
片选信号(低电平有效)
PA5(GPIO_PIN_5)
CLK
SPI 时钟信号
PA6(GPIO_PIN_6)
DO/MISO
主设备输入 / 从设备输出
PA7(GPIO_PIN_7)
DI/MOSI
主设备输出 / 从设备输入

三、测试与验证:串口输出与 SPI 波形分析
ID 识别验证:
发送 0xAB  获取设备 ID, 发送9F 获取厂商 ID
da93ca1b1a7ca7520a5c1cbc8355113e
292dad3e51e98fdd48121c8a8d7fbed2

擦写读闭环测试:
擦除指定扇区(0x20 命令)
写入 字节测试数据
读取相同地址数据并比对
串口输出比对结果(PASS/FAIL)
6526cd7e8a4c2af5e3d1587791b6f89f
3599d77d363900da539f5db057f860f1

串口输出测试结果:
  1. Device ID:0x17

  2. Flash ID:0x234018

  3. SPI write Data to flash

  4. Write data:

  5. 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011

  6. 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012

  7. 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013

  8. 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014

  9. 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015

  10. 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016

  11. 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017

  12. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  13. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  14. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  15. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  16. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  17. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  18. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  19. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  20. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  21. Read data:

  22. 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011

  23. 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012

  24. 0x1013 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013

  25. 0x1014 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014

  26. 0x1015 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015

  27. 0x1016 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016

  28. 0x1017 0x1011 0x1012 0x1013 0x1014 0x1015 0x1016 0x1017

  29. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  30. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  31. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  32. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  33. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  34. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  35. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  36. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  37. 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010 0x1010

  38. SPI Flash test OK! LED2 on
main.c文件
  1. /**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]        main.c
  3. *
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]       Main program body
  5. *
  6. * [url=home.php?mod=space&uid=895143]@version[/url]     V1.0.0
  7. *
  8. * [url=home.php?mod=space&uid=212281]@date[/url]        2024-12-01
  9. *
  10. * @attention
  11. *
  12. *  Copyright (C) 2024-2025 Geehy Semiconductor
  13. *
  14. *  You may not use this file except in compliance with the
  15. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  16. *
  17. *  The program is only for reference, which is distributed in the hope
  18. *  that it will be useful and instructional for customers to develop
  19. *  their software. Unless required by applicable law or agreed to in
  20. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  21. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  22. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  23. *  and limitations under the License.
  24. */

  25. /* Includes ***************************************************************/
  26. #include "main.h"
  27. #include "bsp_w25q16.h"

  28. /* Private includes *******************************************************/
  29. #include <stdio.h>

  30. /* Private macro **********************************************************/
  31. /* printf function configs to USART */
  32. #define DEBUG_USART  USART1
  33. #define DATA_BUF_SIZE       128

  34. typedef enum {FALSE, TRUE} BOOL;
  35. W25Q16_INFO_T w25q16Info;
  36. uint16_t txDataBufSPI1[DATA_BUF_SIZE] = {0};
  37. uint16_t rxDataBufSPI1[DATA_BUF_SIZE] = {0};

  38. /** SPI TX Buffer*/
  39. const uint16_t SPI_Data_TX[DATA_BUF_SIZE] =
  40. {
  41.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  42.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  43.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  44.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  45.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  46.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  47.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  48.     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0X07,
  49. };

  50. /* Private function prototypes ********************************************/
  51. void USART_Init(void);
  52. void Delay(uint32_t count);
  53. void W25Q16_SPI_Test(void);
  54. void Print_Buffer(uint16_t* pBuffer, uint16_t BufferLength);
  55. uint8_t BufferCompare(uint16_t* buf1, uint16_t* buf2, uint8_t size);

  56. /* External variables *****************************************************/

  57. /* External functions *****************************************************/

  58. /*!
  59. * @brief   Main program
  60. *
  61. * @param   None
  62. *
  63. * @retval  None
  64. */
  65. int main(void)
  66. {
  67.                 USART_Init();       

  68.     W25Q16_SPI_Init();
  69.        
  70.     /* Get Flash Device ID */
  71.                 w25q16Info.deviceID = W25Q16_ReadFlashDeviceID();
  72.                 printf("Device ID:0x%X\r\n",w25q16Info.deviceID);
  73.        
  74.                 /* Get Flash ID */
  75.                 w25q16Info.flashID = W25Q16_ReadFlashID();
  76.                 printf("Flash  ID:0x%X\r\n",w25q16Info.flashID);

  77.                 W25Q16_SPI_Test();
  78.     /* Infinite loop */
  79.     while (1)
  80.     {

  81.     }
  82. }

  83. /*!
  84. * @brief       USART INIT
  85. *
  86. * @param       None
  87. *
  88. * @retval      None
  89. *
  90. * @note
  91. */
  92. void USART_Init(void)
  93. {
  94.     USART_Config_T USART_ConfigStruct;
  95.     GPIO_Config_T GPIO_ConfigStruct;

  96.     // 使能 USART1 和 GPIO 端口时钟
  97.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1 | RCM_APB2_PERIPH_GPIOA);

  98.     // 配置 TX 引脚为复用推挽输出
  99.     GPIO_ConfigStruct.pin = GPIO_PIN_9;
  100.     GPIO_ConfigStruct.mode = GPIO_MODE_AF_PP;
  101.     GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
  102.     GPIO_Config(GPIOA, &GPIO_ConfigStruct);

  103.     // 配置 RX 引脚为浮空输入
  104.     GPIO_ConfigStruct.pin = GPIO_PIN_10;
  105.     GPIO_ConfigStruct.mode = GPIO_MODE_IN_FLOATING;
  106.     GPIO_Config(GPIOA, &GPIO_ConfigStruct);

  107.     // USART 配置
  108.     USART_ConfigStructInit(&USART_ConfigStruct);
  109.     USART_ConfigStruct.baudRate = 115200;
  110.     USART_ConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
  111.     USART_ConfigStruct.mode = USART_MODE_TX_RX;  // 同时启用发送和接收模式
  112.     USART_ConfigStruct.parity = USART_PARITY_NONE;
  113.     USART_ConfigStruct.stopBits = USART_STOP_BIT_1;
  114.     USART_ConfigStruct.wordLength = USART_WORD_LEN_8B;

  115.     USART_Config(USART1, &USART_ConfigStruct);

  116.     // 使能 USART1
  117.     USART_Enable(USART1);       
  118. }

  119. /*!
  120. * @brief       Using SPI operate W25Q16 flash
  121. *
  122. * @param       None
  123. *
  124. * @retval      None
  125. *
  126. * @note
  127. */
  128. void W25Q16_SPI_Test(void)
  129. {
  130.     uint16_t i = 0;
  131.    
  132.     /* initialization  Buffer*/
  133.     for (i = 0; i < DATA_BUF_SIZE; i++)
  134.     {
  135.         txDataBufSPI1[i] = SPI_Data_TX[i] + 0x1010;
  136.         rxDataBufSPI1[i] = 0;
  137.     }

  138.     printf("SPI write Data to flash \r\n");

  139.     /* Erase SPI FLASH Sector */
  140.     W25Q16_EraseSector(W25Q16_FLASH_WRITE_ADDR);

  141.     /* Write data to flash */
  142.     W25Q16_WriteBuffer((uint8_t*)txDataBufSPI1, W25Q16_FLASH_WRITE_ADDR, DATA_BUF_SIZE * 2);
  143.     printf("\r\nWrite data: \r\n");
  144.     Print_Buffer(txDataBufSPI1, DATA_BUF_SIZE);

  145.     /* Read data from flash */
  146.     W25Q16_ReadBuffer((uint8_t*)rxDataBufSPI1, W25Q16_FLASH_READ_ADDR, DATA_BUF_SIZE * 2);
  147.     printf("\r\nRead data: \r\n");
  148.     Print_Buffer(rxDataBufSPI1, DATA_BUF_SIZE);

  149.     /* Compare receive Buffer */
  150.     /* Data is ok then turn on LED2 */
  151.     if (BufferCompare(txDataBufSPI1, rxDataBufSPI1, DATA_BUF_SIZE) == TRUE)
  152.     {
  153.         printf("\r\nSPI Flash test OK! LED2 on\n\r");
  154.     }
  155.     else
  156.     {
  157.         printf("\r\nSPI Flash test fail! LED3 on\n\r");
  158.     }
  159. }
  160. /*!
  161. * @brief       Compares two buffers
  162. *
  163. * @param       buf1:    First buffer to be compared
  164. *
  165. * @param       buf1:    Second buffer to be compared
  166. *
  167. * @param       size:    Buffer size
  168. *
  169. * @retval      Return TRUE if buf1 = buf2. If not then return FALSE
  170. */
  171. uint8_t BufferCompare(uint16_t* buf1, uint16_t* buf2, uint8_t size)
  172. {
  173.     uint8_t i;

  174.     for (i = 0; i < size; i++)
  175.     {
  176.         if (buf1[i] != buf2[i])
  177.         {
  178.             return FALSE;
  179.         }
  180.     }

  181.     return TRUE;
  182. }

  183. /*!
  184. * @brief       Print Buffer Data
  185. *
  186. * @param       pBuffer:buffer
  187. *
  188. * @param       length : length of the Buffer
  189. *
  190. * @retval      None
  191. */
  192. void Print_Buffer(uint16_t* pBuffer, uint16_t BufferLength)
  193. {
  194.     uint16_t i;

  195.     for (i=0; i  < BufferLength; i++)
  196.     {
  197.         printf("0x%04X  ", pBuffer[i]);

  198.         if ((i+1)%8 == 0)
  199.         {
  200.             printf("\r\n");
  201.         }
  202.     }
  203. }
  204. /*!
  205. * @brief     Delay
  206. *
  207. * @param     count:  delay count
  208. *
  209. * @retval    None
  210. */
  211. void Delay(uint32_t count)
  212. {
  213.     uint16_t i = 0;

  214.     while (count--)
  215.     {
  216.         i = 7995;
  217.         while (i--);
  218.     }
  219. }

  220. #if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

  221. /*!
  222. * @brief       Redirect C Library function printf to serial port.
  223. *              After Redirection, you can use printf function.
  224. *
  225. * @param       ch:  The characters that need to be send.
  226. *
  227. * @param       *f:  pointer to a FILE that can recording all information
  228. *              needed to control a stream
  229. *
  230. * @retval      The characters that need to be send.
  231. *
  232. * @note
  233. */
  234. int fputc(int ch, FILE* f)
  235. {
  236.     /* send a byte of data to the serial port */
  237.     USART_TxData(DEBUG_USART, (uint8_t)ch);

  238.     /* wait for the data to be send */
  239.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  240.     return (ch);
  241. }

  242. #elif defined (__GNUC__)

  243. /*!
  244. * @brief       Redirect C Library function printf to serial port.
  245. *              After Redirection, you can use printf function.
  246. *
  247. * @param       ch:  The characters that need to be send.
  248. *
  249. * @retval      The characters that need to be send.
  250. *
  251. * @note
  252. */
  253. int __io_putchar(int ch)
  254. {
  255.     /* send a byte of data to the serial port */
  256.     USART_TxData(DEBUG_USART, ch);

  257.     /* wait for the data to be send */
  258.     while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

  259.     return ch;
  260. }

  261. /*!
  262. * @brief       Redirect C Library function printf to serial port.
  263. *              After Redirection, you can use printf function.
  264. *
  265. * @param       file:  Meaningless in this function.
  266. *
  267. * @param       *ptr:  Buffer pointer for data to be sent.
  268. *
  269. * @param       len:  Length of data to be sent.
  270. *
  271. * @retval      The characters that need to be send.
  272. *
  273. * @note
  274. */
  275. int _write(int file, char* ptr, int len)
  276. {
  277.         UNUSED(file);

  278.     int i;
  279.     for (i = 0; i < len; i++)
  280.     {
  281.         __io_putchar(*ptr++);
  282.     }

  283.     return len;
  284. }

  285. #else
  286. #warning Not supported compiler type
  287. #endif
SPI Flash 驱动.c
  1. /*!
  2. * @file        bsp_sdio.c
  3. *
  4. * @brief       SDIO board support package body
  5. *
  6. * @version     V1.0.0
  7. *
  8. * @date        2022-09-30
  9. *
  10. * @attention
  11. *
  12. *  Copyright (C) 2022 Geehy Semiconductor
  13. *
  14. *  You may not use this file except in compliance with the
  15. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  16. *
  17. *  The program is only for reference, which is distributed in the hope
  18. *  that it will be useful and instructional for customers to develop
  19. *  their software. Unless required by applicable law or agreed to in
  20. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  21. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  22. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  23. *  and limitations under the License.
  24. */

  25. /* Includes */
  26. #include "bsp_w25q16.h"

  27. /** @addtogroup Board
  28.   @{
  29. */

  30. /** @addtogroup Board_APM32E103_EVAL
  31.   @{
  32. */

  33. /** @defgroup APM32E103_EVAL_Fuctions
  34.   @{
  35.   */

  36. /*!
  37. * @brief       W25Q16 SPI Initialization
  38. *
  39. * @param       None
  40. *
  41. * @retval      None
  42. */
  43. void W25Q16_SPI_Init(void)
  44. {
  45.     GPIO_Config_T gpioConfig;
  46.     SPI_Config_T spiConfig;

  47.     /* Enable related Clock */
  48.     RCM_EnableAPB2PeriphClock(FLASH_SPI_BUS_CLK | FLASH_SPI_GPIO_CLK | FLASH_SPI_CS_GPIO_CLK |RCM_APB2_PERIPH_AFIO);
  49.    
  50.     GPIO_ConfigPinRemap(GPIO_REMAP_SWJ_JTAGDISABLE);

  51.     /* Configure FLASH_SPI pins: SCK */
  52.     gpioConfig.pin =  FLASH_SPI_SCK_PIN ;
  53.     gpioConfig.mode = GPIO_MODE_AF_PP;
  54.     gpioConfig.speed = GPIO_SPEED_50MHz;
  55.     GPIO_Config(FLASH_SPI_GPIO_PORT, &gpioConfig);

  56.     /* Configure FLASH_SPI pins: MOSI */
  57.     gpioConfig.pin = FLASH_SPI_MOSI_PIN;
  58.     GPIO_Config(FLASH_SPI_GPIO_PORT, &gpioConfig);

  59.     /* Configure FLASH_SPI pins: MISO */
  60.     gpioConfig.pin = FLASH_SPI_MISO_PIN;
  61.     gpioConfig.mode = GPIO_MODE_IN_FLOATING;
  62.     GPIO_Config(FLASH_SPI_GPIO_PORT, &gpioConfig);

  63.     /* Configure FLASH_SPI_CS_PIN pin: sFLASH Card CS pin */
  64.     gpioConfig.pin = FLASH_SPI_CS_PIN;
  65.     gpioConfig.mode = GPIO_MODE_OUT_PP;
  66.     GPIO_Config(FLASH_SPI_CS_GPIO_PORT, &gpioConfig);

  67.     /* Deselect the FLASH: Chip Select high */
  68.     FLASH_SPI_CS_SET();

  69.     /* SPI configuration */
  70.     spiConfig.direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
  71.     spiConfig.mode = SPI_MODE_MASTER;
  72.     spiConfig.length = SPI_DATA_LENGTH_8B;
  73.     spiConfig.polarity = SPI_CLKPOL_HIGH;
  74.     spiConfig.phase = SPI_CLKPHA_2EDGE;
  75.     spiConfig.nss = SPI_NSS_SOFT;
  76.     spiConfig.baudrateDiv = SPI_BAUDRATE_DIV_4;
  77.     spiConfig.firstBit = SPI_FIRSTBIT_MSB;
  78.     spiConfig.crcPolynomial =0;
  79.     SPI_Config(FLASH_SPI_BUS, &spiConfig);

  80.     /* Enable SPI  */
  81.     SPI_Enable(FLASH_SPI_BUS);
  82. }

  83. /*!
  84. * @brief       Erase Falsh Sector
  85. *
  86. * @param       SectorAddr:Sector Addr
  87. *
  88. * @retval      None
  89. */
  90. void W25Q16_EraseSector(uint32_t SectorAddr)
  91. {
  92.     /* Flash Write Enable  */
  93.     W25Q16_EnableFlashWrite();
  94.     W25Q16_WaitFlashWriteEnd();

  95.     /* Select the FLASH */
  96.     FLASH_SPI_CS_CLR();

  97.     /* send cmd */
  98.     W25Q16_SendByte(W25Q16_SECTOR_ERASE);

  99.     /* send Sector Addr */
  100.     W25Q16_SendByte((SectorAddr & 0xFF0000) >> 16);
  101.     W25Q16_SendByte((SectorAddr & 0xFF00) >> 8);
  102.     W25Q16_SendByte(SectorAddr & 0xFF);

  103.     /* Deselect the FLASH */
  104.     FLASH_SPI_CS_SET();

  105.     /* wait Falsh Erase end */
  106.     W25Q16_WaitFlashWriteEnd();
  107. }
  108. /**
  109.   * @brief  擦除FLASH扇区,整片擦除
  110.   * @param  无
  111.   * @retval 无
  112.   */
  113. void SPI_FLASH_BulkErase(void)
  114. {
  115.   /* 发送FLASH写使能命令 */
  116.   W25Q16_EnableFlashWrite();

  117.   /* 整块 Erase */
  118.   /* 选择FLASH: CS低电平 */
  119.   FLASH_SPI_CS_CLR();
  120.   /* 发送整块擦除指令*/
  121.   W25Q16_SendByte(W25Q16_CHIP_ERASE);
  122.   /* 停止信号 FLASH: CS 高电平 */
  123.   FLASH_SPI_CS_SET();

  124.   /* 等待擦除完毕*/
  125.   W25Q16_WaitFlashWriteEnd();
  126. }
  127. /*!
  128. * @brief       Flash Write Page
  129. *
  130. * @param       pBuffer: pointer to the Write buffer
  131. *
  132. * @param       WriteAddr: Write the flash Address
  133. *
  134. * @param       NumToWrite: the number of byte to write
  135. *
  136. * @retval      None
  137. */
  138. void W25Q16_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumToWrite)
  139. {
  140.     /* Enable Flash Write */
  141.     W25Q16_EnableFlashWrite();

  142.     /* Select the FLASH */
  143.     FLASH_SPI_CS_CLR();

  144.     /* W25Q16 Page Program */
  145.     W25Q16_SendByte(W25Q16_PAGE_PROGRAM);
  146.     W25Q16_SendByte((WriteAddr & 0xFF0000) >> 16);
  147.     W25Q16_SendByte((WriteAddr & 0xFF00) >> 8);
  148.     W25Q16_SendByte(WriteAddr & 0xFF);

  149.     if (NumToWrite > W25Q16_FLASH_PAGE_SIZE)
  150.     {
  151.         NumToWrite = W25Q16_FLASH_PAGE_SIZE;
  152.     }

  153.     /* Write data to flash*/
  154.                 while (NumToWrite--)
  155.                 {
  156.                         /* 发送当前要写入的字节数据 */
  157.                         W25Q16_SendByte(*pBuffer);
  158.                         /* 指向下一字节数据 */
  159.                         pBuffer++;
  160.                 }
  161.     /* Deselect the FLASH */
  162.     FLASH_SPI_CS_SET();

  163.     /* Wait Write End*/
  164.     W25Q16_WaitFlashWriteEnd();
  165. }

  166. /*!
  167. * @brief       Flash Write Buffer
  168. *
  169. * @param       pBuffer: pointer to the Write buffer
  170. *
  171. * @param       WriteAddr: Write the flash Address
  172. *
  173. * @param       NumToWrite: the number of byte to write
  174. *
  175. * @retval      None
  176. */
  177. void W25Q16_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumToWrite)
  178. {
  179.     uint8_t i = 0;
  180.     uint8_t PageNumber = 0;
  181.     uint8_t RemainNumber = 0;
  182.     uint8_t PageRemainNumber = 0;

  183.     /* complete Page need to write */
  184.     PageNumber =  NumToWrite / W25Q16_FLASH_PAGE_SIZE;

  185.     /* Remain byte */
  186.     RemainNumber = NumToWrite % W25Q16_FLASH_PAGE_SIZE;

  187.     /* if WriteAddr align */
  188.     if ((WriteAddr % W25Q16_FLASH_PAGE_SIZE) == 0)
  189.     {
  190.         /* NumToWrite < W25Q16_FLASH_PAGE_SIZE */
  191.         if (PageNumber == 0)
  192.         {
  193.             W25Q16_WritePage(pBuffer, WriteAddr, NumToWrite);
  194.         }
  195.         else
  196.         {
  197.             /* write complete Page */
  198.             for (i = 0; i < PageNumber; i++)
  199.             {
  200.                 W25Q16_WritePage(pBuffer, WriteAddr, W25Q16_FLASH_PAGE_SIZE);
  201.                 WriteAddr +=  W25Q16_FLASH_PAGE_SIZE;
  202.                 pBuffer += W25Q16_FLASH_PAGE_SIZE;
  203.             }

  204.             /* write remain data */
  205.             if (RemainNumber > 0)
  206.             {
  207.                 W25Q16_WritePage(pBuffer, WriteAddr, RemainNumber);
  208.             }
  209.         }
  210.     }
  211.     else
  212.     {
  213.         /* Write Address Page Remain Number */
  214.         PageRemainNumber = W25Q16_FLASH_PAGE_SIZE - (WriteAddr % W25Q16_FLASH_PAGE_SIZE);

  215.         /* NumToWrite < W25Q16_FLASH_PAGE_SIZE */
  216.         if (PageNumber == 0)
  217.         {
  218.             if (RemainNumber > PageRemainNumber)
  219.             {
  220.                 /* write all over the current page */
  221.                 W25Q16_WritePage(pBuffer, WriteAddr, PageRemainNumber);
  222.                 WriteAddr +=  PageRemainNumber;
  223.                 pBuffer += PageRemainNumber;

  224.                 RemainNumber = RemainNumber - PageRemainNumber;;

  225.                 /* write remain data */
  226.                 W25Q16_WritePage(pBuffer, WriteAddr, RemainNumber);
  227.             }
  228.             else
  229.             {
  230.                 W25Q16_WritePage(pBuffer, WriteAddr, RemainNumber);
  231.             }
  232.         }
  233.         else
  234.         {
  235.             /* write all over the current page */
  236.             W25Q16_WritePage(pBuffer, WriteAddr, PageRemainNumber);
  237.             WriteAddr +=  PageRemainNumber;
  238.             pBuffer += PageRemainNumber;

  239.             NumToWrite -= PageRemainNumber;
  240.             PageNumber =  NumToWrite / W25Q16_FLASH_PAGE_SIZE;
  241.             RemainNumber = NumToWrite % W25Q16_FLASH_PAGE_SIZE;

  242.             /* write complete Page */
  243.             for (i = 0; i < PageNumber; i++)
  244.             {
  245.                 W25Q16_WritePage(pBuffer, WriteAddr, W25Q16_FLASH_PAGE_SIZE);
  246.                 WriteAddr +=  W25Q16_FLASH_PAGE_SIZE;
  247.                 pBuffer += W25Q16_FLASH_PAGE_SIZE;
  248.             }

  249.             /* write remain data */
  250.             if (RemainNumber > 0)
  251.             {
  252.                 W25Q16_WritePage(pBuffer, WriteAddr, RemainNumber);
  253.             }
  254.         }
  255.     }
  256. }

  257. /*!
  258. * @brief       Flash Read Buffer
  259. *
  260. * @param       pBuffer: pointer to the read buffer
  261. *
  262. * @param       ReadAddr: read the flash Address
  263. *
  264. * @param       NumToWrite: the number of byte to read
  265. *
  266. * @retval      None
  267. */
  268. void W25Q16_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumToRead)
  269. {
  270.     uint16_t i = 0;

  271.     /* Select the FLASH */
  272.     FLASH_SPI_CS_CLR();

  273.     /* send read cmd */
  274.     W25Q16_SendByte(W25Q16_READ_DATA);
  275.     W25Q16_SendByte((ReadAddr & 0xFF0000) >> 16);
  276.     W25Q16_SendByte((ReadAddr& 0xFF00) >> 8);
  277.     W25Q16_SendByte(ReadAddr & 0xFF);

  278.     /* read data to flash*/
  279.     for (i = 0; i < NumToRead; i++)
  280.     {
  281.         *pBuffer = W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  282.         pBuffer++;
  283.     }

  284.     /* Deselect the FLASH */
  285.     FLASH_SPI_CS_SET();
  286. }


  287. /*!
  288. * @brief       Flash Read ID
  289. *
  290. * @param       None
  291. *
  292. * @retval      None
  293. */
  294. uint32_t W25Q16_ReadFlashID(void)
  295. {
  296.     uint32_t TempBuffer[3] = {0};
  297.     uint32_t FlashID = 0;

  298.     /* Select the FLASH */
  299.     FLASH_SPI_CS_CLR();

  300.     /* send read ID cmd */
  301.     W25Q16_SendByte(W25Q16_JEDEC_DEVICE_ID);
  302.     TempBuffer[0] = W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  303.     TempBuffer[1] = W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  304.     TempBuffer[2] = W25Q16_SendByte(W25Q16_DUMMY_BYTE);

  305.     /* Deselect the FLASH */
  306.     FLASH_SPI_CS_SET();

  307.     FlashID = (TempBuffer[0] << 16) | (TempBuffer[1] << 8) | TempBuffer[2];

  308.     return FlashID;
  309. }

  310. /*!
  311. * @brief       Read Flash DeviceID
  312. *
  313. * @param       None
  314. *
  315. * @retval      None
  316. */
  317. uint32_t W25Q16_ReadFlashDeviceID(void)
  318. {
  319.     uint32_t DeviceID = 0;

  320.     /* Select the FLASH */
  321.     FLASH_SPI_CS_CLR();

  322.     /* Send W25Q16 DeviceID cmd */
  323.     W25Q16_SendByte(W25Q16_DEVICE_ID);
  324.     W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  325.     W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  326.     W25Q16_SendByte(W25Q16_DUMMY_BYTE);

  327.     /* Read DeviceID from the FLASH */
  328.     DeviceID = W25Q16_SendByte(W25Q16_DUMMY_BYTE);

  329.     /* Deselect the FLASH */
  330.     FLASH_SPI_CS_SET();

  331.     return DeviceID;
  332. }

  333. /*!
  334. * @brief       SPI read Byte from flash
  335. *
  336. * @param       None
  337. *
  338. * @retval      None
  339. */
  340. uint8_t W25Q16_ReadByte(void)
  341. {
  342.     uint8_t temp = 0;

  343.     temp = W25Q16_SendByte(W25Q16_DUMMY_BYTE);

  344.     return temp;
  345. }

  346. /*!
  347. * @brief       SPI Send Byte to flash
  348. *
  349. * @param       None
  350. *
  351. * @retval      None
  352. */
  353. uint8_t W25Q16_SendByte(uint8_t data)
  354. {
  355.     /* SPI master send data */
  356.     while (SPI_I2S_ReadStatusFlag(FLASH_SPI_BUS, SPI_FLAG_TXBE) == RESET);

  357.     SPI_I2S_TxData(FLASH_SPI_BUS, data);

  358.     /* SPI slave receive data */
  359.     while (SPI_I2S_ReadStatusFlag(FLASH_SPI_BUS, SPI_FLAG_RXBNE) == RESET);

  360.     return SPI_I2S_RxData(FLASH_SPI_BUS);
  361. }

  362. /*!
  363. * @brief       Enable Flash Write
  364. *
  365. * @param       None
  366. *
  367. * @retval      None
  368. */
  369. void W25Q16_EnableFlashWrite(void)
  370. {
  371.     FLASH_SPI_CS_CLR();

  372.     /* send W25Q16 Write Enable cmd */
  373.     W25Q16_SendByte(W25Q16_WRITE_ENABLE);

  374.     FLASH_SPI_CS_SET();
  375. }

  376. /*!
  377. * @brief       Wait Flash Write End
  378. *
  379. * @param       None
  380. *
  381. * @retval      None
  382. */
  383. void W25Q16_WaitFlashWriteEnd(void)
  384. {
  385.     uint8_t RegStatus = 0;

  386.     FLASH_SPI_CS_CLR();

  387.     /* send Read W25Q16 Status cmd */
  388.     W25Q16_SendByte(W25Q16_READ_STATUS_REG);

  389.     do
  390.     {
  391.         /* Read W25Q16 Status Reg */
  392.         RegStatus = W25Q16_SendByte(W25Q16_DUMMY_BYTE);
  393.     }
  394.     while ((RegStatus & W25Q16_WIP_FLAG) != 0);

  395.     FLASH_SPI_CS_SET();
  396. }

  397. /*!
  398. * @brief       Flash Into PowerDown
  399. *
  400. * @param       None
  401. *
  402. * @retval      None
  403. */
  404. void W25Q16_IntoPowerDown(void)
  405. {
  406.     FLASH_SPI_CS_CLR();

  407.     /* send PowerDown cmd*/
  408.     W25Q16_SendByte(W25Q16_POWER_DOWN);

  409.     FLASH_SPI_CS_SET();
  410. }

  411. /**@} end of group APM32E103_EVAL_Functions */
  412. /**@} end of group Board_APM32E103_EVAL */
  413. /**@} end of group Board */
SPI Flash 驱动.h
  1. /* Define to prevent recursive inclusion */
  2. #ifndef __BSP_SPI_FLASH_H
  3. #define __BSP_SPI_FLASH_H

  4. /* Includes */
  5. #include "main.h"

  6. /* W25Q16 */
  7. #define W25Q16_FLASH_ID                   0xEF4015
  8. #define W25Q16_FLASH_PAGE_SIZE            256

  9. #define W25Q16_FLASH_WRITE_ADDR           0x00000
  10. #define W25Q16_FLASH_READ_ADDR            W25Q16_FLASH_WRITE_ADDR

  11. /* W25Q16 CMD */
  12. #define W25Q16_WRITE_ENABLE               0x06
  13. #define W25Q16_WRITE_DISABLE              0x04
  14. #define W25Q16_READ_STATUS_REG            0x05
  15. #define W25Q16_WRITE_STATUS_REG           0x01
  16. #define W25Q16_READ_DATA                  0x03
  17. #define W25Q16_FAST_READ_DATA             0x0B
  18. #define W25Q16_FAST_RAED_DUAL             0x3B
  19. #define W25Q16_PAGE_PROGRAM               0x02
  20. #define W25Q16_BLOCK_ERASE                0xD8
  21. #define W25Q16_SECTOR_ERASE               0x20
  22. #define W25Q16_CHIP_ERASE                 0xC7
  23. #define W25Q16_POWER_DOWN                 0xB9
  24. #define W25Q16_RELEASE_POWER_DOWN         0xAB
  25. #define W25Q16_DEVICE_ID                  0xAB
  26. #define W25Q16_MANUFACT_DEVICE_ID         0x90
  27. #define W25Q16_JEDEC_DEVICE_ID            0x9F
  28. #define W25Q16_WIP_FLAG                   0x01
  29. #define W25Q16_DUMMY_BYTE                 0xFF

  30. /* FLASH CS */
  31. #define FLASH_SPI_BUS                     SPI1
  32. #define FLASH_SPI_BUS_CLK                 RCM_APB2_PERIPH_SPI1

  33. #define FLASH_SPI_MOSI_PIN                GPIO_PIN_7
  34. #define FLASH_SPI_MISO_PIN                GPIO_PIN_6
  35. #define FLASH_SPI_SCK_PIN                 GPIO_PIN_5
  36. #define FLASH_SPI_GPIO_CLK                RCM_APB2_PERIPH_GPIOA
  37. #define FLASH_SPI_GPIO_PORT               GPIOA

  38. #define FLASH_SPI_CS_PIN                  GPIO_PIN_4
  39. #define FLASH_SPI_CS_GPIO_CLK             RCM_APB2_PERIPH_GPIOA
  40. #define FLASH_SPI_CS_GPIO_PORT            GPIOA
  41.                                        
  42. //#define FLASH_SPI_MOSI_SOURCE             GPIO_PIN_SOURCE_15
  43. //#define FLASH_SPI_MISO_SOURCE             GPIO_PIN_SOURCE_14
  44. //#define FLASH_SPI_SCK_SOURCE              GPIO_PIN_SOURCE_13
  45. //#define FLASH_SPI_CS_SOURCE               GPIO_PIN_SOURCE_12
  46. //#define FLASH_SPI_GPIO_AF                 GPIO_AF_PIN1
  47.                                        
  48. #define FLASH_SPI_MOSI_CLR()              GPIO_ResetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_MOSI_PIN)
  49. #define FLASH_SPI_MOSI_SET()              GPIO_SetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_MOSI_PIN)
  50.                                        
  51. #define FLASH_SPI_MISO_CLR()              GPIO_ResetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_MISO_PIN)
  52. #define FLASH_SPI_MISO_SET()              GPIO_SetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_MISO_PIN)
  53.                                        
  54. #define FLASH_SPI_SCK_CLR()               GPIO_ResetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_SCK_PIN)
  55. #define FLASH_SPI_SCK_SET()               GPIO_SetBit(FLASH_SPI_GPIO_PORT, FLASH_SPI_SCK_PIN)
  56.                                        
  57. #define FLASH_SPI_CS_CLR()                GPIO_ResetBit(FLASH_SPI_CS_GPIO_PORT, FLASH_SPI_CS_PIN)
  58. #define FLASH_SPI_CS_SET()                GPIO_SetBit(FLASH_SPI_CS_GPIO_PORT, FLASH_SPI_CS_PIN)

  59. /**@} end of group APM32E103_EVAL_Macros*/

  60. /** @defgroup APM32E103_EVAL_Structures Structures
  61.   @{
  62.   */

  63. typedef struct {
  64.     uint32_t deviceID;
  65.     uint32_t flashID;
  66. } W25Q16_INFO_T;

  67. /**@} end of group APM32E103_EVAL_Structures*/

  68. /** @defgroup APM32E103_EVAL_Functions Functions
  69.   @{
  70.   */

  71. void W25Q16_IntoPowerDown(void);
  72. uint8_t W25Q16_SendByte(uint8_t byte);
  73. uint8_t W25Q16_ReadByte(void);
  74. void W25Q16_SPI_Init(void);
  75. void W25Q16_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumToWrite);
  76. void W25Q16_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumToWrite);
  77. void W25Q16_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumToRead);
  78. uint32_t W25Q16_ReadFlashID(void);
  79. uint32_t W25Q16_ReadFlashDeviceID(void);
  80. void W25Q16_EnableFlashWrite(void);
  81. void W25Q16_WaitFlashWriteEnd(void);
  82. void W25Q16_EraseSector(uint32_t SectorAddr);
  83. void SPI_FLASH_BulkErase(void);
  84. #endif /* __BSP_SPI_FLASH_H */


慢动作 发表于 2025-6-19 00:50 | 显示全部楼层
在命令 0x9F 发出后,应在 MISO 上看到连续 3 字节回应
寂静小夜曲 发表于 2025-6-19 18:19 | 显示全部楼层
也是啊!
操作SPI flash的读写命令可以通过逻辑分析仪直接显示出来!
我之前一直使用回读chipid做测试
OceanGaze 发表于 2025-7-2 23:52 | 显示全部楼层
它这个SPI的硬件片选配置是怎么个驱动的方法啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

58

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

32

主题

58

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部