arm-linux系统开发笔记2

本文介绍了一位初学者如何从零开始在Linux环境下编写LED驱动的过程。从搭建开发环境、编写驱动代码到测试验证,文章详细记录了每一步的操作及遇到的问题解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

板子跑起来以后,迫切的愿望就是操作板子上的东西,可是一看代码里全是linux的内容,都不知道从哪下手后来在网上搜资料,发帖子,折腾了好几天,终于能写一个led的程序了(好像不管玩什么板子,点亮led灯程序都是第一个实验的)

首先,需要知道的是,怎么样写驱动,linux系统中的驱动编写好像挺复杂,都是用模块来表示的,并不像其他芯片那样可以直接写,他需要先建一个驱动的模块文件(也就是写个驱动的C文件,然后把这个C文件做成模块,具体怎么做在下面代码里有),然后用的时候都是open这个文件,然后调用里面的函数(好吧,听着也不是那么复杂,可是开始不知道的时候确实花了我很长时间才懂)

我的linux工程文件夹有apps,kernel文件夹等,因为想让工程比较有条理性,开始的时候我把driver_led.c(即led驱动)放在apps下,新建了一个文件夹,然后发现有一堆问题,什么Makefile不对,头文件找不到,等等等等,后来觉得还是跟其他的驱动放在一起吧,直接和其他的驱动放在相同文件夹下,仿照其他驱动的写法,只需要在对应的Makefile里添上自己的驱动文件就好了(我放的位置是kernel/linux-2.6.30/driver/gpio/)


driver_led.c文件

#include <linux/module.h>  //这一堆头文件是我从网上的例子上搬下来的,好像有一些也没用
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <asm/uaccess.h> 
#include <linux/miscdevice.h>    
#include <linux/pci.h>    
#include <mach/map.h>    
#include <plat/regs-gpio.h>    
#include <plat/gpio-bank-m.h>    
#include <plat/gpio-cfg.h>  


#define LED_MAJOR 240  //这个是后面要创建一个my_led模块用到的主设备号(具体是不是这么叫,我也不确定,反正就是这么个意思了,可以上网查查)
//执行到这个文件时,首先执行的是init()函数(在下面),接着好像就是open()了,这里就是初始化引脚的功能
int led_open (struct inode *inode,struct file *filp)  
{  
unsigned tmp;     

tmp = readl(S3C64XX_GPMCON);     //好像所有的6410的例子都是PM脚,可能是大家的板子都是那几个引脚是输出吧
tmp = (tmp & ~(0xffeeee))|(0x001111U);    
writel(tmp, S3C64XX_GPMCON); 


tmp = readl(S3C64XX_GPMDAT);     
tmp |= (0x0fU);    
writel(tmp, S3C64XX_GPMDAT);

tmp = readl(S3C64XX_GPPCON);     //好像所有的6410的例子都是PM脚,可能是大家的板子都是那几个引脚是输出吧
tmp &= (~0xfU);    
writel(tmp, S3C64XX_GPPCON); 


printf("#########open######\n");  
return 0;  
}  
  
ssize_t led_read (struct file *filp, char __user *buf, unsigned long count,loff_t *f_pos)  

unsigned long tmp;
char wbuf[10];
copy_from_user(wbuf,buf,count);
switch(wbuf[0])
{
case 0:
tmp = readl(S3C64XX_GPPDAT); //这里我用了PP0作为输入,也就是想控制PP0为1时,PM为1,PP0为0时,PM为0
break;
default :  
break;  
}
printk("#########read######\n");  
return tmp;  
}  


ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)  
{  
char wbuf[10];  
unsigned tmp;     
printk("#########write######\n");  
copy_from_user(wbuf,buf,count);//拷贝country个buf数组的值给wbuf

switch(wbuf[0])  
{  
case 0:  
tmp = readl(S3C64XX_GPPDAT);     
tmp &= (~0x0f);//PM0~3 = 0     
writel(tmp, S3C64XX_GPPDAT);  
break;  
case 1:  
tmp = readl(S3C64XX_GPPDAT);     
tmp
|= 0x0f;//PM0~3 = 1    
writel(tmp, S3C64XX_GPPDAT);  

break; 
default:
break;
}  
return count;  
}  
 //这个具体干嘛的还没研究,看所有的例程上都有,就放着了,以后我会添点东西看看到底其什么作用 
