RIOT OS 中的 Silicon Labs EFM32/EFR32/EZR32 移植层解析:时钟、EMU/CMU 与低功耗外设配置指南
2026/9/20 20:50:54 网站建设 项目流程
  • 物联网
  • 嵌入式
  • 操作系统
  • 实时系统

【免费下载链接】RIOT

RIOT - The friendly OS for IoT

项目地址:https://gitcode.com/GitHub_Trending/riot/RIOT
点击查看免费下载

本文以 cpu/efm32/doc.md 为骨架,深入讲解 RIOT OS 对 Silicon Labs EFM32/EFR32/EZR32 系列 Cortex-M MCU 的移植实现:包括所支持的外设清单、内部 RC 振荡器与外部晶振(HFXO/LFXO)的时钟切换方式、EMU/CMU 初始化参数覆写方法,以及通过EFM32_LEUART_ENABLED等变量裁剪低功耗外设以节省内存的具体做法。读完本文,你将掌握如何在板级 Makefile 与periph_conf.h中为 EFM32 系板卡配置时钟源和能量管理参数,并能从源码层面理解cpu_init()的完整启动链路。

模块定位:RIOT OS 中的 EFM32 CPU 移植层

cpu/efm32目录是整个 RIOT OS 中对 Silicon Labs EFM32/EFR32/EZR32 MCU 系列的唯一实现位置。根据 doc.md 的定义,该模块包含所有这些 MCU 的代码与定义,并且底层外设驱动直接使用 Silicon Labs 的 Gecko SDK(vendor 库)。这一点在 Makefile.dep 中得到了印证:模块编译时会自动通过USEPKG += gecko_sdk引入 Gecko SDK 包。

得益于 Gecko SDK 提供统一的em_*系列驱动 API(如em_chip.hem_cmu.hem_emu.hem_dbg.h),RIOT 的移植层得以用一套代码覆盖多个硅片系列,仅在系列差异处通过_SILICON_LABS_32B_SERIES宏做条件编译(见 cpu.c)。

受支持的 MCU 家族

原文档列出了以下受支持的家族,每个家族在仓库中对应一个独立目录,其中包含中断向量表vectors.c、家族信息数据库efm32-info.mk与 Kconfig 配置:

家族说明仓库目录
EFM32GGGiant Geckofamilies/efm32gg
EFM32HGHappy Geckofamilies/efm32hg
EFM32LGLeopard Geckofamilies/efm32lg
EFM32PG1BPearl Gecko 1families/efm32pg1b
EFM32PG12BPearl Gecko 2families/efm32pg12b
EFM32ZGZero Geckofamilies/efm32zg
EFR32MG1BMighty Gecko 1families/efr32mg1b
EFR32MG1PMighty Gecko 1families/efr32mg1p
EFR32MG12PMighty Gecko 2families/efr32mg12p
EZR32WGWonder Gecko(带 Sub-GHz 射频)families/ezr32wg

从仓库实际内容看,支持范围比文档列举的更广:还包含 families/efm32gg11b、families/efm32gg12b、families/efm32tg11b 与 families/efr32zg23(EFR32xG23,Series 2)。家族目录的加入由 Makefile 依据USEMODULE中的cpu_<family>模块名动态决定,例如选择cpu_efm32gg即编译families/efm32gg

家族信息数据库:efm32-info.mk

每个家族下的 efm32-info.mk 是一份按 CPU 型号组织的只读数据库,每行一个CPU_MODEL,格式为:

系列号 - 内核架构 - Flash 基址 - Flash 大小 - SRAM 基址 - SRAM 大小 - Crypto? - TRNG? - Radio?

efm32-info.mk 解析这些字段,生成EFM32_SERIESEFM32_ARCHITECTUREEFM32_FLASH_START/SIZEEFM32_SRAM_START/SIZE以及EFM32_CRYPTOEFM32_TRNGEFM32_RADIO等变量。这些变量随后被 Makefile.include 用于生成链接脚本的ROM_START_ADDR/ROM_LEN/RAM_START_ADDR/RAM_LEN,直接决定固件的内存布局。以 EFM32GG 为例,efm32gg940f1024对应的信息是0 cortex-m3 0x00000000 0x00100000 0x20000000 0x00020000 0 0 0,即 Series 0、Cortex-M3、1 MiB Flash、128 KiB SRAM。

支持的外围设备

