[APM32E0] APM32E030的SPI驱动

[复制链接]
263|4
口天土立口 发表于 2025-9-6 15:04 | 显示全部楼层 |阅读模式
, , spi驱动, gp,
本帖最后由 口天土立口 于 2025-9-7 18:34 编辑

1715568bbdd27052b1.png

APM32E030支持SPI通信;

本次代码基于开发板:APM32E030R Micro-EVB
IO:
      CS     -> PA4
      SCK   -> PA5
      MISO -> PA6
      MOSI -> PA7

SPI初始化代码如下:
  1. /* 初始化SPI引脚 */
  2. static void bsp_spi_gpio_init(void)
  3. {
  4.     GPIO_Config_T gpioConfig;
  5.    
  6.     RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
  7.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);   
  8.     GPIO_ConfigStructInit(&gpioConfig);
  9.    
  10.     /*
  11.      * CS   -> PA4
  12.      * SCK  -> PA5
  13.      * MISO -> PA6
  14.      * MOSI -> PA7
  15.      */
  16.     gpioConfig.pin     = GPIO_PIN_4;
  17.     gpioConfig.mode    = GPIO_MODE_AF;
  18.     gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  19.     gpioConfig.speed   = GPIO_SPEED_50MHz;
  20.     gpioConfig.pupd    = GPIO_PUPD_PU;          /* CS低电平有效,默认拉高 */
  21.     GPIO_Config(GPIOA, &gpioConfig);
  22.     gpioConfig.pupd    = GPIO_PUPD_PD;          /* SPI模式0,SCK默认为低电平 */
  23.     gpioConfig.pin     = GPIO_PIN_5;
  24.     GPIO_Config(GPIOA, &gpioConfig);
  25.     gpioConfig.pupd    = GPIO_PUPD_PU;
  26.     gpioConfig.pin     = GPIO_PIN_7;
  27.     GPIO_Config(GPIOA, &gpioConfig);
  28.     gpioConfig.pupd    = GPIO_PUPD_NO;
  29.     gpioConfig.pin     = GPIO_PIN_6;
  30.     GPIO_Config(GPIOA, &gpioConfig);
  31.    
  32.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_4, GPIO_AF_PIN0);
  33.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_PIN0);
  34.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
  35.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);   
  36. }
  1. /* 初始化SPI */
  2. void bsp_spi_init(void)
  3. {
  4.     SPI_Config_T spiConfig;
  5.    
  6.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
  7.     bsp_spi_gpio_init();
  8.     SPI_ConfigStructInit(&spiConfig);
  9.    
  10.     SPI_Reset(SPI1);
  11.     spiConfig.mode          = SPI_MODE_MASTER;
  12.     spiConfig.length        = SPI_DATA_LENGTH_8B;
  13.     spiConfig.phase         = SPI_CLKPHA_1EDGE;     /* MODE0 */
  14.     spiConfig.polarity      = SPI_CLKPOL_LOW;
  15.     spiConfig.slaveSelect   = SPI_SSC_ENABLE;
  16.     spiConfig.firstBit      = SPI_FIRST_BIT_MSB;
  17.     spiConfig.direction     = SPI_DIRECTION_2LINES_FULLDUPLEX;
  18.     spiConfig.baudrateDiv   = SPI_BAUDRATE_DIV_4;
  19.     spiConfig.crcPolynomial = 7;
  20.     SPI_Config(SPI1, &spiConfig);
  21.     SPI_EnableInternalSlave(SPI1);
  22.     SPI_ConfigFIFOThreshold(SPI1, SPI_RXFIFO_QUARTER);
  23.     SPI_DisableSSoutput(SPI1);
  24.     SPI_Enable(SPI1);
  25. }


