嵌入式实验报告
指导老师: 涂 刚
班 级: 计算机0704
姓 名:
学 号:
姓 名:
学 号:
完成日期: 7.5
试验一:bootloader (ads、引导)
一、实验任务
1、熟悉ADS 1.2开发工具
创建、编译、下载、调试工程
2、串口通讯
串口控制器初始化、收/发数据
3、配置主机端的nfs服务器
配置主机端的nfs服务器,以连接linux核心
4、下载并运行linux核心
使用自己的串口程序下载并运行linux核心
二、实验内容
l 编写串口接收数据函数
l 编写串口发送数据函数
l 学习ads、jtag调试、flash烧写
l 打印菜单,等待用户输入
l 下载并运行linux核心
l 配置主机的nfs服务器,与linux核心连接
三、实验步骤
(1) 修改bootloader:菜单、串口收发、命令行;
Bootloader的main()函数:
int main(void)
{
ARMTargetInit(); //目标板初始化;
//接收用户命令,传递linux核心;
Uart_puts("Menu:\n\r");
Uart_puts("1.Load kernel via Xmodem;\n\r");
Uart_puts("2.Boot linux; \n\r");
Uart_puts("3.Load kernel from flash and boot; \n\r");
Uart_puts("Make your choice.\n\r");
do{
ch=Uart_getc();
}while(ch!='1' && ch!='2' && ch!='3');
return 0;
}//main;
接收串口数据并做相应处理:
while(1)
{
打印菜单并等待用户输入;
switch(ch) //根据用户输入做相应处理
{
case '1':
imgsize=xmodem_receive((char *)KERNEL_BASE, MAX_KERNEL_SIZE);
if(imgsize==0) //下载出错;
else //下载成功;
break;
case '3':
nand_read((unsigned char *)KERNEL_BASE, 0x00030000, 4*1024*1024);
case '2':
BootKernel(); //这里是不会返回的,否则出错;
break;
default:
break;
}
}
串口读写:
void Uart_putc(char c)
{
while(!SERIAL_WRITE_READY());
((UTXH0) = (c));
}
unsigned char Uart_getc( )
{
while(!SERIAL_CHAR_READY());
return URXH0;
}
(2) 使用ads1.2编译bootloader;
(3) 使用uarmjtag下载、调试bootloader;
(4) 使用axd查看变量、内存,单步跟踪;
(5) 配置超级终端,与bootloader通讯;
(6) 使用超级终端下载Linux核心映像;
(7) 启动Linux核心运行,察看结果;
(8) linux核心能够运行到加载root步骤,说明bootloader正常运行;
(9) 将bootloader烧写到flash中,重启目标板电源,察看bootloader是否烧写正常,下载核心测试;
(10)主机重启到Fedora,配置nfs;
编辑/etc/export文件:
/home/arm_os/filesystem/rootfs 目标板ip(rw,sync)
/home/arm_os/filesystem/rootfs 主机ip(rw,sync)
重新启动nfs服务器:
/etc/init.d/nfs restart
测试nfs服务器是否正常运行:
mount 主机ip:/home/arm_os/filesystem/rootfs /mnt
(11)以root用户启动cutecom,将cutecom配置成115200 bps,8位,1位停止位,无校验,xmodem,no line end;
(12)使用bootloader重新下载Linux核心映像,启动核心运行后,察看是否成功加载nfs上的root文件系统;
目标板linux系统正常运行到命令行模式下,能够正常输入linux命令,说明实验成功。
四、实验过程中遇到的问题及解决方案
问题一 :打开dubug,下载zImage失败,调试时观察内存地址不是从0x0开始。
解决方法:从新做了很多遍,仍然失败,最后终于观察到jtag线上的灯没有亮,换了一根好的jtag线,终于成功地下载了核心映像。
问题二 :cmd命令行下烧写bootloader时出现错误,ERROR:K9S1208 IS NOT DETECTED.
解决方法: 因为不明白错误出现的原因,向老师提出疑问,经老师指点,忽略此错误。
问题三 :最后一步使用bootloader重新下载linux核心映像之后,目标板linux系统始终无法正常运行到linux命令模式下。
解决方法:重新到xp下,设置bootlinux.c中的Linux核心启动命令行:
char *linux_cmd="noinitrd init=/init root=/dev/nfs nfsroot=172.16.68.25:/home/arm_os/filesystem/rootfs,tcp ip=172.16.68.24 console=ttySAC0";
通过此设置指定root在nfs服务器上,保持nfs:ip地址的一致。
试验二:linux kernel (gcc、make)
一、实验任务
1、熟悉基本的linux命令
文件操作、文件编辑
串口工具、程序开发
2、配置linux核心
make menuconfig
3、 交叉编译linux核心
make zImage
二、实验内容
l 熟悉基本的linux命令
l 配置linux核心
l 交叉编译linux核心
l 调试自己编译的核心
l 挂载nfs上的root(根目录)
l 编写一个小程序在目标板上运行
三、实验步骤
登陆Fedora,在终端进入管理员模式;
解压缩源码包到/home/下;
察看解压缩后的/home/arm_os目录:Linux核心、编译器、rootfs等;
配置并测试nfs;
配置cutecom:115200,XModem,No line end;
配置核心:make menuconfig;
编译核心:make;
下载并运行核心,加载root文件系统;
重新设置cutecom为LF line end;
熟悉基本的Linux命令;
编写一个小程序hello.c在目标板上运行,察看结果。
#include<stdio.h>
Int main(){
Printf(“hello”);
Return 0;
}
四、实验中遇到的主要问题及解决方法
问题一:核心的配置和编译都成功了,但是打开cutecom不能进入命令行模式,说明加载root文件系统失败,不能调试自己编译的核心。
解决方法:观察mount之后的/mnt目录下是空的,进入XP下发现D盘是空的,于是重新拷贝核心映像文件,重复实验一的工作,最后成功加载root文件系统,进入cutecom命令行。
问题二:写成的hello.c程序用gcc编译之后不能在目标板上运行。
解决方法:编译的命令不对,应该用arm-gcc-linux进行交叉编译,而不是用gcc,得到的可执行文件可以用命令./hello成功运行。
试验三:linux driver (uart)
一、实验任务
1、 Linux驱动编程
基本接口
常用函数
2、 串口驱动
申请中断处理
串口数据读、写
二、实验内容
编写串口驱动初始化、释放函数;
编写串口驱动接收数据函数;
编写串口驱动发送数据函数;
编写串口驱动中断处理函数;
编写串口访问应用程序;
使用模块方式编译驱动;
使用模块方式调试驱动;实现基本的串口数据收发。
三、实验步骤
(1) 填写函数:uart_init、uart_exit、uart_open、uart_ release,实现串口设备初始化、释放、打开、关闭;
串口设备初始化函数:
int ret;
dev_t devno = MKDEV(uart_major, 0);
if(uart_major){
ret = register_chrdev_region(devno, 1, "uart");
}else {
ret = alloc_chrdev_region(&devno, 0, 1, "uart");
uart_major = MAJOR(devno);
}
if(ret < 0){ printk("Register chrdev region failed!\n"); return ret; }
cdev_init(&uart_cdev, &uart_fops);
ret = cdev_add(&uart_cdev, devno, 1);
if(ret){ printk("Add c device failed!\n"); return ret; }
uart = ioremap(S3C2410_PA_UART1, 0x4000);
device_init();
ret = request_irq(IRQ_S3CUART_RX1, irq_rev_uart, IRQF_DISABLED, "uart", NULL);
if(ret){ printk("Request irq failed!\n"); return ret; }
loop_buffer_init(&readb, UART_SIZE); printk("Uart module init.\n");
return 0;
串口设备释放函数:
loop_buffer_free(&readb);
free_irq(IRQ_S3CUART_RX1, NULL);
cdev_del(&uart_cdev);
unregister_chrdev_region(MKDEV(uart_major,0),1);
printk("Uart module exit.\n");
(2) 填写函数: irq_rev_uart、uart_write、uart_read,实现串口设备中断处理、读、写;
串口设备中断处理函数:
char c;
while(!(__raw_readb(uart + S3C2410_UTRSTAT) & 0x1));
c = (char)__raw_readl(uart + S3C2410_URXH);
loop_buffer_add(&readb, c);
return 0;
串口设备读函数:
int i = 0;
if(*ppos >= UART_SIZE) return -EIO;
if(*ppos + size > UART_SIZE) size = UART_SIZE - *ppos;
do
{
char c;
if(!loop_buffer_del(&readb, &c))
{
copy_to_user(buf+i, &c, 1);
i++;
}
else
schedule_timeout(10);
} while(i < size);
return size;
串口设备写函数:
int i; char wmem[UART_SIZE];
if(*ppos >= UART_SIZE) return -EIO;
if(*ppos + size > UART_SIZE)
size = UART_SIZE - *ppos;
copy_from_user(wmem, buf, size);
for(i=0; i<size; i++){
while(!(__raw_readl(uart + S3C2410_UTRSTAT) & 0x4));
__raw_writel(*(wmem + i), uart + S3C2410_UTXH);
}
return size;
串口访问应用程序:
#include <stdio.h>
#include <fcntl.h>
int main()
{
int uart_fd, i; char c;
uart_fd = open("/dev/uart", O_RDWR);
if(uart_fd < 0)
{printf("Open device error!\n"); return -1;}
for(i=0; i<50; i++){
read(uart_fd, &c, 1); printf("%c", c);
write(uart_fd, &c, 1);
if(c == 'q') break;
}
close(uart_fd);
return 0;
}
(3) 用模块方式编译Linux核心,生成uart.ko,启动目标板Linux核心,用insmod、rmmod等命令操作模块;用printk打印调试串口驱动,包括中断相应,读写等;
(4) 编写应用程序:uart.c,实现打开串口设备、读写等,把主机端由cutecom发过来的串口数据回传给主机;
(5) 将目标板上串口线连到串口1;
(6) 编译应用程序uart.c,实现和主机间的串口通讯。
四、实验中遇到的问题及解决方法
问题一:在超级终端下打开cutecom失败
解决方法:由于没有使用交换机,网络需要重新激活,激活网络之后,cutecom打开成功。
问题二:对模块化编译方法不太了解,对其过程不清楚。
解决方法:经老师点拨,逐渐明白其过程:首先修改uart.c中的波特率,然后拷贝驱动,把:/home/arm_os/test/st/test3/driver/下的makefile和uart.c拷贝到:/home/arm_os
/kernel/linux-2.6.29.8/driver/char下,再拷贝应用程序:把:/home/arm_os/test/st/tes
T3/下的makefile和uart.c拷贝到自己的文件夹,用于测试。
试验四:linux driver (touchscreen)
一、实验任务
1、 触摸屏驱动
初始化
坐标值
2、 触摸屏、图形系统协调工作
触摸屏校准
拨号键盘
二、实验内容
l 编写触摸屏驱动初始化、释放函数;
l 编写触摸屏驱动读取数据函数;
l 编写触摸屏驱动中断处理函数;
l 使用模块方式调试驱动;
l 编写触摸屏读取应用程序;
l 编写简单图形系统绘制应用程序,绘制一个数字键盘;
l 实现基本的触摸键盘程序。
三、实验步骤
(1) 函数:ts_init、ts_exit、ts_open、ts_ release,实现触摸屏设备初始化、释放、打开、关闭;
触摸屏设备初始化函数:
int ret;
dev_t devno = MKDEV(ts_major, 0);
if(ts_major){
ret = register_chrdev_region(devno, 1, “ts_ads7843");
}else {
ret = alloc_chrdev_region(&devno, 0, 1, " ts_ads7843 ");
ts_major = MAJOR(devno);
}
if(ret < 0){ printk("Register chrdev region failed!\n"); return ret; }
cdev_init(&ts_cdev, &ts_fops);
ret = cdev_add(&ts_cdev, devno, 1);
if(ret){ printk("Add c device failed!\n"); return ret; }
spi0_base = ioremap(S3C2410_PA_SPI,0x20);
device_init();
init_waitqueue_head(&wq);
ret = request_irq(IRQ_EINT5, ts_isr, IRQF_DISABLED, "ts_ads7843", NULL);
if(ret){ printk("Request irq failed!\n"); return ret; }
TS_OPEN_INT(); ts_time = jiffies;
printk("Ts_ads7843 module init.\n");
return 0;
触摸屏设备释放函数:
free_irq(IRQ_EINT5, NULL);
cdev_del(&ts_cdev);
unregister_chrdev_region(MKDEV(ts_major,0),1);
printk("Ts_ads7843 module exit.\n");
(2) 填写函数:ts_isr、ts_read,实现触摸屏读、中断处理
触摸屏设备中断处理函数:
if(jiffies < ts_time + HZ/20)
return 0;
if((s3c2410_gpio_getpin(S3C2410_GPF5)
& ADS7843_PIN_PEN) == 0)
{
udelay(10);
get_XY();
ts_time = jiffies;
wake_up_interruptible(&wq);
udelay(2);
}
return 0;
触摸屏设备读函数:
struct ts_ret ts_ret;
int size = 0;
while(count >= sizeof(struct ts_ret))
{
interruptible_sleep_on(&wq);
ts_ret.x = x;
ts_ret.y = y;
ts_ret.pressure = PEN_DOWN;
copy_to_user(buffer, (char *)&ts_ret, sizeof(struct ts_ret)); count -= sizeof(struct ts_ret);
size += sizeof(struct ts_ret);
}
return size;
(3) 用模块方式编译Linux核心,生成ts_ads7843.ko,启动目标板Linux核心,用insmod、rmmod等操作模块;
(4) 用printk打印调试触摸屏驱动,包括中断相应,读等;
(5) 编写应用程序:ts_ads7843.c,实现打开触摸屏设备、读等;
触摸屏访问应用程序:
#include <stdio.h>
#include <fcntl.h>
int main()
{
int ts_fd, i; char c; struct ts_ret ts_ret;
ts_fd = open("/dev/ts_ads7843", O_RDWR);
if(ts_fd < 0) {
printf("Open ts device error!\n"); return -1; }
for(i=0; i<50; i++){
if(read(ts_fd, &ts_ret, sizeof(struct ts_ret))) {
if(ts_ret.x < Xmin) ts_ret.x = Xmin;
if(ts_ret.x > Xmax) ts_ret.x = Xmax;
if(ts_ret.y < Ymin) ts_ret.y = Ymin;
if(ts_ret.y > Ymax) ts_ret.y = Ymax;
x = (ts_ret.x-Xmin) * SCREEN_WIDTH/(Xmax-Xmin);
y = (ts_ret.y-Ymin) * SCREEN_HEIGHT/(Ymax-Ymin); }}
close(ts_fd);
return 0;
}
(6) 在ts_ads7843.c 中增加简单图形系统绘制函数,绘制数字键盘,对触摸屏设备数据进行校正,实现触摸键盘的功能。
四、实验中出现的主要问题和解决方法
问题一:挂载网络文件系统上的root再次失败。
解决方法:经过仔细观察总结,发现系统中的编辑/etc/export文件设置为:
/home/ rootfs 目标板ip(rw,sync)
/home /rootfs 主机ip(rw,sync)
分析可能是上一次做实验的人用的主目录路径跟我们的不一样,于是我们重新以/home /rootfs为路径测试测试nfs服务器:mount 主机ip:/homerootfs /mnt ,在后续文件操作中也一直注意这个方面,解决了多次挂载失败的问题。
问题二:主要是触摸屏校正的问题
解决方法:按课件上的方法耐心地测试,直到找出比较合适的值。
实验五、六:GPRS综合试验 (framebuffer)GPRS综合试验
一、实验任务
1、 GPRS模块控制试验
串口控制GPRS模块
AT命令集
2、 综合实验
电话拨号
短消息发送
二、实验过程及遇到的问题
本实验比较简单,把手机的sim卡装在一个卡上,插在目标班上,就可以按键打电话了。碰到的主要问题是对硬件结构不熟悉。
实验体会
嵌入式开发是一个很吸引人的方向。通过三次课与六次实验,我们对这个课题有了一个很清晰的认识和了解,感受到了嵌入式操作系统的独特魅力。
开始老师讲理论的时候,只能大略听懂其中的操作系统部分,对嵌入式的概念理解很模糊。第一次实验是做起来感觉最难的一次,因为是第一次接触很多软件和文件,都不明白自己的每一步操作的原因和目的,一旦出错,也不知道从哪儿排错。第二次实验相对比较简单,基本linux操作和核心编译配置我们以前都有训练过。
做完两次实验好好综合总结了一下,才明白了每一步操作的意义,以及嵌入式两次实验,才明白嵌入式linux的基本原理,有了这个基础,在后续的实验中感觉就明白多了,碰到问题的时候可以自己摸索着解决或者像同学请教,最后完成了用自己开发的简单linux系统打电话的目标。
总觉得在这六次实验中有个遗憾,可能因为课时限制和学生精力有限,代码大部分都是老师给的现成的。应该掌握了这些编程,才算真正掌握了嵌入式系统系统开发,不过这个只能留待我们在课后实现了。