根据原文档,该移植层支持以下外设(具体取决于所用 MCU 型号),仓库中每个外设都有对应的实现文件:

外设实现文件(按系列拆分)
ADCadc_series01.c、adc_series2.c
CPUIDcpuid.c
DACdac.c
Etherneteth.c 及驱动 drivers/eth/eth_netdev.c
Flash pageflashpage.c
GPIOgpio.c、gpio_ll.c
HW RNGhwrng_series1.c、hwrng_series2.c
Power Managementpm.c
PWMpwm.c
RTCrtc_series0.c、rtc_series1.c
RTTrtt_series0.c、rtt_series1.c
SPIspi.c
Timertimer_series01.c、timer_series2.c
UART(含低功耗 LEUART)uart_series01.c、uart_series2.c

外围驱动的编译开关位于 periph/Makefile,系列差异通过EFM32_SERIES变量(Series 0/1 与 Series 2)区分,例如 RTC/RTT/Timer/ADC/UART 都有 series01 与 series2 两套实现。

此外还有两个 EFM32 专属驱动模块:

  • efm32_coretemp:读取 MCU 内部温度传感器,Series 0/1 通过 ADC 通道读取,Series 2 有专用寄存器(见 Makefile.dep 与 drivers/coretemp);
  • efm32_eth:以太网 netdev 驱动,启用后会自动引入iolistnetdev_ethnetdev_new_apiztimer_msec等模块,并FEATURES_REQUIRED += periph_eth periph_gpio(见 Makefile.dep)。

时钟配置:从内部 RC 到外部晶振

原文档指出:默认情况下 MCU 运行在内部 RC 振荡器(HFRCO)上;若板上有外部晶振,可通过设置CLOCK_HF=cmuSelect_HFXO切换;CLOCK_LFACLOCK_LFBCLOCK_LFE同理,使用cmuSelect_LFXO。未使用的内部 RC 振荡器会被关闭。

源码层面的实现

Series 0/1 的时钟初始化实现在 cpu.c 的clk_init()中,流程如下:

  1. 若选择 HFXO,先用板级参数CMU_HFXOINIT调用CMU_HFXOInit()完成初始化,再CMU_ClockSelectSet(cmuClock_HF, CLOCK_HF)切换主时钟;
  2. 通过CMU_ClockDivSet(cmuClock_CORE, CLOCK_CORE_DIV)设置 CORE 分频;
  3. 若主时钟是 HFXO,则调用CMU_OscillatorEnable(cmuOsc_HFRCO, false, false)关闭 HFRCO——这正是文档中"未使用的内部 RC 振荡器将被禁用"的出处;
  4. 对 LFA/LFB(Series 1 还有 LFE)依次做 LFXO 预初始化与时钟源选择;
  5. 仅当 LFA、LFB、LFE 全部使用 LFXO 时,关闭 LFRCO(cpu.c)。

Series 2 的 clk_init() 走另一条路径:振荡器初始化、预分频与时钟源选择分别由clk_div_config[]clk_mux_config[]两个板级配置数组驱动(通过CLK_DIV_NUMOF/CLK_MUX_NUMOF循环设置)。这两个数组定义在板级periph_conf.h中,比 Series 0/1 的单个宏更加灵活。

一个值得注意的细节:LFRCO 抖动与 LEUART

在 Series 1 上,clk_init()还做了一件事:清除CMU->LFRCOCTRL中的ENCHOPENDEM位(cpu.c)。代码注释给出了原因:否则 LFRCO 的抖动过大,导致 LEUART 无法稳定工作在 1800 baud 以上。这解释了为何 UART 外设的低功耗模式需要特定的 LFRCO 配置配合。

如何配置

CLOCK_HF等宏定义在板级periph_conf.h中(EFM32 系列板卡均位于 boards/ 下),典型做法是在板级 Makefile 或periph_conf.h中设定:

/* periph_conf.h 示例 */ #define CLOCK_HF cmuSelect_HFXO /* 使用外部高频晶振 */ #define CLOCK_LFA cmuSelect_LFXO /* 低功耗外设时钟使用外部低频晶振 */ #define CLOCK_LFB cmuSelect_LFXO #define CLOCK_LFE cmuSelect_LFXO

选择外部晶振的前提是硬件上确实连接了对应晶振,具体晶振参数(起振电流、负载电容等)通过后文所述的CMU_HFXOINIT/CMU_LFXOINIT描述。若不配置这些宏,默认值即为内部 RC 振荡器。

