RIOT OS 板级支持详解:STM32 Nucleo-L476RG 开发板的配置、外设与烧录指南
【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT
本指南以 RIOT OS 仓库中 boards/nucleo-l476rg/doc.md 为核心,系统讲解 STM32 Nucleo-L476RG 开发板在 RIOT 中的板级支持(BSP)实现。你将掌握该板的 MCU 资源规格、引脚分配、外设(UART/SPI/I2C/ADC/PWM/定时器/DMA)在源码中的真实映射方式,以及如何用nucleo-l476rg板名完成编译烧录并接入 RIOT shell,从而在此基础上快速开展物联网应用开发。
板级总览:面向低功耗场景的 Cortex-M4F 平台
Nucleo-L476RG 是 ST 公司 Nucleo 系列中的经典低功耗开发板,属于 Nucleo-64 板型家族。RIOT 将它与同系列的其它 64 引脚 Nucleo 板统一放在boards_common_nucleo64分组下,因此 boards/common/nucleo64/doc.md 中描述的通用特性(LED0/SPI 引脚冲突、ST-Link 虚拟串口等)同样适用于本板。
RIOT 对该板的正式描述定义在 boards/nucleo-l476rg/doc.md:
- 板载 MCU 为STM32L476RG,属于 ARM Cortex-M4F 内核(带硬件 FPU);
- 拥有128 KiB RAM与1 MiB Flash;
- 最高主频80 MHz。
以下为 RIOT 文档给出的完整 MCU 资源表:
| 资源 | 规格 |
|---|---|
| MCU | STM32L476RG(ST Microelectronics) |
| 内核 | ARM Cortex-M4F(带 FPU) |
| RAM | 128 KiB |
| Flash | 1 MiB |
| 最高主频 | 80 MHz |
| 定时器 | 16 个(2×看门狗、1×SysTick、6×16 位、2×32 位,其中 TIM2 为 32 位) |
| ADC | 3 个 12 位(最多 16 通道) |
| UART | 6 个(3 个 USART、2 个 UART、1 个低功耗 LPUART) |
| SPI | 3 个 |
| I2C | 3 个 |
| RTC | 1 个 |
| CAN | 1 个 |
| 供电电压 Vcc | 1.71 V – 3.6 V |
从源码角度看,板级定义由以下文件共同构成(均在 boards/nucleo-l476rg/ 目录下):
Makefile:声明MODULE = board,并引入$(RIOTBOARD)/common/nucleo的公共构建逻辑;Makefile.features:声明CPU = stm32、CPU_MODEL = stm32l476rg及板级外设能力;Makefile.include/Makefile.dep:分别引入common/nucleo64的公共包含路径与依赖规则;Kconfig:完成BOARD_NUCLEO_L476RG的 Kconfig 建模;include/periph_conf.h:板级外设的引脚与时钟映射(本指南第三节详述)。
板级特性声明:FEATURES_PROVIDED 揭示的可用外设
boards/nucleo-l476rg/Makefile.features 以FEATURES_PROVIDED的形式声明了 RIOT 应用层可以放心启用的外设模块,这是评估"这块板能做什么"的最直接依据:
CPU = stm32 CPU_MODEL = stm32l476rg # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_can FEATURES_PROVIDED += periph_dma FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart # Put other features for this board (in alphabetical order) FEATURES_PROVIDED += riotboot # load the common Makefile.features for Nucleo boards include $(RIOTBOARD)/common/nucleo64/Makefile.features解读这些声明:
- 模拟/数字外设:
periph_adc、periph_dma、periph_pwm、periph_timer、periph_uart、periph_spi、periph_i2c一应俱全,覆盖了绝大多数传感器驱动与通信场景; - 时间与低功耗:
periph_rtc(日历时钟)与periph_rtt(低功耗运行定时器)都可用,配合 MCU 的 LSE 晶振配置,非常适合电池供电的定时唤醒类应用; - 车载/工业通信:
periph_can表明板载 STM32L476RG 的 CAN 控制器已被 RIOT 驱动启用; - OTA 能力:
riotboot特性说明该板支持 RIOT 的 riotboot 引导加载方案,可做固件升级。
Kconfig 侧则通过 boards/nucleo-l476rg/Kconfig 建立等价模型:BOARD_NUCLEO_L476RG选中BOARD_COMMON_NUCLEO64与CPU_MODEL_STM32L476RG,同时引入nucleo64公共 Kconfig。这意味着无论走 Makefile 还是 Kconfig 配置路径,外设能力保持一致。
外设映射源码解析:periph_conf.h 中的真实引脚分配
boards/nucleo-l476rg/include/periph_conf.h 是本板 BSP 的核心,它决定了 RIOT 各外设驱动与 STM32L476RG 硬件的绑定关系。下面逐项剖析(其中引脚编号遵循 STM32 的 PA0–PA15、PB0–PB15、PC0–PC15 约定)。
时钟配置
#ifndef CONFIG_BOARD_HAS_LSE #define CONFIG_BOARD_HAS_LSE 1 #endif板级强制启用LSE(低速外部晶振,通常为 32.768 kHz),这是 RTC/RTT 模块获得精确走时的前提,也是该板定位低功耗应用的关键配置。
DMA 流配置
static const dma_conf_t dma_config[] = { { .stream = 1 }, /* DMA1 Channel 2 - SPI1_RX | USART3_TX */ { .stream = 2 }, /* DMA1 Channel 3 - SPI1_TX */ { .stream = 3 }, /* DMA1 Channel 4 - USART1_TX */ { .stream = 6 }, /* DMA1 Channel 7 - USART2_TX */ };共定义 4 个 DMA 流,分别服务 SPI1 接收/发送与 USART1/2/3 的发送方向。启用periph_dma后,periph_conf.h 中的 UART 与 SPI 配置会在#ifdef MODULE_PERIPH_DMA分支下自动附加dma/dma_chan字段,实现数据搬运不占用 CPU。
定时器配置(TIM5 32 位)
static const timer_conf_t timer_config[] = { { .dev = TIM5, .max = 0xffffffff, /* 32 位计数上限 */ .rcc_mask = RCC_APB1ENR1_TIM5EN, .bus = APB1, .irqn = TIM5_IRQn } };RIOT 将TIM5(32 位定时器)用作系统periph_timer设备,.max = 0xffffffff表示 32 位满量程,可提供长达数小时的毫秒级定时跨度而不必担心溢出回绕,适合需要长定时的应用。
UART 配置与默认终端
static const uart_conf_t uart_config[] = { { .dev = USART2, /* ST-Link VCP 默认串口 */ .rx_pin = GPIO_PIN(PORT_A, 3), .tx_pin = GPIO_PIN(PORT_A, 2), .rx_af = GPIO_AF7, .tx_af = GPIO_AF7, .bus = APB1, .irqn = USART2_IRQn, .clk_src = 0, /* 使用 APB 时钟 */ #ifdef MODULE_PERIPH_DMA .dma = 3, .dma_chan = 2 #endif }, { .dev = USART3, /* PC10/PC11 */ .rx_pin = GPIO_PIN(PORT_C, 11), .tx_pin = GPIO_PIN(PORT_C, 10), ... }, { .dev = USART1, /* PA9/PA10 */ .rx_pin = GPIO_PIN(PORT_A, 10), .tx_pin = GPIO_PIN(PORT_A, 9), ... } };板上共暴露 3 路 UART 给 RIOT:
- USART2(PA2/PA3):连接板载 ST-Link 的虚拟串口(VCP),是RIOT shell 的默认终端(详见第五节);
- USART3(PC10/PC11)与USART1(PA9/PA10):可分配给外部传感器、GPS、调试日志等用途。
PWM 配置(TIM2 / TIM3 / TIM8)
static const pwm_conf_t pwm_config[] = { { .dev = TIM2, .chan = { { .pin = GPIO_PIN(PORT_A, 15), .cc_chan = 0}, { .pin = GPIO_PIN(PORT_B, 3), .cc_chan = 1}, { .pin = GPIO_PIN(PORT_B, 10), .cc_chan = 2}, { .pin = GPIO_PIN(PORT_B, 11), .cc_chan = 3} }, .af = GPIO_AF1, .bus = APB1 }, { .dev = TIM3, /* 仅 PB4 单通道 */ .chan = { { .pin = GPIO_PIN(PORT_B, 4), .cc_chan = 0 }, { .pin = GPIO_UNDEF, ... }, ... }, .af = GPIO_AF2, .bus = APB1 }, { .dev = TIM8, /* PC6-PC9 四通道 */ .chan = { { .pin = GPIO_PIN(PORT_C, 6), .cc_chan = 0}, { .pin = GPIO_PIN(PORT_C, 7), .cc_chan = 1}, { .pin = GPIO_PIN(PORT_C, 8), .cc_chan = 2}, { .pin = GPIO_PIN(PORT_C, 9), .cc_chan = 3} }, .af = GPIO_AF3, .bus = APB2 } };PWM 资源相当充足:TIM2(PA15/PB3/PB10/PB11)、TIM3(PB4)、TIM8(PC6–PC9)合计 9 个可输出通道,足以驱动多路舵机、LED 调光或电机控制。未被使用的通道以GPIO_UNDEF占位。
SPI 配置(SPI1)
static const spi_conf_t spi_config[] = { { .dev = SPI1, .mosi_pin = GPIO_PIN(PORT_A, 7), .miso_pin = GPIO_PIN(PORT_A, 6), .sclk_pin = GPIO_PIN(PORT_A, 5), .cs_pin = SPI_CS_UNDEF, /* 片选由用户自行管理 */ .mosi_af = GPIO_AF5, .miso_af = GPIO_AF5, .sclk_af = GPIO_AF5, .cs_af = GPIO_AF5, .rccmask = RCC_APB2ENR_SPI1EN, .apbbus = APB2, #ifdef MODULE_PERIPH_DMA .tx_dma = 1, .tx_dma_chan = 1, .rx_dma = 0, .rx_dma_chan = 1, #endif } };SPI1 挂载在PA5(SCLK)/ PA6(MISO)/ PA7(MOSI),即 Arduino 排针的 D13/D12/D11 位置,兼容常见的 Arduino 扩展板与 SPI 传感器。.cs_pin = SPI_CS_UNDEF表示硬件片选由应用自行通过 GPIO 控制,这与大多数外设驱动(如 mrf24j40、sdcard_spi)的用法一致。注意:SPI1 的 SCLK(PA5)恰好与 LED0 冲突,详见第五节。
ADC 配置与 VBAT 监测
static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_A, 0), 0, 5}, /* ADC12_IN5 */ {GPIO_PIN(PORT_A, 1), 0, 6}, /* ADC12_IN6 */ {GPIO_PIN(PORT_A, 4), 1, 9}, /* ADC12_IN9 */ {GPIO_PIN(PORT_B, 0), 1, 15}, /* ADC12_IN15 */ {GPIO_PIN(PORT_C, 1), 2, 2}, /* ADC123_IN2 */ {GPIO_PIN(PORT_C, 0), 2, 1}, /* ADC123_IN1 */ {GPIO_UNDEF, 0, 18}, /* VBAT */ }; #define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */RIOT 为该板定义了6 个外部 ADC 通道 + 1 个内部 VBAT 通道,正好对应 Nucleo 排针的 A0–A5(PA0、PA1、PA4、PB0、PC1、PC0),三段式(引脚, ADC设备号, ADC通道号)的写法可对照板卡手册中的ADC[X]_IN[Y]标注。特别值得关注的是末尾的VBAT 内部通道:它通过 ADC1_IN18 采样,且板载分压电路只测到实际 VBAT 的 1/3,因此可以测量高于参考电压的供电电压,非常适合电池供电应用做电量监测(调用VBAT_ADC即可读取该通道)。
通用板级特性:LED、按键与 SAUL 设备
通过 boards/common/nucleo64/Makefile.include 引入的公共头文件 boards/common/nucleo64/include/board.h 定义了全系列 Nucleo-64 的板级常量。对于 STM32L476RG(不属于特殊分支),其值为:
- LED0(板载绿色 LED):
PA5(LED0_PIN_NUM = 5,LED0_PORT = GPIO_PORT_A); - 用户按键 B1(BTN0):
PC13(BTN0_PIN = GPIO_PIN(PORT_C, 13)),默认GPIO_IN_PU上拉输入——按下时接地,故 gpio_params.h 中为其设置了SAUL_GPIO_INVERTED标志。
公共头文件还为 MRF24J40 802.15.4 模块预留了默认参数(SPI0、5 MHz 时钟、CS/INT/RESET 分别映射到 Arduino 引脚 10/7/5),不过该板默认未启用,仅作为扩展参考。
得益于 boards/common/nucleo64/include/gpio_params.h 的 SAUL 映射,启动后 RIOT 会自动注册两个可通过saul接口访问的 GPIO 设备:LED(green)(输出)与Button(B1 User)(输入),可直接被 tests/saul 之类的应用枚举和使用。
已知冲突:SPI 与 LED0 不能同时使用
这是 Nucleo-64 系列的通用注意事项,记录在 boards/common/nucleo64/doc.md 中:
Due to a pin conflict on Nucleo64 boards, you can not use the SPI peripheral and LED0 at the same time.
由于 SPI1 的 SCLK 占用 PA5(即 LED0 所在引脚),在 Makefile 中加入USEMODULE += periph_spi时,构建系统会打印警告并自动禁用periph_init_led0:
Warning: Using periph_spi on Nucleo64 boards will disable LED0 due to pin conflicts.该逻辑实现在 boards/common/nucleo64/Makefile.dep:检测到periph_spi模块后向DISABLE_MODULE追加periph_init_led0。换言之,在启用 SPI 的工程里,LED0_*相关 API 将不可用,需要改用其它 GPIO 做指示。
烧录与 RIOT shell 接入
编译烧录
RIOT 官方烧录指南(guides 目录 中的 STM32 板卡章节)说明了 ST 系列的标准烧录流程。Nucleo 板载 ST-Link 调试器,make flash会直接通过 ST-Link 完成下载。本板在构建系统中的正式板名是:
nucleo-l476rg典型用法(以 hello-world 为例,源码位于 examples/hello-world):
make -C examples/hello-world BOARD=nucleo-l476rg flash其中BOARD=nucleo-l476rg会命中 boards/nucleo-l476rg/Makefile 及common/nucleo下的烧录规则。此外,由于板级声明了riotboot特性,还可以搭配 riotboot_serial 通过串口进行固件更新。
接入 RIOT shell
根据 boards/common/nucleo64/doc.md,RIOT shell 默认通过ST-Link 的虚拟串口(VCP)提供,无需外接 USB 转串口模块。各 Nucleo 变体的 VCP 所连接的 USART 不同,对 L476RG 而言,从 periph_conf.h 可以看到默认终端为USART2(PA2/PA3)。
串口参数固定为:
| 参数 | 值 |
|---|---|
| 波特率 | 115200 |
| 数据位 | 8 |
| 校验 | 无(N) |
| 停止位 | 1(即 8N1) |
在宿主机上使用任意串口工具(如minicom、screen、picocom)连接 ST-Link 枚举出的串口设备,即可进入 RIOT shell 与板卡交互,例如help查看可用命令、ps查看线程、ifconfig查看网络接口等。
应用实践要点小结
围绕 boards/nucleo-l476rg/doc.md 与配套源码,可归纳出该板在 RIOT 中的开发要点:
- 选型定位:STM32L476RG 的 Cortex-M4F + FPU 与 128 KiB RAM 足以承载 RIOT 的网络栈(如 gnrc)与部分 ML 推理负载,1 MiB Flash 也为
riotboot双分区固件留出空间; - 外设充足:3 路 UART、SPI1、6+1 路 ADC(含 VBAT 电量监测)、9 路 PWM 输出,基本覆盖传感器采集、执行器控制、串口调试三大类需求;
- 注意引脚冲突:启用
periph_spi前须确认无需使用 LED0; - 默认终端固定:RIOT shell 走 USART2/ST-Link VCP,115200-8N1,开箱即用;
- 深入扩展入口:继续阅读 cpu/stm32 下的时钟与
clk_conf.h头文件,可进一步了解 80 MHz 主频与 HSE/LSE 的时钟树配置细节。
若需获取更精细的引脚布局与丝印对应关系,可参照板卡手册 UM1724 中的引脚图,并在实际接线前核对 periph_conf.h 中每项外设的具体引脚映射。
【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考