MCU与外设驱动问答总集

📚 总集 📅 2026-09-04
#来源/立芯星球 #类型/问答总集 #技术/MCU外设

MCU与外设驱动问答总集

本目录 5 篇问答合集(中断与NVIC / DMA与总线 / 串口UART / ADC采样 / BSP分层与驱动架构)+ 102 篇散帖的全量知识重组。按知识相关性组织为十二章:时钟与启动流程 → GPIO → 中断与 NVIC → DMA 与总线矩阵 → 定时器与 PWM → ADC 与模拟前端 → 串口 UART → I2C/SPI 总线与传感器 → 低功耗与电源 → BSP 分层与驱动架构 → 调试外设的典型案例 → 硬件与板级周边。原帖全部保留,每条末尾标注出处;同一问题多来源合并为多源引用。

知识地图

  1. 时钟、体系结构与启动流程 — 内核架构基础 / 时钟系统 / 复位启动全链路 / BOOT 模式 / 分散加载与重定位 / 存储介质与固件安全
  2. GPIO — 复用与重映射 / M3-M4 总线挂载差异
  3. 中断与 NVIC — 中断延时与优化 / 仲裁与嵌套 / 屏蔽语义 / ISR 与 RTOS / 编写守则 / HardFault
  4. DMA 与总线矩阵 — 速率与仲裁 / 双端口 / 总线拓扑 / Burst / 案例复盘
  5. 定时器与 PWM — 延时方案 / 多任务定时调度
  6. ADC 与模拟前端 — 转换模式 / ADC+DMA 架构 / HAL 回调 / 前端硬件 / 标定
  7. 串口 UART — 断帧 / 双缓冲与解包 / 收发架构 / 实战优化案例 / printf
  8. I2C / SPI 总线与传感器 — I2C 仲裁与 I3C / SPI 主从 / 总线冲突 / 传感器抽象
  9. 低功耗与电源 — 功耗模型 / GPIO 倒灌与 inrush / 休眠档位
  10. BSP 分层与驱动架构 — 分层链路 / Handler 线程模型 / 私有数据 / 事件驱动 / 分层代价 / HAL 库 / 内存管理
  11. 调试外设的典型案例 — LCD / LVGL / SWD-JLink / 栈回溯 / Bringup / 开发环境
  12. 硬件与板级周边 — 三极管与 MOS / 0 欧电阻 / 样机测试 / PCB 设计

一、时钟、体系结构与启动流程

1.1 内核与体系结构基础

哈佛架构 vs 冯诺依曼架构:哈佛架构 RAM 存数据、Flash 存代码,有 I-Bus / D-Bus 两条总线分别取指、取数,并行运行速度快;冯诺依曼架构(PC 常见)代码与数据都拷到 RAM 后用一条总线访问,理论上速度不及哈佛。

冯诺依曼和哈佛架构区别: 哈(Jack)

"Cortex-M3/M4 架构"指什么:指的是 CPU 内部电路设计(内核微架构),而非 SoC 框图中的总线拓扑(配图解答)。

老师,我想知道我们常说的Cortex-M3架构和Cortex-M4架构(Jack)

ARM 与 RISC-V 对应用开发的影响(提问未答):用 C 写程序时几乎感知不到指令集架构差异。

arm架构,risc-v架构的区别对我们开发嵌入式软件的有什么地方的影响(奶龙)

SCB(系统控制块):Cortex-M 内核里管理异常、系统状态、优先级、向量表的寄存器集合,不是外设。常见成员:VTOR(向量表地址)、AIRCR(优先级分组/系统复位)、ICSR(异常状态/PendSV 挂起)、SHPR(系统异常优先级)、CFSR/HFSR(Fault 状态,排查 HardFault 常看)、CCR。改中断分组、切向量表、软复位、查 fault 原因都绕不开它。

SCB是什么: 在 Cort(Jack)

PC 与 LR:LR 装的是当前函数退出后将要执行的第一条指令地址;PC 装的是即将执行(还没执行)的指令地址。

老师,PC和LR寄存器的理解不够透彻,能再说下(Jack)

汇编里的"绕路"不是多此一举:ARM 很多算术/逻辑操作只能在寄存器中进行。把值给 R0 → 清 R0 最低位 → 写回 R3 指向的内存,实际是读内存→改位→写回内存,并非在清 R3 本身。

老师,为什么清除R3的值会这么麻烦,把值给r0 清除r0的值然后再赋值给R3(Jack)

学习资料:Cortex-M 深入开发必读《Cortex-M3 权威指南》(PDF 资源)— 分享一本Cortex-M开发若要深入开发必读的一本书(Jack);权威指南看哪章是重点之问未答 — 老师,要看ARM cortex-m3与m4权威指南的话,哪一章是重点(不破不立)。

1.2 时钟系统

上电先用 HSI 再切 HSE:单片机启动先用内部晶振,内部时钟给外部晶振提供激励,外部晶振起振稳定后再切换到外部时钟。

老师,请教下,单片机启动的时候是先用内部晶振(Jack)

HSE 与 HSI 的取舍:两者都能把 APB 配到满频,区别在 HSE 是外部时钟、一般更准确;HSI 是内部时钟,精度差一些但启动快、不占引脚。

HSE和HSI都可以将APB总线配置为满频,这样分别使用两者的区别在哪:(Jack)

FCLK 与 HCLK:FCLK 是 HCLK 旁路出的一路。HCLK 驱动 CPU,可以给 CPU 断供时钟使其休眠,但 FCLK 依然供电——CPU 休眠时 FCLK 仍驱动中断查询等唤醒门电路,实现唤醒(free running 的意义)。

STM32中的FCLK和HCLK时钟的区别(Jack)

快速确定外设时钟频率(长文存根):先确定 SYSCLK 来源(HSI/HSE/PLL),看 RCC->CFGR 配置或 CubeMX 时钟树,再沿 AHB/APB 分频系数推到外设。

在 STM32 微控制器中,确定外设时钟频率的步骤如下(山海无名)

M3 与 M4 的 GPIO 挂载差异:F103(M3)时代 GPIO 挂在 APB 上,而 M4 芯片 GPIO 挂载在 AHB 总线——初始化外设时钟时 RCC 参数完全不同,换芯片要看手册确认挂载,不能凭经验。

今天在写标准库代码、初始化配置外设时钟的时候发现打开GPIO外设时钟的时候(Lili_iliLX,长文存根)

1.3 复位与启动全链路

从上电到 main() 的完整链路:上电复位 → 硬件复位初始化(寄存器复位、外设默认态)→ BootROM(厂商流片固化:初始化基础时钟、必要外设,检测 BOOT 模式)→ 用户 Bootloader(可选:PLL 倍频、外设深度初始化、OTA 检测)→ startup_xxx.s(建 C 环境:复制 .data、清零 .bss)→ __main → main()。

上电复位 ↓ 硬(Jack)

取栈顶指针是谁完成的:在 BootROM 中完成——BootROM 根据上电时 BOOT0/BOOT1 引脚配置,去特定位置加载栈顶到 MSP 并执行第一条复位语句。

老师,在第一步过程中,取栈顶指针到msp中,是在谁的指导下完成(Jack)

