如何写好QSPI驱动

1. 摘要

本篇笔记主要介绍,如何开发稳定可靠,功能齐全的QSPI驱动。

2. 准备工作

     1, IAR 8.32.1

     2, STM32Cube_FW_H7_V1.6.0

3. QSPI简介

4. QSPI驱动

在项目的开发中,我们经常会使用外挂Flash在做一些应用,而STM32H743带QSPI接口,可以用来外挂QSPI Flash,在之前的推送中我们以winbond华邦的W25Q256为例给大家说明了下QSPI的操作,借助ST的HAL库例程可以快速验证,不同型号的QSPI Flash会有一些参数和命令区别,大家应用时候要注意,例如美光和华邦的有的命令码就不同。ST的驱动里STM32H743的评估板是以美光的MT25T_QLKT_L_01G为例。如果你使用不同的型号,请注意区分,既然是评估板,那么就只是给大家参考,在正式的项目中,还需要考虑一些其他的问题。

5. 驱动架构

驱动的架构可以参考STM32Cube_FW_H7中对QSPI  Flash驱动架构,也可以自己做架构,尽量简单明了,易用且稳定。对具体型号Flash的驱动可以放在一个文件下建立一个.c和.h. 如我们以华邦的W25Q系列为例,

还可以建立一个文本文档,用来记录驱动的一些变更,发布笔记等。

BSP层可以在BSP文件夹下建立QSPI的驱动,名字可以参考ST库,也可以按照自己的命名规则来定,或者企业的软件文件命名规则来定。

