高通字库
版本 V1.1 · 更新于 2026-03

6. 示例程序

以下示例基于AT32F437VGT7 MCU,使用厂商SDK中的SPI和QSPI驱动,演示GT5G系列芯片的读写操作。

6.1 SPI示例程序

字节写入/读取

// AT32F437VGT7 MCU 的 MCU SDK SPI 示例

/**
 * @brief 向Flash写入一个字节
 * @param data: 要写入的数据
 * @retval Flash返回数据
 */
uint8_t spi_byte_write(uint8_t data)
{
    uint8_t brxbuff;
    spi_i2s_dma_transmitter_enable(SPI4, FALSE);   // 关闭DMA发送
    spi_i2s_dma_receiver_enable(SPI4, FALSE);       // 关闭DMA接收
    spi_i2s_data_transmit(SPI4, data);              // 发送数据
    while (spi_i2s_flag_get(SPI4, SPI_I2S_RDBF_FLAG) == RESET); // 等待接收
    brxbuff = spi_i2s_data_receive(SPI4);           // 读取接收数据
    while (spi_i2s_flag_get(SPI4, SPI_I2S_BF_FLAG) != RESET);   // 等待忙标志清除
    return brxbuff;                                 // 返回接收数据
}

/**
 * @brief 从Flash读取一个字节
 * @param none
 * @retval Flash返回数据
 */
uint8_t spi_byte_read(void)
{
    return (spi_byte_write(FLASH_SPI_DUMMY_BYTE));  // 发送空字节触发读取
}

Flash读取

/**
 * @brief 从Flash读取数据(READ指令0x03)
 * @param pbuffer: 数据缓冲区指针
 * @param read_addr: 读取起始地址(24位)
 * @param length: 读取长度
 * @retval none
 */
void spiflash_read(uint8_t *pbuffer, uint32_t read_addr, uint32_t length)
{
    FLASH_CS_LOW();                                  // CS#拉低
    spi_byte_write(0x03);                            // 发送READ指令0x03
    spi_byte_write((uint8_t)((read_addr) >> 16));    // 地址[23:16]
    spi_byte_write((uint8_t)((read_addr) >> 8));     // 地址[15:8]
    spi_byte_write((uint8_t)read_addr);              // 地址[7:0]
    // spi_byte_write((uint8_t)0xff);                // 0x0B模式需要空字节
    spi_bytes_read(pbuffer, length);                 // 连续读取
    FLASH_CS_HIGH();                                 // CS#拉高
}

扇区擦除

/**
 * @brief 擦除一个扇区(4KB)
 * @param erase_addr: 要擦除的扇区地址
 * @retval none
 */
void spiflash_sector_erase(uint32_t erase_addr)
{
    spiflash_write_enable();                         // 写使能
    spiflash_write_enable();                         // 再次确认写使能
    spiflash_wait_busy();                            // 等待空闲
    FLASH_CS_LOW();                                  // CS#拉低
    spi_byte_write(0x20);                            // 发送SE指令0x20
    spi_byte_write((uint8_t)((erase_addr) >> 16));   // 地址[23:16]
    spi_byte_write((uint8_t)((erase_addr) >> 8));    // 地址[15:8]
    spi_byte_write((uint8_t)erase_addr);             // 地址[7:0]
    FLASH_CS_HIGH();                                 // CS#拉高,开始擦除
    spiflash_wait_busy();                            // 等待擦除完成
}

连续读取

/**
 * @brief 连续读取多个字节
 * @param pbuffer: 数据缓冲区
 * @param length: 读取长度
 * @retval none
 */
void spi_bytes_read(uint8_t *pbuffer, uint32_t length)
{
    while (length--)
    {
        while (spi_i2s_flag_get(SPI4, SPI_I2S_TDBE_FLAG) == RESET);  // 等待发送空
        spi_i2s_data_transmit(SPI4, 0xa5);           // 发送空字节
        while (spi_i2s_flag_get(SPI4, SPI_I2S_RDBF_FLAG) == RESET);  // 等待接收
        *pbuffer = spi_i2s_data_receive(SPI4);       // 读取数据
        pbuffer++;                                   // 指针递增
    }
}

读取设备ID

/**
 * @brief 读取设备ID(REMS指令0x90)
 * @param none
 * @retval 设备ID(16位)
 */
uint16_t spiflash_read_id(void)
{
    uint16_t wreceivedata = 0;
    FLASH_CS_LOW();                                  // CS#拉低
    spi_byte_write(0x90);                            // 发送Read ID指令0x90
    spi_byte_write(0x00);                            // 地址0x00
    spi_byte_write(0x00);
    spi_byte_write(0x00);
    wreceivedata |= spi_byte_read() << 8;            // 读取高8位ID
    wreceivedata |= spi_byte_read();                 // 读取低8位ID
    FLASH_CS_HIGH();                                 // CS#拉高
    return wreceivedata;                             // 返回设备ID
}

6.2 Quad SPI示例程序

以下示例使用AT32F437VGT7 QSPI外设驱动GT5G系列芯片。

