第一、二期衔接——3.3 字符驱动设备—LED设备驱动点灯

LED设备驱动点灯

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发手册》
  • 开发环境:Linux 2.6.22.6 内核、arm-linux-gcc-3.4.5-glibc-2.3.6工具链

目录

  • LED设备驱动点灯
    • 一、硬件原理
    • 二、芯片手册
    • 三、驱动编写
      • 1、首先建立一个指针变量,用来给后面的地址映射
      • 2、完成映射
      • 3、取消映射
      • 4、硬件代码(直接贴全部代码)
      • 4、具体实验效果


一、硬件原理

第一、二期衔接——3.3 字符驱动设备—LED设备驱动点灯_第1张图片

二、芯片手册

第一、二期衔接——3.3 字符驱动设备—LED设备驱动点灯_第2张图片
上述条件,是为了下面的硬件操作准备的。

三、驱动编写

在裸板开发的时候,我们操作的是物理地址,而通过加载驱动的方式操作硬件时,我们操作的是虚拟地址。

  • 提问:虚拟地址和物理地址之间是如何建立联系的呢?
  • 回答:通过ioremap()函数。
  • 原型:#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr))

1、首先建立一个指针变量,用来给后面的地址映射

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;

2、完成映射

*gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
*gpfdat = gpfcon + 1;

3、取消映射

iounmap(gpfcon);

4、硬件代码(直接贴全部代码)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static struct class *firstdrv_class;
static struct class_device	*firstdrv_class_dev;

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;


static int first_drv_open(struct inode *inode, struct file *file)
{
	//printk("first_drv_open\n");
	/* 配置GPF4,5,6为输出 */
	*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
	*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
	return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	int val;

	//printk("first_drv_write\n");

	copy_from_user(&val, buf, count); //从用户空间拷贝数据到内核空间

	if (val == 1)
	{
		// 点灯
		*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
	}
	else
	{
		// 灭灯
		*gpfdat |= (1<<4) | (1<<5) | (1<<6);
	}
	
	return 0;
}

static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     
	.write	=	first_drv_write,	   
};


int major;
static int first_drv_init(void)
{
	major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核

	firstdrv_class = class_create(THIS_MODULE, "firstdrv");

	firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
	gpfdat = gpfcon + 1;

	return 0;
}

static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv"); // 卸载

	class_device_unregister(firstdrv_class_dev);
	class_destroy(firstdrv_class);
	iounmap(gpfcon);
}

module_init(first_drv_init);
module_exit(first_drv_exit);


MODULE_LICENSE("GPL");

4、具体实验效果

第一、二期衔接——3.3 字符驱动设备—LED设备驱动点灯_第3张图片
通过如下的指令,可以控制LED灯的亮灭。

你可能感兴趣的:(嵌入式Linux第一,二阶段衔接,内核,嵌入式,linux)