实验一 灯程序——OK6410A开发板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系统映像等知识。

原文地址:https://www.cnblogs.com/qingjielaojiu/p/15708692.html