第 6 章:GPIO 与外部中断——M33 掌控下的 LED 与按键响应

在之前的章节中,我们已经打通了串口和 I2C。现在,我们要深入探讨异构多核架构中最基础也最关键的部分:GPIO 的所有权与中断抢占

在 STM32MP257F-DK 上,有些引脚是"跨界"的。如果 Linux(A35)和裸机(M33)同时尝试操作同一个 GPIO 组,系统会发生不可预知的冲突。本章我们将通过 RIFEXTI,让 M33 建立一个独立于 Linux 之外的硬实时控制环路。


6.1 硬件资源分配方案

在我们的实战项目中,分配如下:

  • LED 控制:GPIOZ 端口。在 MP257 中,GPIOZ 通常被视为"安全域"外设,由 M33 优先接管。

  • 用户按键:USER1 Button,连接到特定的 GPIO 引脚。

  • 目标:实现按键触发外部中断,M33 立即翻转 LED 状态。即便 A35 侧 Linux 内核正在启动或发生阻塞,这个动作也必须是毫秒级响应。


6.2 实战:RIF 锁定 GPIO 控制权

在 MP257 中,GPIO 的访问受 RISCF 保护。我们必须在 main 初始化阶段声明对 GPIOZ 的所有权。

void RIF_GPIO_Config(void) {

// 启用 GPIOZ 始终

__HAL_RCC_GPIOZ_CLK_ENABLE();

/* 配置 RIF:将 GPIOZ 分配给 CID1 (M33)

MP257 的 GPIO 分组非常细致,我们必须确保 M33 拥有写权限

*/

RIF_RISCF_GPIOZ->CIDCFGR = (1 << RIF_RISCF_CIDCFGR_SCID_Pos) | RIF_RISCF_CIDCFGR_CONF;

RIF_RISCF_GPIOZ->PRIVCFGR = RIF_RISCF_PRIVCFGR_PRIV;

}

6.3 GPIO 与 LED 初始化

我们将 GPIOZ 的第 1 针(假设连接到板载 LED)配置为推挽输出。

void LED_Init(void) {

GPIO_InitTypeDef GPIO_InitStruct = {0};

GPIO_InitStruct.Pin = GPIO_PIN_1;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(GPIOZ, &GPIO_InitStruct);

// 初始状态熄灭

HAL_GPIO_WritePin(GPIOZ, GPIO_PIN_1, GPIO_PIN_RESET);

}

6.4 深度实战:外部中断 (EXTI) 配置

MP257 的中断控制器与标准 STM32 略有不同,它需要处理多核中断路由。我们要确保按键中断(假设在 GPIOG)路由到 M33 的 NVIC。

void Button_Interrupt_Init(void) {

GPIO_InitTypeDef GPIO_InitStruct = {0};

// 配置引脚为下降沿触发中断

GPIO_InitStruct.Pin = GPIO_PIN_0; // 假设 User 按键在 PG0

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

GPIO_InitStruct.Pull = GPIO_PULLUP;

HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

// 设置 NVIC 优先级并开启中断

// 注意:M33 的优先级要高于后面 A35 通讯的优先级

HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);

HAL_NVIC_EnableIRQ(EXTI0_IRQn);

}

6.5 中断服务函数 (ISR) 与消抖逻辑

在异构实时开发中,我们严禁 在中断里使用 HAL_Delay()。为了实战性能,我们使用简单的标志位或时间戳对比。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {

static uint32_t last_tick = 0;

uint32_t current_tick = HAL_GetTick();

if (GPIO_Pin == GPIO_PIN_0) {

// 简易软件消抖:200ms 内只触发一次

if (current_tick - last_tick > 200) {

HAL_GPIO_TogglePin(GPIOZ, GPIO_PIN_1); // 翻转 LED

printf("Button Pressed! M33 Response Time: < 1ms\r\n");

last_tick = current_tick;

}

}

}

6.6 多核避坑指南:GPIO 冲突的代价

如果此时 A35 侧的 Linux 也尝试加载一个控制所有 GPIO 的驱动,会发生什么?

  1. 访问拒绝 :如果 RIF 配置成功,A35 尝试写入 GPIOZ 寄存器时会触发一个 System Error 或被硬件静默忽略。

  2. 时钟被关:如果 Linux 认为 GPIOZ 没用,由于功耗管理机制,它可能会关闭 GPIOZ 的时钟。

    • 对策:在 M33 侧通过 RIF 将时钟控制器(RCC)的相关外设位也设为 M33 独占,或者在 Linux 设备树中明确标注该时钟由安全域管理。

6.7 章节小结

通过本章,我们完成了一个具备基本交互能力的实时系统:

  • 输入:用户按键(外部中断)。

  • 处理:M33 逻辑判断(消抖与状态翻转)。

  • 输出:LED 状态指示。

这虽然看起来简单,但由于它运行在 RIF 保护下的 M33 核心,这保证了无论 Linux 侧如何"折腾"(例如内核 panic 或进行大数据拷贝导致的总线拥塞),LED 的响应永远是确定性的。

相关推荐
闲人编程2 小时前
任务监控与错误重试
linux·服务器·网络·celery·任务队列·任务监控·错误重试
LCG元3 小时前
直流电机闭环控制:STM32F1 PWM+ADC电流采集,PID调速实战
stm32·单片机·嵌入式硬件
Y1rong4 小时前
STM32之MQTT
stm32
REDcker4 小时前
FTP协议原理及应用精解
linux·后端·计算机网络·互联网·ftp·服务端开发
Zeku4 小时前
TCP交错传输多通道实现原理
stm32·freertos·linux应用开发
@syh.5 小时前
【linux】进程信号
linux
funnycoffee1235 小时前
Linux查看版本号命令cat /etc/os-release
linux·服务器
z20348315206 小时前
如何使用Micropython进行单片机开发(一)
单片机·嵌入式硬件·micropython
xiaoliuliu123456 小时前
Kylin V10 安装 compat-gcc-44-4.4.7-8.el7.x86_64.rpm 详细步骤
linux·运维·服务器