开发板自动启动的LED闪烁实验
平台S3C2440A TQ2440开发板 虚拟机安装的ubuntu10.04 linux-2.6.32.60
这几天一直在思考该找工作了,自己虽然学习linux一段时间了,而且也可以写一写驱动程序,但都是编译成模块的,需要在终端加载模块再运行测试程序才行,如果能让程序自动运行的话 找工作就可以带上自己的板子,演示自己的程序给工程师看,这样把握更大,但是怎么自动启动呢?
因为是第一次尝试开机自动启动程序,我选择最简单的LED闪烁驱动,
第一步当然是编写驱动和测试程序啦,先以模块的方法是用驱动程序和测试程序都OK ,然后是如何自动启动了,驱动程序如下
驱动程序my_gpio.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#define DEVICE_NAME "LEDS"
int MAJOR;
//使用mdev机制自动创建设备节点
static struct class *led_class;
static struct device *led_class_devs;
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
static int led_open(struct inode *inode,struct file *file)
{
*gpfcon &= ~((0x3<<(5*2)) | (0x3<<(6*2)) | (0x3<<(7*2))| (0x3<<(8*2)));
*gpfcon |= ((0x1<<(5*2)) | (0x1<<(6*2)) | (0x1<<(7*2))| (0x1<<(8*2)));
return 0;
}
static ssize_t led_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
int val;
copy_from_user(&val, buf, count); // 实现用户空间到内核空间的传递
printk("valllll= %d \n",val); // copy_to_user(); 实现内核空间向用户空间传递数据,,如果完全复制成功,返回值为 0
if (val == 0)
{
// 点灯
*gpfdat &= ~((1<<5) | (1<<6) |(1<<7) |(1<<8));
printk("LED ON\n");
}
else
{
// 灭灯
*gpfdat |= ((1<<5) | (1<<6) |(1<<7) |(1<<8));
printk("LED OFF\n");
}
return 0;
}
/* 这个结构是字符设备驱动程序的核心
* 当应用程序操作设备文件时所调用的open、read、write等函数,
* 最终会调用这个结构中指定的对应函数
*/
static struct file_operations led_fops={
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_open,
.write = led_write,
};
static int __init led_init(void)
{
MAJOR = register_chrdev(0,DEVICE_NAME,&led_fops );//注册程序
//自动创建设备节点
led_class = class_create(THIS_MODULE,"led");
led_class_devs = device_create(led_class, NULL,MKDEV(MAJOR,0),NULL,"XYZ");
gpfcon = (volatile unsigned long *)ioremap(0x56000010, 16); //物理地址到虚拟地址的映射
gpfdat = gpfcon + 1;
if(MAJOR < 0)
{
printk(DEVICE_NAME "canot register major number");
return MAJOR;
}
printk(DEVICE_NAME"init yes \n");
return 0;
}
static void __exit led_exit(void)
{
unregister_chrdev(MAJOR,DEVICE_NAME); //注销程序
//注销设备节点,注销的顺序一般和注册顺序相反
device_unregister(led_class_devs);
class_destroy(led_class);
iounmap(gpfcon);//程序结束释放虚拟地址
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
测试程序Ledtest.c如下
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc,char **argv)
{
int fd ;
volatile int val;
fd = open("/dev/XYZ",O_RDWR);//系统调用open函数已经被内核处理了,在驱动程序中看不出来
if(fd < 0)
printf("can't open \n");
else
printf("open OK\n");
while(1)
{
val=1;
write(fd,&val,4);//这里第三个参数最小为sizeof(val)
sleep(5);
val=0;
write(fd,&val,4);
sleep(5);
}
return 0;
}
把写好的驱动程序移动到linux-2.6.32.60/drivers/char目录下
并修改linux-2.6.32.60/drivers/char/Kconfig添加如下
其中config MYLEDS 将在,Makefile里使用 对应里面的CONFIG_MYLEDS
"WANG ZHI GUO LEDS 对应
并修改linux-2.6.32.60/drivers/char$目录下Makefile
添加如下一行
obj-$(CONFIG_MYLEDS) += my_gpio.o
让后重新配置内核 并编译 生成zImage 下载到开发板
然后再把编译好的测试程序通过rz命令上传到开发板,我是上传到自己新建的目录 modules里,然后 vi etc/init.d/rcS 新增modules/Ledtest & 其中&使程序在后台运行,
重启开发板即可