口天土立口 发表于 2025-9-6 15:04

APM32E030的SPI驱动

本帖最后由 口天土立口 于 2025-9-7 18:34 编辑



APM32E030支持SPI通信;

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

SPI初始化代码如下:
/* 初始化SPI引脚 */
static void bsp_spi_gpio_init(void)
{
    GPIO_Config_T gpioConfig;
   
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);   
    GPIO_ConfigStructInit(&gpioConfig);
   
    /*
   * CS   -> PA4
   * SCK-> PA5
   * MISO -> PA6
   * MOSI -> PA7
   */
    gpioConfig.pin   = GPIO_PIN_4;
    gpioConfig.mode    = GPIO_MODE_AF;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.speed   = GPIO_SPEED_50MHz;
    gpioConfig.pupd    = GPIO_PUPD_PU;          /* CS低电平有效,默认拉高 */
    GPIO_Config(GPIOA, &gpioConfig);
    gpioConfig.pupd    = GPIO_PUPD_PD;          /* SPI模式0,SCK默认为低电平 */
    gpioConfig.pin   = GPIO_PIN_5;
    GPIO_Config(GPIOA, &gpioConfig);
    gpioConfig.pupd    = GPIO_PUPD_PU;
    gpioConfig.pin   = GPIO_PIN_7;
    GPIO_Config(GPIOA, &gpioConfig);
    gpioConfig.pupd    = GPIO_PUPD_NO;
    gpioConfig.pin   = GPIO_PIN_6;
    GPIO_Config(GPIOA, &gpioConfig);
   
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_4, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);   
}/* 初始化SPI */
void bsp_spi_init(void)
{
    SPI_Config_T spiConfig;
   
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
    bsp_spi_gpio_init();
    SPI_ConfigStructInit(&spiConfig);
   
    SPI_Reset(SPI1);
    spiConfig.mode          = SPI_MODE_MASTER;
    spiConfig.length      = SPI_DATA_LENGTH_8B;
    spiConfig.phase         = SPI_CLKPHA_1EDGE;   /* MODE0 */
    spiConfig.polarity      = SPI_CLKPOL_LOW;
    spiConfig.slaveSelect   = SPI_SSC_ENABLE;
    spiConfig.firstBit      = SPI_FIRST_BIT_MSB;
    spiConfig.direction   = SPI_DIRECTION_2LINES_FULLDUPLEX;
    spiConfig.baudrateDiv   = SPI_BAUDRATE_DIV_4;
    spiConfig.crcPolynomial = 7;
    SPI_Config(SPI1, &spiConfig);
    SPI_EnableInternalSlave(SPI1);
    SPI_ConfigFIFOThreshold(SPI1, SPI_RXFIFO_QUARTER);
    SPI_DisableSSoutput(SPI1);
    SPI_Enable(SPI1);
}

