树莓派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
相关产品推荐
相关产品推荐

