【发布时间】:2023-08-06 11:37:01
【问题描述】:
我一直试图通过内核模块访问 beaglebone black 上的 GPIO2 和 GPIO3,但没有成功。每次我尝试将输出值分配给 GPIO 2 和 3 时,都会出现分段错误。
完全相同的代码(具有适当的引脚分配)适用于 GPIO0 和 GPIO1。
我尝试了 P8 和 P9 上与 GPIO2 和 GPIO3 相关的各种引脚,但均未成功。另一方面,相同的代码适用于 GPIO0 和 GPIO1,并具有适当的引脚分配。
对于引脚值,我使用的是官方 BBB 手册。为了获得适当的 I/O GPIO 可用性,我正在从 beagleboard.com 检查此图:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <net/tcp.h>
//Macros
#define GPIO1_START_ADDR 0x4804C000
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_END_ADDR 0x481ACFFF
#define GPIO3_START_ADDR 0x481AE000
#define SIZE (GPIO2_END_ADDR - GPIO2_START_ADDR)
#define GPIO_OE 0x134
#define GPIO_DATAOUT 0x13C
//A couple of standard descriptions
MODULE_LICENSE("GPL");
static int hello_init(void)
{
volatile void *gpio_addr;
volatile unsigned int *oe_addr;
volatile unsigned int *dataout_addr;
printk(KERN_NOTICE "Module: Initializing module\n");
printk(KERN_NOTICE "Module: Map GPIO\n");
gpio_addr = ioremap(GPIO3_START_ADDR,SIZE);
printk(KERN_NOTICE "Module: Set oe_addr\n");
oe_addr = gpio_addr + GPIO_OE;
printk(KERN_NOTICE "Module: Set dataout_addr\n");
dataout_addr = gpio_addr + GPIO_DATAOUT;
//Code will work up to here for any GPIO.
//It crashes on the following for GPIO2 and GPIO3:
printk(KERN_NOTICE "Module: Set pin to OUTPUT\n");
*oe_addr &= (0xFFFFFFFF ^ (1<<19));
printk(KERN_NOTICE "Module: Set pin output to HIGH\n");
*dataout_addr |= (1<<19);
return 0;
}
static void hello_exit(void)
{
printk(KERN_INFO "Exit module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
如果我屏蔽了这两行
*oe_addr &= (0xFFFFFFFF ^ (1<<19)); 和
*dataout_addr |= (1<<19);,该程序在所有 GPIO 上运行均无故障。
$uname -a: Linux beaglebone 3.8.13-bone79
为什么访问 GPIO2 和 GPIO3 时出现分段错误?
【问题讨论】:
-
"如果我屏蔽了这两行 [...] 程序会为所有 GPIO 运行而不会出现故障。" ... 如果你这样做了,那么 IO 不是完全访问!?此外,这不是真正的代码 -
module_init()和module_exit()在任何函数之外被“调用”,这是不可能的。如果代码不是真实的,我们怎么能相信它会显示失败? -
@Clifford 你是什么意思它不是代码?它运行。我在其中一个引脚上连接了一个 LED,当我运行它时 LED 会亮起。这就是内核模块的格式化方式。插入模块时调用 module_init(arg),移除模块时调用 module_exit(arg),其中 arg 是这些宏将指向的函数。
-
我认为(来自快速谷歌)你需要在
ioremap()之前调用request_mem_region()。 -
您的模块绝对没有任何业务试图访问“GPIO(控制)寄存器”,这些寄存器已经由引脚控制 (pinctrl) 子系统拥有。阅读有关获取和使用 GPIO 引脚的正确方法的内核文档:kernel.org/doc/Documentation/gpio “完全相同的代码(具有适当的引脚分配)适用于 GPIO0 和 GPIO1。” -- 更有可能是得到一个误报。
-
@CallMeTheMan,如果其他 GPIO 正在使用上面的代码,而只有 GPIO2 和 GPIO3 没有,这意味着时钟没有启用到 GPIO2/3 你是否检查了 CM_PER_GPIO2/3_CLKCTRL 的值.我没有找到方便的基地址数据表。在设备树中启用它应该有帮助(status="okay"),或者在 u-boot 中刚刚找到这个链接 (e2e.ti.com/support/arm/sitara_arm/f/791/t/248181)
标签: c module linux-kernel beagleboneblack