在 RIOT OS 中使用 NXP FRDM-KL43Z:板级支持、外设配置与烧录指南
2026/9/18 5:26:28 网站建设 项目流程

在 RIOT OS 中使用 NXP FRDM-KL43Z:板级支持、外设配置与烧录指南

【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT

导读:本文以 RIOT 开源物联网操作系统中boards/frdm-kl43z板级支持包(BSP)为主线,系统讲解基于 MKL43Z256VLH4(ARM Cortex-M0+)的 NXP FRDM-KL43Z Freedom 开发板的时钟树、UART/ADC/I2C/定时器外设映射、板载 LED 与传感器(MAG3110、MMA8451Q)的 SAUL 接入,以及基于 OpenOCD/CMSIS-DAP 的编译烧录流程。读者读完可掌握在 RIOT 中为该板编写应用、定制外设映射和调试部署的完整方法。

1. 板级概述:一块面向低功耗的 Kinetis L 系列开发板

FRDM-KL43Z 是 NXP 出品的 Freedom 系列开发板,其核心是MKL43Z256VLH4——一颗基于ARM Cortex-M0+内核的 Kinetis L 系列低功耗 MCU。RIOT 将其定位为“低功耗嵌入式应用与 Kinetis L 系列实验”的紧凑平台,这一点直接体现在 boards/frdm-kl43z/doc.md 的文档定义中:

  • 支持组(defgroup):boards_frdm-kl43z
  • 隶属组:boards(板级支持组)
  • 说明:Support for the NXP FRDM-KL43Z board(对 NXP FRDM-KL43Z 开发板的支持)

从 boards/frdm-kl43z/Makefile.features 可以看到 RIOT 对该板的外设能力声明(按字母序排列):

CPU = kinetis CPU_MODEL = mkl43z256vlh4 FEATURES_PROVIDED += periph_adc FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart

即该板在 RIOT 中默认提供ADC、I2C、RTC、RTT、Timer、UART六类外设抽象接口;CPU/CPU_MODEL两个变量把板级实现与cpu/kinetis下的 Kinetis 通用驱动和mkl43z256vlh4具体型号配置关联起来。

在 Kconfig 一侧,boards/frdm-kl43z/Kconfig 将板名与 CPU 型号绑定:

config BOARD default "frdm-kl43z" if BOARD_FRDM_KL43Z config BOARD_FRDM_KL43Z bool default y select CPU_MODEL_MKL43Z256VLH4

2. 时钟系统:8 MHz 内部时钟 + 32.768 kHz RTC 晶振

FRDM-KL43Z 的时钟配置集中定义在 boards/frdm-kl43z/include/periph_conf.h 的clock_config_t clock_config结构体中。该板采用LIRC8M(内部 8 MHz 低速参考时钟)作为默认模式,并以 32.768 kHz 低速晶振驱动 RTC:

static const clock_config_t clock_config = { /* * 该配置使系统运行在内部时钟上,频率如下: * Core: 8 MHz * Bus: 8 MHz * Flash: 8 MHz */ .clkdiv1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV4(0), /* 不确定该 RTC 负载电容配置是否正确 */ .rtc_clc = RTC_CR_SC8P_MASK | RTC_CR_SC4P_MASK, /* 使用 32 kHz 系统振荡器输出作为 ERCLK32K。 */ .osc32ksel = SIM_SOPT1_OSC32KSEL(0), .clock_flags = KINETIS_CLOCK_RTCOSC_EN | KINETIS_CLOCK_USE_FAST_IRC | KINETIS_CLOCK_MCGIRCLK_EN | /* 用于 LPUART 时钟 */ KINETIS_CLOCK_MCGIRCLK_STOP_EN | 0, /* 默认使用 LIRC8M 模式 */ .default_mode = KINETIS_MCG_MODE_LIRC8M, /* 连接到 EXTAL0 的晶振为 32.768 kHz */ .erc_range = KINETIS_MCG_ERC_RANGE_LOW, .osc_clc = 0, /* 无负载电容配置,KL43Z 上由 rtc_clc 覆盖 */ .fcrdiv = MCG_SC_FCRDIV(0), /* LIRC_DIV1 除 1 => 8 MHz */ .lirc_div2 = MCG_MC_LIRC_DIV2(0), /* LIRC_DIV2 除 1 => 8 MHz */ }; #define CLOCK_CORECLOCK ( 8000000ul) #define CLOCK_MCGIRCLK ( 8000000ul) #define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 1)