<think>我们正在为ST77916显示屏开发QSPI接口驱动程序。由于ST77916支持QSPI接口,我们需要编初始化序列、发送命令和数据的函数,以及实现屏幕的刷新。 注意:QSPI接口可以工作在多种模式,包括间接模式(使用寄存器发送命令和数据)和内存映射模式(直接通过内存访问显示数据)。通常,初始化阶段使用间接模式,而在刷新屏幕时可以使用内存映射模式以提高性能。 步骤: 1. 初始化QSPI外设(包括GPIO和QSPI时钟配置)。 2. 配置QSPI的参数(如时钟分频、采样边沿等)。 3. 编发送命令和数据的函数(通过QSPI发送命令和数据到显示屏)。 4. 实现显示屏的初始化序列(根据ST77916的数据手册编初始化命令序列)。 5. 实现屏幕刷新(将帧缓冲区的内容发送到显示屏)。 由于不同硬件平台(如STM32)的QSPI外设操作有所不同,这里我们以STM32为例(使用HAL库)进行说明。 参考代码结构: 1. 初始化QSPI外设: - 配置QSPI相关的GPIO(CLK, NCS, IO0, IO1, IO2, IO3)为复用功能。 - 使能QSPI时钟。 - 配置QSPI参数(如:HAL_QSPI_Init)。 2. 发送命令函数: - 使用HAL_QSPI_Command函数发送命令(8位或16位),并设置命令模式(仅命令线或四线等)。 - 发送数据时,使用HAL_QSPI_Transmit函数(在地址阶段后发送数据,或者使用单独的数据发送函数)。 3. 初始化序列: - 根据ST77916的数据手册,发送一系列命令和参数(如设置像素格式、扫描方向、睡眠模式退出等)。 4. 刷新屏幕: - 一种方法是使用内存映射模式:将QSPI映射到内存地址,然后直接向该内存区域入像素数据(需要DMA或CPU入)。但要注意,内存映射模式是只读的,所以通常用于读取,而操作可能需要使用间接模式。 - 另一种方法是使用间接模式:发送命令(如0x2C)后,再发送像素数据(可以以DMA方式传输以提高效率)。 注意:ST77916的数据手册是开发驱动的基础,必须参考手册中的命令定义和时序要求。 由于我们无法直接获取ST77916的完整数据手册(可能受限于版权),但我们可以参考类似驱动(如ST7789)的初始化序列,并根据ST77916的规格书调整。 以下是一个简化的代码示例(基于STM32 HAL库): 步骤1:初始化QSPI外设 ```c void QSPI_Init(void) { // 使能QSPI时钟 __HAL_RCC_QSPI_CLK_ENABLE(); // 初始化GPIO(具体引脚根据硬件连接) // ... 初始化CLK, NCS, IO0, IO1, IO2, IO3为复用推挽输出,并设置复用功能 // 配置QSPI QSPI_Handle.Instance = QUADSPI; QSPI_Handle.Init.ClockPrescaler = 1; // 根据系统时钟和QSPI时钟要求设置分频 QSPI_Handle.Init.FifoThreshold = 1; QSPI_Handle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPI_Handle.Init.FlashSize = 23; // 2^23 = 8MB(根据实际Flash大小设置) QSPI_Handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE; QSPI_Handle.Init.ClockMode = QSPI_CLOCK_MODE_0; QSPI_Handle.Init.FlashID = QSPI_FLASH_ID_1; QSPI_Handle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; HAL_QSPI_Init(&QSPI_Handle); } ``` 步骤2:发送命令和数据的函数 ```c // 发送命令(8位)和参数(可选) static void ST77916_SendCommand(uint8_t cmd) { QSPI_CommandTypeDef s_command; s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = cmd; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; HAL_QSPI_Command(&QSPI_Handle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); } // 发送数据(8位数据) static void ST77916_SendData(uint8_t data) { QSPI_CommandTypeDef s_command; s_command.InstructionMode = QSPI_INSTRUCTION_NONE; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; // 单线模式发送数据,也可以使用四线模式(QSPI_DATA_4_LINES)如果支持的话 s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; // 数据长度:1字节 s_command.NbData = 1; HAL_QSPI_Command(&QSPI_Handle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); HAL_QSPI_Transmit(&QSPI_Handle, &data, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); } // 发送多个数据(数组) static void ST77916_SendDataMulti(uint8_t *data, uint32_t count) { if (count == 0) return; QSPI_CommandTypeDef s_command; s_command.InstructionMode = QSPI_INSTRUCTION_NONE; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; // 或者四线模式 s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; s_command.NbData = count; HAL_QSPI_Command(&QSPI_Handle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); HAL_QSPI_Transmit(&QSPI_Handle, data, HAL_QPSI_TIMEOUT_DEFAULT_VALUE); } ``` 步骤3:初始化序列(示例,具体命令需参考手册) ```c void ST77916_Init(void) { // 硬件复位(如果有复位引脚) // ... // 软件复位 ST77916_SendCommand(0x01); HAL_Delay(100); // 退出睡眠模式 ST77916_SendCommand(0x11); HAL_Delay(120); // 设置像素格式(16位RGB565) ST77916_SendCommand(0x3A); ST77916_SendData(0x55); // 16位/pixel // 设置方向(旋转) ST77916_SendCommand(0x36); // 根据手册设置参数(例如:0x00表示正常方向) ST77916_SendData(0x00); // ... 其他初始化命令 // 打开显示 ST77916_SendCommand(0x29); } ``` 步骤4:刷新屏幕(使用间接模式) ```c void ST77916_DrawFrame(uint16_t *pixels, uint32_t count) { // 发送命令(0x2C) ST77916_SendCommand(0x2C); // 发送像素数据(注意:每个像素16位,所以count是像素个数,但数据是16位的,因此需要转换为字节流) // 注意:HAL_QSPI_Transmit要求数据是uint8_t*,所以需要转换 ST77916_SendDataMulti((uint8_t*)pixels, count*2); // 每个像素2字节 } ``` 注意:以上代码是简化示例,实际开发中需要根据具体硬件和显示屏规格调整。特别是QSPI的数据线模式(单线、四线)需要根据显示屏支持情况设置。 另外,为了提高刷新速度,可以使用DMA传输。在HAL_QSPI_Transmit函数中,可以使用HAL_QSPI_Transmit_DMA。 由于QSPI接口的复杂性,建议参考ST提供的QSPI外设文档和ST77916的数据手册。 相关问题: 1. ST77916的QSPI初始化序列有哪些关键命令? 2. 如何优化ST77916的屏幕刷新速度? 3. 在STM32中,如何使用内存映射模式刷新QSPI接口的显示屏? 4. ST77916的QSPI接口支持哪些数据格式?</think>### ST77916 QSPI显示屏驱动开发指南 开发ST77916的QSPI接口驱动程序需要结合显示屏规格书和MCU的QSPI外设特性。以下是关键步骤和代码示例: #### 1. 硬件配置要点 - **QSPI模式**:ST77916支持单/双/四线SPI模式,QSPI需配置为**四线模式** - **时钟频率**:建议初始使用10-20MHz,稳定后可提升至80MHz(参考规格书最大值) - **信号线连接**: ``` QSPI_CLK → SCL QSPI_IO0 → SDA (MOSI) QSPI_IO1 → MISO (用于读取状态) QSPI_IO2 → RES (可选复用) QSPI_IO3 → DC (命令/数据选择) QSPI_NSS → CS ``` #### 2. 核心驱动函数实现 ```c /* 命令/数据选择 */ #define ST77916_CMD 0 #define ST77916_DATA 1 /* QSPI传输结构体配置 */ void ST77916_Send(uint8_t type, uint8_t* data, uint32_t size) { QSPI_CommandTypeDef cmd = { .InstructionMode = QSPI_INSTRUCTION_NONE, .AddressMode = QSPI_ADDRESS_NONE, .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, .DataMode = (size > 0) ? QSPI_DATA_4_LINES : QSPI_DATA_NONE, .DummyCycles = 0, .NbData = size, .DdrMode = QSPI_DDR_MODE_DISABLE, .DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY, .SIOOMode = QSPI_SIOO_INST_EVERY_CMD }; // 设置DC线状态(命令/数据选择) HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, type); // 执行传输 HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT); if(size > 0) { HAL_QSPI_Transmit(&hqspi, data, HAL_QSPI_TIMEOUT_DEFAULT); } } /* 初始化序列 */ void ST77916_Init(void) { // 硬件复位 HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET); HAL_Delay(120); // 软件复位 uint8_t sw_reset[] = {0x01}; ST77916_Send(ST77916_CMD, sw_reset, sizeof(sw_reset)); HAL_Delay(150); // 设置像素格式 (RGB565) uint8_t pixel_format[] = {0x3A, 0x55}; // 0x55=16bpp ST77916_Send(ST77916_CMD, pixel_format, sizeof(pixel_format)); // 设置显示方向 uint8_t madctl[] = {0x36, 0x00}; // 0x00=正常方向 ST77916_Send(ST77916_CMD, madctl, sizeof(madctl)); // 退出睡眠模式 uint8_t sleep_out[] = {0x11}; ST77916_Send(ST77916_CMD, sleep_out, sizeof(sleep_out)); HAL_Delay(120); // 开启显示 uint8_t disp_on[] = {0x29}; ST77916_Send(ST77916_CMD, disp_on, sizeof(disp_on)); } ``` #### 3. 显存刷新优化 使用**内存映射模式**可大幅提升刷新率: ```c void ST77916_EnableMemoryMap(void) { // 配置QSPI为内存映射模式 QSPI_CommandTypeDef cmd = { .Instruction = 0x2C, // 显存入命令 .InstructionMode = QSPI_INSTRUCTION_4_LINES, .AddressMode = QSPI_ADDRESS_4_LINES, .AddressSize = QSPI_ADDRESS_24_BITS, .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE, .DataMode = QSPI_DATA_4_LINES, .DummyCycles = 8, // 根据规格书要求设置 .NbData = 0, .DdrMode = QSPI_DDR_MODE_DISABLE }; HAL_QSPI_Command(&hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT); HAL_QSPI_MemoryMapped(&hqspi); } // 使用示例 #define DISPLAY_BUFFER ((volatile uint16_t*)0x90000000) void UpdateScreen(void) { ST77916_EnableMemoryMap(); // 直接操作内存地址入像素 DISPLAY_BUFFER[0] = 0xF800; // 红色像素 (RGB565) } ``` #### 4. 关键注意事项 1. **时序参数**:需严格遵循规格书中的建立/保持时间要求 2. **DMA传输**:使用`HAL_QSPI_Transmit_DMA()`提升大数据量传输效率 3. **双缓冲机制**:防止屏幕撕裂现象 4. **电源管理**:休眠模式需保持1.8V最小供电[^1] > 完整实现需参考:[ST77916规格书](https://www.displayfuture.com/Display/datasheet/controller/ST77916.pdf) 和 [STM32 QSPI编程手册](https://www.st.com/resource/en/programming_manual/pm0215-stm32f0xxx-cortexm0-programming-manual-stmicroelectronics.pdf)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值