5、示例程序

5.1  SPI 驱动程序

GT5GL64芯片在使用“Quad Output Fast Read”, “Quad I/O Fast Read” (6BH, EBH)指令时支持Quad SPI操作,这些指令允许数据以标准SPI的四倍速率与设备进行传输,使用Quad SPI 指令时,SI和SO引脚变为双向I/O引脚(IO0和IO1),WP#和HOLD#变为IO2和IO3。 Quad SPI指令需要设置状态寄存器中的Quad Enable bit (QE)为1。

//注:此代码是在雅特力AT32F437VGT7实现的代码,仅供参考,其他MCU请参考各自MCU厂商提供的SDK编写SPI驱动。

/**

* @brief Write a byte to flash

* @param data: Data to write

* @retval Flash return data

*/

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 Read a byte from flash

* @param none

* @retval Flash return data

*/

uint8_t spi_byte_read(void)

{

return (spi_byte_write(FLASH_SPI_DUMMY_BYTE)); // 发送虚拟字节并返回接收到的数据

}

 

/**

* @brief Read data from flash

* @param pbuffer: Pointer to data buffer

* @param read_addr: Address where the data is read

* @param length: Buffer length

* @retval none

*/

void spiflash_read(uint8_t *pbuffer, uint32_t read_addr, uint32_t length)

{

FLASH_CS_LOW(); // 片选拉低

spi_byte_write(0x03); // 发送读取指令0x03

spi_byte_write((uint8_t)((read_addr) >> 16)); // 发送24位地址

spi_byte_write((uint8_t)((read_addr) >> 8));

spi_byte_write((uint8_t)read_addr);

// spi_byte_write((uint8_t)0xff); // 使用0x0B快速读取时需额外发送一个字节

spi_bytes_read(pbuffer, length); // 读取数据

FLASH_CS_HIGH(); // 片选拉高

}

 

/**

* @brief Erase a sector of data

* @param erase_addr: Sector address to erase

* @retval none

*/

void spiflash_sector_erase(uint32_t erase_addr)

{

spiflash_write_enable(); // 使能写操作

spiflash_write_enable(); // 再次使能写操作

spiflash_wait_busy(); // 等待设备空闲

FLASH_CS_LOW(); // 片选拉低

spi_byte_write(0x20); // 发送擦除指令0x20

spi_byte_write((uint8_t)((erase_addr) >> 16)); // 发送24位地址

spi_byte_write((uint8_t)((erase_addr) >> 8));

spi_byte_write((uint8_t)erase_addr);

FLASH_CS_HIGH(); // 片选拉高

spiflash_wait_busy(); // 等待擦除完成

}

 

/**

* @brief Read data continuously

* @param pbuffer: Buffer to save data

* @param length: Buffer 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++; // 指针后移

}

}

 

/**

* @brief Read device ID

* @param none

* @retval Device ID

*/

uint16_t spiflash_read_id(void)

{

uint16_t wreceivedata = 0;

FLASH_CS_LOW(); // 片选拉低

spi_byte_write(0x90); // 发送读取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(); // 片选拉高

return wreceivedata; // 返回设备ID

}

5.2 Quad SPI 通信程序

//注:此代码是在雅特力AT32F437VGT7实现的代码,仅供参考,其他MCU请参考各自MCU厂商提供的SDK编写QSPI驱动。

 

#include "qspi_flash.h" // 假设有一个头文件包含必要的定义和声明

 

qspi_cmd_type qspi_flash_cmd_config;

 

#define QSPI_FLASH_FIFO_DEPTH (32 * 4)

#define QSPI_FLASH_PAGE_SIZE 256

#define QSPI_FLASH_QSPIx QSPI1

 

/**

* @brief qspi flash 写使能

* @param none

* @retval none

*/

void qspi_flash_write_enable(void) {

// 写使能配置

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; // 性能增强模式关闭

qspi_cmd_struct->pe_mode_operate_code = 0;

qspi_cmd_struct->instruction_code = 0x20; // 擦除指令

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 = 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; // 读状态寄存器指令

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

}

 

/**

* @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(); // 检查忙状态

}

 

/**

* @brief qspi_flash 读命令配置

* @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; // 四线读指令

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; // 指令单线,地址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;

}

 

/**

* @brief qspi_flash 读命令配置

* @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; // 四线读指令

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; // 第二个虚拟状态周期数 6

qspi_cmd_struct->operation_mode = QSPI_OPERATE_MODE_114; // 指令单线,地址单线,数据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;

}

 

/**

* @brief qspi flash 读取数据

* @param addr: 读取地址

* @param total_len: 读取长度

* @param buf: 读取数据的指针

* @retval none

*/

void qspi_flash_data_read(uint32_t addr, uint8_t* buf, uint32_t total_len) {

uint32_t i, len = total_len;

 

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

}

 

/**

* @brief qspi flash 写入数据

* @param addr: 写入地址

* @param total_len: 写入长度

* @param buf: 写入数据的指针

* @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);

}

 

 

 

下一页
上一页
    • 联系电话

    • 0755—83453881
    • 服务时间

    • 周一至周五 9:00-18:00
    • 高通GT-HMI交流群