几个值得注意的细节:

  • CLOCK_CORECLOCK、CLOCK_BUSCLOCK、CLOCK_MCGIRCLK 均为 8 MHz,其中CLOCK_MCGIRCLK(内部参考时钟)被专门启用并配置为LPUART 的时钟源(见下文 UART 一节),MCGIRCLK_STOP_EN允许其在低功耗停止模式下继续工作。
  • rtc_clc设置了 RTC 振荡器的负载电容位(SC8P/SC4P),源码注释明确提示“不确定该 RTC 负载电容配置是否正确”,属于板级作者遗留的待验证项,读者在定制时可根据实际晶振负载需求调整。
  • erc_range = KINETIS_MCG_ERC_RANGE_LOW对应外部 32.768 kHz 晶振的低频范围。

3. 外设引脚映射(periph_conf.h)

3.1 UART:LPUART0,默认控制台接口

板载调试/控制台串口使用LPUART0,引脚为PTA1(RX)/ PTA2(TX),引脚复用功能 MUX 2,帧格式8N1

static const uart_conf_t uart_config[] = { { .dev = LPUART0, .freq = CLOCK_MCGIRCLK, /* 以内部参考时钟为时钟源 */ .pin_rx = GPIO_PIN(PORT_A, 1), .pin_tx = GPIO_PIN(PORT_A, 2), .pcr_rx = PORT_PCR_MUX(2), .pcr_tx = PORT_PCR_MUX(2), .irqn = LPUART0_IRQn, .scgc_addr = &SIM->SCGC5, .scgc_bit = SIM_SCGC5_LPUART0_SHIFT, .mode = UART_MODE_8N1, .type = KINETIS_LPUART, }, }; #define UART_NUMOF ARRAY_SIZE(uart_config) #define LPUART_0_ISR isr_lpuart0 /* 使用 MCGIRCLK(内部参考时钟) */ #define LPUART_0_SRC 3

关键点:.freq = CLOCK_MCGIRCLK配合LPUART_0_SRC 3,表明 LPUART0 由 MCGIRCLK 驱动(该时钟被显式开启正是为了串口用途);scgc_addr/scgc_bit给出外设时钟门控(SIM_SCGC5)的使能位置。启动后该串口即作为 RIOT 的默认 STDIO 输出使用。

3.2 ADC:ADC0 六通道,直连 Arduino 排针 A0–A5

ADC 使用 ADC0,共配置6 个通道,与 Arduino 兼容排针 A0–A5 一一对应:

static const adc_conf_t adc_config[] = { /* dev, pin, channel */ { .dev = ADC0, .pin = GPIO_PIN(PORT_B, 0), .chan = 8, .avg = ADC_AVG_MAX }, /* Arduino A0 */ { .dev = ADC0, .pin = GPIO_PIN(PORT_B, 1), .chan = 9, .avg = ADC_AVG_MAX }, /* Arduino A1 */ { .dev = ADC0, .pin = GPIO_PIN(PORT_B, 2), .chan = 15, .avg = ADC_AVG_MAX }, /* Arduino A2 */ { .dev = ADC0, .pin = GPIO_PIN(PORT_B, 3), .chan = 4, .avg = ADC_AVG_MAX }, /* Arduino A3 */ { .dev = ADC0, .pin = GPIO_PIN(PORT_C, 2), .chan = 11, .avg = ADC_AVG_MAX }, /* Arduino A4 */ { .dev = ADC0, .pin = GPIO_PIN(PORT_C, 1), .chan = 15, .avg = ADC_AVG_MAX }, /* Arduino A5 */ }; #define ADC_NUMOF ARRAY_SIZE(adc_config) /* KL43Z ADC 参考电压设置: * 0: VREFH/VREFL 外部引脚对 * 1: VDDA/VSSA 电源引脚 * 2-3: 保留 */ #define ADC_REF_SETTING 0
  • 每通道均启用最大平均(ADC_AVG_MAX),用于抑制采样噪声、提升有效位数。
  • ADC_REF_SETTING 0表示采用VREFH/VREFL 外部基准引脚对(即板上的外部基准源),源码注释也列出了其他取值含义(1 为 VDDA/VSSA 电源基准,2–3 保留)。