W25Q32驱动代码:
  1. /* 最大容量 4MB */
  2. #define W25Q32_MAX_CAPACITY             ((uint32_t)0x400000)
  3. /* 扇区大小 4KB */  
  4. #define W25Q32_SECTOR_SIZE              ((uint16_t)0x1000)
  5. /* 块大小 64KB */  
  6. #define W25Q32_BLOCK_SIZE               ((uint16_t)0x10000)
  7. /* 页编程大小 */
  8. #define W25Q32_PAGE_PROGRAM_SIZE        ((uint16_t)0x100)
  9. /* 制造商ID */
  10. #define W25Q32_MANUFACTURE_ID           ((uint32_t)0xEF)
  11. /* JEDEC ID */  
  12. #define W25Q32_JEDEC_ID                 ((W25Q32_MANUFACTURE_ID << 16) | 0x4016)
  13. /* 制造商设备ID */
  14. #define W25Q32_MANUFACTURE_DEVICE_ID    ((W25Q32_MANUFACTURE_ID << 8) | (uint8_t)0x15)
  15. /* 超时 */
  16. #define W25Q32_TIMEOUT                  ((uint32_t)0xFF000)
  1. /*
  2. * @brief       初始化
  3. *
  4. * @param       None
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_init(void)
  10. {
  11.     uint32_t JEDEC_id = 0;
  12.     uint16_t Manufacturer_id = 0;
  13.    
  14.     bsp_spi_init();
  15.     /* JEDEC ID */
  16.     if ((bsp_w25q32_read_JEDEC_id(&JEDEC_id) != 0) || (JEDEC_id != W25Q32_JEDEC_ID)) {
  17.         return -1;
  18.     }
  19.     /* 制造商设备ID */
  20.     if ((bsp_w25q32_read_manufacturer_devid(&Manufacturer_id) != 0) || (Manufacturer_id != W25Q32_MANUFACTURE_DEVICE_ID)) {
  21.         return -1;
  22.     }
  23.    
  24.     return 0;
  25. }
  1. /*
  2. * @brief       写寄存器
  3. *
  4. * @param       reg: 寄存器
  5. *              data: 寄存器数据缓存
  6. *              data_num: 寄存器数据数量
  7. *              data_ex: 额外数据缓存
  8. *              data_ex_num: 额外数据数量
  9. *
  10. * @retval      0: 成功; -1: 失败
  11. *
  12. */
  13. static int8_t bsp_w25q32_write_reg(uint8_t reg, uint8_t *data, uint32_t data_num, uint8_t *data_ex, uint32_t data_ex_num)
  14. {
  15.     uint32_t timeout = 0;
  16.     uint32_t i = 0;
  17.    
  18.     /* 等待空闲 */
  19.     timeout = W25Q32_TIMEOUT;
  20.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_BUSY) == SET) {
  21.         timeout--;
  22.         if (timeout == 0) {
  23.             return -1;
  24.         }
  25.     }
  26.    
  27.     /* 等待发送为空 */
  28.     timeout = W25Q32_TIMEOUT;
  29.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  30.         timeout--;
  31.         if (timeout == 0) {
  32.             return -1;
  33.         }
  34.     }
  35.    
  36.     SPI_EnableSSoutput(SPI1);
  37.    
  38.     /* 发送寄存器 */
  39.     SPI_TxData8(SPI1, reg);
  40.     /* 等待发送完成 */
  41.     timeout = W25Q32_TIMEOUT;
  42.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  43.         timeout--;
  44.         if (timeout == 0) {
  45.             SPI_DisableSSoutput(SPI1);
  46.             return -1;
  47.         }
  48.     }
  49.     /* 获取接收数据 */
  50.     (void)SPI_RxData8(SPI1);
  51.         
  52.     /* 发送数据 */
  53.     while (i < data_num) {
  54.         SPI_TxData8(SPI1, data[i++]);
  55.         /* 等待发送完成 */
  56.         timeout = W25Q32_TIMEOUT;
  57.         while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  58.             timeout--;
  59.             if (timeout == 0) {
  60.                 SPI_DisableSSoutput(SPI1);
  61.                 return -1;
  62.             }
  63.         }
  64.         /* 获取接收数据 */
  65.         (void)SPI_RxData8(SPI1);
  66.     }
  67.      
  68.     /* 发送数据 */
  69.     i = 0;
  70.     while (i < data_ex_num) {
  71.         SPI_TxData8(SPI1, data_ex[i++]);
  72.         /* 等待发送完成 */
  73.         timeout = W25Q32_TIMEOUT;
  74.         while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  75.             timeout--;
  76.             if (timeout == 0) {
  77.                 SPI_DisableSSoutput(SPI1);
  78.                 return -1;
  79.             }
  80.         }
  81.         /* 获取接收数据 */
  82.         (void)SPI_RxData8(SPI1);
  83.     }
  84.    
  85.     SPI_DisableSSoutput(SPI1);
  86.    
  87.     return 0;
  88. }
  1. /*
  2. * @brief       读寄存器
  3. *
  4. * @param       reg: 寄存器
  5. *              w_data: 写寄存器数据缓存
  6. *              w_data_num: 写寄存器数据数量
  7. *              r_data: 读数据缓存
  8. *              r_data_num: 读数据数量
  9. *
  10. * @retval      0: 成功; -1: 失败
  11. *
  12. */
  13. static int8_t bsp_w25q32_read_reg(uint8_t reg, uint8_t *w_data, uint32_t w_data_num, uint8_t *r_data, uint32_t r_data_num)
  14. {
  15.     uint32_t timeout = 0;
  16.     uint32_t i = 0;
  17.    
  18.     /* 等待空闲 */
  19.     timeout = W25Q32_TIMEOUT;
  20.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_BUSY) == SET) {
  21.         timeout--;
  22.         if (timeout == 0) {
  23.             return -1;
  24.         }
  25.     }
  26.    
  27.     /* 等待发送为空 */
  28.     timeout = W25Q32_TIMEOUT;
  29.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  30.         timeout--;
  31.         if (timeout == 0) {
  32.             return -1;
  33.         }
  34.     }
  35.    
  36.     SPI_EnableSSoutput(SPI1);
  37.    
  38.     /* 发送寄存器 */
  39.     SPI_TxData8(SPI1, reg);
  40.     /* 等待发送完成 */
  41.     timeout = W25Q32_TIMEOUT;
  42.     while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  43.         timeout--;
  44.         if (timeout == 0) {
  45.             SPI_DisableSSoutput(SPI1);
  46.             return -1;
  47.         }
  48.     }
  49.     /* 获取接收数据 */
  50.     (void)SPI_RxData8(SPI1);
  51.    
  52.     /* 发送数据 */
  53.     i = 0;
  54.     while (i < w_data_num) {
  55.         SPI_TxData8(SPI1, w_data[i++]);
  56.         /* 等待发送完成 */
  57.         timeout = W25Q32_TIMEOUT;
  58.         while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  59.             timeout--;
  60.             if (timeout == 0) {
  61.                 SPI_DisableSSoutput(SPI1);
  62.                 return -1;
  63.             }
  64.         }
  65.         /* 获取接收数据 */
  66.         (void)SPI_RxData8(SPI1);
  67.     }
  68.         
  69.     /* 接收数据 */
  70.     i = 0;
  71.     while (i < r_data_num) {
  72.         /* 制造时钟信号 */
  73.         SPI_TxData8(SPI1, 0xFF);
  74.         /* 等待发送完成 */
  75.         timeout = W25Q32_TIMEOUT;
  76.         while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
  77.             timeout--;
  78.             if (timeout == 0) {
  79.                 SPI_DisableSSoutput(SPI1);
  80.                 return -1;
  81.             }
  82.         }
  83.         /* 获取接收数据 */
  84.         r_data[i++] = SPI_RxData8(SPI1);
  85.     }
  86.    
  87.     SPI_DisableSSoutput(SPI1);
  88.    
  89.     return 0;
  90. }
  1. /*
  2. * @brief       读状态1
  3. *
  4. * @param       status1: 状态
  5. *
  6. * @retval      None
  7. *
  8. */
  9. static int8_t bsp_w25q32_read_status1(uint8_t *status1)
  10. {
  11.     return bsp_w25q32_read_reg(0x05, NULL, 0, status1, 1);
  12. }
  1. /*
  2. * @brief       检查忙
  3. *
  4. * @param       status1: 状态
  5. *
  6. * @retval      0: 非忙; 1: 忙; -1: 失败
  7. *
  8. */
  9. static int8_t bsp_w25q32_is_busy(void)
  10. {
  11.     uint8_t status1 = 0;
  12.    
  13.     if (bsp_w25q32_read_reg(0x05, NULL, 0, &status1, 1) == 0) {
  14.         if ((status1 & 0x01) == 0) {
  15.             return 0;   /* 非忙 */
  16.         } else {
  17.             return 1;   /* 忙 */
  18.         }
  19.     }
  20.    
  21.     return -1;  /* 异常 */
  22. }
  1. /*
  2. * @brief       写使能
  3. *
  4. * @param       status1: 状态
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. static int8_t bsp_w25q32_write_enable(void)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t status1 = 0;
  13.    
  14.     /* 等待空闲 */
  15.     timeout = W25Q32_TIMEOUT;
  16.     while (bsp_w25q32_is_busy() != 0) {
  17.         timeout--;
  18.         if (timeout == 0) {
  19.             return 0;
  20.         }
  21.     }
  22.    
  23.     if (bsp_w25q32_write_reg(0x06, NULL, 0, NULL, 0) == 0) {        
  24.         /* 检查忙 */
  25.         do {
  26.             if (bsp_w25q32_read_status1(&status1) == 0) {
  27.                 if ((status1 & 0x01) == 0) {
  28.                     if ((status1 & 0x02) != 0) {
  29.                         return 0;   /* 写使能成功 */
  30.                     }
  31.                     return -1;   /* 写使能失败 */
  32.                 } else {
  33.                     continue;   /* 忙 */
  34.                 }
  35.             } else {
  36.                 return -1;   /* 异常 */
  37.             }
  38.         } while (1);
  39.     }
  40.    
  41.     return -1;
  42. }
  1. /*
  2. * @brief       读数据
  3. *
  4. * @param       addr: 数据地址
  5. *              buf: 数据缓存
  6. *              data_size: 数据数量
  7. *
  8. * @retval      0: 失败; 其他: 数据数量
  9. *
  10. */
  11. uint32_t bsp_w25q32_read_data(uint32_t addr, uint8_t *buf, uint32_t data_size)
  12. {
  13.     uint8_t w_data[3] = {0};
  14.     int8_t status1 = 0;
  15.     uint32_t timeout = 0;
  16.    
  17.     /* 检查入参 */
  18.     if ((data_size == 0) || (buf == NULL) || (addr >= W25Q32_MAX_CAPACITY) || ((addr + data_size) > W25Q32_MAX_CAPACITY)) {
  19.         return 0;
  20.     }
  21.    
  22.     /* 等待空闲 */
  23.     timeout = W25Q32_TIMEOUT;
  24.     while (bsp_w25q32_is_busy() != 0) {
  25.         timeout--;
  26.         if (timeout == 0) {
  27.             return 0;
  28.         }
  29.     }
  30.    
  31.     w_data[0] = (addr >> 16) & 0xFF;
  32.     w_data[1] = (addr >> 8) & 0xFF;
  33.     w_data[2] = addr & 0xFF;
  34.     if (bsp_w25q32_read_reg(0x03, w_data, 3, buf, data_size) == 0) {
  35.         /* 检查忙 */
  36.         do {
  37.             status1 = bsp_w25q32_is_busy();
  38.             if (status1 == 0) {
  39.                 return data_size;
  40.             } else if (status1 == -1) {
  41.                 break;
  42.             }
  43.         } while (1);
  44.     }
  45.    
  46.     return 0;
  47. }
  1. /*
  2. * @brief       写数据
  3. *
  4. * @param       addr: 数据地址
  5. *              buf: 数据缓存
  6. *              data_size: 数据数量
  7. *
  8. * @retval      0: 失败; 其他: 数据数量
  9. *
  10. */
  11. uint32_t bsp_w25q32_write_data(uint32_t addr, uint8_t *buf, uint32_t data_size)
  12. {
  13.     uint32_t timeout = 0;
  14.     uint8_t w_data[3] = {0};
  15.     int8_t status1 = 0;
  16.     uint16_t write_bytes = 0;
  17.     uint16_t current_page_write_size = 0;       /* 当前页写大小 */
  18.         
  19.     /* 检查入参 */
  20.     if ((data_size == 0) || (buf == NULL) || (addr >= W25Q32_MAX_CAPACITY) || ((addr + data_size) > W25Q32_MAX_CAPACITY)) {
  21.         return 0;
  22.     }
  23.         
  24.     do {
  25.         /* 单页写数据超长将回环覆盖 */
  26.         current_page_write_size = W25Q32_PAGE_PROGRAM_SIZE - (addr % W25Q32_PAGE_PROGRAM_SIZE);
  27.         current_page_write_size = (current_page_write_size <= (data_size - write_bytes)) ? current_page_write_size : (data_size - write_bytes);
  28.         
  29.         /* 等待空闲 */
  30.         timeout = W25Q32_TIMEOUT;
  31.         while (bsp_w25q32_is_busy() != 0) {
  32.             timeout--;
  33.             if (timeout == 0) {
  34.                 return 0;
  35.             }
  36.         }
  37.         
  38.         if (bsp_w25q32_write_enable() != 0) {
  39.             return 0;
  40.         }
  41.             
  42.         w_data[0] = (addr >> 16) & 0xFF;
  43.         w_data[1] = (addr >> 8) & 0xFF;
  44.         w_data[2] = addr & 0xFF;
  45.         if (bsp_w25q32_write_reg(0x02, w_data, 3, &buf[write_bytes], current_page_write_size) == 0) {
  46.             /* 检查忙 */
  47.             do {
  48.                 status1 = bsp_w25q32_is_busy();
  49.                 if (status1 == 0) {
  50.                     write_bytes += current_page_write_size;
  51.                     addr += current_page_write_size;
  52.                     break;
  53.                 } else if (status1 == -1) {
  54.                     break;
  55.                 }
  56.             } while (1);
  57.         } else {
  58.             break;
  59.         }
  60.     } while (write_bytes < data_size);
  61.    
  62.     return write_bytes;
  63. }
  1. /*
  2. * @brief       扇区擦除
  3. *
  4. * @param       addr: 数据地址
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_sector_erase(uint32_t addr)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t w_data[3] = {0};
  13.     int8_t status1 = 0;
  14.    
  15.     /* 4KB对齐 */
  16.     addr = addr & (~0xFFFU);
  17.    
  18.     /* 等待空闲 */
  19.     timeout = W25Q32_TIMEOUT;
  20.     while (bsp_w25q32_is_busy() != 0) {
  21.         timeout--;
  22.         if (timeout == 0) {
  23.             return 0;
  24.         }
  25.     }
  26.    
  27.     if (bsp_w25q32_write_enable() != 0) {
  28.         return -1;
  29.     }
  30.         
  31.     w_data[0] = (addr >> 16) & 0xFF;
  32.     w_data[1] = (addr >> 8) & 0xFF;
  33.     w_data[2] = addr & 0xFF;
  34.     if (bsp_w25q32_write_reg(0x20, w_data, 3, NULL, 0) == 0) {
  35.         /* 检查忙 */
  36.         do {
  37.             status1 = bsp_w25q32_is_busy();
  38.             if (status1 == 0) {
  39.                 return 0;
  40.             } else if (status1 == -1) {
  41.                 break;
  42.             }
  43.         } while (1);
  44.     }
  45.    
  46.     return -1;
  47. }
  1. /*
  2. * @brief       块32KB擦除
  3. *
  4. * @param       addr: 数据地址
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_block_32kb_erase(uint32_t addr)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t w_data[3] = {0};
  13.     int8_t status1 = 0;
  14.    
  15.     /* 32KB对齐 */
  16.     addr = addr & (~0x7FFFU);
  17.    
  18.     /* 等待空闲 */
  19.     timeout = W25Q32_TIMEOUT;
  20.     while (bsp_w25q32_is_busy() != 0) {
  21.         timeout--;
  22.         if (timeout == 0) {
  23.             return 0;
  24.         }
  25.     }
  26.    
  27.     if (bsp_w25q32_write_enable() != 0) {
  28.         return -1;
  29.     }
  30.         
  31.     w_data[0] = (addr >> 16) & 0xFF;
  32.     w_data[1] = (addr >> 8) & 0xFF;
  33.     w_data[2] = addr & 0xFF;
  34.     if (bsp_w25q32_write_reg(0x52, w_data, 3, NULL, 0) == 0) {
  35.         /* 检查忙 */
  36.         do {
  37.             status1 = bsp_w25q32_is_busy();
  38.             if (status1 == 0) {
  39.                 return 0;
  40.             } else if (status1 == -1) {
  41.                 break;
  42.             }
  43.         } while (1);
  44.     }
  45.    
  46.     return -1;
  47. }
  1. /*
  2. * @brief       块64KB擦除
  3. *
  4. * @param       addr: 数据地址
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_block_64kb_erase(uint32_t addr)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t w_data[3] = {0};
  13.     int8_t status1 = 0;
  14.    
  15.     /* 64KB对齐 */
  16.     addr = addr & (~0xFFFFU);
  17.    
  18.     /* 等待空闲 */
  19.     timeout = W25Q32_TIMEOUT;
  20.     while (bsp_w25q32_is_busy() != 0) {
  21.         timeout--;
  22.         if (timeout == 0) {
  23.             return 0;
  24.         }
  25.     }
  26.    
  27.     if (bsp_w25q32_write_enable() != 0) {
  28.         return -1;
  29.     }
  30.         
  31.     w_data[0] = (addr >> 16) & 0xFF;
  32.     w_data[1] = (addr >> 8) & 0xFF;
  33.     w_data[2] = addr & 0xFF;
  34.     if (bsp_w25q32_write_reg(0xD8, w_data, 3, NULL, 0) == 0) {
  35.         /* 检查忙 */
  36.         do {
  37.             status1 = bsp_w25q32_is_busy();
  38.             if (status1 == 0) {
  39.                 return 0;
  40.             } else if (status1 == -1) {
  41.                 break;
  42.             }
  43.         } while (1);
  44.     }
  45.    
  46.     return -1;
  47. }
  1. /*
  2. * @brief       整片擦除
  3. *
  4. * @param       None
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_chip_erase(void)
  10. {
  11.     uint32_t timeout = 0;
  12.     int8_t status1 = 0;
  13.    
  14.     /* 等待空闲 */
  15.     timeout = W25Q32_TIMEOUT;
  16.     while (bsp_w25q32_is_busy() != 0) {
  17.         timeout--;
  18.         if (timeout == 0) {
  19.             return 0;
  20.         }
  21.     }
  22.    
  23.     if (bsp_w25q32_write_enable() != 0) {
  24.         return -1;
  25.     }
  26.    
  27.     if (bsp_w25q32_write_reg(0x60, NULL, 0, NULL, 0) == 0) {
  28.         /* 检查忙 */
  29.         do {
  30.             status1 = bsp_w25q32_is_busy();
  31.             if (status1 == 0) {
  32.                 return 0;
  33.             } else if (status1 == -1) {
  34.                 break;
  35.             }
  36.         } while (1);
  37.     }
  38.    
  39.     return -1;
  40. }
  1. /*
  2. * @brief       复位
  3. *
  4. * @param       None
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_reset_device(void)
  10. {
  11.     uint8_t w_data = 0x99;
  12.     int8_t status1 = 0;
  13.    
  14.     if (bsp_w25q32_write_reg(0x66, &w_data, 1, NULL, 0) == 0) {
  15.         /* 检查忙 */
  16.         do {
  17.             status1 = bsp_w25q32_is_busy();
  18.             if (status1 == 0) {
  19.                 return 0;
  20.             } else if (status1 == -1) {
  21.                 break;
  22.             }
  23.         } while (1);
  24.     }
  25.    
  26.     return -1;
  27. }
  1. /*
  2. * @brief       读制造商设备ID
  3. *
  4. * @param       id: 制造商设备ID
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_read_manufacturer_devid(uint16_t *id)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t w_data[3] = {0, 0, 0};
  13.     uint8_t r_data[2] = {0};
  14.    
  15.     /* 等待空闲 */
  16.     timeout = W25Q32_TIMEOUT;
  17.     while (bsp_w25q32_is_busy() != 0) {
  18.         timeout--;
  19.         if (timeout == 0) {
  20.             return 0;
  21.         }
  22.     }
  23.    
  24.     if (bsp_w25q32_read_reg(0x90, w_data, 3, r_data, 2) == 0) {
  25.         *id = (((uint16_t)r_data[0]) << 8) + r_data[1];
  26.     } else {
  27.         return -1;
  28.     }
  29.    
  30.     return 0;
  31. }
  1. /*
  2. * @brief       读 JEDEC ID
  3. *
  4. * @param       id: JEDEC ID
  5. *
  6. * @retval      0: 成功; -1: 失败
  7. *
  8. */
  9. int8_t bsp_w25q32_read_JEDEC_id(uint32_t *id)
  10. {
  11.     uint32_t timeout = 0;
  12.     uint8_t r_data[3] = {0};
  13.    
  14.     /* 等待空闲 */
  15.     timeout = W25Q32_TIMEOUT;
  16.     while (bsp_w25q32_is_busy() != 0) {
  17.         timeout--;
  18.         if (timeout == 0) {
  19.             return 0;
  20.         }
  21.     }
  22.    
  23.     if (bsp_w25q32_read_reg(0x9F, NULL, 0, r_data, 3) == 0) {
  24.         *id = (((uint32_t)r_data[0]) << 16) + (((uint16_t)r_data[1]) << 8) + r_data[2];
  25.     } else {
  26.         return -1;
  27.     }
  28.    
  29.     return 0;
  30. }


