ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

U8g2 在 STM32L031 上的 DMA SPI 驱动性能实测:SW/HW/DMA 三种传输方式 FPS 与内存对比

U8g2 在 STM32L031 上的 DMA SPI 驱动性能实测:SW/HW/DMA 三种传输方式 FPS 与内存对比 嵌入式嵌入式GUI驱动开发【免费下载链接】u8g2U8glib library for monochrome displays, version 2项目地址https://gitcode.com/gh_mirrors/u8/u8g2点击查看免费下载导读本文基于 U8g2 仓库中的官方 DMA 性能测试工程sys/arm/stm32l031x4/u8g2_dma_spi_2mhz完整还原 STM32L031 驱动 UC1609 SLG19264 单色屏时软件模拟 SPISW SPI、硬件 SPIHW SPI与 DMA SPI 三种数据传输方式的实测帧率FPS与静态内存BSS占用并深入解析 u8x8cb.c 中三个 byte 回调函数的底层实现差异。读完本文你将掌握如何在 Cortex-M0 上为 U8g2 接入 DMA SPI 传输、三种方式在 2MHz 与 32MHz 主频下的真实性能差距以及全缓冲full buffer与页缓冲page buffer模式各自的内存代价可直接复用到自己的 STM32 裸机工程中。一、测试工程概览该工程位于sys/arm/stm32l031x4/u8g2_dma_spi_2mhz/是一个以gnu-arm-none-eabi工具链构建的裸机 C 工程由以下几部分组成文件作用main.c主程序时钟切换、显示初始化、FPS 计测与循环刷屏u8x8cb.cU8x8 回调层GPIO/延时回调 HW SPI / DMA SPI 字节回调delay.c基于 SysTick 的微秒级延时实现MakefileGNU ARM 构建脚本含upload/clean目标stm32l031x4.ld链接脚本测试对象是UC1609 SLG19264192×64 点阵显示屏其驱动定义与三种 Setup 函数页缓冲_1、_2与全缓冲_f位于 csrc/u8g2_d_setup.c。二、实测性能数据2MHz 与 32MHz 主频工程 READMEREADME.md给出了两组权威实测数据。测试中 MCU 系统时钟分别运行在2MHz与32MHz同一屏幕分别使用全缓冲构造器uc1609_slg19264_f与页缓冲构造器uc1609_slg19264_1并切换三种 SPI 传输方式。2.1 系统时钟 2MHzHSI 4MHz 分频场景ConstructorSysClkTransferFPSBSS (RAM)uc1609_slg19264_f2MHzSW SPI0.31692uc1609_slg19264_f2MHzHW SPI4.71692uc1609_slg19264_f2MHzDMA SPI5.01948uc1609_slg19264_12MHzSW SPI0.3348uc1609_slg19264_12MHzHW SPI2.6348uc1609_slg19264_12MHzDMA SPI2.66042.2 系统时钟 32MHzPLL 场景ConstructorSysClkTransferFPSBSS (RAM)uc1609_slg19264_f32MHzSW SPI6.01692uc1609_slg19264_f32MHzHW SPI73.81692uc1609_slg19264_f32MHzDMA SPI76.71948uc1609_slg19264_132MHzSW SPI5.6348uc1609_slg19264_132MHzHW SPI39.6348uc1609_slg19264_132MHzDMA SPI40.7604说明数据来源为工程 README 及 main.c 中的注释二者完全一致。2.3 数据解读SW SPI 是性能瓶颈32MHz 主频下全缓冲模式仅 6.0 FPS因为每个比特都要由 CPU 通过 GPIO 翻转产生且 u8x8cb.c 中时钟/数据引脚翻转均依赖 CPU 逐位执行HW SPI 带来数量级提升32MHz 下全缓冲从 6.0 FPS 跃升至 73.8 FPS约 12 倍数据传输交给 SPI 外设硬件完成CPU 仅负责逐字节写数据寄存器DMA SPI 进一步榨干外设32MHz 下全缓冲达到 76.7 FPS比 HW SPI 再提升约 4%页缓冲模式达到 40.7 FPS比 HW SPI 的 39.6 略高页缓冲内存优势明显_1构造器 BSS 仅 348 字节DMA 版 604 字节而全缓冲_f需 1692 字节DMA 版 1948 字节多出的约 256 字节正是 u8x8cb.c 中 DMA 中转缓冲区dma_buffer[256]的占用低主频下差异被 SPI 时序掩盖2MHz 主频时 HW SPI 与 DMA SPI 差距极小4.7 vs 5.0此时瓶颈已不在传输本身而在于整机执行帧绘制逻辑的速度。三、硬件接线STM32L031 与 UC1609 SLG19264工程提供了手绘接线示意图与实物连线照片二者相互印证实物照片中屏幕正显示STM32L031 02 MHz 069 FPS:005.1即 2MHz 主频下 FPS 计测画面。SPI 四线接法不含 I2C 的 SDA/SCL对应关系如下GPIODisplayColorPA14CDbrown棕PA13CSyellow黄PA7MOSIgreen绿PA6Resetwhite白PA5SCKpurple紫该映射在 u8x8cb.c 的注释中与代码一一对应PA5 作 SCK、PA7 作 MOSI数据、PA13 作 CS、PA14 作 CD数据/命令选择、PA6 作 Reset。需要留意的是该工程未使用硬件片选SPI1-CR1中开启了SSM | SSI软件管理 NSSCS 引脚完全由 GPIO 回调手动控制。四、U8g2 回调机制与三种传输的实现剖析U8g2 的显示驱动层通过两个回调把上层绘图指令最终落到硬件byte 回调u8x8_byte_hw_spi、u8x8_byte_dma_spi等负责U8X8_MSG_BYTE_SEND、U8X8_MSG_BYTE_START_TRANSFER、U8X8_MSG_BYTE_END_TRANSFER、U8X8_MSG_BYTE_SET_DC等消息消息定义见 csrc/u8x8.hGPIO/延时回调负责U8X8_MSG_GPIO_SPI_CLOCK、U8X8_MSG_GPIO_SPI_DATA、U8X8_MSG_GPIO_CS、U8X8_MSG_GPIO_DC、U8X8_MSG_GPIO_RESET及各延时消息。在 main.c 的initDisplay()中通过切换u8g2_Setup_uc1609_slg19264_f的第三个参数即可在三者间切换// 软件模拟 SPI注释状态 // u8g2_Setup_uc1609_slg19264_f(u8g2, U8G2_R2, u8x8_byte_4wire_sw_spi, u8x8_gpio_and_delay_stm32l0_spi); // 硬件 SPI u8g2_Setup_uc1609_slg19264_f(u8g2, U8G2_R2, u8x8_byte_stm32l0_hw_spi, u8x8_gpio_and_delay_stm32l0_spi); // DMA SPI注释状态 // u8g2_Setup_uc1609_slg19264_f(u8g2, U8G2_R2, u8x8_byte_stm32l0_dma_spi, u8x8_gpio_and_delay_stm32l0_spi);u8x8_byte_4wire_sw_spi是 U8g2 内置的软件 SPI 字节回调直接调用U8X8_MSG_GPIO_SPI_CLOCK/U8X8_MSG_GPIO_SPI_DATA消息驱动 GPIO 翻转对应 u8x8cb.c 中 PA5/PA7 的 BSRR 原子操作。4.1 硬件 SPICPU 逐字节搬运u8x8_byte_stm32l0_hw_spiu8x8cb.c的核心流程case U8X8_MSG_BYTE_SEND: data (uint8_t *)arg_ptr; while( arg_int 0 ) { while ( (SPI1-SR SPI_SR_BSY) || (DMA1_Channel3-CNDTR ! 0) ) // 等待上次传输完成 ; *(uint8_t *)(SPI1-DR) *data; // 逐字节写入数据寄存器 data; arg_int--; } break;在U8X8_MSG_BYTE_INIT中完成 SPI1 时钟使能、PA5/PA7 复用模式配置AF0、SPI1-CR1主模式配置MSTR | SSM | SSICPHA/CPOL 均为 0即 SPI Mode 0并明确 SPI 时钟分频由主频决定、未强制预分频2MHz 场景无需分频。4.2 DMA SPI外设自动搬运u8x8_byte_stm32l0_dma_spiu8x8cb.c在 HW SPI 基础上引入 DMA1 通道 3U8X8_MSG_BYTE_INIT除 SPI1 外还使能RCC_AHBENR_DMA1EN通过DMA1_CSELR将通道 3 请求源选择为SPI_TX配置CMAR内存地址指向dma_buffer与CPAR外设地址指向SPI1-DR并使能SPI1-CR2 SPI_CR2_TXDMAEN发送 DMA 使能U8X8_MSG_BYTE_SEND由于回调返回后arg_ptr指向的数据区会被覆盖先手动拷贝到全局dma_buffer[256]注释明确说明memcpy反而更慢因此使用循环赋值随后重置通道CCR 0CNDTR arg_int传输字节数再置MINC内存地址递增、DIR内存到外设、EN使能通道启动传输同步等待在U8X8_MSG_BYTE_SET_DC与U8X8_MSG_BYTE_END_TRANSFER处均通过(SPI1-SR SPI_SR_BSY) || (DMA1_Channel3-CNDTR ! 0)等待 DMA 传输真正完成随后才切换 DC 或拉高 CS。关键结论由源码结构推断DMA SPI 的加速本质是CPU 只负责一次内存拷贝 启动 DMA剩余的逐字节 SPI 发送完全由 DMA 与 SPI 外设流水完成。在本测试中 DMA 拷贝 256 字节的开销被外设级并发所抵消因此在 32MHz 下获得约 4% 的额外提升但代价是 256 字节的全局 DMA 缓冲区常驻 BSS——这正是第二节表格中 DMA 列 BSS 比 HW 列多出约 256 字节的直接原因。4.3 页缓冲与全缓冲的内存差异从 csrc/u8g2_d_setup.c 可以看到三个构造器的缓冲差异uc1609_slg19264_1调用u8g2_m_24_8_1仅分配 1 页缓冲页高 8 像素uc1609_slg19264_2调用u8g2_m_24_8_22 页缓冲uc1609_slg19264_f调用u8g2_m_24_8_f全缓冲一次性容纳整幅 192×64 画面。三者的刷新流程也不同页缓冲用u8g2_FirstPage()/u8g2_NextPage()分页绘制main.c 即采用此模式全缓冲则用u8g2_ClearBuffer()/u8g2_SendBuffer()。实测数据显示帧率上全缓冲明显优于页缓冲76.7 vs 40.7但代价是 BSS 从 604 字节涨到 1948 字节在 RAM 紧张的 MCU 上需要权衡。五、FPS 计测方法SysTick 计时main.c 的测速逻辑非常简洁可复用到任何工程startUp()中配置 SysTick 每 10ms 触发一次中断main.cSysTick_Handler累加全局计数SysTickCount主循环每完成一次完整刷屏frame_cnt同时计算fps frame_cnt*1000 / diffdiff为 10ms 刻度计数再拆出整数与小数部分屏幕上实时显示STM32L031、系统主频MHz、计数器值与FPS:x.xmain.c。同时PA9被配置为输出并随每帧翻转可用示波器/逻辑分析仪直接观测帧周期main.c。六、系统时钟切换HSI 与 PLL测试覆盖 2MHz 与 32MHz 两个主频点切换逻辑在setHSIClock()main.c2MHz 场景直接使用 HSI 4MHz 时钟setHSIClock()被注释代码注释表明2MHz uC Clock32MHz 场景使能 HSI 并开启RCC_CR_HSIDIVENHSI 4 分频 → 4MHz随后配置 PLLPLLMUL16 | PLLDIV2即 4MHz × 16 ÷ 2 32MHz切换时钟源后调用SystemCoreClockUpdate()同步全局变量。延时函数delay_micro_seconds()delay.c依赖SystemCoreClock换算系统 tick因此 README 与代码均强调必须先调用SystemCoreClockUpdate()再使用延时。七、构建、烧录与复现实验该工程使用 GNU ARM 工具链构建Makefile关键配置如下架构-mcpucortex-m0plus -mthumb定义STM32L031xx优化等级-Os源码组织CSRC : $(wildcard *.c)收集本目录源文件U8G2SRC : $(wildcard ../../../../csrc/*.c)全量编译 U8g2 的 csrc 源码系统库取自../../stm32l031x6/stm32l0xx/该目录同时存放 STM32L0 标准外设库的头文件与源文件链接使用 stm32l031x4.ld并开启--gc-sections裁剪未引用段。常用命令make # 生成 u8g2_test.hex / .elf / .dis并打印 size make clean # 清理所有生成物 make upload # 通过 stm32flash 以 115200 波特率写入串口设备脚本内为 /dev/ttyUSB0复现性能对比的完整步骤保持u8g2_Setup_uc1609_slg19264_f(u8g2, U8G2_R2, u8x8_byte_stm32l0_dma_spi, u8x8_gpio_and_delay_stm32l0_spi);为有效行注释掉其他两个 Setup 调用默认setHSIClock()被注释时测 2MHz 场景取消注释后测 32MHz 场景将构造器换成uc1609_slg19264_1并保持u8g2_FirstPage/NextPage循环即可对比页缓冲数据编译烧录后读取屏幕上的FPS:x.x并与第二节表格对照。八、工程延伸与参考同系列还有 sys/arm/stm32l031x4/u8g2_dma_spi_32mhz 与 sys/arm/stm32l031x4/u8g2_test 工程可对比不同主频与不同显示驱动下的表现UC1609 页/全缓冲 Setup 的定义集中在 csrc/u8g2_d_setup.cDMA 用到的 SPI_TX 请求映射与 SPI 外设寄存器操作见 u8x8cb.c该工程最初针对 U8g2 issue #2564DMA 性能讨论而建立实测结论即本文第二节的两组数据若需在 Linux 上快速验证 U8g2 的 SW/HW 传输差异可参考 sys/sdl 下的 SDL 仿真示例本工程则适用于真实硬件时序验证。总结对 Cortex-M0 这类资源受限平台DMA SPI 是用 256 字节 BSS 换约 4% 帧率提升的划算选择而 HW SPI 已是性价比最高的方案若 RAM 紧张_1页缓冲构造器配合 HW/DMA SPI 可在 348/604 字节 BSS 下获得接近全缓冲 50% 的帧率。实际选型时请结合自身主频、可用 RAM 与显示刷新需求参考本文第二节的完整数据表决策。赞分享嵌入式嵌入式GUI驱动开发【免费下载链接】u8g2U8glib library for monochrome displays, version 2项目地址https://gitcode.com/gh_mirrors/u8/u8g2点击查看免费下载相关推荐ts-pattern 高级玩法P.array、P.record、P.set、P.map 与可变元组匹配深度教程ts pattern 高级玩法P.array、P.record、P.set、P.map 与可变元组匹配深度教程 ts pattern 是 TypeScript嵌入式嵌入式GUI驱动开发Gist插件与GitHub无缝集成企业版API URL自定义教程Gist插件与GitHub无缝集成企业版API URL自定义教程 你是否在使用Sublime Text编辑器时希望将代码片段快速分享到GitHub Gist开发工具CANN/catlass Tile逐元素乘法TileElemwiseMul 代码位置 https://link.gitcode.com/i/db1feec07d057aadc3bb048c308537b7算子库人工智能深度学习高性能计算CANNAscend上一篇逆向工程师工具集构建Windows恶意PDF分析的完整解决方案下一篇qm 会话分享Session Sharing机制全解析只读快照、受众控制与安全边界创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表