3.3 I2C:I2C0 与 I2C1 双总线

板上配置了两条 I2C 总线,均运行在I2C_SPEED_FAST(400 kHz 档)

总线SCLSDA引脚复用
I2C0PTE24PTE25MUX 5
I2C1PTE1PTE0MUX 6
static const i2c_conf_t i2c_config[] = { { .i2c = I2C0, .scl_pin = GPIO_PIN(PORT_E, 24), .sda_pin = GPIO_PIN(PORT_E, 25), .freq = CLOCK_CORECLOCK, .speed = I2C_SPEED_FAST, .irqn = I2C0_IRQn, .scl_pcr = (PORT_PCR_MUX(5)), .sda_pcr = (PORT_PCR_MUX(5)), }, { .i2c = I2C1, .scl_pin = GPIO_PIN(PORT_E, 1), .sda_pin = GPIO_PIN(PORT_E, 0), .freq = CLOCK_CORECLOCK, .speed = I2C_SPEED_FAST, .irqn = I2C1_IRQn, .scl_pcr = (PORT_PCR_MUX(6)), .sda_pcr = (PORT_PCR_MUX(6)), }, }; #define I2C_NUMOF ARRAY_SIZE(i2c_config) #define I2C_0_ISR isr_i2c0 #define I2C_1_ISR isr_i2c1

板载的 MAG3110 磁力计与 MMA8451Q 加速度计都挂在I2C0上(见第 5 节),因此 I2C0 是板载传感器数据通路,I2C1 可供用户扩展外设。

3.4 定时器:PIT + LPTMR

RIOT 的periph_timer由两类硬件定时器共同提供:

#define PIT_NUMOF (1U) #define PIT_CONFIG { \ { \ .prescaler_ch = 0, \ .count_ch = 1, \ }, \ } #define LPTMR_NUMOF (1U) #define LPTMR_CONFIG { \ { \ .dev = LPTMR0, \ .irqn = LPTMR0_IRQn, \ .src = 2, \ .base_freq = 32768u, \ }, \ } #define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF)) #define PIT_BASECLOCK (CLOCK_BUSCLOCK) #define PIT_ISR_0 isr_pit1 #define LPTMR_ISR_0 isr_lptmr0
  • PIT(周期中断定时器):1 路,基于总线时钟(8 MHz)计数。
  • LPTMR(低功耗定时器):1 路,base_freq = 32768u,由 RTC 32.768 kHz 时钟驱动,可用于低功耗场景下的计时。

board.h中还根据KINETIS_XTIMER_SOURCE_PIT宏选择 xtimer 的后端:默认走LPTMR(16 位、32768 Hz),并配套定义了 xtimer 的XTIMER_WIDTHXTIMER_BACKOFFXTIMER_ISR_BACKOFFXTIMER_OVERHEAD等校准参数;若选择 PIT 后端则沿用默认 xtimer 参数:

#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT) #define XTIMER_DEV (TIMER_PIT_DEV(0)) #define XTIMER_CHAN (0) #else #define XTIMER_DEV (TIMER_LPTMR_DEV(0)) #define XTIMER_CHAN (0) /* LPTMR 为 16 位,由 RTC 驱动运行在 32768 Hz */ #define XTIMER_WIDTH (16) #define XTIMER_BACKOFF (5) #define XTIMER_ISR_BACKOFF (5) #define XTIMER_OVERHEAD (4) #define XTIMER_HZ (32768ul) #endif

4. 板载 LED、按键与启动配置(board.h)

boards/frdm-kl43z/include/board.h 定义了板级基础资源:

LED 引脚(低电平点亮)。源码注释明确说明:原厂原理图中 LED 命名为 LED1/LED2,RIOT 将其重映射为从 0 开始的编号——NXP LED1 → RIOT LED0,NXP LED2 → RIOT LED1

RIOT 名称引脚原厂名称控制寄存器操作
LED0PTD5LED1GPIOD->PCOR/PSOR/PTOR
LED1PTE31LED2GPIOE->PCOR/PSOR/PTOR
#define LED0_PIN GPIO_PIN(PORT_D, 5) #define LED1_PIN GPIO_PIN(PORT_E, 31) #define LED0_ON (GPIOD->PCOR = LED0_MASK) #define LED0_OFF (GPIOD->PSOR = LED0_MASK) #define LED0_TOGGLE (GPIOD->PTOR = LED0_MASK)

