4. EFR32 GPIO、中断与定时器开发

EFR32 的外设开发有一个显著特点:芯片内部的外设数量多、复用关系复杂,但 Silicon Labs 提供的 Simplicity Configurator(在 Simplicity Studio 中通常以 .isc 配置文件形式存在)可以把引脚分配、时钟树、外设参数和初始化代码生成统一起来。本节围绕 GPIO、外部中断、USART、I2C、SPI、ADC、DAC、定时器/PWM 和 RTC 这几类常用外设,说明如何借助配置器生成初始化代码,并在应用层完成驱动开发。

4.1 从引脚与外设映射开始

EFR32 的每个 GPIO 都可以被多个外设复用,例如 USART0 的 TX/RX 可以映射到 PA0/PA1,也可以映射到 PB7/PB8 等。配置器中的第一步不是写代码,而是确定“哪个外设用哪组引脚”。这一步决定了后续初始化代码中的 GPIO_PinModeSet、GPIO_ExtIntConfig 以及外设初始化函数的参数。

以 EFR32MG21 为例,假设我们要实现一个带按键、LED、串口调试、I2C 传感器和 PWM 调光的节点,可以按如下方式分配:

  • LED:PA4,推挽输出,初始低电平;
  • 按键:PB0,输入上拉,下降沿触发外部中断;
  • USART0:PA0 为 TX,PA1 为 RX,波特率 115200;
  • I2C0:PA2 为 SDA,PA3 为 SCL,速率 100 kHz;
  • PWM:TIMER0 通道 0 输出到 PA5,频率 1 kHz;
  • ADC:AIN0 接 PA6,用于采集电位器电压。

在 Simplicity Configurator 中,这些分配会直接反映到生成的 init_mcu.c、init_board.c 和 init_app.c 中。配置器生成的代码通常包含 CMU_ClockEnable、GPIO_PinModeSet、USART_InitAsync、I2C_Init、TIMER_Init 等调用,开发者不需要手写底层时钟使能和引脚复用寄存器。

4.2 GPIO 输入输出与外部中断

GPIO 输出最简单,但要注意驱动能力和初始状态。例如 LED 接 PA4,配置为推挽输出,初始输出低电平,则点亮时调用 GPIO_PinOutSet(gpioPortA, 4),熄灭时调用 GPIO_PinOutClear(gpioPortA, 4)。如果 LED 是低电平点亮,则逻辑相反,配置时初始输出高电平即可。

按键输入需要处理抖动和中断。配置器中将 PB0 设为输入上拉,并启用外部中断,触发方式选择下降沿。生成的初始化代码会包含类似:

GPIO_PinModeSet(gpioPortB, 0, gpioModeInputPull, 1);
GPIO_ExtIntConfig(gpioPortB, 0, 0, false, true, true);
NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
NVIC_EnableIRQ(GPIO_EVEN_IRQn);

在中断服务函数中,应先清除中断标志,再处理按键事件。由于机械按键存在抖动,实际工程中通常不在中断里直接执行复杂逻辑,而是置位一个标志或发送事件到主循环,由主循环做 20 ms 消抖确认。

4.3 串行通信:USART、I2C 与 SPI

USART 常用于调试输出和与模组通信。配置器中设置波特率 115200、8 数据位、1 停止位、无校验,生成 USART_InitAsync 后,发送字符串可以调用 USART_Tx 或使用 printf 重定向。接收侧如果使用中断,需要使能 USART0_RX_IRQn,在中断中读取 USART0->RXDATA 并存入环形缓冲区。

I2C 用于连接传感器,例如 BME280 或 SHT30。配置器中选择 I2C0,设置 SDA/SCL 引脚和 100 kHz 速率,生成 I2C_Init。应用层通过 I2C_TransferSeq_TypeDef 构造读/写序列,调用 I2C_TransferInit 和 I2C_Transfer 完成一次传输。注意 I2C 从机地址通常为 7 位,配置器中的地址字段需要左移一位或按库函数要求填写。

SPI 用于高速外设,如外部 Flash 或显示屏。配置器中选择 SPI0,设置主模式、时钟极性/相位、位速率和片选引脚。生成代码后,使用 SPI_Transfer 或 SPI_Write 发送数据。SPI 没有应答机制,片选时序必须由软件或硬件正确控制。

4.4 ADC、DAC 与定时器/PWM