栈对齐:启动文件指定栈为 8 字节对齐(2³)。

老师,我们单片机的栈在使用时,是多少字节对齐(Jack)

中断向量表在启动时如何就位:启动时通过链接把向量表链接到固件最开头;SystemInit 里有 C 代码做偏移;若打开 USER_VECT_TAB_ADDRESS 宏会再做一次偏移(高级应用才用)。

老师,单片机从flash启动过程中,没有设置中断向量表地址(Jack)

1.4 BOOT 启动模式

三种 BOOT 启动方式(主 Flash / 系统存储器 / SRAM)的本质是把不同存储的地址映射到 0 地址:系统存储器模式从内部 ROM 的出厂代码(厂商 Bootloader,如 USB DFU)启动;SRAM 启动时 SRAM 物理地址 0x2000_0000 被映射到地址 0。BOOT 引脚三种连接方式对应三种映射(图解)。

BOOT的三种启动方式里面,系统存储器模式是从内部ROM中的出厂代码启动(Jack)、boot引脚的三种不同连接方式对应的三种不同的启动方式(Jack)

1.5 分散加载与重定位、RW/ZI

分散加载 vs 重定位(高含金量之问):分散加载(Scatter Loading,即链接控制文件)解决"程序不同部分放到哪个物理地址执行";重定位解决"程序地址不固定,运行前修正成实际地址"。启动时把 rwdata 从 Flash 搬到 RAM(.data 初始化)是"运行时拷贝初始化",属于重定位的一部分而非 scatter loading 本体——分散加载决定 .data 最终在 RAM 的哪个地址,重定位实际完成拷贝让后续引用正确。

老师,这里为什么不是分散加载,(Jack)

RW/ZI 能不能放 Flash 里运行:不能。Flash 按扇区/页整体擦写,而 RW/ZI(全局变量)运行中频繁变更,若放 Flash 每次修改都要"读整扇区→改→写整扇区",速度无法接受。

老师 有个问题 rw和zi段可以不放在sram(Jack)

重定位的工程价值:进入用户空间前把中断向量表搬到 RAM 可减少中断延时,在 ADC 等高速应用中提升整体性能;另一用处是进入用户程序前做前置校验与配置。

重定位的用处: 1.进入用户空(Jack)

飞秒启动两种方式:直接写入 hex 由 Flash 加载并被 cache 加速;函数指针挂载(RAM 中)的数据通过 DMA 在系统启动时填充到 RAM,快速达到系统就绪状态。

飞秒启动起始它分两种方式: 1(Jack)

1.6 存储介质与固件安全

单片机选 NOR 还是 NAND:一般用 NOR——支持字节级随机读取、可直接片上执行(XIP),适合代码存储;NAND 按块寻址、不能直接跑代码,主要用于大容量数据存储。

老师,单片机一般使用 NOR Flash 还是 NAND Flash?为什么(Jack)

Flash 有剩余为何还要 EEPROM 存临时数据:内部 Flash 写入要解锁-写入-上锁、写时要关中断,写多了可持续十到近百毫秒,对高实时项目不可接受。Bootloader 跳转时用内部 Flash 做标志位则无妨——跳转时本来也没有任务在跑。

老师,为什么内部flash空间还有剩余,我们却依然要去eeprom存储一些临时数据(Jack)

擦除内部 Flash 后死机(图问,未答)。

stm32擦除内部flash后死机,死在第二张图有人遇到过(不破不立)

固件加密烧录流程:一般先把密文搬运到内部 RAM,在 RAM 中解密,再刷入内部 Flash。

一般是先把密文搬运到内部ram,然后内部ram进行解密,再刷入内部flash(Jack)

性能基准:Coremark 的 MCU 性能跑分(原帖为图)。

Coremark 的 mcu性(Jack)


二、GPIO

复用、重映射与 AFIO 时钟的关系:重映射 = 先决定外设信号走到哪个引脚;复用 = 再让该引脚切到外设功能。凡是要改映射/重映射/EXTI 路由类寄存器,就需要开对应的 AFIO/SYSCFG/AF 时钟;单纯把 GPIO 设成输入输出只需 GPIO 时钟。remap/mux 位写下后一般即时生效,工程上稳妥顺序:先配 remap/mux → 再配 GPIO AF → 再开外设(如 TIM)输出,避免"波形跑到别的脚"或"脚没接上外设就开始翻转"。

1.重映射 = 先决定这外设信(深蓝问,Jack 答)

SWD 烧录引脚与 GPIO 复用冲突:GPIO 初始化时先读该引脚电平——置高(接了下载器)就不配置该引脚,留作下载口;置低(没接下载器)则正常配置。

烧录引脚和GPIO共用了咋整?(Jack)