LED 通过 GPIO 的 PCOR(清位)/PSOR(置位)/PTOR(翻转)寄存器直接控制,属于低电平有效的板载指示灯。

启动配置(FOPT)KINETIS_FOPT定义了 flash 配置字段——禁用 ROM 引导加载程序,直接从 flash 启动用户应用

/* 禁用 ROM bootloader,从 flash 启动用户应用 */ #define KINETIS_FOPT (0xff & ~(NV_FOPT_BOOTSRC_SEL_MASK | NV_FOPT_BOOTPIN_OPT_MASK))

这一点与烧录章节中check-fcfield.sh的预烧录检查相互呼应(见第 7 节)。

5. 板载传感器与 SAUL 接入

FRDM-KL43Z 板载两颗 I2C 传感器,均挂在I2C0上,其总线参数直接在board.h中通过*_PARAM_*宏预定义:

/* MAG3110 三轴磁力计 */ #define MAG3110_PARAM_I2C I2C_DEV(0) #define MAG3110_PARAM_ADDR 0x0E /* MMA8451Q 三轴加速度计 */ #define MMA8X5X_PARAM_I2C I2C_DEV(0) #define MMA8X5X_PARAM_ADDR 0x1D #define MMA8X5X_PARAM_TYPE (MMA8X5X_TYPE_MMA8451)
  • MAG3110:三轴磁力计,I2C 地址0x0E(对应 drivers/mag3110 驱动);
  • MMA8451Q:三轴加速度计,I2C 地址0x1D,类型指定为MMA8451(对应 drivers/mma8x5x 驱动)。

当应用启用saul_default模块时,boards/frdm-kl43z/Makefile.dep 会自动追加相关依赖:

ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += saul_gpio USEMODULE += saul_adc USEMODULE += mag3110 USEMODULE += mma8x5x endif

这样一次编译即可把板载 LED、SW1 按键、A0–A3 模拟通道以及 MAG3110/MMA8451Q 两颗传感器统一注册进 SAUL(Sensor Actuator Uber Layer)注册表,通过saulshell 命令或自动初始化(auto_init)即可直接枚举与访问。

具体到 SAUL 的直连映射:

  • boards/frdm-kl43z/include/gpio_params.h 注册了 3 个 GPIO 设备:
SAUL 名称引脚模式标志
LED1(green)LED0_PIN (PTD5)GPIO_OUTSAUL_GPIO_INVERTED
LED2(red)LED1_PIN (PTE31)GPIO_OUTSAUL_GPIO_INVERTED
SW1PTC3GPIO_IN_PU

SAUL_GPIO_INVERTED标志与 LED 低电平有效特性一致(写 1 关灯、写 0 开灯)。

  • boards/frdm-kl43z/include/adc_params.h 将 A0–A3 注册为 16 位分辨率采样通道(ADC_RES_16BIT),供 SAUL 直接读取模拟量:
static const saul_adc_params_t saul_adc_params[] = { { .name = "A0", .line = ADC_LINE(0), .res = ADC_RES_16BIT }, { .name = "A1", .line = ADC_LINE(1), .res = ADC_RES_16BIT }, { .name = "A2", .line = ADC_LINE(2), .res = ADC_RES_16BIT }, { .name = "A3", .line = ADC_LINE(3), .res = ADC_RES_16BIT }, };

6. 板级构建结构一览

boards/frdm-kl43z目录的构成与 RIOT 标准板级包一致:

boards/frdm-kl43z/ ├── Kconfig # BOARD 符号与 CPU_MODEL 选择 ├── Makefile # MODULE = board,引入 Makefile.base ├── Makefile.dep # saul_default 依赖(saul_gpio/saul_adc/mag3110/mma8x5x) ├── Makefile.features # CPU、CPU_MODEL 与 FEATURES_PROVIDED ├── Makefile.include # 调试适配器与 FRDM 公共配置 ├── doc.md # 板级文档 └── include/ ├── adc_params.h # SAUL ADC 直连映射 ├── board.h # LED/按键/传感器/xtimer/FOPT 定义 ├── gpio_params.h # SAUL GPIO 直连映射 └── periph_conf.h # 时钟、UART、ADC、I2C、定时器配置

