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);
}


