实验一 灯程序——OK6410-A开发板LINUX3.0.1(嵌入式开发)
实验一 灯程序
一、实验目的
1.熟悉linux系统,学会简单linux指令
2.熟悉OK6410-A开发板的烧入步骤
3.熟悉ARM寄存器,地址等。
4.系统性的了解UBOOT和linux内核,yaffs2系统映像等知识
二、实验仪器
开发机环境
操作系统:ubuntu 20.04
交叉编译环境:arm-linux-gcc 4.6.4
6410板子内核源码:linux-3.0.1
目标板环境
OK6410-A linux-3.0.1
三、实验内容(原理)
1.硬件部分
从上面的原理图可以得知,LED与CPU引脚的连接方法如下,低电平点亮。
LED1 -GPM0
LED2 -GPM1
LED3 -GPM2
LED4 -GPM3
2.寄存器部分
重点观察下面寄存器的地址,输出方式等信息
通过上面可以得知,如果要点亮灯1,需要先将GPM0设置为输出方式。将相应的寄存器进行配置。然后将GPMDAT寄存器的第0位置0灯亮,置1灯灭。
四、实验步骤
1.编写驱动程序
driver_led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>
#include <plat/gpio-cfg.h>
MODULE_LICENSE("GPL" );
#define LED_MAJOR 240
int led_open (struct inode *inode,struct file *filp)
{
unsigned tmp;
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0x7U<<1))|(0x2U);
writel(tmp, S3C64XX_GPMCON);
printk("#########open######\n");
return 0;
}
ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
printk("#########read######\n");
return count;
}
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);
switch(wbuf[0])
{
case 0: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
default :
break;
}
return count;
}
int led_release (struct inode *inode, struct file *filp)
{
printk("#########release######\n");
return 0;
}
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");
rc = register_chrdev(LED_MAJOR,"led",&led_fops);
if (rc <0)
{
printk ("register %s char dev error\n","led");
return -1;
}
printk ("ok!\n");
return 0;
}
void __exit led_exit (void)
{
unregister_chrdev(LED_MAJOR,"led");
printk ("module exit\n");
return ;
}
module_init(led_init);
module_exit(led_exit);
2.编写Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := driver_led.o
else
KDIR := /home/kk/Desktop/forlinx/linux-3.0.1
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
3.编写test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
int fd;
char buf[10]={0,1};
fd = open("/dev/my_led",O_RDWR);
if (fd < 0)
{
printf ("Open /dev/my_led file error\n");
return -1;
}
while(1)
{
write(fd,&buf[0],1);
sleep(1);
write(fd,&buf[1],1);
sleep(1);
}
close (fd);
return 0;
}
4.编译驱动程序与测试程序
#make
将编译生成 driver_led.ko等文件
#arm-linux-gcc test.c -o test
将生成test可执行文件
最后呈现以下文件
5.格式化SD卡,把 SD 卡格式化为 FAT32 格式。
6.用SD_Writer将 mmc.bin 烧写到 SD 卡中
1.以管理员身份运行
2.点击”Scan”,这个步骤是自动搜寻 SD 卡所在盘符。如果"Scan"没有正确设置 SD 卡所在盘符,就需要手动 调整 SD Volume,把盘符号调整为 SD 卡所在盘符(比如说,PC 的 USB 口接了两个或者两个以上的 U 盘或 者 SD 卡,就有可能错误到扫描 SD 卡盘符)。
3.将”SD Type”更改为 auto。这个步骤是为了让 SD_Writer 自动识别 SD 卡类型。
4.将”OS Type”更改为 Linux。这个步骤是选择要烧写的系统类型。
5.点击”Select Boot”, 选择适合自己开发板的 mmc.bin
mmc_ram128.bin 适用于 128M 内存的开发板
mmc_ram256.bin 适用于 256M 内存的开发板
6.点击”Program”,出现”It’s OK”表示操作成功。
7.拷贝系统文件
首先,将 u-boot.bin 拷贝到 SD 卡中。
u-boot_ram128.bin 专门用于 128M 内存开发板。
u-boot_ram256.bin 专门用于 256M 内存开发板。
将与开发板对应的 u-boot 拷贝到 SD 卡中。接着在 SD 卡中将文件名改为u-boot.bin 即可。
然后,将 zImage 拷贝到 SD 卡中。zImage 是 Linux 的内核映像文件。
最后,将 rootfs.yaffs2 拷贝到 SD 卡中。
rootfs.yaffs2-nand256m 专门用于 128M 内存,256M NandFlash开发板。
rootfs.yaffs2-nand2g 专门用于 256M 内存,1G 或 2G 或者 4G Nandflash 的开发板
8.拷贝驱动程序与测试程序
将driver_led.ko与test拷贝到SD卡上
9.烧写Linux到开发板的NandFlash
步骤 1. 将制作好的 SD 卡插入开发板 SD 的插槽。
步骤 2. 接好 5V 直流电源(飞凌提供此电源,请使用飞凌提供的电源)。
步骤 3. 拨码开关设置为 SD 卡启动。
拨码开关在底板SD 卡启动的拨码开关设置如下:
引脚号 | Pin8 | Pin7 | Pin6 | Pin5 | Pin4 | Pin3 | Pin2 | Pin1 |
---|---|---|---|---|---|---|---|---|
引脚定义 | SELNAND | OM4 | OM3 | OM2 | OM1 | GPN15 | GPN14 | GPN13 |
SD卡启动 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
10. 测试
1.打开终端
2.加载驱动
#insmod /sdcard/driver_led.ko
3.创建设备文件
#mknod /dev/my_led c 240 0
4.测试
./test
5.卸载驱动
#rmmod driver_led
看到小灯点亮,实验成功!
五、实验程序(包括流程图)
1.点灯
driver_led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>
#include <plat/gpio-cfg.h>
MODULE_LICENSE("GPL" );
#define LED_MAJOR 240
int led_open (struct inode *inode,struct file *filp)
{
unsigned tmp;
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0x7U<<1))|(0x2U);
writel(tmp, S3C64XX_GPMCON);
printk("#########open######\n");
return 0;
}
ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
printk("#########read######\n");
return count;
}
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);
switch(wbuf[0])
{
case 0: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
default :
break;
}
return count;
}
int led_release (struct inode *inode, struct file *filp)
{
printk("#########release######\n");
return 0;
}
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");
rc = register_chrdev(LED_MAJOR,"led",&led_fops);
if (rc <0)
{
printk ("register %s char dev error\n","led");
return -1;
}
printk ("ok!\n");
return 0;
}
void __exit led_exit (void)
{
unregister_chrdev(LED_MAJOR,"led");
printk ("module exit\n");
return ;
}
module_init(led_init);
module_exit(led_exit);
Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := driver_led.o
else
KDIR := /home/kk/Desktop/forlinx/linux-3.0.1
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
int fd;
char buf[10]={0,1};
fd = open("/dev/my_led",O_RDWR);
if (fd < 0)
{
printf ("Open /dev/my_led file error\n");
return -1;
}
while(1)
{
write(fd,&buf[0],1);
sleep(1);
write(fd,&buf[1],1);
sleep(1);
}
close (fd);
return 0;
}
2.流水灯
driver_led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>
#include <plat/gpio-cfg.h>
MODULE_LICENSE("GPL" );
#define LED_MAJOR 240
int led_open (struct inode *inode,struct file *filp)
{
unsigned tmp;
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0x7U<<1))|(0x1U);
writel(tmp, S3C64XX_GPMCON);
printk("#########open######\n");
return 0;
}
ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
printk("#########read######\n");
return count;
}
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);
switch(wbuf[0])
{
case 7: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x1U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 0: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x1U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 6: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x2U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 5: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x4U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 2: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x4U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 4: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x8U);
writel(tmp, S3C64XX_GPMDAT);
break;
case 3: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x8U);
writel(tmp, S3C64XX_GPMDAT);
break;
default :
break;
}
return count;
}
int led_release (struct inode *inode, struct file *filp)
{
printk("#########release######\n");
return 0;
}
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");
rc = register_chrdev(LED_MAJOR,"led",&led_fops);
if (rc <0)
{
printk ("register %s char dev error\n","led");
return -1;
}
printk ("ok!\n");
return 0;
}
void __exit led_exit (void)
{
unregister_chrdev(LED_MAJOR,"led");
printk ("module exit\n");
return ;
}
module_init(led_init);
module_exit(led_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := driver_led.o
else
KDIR := /home/kk/Desktop/forlinx/linux-3.0.1
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
int fd;
char buf[10]={0,1,2,3,4,5,6,7};
fd = open("/dev/my_led",O_RDWR);
if (fd < 0)
{
printf ("Open /dev/my_led file error\n");
return -1;
}
while(1)
{
write(fd,&buf[0],1);
sleep(1);
write(fd,&buf[1],1);
sleep(1);
write(fd,&buf[2],1);
sleep(1);
write(fd,&buf[3],1);
sleep(1);
write(fd,&buf[4],1);
sleep(1);
write(fd,&buf[5],1);
sleep(1);
write(fd,&buf[6],1);
sleep(1);
write(fd,&buf[7],1);
sleep(1);
}
close (fd);
return 0;
}
3.流程图
六、运行结果
1.点灯程序
2.流水灯程序
视频就不贴了
七、心得体会
第一次接触嵌入式开发,第一次靠自己一步一步做到从配置环境到烧写到点亮第一个小灯,收获点亮小灯的喜悦。这一路并不是一帆风顺的。遇到过ubuntu12.04的源因为年代久远失效,遂更换20.04。遇到过64位操作系统不支持32位交叉编译器的问题,也遇到过各种无读写权限,找不到文件,文件报错,驱动代码报错等大大小小的问题,挣扎了很久,也收获了很多。在硬件领域,很多的第一次,都是从小灯开始,小灯点亮不只是代表着这一个简单的步骤,更是代表第一次走通了这条路,可以第一次说我行了。
最后,做一个收获的总结,熟悉linux系统,学会简单linux指令,熟悉OK6410-A开发板的烧入步骤,熟悉ARM寄存器,地址等。系统性的了解UBOOT和linux内核,yaffs2系统映像等知识。