Makefile.include负责接入烧录工具链配置,并引入 FRDM 系列公共配置:

# 本板 OpenSDA 出厂预装 P&E 调试器固件,RIOT 不支持该固件。 # 请从 NXP 官网将 OpenSDA 固件更新为最新的 CMSIS-DAP 固件。 OPENOCD_DEBUG_ADAPTER ?= dap # 引入默认 FRDM 板配置 include $(RIOTBOARD)/common/frdm/Makefile.include

注意其中的重要提示:板载 OpenSDA 调试器出厂时运行的是 P&E 调试器固件,RIOT 的烧录工具链不支持该固件,需要先将其升级为 CMSIS-DAP 固件才能配合 OpenOCD 使用。

7. 编译与烧录:OpenOCD + CMSIS-DAP

FRDM 系列的公共烧录配置位于 boards/common/frdm/Makefile.include:

# 默认使用 OpenOCD 烧录 PROGRAMMER ?= openocd # 使用共享的 OpenOCD 配置 # 使用 dap 还是 jlink 取决于 OpenSDA 调试器运行的固件 OPENOCD_DEBUG_ADAPTER ?= dap #OPENOCD_DEBUG_ADAPTER ?= jlink ifeq ($(CPU_CORE), cortex-m0plus) OPENOCD_KINETIS_FAMILY = klx else OPENOCD_KINETIS_FAMILY = kx endif OPENOCD_CONFIG ?= $(RIOTBOARD)/common/frdm/dist/openocd-$(OPENOCD_KINETIS_FAMILY).cfg # 烧录前检查 flash 配置字段 OPENOCD_PRE_FLASH_CHECK_SCRIPT = $(RIOTCPU)/$(CPU)/dist/check-fcfield.sh # 板子在运行一段时间后可能变得不可烧录, # 使用 connect_assert_srst 保证始终可以烧录或复位板子。 OPENOCD_RESET_USE_CONNECT_ASSERT_SRST ?= 1 PROGRAMMERS_SUPPORTED += openocd

FRDM-KL43Z 属于 Cortex-M0+(CPU_CORE为 cortex-m0plus),因此 OpenOCD 使用klx系列配置openocd-klx.cfg)。同时:

  • CMSIS-DAP 适配器:默认OPENOCD_DEBUG_ADAPTER = dap(对应升级后的 OpenSDA 固件);若你的 OpenSDA 刷的是 J-Link 固件,可改用jlink
  • 烧录前检查check-fcfield.sh会在烧录前校验 flash 配置字段,与board.hKINETIS_FOPT(禁用 ROM bootloader)直接相关,防止板子因配置字错误而变砖。
  • connect_assert_srst:默认开启,确保板子在异常状态下仍可被复位与重新烧录。

编译并烧录示例:

# 使用板载 OpenSDA(CMSIS-DAP)编译并烧录 make BOARD=frdm-kl43z flash # 仅编译 make BOARD=frdm-kl43z # 以 J-Link 固件模式的 OpenSDA 烧录 make BOARD=frdm-kl43z OPENOCD_DEBUG_ADAPTER=jlink flash

前提与限制:以上命令需要在已配置好的 RIOT 开发环境(含 ARM 交叉编译工具链与 OpenOCD ≥ 0.10.0)中执行;首次使用前务必完成 OpenSDA 固件的 CMSIS-DAP 升级。

8. 上手示例与进一步阅读

基于上述板级支持,一个最小应用只需在应用目录下指定BOARD=frdm-kl43z,即可自动获得串口控制台、LED 控制、A0–A3 ADC 采样与板载传感器的 SAUL 访问能力。可参考仓库内配套测试与示例:

  • 外设自测程序见 tests/periph_uart、tests/periph_adc、tests/periph_i2c、tests/periph_timer 等目录,可用于验证本文介绍的各类引脚映射;
  • SAUL 相关用法可参考 tests/saul 与 examples/saul;
  • Kinetis 系列底层时钟与外设驱动实现位于 cpu/kinetis,其中dist/check-fcfield.sh即烧录前检查脚本所在;
  • 若需定制引脚或增加外设,直接修改 boards/frdm-kl43z/include/periph_conf.h 中的*_config[]数组与*_NUMOF宏即可,改动后重新编译即生效。

【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT

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

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

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

立即咨询