int led_release (struct inode *inode, struct file *filp)  
{  
printk("#########release######\n");  
return 0;  
}  
//这个结构体的具体意思我也是在网上查了很久才大概知道什么意思,反正只要理解成几个函数就行了,我这边看网上的例子后知道:在外面调用open函数,就会操作这个驱

//动文件里的led_open函数,大体上就是这个意思。    
struct file_operations led_fops ={  
.owner = THIS_MODULE,  
.open = led_open,  
.read = led_read,  
.write = led_write,  
.release = led_release,  
};  
//在这里初始化该驱动,我在里面用函数控制在系统初始化的时候就把这个模块加载上去,不然还用手动加载  

//里面的函数刚开始用,如果有什么不对的请大家指出来哈
int __init led_init (void)  
{   
int rc;  
printk ("Test led dev\n");  
//驱动字符加载函数 LED_MAJOR:主设备号 ,led设备名 led_fops:包含基 本函数入口点的结构体
rc = register_chrdev(LED_MAJOR,"led",&led_fops);  
if (rc <0)  
{  
printk ("register %s char dev error\n","led");  
return -1;  
}
simple_class= class_create(THIS_MODULE, "my_led");  
if(IS_ERR(simple_class)) 
{  
printk("ERR:cannot create a simple_class");  
return -1;  
}  
device_create(simple_class,NULL, MKDEV(LED_MAJOR, 0), 0, "my_led");    
printk ("ok!\n");  
return 0;  
}  
  //这个当然就是退出了
void __exit led_exit (void)  
{  
unregister_chrdev(LED_MAJOR,"led");  
printk ("module exit\n");   
}  
  
module_init(led_init);  //装载驱动后第一个执行的就是该函数
module_exit(led_exit);  


这些完成后,在个gpio文件夹下的Makefile里添加一句话:

obj-$(CONFIG_GPIO_DRIVER_LED) += driver_led.o

在Kconfig里添加以下内容:

menu "LED Support" 
config GPIO_DRIVER_LED
bool "LED Support" 

---help---
If you want LED Support, you should say Y here and also to the
specific driver for your bus adapter(s) below.
This LED Support can  be built as a module.
endmenu

这样make的时候就会提示是否加载led驱动了

把生成的image到板子里以后,secureCRT软件里,#cd dev/,应该就会出现一个my_led的文件了(这个是后话,在这之前还要建立一个测试的C文件,毕竟写驱动就是为了用嘛)


ledtest.c文件  这个文件我是放在apps里的,没有内核的头文件,不会有头文件编译不过的问题,所以就放这里了。

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
int main (void)  
{  
int fd;  
unsigned tmp;
char buf[10]={0,1};  
fd = open("/dev/my_led",O_RDWR);  //打开my_led文件 O_RDWR表示可读可写
if (fd < 0)  
{  
printf ("Open /dev/my_led file error\n");  
return -1;  
}     
while(1)  
{  
tmp = read(fd,&buf[0],1);//PP10引脚  这里的read()函数实际就是调用的led_read()函数了,对应上面driver_led.c里的结构体

if(((tmp>>0)&0x01) == 0)//如果PP0为0
{
write(fd,&buf[0],2);//P0~3 =0//好简单的功能。。。。
}
else if (((tmp>>0)&0x01) == 1)//如果PP10的引脚为1

{
write(fd,&buf[1],1);//P0~3 =01

}
}  
close (fd);  
return 0;  
}

下面是ledtest.c的Makefile文件(Makefile文件还是没研究透,只能依样画葫芦了,参考别的写的,Makefile文件里每一行开头的缩进都是tab键而不是空格键!!!!!!!!!!!!!!!!!!!!!!!!!!!)

include ../../Rule.mk
CFLAGS += -Os -Wall -s 


#INCLUDES = -I. -I../bcmutils -I. -I../nvram
#LIBS= -L../bcmutils -lbcmutils -L../nvram -lnvram


BIN = gpio_main


OBJS  = gpio_main.o


all: $(BIN)


$(BIN):$(OBJS)
$(CC)  $(CFLAGS) $(OBJS) $(LIBS) -o  $@ 

%.o: %.c
$(CC) $(CFLAGS) $(INCLUDES) -c $<

install:
cp -a led_main ../../target/usr/sbin


clean:
rm -f led_main *.o


这下就可以生成Image文件了。

烧录以后,执行下面的命令:

#cd usr/

#cd sbin/

#./ledtest

就可以操作引脚了,当然,这里需要自己在硬件上把PP0做成输入,有个按键是最好的了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值