ADC 用于采集模拟量。配置器中选择 ADC0,设置参考电压、分辨率和输入通道。例如采集 PA6 上的电位器电压,选择 12 位分辨率、内部 1.25 V 参考,则满量程对应 4095。调用 ADC_Init 后,通过 ADC_Start 和 ADC_PollForConversion 获取结果,再按 V = code / 4095 * 1.25 换算电压。

DAC 用于输出模拟电压,EFR32 部分型号支持 12 位 DAC。配置器中使能 DAC0,选择输出引脚,设置参考电压。应用层调用 DAC_Enable 和 DAC_Output 即可输出指定码值。

定时器和 PWM 是控制周期与占空比的核心。配置器中选择 TIMER0,设置频率 1 kHz、通道 0 为 PWM 输出。生成代码后,使用 TIMER_Init、TIMER_CompareSet 和 TIMER_Cmd 启动。占空比通过比较值调整,例如周期为 1000 计数,比较值为 300 时占空比约 30%。

4.5 RTC 与低功耗时间基准

RTC 通常使用 32.768 kHz 低频晶振,用于秒级计时和低功耗唤醒。配置器中使能 RTC,选择 LFXO 作为时钟源,设置预分频和比较值。例如要产生 1 秒中断,预分频设为 32768,比较值设为 1,则每秒触发一次 RTC_IRQHandler。在中断中更新系统时间戳或唤醒主循环。

需要注意的是,RTC 配置与低功耗模式密切相关。如果使用 EM2 深度睡眠,RTC 是少数可以继续运行的外设之一,但必须确保时钟源和电源域配置正确。

EFR32 外设配置与初始化代码生成关系图 Simplicity Configurator .isc 配置文件 引脚分配 / 复用 时钟树 / 参考源 外设参数 中断优先级 低功耗模式 生成文件 init_mcu.c init_board.c init_app.c 外设驱动与初始化代码 GPIO / 外部中断 GPIO_PinModeSet / GPIO_ExtIntConfig PA4 LED / PB0 按键 USART USART_InitAsync / USART_Tx PA0 TX / PA1 RX 115200 I2C I2C_Init / I2C_Transfer PA2 SDA / PA3 SCL 100 kHz SPI SPI_Init / SPI_Transfer 主模式 / 片选控制 ADC ADC_Init / ADC_Start PA6 AIN0 / 12 位 / 1.25 V DAC DAC_Enable / DAC_Output 12 位模拟输出 TIMER / PWM TIMER_Init / TIMER_CompareSet PA5 / 1 kHz / 占空比可调 RTC RTC_Init / RTC_CompareSet LFXO 32.768 kHz / 1 s 中断 配置器生成初始化代码 → 应用层调用驱动 API → 中断/轮询处理数据

4.6 配置器生成代码后的应用层组织

配置器生成的初始化代码通常放在 init_mcu()、init_board() 和 init_app() 中,主函数只需依次调用它们,然后进入应用主循环。应用层不建议直接修改生成文件,而应在单独的 app.c 中封装业务逻辑,例如按键事件处理、传感器读取、PWM 调光和串口命令解析。

一个常见的组织方式是:初始化完成后,主循环轮询按键标志、读取 ADC 值、更新 PWM 占空比,并通过 USART 输出调试信息。中断服务函数只做最小必要操作,例如清除标志、写入缓冲区或置位事件标志。这样既利用了配置器生成的底层初始化,又保持了应用代码的可维护性。

配置器中的引脚分配一旦确定,应同步更新原理图和 PCB 网络表。如果后期修改引脚,必须重新生成初始化代码,并检查所有依赖该引脚的驱动是否仍然一致。
EFR32 的部分外设共享时钟和中断向量。例如 USART0 和 TIMER0 可能共用同一时钟分支,修改时钟树时需确认不会影响已使能的外设。中断优先级也应在配置器中统一规划,避免高优先级中断阻塞低优先级通信。

通过 Simplicity Configurator 完成引脚、时钟和外设参数配置后,开发者可以把精力集中在应用逻辑和数据处理上。GPIO、中断、USART、I2C、SPI、ADC、DAC、定时器/PWM 和 RTC 的初始化代码由工具生成,应用层只需按外设 API 完成读写、转换和事件响应,从而加快 EFR32 无线物联网产品的开发与量产验证。