资讯详情

Momentum Firmware 外设总线管理:深入解析 FuriHalBus API 的启用、复位与关闭机制

📅 2026/9/16 12:19:55 | 华诺云谱 👁 阅读
Momentum Firmware 外设总线管理:深入解析 FuriHalBus API 的启用、复位与关闭机制
Momentum Firmware 外设总线管理深入解析 FuriHalBus API 的启用、复位与关闭机制【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware导读本文以 documentation/FuriHalBus.md 为核心系统讲解 Momentum Firmware基于 STM32WB55 的 Flipper 固件中FuriHalBus外设总线管理 API 的设计与使用。文中覆盖外设默认状态、三类外设的启用策略、DMA 通道分配并结合 furi_hal_bus.c 等源码揭示底层 RCC 寄存器操作与启动时序。读完本文你将掌握furi_hal_bus_enable()/furi_hal_bus_disable()/furi_hal_bus_reset()的正确调用姿势、前置条件与常见陷阱能够在开发驱动或应用时安全、规范地管理片上外设的时钟与复位。一、背景为什么外设默认处于复位且无时钟状态在 STM32WB55 平台上系统启动时绝大多数外设默认处于复位状态且时钟未开启。这一设计有两个直接目的降低功耗未上电的外设不消耗动态功耗这对电池供电的便携设备至关重要保证确定性所有外设从同一确定状态出发避免上电残留状态带来的不可预期行为。少数关键外设由系统在启动阶段直接启用例如 DMA、GPIO、FLASH其余外设必须由用户代码显式启用后才能访问。NOTE本文语境下的系统system泛指操作系统代码、硬件驱动以及内置应用即任何不属于用户 FAP 应用代码的部分。二、核心 API启用、复位与关闭FuriHalBus 的对外接口全部声明在 furi_hal_bus.h实现位于 furi_hal_bus.c。四个核心函数及其强制前置条件如下函数作用前置条件违反即崩溃furi_hal_bus_enable(bus)开启外设时钟并解除复位外设必须处于禁用状态不可重复启用furi_hal_bus_disable(bus)关闭外设时钟并施加复位外设必须处于启用状态不可重复禁用furi_hal_bus_reset(bus)先施加复位再解除复位将寄存器恢复初始状态外设必须处于启用状态furi_hal_bus_is_enabled(bus)查询外设是否处于启用状态无特殊要求返回bool三个写操作的关键语义是状态机约束enable要求外设当前是 disableddisable与reset要求外设当前是 enabled。这意味着任何一个外设都不能在未先禁用的情况下被重复启用反之亦然。违反条件时代码会通过furi_check()触发崩溃fault以明确标示使用错误而不是让系统带病运行。2.1 底层实现RCC 寄存器与 LL 库宏从源码 furi_hal_bus.c 可以看到所谓启用/禁用/复位本质上是操作 RCCReset and Clock Control外设的时钟使能寄存器ENR与复位寄存器RSTR#define FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, value, ...) \ (FURI_HAL_BUS_IS_ALL_SET(RCC-bus##ENR##__VA_ARGS__, (value))) #define FURI_HAL_BUS_IS_RESET_ASSERTED(bus, value, ...) \ (FURI_HAL_BUS_IS_ALL_SET(RCC-bus##RSTR##__VA_ARGS__, (value))) #define FURI_HAL_BUS_PERIPH_ENABLE(bus, value, grp) \ FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp); \ FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) #define FURI_HAL_BUS_PERIPH_DISABLE(bus, value, grp) \ FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp)可以看到启用 先打开时钟*ENR置位再解除复位*RSTR清零顺序不能颠倒禁用 先施加复位*RSTR置位再关闭时钟*ENR清零顺序同样固定复位 先施加复位再解除复位时钟保持开启用于将外设所有寄存器恢复初始状态而不必关闭外设。所有操作均包裹在FURI_CRITICAL_ENTER()/FURI_CRITICAL_EXIT()临界区内避免与中断上下文中的并发操作冲突见 furi_hal_bus.c。2.2 总线分组与 FuriHalBus 枚举每个外设归属于 STM32WB55 的某条总线组AHB1/AHB2/AHB3/APB1/APB2/APB3。FuriHalBus枚举按总线组组织见 furi_hal_bus.h例如typedef enum { FuriHalBusAHB1_GRP1, FuriHalBusDMA1, FuriHalBusDMA2, FuriHalBusDMAMUX1, FuriHalBusCRC, FuriHalBusTSC, FuriHalBusAHB2_GRP1, FuriHalBusGPIOA, ..., FuriHalBusAES1, FuriHalBusAHB3_GRP1, FuriHalBusQUADSPI, FuriHalBusPKA, FuriHalBusAES2, FuriHalBusRNG, FuriHalBusHSEM, FuriHalBusIPCC, FuriHalBusFLASH, FuriHalBusAPB1_GRP1, FuriHalBusTIM2, FuriHalBusLCD, FuriHalBusSPI2, FuriHalBusI2C1, FuriHalBusI2C3, FuriHalBusCRS, FuriHalBusUSB, FuriHalBusLPTIM1, FuriHalBusAPB1_GRP2, FuriHalBusLPUART1, FuriHalBusLPTIM2, FuriHalBusAPB2_GRP1, FuriHalBusTIM1, FuriHalBusSPI1, FuriHalBusUSART1, FuriHalBusTIM16, FuriHalBusTIM17, FuriHalBusSAI1, FuriHalBusAPB3_GRP1, FuriHalBusRF, FuriHalBusMAX, } FuriHalBus;实现中维护了一张静态映射表furi_hal_bus[]将枚举值翻译为对应的 LL 外设位掩码如LL_APB1_GRP1_PERIPH_TIM2。值得注意的细节组占位符如FuriHalBusAHB1_GRP1映射为FURI_HAL_BUS_IGNORE (0x0)调用对应 API 时直接返回不做任何操作ADC 的总线归属随芯片型号变化在支持ADC_SUPPORT_5_MSPS的目标上挂到 AHB2在ADC_SUPPORT_2_5_MSPS目标上挂到 APB2源码通过条件编译处理这一差异FLASH 由硬件默认使能不参与时钟开关APB3 组是共享外设的特殊情况对 core1 而言其时钟常开furi_hal_bus_is_enabled()只能报告复位状态而非时钟状态详见 furi_hal_bus.h 注释。三、启动时序init_early 与 deinit_early外设总线管理发生在固件启动的最早期阶段调用链见 furi_hal.cvoid furi_hal_init_early(void) { furi_hal_cortex_init_early(); furi_hal_clock_init_early(); furi_hal_bus_init_early(); // 关闭 APB1/APB2 全部外设时钟与复位 furi_hal_dma_init_early(); // 立即启用 DMA1/DMA2/DMAMUX1 furi_hal_resources_init_early(); ... }furi_hal_bus_init_early()见 furi_hal_bus.c在临界区内对 APB1 两组、APB2 一组执行PERIPH_DISABLE并对 APB3RF施加复位从而把绝大多数外设统一收拢到复位 无时钟的确定状态。对应地furi_hal_bus_deinit_early()在关机路径上逆向恢复这些外设的时钟与复位状态。紧接着furi_hal_dma_init_early()见 furi_hal_dma.c立即启用FuriHalBusDMA1、FuriHalBusDMA2和FuriHalBusDMAMUX1因为 DMA 是系统早期运行如 SPI 配置、内存搬运就依赖的基础设施。四、外设的三类管理策略内置外设按管理方式分为三类用户代码必须严格遵循对应策略。4.1 始终在线外设Always-on系统启用禁止禁用以下外设由系统在启动阶段启用且永不关闭。用户代码绝不能尝试禁用它们如果存在对应 API必须通过 API 访问而不是绕过 API 直接操作寄存器。表 1 — 系统启用且始终在线的外设外设启用位置DMA1furi_hal_dma.cDMA2--DMAMUX--GPIOAfuri_hal_resources.cGPIOB--GPIOC--GPIOD--GPIOE--GPIOH--PKAfuri_hal_bt.cAES2--HSEM--IPCC--FLASH由硬件启用源码佐证furi_hal_dma.c 中furi_hal_dma_init_early()依次启用 DMA1、DMA2、DMAMUX1furi_hal_resources.c 中furi_hal_resources_init()启用 GPIOA 至 GPIOH 共 7 个 GPIO 端口furi_hal_bt.c 中蓝牙初始化启用 HSEM、IPCC、AES2、PKA、CRCCRC 实际按需处理见下。4.2 按需系统外设On-demand系统按需启停这类外设由系统驱动按需启用/禁用。用户代码应优先使用对应 API避免直接操作。若因特殊需求必须直接访问则必须自行负责启用并在不再需要时关闭。表 2 — 系统按需启停的外设及其 API 头文件外设API 头文件RNGfuri_hal_random.hSPI1furi_hal_spi.hSPI2--I2C1furi_hal_i2c.hI2C3--USART1furi_hal_serial.hLPUART1--USBfuri_hal_usb.h源码佐证furi_hal_random.c 的furi_hal_random_init()先furi_hal_bus_enable(FuriHalBusRNG)再设置 RNG 时钟源furi_hal_i2c_config.c 在 I2C 总线激活时enable(FuriHalBusI2C1)、停用时disable(FuriHalBusI2C1)I2C3 同理furi_hal_serial.c 分别对 USART1 与 LPUART1 执行enable并在串口关闭时先is_enabled判断再disableL698-L709这正是配对使用 状态查询的规范范例。4.3 用户按需共享外设On-demand shared用户代码负责启停这类外设默认不启用用户代码每次访问前必须显式启用。其中部分外设可能同时被系统某些功能占用只有当对应功能实际使用时系统才会接管该外设。表 3 — 由用户启用/禁用的共享外设外设系统占用用途CRCTSCADCQUADSPITIM1是subghz、lfrfid、nfc、infrared 等TIM2是subghz、infrared 等TIM16是speakerTIM17是cc1101_extLPTIM1是tickless idle timer低功耗空闲定时器LPTIM2是pwmSAI1LCD源码佐证furi_hal_speaker.c 在扬声器启动时启用FuriHalBusTIM16停止时禁用furi_hal_pwm.c 根据 PWM 通道选择启用FuriHalBusTIM1或FuriHalBusLPTIM2并用furi_hal_bus_is_enabled()查询当前状态furi_hal_idle_timer.h 中 tickless idle 定时器依赖FuriHalBusLPTIM1空闲时启用、退出时复位furi_hal_rfid.c 中 RFID 读取/模拟/场强计等多个场景分别启用与禁用对应的定时器总线furi_hal_infrared.c 红外接收启用/禁用INFRARED_RX_TIMER_BUS。特别提醒FuriHalBusLPTIM1由系统的 tickless idle 机制占用用户代码若直接操作 LPTIM1 会干扰系统低功耗调度务必通过系统 API 访问。五、DMA多通道外设的特殊管理DMA1/DMA2 是特殊情况每个 DMA 包含多个独立通道系统可能已占用其中部分通道。用户代码在选用 DMA 通道前应先确认目标通道是否已被系统占用。表 4 — DMA 通道及系统占用情况DMA通道系统占用用途DMA11是digital signal--2是----3--4是pulse reader--5--6是USART_Rx--7是LPUART_RxDMA21是infrared、lfrfid、subghz--2是----3是cc1101_ext--4是cc1101_ext--5是cc1101_ext--6是SPI--7是SPI从表中可以看到DMA2 的全部 7 个通道均被系统占用DMA1 的通道 3、5 未被系统使用可供用户代码选用。DMA 总线本身属于始终在线类别无需用户手动启停但用户新驱动若引入对 DMA 通道的新占用应更新此表以保持文档与实现的同步。六、实战在用户代码中正确管理外设6.1 基本用法配对启用与禁用最基础的模式是启用 → 使用 → 禁用适用于用户独占的外设如表 3 中未被系统占用的 CRC、TSC、QUADSPI、SAI1、LCD 等#include furi_hal_bus.h // 使用前启用 furi_hal_bus_enable(FuriHalBusCRC); // ... 访问 CRC 硬件寄存器 ... // 使用完毕必须禁用否则外设保持耗电 furi_hal_bus_disable(FuriHalBusCRC);关键约束furi_hal_bus_enable()要求外设当前必须处于禁用状态因此不要在未先disable的情况下重复enable否则会因furi_check()失败而崩溃。若无法确定外设当前状态先用furi_hal_bus_is_enabled()查询参考 furi_hal_nfc_timer.c 的写法if(furi_hal_bus_is_enabled(config-bus)) { furi_hal_bus_disable(config-bus); }6.2 复位场景无需关闭即可恢复初始状态当外设处于启用状态、需要把所有寄存器恢复到初始值例如驱动状态机异常后重新初始化时使用furi_hal_bus_reset()它不改变时钟状态furi_hal_bus_reset(FuriHalBusTIM2); // 仅复位寄存器时钟保持开启6.3 完整示例NFC 定时器的启停模式furi_hal_nfc_timer.c 展示了启用-使用-检查-禁用的完整生命周期管理范式static void furi_hal_nfc_timer_init(FuriHalNfcTimer timer) { const FuriHalNfcTimerConfig* config furi_hal_nfc_timers[timer]; furi_hal_bus_enable(config-bus); // 1. 启用定时器总线 LL_TIM_SetOnePulseMode(config-timer, LL_TIM_ONEPULSEMODE_SINGLE); // ... 其余 LL 配置 ... NVIC_EnableIRQ(config-irq_type); } static void furi_hal_nfc_timer_deinit(FuriHalNfcTimer timer) { const FuriHalNfcTimerConfig* config furi_hal_nfc_timers[timer]; // ... 清理中断与回调 ... if(furi_hal_bus_is_enabled(config-bus)) { // 2. 先查询再禁用避免重复禁用崩溃 furi_hal_bus_disable(config-bus); } }七、常见陷阱与排查建议重复启用/禁用导致崩溃enable/disable/reset均有严格前置条件违反时触发furi_check()。不确定状态时先用furi_hal_bus_is_enabled()判断或在修改系统驱动时参考既有驱动的查询后再操作模式。直接操作系统占用的外设TIM1、TIM2、TIM16、TIM17、LPTIM1、LPTIM2 均被系统功能占用见表 3用户代码应通过对应系统 API 使用而非绕过 API 直接enable否则可能与 subghz、speaker、pwm、tickless idle 等机制冲突。DMA 通道冲突DMA2 全部通道已被系统占用DMA1 通道 3/5 空闲见表 4。新增 DMA 使用时优先选择空闲通道并在 documentation/FuriHalBus.md 的表格中登记新占用。临界区与中断上下文furi_hal_bus_*内部使用FURI_CRITICAL_ENTER/EXIT保护寄存器访问不要在已处于临界区或不可屏蔽中断的上下文中嵌套调用避免锁嵌套问题。调试辅助furi_hal_bus_is_enabled()可用于打印外设状态辅助定位问题对于 APB3 组RF外设其时钟始终开启查询结果仅反映复位状态判断时需留意这一语义差异见 furi_hal_bus.h。八、扩展阅读总线 API 头文件与实现furi_hal_bus.h、furi_hal_bus.c启动/关机调用链furi_hal.c典型调用范例furi_hal_dma.c、furi_hal_random.c、furi_hal_nfc_timer.c、furi_hal_speaker.c、furi_hal_serial.c配套文档文档原文 documentation/FuriHalBus.md硬件相关说明可参考 documentation/HardwareTargets.md 与 documentation/FuriHalDebugging.md【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。