电子科技大学
目录
课程名称 微处理器与嵌入式系统
实验名称 :Linux驱动程序开发
1.掌握Linux系统下设备驱动程序的作用与编写技巧
2.掌握Linux驱动程序模块加载和卸载的方法
3.了解串口驱动的原理和工作方式
4.了解串口驱动的原理和工作方式
1基于ARM的模块方式驱动程序实验2基于ARM的串口驱动实验
Led驱动
1.在vivado里搭建好硬件工程,包括:led、sw和uart模块。(详见实验2)
2.搭建好后生成比特流文件,利用SDK软件将fsbl文件、比特流文件、u-boot文件生成boot.bin启动文件。(详见实验2)
3.在driver_code/led目录下找到ees331_led.c源文件,双击打开源文件,也可以通过终端命令gedit 打开:
编写led驱动源代码,修改三个部分:
1)添加led的地址:
/* Modify the address to your peripheral */
#define ees331_led_PHY_ADDR
/* Modify the address to your peripheral */
led驱动的初始化函数为如下:
int __init ees331_led_init(void)
{
int ret;
GPIO_Regs = ioremap(ees331_led_PHY_ADDR, 32);
ret = misc_register(&ees331_led_dev);
if (ret)
{
printk("ees331_led:[ERROR] Misc device register failed\n");
return ret;
},
printk("ees331_led: success! Module init complete\n");
iowrite32(255, GPIO_Regs);
return 0; /* Success */
}
2)添加控制函数的代码,如下:
static int ees331_led_ioctl(struct file *filp, unsigned int reg_num, unsigned long arg)
{
/* Add your code here */
//通过led地址给led寄存器赋值
/* Add your code here */
return 0;
}
3)在驱动的文件操作结构体添加代码,如下
static const struct file_operations ees331_led_fops =
{
.owner = THIS_MODULE,
/* Add your code here */
.open =,
.release =,
.read =,
.unlocked_ioctl =,
/* Add your code here */
};
4.打开Makefile 文件,修改其中部分,加入交叉编译器和内核源码树目录,如下。
ifneq ($(KERNELRELEASE),)
obj-m := ees331_led.o
else
ifeq ($(TARGET),)
TARGET := $(shell uname -r)
endif
PWD := $(shell pwd)
/* Add your code here */
CC =
KDIR ?=
/* Add your code here */
default:
@echo $(TARGET) > module.target
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
@rm -f *.ko *.o modules.order Module.symvers *.mod.? .ees331_led*.* *~
@rm -rf .tmp_versions module.target
install: ees331_led.ko
install --mode 0644 ees331_led.ko /lib/modules/$(shell cat module.target)/kernel/drivers/char/
/sbin/depmod -a $(shell cat module.target)
ees331_led.ko:
$(MAKE)
endif
在需要添加部分加入交叉编译器和内核源码树目录$(CROSS_COMPILE)gcc、/home/zynq/Downloads/2016.3/linux-xlnx-xilinx-v2016.3
5.虚拟机中打开一个终端,在led目录下执行make命令,生成.ko驱动模块文件。
make
6.将测试文件ledtest.c进行交叉编译,(或者在开发板上执行gcc命令),生成可执行文件ledtest。
arm-linux-gnueabihf-gcc ledtest.c -o ledtest
7.在win7系统里打开putty软件,选择对应的com口,波特率选择为115200。
8.putty的窗口里,进入到arm-linux系统里,将ees331_led.ko和 ledtest文件拷贝到SD卡根文件系统的root目录下。
scp zynq@192.168.1.12:/home/zynq/driver_code/led/ledtest /root
scp zynq@192.168.1.12:/home/zynq/driver_code/led/ees331_led.ko /root
9.putty的窗口里,在/root(~)目录下执行insmod 命令,将驱动模块动态加载到内核中。
insmod ees331_led.ko
驱动加载成功后,在/dev/目录中用ls命令可以查看到相应的设备。
ls /dev/
putty的窗口里,返回到/root目录,在/root(~)目录下运行测试程序ledtest,putty的ARM-linux 操作系统的命令行输入:
./ledtest
putty的窗口里,程序会提示:please enter the led status,输入与希望显示的led 状态对应的ledstatus 值(输入十进制值即可),观察led 的显示情况。
putty的窗口里,卸载led驱动模块:
rmmod ees331_led
UART驱动
1.在vivado里搭建好硬件工程,包括:led、sw和uart模块。
2.搭建好后生成比特流文件,利用SDK软件将fsbl文件、比特流文件、u-boot文件生成boot.bin启动文件。
3.在driver_code/BOOT相应目录下找到devicetree.dts源文件,打开源文件(图中的目录是devicetree目录,实际是BOOT),修改设备树文件,如下:
ees331_uart@42c00000 {
clock-names = "ref_clk";
clocks = "clkc 0";
compatible = "xlnx,xps-uartlite-1.00.a";
current-speed = <0x2580>;
device_type = "serial";
port-number = <0x1>;
/* Add your code here */
reg = <>; //寄存器的起始地址 和偏移量
xlnx,baudrate = <>; //波特率
xlnx,data-bits = <>; //数据位宽
xlnx,odd-parity = <>; //奇偶校验位
interrupt-parent=<>; //中断节点数
interrupts=<>; //中断信息
/* Add your code here */
xlnx,s-axi-aclk-freq-hz-d = "100.0";
xlnx,use-parity = <0x0>;
};
在注释部分增加设备树信息。
4.在虚拟机终端中,将设备树文件dts转换成dtb格式,并通过读卡器将devicetree.dtb拷贝到SD里的BOOT分区里:
dtc -I dts -O dtb -o devicetree.dtb devicetree.dts
在driver_code/uartlite目录下修改测试程序uart.c。
int main(void)
{
int fd,ret;
/* Add your code here */
//1.加入设备名称;2.填写自己的学号
char *uart = "";
char buffer_out[] = "";
/* Add your code here */
char buffer_in[512];
memset(buffer_in,0,512);
fd = open(uart,O_RDWR | O_NOCTTY);
if(fd == -1)
{
printf("%s open failed\n",uart);
return -1;
}
printf("%s open success\n",uart);
ret = set_opt(fd,9600,8,'N',1);
if(ret == -1)
{
exit(-1);
}
ret = write(fd,buffer_out,strlen(buffer_out));
printf("your number sent %d\n",ret);
while(1)
{
/* Add your code here */
//1.主程序实现接收字符,并把接收到的字符在发送出去
/* Add your code here */
}
close(fd);
}
6.对提供的测试程序uart.c 进行交叉编译,生成可执行文件uart,在终端下输入以下命令:
cd /home/zynq/driver_code/uartlite
sudo su (密码:1)
source zynq-env.sh
arm-linux-gnueabihf-gcc uart.c -o uart
7.对驱动文件进行编译,生成驱动模块uartlite.ko,在同一个终端下继续输入命令:
make
8.在win7系统里打开putty软件,选择对应的com口,波特率选择为115200。
9.putty的窗口里,将uartlite.ko和uart文件拷贝到SD卡的root目录下。
scp zynq@192.168.1.12:~/driver_code/uartlite/uart /root
scp zynq@192.168.1.12:~/driver_code/uartlite/uartlite.ko /root
10.putty的窗口里,进入到arm-linux系统里,在/root(~)目录下执行insmod 命令,将驱动模块动态加载到内核中。
insmod uartlite.ko
驱动加载成功后,在/dev/目录中用ls命令可以查看到相应的设备。
ls /dev/
11.用双头usb线将开发板上PL的串口(5上)与上位机连接,打开串口助手,选择对应的com口与波特率9600。
12..putty的窗口里,在/root(~)目录下运行测试程序uart,putty的ARM-linux 操作系统的命令行输入:
./uartlite
四、实验结果
| 基于ARM的模块方式驱动程序实验关键代码: |
|
|
| 基于ARM的模块方式驱动程序实验结果: |
|
|
实验现象:在putty运行相关程序后,在putty窗口输入相应的数字,板子上相应的灯会点亮。
|
| 基于ARM的串口驱动实验实验结果: |
|
|
实验现象解释:可以看到在实验当中,连接上之后,首先会发送自己的学号,然后在输入1234之后也会接收到消息,当输入有x字符后,程序会自动结束。
1.在进行数码管的实验当中,利用linux系统进行驱动程序的编写,熟悉了Linux系统下的指令的编写,认识到了linux系统下的文件的操作方式,熟悉了虚拟机的使用。
2.在实验当中,深入了解了串口通信的原理,理解了波特率和端口的强大作用。
3.学习到了uart驱动,了解了设备和驱动程序之间的关系
4.理解了uart的测试程序,交叉编译后运行,进行串口通信,学习到了串口下相关接口函数使用。
基于ARM的模块方式驱动程序实验
1.驱动里led的地址是怎么查看的?
可以在硬件工程里面查看led的地址。
2.模块化的最大优点是什么?
每个模块可以实现不同的功能,方便团队之间分工协作。
3. printk()函数的作用是什么,怎么查看printk函数打印的消息?
printk ()函数的作用是将printk ()的内容输出到控制台。在shell中使用dmesg指令就可以查看printk函数打印的消息。1在终端下输入:
2 while true
3 do
4 sudo dmesg -c
5 sleep 1
6 done
4.文件操作结构体struct file_operations的作用是什么?
用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。
结构体file_operations在头文件 linux/fs.h中定义,用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。该结构体的每个域都对应着驱动内核模块用来处理某个被请求的事务的函数的地址。
每一个设备文件都代表着内核中的一个file结构体。该结构体在头文件linux/fs.h定义。file结构体是内核空间的结构体,这意味着它不会在用户程序的代码中出现。它绝对不是在glibc中定义的FILE。FILE自己也从不在内核空间的函数中出现。。
基于ARM的串口驱动实验
1. vivado里uart的波特率是怎么查看和修改?
在uart_register_driver中把 normal->init_termios.c_cflag改成:
normal->init_termios.c_cflag = B1152000 | CS8 | CREAD | HUPCL | CLOCAL;
而 B115200为0x00001002,即.c_cflag 0~3bit位十进制值为2,那么在tty_termios_baud_rate中会cbaud += 15后 cbaud为17,结baud_table[17] = 115200;在msm_hs_set_bps_locked中有case 115200: msm_hs_write(uport, UART_DM_CSR, 0xcc); 而uport->uartclk = 7372800;0xc的分频系数为 64,那么7372800/64=115200.
2. 设备树的作用是什么,与驱动程序有什么联系?设备树得作用是:描述板卡上的硬件资源信息
与驱动程序的联系是:在kernel 3.0以及之后的版本,都是采用设备树的方法实现驱动与设备之间的联系。将设备改为设备树实现,解决了总线方法中代码冗余多的问题。
设备树方法只需要在总线方法的基础上稍微修改一下。
3. 文件操作结构体struct file_operations的作用是什么?用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。
结构体file_operations在头文件 linux/fs.h中定义,用来存储驱动内核模块提供的对设备进行各种操作的函数的指针。该结构体的每个域都对应着驱动内核模块用来处理某个被请求的事务的函数的地址。
每一个设备文件都代表着内核中的一个file结构体。该结构体在头文件linux/fs.h定义。file结构体是内核空间的结构体,这意味着它不会在用户程序的代码中出现。它绝对不是在glibc中定义的FILE。FILE自己也从不在内核空间的函数中出现。。
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用这两种语言中的任何一种(最好是ruby)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生
我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby-vips的github页面上的链接,我们将不胜感激!如果有ruby-
我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d
我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。
我想验证一个电子邮件地址是否是PayPal用户。是否有API调用来执行此操作?是否有执行此操作的ruby库?谢谢 最佳答案 GetVerifiedStatus来自PayPal'sAdaptiveAccounts平台会为您做这件事。PayPal没有任何codesamples或SDKs用于Ruby中的自适应帐户,但我确实找到了编写codeforGetVerifiedStatusinRuby的人.您需要更改该代码以检查他们拥有的帐户类型的唯一更改是更改if@xml['accountStatus']!=nilaccount_status
我想知道我应该如何着手这个项目。我需要每周向人们发送一次电子邮件。但是,这必须在每周的特定时间自动生成并发送。编码有多难?我需要知道是否有任何书籍可以提供帮助,或者你们中的任何人是否可以指导我。它必须使用rubyonrails进行编程。因此有一个网络服务和数据库集成。干杯 最佳答案 为什么这么复杂?您只需安排工作。您可以使用Delayed::Job例如。Delayed::Job让您可以使用run_at符号在特定时间安排作业,如下所示:Delayed::Job.enqueue(SendEmailJob.new(...),:run_
我查看了Stripedocumentationonerrors,但我仍然无法正确处理/重定向这些错误。基本上无论发生什么,我都希望他们返回到edit操作(通过edit_profile_path)并向他们显示一条消息(无论成功与否)。我在edit操作上有一个表单,它可以POST到update操作。使用有效的信用卡可以正常工作(费用在Stripe仪表板中)。我正在使用Stripe.js。classExtrasController5000,#amountincents:currency=>"usd",:card=>token,:description=>current_user.email)
当profile为nil时,总是让我感到悲伤...我该怎么办? 最佳答案 在View中使用变量之前,始终检查变量是否为nil。我确信这个问题有更优雅的解决方案,但这应该能让您入门。 关于ruby-on-rails-Rails处理.Erb与Nils,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/2709605/
我有一个应用程序专门使用Facebook作为身份验证提供程序,并正确设置了生产模式的回调。为了让它工作,您需要为您的Facebook应用程序提供一个站点URL和一个用于回调的站点域,在我的例子中是http://appname.heroku.com和appname。heroku.com分别。问题是我的Controller设置为只允许经过身份验证的session,所以我无法在开发模式下查看我的应用程序,因为Facebook应用程序的域显然没有设置为本地主机。如何在不更改Facebook设置的情况下解决这个问题? 最佳答案 创建另一个域l