QSPI初始化配置

#include "qspi_flash.h"                              // QSPI Flash驱动头文件

qspi_cmd_type qspi_flash_cmd_config;

#define QSPI_FLASH_FIFO_DEPTH  (32 * 4)              // FIFO深度
#define QSPI_FLASH_PAGE_SIZE   256                   // 页大小256字节
#define QSPI_FLASH_QSPIx       QSPI1                 // 使用QSPI1

写使能

/**
 * @brief qspi flash写使能
 * @param none
 * @retval none
 */
void qspi_flash_write_enable(void)
{
    // 配置WREN指令
    qspi_flash_cmd_wren_config(&qspi_flash_cmd_config);
    qspi_cmd_operation_kick(QSPI_FLASH_QSPIx, &qspi_flash_cmd_config);

    // 等待指令完成
    while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG) == RESET);
    qspi_flag_clear(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG);
}

扇区擦除配置

/**
 * @brief qspi_flash扇区擦除配置
 * @param qspi_cmd_struct: qspi_cmd_type结构体指针
 * @param addr: 擦除地址
 * @retval none
 */
void qspi_flash_cmd_erase_config(qspi_cmd_type *qspi_cmd_struct, uint32_t addr)
{
    qspi_cmd_struct->pe_mode_enable       = FALSE;               // 关闭PE模式
    qspi_cmd_struct->pe_mode_operate_code = 0;
    qspi_cmd_struct->instruction_code     = 0x20;                // SE指令
    qspi_cmd_struct->instruction_length   = QSPI_CMD_INSLEN_1_BYTE; // 指令1字节
    qspi_cmd_struct->address_code         = addr;                // 擦除地址
    qspi_cmd_struct->address_length       = QSPI_CMD_ADRLEN_3_BYTE; // 地址3字节
    qspi_cmd_struct->data_counter         = 0;
    qspi_cmd_struct->second_dummy_cycle_num = 0;
    qspi_cmd_struct->operation_mode       = QSPI_OPERATE_MODE_111;
    qspi_cmd_struct->read_status_config   = QSPI_RSTSC_HW_AUTO;
    qspi_cmd_struct->read_status_enable   = FALSE;
    qspi_cmd_struct->write_data_enable    = TRUE;
}

状态寄存器读取

/**
 * @brief qspi_flash状态寄存器读取配置
 * @param qspi_cmd_struct: qspi_cmd_type结构体指针
 * @retval none
 */
void qspi_flash_cmd_rdsr_config(qspi_cmd_type *qspi_cmd_struct)
{
    qspi_cmd_struct->pe_mode_enable       = FALSE;
    qspi_cmd_struct->pe_mode_operate_code = 0;
    qspi_cmd_struct->instruction_code     = 0x05;                // RDSR指令
    qspi_cmd_struct->instruction_length   = QSPI_CMD_INSLEN_1_BYTE;
    qspi_cmd_struct->address_code         = 0;
    qspi_cmd_struct->address_length       = QSPI_CMD_ADRLEN_0_BYTE;
    qspi_cmd_struct->data_counter         = 0;
    qspi_cmd_struct->second_dummy_cycle_num = 0;
    qspi_cmd_struct->operation_mode       = QSPI_OPERATE_MODE_111;
    qspi_cmd_struct->read_status_config   = QSPI_RSTSC_HW_AUTO;
    qspi_cmd_struct->read_status_enable   = TRUE;
    qspi_cmd_struct->write_data_enable    = FALSE;
}

忙检测

/**
 * @brief qspi flash忙检测
 * @param none
 * @retval none
 */
void qspi_flash_busy_check(void)
{
    qspi_flash_cmd_rdsr_config(&qspi_flash_cmd_config);
    qspi_cmd_operation_kick(QSPI_FLASH_QSPIx, &qspi_flash_cmd_config);

    // 等待指令完成
    while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG) == RESET);
    qspi_flag_clear(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG);
}

QSPI擦除

/**
 * @brief qspi flash扇区擦除
 * @param sec_addr: 扇区地址
 * @retval none
 */
void qspi_flash_erase(uint32_t sec_addr)
{
    qspi_flash_write_enable();                           // 写使能
    qspi_flash_cmd_erase_config(&qspi_flash_cmd_config, sec_addr); // 配置擦除
    qspi_cmd_operation_kick(QSPI_FLASH_QSPIx, &qspi_flash_cmd_config); // 执行

    // 等待指令完成
    while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG) == RESET);
    qspi_flag_clear(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG);
    qspi_flash_busy_check();                             // 等待擦除完成
}

QSPI 4READ读取配置

/**
 * @brief qspi_flash 4READ读取配置(0xEB指令)
 * @param qspi_cmd_struct: qspi_cmd_type结构体指针
 * @param addr: 读取地址
 * @param counter: 读取字节数
 * @retval none
 */