(SWD/JTAG 四线波形与 TAP/DAP 细节见 [[#十一、调试外设的典型案例]]。)


三、中断与 NVIC

3.1 中断延时与上半部/下半部

中断延时的定义:中断请求发生到进入 ISR 之前的那段时间。经典分法:上半部是 ISR 内必须立刻做的(最重要的是清中断标志位);下半部是标志位改完后的相关事务,安排在 ISR 之外执行,可有效减少中断服务时间、降低中断延时。

中断延时是中断请求到进入ISR之前的时间,上半部是ISR内必须要做的部分(Jack)
什么是中断延时: 中断延时是 与上篇同文异发,近似重复保留待合并。)

减少中断延迟的四条实操路径:提高中断优先级;减少更高优先级服务函数的执行时间(全局标志位"快进快出");减少临界区;把中断服务函数分散加载到 RAM 执行,减少流水线取指时间。

老师,中断的延迟处理时间要怎么(Jack)

系统级视角——中断偏移:单一中断耗时久不久不重要,重要的是所有中断延时加起来是否构成系统的中断偏移。产生偏移说明中断资源已溢出、系统在中断任务上失去实时性。

单一中断久不久不重要,重要的是所有中断延时加起来是不是构成了整个系统的中断偏移(Jack)

中断优化全景:中断是非常紧俏的资源,处理过久会影响实时性甚至丢中断。上半部优化——精简逻辑、减少不必要的局部变量(避免压栈出栈开销)、中断线程化时用全局变量通知(比 IPC 消耗低);下半部优化——把耗时处理剥离到线程。系统实时性有上限,中断资源比线程资源宝贵得多,宁可在线程里多花时间也要保证中断畅通;负载超过芯片能力时丢中断是必然,此时用看门狗、GPIO+示波器定位瓶颈,软件到极限就升级硬件。

关于中断优化: 中断在系统是一(Jack)

实战:串口框架定制优化(通用框架为通用性不做深度优化):单次拷贝是高速 IO 大忌。压力测试不丢包前提下,方案一保留中断内拷贝、Buf 从 1024 缩到 512,中断执行时间缩到 8us;方案二用任务通知,中断里只算 DMA 接收大小和位置、线程里 memcpy 保存,中断执行时间压缩到 2.6us(详见 [[#七、串口 UART]] 案例)。

往往通用框架为了通用性,往往不会做深度优化(需要传入特定的芯片特性操作(Jack)

3.2 NVIC 仲裁与嵌套

同优先级同时触发:IRQ 号小的先执行(NVIC 手册:If multiple interrupts are pending for the same priority level, the interrupt with the lowest IRQ number is processed first.)。

老师,如果这两个定时器的中断优先级设置的一样,如果同时触发是定时器6会先执行(Jack)

实验观察中断嵌套:两个中断函数分别设断点做对照——在低优先级 ISR 里人为 NVIC_SetPendingIRQ 触发另一中断后 while(1);若能进高优先级的 ISR 说明嵌套发生,卡死在 while(1) 则说明没有嵌套。

怎么看中断有没有嵌套? 观察(Jack)

屏蔽的语义:被中断屏蔽寄存器组屏蔽的中断可以悬起但不能响应——解除屏蔽后仍会补上处理,事件不丢。

使用中断屏蔽寄存器组屏蔽的中断是可以悬起不能响应,还是连悬起都没有(Jack)

任务级开关中断与可屏蔽中断的关系(图答)。

任何中断都可以打断正在执行的任务是吗 可屏蔽的中断起作用是任务重添加tasKDISA(Jack)

3.3 ISR 与 RTOS

ISR 里调 OS API 后的切换时机:在 ISR 中调队列发送等 API 唤醒了高优先级任务,不会立即切换——只置位 PendSV 悬起,退出所有中断后再响应 PendSV 完成任务切换(类似中断下半部思路,不破坏实时性)。若不主动让出,ISR 结束会继续跑被打断的低优任务直到时间片用完或阻塞。

在0-4的中断里面调用os的api函数,也算是执行了这个中断的ISR(Jack)、在中断服务程序中向队列中发送数据时,可能会有更高优先级的任务会因此被唤醒,这里的更高(Jack)、中断中发送消息通知后,如果有高优先级线程被唤醒该怎么办(Jack)

软件中断的用武之地:业务开发用得少,但线程间通信内部到处在用——FreeRTOS 消息队列发送后发现更高优先级任务被唤醒,就触发 PendSV 软件中断做上下文切换。

老师,请问在开发中,软件中断是(Jack)

3.4 ISR 编写守则

不修改共享全局变量:中断内只置标志位或发信号量,让线程有秩序地修改。

中断里面不建议修改被共享的全局变量,中断里面可以置位一个标志位,或者发信号量(Jack)

中断中不能做的五大操作(长文存根):如避免调用依赖 systick 的延时函数(其依赖的定时器中断若优先级更低将无法工作);避免在 ISR 中调用优先级更低的中断相关操作等。

MCU中断中,不能做的五大操作(立芯嵌入式)

3.5 HardFault 与向量表

LR = 0xFFFFFFF1 的含义:进入 HardFault 之前已处于中断之中——错误调用路径是线程 → 中断 → HardFault,为栈回溯定位提供关键线索。

当你在错误中断(Hardfault)中看到LR是0xFFFFFFF1时(Jack)

BOOT 与 APP 能否共用中断向量表(实践困惑,未答)。

关于中断向量表的疑问:如果BOOT和APP的中断服务函数源代码都相同(橙子)


四、DMA 与总线矩阵

4.1 速率与带宽

DMA 速率上限:最高不超过 AHB 总线速度,还受 CPU 抢占总线、外设写入/读出速度限制。想跑高速可用 Burst 模式抢占 AHB 总线

老师,dma的速率是多少?(Jack)

"DMA 降低 AHB 带宽"的正确理解:不是"DMA 搬数据让 CPU 干别的",而是 DMA 不经 CPU 直接把外设数据经 AHB 放进 SRAM,省下的是原本 CPU 访问占用的总线带宽

老师,DMA能降低ahb总线带宽的意思是不是:我们通过dma搬运数据(Jack)

4.2 仲裁与端口

多主设备访问同一总线:CM4 和 DMA2 同时经 APB2 访问 UART 和 ADC 时,UART 和 ADC 不能同时被访问——多主访问经仲裁器(arbiter)串行化。

老师,根据您的对DMA的讲解,ARM CM4和DMA2同时通过APB2访问UART(Jack)

DMA 双端口设计:DMA 有内存端口和外设端口都连到总线矩阵。APB2 数据必须"外设端口收、内存端口写"两段路,因为无法通过外设总线执行内存写操作——这正是双端口设计的原因。

老师,DMA主控有两个端口——内存端口和外设端口。这两个端口都连接到总线矩阵(Jack)

4.3 总线拓扑

同一条 APB2 上多外设不竞争:多个外设可同时发数据而不竞争——APB2 带宽足以支撑同时通信,不会在处理器或 DMA 介入前发生总线竞争。

Q: 老师,如果多个外设连接到(Jack)

CPU 读一次外设经过几次 AHB:CPU 经 S 总线→AHB 矩阵→外设寄存器是一次;把数据搬到 SRAM 又是一次——共两次经过 AHB

老师,cpu去外设读数据时需要经过AHB总线(CPU通过S总线→AHB总线矩阵→SR(Jack)

内核 I/D/S 总线与 MCU 总线矩阵:Cortex-M 内核把取指、数据访问、系统访问分成多个 master 端口(I-Code/D-Code/System),以 AHB-Lite 接入 MCU 总线互连矩阵,形成三条访问通路提升并行性(资料对照之问见图)。

老师们,我在整理资料的时候发现了一个问题,是不是Cortex内核里面也有个Bus(Jack)、各位大佬好,有个问题想请教一下。D-Code是否可以访问SRAM数据?如图一所写(🍊)

D-BUS 访问 SRAM 与启动方式有关:STM32F411 中 D-BUS 具备访问 SRAM 的可能性,但只有从 SRAM 启动时(SRAM 映射到地址 0)才可访问代码区。

STM32F411中D-BUS可以访问到SRAM(高耦合)

外部存储控制器命名:EXMC = External Memory Controller;STM32 叫 FSMC/FMC,GD32/HC32 叫 EXMC,N32 有时仍叫 EXMC。

EXMC = External(Jack)

4.4 Burst 与位宽

Burst 传输图解 — DMA的Burst的理解(Jack);Burst 被抢占打断的图解 — 关于burst的打断(Jack);SPI+DMA 混用时数据位宽匹配(四图详解)— SPI和DMA混合应用数据位宽(Jack)。

4.5 案例复盘:RH850 UART+DMA 接收错位

现象:DMA 启动接收后 Rx 数据整体后移(期望 A B C D…,实际 X A B C D…)。根因不是 DMA 搬错,而是"只发送不接收"阶段 Rx 引脚仍处于 UART 复用输入态,误采集波形残留在外设接收寄存器中;下次使能 DMA 时先把残留数据搬进 buffer,真数据整体后移。解决:按接收状态动态切 Rx 引脚模式——不接收时配成普通 DIO 输入断开 UART 接收链路,接收时再配回复用输入。核心经验:DMA 只是被动搬运工,不判断数据有效性;查 DMA 接收异常不能只盯 DMA 配置,还要查外设输入源是否干净(Rx 引脚模式、接收寄存器、挂起的 DMA request、使能前是否有残留)。

最近在 RH850 平台调试 时,遇到一个比较典型的问题(zzz,👍6)


五、定时器与 PWM

多周期任务的最大公约数定时调度:A 事件 5 秒、B 事件 10 秒、C 事件 15 秒调度一次,取最大公约数 5 秒设一个定时器,在其中断回调里同时调度三个任务;任务更多就设多个"周期公约数"定时器。相当于找到任务在时间轴上的交点,前后台切换几乎不消耗调度;限制是单个回调不能执行太久。

还有一种射线回调就是: 比如说(Jack)

osDelay vs osDelayUntil:osDelay 是相对延时(从调用时刻起算,"吃完早饭等 4 小时"),任务执行超时会导致周期漂移;osDelayUntil 是绝对延时(固定 7:00/12:00/18:00 吃饭),记录上次唤醒时间自动补偿执行耗时,保证周期稳定,首次调用前需设基准 xLastWakeTime = osKernelGetTickCount()。周期性任务(如传感器定时采样)优先用 osDelayUntil,避免累积误差;单次延时用 osDelay 更简单。

osDelay是相对延时(从调用时刻开始计时(Jack,👍3)

微秒级死等延时的方案(图答):另开一个定时器做微秒级死等延时是常见做法。

如果需要做死等的延时,用什么方案更好,我现在一般是再开一个定时器来做微秒级延时(Jack)

CubeMX 配定时器 PWM 为何 clock source 都选 internal clock(提问未答)。

为什么网上cubemx配置定时器输出pwn波(圣井户御代)


六、ADC 与模拟前端

6.1 设备架构总纲(前后端模型)

ADC/串口这类设备分前端后端:前端做数据分发(显式双 buffer / 隐式双 buffer),后端做解包(原地解包 / 异地解包);前端靠近中断,往往具有系统最高优先级。内核优化方向:中断延时、Sbus 总线、Icode、中断向量表、减少嵌套;上半部优化(指针穿透、减少冗余判断);下半部优化(原地/异地解包、显式/隐式双 buffer、流 buffer)。

软件架构层面来说: ADC:(Jack)

6.2 转换模式详解

Scan / Continuous / Discontinuous 三模式:Scan Conversion——使能后每次触发依次转换选中的多个通道,禁用则每次只转单通道;Continuous——使能后一次触发就无限循环转换,禁用则每次转换都需触发;Discontinuous——Scan 使能后的可选配置,把通道分组(如 6 通道、组大小 2 → 0 1 / 2 3 / 4 5),每次触发只转一个小组。

Scan Conversion Mode:是当我们的ADCx选中多个通道时(Jack)

连续与单次都失能会怎样:ADC 在每个触发事件下仅执行一次转换然后停止,适合有信号建立时间、需要在特定时刻采样才精准的场景。

老师,请问ADC中如果连续装换模式和单次转换模式都失能,会发生什么(Jack)

6.3 ADC + DMA 协同

DMA 循环模式与 ADC 连续模式要配套:DMA 循环模式指连续不断地接收 ADC 的 DMA request;不开 ADC 连续模式(转完自动接着转、无需再 start)就没必要开 DMA 循环。Scan 模式即连续转换多通道;EOC 时产生 DMA request,可每通道搬一次或全部转完一起搬。

老师请问开启dma的循环模式必须配合adc的连续模式使用(Jack)

多路 ADC 并行:在 adc1 的中断回调里启动 adc2,buffer 各自分开放;DMA 无需特殊处理,绑定过对应 ADC 就会自动搬运并产生 request。

多路adc实现adc+dma并(Jack)

双 buffer 来不及切换:测试阶段测出峰值,把 buffer 空间设到足够大;嵌入式基本不在运行时 malloc,风险非常大。

adc+dma,双buffer,我们在a线程进行切换的时候(Jack)

实战坑:Normal 模式重启数据错位:DMA Normal 模式搬完停下但 ADC 还没停,重新开启时通道与数组索引不对应。解决:重开 DMA 前先 ADC_STOP

ADC应用经验: 今天被ADC(Jack)

HAL 回调嵌套:用 HAL_ADC_Start_DMA 启动后,ADC 转换完成触发 DMA 传输,DMA 完成整块搬运后才触发 HAL_ADC_ConvCpltCallback——转换完成回调是在 DMA 传输完成回调中被调用的,这是 HAL 库的回调嵌套特性,不会出现"转换完但 DMA 没搬完"就进回调的情况。

老师,还有一个问题,你们给的参考例程中,为什么这里使用adc转换完成的中断回调(Jack)

12 位 ADC 为何申请 32 位缓冲:4 字节存取更有效率(Cortex-M 32 位对齐访问更快、减少总线访问次数);且 HAL 的 HAL_ADC_Start_DMA 要求 uint32_t* 缓冲,DMA 配 16 位传输需手动改初始化配置。

老师,请问这里为什么12位的ADC要申请32位的缓存区(Jack)

6.4 采样前端硬件与标定

为什么要加电压跟随器:采样模块内部阻抗不够,直连分压信号可能有电流流进采样模块、污染信号源。跟随器起隔离作用并增强信号强度,使采集不影响原信号源。

我想问,采样ad为什么要加跟随器,不能直接分压加到采样模块(Jack)

标定的定义:生产线上用测试仪器让传感器的值微调到与仪器一致。

传感器测出来的值,是怎么确定正确的还是错误的?如何标定(Jack)

量产高精度怎么标:出厂都要校准——装配公差、批次差异带来系统误差;产线每个传感器单独标定,标定数据出厂时通过 JLink 下载算法写入外部 Flash、EEPROM 或内部 Flash 特定区域。

老师好哇,话说那个咱们温湿度传感器量产的时候要达到这么高的精度(Jack)

原始数据的定点化处理(AHT21 湿度为例):除 2^20 用右移等价替换提升效率;直接右移必损精度,所以先放大再右移——乘 1000 右移 20 位、后续除 10 得小数点后一位;要两位精度就乘 10000 右移、再除 100。

老师,是不是到红框这里时我们的retu_data已经是湿度的原始数据(Jack)

6.5 未答之问

注入通道与规则通道的区别及使用场景 — 老师,adc 的注入通道和规则通道有什么区别,分别在什么场景下用(这是一个好听的id);8 通道 3 类数据多应用分发的采样任务设计 — 大佬好,假设我ADC1里面8个通道都要用上,有3个通道用来测不同气管的压力(权)。


七、串口 UART

7.1 不定长接收与断帧

没有空闲中断怎么断帧:自己查询 DMA 剩余传输长度、结合时间来断帧——很多没有串口空闲中断的单片机都这么做,还能节省中断资源

串口dma接收,不用idle的话,可以自己查询dma剩余传输长度结合时间来断帧(Jack)、单片机的串口本身没有空闲中断怎(Jack,图解)

有空闲中断时的指针偏移法:不定长接收不能靠 DMA 定长中断,要用指针偏移法配合空闲中断——每次空闲产生就自动解析数据,但不要去干预 DMA,否则容易挂。

这里不能靠dma中断去定长度进(匿名提问,Jack 答)

7.2 收发架构

为什么解析不放在前端:数据解析可能耗时过长、不能及时响应中断——前端职责是尽快把数据收下来,解析放后端。

看完串口相关视频我是这么理解的:串口接收不定长架构(Jack)

串口 DMA + 环形缓冲与协议帧:发送用定长 buffer + 串口 DMA 发送;接收用串口 + 环形缓冲实时收命令;自定义协议帧结构:包头识别符、包长度、净荷数据、包尾识别符

老师,我们的串口dma加环形缓冲区主要是用于传输数据(Jack)

显式/隐式双 buffer 与原地/异地解包:显式双 buffer 是两个独立缓冲区、满后切换,配合 DMA Normal 模式全满切换并通知线程解包;隐式双 buffer 只有一个缓冲区、半满即通知,用半满中断+全满中断+Circular 模式实现同一 buffer 前后半段复用。原地解包:数据在哪就在哪拆、免拷贝,中断时间短、指针快速切换,但数据快时可能覆盖未解包数据(取决于解包线程速度);异地解包:DMA 把未解包数据提前搬走,不会被新数据覆盖、对解包线程实时性要求宽松,但空间开销大且多一次 DMA 搬运。

数据缓冲与解包: 以串口为例(Jack,图解)

一读多写串口策略模式(设计图)。

一读多写串口策略模式(Jack)

7.3 疑难与案例

最后一个字节先发出来:使用 ST 串口发送函数出现此现象,多半是环形缓冲区上一包数据还没发完(发送时序被上一包残留占用)。

我猜测,因为你的环形缓冲区没有(Jack)

中断耗时优化案例(与 [[#三、中断与 NVIC]] 互链):串口定制优化把中断执行时间从 8us 压到 2.6us——中断里只记录 DMA 接收大小与位置,拷贝移到线程,配合任务通知,压力测试不丢包。

往往通用框架为了通用性,往往不会做深度优化(需要传入特定的芯片特性操作(Jack)

RH850 UART+DMA 数据错位复盘:DMA 使能前外设接收寄存器有脏数据导致整体后移,解法是按状态切换 Rx 引脚复用模式——详见 [[#4.5 案例复盘:RH850 UART+DMA 接收错位]]。

最近在 RH850 平台调试 时,遇到一个比较典型的问题(zzz)

USB 口当串口:可以,USB 枚举成 CDC 串口,但需要系统完整跑起来,否则枚举不成功、电脑端不出 COM 口。

我想问一下,单片机的USB口,可以当串口使用吗?我之前USB口是用串口,用来调试(Jack)

参考工程:串口单字节不定长双 buffer 的 DMA 和 CPU 并行工作 Demo 完整工程(zip 附件)。

B站视频中的串口单字节不定长双buffer的DMA和CPU并行工作Demo(Jack)

7.4 printf

printf 无法输出中文的解决方式之一(图)— printf无法输出中文的解决(Jack);标准库 printf 内存占用不小——重定位时会申请一个 printf 使用的缓冲空间 — print这种内存占用也大吗?(Jack)。


八、I2C / SPI 总线与传感器

8.1 I2C

I2C 仲裁过程:主机 A、B 同时发送,第一时钟周期 SDA 电平相同继续传;第二周期 A 发高、B 发低,总线为低,A 检测到冲突停止发送转接收,B 继续完成传输。

IIC仲裁简单描述是怎么样的?(Jack,👍2)

I2C 基础资源:IIC 通信简介、为什么要加上拉电阻、面试如何回答 I2C(B 站视频链接)。

1、 IIC通信简介(立芯嵌入式)

I3C 前沿(MIPI 推出的 I2C 迭代总线):省去独立中断引脚,支持带内中断 IBI(地址号越小优先级越高);速率大幅提升——I2C 封顶 3.4MHz,I3C 默认 SDR 12.5Mbps,HDR 档最高 37.5Mbps;主机动态分配地址、兼容老式 I2C 从机(不支持 10 位拓展地址);推挽输出增强驱动,不支持 I2C 的时钟拉伸。两根线整合多外设接口,省 GPIO、降 PCB 成本。

很多人都会用 I2C,目前 I3C 也正在普及和落地,带大家前沿看一下 I3C(Jason)

模拟 I2C 被编译器优化:调整优化等级后温度读不出——要对驱动代码做禁止优化修饰(#pragma O0__attribute__((optnone)) 等),否则优化指令顺序/循环展开会破坏外部时序。

老师,调整优化等级后,我的温度读不出来了,用的模拟IIC,这怎么办(Jack)

未答之问:中断里读陀螺仪与线程刷屏抢 I2C 总线的冲突方案 — 想问一个问题: 最近我在做一个(少年、潜行);同一 I2C 总线两颗 MPU6050 的写寄存器接口如何区分对象 — 老师,如果我有两个MPU6050,都挂接在同一个IIC总线上,它们通过地址来区分(mx)。

8.2 SPI

SPI 从机主动上报:从机不能通过 SPI 机制主动给主机发消息,要通过另一根 IO 告诉主机"数据就绪,可以来取"(公司代码把 GPIO 拉低,主机配成中断)。

老师,公司里面一个项目:spi从设备想主动发数据给主机的话,可以怎么实现(Jack)

未答之问:SPI 多从机的多 NSS 与菊花链的使用场景、与 I2C 多从机对比 — jack老师,您好,请问SPI中的多从机模式,多NSS和菊花链(😌);SPI 控制器驱动在 RTOS 下同步/异步两种收发的框架思路 — 大佬,如果是spi控制器驱动要怎么以怎么样的思路和框架写好(无能狂怒人)。

8.3 传感器驱动

设备多通信接口的抽象之问(未答):bsp_aht21_driver_t 中 iic_driver 函数指针给 AHT21 提供通信接口;若设备有多种接口(如 MPU6050 有 IIC 和 SPI),可用结构体带接口类型 + handler 传入类型、inst 里 switch 选择。

看了b站的aht21驱动视频,(爱健身的机器人)

资源:AHT21 驱动调用流程图(PDF)— AHT21驱动的调用流程参考(Jack);驱动视频 speaker 驱动文件(zip)— 驱动视频里的那个speaker驱动文件,大家可以参考(Jack)。


九、低功耗与电源

功耗模型先行:针对低功耗的功耗模型做有条件的待机时长优化,是做低功耗的开始。

针对低功耗的功耗模型,做有条件的待机时间时长优化是做低功耗的开始(Jack)

GPIO 倒灌的机理与排查:本质是某电源域已掉电但外部信号仍给 GPIO 高电平,电流经 ESD 二极管/钳位电路反向灌入电源域。典型现象:进低功耗后整机电流异常偏大;断开的电源域上仍有"虚电压";断开某根外设线低功耗电流立刻恢复;关机后某些 GPIO 还有电平、芯片半上电。

我看了咱发的低功耗相关的内容,关于手表低功耗关闭 cpu 这块,我有两个问题想问下(Jack)

inrush 电流与休眠档位策略:电容性负载重新上电必然有 inrush(RF 模块、屏幕、电源轨去耦电容、LDO 输出电容、sensor 电源域)。低功耗不只看瞬间电流峰值,要测"一次关断再唤醒"是否真小于"一直等待"的能量,据此定策略:几十毫秒以内通常不进深睡(最多 WFI/Sleep);几百毫秒级看唤醒时间与实时性,可能进 Stop/light sleep;秒级以上才考虑 deep sleep、部分外设断电。

我看了咱发的低功耗相关的内容,关于手表低功耗关闭 cpu 这块,我有两个问题想问下(Jack)

硬件配合:Load-switcher 负载开关(图)。

Load-switcher(Jack)

FCLK 独立供电支撑唤醒(与 1.2 互链)— STM32中的FCLK和HCLK时钟的区别(Jack);事件驱动按键避免空扫、支撑低功耗(与 10.5 互链)— 问:按键模块是怎么进行的 答:(Jack)。


十、BSP 分层与驱动架构

10.1 一条链路读懂各层:hal → driver → handler → adapter → APP

hal 是硬件抽象层;driver 把 hal 组合起来完成基本外设控制;handler 控制 driver 满足运行逻辑;adapter 把 handler 挂到 wrapper 抽象接口上;APP 调用 platform 的 wrapper 完成业务。

hal是硬件抽象层,driver将hal组合起来完成基本的外设控制(Jack)

材料包比喻:Driver 是材料包(木头、手柄,如 hal 库,实际没做事,CPU 通过调库配置寄存器);Core 把材料拼成锤子(含 main.c,初始化后获得装好外设的"外设库",如 IIC 句柄);BSP 调用外设库里已初始化的外设通信;BSP 与操作系统层、APP 层构成生产者消费者模型——APP 不能直接调 BSP,一定要经过操作系统层

Driver:理解为材料包,木头,手柄,比如hal库(Jack)

10.2 Core 与 BSP 的边界

BSP 是面向设备的驱动,Core 是芯片底层驱动,BSP 是 Core 的上层结构:IIC 接口的 MPU6050,Core 是 IIC 初始化,BSP 是 MPU6050 驱动。

同学提问: Core和BSP(Jack)

Driver 层与 Core 层都提"外设初始化"的区别:driver 层没有做初始化操作——driver 基本都是库,不会有任何代码执行;core 调用 driver 实现最终操作句柄,提供给 BSP 调用。

对Driver层和Core层还是不太理解,为什么都提到了对外设的初始化(Jack)

ADC+DMA 采集代码不属于 BSP:BSP 描述 MCU 外部的东西与 MCU 的通信逻辑,ADC 是片内外设(AHB/APB 总线上、CPU 以外的部分)。

老师,我写了个ADC+DMA的代码,实现了ADC数据采集以后(Jack)

10.3 BSP 的纯粹性与可移植性

最优秀的 BSP 驱动文件中只放 MCU 和板上外设的交互逻辑

什么类型的函数适合放到BSP驱(Jack)

BSP 应是纯粹描述 MCU 与片上器件通讯的代码:IIC、GPIO 初始化都由 MCU(Core)提供,BSP 只调用接口完成通信。这样同一份 BSP 可跑在 STM32、GD32 甚至 Linux 上,实现高移植性——跳槽时逻辑才能跟着你走,尽可能屏蔽硬件差异。

对于bsp层,它的作用是什么?(Jack,👍5)

10.4 Handler 与线程模型

BSP 层设计逻辑总结(Driver + Handler 两部分):Driver 面向底层硬件,简单通用便于硬件更换;Handler 向上提供统一北向接口、内部携带独立线程管理 Driver 与硬件资源。需要 Handler 的四个理由:(1) 线程是 CPU 时间最小分配单位,硬件操作时间占用可控;(2) 避免 App 与 Driver 直接耦合,换硬件只改 Driver;(3) Driver 操作(I2C/SPI)可能长时间阻塞,Handler 隔离阻塞保护 App 实时性;(4) 统一资源管理与协调。

BSP层的设计逻辑与优势总结(Jack,👍1,精华)

一个 handler 构造一个线程:handler inst 会调用外部传入的线程创建接口;通用算法能管理的对象数量有上限(不可能一个 handler 管上百万个 LED),超了就得再开线程。

老师,调用handler inst的时候会调用外部传入的线程创建接口(Jack)

inst 函数的地位:inst 不只是把接口挂到自身——每层拿到上层传来的"装满接口的包裹"后先解包自挂载(解耦上层),init 函数再执行实现本层业务的前提(handler 建队列、driver 读 ID 自检),init 之后才能放心实现业务逻辑。

inst函数在整个模块中的地位(Jack)

Handler 与 Driver 传递的延时函数为何不同(图答)。

为什么Handler和Driver传递的延时函数不一样(Jack)

兼容多芯片后 handler 的命名:只有 aht21 时按 aht21 命名没问题;一旦 handler 层加入 dht11 兼容逻辑,就应命名成"获取温湿度的 handler"或"兼容 aht21/dht11 的 handler"——否则 handler 与 driver 是"选择性耦合"。(星主确认:对的)

问: 老师,我们现在的这里的教(Jack)

操作系统层对 BSP 的 I/O 控制实现(图答)。

想问下操作系统层对bsp层的I:O控制是怎么实现的?看了视频(爱健身的机器人)

10.5 私有数据保护

行业常识:驱动中私有变量的访问要有防脏数据的保护方法(图解)。

行业常识:驱动中私有变量的访问方法(防止脏数据系统紊乱(Jack)

APP 读设备 ID 的正确姿势:不能让 APP 直接读——若 APP 比 BSP 先启动,可能读到脏数据,该 ID 若间接引起 IO 变化会非常危险。应提供专用函数,获取前先检查 BSP 设备初始化成功,再读给 APP。

BSP驱动中如何处理私有数据?比如设备的ID,APP想知道设备的ID:(Jack)

10.6 硬件管理 vs 业务逻辑的边界

BSP 只管硬件,语义判定归 APP:按键按下检测(中断触发)是硬件管理(HAL_Driver 层);把"按下时间、按下/松开"告知需要者(Handler 层解决信号传输、栈隔离、调用链确定性)之后,BSP 任务就完成了;APP 收到事件后自己判断——打开继电器是纯业务逻辑。长按/短按/三连按的语义判定不应写进 BSP:BSP 会臃肿且永远穷不尽所有可能,不同用户对长按的理解也不同。分工上写 APP 和写 BSP Driver 往往不是同一人,BSP 应提供最原始的数据与最高效稳定的非阻塞接口。

问:bsp层的目的之一是完全将硬件管理和业务逻辑分开吗?如果是的话(Jack,👍4)

双击/多击的超时判定与状态机优化:做双击连按需要超时检测——短按 tick 算出后不能立刻判定,要等超时。超时是否需要应由上层业务决定:只有短按有效的场景(按一下开关灯)可不判超时、快速响应;要双击调亮度的场景才加入超时判断(单击也照常关灯,不影响体验)。核心是明确状态、缩小状态控制区

如果在按键中,我需要检测双击,也就是某段时间内再次按下,判定双击、多击等等(Jack)

事件驱动:按键检测线程大部分时间阻塞(不占 CPU,无轮询);按键按下发出队列消息,线程退出阻塞开始占 CPU。

什么是事件驱动? 事件驱动简(Jack)

按键模块实现:基于中断计数队列传输的事件驱动;轮询扫描会造成大量空扫,设备无法低功耗。

问:按键模块是怎么进行的 答:(Jack)

LED 为何单独建队列:做模块化时驱动之间不传递信息——写 LED 驱动的人并不知道 key 的存在,各干各的事。

老师我这里不是很理解为什么要为led也创建一个队列,按道理两个线程(Jack)

10.7 分层的代价与回报

分层开销的量化:函数指针解耦确实增加寻址次数,但 72MHz 下一条指令约 10~100ns,一次指针跳转 2 条指令、顶多 4 层指针约 200ns,影响极小;而且可用 sct 分散加载把常用 IO 固定链接地址、直接立即数访问,比函数嵌套还快,指针消耗可减到消失。真正的代价是对开发人员水平要求高。

问: 我们把bsp层抽出来,(Jack,👍5)

LED 驱动为何用桥接模式:关键不在文件数量,而在系统层面的方法——通过文件管理链接最小单元,实现变量高内聚低耦合,才能在 hex 层面直接调用解析、支撑异步 IO 构造、系统集成、飞秒启动、差分升级。花式点灯是给人看的,治标不治本;这套架构的目的是数据归类、差分升级、加快启动,在 hex 层面彻底优化系统。桥接/工厂只是常用手段,架构极度灵活,要辩证使用与创造——应掌握的是背后的设计能力,确定性架构不要死记。

老师,写这个LED驱动为啥要用设计模式中的桥接模式,优点在哪(Jack,👍3)

Core 以下再做抽象意义不大:CubeMX 生成的代码解耦性不强,但这部分原厂会提供、复用度太小——换芯片时 Core 及以下全换,是原厂 SDK 的事。

老师,做解耦时,core 层和 driver层感觉cubemx生成的代码解耦性不强(Jack)

平台化与去平台化的本质:驱动与 app 解耦完成即"去平台化";项目实际运行要把抽象接口具体化,即把各模块"平台化"——平台化的本质就是将模块内部的抽象接口具体化

关于“平台化”和“去平台化”的(Lili_iliLX 提问,Jack 确认)

adapter 必然存在:无论单元接口怎么设计,系统集成工程师都会设计 adapter 去集成你和其他模块的关系,明确接口和测试范围。

老师,看了你们aht21这个初级框架的课程。我讲一下我现在驱动这里怎么做(Jack)

架构无法一通百通:物联网传感器非常碎片化,效率和兼容性互相转换且代价大(资源、性能);只能研究嵌入式设计模式与架构设计能力,具体架构灵活变通。

之前一家企业找我做过帮他们集团设计物联网架构的项目,我后来一通操作下来(Jack)

面向对象的封装思考(长文存根):片外外设(IIC/SPI 访问)可抽象 BSP Driver 满足跨平台适配;片内外设是否也要封装、SPI/IIC 在 OS 下是否需要独立任务管理之问。

Q1:采用面向对象的思想去对项目去开发。核心外部通过IIC、SPI等通信线进行访问(山海无名)

语言选型:因为项目选语言,不是为语言选项目——音视频/云端可能用 go,UI 可能上 JS 解释器,极小资源高效率的 bootloader 可能用汇编;提前学 C++ 是积累。

老师,cpp什么时候用在单片机(Jack)

未答之问:固定参数写死 BSP 还是引出接口 — 如果在驱动初始化时要对设备做一些参数设置,这些设置以后是不会改(Jack);双 buffer 与环形缓冲区选型 — 老师,为什么OTA的课和mpu6050驱动的课都使用buff1和buff2而不使用环(daneel.wan);按键 task 为何放 BSP 层 — 老师,按键这部分课程中,为什么要把task放入bsp层呢?我理解他应该是应用层(daneel.wan);软硬件 SPI/IIC 统一对象封装 — 星主,请教一个问题,我想把软件 spi 和硬件 spi 用一个对象封装起来(这是一个好听的id)。

与 RT-Thread 的对应:RT-Thread 设备框架是"片上外设驱动框架",对应本架构 BSP 层的 Handler 层

问: 我之前用过 RT Thr(Jack)

10.8 HAL 库与 SDK

HAL 库与标准库的区别(长文,精华):
- 句柄:标准库初始化用局部结构体 + Init 函数,初始化完结构体即失效;HAL 的 UART_HandleTypeDef全局句柄——除配置参数外还封装数据指针、收发计数、DMA 句柄、Lock、State、ErrorCode,配置一次全项目可传。
- MSP 函数:HAL 把"与 MCU 无关的理论参数"(波特率、停止位)和"MCU 相关的具体方案"(PA9/PA10、时钟使能、GPIO 配置)分开——HAL_USART_Init() → HAL_USART_MspInit(),后者由 CubeMX 生成。

HAL库与标准库对比(Jack)

学 HAL 还是标准库:两种都涉及,做 OTA bootloader 需要标准库;遇到问题都要进库查配置。企业中两者都有占比,标准库胜在年代久、大家熟;ST 已停止维护标准库;HAL 缩短 0 到 1 周期、配置环境规避寄存器配置错误,市场只会越来越广。

老师,课程都是教HAL库嘛?但是开发中不是标准库用的多一点嘛?一些老一点的项目(Jack)

HAL 使用心态:HAL 库有些操作(尤其中断回调)可能与预期不一致——用别人的库,一定要能通过各种方法走到最底层去调试

hal库的有些操作,尤其是中断回调,有时候和我们预期是不一致(Jack)

CMSIS 调用链(图答)。

是谁在调用cmsis-core(Jack)

CubeMX 打不开生成文件:一般是芯片包没装,装对应系列的 pack。

老师,打开cubemx生成的文件,结果是这样,是哪里没有安装(Jack)

从手册推导驱动初始化流程:面对新芯片新外设,不知道"先配什么、后配什么、最后怎么使能"——用 HAL 本质是在用 SDK,看 .h 文件描述和官方文档(厂家验证过的工作流程,甚至包含芯片缺陷的软件修复);完全从寄存器重走 SDK 的路,项目资源不会允许,芯片厂有义务维护好 SDK。

老师,在编写某个外设驱动时,我知道可以通过数据手册查到单个寄存器或某个功能点(Jack)

典型外设需要去初始化的案例(图答)。

一个典型的外设需要去初始化的案(Jack)

10.9 内存管理

不要在运行期频繁 malloc:充电桩产品(CAN/485 模块多)要不要动态内存?不建议 C 标准库 malloc——要么只在启动阶段有限 malloc 且整个生命周期不 free;运行期频繁 malloc/free 必产生碎片,且 malloc 时间不确定、易偶现问题。需要优雅就自己实现内存池:一个数组构成的池,两个队列维护——队列 A 存空闲内存单元地址,队列 B 存使用中地址;malloc 从 A 取、free 还回 A,时间确定且无碎片。

老师,请问下stm32单片机跑时间片轮询架构,什么时候需要用到动态内存管理(Jack)

适用单片机的内存管理算法之问(未答)。

老师,有没有适用单片机这种资源有限的内存管理算法推荐。不想用 rtos 自带(这是一个好听的id)

MPU 保护核心区域:裸机/RTOS 都可直接访问硬件,但高级研发会用 MPU 保护核心区域防野指针——例如保护数组周围地址,越界访问立即 HardFault,对离线(非在线调试)排错很有益。

问:有点疑问,我们用 MCU,裸机或者用RTOS,不是都可以至今访问硬件么(Jack)


十一、调试外设的典型案例

11.1 LCD / 显示

TFTLCD 点不亮的收敛式调试流程:点亮屏幕难在难收敛问题——① 备齐 datasheet、初始化代码、原理图;② 先确认电源,测所有 IO 电压并记录;③ 逻辑分析仪挂通信线(IIC/SPI)观测;④ 先读 LCD ID——ID 是芯片唯一随生产就有的数字,能读出就证明硬件和软件通信方式没问题;⑤ 发初始化代码,不行就用画点/画线函数试画,再用手电筒照屏幕——有画面就是背光没开;⑥ 还没画面就回逻辑分析仪逐帧分析,找画点坐标对应的时序波形;有条件发原厂分析,或买一块点亮过此屏的开发板对照正确波形修正自己的。

移植TFTLCD的时候点不亮(Jack,👍4)

屏幕的 HSYNC/VBP/HFP 消隐区:任何屏幕(手机/平板/电视)画面都无法占满整个 LCD——扫描换行/换场需要准备时间,上下左右永远有一条物理上消不掉的窄黑边;HSYNC/HBP/HFP、VSYNC/VBP/VFP 参数就是黑边宽度,算时钟信号时必须加上。

这个说法有点不理解,意思是在HSYNC:HBP:HFP、VSYNC:VBP:VFP(Jack)

LVGL:旋转屏幕配置(图)— LVGl旋转屏幕 LVGL8(Jack);厂商移植的 LVGL 缺 lv_anim_start/stop API——用 lv_anim_delete 删除 animimg 类中创建的 anim,仿写一个删除函数,或自建 anim 不断切换 img 的 src — 老师,请问一下 厂商移植的lvgl里面没有lv_anim_start和lv_anim(Jack);趋势:手表 MCU 普遍带 GPU,LVGL 的 GPU 并行优化(先 SIMD 后 GPU)是重点方向 — 现在的市面上手表中的MCU都是带GPU,以后LVGL大行其道(Jack,👍3)。

11.2 SWD / JLink

SWD 复用脚的波形与 TAP/DAP:JTAG 四线中 TDI 由 Jlink 发出、TDO 由 MCU 回复、TRST 复位 DAP。SWD 与 GPIO 功能冲突时:不初始化串口即可。能否读复用脚电平判断烧录模式?——本质是两个外设单元,对频前不能配置也不能读写 GPIO 寄存器;没有 TRST 时 TMS/SWDIO 长时间低电平也能复位 DAP。

问题1: gpio如果是复用成swd用做jlink烧录,它在建立通信的时候(Jack)

卡死且 JLink 检测不到芯片:DAP 所在时钟可能已停摆,JTAG 状态机无法与 Jlink 对频(RCC 时钟可能已故障)。对策:HardFault 后用 cmbacktrace 打印栈做离线诊断(需外挂 Flash 存储);或外接 Trace 接口吐出 CPU 实际运行状态做非侵入调试。

请问单片机卡死,同时jlink链接无法检测到芯片,复位后可以检测得到(Jack)

JLink 下载失败:先试调低 JLink 频率(如 5kHz)。

遇到单片机Jlink下载失败,如下图片怎么办(Jack)

Keil 下载后不自动运行:勾选对应选项即可(图)。

Keil程序下载后,不会自动运(Jack)

11.3 栈回溯与底层工具

CmBacktrace 错误处理函数为何能传参:用了寄存器传参——汇编里把 LR 和 SP 存入寄存器 1、2,调用该函数时自动赋值给两个入参。

老师,Cmbacktrace中这个错误处理这个函数为什么能传函数参数(Jack)

提高 cache 命中率(图答)。

老师,有如何提高cache的命中率的相关讲解(Jack)

Bringup 软件是什么:为让一块全新硬件"活过来"而临时写的初始化与验证程序——打板回来时什么都不知道(电源起没起、时钟抖不抖、DDR 能否初始化、外设有没有焊好、Boot 能不能跳),上不了系统只能靠 Bringup 一关一关地通。

:你必须要知道的关键词: Br(Jack,👍2)

11.4 开发环境

VS Code + Keil5 + CubeMX 半联动:Keil 负责工程配置、编译和下载,VS Code 负责写代码(PDF 教程附件)。

从 0 到 1 搭建 VS C(刘子奇,👍6)

"熟悉 Arm 主板 SDK 编写、在各种 Arm 平台部署程序"代表什么能力(图问)— 熟悉Arm主板SDK的编写,在各种Arm平台部署各种的程序软件(Jack)。


十二、硬件与板级周边

三极管 vs MOS 管:控制上,三极管是电流控制,MOS 是电压控制——电压控制阻抗高、消耗低,IO 只有 0.1mA 驱动能力时用 MOS 压力小得多、控制系统更稳;MOS 信号建立快、擅长高速 IO 控制(如电机)。成本上三极管更便宜。集成密度 MOS 更小(芯片内部多用 MOS 实现)。功耗 MOS 发热小;三极管发热大。

三极管和MOS管的区别? 简(Jack)

0 欧电阻代替跨孔:多层 PCB 走线交叉时需要过孔到另一层再回来,这个过孔可以替换成 0 欧电阻充当飞线。

老师,0欧电阻应用中:其中有一个作用是“代替跨孔”,这个跨孔指的是什么:(Jack)

A/B/C 样机制与可测性设计:一板成功没人能保证,一般分 A 样、B 样、C 样(SOP)三阶段,B 样硬件冻结、C 样基本没问题。A 样贴片板在设计时安装很多 0 欧电阻(开关电阻),拆 0 欧断连某块区域做对比测试;Demo 阶段留测试点,到 B 样才去掉。

5.2 在公司里面,一般设计好的电路板交给工厂去打板时(Jack)、2、现在大多都是直接贴片完成了。那调试过程局部测试是否就更看板子的设计阶段解决(Jack)

PCB 布局技巧(图)。

PCB布局技巧:硬件电路设计(刘子奇,👍5)

硬件工程师手册导读:硬件设计是电磁场理论、材料科学、热力学、生产工艺学与可靠性工程的综合——EDA 选型(AD / Cadence / PADS-Xpedition / KiCad 的定位)、器件降额设计(电容耐压与电阻功率留 50% 余量、考虑温漂与停产风险)等全流程拆解。

:硬件电路设计 ::硬件 ::(刘子奇,👍4)


来源笔记

合集吸收(69 篇,已并入上文各章)

新增散帖(102 篇,本次并入)

跳过(5 篇,原帖已标 review: 建议隔离)

  • 有没有AHT21的完整工程啊,(资源索取帖)
  • 我想问一下关于嵌入式低功耗相关(提问帖)
  • 开关电源软件工程师 _岗位(招聘帖)
  • 星主,可以分享一下驱动视频里的(资源索取帖)
  • 星主,能否在星球内部公布一下m(资源索取帖)