You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4内核驱动生成1MHz GPIO时钟不稳定及模块加载异常问题

树莓派4内核驱动GPIO时钟问题排查

问题1:1MHz GPIO时钟偶尔卡顿

我在树莓派4上通过Linux内核驱动控制GPIO21生成稳定1MHz时钟,用逻辑分析仪检测时发现时钟偶尔卡顿,疑似内核线程被抢占,其余时段正常。测试时已将CPU模式设为performance,cntfrq_el0始终保持54MHz。

所用内核模块代码

#include <linux/module.h>       /* Needed by all modules */
#include <linux/kernel.h>       /* Needed for KERN_INFO */
#include <linux/init.h>         /* Needed for the macros */
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#define GPIO_26 21

static int __init hello_start(void)
{
    unsigned i;
    u64 freq, base_clock, current_clock, target_elapsed;

    printk(KERN_INFO "Loading hello module...\n");
    if (!gpio_is_valid(GPIO_26)) {
        printk(KERN_INFO "GPIO_26 is not valid\n");
        return -1;         
    }
    // 原代码存在逻辑误判:gpio_request返回负值表示错误,此处判断等于0则返回错误
    if (!gpio_request(GPIO_26,"GPIO_26")) {
        printk(KERN_INFO "GPIO_26 cannot be requested\n");
        return -1;         
    }
    gpio_direction_output(GPIO_26, 0);

    asm volatile ("isb; mrs %0, cntfrq_el0" : "=r" (freq));
    printk(KERN_INFO "freq = %llu\n", freq);
    freq *= 1;
    freq /= 1000000;
    
    local_bh_disable();
    local_irq_disable();
    target_elapsed = 0;
    asm volatile ("isb; mrs %0, cntvct_el0" : "=r" (base_clock));
    for(i = 0; i < 500000; ++i) {
        target_elapsed += freq;
        while(true) {
            asm volatile ("isb; mrs %0, cntvct_el0" : "=r" (current_clock));
            if (current_clock-base_clock >= target_elapsed)
                break;
        }
        gpio_set_value(GPIO_26, i & 1);
    }
    local_irq_enable();
    local_bh_enable();

    gpio_free(GPIO_26);
    printk(KERN_INFO "Hello world\n");
    return 0;
}

static void __exit hello_end(void)
{
}

module_init(hello_start);
module_exit(hello_end);

MODULE_LICENSE("GPL");

已完成的排查操作

2023年6月1日补充

  • 修正了gpio_request()的错误判断逻辑:原代码将返回0(成功)误判为失败,现已明确返回负值才表示错误。
  • 替换为gpiod_*系列函数,未解决卡顿问题。
  • 直接通过ioremap()映射GPIO基地址0xfe200000(从/proc/iomem获取),手动控制引脚输出(尝试过ioremap_np()、直接内存赋值、iowrite32()、writel()等方式),卡顿现象依旧。
  • 实测CNTPCT_EL0与CNTVCT_EL0计数无差异,未发现二者存在偏移,且CNTVCTSS_EL0寄存器不存在。
  • 运行期间CNTFRQ_EL0始终稳定在54MHz。
  • 计数器测量显示时序理论上完全稳定:25000个时钟周期(50000次电平变化)内,GPIO写入操作后的时钟值与上一次的差值为540(49999次)或541(仅1次),但逻辑分析仪仍能检测到卡顿。
  • 该时钟用于Commodore 64的SID/VIC芯片仿真,时序问题阻碍项目推进。

2023年6月3日补充

  • 参考"sloppy GPIO logic analyzer"项目代码添加preempt_disable_notrace()调用,无改善。
  • 确认逻辑分析仪无故障:微控制器生成的稳定时钟被树莓派4捕获时出现不稳定时间戳,问题根源在树莓派4侧,疑似抢占机制未完全禁用。
  • 尝试在自旋锁内运行时钟生成代码,验证local_irq_disable()的有效性,无变化。

提问:该卡顿现象的原因是什么?是否可通过禁用某些机制修复?


问题2:GPIO请求循环失败

首次加载模块时gpio_request()调用失败,模块被卸载;第二次执行insmod成功;执行rmmod卸载后再次insmod又失败,如此循环往复。

提问:该循环失败的原因是什么?


内容的提问来源于stack exchange,提问作者NoiseEHC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 10:37:53