void qspi_flash_cmd_read_config(qspi_cmd_type *qspi_cmd_struct,
                                uint32_t addr, uint32_t counter)
{
    qspi_cmd_struct->pe_mode_enable       = FALSE;
    qspi_cmd_struct->pe_mode_operate_code = 0;
    qspi_cmd_struct->instruction_code     = 0xEB;                // 4READ指令
    qspi_cmd_struct->instruction_length   = QSPI_CMD_INSLEN_1_BYTE;
    qspi_cmd_struct->address_code         = addr;
    qspi_cmd_struct->address_length       = QSPI_CMD_ADRLEN_3_BYTE; // 3字节地址
    qspi_cmd_struct->data_counter         = counter;             // 读取字节数
    qspi_cmd_struct->second_dummy_cycle_num = 6;                 // 6个空周期
    qspi_cmd_struct->operation_mode       = QSPI_OPERATE_MODE_144; // 1-4-4模式
    qspi_cmd_struct->read_status_config   = QSPI_RSTSC_HW_AUTO;
    qspi_cmd_struct->read_status_enable   = FALSE;
    qspi_cmd_struct->write_data_enable    = FALSE;
}

QSPI QREAD读取配置

/**
 * @brief qspi_flash QREAD读取配置(0x6B指令)
 * @param qspi_cmd_struct: qspi_cmd_type结构体指针
 * @param addr: 读取地址
 * @param counter: 读取字节数
 * @retval none
 */
void qspi_flash_cmd_read_config_6B(qspi_cmd_type *qspi_cmd_struct,
                                   uint32_t addr, uint32_t counter)
{
    qspi_cmd_struct->pe_mode_enable       = FALSE;
    qspi_cmd_struct->pe_mode_operate_code = 0;
    qspi_cmd_struct->instruction_code     = 0x6B;                // QREAD指令
    qspi_cmd_struct->instruction_length   = QSPI_CMD_INSLEN_1_BYTE;
    qspi_cmd_struct->address_code         = addr;
    qspi_cmd_struct->address_length       = QSPI_CMD_ADRLEN_3_BYTE; // 3字节地址
    qspi_cmd_struct->data_counter         = counter;
    qspi_cmd_struct->second_dummy_cycle_num = 8;                 // 8个空周期
    qspi_cmd_struct->operation_mode       = QSPI_OPERATE_MODE_114; // 1-1-4模式
    qspi_cmd_struct->read_status_config   = QSPI_RSTSC_HW_AUTO;
    qspi_cmd_struct->read_status_enable   = FALSE;
    qspi_cmd_struct->write_data_enable    = FALSE;
}

QSPI数据读取

/**
 * @brief qspi flash数据读取
 * @param addr: 起始地址
 * @param buf: 数据缓冲区
 * @param total_len: 读取总长度
 * @retval none
 */
void qspi_flash_data_read(uint32_t addr, uint8_t* buf, uint32_t total_len)
{
    uint32_t i, len = total_len;

    // 使用4READ模式读取
    // qspi_flash_cmd_read_config_6B(&qspi_flash_cmd_config, addr, total_len);
    qspi_flash_cmd_read_config(&qspi_flash_cmd_config, addr, total_len);
    qspi_cmd_operation_kick(QSPI_FLASH_QSPIx, &qspi_flash_cmd_config);

    // 循环读取直到取完
    do {
        if (total_len >= QSPI_FLASH_FIFO_DEPTH) {
            len = QSPI_FLASH_FIFO_DEPTH;
        } else {
            len = total_len;
        }

        while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_RXFIFORDY_FLAG) == RESET);

        for (i = 0; i < len; ++i) {
            *buf++ = qspi_byte_read(QSPI_FLASH_QSPIx);
        }

        total_len -= len;
    } while (total_len);

    // 等待指令完成
    while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG) == RESET);
    qspi_flag_clear(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG);
}

QSPI数据写入

/**
 * @brief qspi flash数据写入
 * @param addr: 起始地址
 * @param buf: 数据缓冲区
 * @param total_len: 写入总长度
 * @retval none
 */
void qspi_flash_data_write(uint32_t addr, uint8_t* buf, uint32_t total_len)
{
    uint32_t i, len;

    do {
        qspi_flash_write_enable();

        // 计算当前页剩余空间(页大小256字节)
        len = (addr / QSPI_FLASH_PAGE_SIZE + 1) * QSPI_FLASH_PAGE_SIZE - addr;
        if (total_len < len) {
            len = total_len;
        }

        qspi_flash_cmd_write_config(&qspi_flash_cmd_config, addr, len);
        qspi_cmd_operation_kick(QSPI_FLASH_QSPIx, &qspi_flash_cmd_config);

        for (i = 0; i < len; ++i) {
            while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_TXFIFORDY_FLAG) == RESET);
            qspi_byte_write(QSPI_FLASH_QSPIx, *buf++);
        }

        total_len -= len;
        addr += len;

        // 等待指令完成
        while (qspi_flag_get(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG) == RESET);
        qspi_flag_clear(QSPI_FLASH_QSPIx, QSPI_CMDSTS_FLAG);
        qspi_flash_busy_check();
    } while (total_len);
}