exynos 4412 LED字符设备驱动测试(随笔)

LED驱动代码以及原理图

实验的目的:验证gpio的虚拟地址。
实验现象:在开发板加载模块时候,LED亮;卸载模块,LED灭

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>

#include <plat/map-base.h>
#include <plat/map-s5p.h>

#define MYMAJOR 0
#define NAME	"MyModule"

//LED接在GPL2的第0管脚
#define GPL2CON	((volatile unsigned int *)(S5P_VA_GPIO2 + 0x100))
#define GPL2DAT ((volatile unsigned int *)(S5P_VA_GPIO2 + 0x104))

#define rGPL2CON (*GPL2CON)
#define rGPL2DAT (*GPL2DAT)

int major;

static int module_open(struct inode *inode, struct file *file)
{
	printk("module_open\n");
	return 0;
}

static ssize_t module_write(struct file *file,
	const char __user *user_buf,
	size_t count, loff_t *ppos)
{
	printk("module_write\n");
	return 0;
}

static ssize_t module_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	printk("module_read\n");	
	return 0;
}

static int module_release(struct inode *inode, struct file *file)
{
	printk("module_release\n");
	return 0;
}

static const struct file_operations fops = {
	.open = module_open,
	.write = module_write,
	.read = module_read,
	.release = module_release,
	.owner = THIS_MODULE,
};

static int __init module_test(void)
{
	//int ret;
	printk(KERN_DEBUG "install module_test");
	major = register_chrdev(MYMAJOR, NAME, &fops);
	if (major < 0) 
	{
		printk(KERN_ERR "register_chrdev failed\n");
		return -EINVAL;
	}
	printk("module_test major: %d\n",major);
	
	//用来测试LED驱动
	rGPL2CON = 0X11111111;
	rGPL2DAT = (1 << 0);

	printk("GPL2CON:%p\n", GPL2CON);
	printk("GPL2DAT:%p\n", GPL2DAT);
	return 0;
}

static void __exit module_ex(void)
{
	unregister_chrdev(major, NAME);
	printk(KERN_DEBUG "uninstall module_test");
	rGPL2DAT = (0 << 0);
}


module_init(module_test);
module_exit(module_ex);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zhou");

在这里插入图片描述
在这里插入图片描述

(1)exynos4412相关的虚拟地址包含哪些文件?

  • map-base.h:定义了虚拟地址的基地址,#define S3C_ADDR_BASE 0xF6000000这个是所有虚拟地址的基地址,然后各个模块的基地址=S3C_ADDR_BASE + 偏移量。
  • gpio-exynos4.h: gpio相关的虚拟映射表,表中定义各个IO口的地址。
    比如:#define EXYNOS4_GPL0(_nr) (EXYNOS4_GPIO_L0_START + (_nr)),我们调用内核的提供的API, 就能实现对GPIO的操作。
	s3c_gpio_cfgpin(EXYNOS4_GPL2(0), S3C_GPIO_OUTPUT);		//将管脚设置为输出
	gpio_set_value(EXYNOS4_GPL2(0), 1);						//置1
	gpio_set_value(EXYNOS4_GPL2(0), 0);						//置0
  • gpio-exynos4.c: 这个文件定义了类似标签的结构体,用来描述 GPIO虚拟地址的一些信息,比如,给它们一个名字,保持它们的基地址和偏移量等等。
    我先截取一小部分出来,这个是实验用到的端口。我们只需知道GPL2的基地址是 S5P_VA_GPIO2 + 0x100,实验中点亮LED,是通过它寄存器的虚拟地址来操作。当然,也可以用内核提供号的API来操作。只不过,当你要点亮多盏LED灯时候,直接操作寄存器,还是挺方便的。
 	{
		.base   = (S5P_VA_GPIO2 + 0x100),
		.eint_offset = 0x20,
		.group	= 22,
		.chip	= {
			.base	= EXYNOS4_GPL2(0),
			.ngpio	= EXYNOS4_GPIO_L2_NR,
			.label	= "GPL2",
		}
	}

(2)怎么对GPIO的虚拟寄存器进行操作?

  • 第一步:需要将一串数字,变成一个指针变量,也就是真正的变成一个地址。接着,对地址取 * 就能对这个地址的内容进行读写。此处,我将它们封装为一个宏。
#define GPL2CON	((volatile unsigned int *)(S5P_VA_GPIO2 + 0x100))
#define GPL2DAT ((volatile unsigned int *)(S5P_VA_GPIO2 + 0x104))
#define rGPL2CON (*GPL2CON)
#define rGPL2DAT (*GPL2DAT)

  • 第二步: 配置端口。rGPL2CON = 0X11111111; 将GPL2的0-7管脚配置成输出状态,你也可以根据需求来配置。具体可查看数据手册的第243页。
  • 第三步:写入数据。rGPL2DAT = (1 << 0);点亮GPL2(0)的LED灯。

(3)为什么GPL2DAT的偏移量比GPL2CON的多出 0x04?

在这里插入图片描述
从文档上可知,它们的偏移量相差是0X04.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值