测试代码如下:
  1. #define BUF_SIZE    (4096)
  2. #define TEST_4KB    (0x1000)
  3. uint8_t test_buf[BUF_SIZE];
  4. uint32_t test_addr = 0;
  5. uint32_t i = 0;
  6. int8_t result = 0;
  7. uint32_t num_index = 0;

  8. // 应用初始化
  9. void app_init(void)
  10. {
  11.     bsp_w25q32_init();
  12.    
  13.     /* 4KB测试 */
  14.     num_index = 0;
  15.     result = 0;
  16.     do {
  17.         /* 1.扇区擦除 */
  18.         if (bsp_w25q32_sector_erase(test_addr) == 0) {
  19.             /* 回读检查 */
  20.             memset(test_buf, 0, sizeof(test_buf));
  21.             if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
  22.                 for (i = 0; i < TEST_4KB; i++) {
  23.                     if (test_buf[i] != 0xFF) {
  24.                         result = -1;
  25.                         break;
  26.                     }
  27.                 }
  28.                 if (result != 0) {
  29.                     break;
  30.                 }
  31.                
  32.                 /* 2.写新数据 */
  33.                 num_index += 10;
  34.                 for (i = 0; i < TEST_4KB; i++) {
  35.                     test_buf[i] = num_index + i;
  36.                 }
  37.                 if (bsp_w25q32_write_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
  38.                     /* 回读检查 */
  39.                     memset(test_buf, 0, sizeof(test_buf));
  40.                     if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
  41.                         for (i = 0; i < TEST_4KB; i++) {
  42.                             if (test_buf[i] != (uint8_t)(num_index + i)) {
  43.                                 result = -1;
  44.                                 break;
  45.                             }
  46.                         }
  47.                         if (result != 0) {
  48.                             break;
  49.                         }
  50.                         
  51.                         /* 3.擦除数据 */
  52.                         if (bsp_w25q32_sector_erase(test_addr) == 0) {
  53.                             /* 回读检查 */
  54.                             memset(test_buf, 0, sizeof(test_buf));
  55.                             if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
  56.                                 for (i = 0; i < TEST_4KB; i++) {
  57.                                     if (test_buf[i] != 0xFF) {
  58.                                         result = -1;
  59.                                         break;
  60.                                     }
  61.                                 }
  62.                             } else {
  63.                                 result = -1;
  64.                                 break;
  65.                             }
  66.                         } else {
  67.                             result = -1;
  68.                             break;
  69.                         }
  70.                     } else {
  71.                         result = -1;
  72.                         break;
  73.                     }
  74.                 } else {
  75.                     result = -1;
  76.                     break;
  77.                 }
  78.             } else {
  79.                 result = -1;
  80.                 break;
  81.             }
  82.         } else {
  83.             result = -1;
  84.             break;
  85.         }      
  86.         if (result != 0) {
  87.             break;
  88.         }     
  89.         test_addr += TEST_4KB;
  90.     } while (test_addr < 0x400000);
  91.     if (result == 0) {
  92.         result = 2;
  93.     }
  94. }

  95. // 应用任务
  96. void app_task(void)
  97. {
  98. }


详细代码,请查看附件:
W25Q32.zip (2.13 MB, 下载次数: 0)




幻影书记 发表于 2025-9-8 14:15 | 显示全部楼层
贴了好长的代码啊
 楼主| 口天土立口 发表于 2025-9-8 19:39 | 显示全部楼层
幻影书记 发表于 2025-9-8 14:15
贴了好长的代码啊

同时方便不想下载源码的朋友直接看代码
空灵回声 发表于 2025-9-9 15:41 | 显示全部楼层
楼主,SPI发送里面为什么要有超时判断?
我主发送不是一定能成功的吗?
 楼主| 口天土立口 发表于 2025-9-9 18:12 | 显示全部楼层
空灵回声 发表于 2025-9-9 15:41
楼主,SPI发送里面为什么要有超时判断?
我主发送不是一定能成功的吗?

外设的状态会有异常,MCU有可能不会给你想要的结果,安全的设计必须考虑异常情况的处理
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

45

帖子

0

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