EMU 与 CMU 配置:可覆写的默认参数

原文档说明:EMU(Energy Management Unit,能量管理单元)与 CMU(Clock Management Unit,时钟管理单元)使用 Gecko SDK 提供的默认值初始化,开发者可以覆写以下宏:

含义
CMU_HFXOINIT高频外部晶振初始化参数(CMU_HFXOInit_TypeDef
CMU_LFXOINIT低频外部晶振初始化参数(CMU_LFXOInit_TypeDef
EMU_DCDCINIT集成 DC-DC 稳压器初始化参数(EMU_DCDCInit_TypeDef
EMU_EM23INITEM2/EM3 低功耗模式参数(EMU_EM23Init_TypeDef
EMU_EM4INITEM4 关断模式参数(EMU_EM4Init_TypeDef

源码中的默认值

cpu.c 为 EMU 相关宏提供了回退默认值,全部指向 Gecko SDK 的*_DEFAULT常量:

#ifndef EMU_DCDCINIT #define EMU_DCDCINIT EMU_DCDCINIT_DEFAULT #endif #ifndef EMU_EM23INIT #define EMU_EM23INIT EMU_EM23INIT_DEFAULT #endif #ifndef EMU_EM4INIT #define EMU_EM4INIT EMU_EM4INIT_DEFAULT #endif

CMU 的两个宏(CMU_HFXOINITCMU_LFXOINIT)同样在 cpu.c 中有*_DEFAULT回退,且仅对_SILICON_LABS_32B_SERIES < 2的型号生效;Series 2 只在宏已定义时才调用CMU_HFXOInit()(cpu.c)。

DC-DC 与电源模式初始化

  • DC-DC:当芯片带有集成稳压器(DCDC_PRESENTDCDC_COUNT > 0)时,dcdc_init()会执行——若定义了EMU_DCDCINIT_OFF则直接EMU_DCDCPowerOff()关闭,否则用EMU_DCDCINIT参数调用EMU_DCDCInit()(cpu.c);
  • 睡眠模式pm_init()使用EMU_EM23INIT初始化 EM2/EM3,在 Series 1/2 上再以EMU_EM4INIT初始化 EM4(cpu.c)。另外,若启用了DEVELHELP,会调用DBG_EM2DebugEnable(true)让调试单元在 EM2 下保持工作,方便开发期调试。

完整的启动顺序

以上初始化都在cpu_init()中按固定顺序执行(cpu.c):

  1. CHIP_Init():应用芯片 errata 修正(RIOTBOOT 场景跳过);
  2. cortexm_init():初始化 Cortex-M 内核;
  3. dcdc_init():初始化 DC-DC(如存在);
  4. clk_init():初始化时钟源与通用时钟;
  5. pm_init():初始化电源管理接口;
  6. early_init():初始化 stdio(使DEBUG()periph_init()阶段可用);
  7. periph_init():触发各静态外设的初始化。

低功耗配置:EFM32_LEUART_ENABLED 与特性裁剪

原文档强调:EFM32/EFR32/EZR32 支持低功耗外设,该支持默认启用但可关闭。设置EFM32_LEUART_ENABLED=0会关闭 UART 驱动中的 LEUART 支持,大约节省 400 字节,并提示参考efm32-features.mk查看更多选项。

实现与默认值

efm32-features.mk 是该特性的唯一默认定义:

# 可以从命令行或板级 Makefile 覆写;注意部分特性并非适用于所有 EFM32 板卡/CPU。 EFM32_LEUART_ENABLED ?= 1

该变量被 Makefile.features 消费:当EFM32_LEUART_ENABLED=1时,向编译器追加-DEFM32_LEUART_ENABLED=1宏定义,驱动代码据此决定是否编译 LEUART 路径。关闭方式:

# 板级 Makefile 或命令行 EFM32_LEUART_ENABLED = 0

由于底层 UART 驱动(uart_series01.c、uart_series2.c)需要同时支持普通 UART 与低功耗 LEUART 两套初始化/收发逻辑,关闭 LEUART 后这部分代码与数据不再链接,从而节省约 400 字节的 ROM/RAM——这正是文档给出的数值。注意该特性只影响UART 驱动中的 LEUART 支持,不影响 LEUART 硬件本身,也并非对所有型号都适用(见efm32-features.mk的注释)。

其他低功耗相关默认配置

  • Makefile.default 将pm_layered加入DEFAULT_MODULE,即默认启用分层电源管理(RIOT 的pm_layered框架),这是 EFM32 睡眠模式(EM0–EM4)接入 RIOT 电源管理的基础;
  • Makefile.features 对除efm32hgefm32tg11befm32zg外的家族提供cortexm_mpu特性。

特性矩阵与使用约束

cpu/efm32/Makefile.features 集中声明了该 CPU 移植层提供的 RIOT 特性(features),是理解"能做什么"的第一手依据:

  • 全部家族通用periph_cpuidperiph_flashpage(含periph_flashpage_in_address_spaceperiph_flashpage_pagewise)、periph_gpio/periph_gpio_irq/periph_gpio_ll(含上下拉、开漏开源等)、periph_rtt_set_counterperiph_rtt_overflowperiph_uart_modecfgperiph_wdt
  • 按型号提供periph_hwrng仅当EFM32_TRNG=1时提供;periph_wdt_cb仅对 Series 1/2 提供(Makefile.features);
  • MPU:除efm32hgefm32tg11befm32zg三个无 MPU 家族外均提供cortexm_mpu

需要注意的冲突

原文档之外,Makefile.features 还声明了两条关键约束:

FEATURES_CONFLICT += periph_rtc:periph_rtt FEATURES_CONFLICT_MSG += "On the EFM32, the RTC and RTT map to the same hardware peripheral."

RTC 与 RTT 在 EFM32 上映射到同一硬件外设,二者不能同时启用。另一个冲突是cortexm_fpugecko_sdk_librail_nonfpu:使用 librail(EFR32 射频库)时不能启用 FPU。

内存与引导配置

cpu/efm32/Makefile.include 中还定义了:

  • RIOTBOOT 长度:启用periph_usbdevRIOTBOOT_LEN默认为0x4000,否则为0x2000(USB 引导区更大,注释说明 EFM32 上 riotboot 的默认值偏小);
  • 链接脚本统一使用 cortexm.ld(经由 cortexm.inc.mk);
  • Flash 页参数在 include/cpu_conf.h 中定义:最小写块 4 字节、4 字节对齐、擦除块为整页。

实战:如何在板级工程中使用

在基于 EFM32 的 RIOT 应用中,通常需要做三件事:

  1. 选择 CPU/板卡:RIOT 构建系统根据BOARD自动引入对应的cpu/efm32代码与家族模块(USEMODULE += cpu_$(CPU_FAM),见 Makefile.dep);若板卡在 boards/ 下,直接BOARD=xxx make即可。
  2. 配置时钟与 EMU/CMU:在板级 periph_conf.h(位于各板卡目录)中定义CLOCK_HFCLOCK_LFA/LFB/LFECMU_HFXOINITEMU_DCDCINIT等宏;晶振初始化参数参考 Gecko SDK 文档。
  3. 裁剪低功耗外设:在板级 Makefile 或命令行中加入EFM32_LEUART_ENABLED = 0以节省约 400 字节。

需要注意的是:EFM32 上RTC 与 RTT 共享同一硬件外设,应用中只能二选一;若用到 EFR32 的 Sub-GHz 射频(librail),还需避免与cortexm_fpu同时启用。

总结

cpu/efm32是一个典型的"vendor 库驱动 + RIOT 外设抽象"式 CPU 移植层:外围驱动直接建立在 Gecko SDK 之上,RIOT 层负责统一的periph_*API、内存布局与电源管理接入。文档中寥寥数行描述的时钟宏(CLOCK_HF/CLOCK_LFA/CLOCK_LFB/CLOCK_LFE)、EMU/CMU 覆写点(CMU_HFXOINITCMU_LFXOINITEMU_DCDCINITEMU_EM23INITEMU_EM4INIT)与低功耗开关(EFM32_LEUART_ENABLED),在 cpu.c、Makefile.features 等源码中均有完整闭环的实现支撑。掌握了这些配置项与启动链路,你就可以在任意 EFM32/EFR32/EZR32 板卡上精准地切换时钟源、定制电源模式并裁剪外设开销。

  • 物联网
  • 嵌入式
  • 操作系统
  • 实时系统

【免费下载链接】RIOT

RIOT - The friendly OS for IoT

项目地址:https://gitcode.com/GitHub_Trending/riot/RIOT
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询