蜂蜜加醋怎么喝减肥:S3C6410开发板实践记录
来源:百度文库 编辑:偶看新闻 时间:2024/04/26 20:29:12
CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
1. LINUX FLASH分区问题
看到linux在启动的时候打印出:
- Creating 4 MTD partitions on "NAND 2GiB 3,3V 8-bit":
- 0x00000000-0x00040000 : "Bootloader"
- 0x00040000-0x00400000 : "Kernel"
- 0x00400000-0x05400000 : "Rootfs"
- 0x05400000-0x80000000 : "File System"
所以bootloader应该是0x00000000-0x00040000,大小256k,但是为何文档中升级uboot的时候更新的是0x100000大小的FLASH空间?
后在LINUX中dump出来/dev/mtdblock1和写入zImage比较发现前一部分是uboot的东西,之所以系统可以加载Rootfs成功是因为0x00400000-0x05400000和文档中的根文件系统是一致的。所以这里需要更改内核分区的大小,位于linux2.6.28/arch/arm/plat-s3c/include/ plat/partition.h
- struct mtd_partition s3c_partition_info[] =
- {
- {
- .name = "Bootloader",
- .offset = 0,
- .size = (SZ_1M),
- .mask_flags = MTD_CAP_NANDFLASH,
- },
- {
- .name = "Kernel",
- .offset = (SZ_1M),
- .size = (4*SZ_1M) - (SZ_1M),
- .mask_flags = MTD_CAP_NANDFLASH,
- },
- #if defined(CONFIG_SPLIT_ROOT_FILESYSTEM)
- {
- .name = "Rootfs",
- .offset = (4*SZ_1M),
- .size = (80*SZ_1M),//(48*SZ_1M),
- },
- #endif
- {
- .name = "File System",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- }
- };
此时在内核启动时输出的信息与实际NAND Flash的分区情况是一致的了。
0x00000000-0x00100000 : "Bootloader"
0x00100000-0x00400000 : "Kernel"
0x00400000-0x05400000 : "Rootfs"
0x05400000-0x80000000 : "File System"
2.如何实现tftp uboot升级
这个网上有DM9000A的驱动,只要替换对应的driver/dm9000.c 和driver/dm9000.h即可,但是发现只有在使用ping命令(发送数据包)的时候,对应的网卡才会激活,而一旦ping结束后,那么网卡就会自动断掉,查看代码发现在do_ping时会做eth_init,而结束后会做eth_close动作
所以在start_armboot函数中加入初始化动作:eth_init(gd->bd); 并注释掉eth_close动作即可。
硬件平台:MainBoard:OK6410CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6 3.使用TFTP升级Uboot 发现使用tftp升级uboot的时候无法成功,但是升级fs和kernel的时候可以。
后发现S3C6410启动的时候会通过NAND控制器将nandflash的头4K拷贝到SRAM中执行,这一步叫做steppingstone,SRAM的大小有8K,但是steppingstone只用了其中的4K,另外NAND控制器支持每FLASH页读取的大小为512B/2K,所以当flash页大小为4K的时候,它只能每块读取前2K,这里就需要在写Uboot的时候前面个PAGE每个只能写入2K,也即
- nand erase 0 100000
- nand write 50008000 0 1000
- nand write 50008800 1000 1000
- nand write 50009000 2000 FF000
- nand erase 0 100000
- nand write 50008000 0 1000
- nand write 50008800 1000 1000
- nand write 50009000 2000 1000
- nand write 50009800 3000 1000
- nand write 5000A000 4000 FE000
- else if(!read && !strcmp(s, ".uboot"))
- {
- /* for Page 2048 then just do normal writing */
- if(nand->writesize == 0x800)
- goto write;
- else if(nand->writesize == 0x1000)
- {
- /* try to simulate a 0x800 page size flash and do a remap */
- int blocks = 5, i = 0;
-
- for(; i < blocks; i++)
- {
- if(i == blocks - 1)
- size = 0xfe000;
- else
- size = 0x1000;
-
- printf("Write at Offset %x from Addr:%x with Size %x\n", off + i * 0x1000, addr + i * 0x800, size);
- ret = nand_write(nand, off + i * 0x1000, &size, (u_char *)(addr + i * 0x800));
-
- if(ret == 0)
- {
- uint *magic = (uint*)(PHYS_SDRAM_1);
- if((0x24564236 == magic[0]) && (0x20764316 == magic[1]))
- magic[0] = 0x27051956;
- }
-
- if(ret)
- {
- printf(" 0x%x bytes %s to 0x%x %s\n", size, read ? "read" : "written", off + i * 0x1000, 0x1000,
- ret ? "ERROR" : "OK");
- return 1;
- }
- }
-
- printf("Uboot have been updated, please do reset!\n");
- return 0;
- }
- else
- {
- printf("Only support page size 2K and 4K!\n");
- return 1;
- }
- }
CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
4.BOOT SELECT
OK6410底板原理图.pdf第5页上的BOOT SELECT接线标记反了,如下图:
而在LINUX2.6.28使用手册中的拨码开关说明如下:
显然这里的Pin8为SELNAND,也即是OK6410 BOOT SELECT电路图的PIN1。
5.关于S3C6410启动模式
http://www.hzlitai.com.cn/article/ARM11/SYSTEM/S3C6410qd.html有详细的解释。
先读一下S3C6410 User Manual的第3章 System Controller,在123页列了一张表,如图:
从表中可以看出,S3C6410好像并不支持Nandflash启动,因为Boot Device中没有Nandflash设备。当OM[4:0]为0000x/0001x/0010x/0011x的时候,Boot Device是Reserved,我想这里是Samsung在6410中有意要隐瞒什么。如果你用过S3C6400,你应该知道在S3C6400 User Manual中也有这么一张表,描述了s3c6400的启动模式,具体S3C6400的启动模式也是在第3章 System Controller,在第107页的表,如图:
从表中可以看出,S3C6410好像并不支持Nandflash启动,因为Boot Device中没有Nandflash设备。当OM[4:0]为0000x/0001x/0010x/0011x的时候,Boot Device是Reserved,我想这里是Samsung在6410中有意要隐瞒什么。如果你用过S3C6400,你应该知道在S3C6400 User Manual中也有这么一张表,描述了s3c6400的启动模式,具体S3C6400的启动模式也是在第3章 System Controller,在第107页的表,如图:
OK6410提供了两种选择,也即PIN7/6为11时,OM[4:1]为1111,此时为SD/MMC(CH0),当PIN7/6为00时,OM[4:1]为0011,且XSELNAND永远为1,所以选择为Large Page,AddrCycle=5(Flash的读写周期)。
硬件平台:MainBoard:OK6410CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
6.关于NAND FLASH K9GAG08U0D的读写
在K9GAG08U0D.pdf的第10页,提到它的操作时钟周期为5Cycle,另外页大小是4096Byte,
6.
在uboot1.1.6_256M\cpu\s3c64xx\nand_cp.c的72行,有如下代码:
显然这里使用了5个Cycles,与文档是相符的。
如果对照本文件中的S3C2410的读FLASH的代码,那么对于NAND FLASH的读写将会有更深的理解。其实如果
你在本文件中改写了S3C6410读取的方法,那么也是可以成功使用tftp升级uboot的。
硬件平台:MainBoard:OK6410
CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
7.Busybox 的编译
选择合适的Busybox版本,这里选择用2.6.28内核对应的busybox-1.16.2版本,然后做以下配置:
1) make menuconfig
2) Busybox Settings ---> Build Options --->
选择编译成静态库,这样就避免了繁琐的动态库安装,当然如果使用了动态库,那么需要将uclibc中的库so文件拷贝到lib文件夹中,这样其他的应用程序也可以使用动态库编译而不增加代码大小。
指定交叉编译工具链。
3) Busybox Settings ---> Installation Options --->
选择Don't use /usr防止busybox安装到宿主机
指定安装路径为/home/red/forlinux/rootfs
此时安装到rootfs的文件和目录如下:
- #ls /home/red/forlinux/rootfs
- drwxr-xr-x 2 root root 4.0K 2011-07-12 10:38 bin/
- lrwxrwxrwx 1 root root 11 2011-07-12 10:38 linuxrc -> bin/busybox*
- drwxr-xr-x 2 root root 4.0K 2011-07-12 10:38 sbin/
创建一些系统启动必须的目录和文件
创建设备节点,通常需要root权限才能使用mknod来创建,我们直接赋值已经创建好的设备节点即可,另外一种方法是使用mdev命令根据mdev.conf在启动时生成。
设备节点应该具有合适的权限,否则在使用该设备的时候会出问题。
etc下的配置文件:
1) inittab :在busybox执行linuxrc或者init链接的时候解析并执行。
2) init.d:是一个文件夹,一般放置rcS脚本
3) profile:用来配置终端
export PS1='[\u@\h \W]\# ' 后发现终端提示符号不正确,如下显示:
[\u@\h \W]\#
busybox settings->busybox library tuning->username completion、fancy shell prompts选上
CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
CONFIG_FEATURE_USERNAME_COMPLETION=y
重新编译即可。也只有开启了此两选线,/etc/profile才有意义。
8.关于nfs文件系统的挂载
在ubuntu10.10上测试通过,参考了网上的一些文档,有些命令在ubuntu上需要修改
- #sudo apt-get install portmap
- #sudo apt-get install nfs-kernel-server
- #sudo vim /etc/exports
- 添加/forlinx *(rw,sync,no_root_squash)
- #sudo /etc/init.d/portmap restart //该命令应为service portmap stop; service portmap start
- #sudo /etc/init.d/nfs-kernel-server restart // 该命令为service nfs-kernel-server restart
另外查看rpcbind有没有运行。如果没有则rpcbind –w&
- #exportfs –rv // 这一步很关键
- #showmount -e // 显示共享出的目录
本机测试命令为:
- #sudo mount -t nfs localhost:/forlinux/root /mnt/tmp
嵌入式系统测试为:
- mount -t nfs localhost:/forlinux/root /mnt/tmp -o nolock // nolock 必须要添加
如果作为根系统启动,则
- #setenv bootargs "root=/dev/nfs nfsroot=10.255.21.240:/forlinux/root ip=10.255.21.213:10.255.21.240:10.255.21.254:255.255.255.0:hostname:eth0:off console=ttySAC0,115200"
- #saveenv
- #reset
10.255.21.240 PC 端Ubuntu 的IP
10.255.21.213开发板IP
10.255.21.254 网关
255.255.255.0 子网掩码
硬件平台:MainBoard:OK6410
CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6 9.LED灯驱动 这几天研究USB驱动,不想板子的USB坏了,所以闲着没事就看了看LED灯驱动.OK6410没有使用内核提供的LED驱动模板,而是直接通过寄存器虚拟地址进行操作,比起USB驱动来说要简单得多。 首先还是从电路图开始:
User LED电路图
User LED CPU管脚接线图
从电路图文档中可以看出,LED是通过GPIO的M端口实现的,其中分别用到了GPM0/1/2/3管脚。根据LED的接线图可以看出只有在NLED0/1/2/3为低电平时,才会导通点亮。M端口有6个管脚,三个对应的寄存器:
GPMCON是控制寄存器,控制管脚的功能:用作输入,输出等。
GPMDAT是数据寄存器,内容与管脚电平相一致,也即GPM0为高电平那么对应的0b1为1.
GPMPUD是用来控制功率输出的,通常在电平输出不符合要求是,实现电平的上拉和下拉。
相关寄存器文档(芯片手册300 pg.)
Bootloader中对应GPM初始化的代码位于board/samsung/smdk6410/lowlevel_init.S
相关寄存器定义在include/s3c6410.h
ldr指令用来将立即数装载如寄存器,str将r1中的值写入间址GPMDAT_OFFSET+r0。ELFIN_GPIO_BASE定义的就是实际的物理地址,不难看出bootloader是实地址寻址的。
前3行写入0x00111111到GPMCON寄存器,也即配置GPM0-5为输出。
接着2行写入0x00000555到GPMPUD寄存器,配置GPM0-5内部电阻下拉使能。这是因为如果要点亮LED,那么需要低电平,下拉可以保证下拉电阻接地产生低电平。
最后2行写入0x002a到GPMDATA寄存器,也即0b101010,所以对应的GPM0/2/4是低电平,GPM1/3/5是高电平,与此相连的LED1/3点亮,LED2/4熄灭,这也就是为何开发板上电后LED1/3点亮的原因。
硬件平台:MainBoard:OK6410
CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
11. LINUX下led驱动解析
Linux2.6.28中的LED驱动位于drivers/char/s3c6410_leds.c。
- static int __init s3c6410_leds_init(void)
- {
- int ret = 0;
- unsigned long tmp;
- dev_t devno;
-
- printk(KERN_NOTICE "enter s3c6410_leds_init\n");
- devno = MKDEV(LED_MAJOR,0);
-
- //申请设备号资源,对应到内核的HASH表chrdevs
- ret = register_chrdev_region(devno,1,DEVICE_NAME);
- if(ret<0)
- {
- printk(KERN_NOTICE "can not register led device");
- return ret;
- }
-
- //初始化字符设备cdev_leds,并安装操作函数
- cdev_init(&cdev_leds,&s3c6410_leds_fops);
- cdev_leds.owner = THIS_MODULE;
-
- //通告内核,这样就可以在/proc/devices下看到231 leds设备了
- ret =cdev_add(&cdev_leds,devno,1);
- if(ret)
- {
- printk(KERN_NOTICE "can not add leds device");
- return ret;
- }
-
- //创建/sys下的my_class类文件
- my_class = class_create(THIS_MODULE,"my_class");
- if(IS_ERR(my_class))
- {
- printk("Err: Failed in creating class\n");
- return -1;
- }
-
- // 创建/dev/leds文件,提供用户空间访问的接口
- device_create(my_class,NULL,MKDEV(LED_MAJOR,0),NULL,DEVICE_NAME);
- //与lowlevel_init.S初始化类似的操作,但是这里的地址都是虚拟地址
- //gpm0-3 pull up
- tmp = __raw_readl(S3C64XX_GPMPUD);
- tmp &= (~0xFF);
- tmp |= 0xaa;
- __raw_writel(tmp,S3C64XX_GPMPUD);
-
- //gpm0-3 output mode
- tmp = __raw_readl(S3C64XX_GPMCON);
- tmp &= (~0xFFFF);
- tmp |= 0x1111;
- __raw_writel(tmp,S3C64XX_GPMCON);
-
- //gpm0-3 output 0
- tmp = __raw_readl(S3C64XX_GPMDAT);
- tmp |= 0x10;
- __raw_writel(tmp,S3C64XX_GPMDAT);
-
- printk(DEVICE_NAME " initialized\n");
-
- return 0;
- }
相关的寄存器虚地址定义在arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
- #define S3C64XX_GPMCON (S3C64XX_GPM_BASE + 0x00)
- #define S3C64XX_GPMDAT (S3C64XX_GPM_BASE + 0x04)
- #define S3C64XX_GPMPUD (S3C64XX_GPM_BASE + 0x08)
GPIO M端口的基地址定义在arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
- #define S3C64XX_GPM_BASE (S3C64XX_VA_GPIO + 0x0820)
GPIO的虚地址定义在arch/arm/mach-s3c6400/include/mach/map.h
- #define S3C64XX_VA_GPIO S3C_ADDR(0x00500000)
GPIO的虚地址是有全局虚地址S3C_ADDR_BASE计算出来的,void __iomem __force *作用是强制转化为地址。arch/arm/plat-s3c/include/plat/map.h
- #define S3C_ADDR_BASE (0xF4000000)
- #ifndef __ASSEMBLY__
- #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
- #else
- #define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
- #endif
由此可以得到GPM寄存器对应的虚地址分别为:
- S3C64XX_GPMCON 0xF4500820
- S3C64XX_GPMDAT 0xF4500824
- S3C64XX_GPMPUD 0xF4500828
驱动中的接口通过ioctl来提供,
- static struct file_operations s3c6410_leds_fops = {
- .owner = THIS_MODULE,
- .ioctl = s3c6410_leds_ioctl,
- };
- static int s3c6410_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
- {
- unsigned long tmp;
- switch(cmd)
- {
- case 0: //熄灭
- case 1:// 点亮
- if(arg > 4)
- return -EINVAL;
- tmp = __raw_readl(S3C64XX_GPMDAT);
- if(cmd) //注意cmd为1时点亮动作,对应的位置0
- tmp &= (~(1<
- else
- tmp |= (1<
- __raw_writel(tmp,S3C64XX_GPMDAT);
- return 0;
- default:
- return -EINVAL;
- }
- }
- else
尽管该驱动在编译进内核时,运行led或者led-player可以正常工作,但是当你把选项CONFIG_TE6410_LEDS=y改为CONFIG_TE6410_LEDS=m时,问题出现了。
进行insmode s3c6410_leds.ko没有问题,而进行rmmod s3c6410_leds时则会提示:
rmmod: chdir(/lib/modules): No such file or directory,关于此问题网上有很多解决方法,比如http://www.cnblogs.com/junmao/articles/1991495.html。
真正的问题不在于卸载,而在于卸载后再次insmod时提示加载失败,分析源码发现,驱动的卸载载函数存
在问题:
- static void __exit s3c6410_leds_exit(void)
- {
- /* added by lli_njupt */
- device_destroy(my_class, MKDEV(LED_MAJOR,0));
- class_destroy(my_class);
- cdev_del(&cdev_leds);
- unregister_chrdev_region(MKDEV(LED_MAJOR,0),1);
- printk(KERN_NOTICE "s3c2440_leds_exit\n");
- }
注意红色部分由笔者添加,加载失败的原因就在于没有从/dev/下注销leds,另外/sys下的class文件也需要注销。如此天下太平了。
硬件平台:MainBoard:OK6410CPU: S3C6410
RAM: 256M
FLASH:1G K9GAG08U0DKernel:Linux2.6.28BootLoader:Uboot1.1.6
12.用户空间的跑马灯
- int main(void)
- {
- int on=1;
- int led;
- int fd;
-
- fd = open("/dev/leds",0);
- if(fd<0)
- {
- perror("open device leds");
- exit(1);
- }
- printf("leds test show.press ctrl+c to exit\n");
- while(1)
- {
- for(led = 0; led < 4; led++)
- {
- // 这个实现倒是很简洁,每隔60000微秒切换一次
- ioctl(fd, on, led);
- usleep(60000);
- }
- on = !on;
- }
-
- close(fd);
- return 0;
- }