W25Q32驱动代码:
/* 最大容量 4MB */
#define W25Q32_MAX_CAPACITY             ((uint32_t)0x400000)
/* 扇区大小 4KB */
#define W25Q32_SECTOR_SIZE            ((uint16_t)0x1000)
/* 块大小 64KB */
#define W25Q32_BLOCK_SIZE               ((uint16_t)0x10000)
/* 页编程大小 */
#define W25Q32_PAGE_PROGRAM_SIZE      ((uint16_t)0x100)
/* 制造商ID */
#define W25Q32_MANUFACTURE_ID         ((uint32_t)0xEF)
/* JEDEC ID */
#define W25Q32_JEDEC_ID               ((W25Q32_MANUFACTURE_ID << 16) | 0x4016)
/* 制造商设备ID */
#define W25Q32_MANUFACTURE_DEVICE_ID    ((W25Q32_MANUFACTURE_ID << 8) | (uint8_t)0x15)
/* 超时 */
#define W25Q32_TIMEOUT                  ((uint32_t)0xFF000)/*
* @brief       初始化
*
* @param       None
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_init(void)
{
    uint32_t JEDEC_id = 0;
    uint16_t Manufacturer_id = 0;
   
    bsp_spi_init();
    /* JEDEC ID */
    if ((bsp_w25q32_read_JEDEC_id(&JEDEC_id) != 0) || (JEDEC_id != W25Q32_JEDEC_ID)) {
      return -1;
    }
    /* 制造商设备ID */
    if ((bsp_w25q32_read_manufacturer_devid(&Manufacturer_id) != 0) || (Manufacturer_id != W25Q32_MANUFACTURE_DEVICE_ID)) {
      return -1;
    }
   
    return 0;
}/*
* @brief       写寄存器
*
* @param       reg: 寄存器
*            data: 寄存器数据缓存
*            data_num: 寄存器数据数量
*            data_ex: 额外数据缓存
*            data_ex_num: 额外数据数量
*
* @retval      0: 成功; -1: 失败
*
*/
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)
{
    uint32_t timeout = 0;
    uint32_t i = 0;
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_BUSY) == SET) {
      timeout--;
      if (timeout == 0) {
            return -1;
      }
    }
   
    /* 等待发送为空 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
      timeout--;
      if (timeout == 0) {
            return -1;
      }
    }
   
    SPI_EnableSSoutput(SPI1);
   
    /* 发送寄存器 */
    SPI_TxData8(SPI1, reg);
    /* 等待发送完成 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
      timeout--;
      if (timeout == 0) {
            SPI_DisableSSoutput(SPI1);
            return -1;
      }
    }
    /* 获取接收数据 */
    (void)SPI_RxData8(SPI1);
      
    /* 发送数据 */
    while (i < data_num) {
      SPI_TxData8(SPI1, data);
      /* 等待发送完成 */
      timeout = W25Q32_TIMEOUT;
      while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
            timeout--;
            if (timeout == 0) {
                SPI_DisableSSoutput(SPI1);
                return -1;
            }
      }
      /* 获取接收数据 */
      (void)SPI_RxData8(SPI1);
    }
   
    /* 发送数据 */
    i = 0;
    while (i < data_ex_num) {
      SPI_TxData8(SPI1, data_ex);
      /* 等待发送完成 */
      timeout = W25Q32_TIMEOUT;
      while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
            timeout--;
            if (timeout == 0) {
                SPI_DisableSSoutput(SPI1);
                return -1;
            }
      }
      /* 获取接收数据 */
      (void)SPI_RxData8(SPI1);
    }
   
    SPI_DisableSSoutput(SPI1);
   
    return 0;
}/*
* @brief       读寄存器
*
* @param       reg: 寄存器
*            w_data: 写寄存器数据缓存
*            w_data_num: 写寄存器数据数量
*            r_data: 读数据缓存
*            r_data_num: 读数据数量
*
* @retval      0: 成功; -1: 失败
*
*/
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)
{
    uint32_t timeout = 0;
    uint32_t i = 0;
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_BUSY) == SET) {
      timeout--;
      if (timeout == 0) {
            return -1;
      }
    }
   
    /* 等待发送为空 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
      timeout--;
      if (timeout == 0) {
            return -1;
      }
    }
   
    SPI_EnableSSoutput(SPI1);
   
    /* 发送寄存器 */
    SPI_TxData8(SPI1, reg);
    /* 等待发送完成 */
    timeout = W25Q32_TIMEOUT;
    while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
      timeout--;
      if (timeout == 0) {
            SPI_DisableSSoutput(SPI1);
            return -1;
      }
    }
    /* 获取接收数据 */
    (void)SPI_RxData8(SPI1);
   
    /* 发送数据 */
    i = 0;
    while (i < w_data_num) {
      SPI_TxData8(SPI1, w_data);
      /* 等待发送完成 */
      timeout = W25Q32_TIMEOUT;
      while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
            timeout--;
            if (timeout == 0) {
                SPI_DisableSSoutput(SPI1);
                return -1;
            }
      }
      /* 获取接收数据 */
      (void)SPI_RxData8(SPI1);
    }
      
    /* 接收数据 */
    i = 0;
    while (i < r_data_num) {
      /* 制造时钟信号 */
      SPI_TxData8(SPI1, 0xFF);
      /* 等待发送完成 */
      timeout = W25Q32_TIMEOUT;
      while (SPI_ReadStatusFlag(SPI1, SPI_FLAG_TXBE) == RESET) {
            timeout--;
            if (timeout == 0) {
                SPI_DisableSSoutput(SPI1);
                return -1;
            }
      }
      /* 获取接收数据 */
      r_data = SPI_RxData8(SPI1);
    }
   
    SPI_DisableSSoutput(SPI1);
   
    return 0;
}/*
* @brief       读状态1
*
* @param       status1: 状态
*
* @retval      None
*
*/
static int8_t bsp_w25q32_read_status1(uint8_t *status1)
{
    return bsp_w25q32_read_reg(0x05, NULL, 0, status1, 1);
}/*
* @brief       检查忙
*
* @param       status1: 状态
*
* @retval      0: 非忙; 1: 忙; -1: 失败
*
*/
static int8_t bsp_w25q32_is_busy(void)
{
    uint8_t status1 = 0;
   
    if (bsp_w25q32_read_reg(0x05, NULL, 0, &status1, 1) == 0) {
      if ((status1 & 0x01) == 0) {
            return 0;   /* 非忙 */
      } else {
            return 1;   /* 忙 */
      }
    }
   
    return -1;/* 异常 */
}/*
* @brief       写使能
*
* @param       status1: 状态
*
* @retval      0: 成功; -1: 失败
*
*/
static int8_t bsp_w25q32_write_enable(void)
{
    uint32_t timeout = 0;
    uint8_t status1 = 0;
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_write_reg(0x06, NULL, 0, NULL, 0) == 0) {      
      /* 检查忙 */
      do {
            if (bsp_w25q32_read_status1(&status1) == 0) {
                if ((status1 & 0x01) == 0) {
                  if ((status1 & 0x02) != 0) {
                        return 0;   /* 写使能成功 */
                  }
                  return -1;   /* 写使能失败 */
                } else {
                  continue;   /* 忙 */
                }
            } else {
                return -1;   /* 异常 */
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       读数据
*
* @param       addr: 数据地址
*            buf: 数据缓存
*            data_size: 数据数量
*
* @retval      0: 失败; 其他: 数据数量
*
*/
uint32_t bsp_w25q32_read_data(uint32_t addr, uint8_t *buf, uint32_t data_size)
{
    uint8_t w_data = {0};
    int8_t status1 = 0;
    uint32_t timeout = 0;
   
    /* 检查入参 */
    if ((data_size == 0) || (buf == NULL) || (addr >= W25Q32_MAX_CAPACITY) || ((addr + data_size) > W25Q32_MAX_CAPACITY)) {
      return 0;
    }
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    w_data = (addr >> 16) & 0xFF;
    w_data = (addr >> 8) & 0xFF;
    w_data = addr & 0xFF;
    if (bsp_w25q32_read_reg(0x03, w_data, 3, buf, data_size) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return data_size;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return 0;
}/*
* @brief       写数据
*
* @param       addr: 数据地址
*            buf: 数据缓存
*            data_size: 数据数量
*
* @retval      0: 失败; 其他: 数据数量
*
*/
uint32_t bsp_w25q32_write_data(uint32_t addr, uint8_t *buf, uint32_t data_size)
{
    uint32_t timeout = 0;
    uint8_t w_data = {0};
    int8_t status1 = 0;
    uint16_t write_bytes = 0;
    uint16_t current_page_write_size = 0;       /* 当前页写大小 */
      
    /* 检查入参 */
    if ((data_size == 0) || (buf == NULL) || (addr >= W25Q32_MAX_CAPACITY) || ((addr + data_size) > W25Q32_MAX_CAPACITY)) {
      return 0;
    }
      
    do {
      /* 单页写数据超长将回环覆盖 */
      current_page_write_size = W25Q32_PAGE_PROGRAM_SIZE - (addr % W25Q32_PAGE_PROGRAM_SIZE);
      current_page_write_size = (current_page_write_size <= (data_size - write_bytes)) ? current_page_write_size : (data_size - write_bytes);
      
      /* 等待空闲 */
      timeout = W25Q32_TIMEOUT;
      while (bsp_w25q32_is_busy() != 0) {
            timeout--;
            if (timeout == 0) {
                return 0;
            }
      }
      
      if (bsp_w25q32_write_enable() != 0) {
            return 0;
      }
            
      w_data = (addr >> 16) & 0xFF;
      w_data = (addr >> 8) & 0xFF;
      w_data = addr & 0xFF;
      if (bsp_w25q32_write_reg(0x02, w_data, 3, &buf, current_page_write_size) == 0) {
            /* 检查忙 */
            do {
                status1 = bsp_w25q32_is_busy();
                if (status1 == 0) {
                  write_bytes += current_page_write_size;
                  addr += current_page_write_size;
                  break;
                } else if (status1 == -1) {
                  break;
                }
            } while (1);
      } else {
            break;
      }
    } while (write_bytes < data_size);
   
    return write_bytes;
}/*
* @brief       扇区擦除
*
* @param       addr: 数据地址
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_sector_erase(uint32_t addr)
{
    uint32_t timeout = 0;
    uint8_t w_data = {0};
    int8_t status1 = 0;
   
    /* 4KB对齐 */
    addr = addr & (~0xFFFU);
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_write_enable() != 0) {
      return -1;
    }
      
    w_data = (addr >> 16) & 0xFF;
    w_data = (addr >> 8) & 0xFF;
    w_data = addr & 0xFF;
    if (bsp_w25q32_write_reg(0x20, w_data, 3, NULL, 0) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return 0;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       块32KB擦除
*
* @param       addr: 数据地址
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_block_32kb_erase(uint32_t addr)
{
    uint32_t timeout = 0;
    uint8_t w_data = {0};
    int8_t status1 = 0;
   
    /* 32KB对齐 */
    addr = addr & (~0x7FFFU);
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_write_enable() != 0) {
      return -1;
    }
      
    w_data = (addr >> 16) & 0xFF;
    w_data = (addr >> 8) & 0xFF;
    w_data = addr & 0xFF;
    if (bsp_w25q32_write_reg(0x52, w_data, 3, NULL, 0) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return 0;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       块64KB擦除
*
* @param       addr: 数据地址
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_block_64kb_erase(uint32_t addr)
{
    uint32_t timeout = 0;
    uint8_t w_data = {0};
    int8_t status1 = 0;
   
    /* 64KB对齐 */
    addr = addr & (~0xFFFFU);
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_write_enable() != 0) {
      return -1;
    }
      
    w_data = (addr >> 16) & 0xFF;
    w_data = (addr >> 8) & 0xFF;
    w_data = addr & 0xFF;
    if (bsp_w25q32_write_reg(0xD8, w_data, 3, NULL, 0) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return 0;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       整片擦除
*
* @param       None
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_chip_erase(void)
{
    uint32_t timeout = 0;
    int8_t status1 = 0;
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_write_enable() != 0) {
      return -1;
    }
   
    if (bsp_w25q32_write_reg(0x60, NULL, 0, NULL, 0) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return 0;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       复位
*
* @param       None
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_reset_device(void)
{
    uint8_t w_data = 0x99;
    int8_t status1 = 0;
   
    if (bsp_w25q32_write_reg(0x66, &w_data, 1, NULL, 0) == 0) {
      /* 检查忙 */
      do {
            status1 = bsp_w25q32_is_busy();
            if (status1 == 0) {
                return 0;
            } else if (status1 == -1) {
                break;
            }
      } while (1);
    }
   
    return -1;
}/*
* @brief       读制造商设备ID
*
* @param       id: 制造商设备ID
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_read_manufacturer_devid(uint16_t *id)
{
    uint32_t timeout = 0;
    uint8_t w_data = {0, 0, 0};
    uint8_t r_data = {0};
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_read_reg(0x90, w_data, 3, r_data, 2) == 0) {
      *id = (((uint16_t)r_data) << 8) + r_data;
    } else {
      return -1;
    }
   
    return 0;
}/*
* @brief       读 JEDEC ID
*
* @param       id: JEDEC ID
*
* @retval      0: 成功; -1: 失败
*
*/
int8_t bsp_w25q32_read_JEDEC_id(uint32_t *id)
{
    uint32_t timeout = 0;
    uint8_t r_data = {0};
   
    /* 等待空闲 */
    timeout = W25Q32_TIMEOUT;
    while (bsp_w25q32_is_busy() != 0) {
      timeout--;
      if (timeout == 0) {
            return 0;
      }
    }
   
    if (bsp_w25q32_read_reg(0x9F, NULL, 0, r_data, 3) == 0) {
      *id = (((uint32_t)r_data) << 16) + (((uint16_t)r_data) << 8) + r_data;
    } else {
      return -1;
    }
   
    return 0;
}

测试代码如下:
#define BUF_SIZE    (4096)
#define TEST_4KB    (0x1000)
uint8_t test_buf;
uint32_t test_addr = 0;
uint32_t i = 0;
int8_t result = 0;
uint32_t num_index = 0;

// 应用初始化
void app_init(void)
{
    bsp_w25q32_init();
   
    /* 4KB测试 */
    num_index = 0;
    result = 0;
    do {
      /* 1.扇区擦除 */
      if (bsp_w25q32_sector_erase(test_addr) == 0) {
            /* 回读检查 */
            memset(test_buf, 0, sizeof(test_buf));
            if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
                for (i = 0; i < TEST_4KB; i++) {
                  if (test_buf != 0xFF) {
                        result = -1;
                        break;
                  }
                }
                if (result != 0) {
                  break;
                }
               
                /* 2.写新数据 */
                num_index += 10;
                for (i = 0; i < TEST_4KB; i++) {
                  test_buf = num_index + i;
                }
                if (bsp_w25q32_write_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
                  /* 回读检查 */
                  memset(test_buf, 0, sizeof(test_buf));
                  if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
                        for (i = 0; i < TEST_4KB; i++) {
                            if (test_buf != (uint8_t)(num_index + i)) {
                              result = -1;
                              break;
                            }
                        }
                        if (result != 0) {
                            break;
                        }
                        
                        /* 3.擦除数据 */
                        if (bsp_w25q32_sector_erase(test_addr) == 0) {
                            /* 回读检查 */
                            memset(test_buf, 0, sizeof(test_buf));
                            if (bsp_w25q32_read_data(test_addr, test_buf, sizeof(test_buf)) == sizeof(test_buf)) {
                              for (i = 0; i < TEST_4KB; i++) {
                                    if (test_buf != 0xFF) {
                                        result = -1;
                                        break;
                                    }
                              }
                            } else {
                              result = -1;
                              break;
                            }
                        } else {
                            result = -1;
                            break;
                        }
                  } else {
                        result = -1;
                        break;
                  }
                } else {
                  result = -1;
                  break;
                }
            } else {
                result = -1;
                break;
            }
      } else {
            result = -1;
            break;
      }      
      if (result != 0) {
            break;
      }   
      test_addr += TEST_4KB;
    } while (test_addr < 0x400000);
    if (result == 0) {
      result = 2;
    }
}

// 应用任务
void app_task(void)
{
}

详细代码,请查看附件:





幻影书记 发表于 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有可能不会给你想要的结果,安全的设计必须考虑异常情况的处理
页: [1]
查看完整版本: APM32E030的SPI驱动