移植uboot2010.12到飞凌6410及TQ2440

本文介绍U-Boot编译流程与配置,包括环境变量设置、makefile指令解析等内容。同时深入探讨NAND Flash的工作原理,涉及硬件ECC、坏块管理等关键技术。

eldk编译器 金山网盘下载   官方下载


安装eldk编译器

mount -t iso9660 -o loop arm-2008-11-24.iso mount_dir

cd mount_dir

 ./install -d /opt/eldk



修改后的支持网络的u-boot代码,基于官方u-boot2010.12

  version2012-09-08这里下载 


/× 1.修改了一些小的bug,

/×2.增加debug开关

/×3.增加命令 updateuboot updatezImage updatecramfs 

 version2012-09-18这里下载  


linux内核与 文件系统

linux内核/文件系统直接使用飞凌提供的,但kernel有一个文件需要修改,否则内核不能启动


把文件中的全局变量赋上初值

inux2.6.28_FORLINUX\arch\arm\plat-s3c\include\plat\uncompress.h


/* uart setup */


static unsigned int fifo_mask = (0x3F << 8);
static unsigned int fifo_max = 5;


===============================================================================================================================

编译:设置环境变量

OLD_PATH=$PATH
export PATH=/opt/eldk/arm/usr/bin:/opt/eldk/arm/bin/:$PATH
export CROSS_COMPILE=arm-
#export PATH=$OLD_PATH


# some targets like unconfig, clean, clobber, distclean, etc.

make mrproper

make smdk6400_config  2>&1 |tee configure.out

make 或者make all 


编译后的u-boot文件名称:u-boot-nand.bin,这个专门用作nand 的启动


通过网络更换u-boot 更换 zImage,当然了,第一次还是要使用sd卡按照飞凌的方法更换u-boot

默认tftp服务器的IP为 192.168.0.11

/**********************************/
/*   update uboot via net                              */
/*   tftpboot 0x51000000 u-boot.bin           */
/*   nand erase 0x0 0x80000                      */
/*   nand write 0x51000000 0x0 0x80000  */
/**********************************/


/*****************************************/
/*   update kernel via net                                           */
/*   tftpboot 0x51000000 u-boot.bin                        */
/*   nand erase 0x50008000 0x300000                        */
/*   nand write 0x50008000 0x100000 0x300000    */
/*****************************************/


===============================================================================================================================

uboot2010.12 makefile分析:

常用指令:

make mrproper   恢复到初始状态
make distclean
make clobber
make clean
make unconfig
make smdk6400_config
make 或者 make all
 



make target_config分析:

target: 当你不知道target的具体名字的时候可以通过以下两种途径来查找

1. 一般都存在boards.cfg中,通过makefile-->sinclude .boards.depend --〉boards.cfg来引用

2.  另外如果target需要额外的处理,那么就不会放在boards.cfg,而是直接放在Makefile中,(cat Makefile|grep unconfig|grep :)该命令可以过滤出所有不再boards.cfg中的target

make smdk6400_config 的执行结果:

以下这些文件有mkconfig脚本生成,mkconfig用于生成头文件和相关的link文件  
[cc@iZ23rrduja6Z ~]$ diff -r u-boot-2010.12/ u-boot-2010.12.mrproper/
Only in u-boot-2010.12/arch/arm/include/asm: arch                      #ln directory
Only in u-boot-2010.12/arch/arm/include/asm: proc                      #ln directory
Only in u-boot-2010.12/board/samsung/smdk6400: config.tmp
Only in u-boot-2010.12/: .boards.depend
Only in u-boot-2010.12/include: asm                                    #ln directory
Only in u-boot-2010.12/include: config.h
Only in u-boot-2010.12/include: config.mk


[cc@iZ23rrduja6Z ~]$ cat u-boot-2010.12/board/samsung/smdk6400/config.tmp   
RAM_TEXT = 0x57e00000
[cc@iZ23rrduja6Z ~]$ cat  u-boot-2010.12/include/config.h
/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/samsung/smdk6400
#include <config_defaults.h>
#include <configs/smdk6400.h>
#include <asm/config.h>
[cc@iZ23rrduja6Z ~]$ cat u-boot-2010.12/include/config.mk   //由mkconfig根据boards.cfg中或者Makefile中的 ARCH CPU BOARD VENCOR SOC 来生成
ARCH   = arm
CPU    = arm1176
BOARD  = smdk6400
VENDOR = samsung
SOC    = s3c64xx
CONFIG_NAND_U_BOOT = y



make -p target_config的作用:

 -p 选项用于打印出所有的make 目标,这样就便于分析makefile结构


uboot的makefile目标分析:使用make -p 可以分析出所有的目标


make -d 的作用:

用于打印出 更多地makefile调试信息,当你不知道makefile的结构的时候,这些都是有用的





make 相当于make all 
all: u-boot.srec u-boot.bin System.map u-boot-nand.bin



=================================================================================================================================

arm-ld 连接器参数说明:   -T 用于指定连接脚本及连接参数,一般包含于LDFLAGS变量

LDFLAGS = -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS) -Ttext $(CONFIG_SYS_TEXT_BASE)  
u-boot.lds  #D:\cc\u-boot-2010.12\board\samsung\smdk6400\u-boot-nand.lds
CONFIG_SYS_TEXT_BASE = $(RAM_TEXT)  #在makefile中smdk6400_config段被定义
 -T u-boot.lds  -Ttext 0x57e00000   用于指定使用u-boot.lds连接脚本 ,-Ttext 0x57e00000 用与指定正文段从0x57e00000开始



==================================================================================================================

smdk6400的编译连接分三步:

1. make 编译连接成  /home/cc/u-boot-2010.12/u-boot.map  /home/cc/u-boot-2010.12/u-boot      ,再由objcopy生成  u-boot.srec u-boot.bin
2. make编译连接成/home/cc/u-boot-2010.12/nand_spl/u-boot-spl.map  /home/cc/u-boot-2010.12/nand_spl/u-boot-spl ,再由objcopy生成/home/cc/u-boot-2010.12/nand_spl/u-boot-spl.bin  /home/cc/u-boot-2010.12/nand_spl/u-boot-spl-16k.bin
3.   cat nand_spl/u-boot-spl-16k.bin u-boot.bin > u-boot-nand.bin
因为nand不同于nor,不能直接存取内存,因此在cpu内部的stepping stone controller 自动读取前4k的nand到cpu内部来启动,然后再由前4k 拷贝其他的uboot到内存中,至此才能完全启动





======================================================================================================================

smdk6410 uboot第二阶段编译地址空间分配:

CONFIG_SYS_TEXT_BASE= 0x57e00000    #/u-boot-2010.12\Makefile 

#define CONFIG_SYS_SDRAM_BASE 0x50000000  /*内存开始地址*/   D:\cc\u-boot-2010.12\include\configs\smdk6400.h


/* stack address for uboot*/
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 128 * 1024 *1024 - 4*1024)   #D:\cc\u-boot-2010.12\include\configs\smdk6400.h



      |           |  
      |           |
      |  stack1   |CONFIG_SYS_INIT_SP_ADDR = 0x57fff000   调用board_init_f时的stack
      |           |
      |   gd      | global data 区域
      |  other    |
      |  stack2   |  调用board_init_r时 的stack                 
      |           |
      |           |
      |           |
      |           |
      |           |
      |           |
      |  text     |CONFIG_SYS_SDRAM_BASE = 0x50000000 
      |           |
      |           |




===============================================================================

第二阶断启动流程:


reset:   -------------- #D:\cc\u-boot-2010.12\arch\arm\cpu\arm1176\start.S   
     |
     V
bl	lowlevel_init ----   #D:\cc\u-boot-2010.12\board\samsung\smdk6400\lowlevel_init.S 
     |
     V
bl	board_init_f   -----      # /home/cc/u-boot-2010.12/arch/arm/lib\board.c
     |
     V
init_sequence  ----   #/home/cc/u-boot-2010.12/arch/arm/lib\board.c 
     |                   其中有初始化serial: 
     |                  arch_cpu_init/board_early_init_f/timer_init/
     |                  get_clocks/env_init/init_baudrate/serial_init
                        console_init_f/display_banner/print_cpuinfo/
                        checkboard/init_func_i2c/dram_init/arm_pci_init
     |
     V     
relocate_code (addr_sp, id, addr); # board_init_f函数为board_init_r准备好堆栈运行空间后跳转到board_init_r
     |
     V
board_init_r   ---------     #/home/cc/u-boot-2010.12/arch/arm/lib\board.c
     |
     V
flash_init()  ------------------#/home/cc/u-boot-2010.12/common/flash.c
     |
     V
nand_init() ------------------#/u-boot-2010.12/drivers/mtd/nand/nand.c     
     |
     V
main_loop  --------------     #/home/cc/u-boot-2010.12/common/main.c 到此进入uboot命令行




==========================================================================================================

第一阶段,前4k的地址空间分配

      |           |  
      |           |
      |  stack1   |CONFIG_SYS_INIT_SP_ADDR = 0x57fff000   调用board_init_f时的stack
      |           |
      |   gd      |  global data 区域
      |  other    |
      |  stack2   |  0x57c00000 调用nand_boot时 的stack                 
      |           |
      |           |
      |           |
      |           |
      |           |
      |           |
      |  text     |CONFIG_SYS_SDRAM_BASE = 0x00000000 
      |           |
      |           |





===============================================================

第一阶段,前4k启动流程

reset:   -------------- #D:\cc\u-boot-2010.12\arch\arm\cpu\arm1176\start.S   
     |
     V
bl	lowlevel_init ----   #D:\cc\u-boot-2010.12\board\samsung\smdk6400\lowlevel_init.S 
     |
     V
bl	board_init_f   -----      # /home/cc/u-boot-2010.12/nand_spl/nand_boot.c
     |
     V     
relocate_code ; # 仅仅设置好sp
     |
     V
nand_boot   ---------     #/home/cc/u-boot-2010.12/nand_spl/nand_boot.c
     |
     V
nand_load   ---------     #/home/cc/u-boot-2010.12/nand_spl/nand_boot.c 加载4k以后的u-boot(第二阶段u-boot)到0x57e00000
     |
     V
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;   ---------     #/home/cc/u-boot-2010.12/nand_spl/nand_boot.c    第二阶段u-boot的第一条指令



==========================================================================

main_loop中对命令行的执行:

U_BOOT_CMD宏用于定义一个uboot命令行,如下:宏的第一个参数bootm是 命令字,do_bootm是实际调用的执行函数


U_BOOT_CMD(
bootm,CONFIG_SYS_MAXARGS,1,do_bootm,
"boot application image from memory",
"[addr [arg ...]]\n    - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
 



输入"bootm 0x50008000"     表示从0x50008000内存地址启动kernel ;argv[0]=bootm argv[1]=x50008000

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

常用的uboot command

run 用于运行一个存储在evn中的命令,如 :run updatezImage 


=====================================================

DM9000 网卡的支持


开发板的网口插上网线后,等不会亮,PC端的网卡也显示没有连线状态,但可以使用tftpboot ping 命令后自动启动网卡。这个问题原因不详细,待稍后解决。

============================================

nandflash基本知识介绍:






















==增加 Target TQ2440 到uboot (以smdk2410为蓝本)================================


主makefie的修改

## ARM920T Systems
#########################################################################

TQ2440_config   :       unconfig
	@$(XECHO) specifiy TQ2440_config;
	@mkdir -p $(obj)include $(obj)board/samsung/TQ2440
	@mkdir -p $(obj)nand_spl/board/samsung/TQ2440
	@echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
#       @if [ -z "$(findstring smdk6400_noUSB_config,$@)" ]; then                       \
#       #               echo "RAM_TEXT = 0x57e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
#       else                                                                            \
#       #               echo "RAM_TEXT = 0xc7e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
#       fi
#       #                    ARCH  CPU         BOARD    VENDOR  SOC
	@$(MKCONFIG) TQ2440  arm   arm920t     TQ2440   samsung s3c24x0
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk





boards.cfg 的修改

# Target                     ARCH        CPU         Board name          Vendor	        SoC         Options
###########################################################################################################

qong                         arm         arm1136     -                   davedenx       mx31
mx31ads                      arm         arm1136     -                   freescale      mx31
imx31_litekit                arm         arm1136     -                   logicpd        mx31
omap2420h4                   arm         arm1136     -                   ti             omap24xx
tnetv107x_evm                arm         arm1176     tnetv107xevm        ti             tnetv107x
armadillo                    arm         arm720t
ep7312                       arm         arm720t
impa7                        arm         arm720t
modnet50                     arm         arm720t
lpc2292sodimm                arm         arm720t     -                   -              lpc2292
SMN42                        arm         arm720t     -                   siemens        lpc2292
evb4510                      arm         arm720t     -                   -              s3c4510b
a320evb                      arm         arm920t     -                   faraday        a320
at91rm9200ek                 arm         arm920t     at91rm9200ek        atmel          at91        at91rm9200ek
at91rm9200ek_ram             arm         arm920t     at91rm9200ek        atmel          at91        at91rm9200ek:RAMBOOT
eb_cpux9k2                   arm         arm920t     -                   BuS            at91
cm41xx                       arm         arm920t     -                   -              ks8695
sbc2410x                     arm         arm920t     -                   -              s3c24x0
VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
smdk2400                     arm         arm920t     -                   samsung        s3c24x0
smdk2410                     arm         arm920t     -                   samsung        s3c24x0
TQ2440                       arm         arm920t     -                   samsung        s3c24x0



增加board对应的文件夹及文件

include/configs/TQ2440.h             ------------config文件 
                   
board/samsung/TQ2440/TQ2440.c
board/samsung/TQ2440/config.mk
board/samsung/TQ2440/Makefile
board/samsung/TQ2440/lowlevel_init.S
board/samsung/TQ2440/flash.c
board/samsung/TQ2440                 -------------该board对应的文件夹

nand_spl/board/samsung/TQ2440/u-boot.lds
nand_spl/board/samsung/TQ2440/config.mk
nand_spl/board/samsung/TQ2440/Makefile
nand_spl/board/samsung/TQ2440       --------------用于nandflash启动的文件夹


make 



TQ2440 uboot第二阶段编译地址空间分配:(u_boot的大小定义为1M,紧接其后是4K的ENV空间)
CONFIG_SYS_TEXT_BASE= 0x33E80000      #/u-boot-2010.12\samsung\TQ2440\config.mk  内存62.5M的地方 
#define CONFIG_SYS_UBOOT_SIZE (1024 * 1024) = 1M
#define CONFIG_NAND_ENV_DST (CONFIG_SYS_UBOOT_BASE + CONFIG_SYS_UBOOT_SIZE)
#define CONFIG_ENV_SIZE 0x10000= 4K
#define CONFIG_SYS_SDRAM_BASE 3000'0000   /*内存开始地址*/   D:\cc\u-boot-2010.12\include\configs\TQ2440.h


/* stack address for uboot*/  最顶端的4k是堆栈空间
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 64 * 1024 *1024 - 4*1024)   #D:\cc\u-boot-2010.12\include\configs\TQ2440.h




      |           |  
      |           |
      |  stack1   |CONFIG_SYS_INIT_SP_ADDR = 0x33fff000   调用board_init_f时的stack
      |           |
      |   gd      | global data 区域
      |  other    |
      |  stack2   |  调用board_init_r时 的stack                 
      |           |
      |           |
      |           |
      |           |
      |    text   |CONFIG_SYS_TEXT_BASE  = 0x33E80000
      |           |
      |           |CONFIG_SYS_SDRAM_BASE = 0x30000000 
      |           |
      |           |


==========================================================================================================

第一阶段,前4k的地址空间分配

      |           |  
      |     gd    |global data 区域
      |  stack1   |CONFIG_SYS_INIT_SP_ADDR = 0x33fff000   调用board_init_f时的stack
      |           |
      |           |  
      |  other    |
      |  stack2   |  0x57c00000 调用nand_boot时 的stack                 
      |           |
      |           |
      |           |
      |           |
      |           |
      |           |
      |  text     |CONFIG_SYS_SDRAM_BASE = 0x00000000 
      |           |
      |           |


第一阶段如果使用到serial,注意配置gd的地址,防止除以0的发生,正确配置波特率

	/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
	reg = get_PCLK() / (16 * gd->baudrate) - 1;



======nand flash==========




  • nandflash的特性

nandflash支持按page进行读写,写操作能把flash 1->0  而不能 0->1  ,所有每页只能写一次(记录已写),整块的页都用过后再整block擦除,然后置1

nandflash支持按block进行擦除,擦除可以支持把flash 全部置1

  • nand.h 对外函数

nand_read  nand_write  

nand_block_isbad   nand_erase   nand_read_skip_bad   nand_write_skip_bad  nand_erase_opts

nand_lock  nand_unlock  board_nand_select_device


  • nand_flash 调试经验

SC2440+K9F2G08U0A芯片第一次saveenv总是失败,第二次总能成功,

最后测试发现NAND_CMD_READID命令后NAND_CMD_STATUS的状态总出现写保护异常,必须NAND_CMD_READID再调用NAND_CMD_RESET后NAND_CMD_STATUS就正常



nand_get_flash_type, type->pagesize 0 writesize: 800(2k)   oobsize: 40  erasesize: 20000(2k*64) busw: 0

writesize:  每页大小,这款芯片是2k
oobSize : 扩展页字节,这款芯片是64字节
erasesize: 块大小,这款芯片是2K*64page=128K
chip->page_shift:b(11位,用于右移后得到页地址) 
chip->pagemask:1ffff (17位,A12~A28,用于确定页地址最大是17位)
chip->phys_erase_shift = chip->bbt_erase_shift:11 (17位,用于右移得到block地址,A18~A28)
chip->chip_shift:1c (28位,256M,用于右移后得到chipnr)



nand_read_oob--->nand_do_read_oob--->nand_read_oob_std

页读取指令,如果A11=1 表示仅仅读出oob的64个字节


nand_read_page_raw     -----后缀raw 的意思是读取page+oob数据
nand_read_oob_std      -----后缀oob_std的意思是读取oob数据
nand_read_page_hwecc   ------后缀hwecc的意思是,类似于nand_read_page_raw,意思是ecc方式读出page+oob



  • nandflash的坏块管理:

对于每个block来讲,一般第一页OOB的第六个字节0xFF表示该block是正常的,否则为坏block

对于2440板子配置的K9F2G08X0A,每个block的第一页和第二页的第一个字节为0xFF表示该block是正常,否则为坏block


  • nand bad 命令

do_nand               (cmd_nand.c)            
   |
   V
nand_block_checkbad   (nand.h)
   |
   V
chip->scan_bbt        (nand_bbt.c)  
   |
   V
nand_default_bbt      (nand_bbt.c)
   |
   V
nand_scan_bbt         (nand_bb.c)  
   |
   V
create_bbt            (nand_bbt.c)

   |
   V
mtd->read_oob          (nand_base.c)
   |
   V
nand_read_oob          (nand_base.c)
   |
   V
nand_do_read_oob        (nand_base.c)
   |
   V
nand_read_oob_std       (nand_base.c)


  • nand info命令  、nand device命令


do_nand
   |
   V
nand_print_info
   |
   V
chip->numchips  nand->name, nand->erasesize >> 10


  • nand erase命令
对于 nannd erase/nand read/nand write 其输入参数  off 、size,使用的都是容量地址;对于off=0x1000,size=0x2000表示从4k的边界开始,读取8k的内容;  转化为flash的行地址和列地址为0x2000,意思是从第3页开始读取连续4页的内容 
nand erase的参数有两种 :  offs+size    ;  partName: bios 会自动把partname转化为off+size 

and erase[.spread] [clean] [off [size]]     ---nand erase 0x500000 0x3C00000   ----nand erase bios 
   |
   V
do_nand          cmd_nand.c
   |
   V
nand_erase_opts   cmd_nand.c
   |
   V
meminfo->erase    cmd_nand.c
   |
   V
nand_erase         nand_base.c
   |
   V
nand_erase_nand     nand_base.c
   |
   V
chip->erase_cmd = single_erase_cmd;     nand_base.c




erase的起始地址(off)必须是block的边界地址、长度(len)会被进位到整块






  • nand read 

对nand的访问最终会转化为page和column,如果column的最高位为0,则读出2048+64 ,那么可以寄存器NFCMMD中读取2048+64个字节;如果column的最高位是1,则只读出64字节的OOB;同理对于nand write也是一样的


nand read - addr off|partition size    -----nand read 0x30008000 0x200000 0x300000   
                                       ----nand read 0x30008000 bios 0x300000  (bios partname)
nand read - addr off|partition size  从 off 读取size 到内存addr ;第二块的起始地址为0x20000   
   |  
   V  
do_nand                    ----------cmd_nand.c   
   |  
   V  
nand_read_skip_bad         ----------nand_uitl.c  
   |  
   V  
nand_read                 ----------nand_base.c  
   |  
   V  
nand_do_read_ops          -----------nand_base.c  
   |  
   V  
ecc.read_page                 
   |  
   V  
nand_read_page_hwecc(NAND_ECC_HW)  nand_read_page_swecc(NAND_ECC_SOFT)    ----nand_base.c  




nand read  起始地址必须是页地址对齐的


s3c2410_nand_enable_hwecc    ----------\
s3c2410_nand_calculate_ecc   ----------|------   用于读取页数据的时候有硬件ECC生成ecc结果
s3c2410_nand_correct_data   ------------------用于比较oob区域的ecc和硬件生成的ecc




  • nand ECC

struct nand_ecclayout 之解义 ,eccbytes,eccpos,eccfree


     
这里讨论下struct nand_ecclayout,即nand 的ecc布局问题,基于2.6.32-rc2.
该结构体定义如下:
 
struct nand_ecclayout {
uint32_t eccbytes;    //表示使用几个ecc字节
uint32_t eccpos[128]; //表示ecc占用的位置,因为现在大页面4kbyte也就128个,所以这里写了128,
                                   //以后有更大页面的,这里也要改了。
uint32_t oobavail;       //有几个oob可用,这个跟下面的成员有点像,一般用下面的
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  //定义oob有效个数,从哪开始等
};
 
 
给个例子:
 
static struct nand_ecclayout mylayout = {
#ifdef CONFIG_SYS_NAND_PAGE_2K
.eccbytes = 40,
.eccpos = { 
24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 
},
.oobfree = {
{.offset = 2, .length = 22, },
},
#endif
}
 其中,.eccbytes = 40,跟初始化有关系,我们一般这样初始化:
nand->ecc.size = 512; 
nand->ecc.bytes = 10;
恩,这下明朗了,我们需要每512个字节产生10个ecc字节,因此对2kbyte页面的flash来说,一页就是4个512,因此需要4*10=40个ecc字节。
.eccpos就是告诉驱动,这些ecc字节放在哪里,一般是按顺序存放,不要覆盖芯片默认的坏块标记位,对2kbyte的flash来说,厂家说是前两个即第0、1个字节是坏块标志。
所以分配为eccbytes和eccpos后,后面有个oobfree,这样看来也很明白了:
offset=2表示从第2个字节开始(因为前面2个是坏块标志啊~~),length=22表示(从offset开始)共22个ecc字节可以用户随便用。
这下一目了然了吧。
 

u-boot-2016.03 在mini2440上移植之nandflash 硬件ecc


无论是nand_write_page_hwecc函数,还是nand_write_page_hwecc函数,内部都有一个这样的for循环体:

for(i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {

……  ……

}

其中三个主要变量的定义为:

eccsize= chip->ecc.size;

eccbytes= chip->ecc.bytes;

eccsteps= chip->ecc.steps;

下面我们就来介绍一下这个循环的作用:不同的CPU的NandFlash控制器一次所能完成的硬件ECC的字节数是不一样的,例如有些CPU一次只能完成512字节的硬件ECC,但如果开发板上的NandFlash每页有2048个字节,那该怎么办呢?这时就要用到一个循环体,通过循环多次来得到一页的硬件ECC。例如上面这种情况,就要循环4次(2048÷512=4),才能得到这个页内数据完整的硬件ECC。另外每一次硬件ECC,不同的CPU所生成的ECC字节数也是不同的,有的是3个字节,有的是4个字节。

那么,上面那三个变量的含义就分别为:

ecc.size:每一次硬件ECC所检验的字节个数   ------   #define CONFIG_SYS_NAND_ECCSIZE  2048

ecc.bytes:每一次硬件ECC所生成的字节个数  -------  #define CONFIG_SYS_NAND_ECCBYTES  4

ecc.steps:每一页需要进行硬件ECC的次数

对于S3C2440来说,一次硬件ECC可以检验2048个字节,并且生成4个字节的ECC,因此ecc.size应该为2048,ecc.bytes应该为4。而ecc.steps是通过计算得到的,即系统上电后能够获知NandFlash的每页的大小,用这个值除以ecc.size就等于ecc.steps。

include/configs/smdk2410.h文件内定义

#define CONFIG_SYS_NAND_ECCSIZE  2048

#define CONFIG_SYS_NAND_ECCBYTES  4

对于2440的板子来说,以下是2440板子的手册内容:

NAND Flash controller consists of four ECC (Error Correction Code) modules. The two ECC modules (one for
data[7:0] and the other for data[15:8]) can be used for (up to) 2048 bytes ECC Parity code generation, and the
others(one for data[7:0] and the other for data[15:8]) can be used for (up to) 16 bytes ECC Parity code generation.
— 28-bit ECC Parity Code = 22-bit Line parity + 6bit Column Parity
— 14-bit ECC Parity Code = 8-bit Line parity + 6bit Column Parity

对于ECCSIZE=256或者2048硬件ECC的实际的测试结果发现,不能达到纠正1bit的错误,所有只能采用soft_ecc 检测方法,测试方法参考:

http://www.51hei.com/bbs/dpj-32707-1.html




  • nand read.oob 

等同于nand read,只不过用于读取同地址后边的OOB部分



  • nand write

nand write - addr off|partition size  -----nand write 0x33000000 0x0200000 $(filesize);
                                      -----nand write 0x33000000 bios $(filesize);    bios(mdpartname)         
nand write - addr off|partition size  从内存addr写数据 到off 共size ;第二块的起始地址为0x20000 
   |
   V
do_nand                                ----------cmd_nand.c    
   |
   V
nand_write_skip_bad                   ----------nand_uitl.c 
   |
   V
nand_write                            ---------nand_base.c
   |
   V
nand_do_write_ops                     -----------nand_base.c
   |
   V
ecc.write_page
   |
   V
nand_write_page                      -----------nand_base.c
   |
   V
nand_write_page_hwecc(NAND_ECC_HW)  nand_write_page_swecc(NAND_ECC_SOFT)  ---nand_base.c



  • nand write.oob 



  • nand dump

nand dump[.oob] off - dump page
   |
   V
do_nand                                ----------cmd_nand.c  
   |
   V
nand_dump                              ----------cmd_nand.c  
   |
   V
mtd->read_oob   
   |
   V
nand_read_oob                         ---------nand_base.c 
   |
   V
nand_do_read_ops                      ---------nand_base.c 
   |
   V
chip->ecc.read_page_raw
   |
   V
nand_read_page_raw                   ---------nand_base.c 




内存引脚及总线配置



nXBREQ 输入: nXBREQ 总线控制请求信号,允许另一个总线控制器请求控制本地总线,nXBACK信号激活指示已经得到总线控制权

nXBACK 输出:总线应答信号。

nWAIT 输入:nWAIT请求延长当前的总线周期,只要nWAIT为低,当前的总线周期不能完成。


=========DM9000网卡的配置=======================

  • DM9000用到的引脚

S3C2440的nGCS4信号接到DM9000的AEN(Adress Enable)引脚,所以网卡的地址是从0x20000000 开始

S3C2440的LADDR2接到DM9000的CMD引脚,所以: 访问IO端口:0x20000000   访问数据端口:0x20000004


	dev->init = dm9000_init;    
	dev->halt = dm9000_halt;
	dev->send = dm9000_send;
	dev->recv = dm9000_rx;


  • 端口的读写-
/*   Read a byte from I/O port */  先把要读的寄存器地址写入DM9000_IO,再从DM9000_DATA 读出寄存器的数据
static u8 DM9000_ior(int reg)
{
	DM9000_outb(reg, DM9000_IO);
	return DM9000_inb(DM9000_DATA);
}

/*   Write a byte to I/O port*/ 先把需要写的寄存器地址写入DM9000_IO,在把需要写入寄存器的数据写入到DM9000_DATA
static void DM9000_iow(int reg, u8 value)
{
	DM9000_outb(reg, DM9000_IO);
	DM9000_outb(value, DM9000_DATA);
}




  • PHY层的读写

PHY层的读写是通过DM9000的端口寄存器转接的,转接寄存器是DM9000_EPAR   DM9000_EPCR  DM9000_EPDRH DM9000_EPDRL

/*   Read a word from phyxcer*/
static u16 phy_read(int reg)
{
	u16 val;

	/* Fill the phyxcer register into REG_0C */
	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
	DM9000_iow(DM9000_EPCR, 0xc);	/* Issue phyxcer read command */
	udelay(100);			/* Wait read complete */
	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer read command */
	val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);

	/* The read data keeps on REG_0D & REG_0E */
	DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val);
	return val;
}

/*   Write a word to phyxcer */
static void phy_write(int reg, u16 value)
{

	/* Fill the phyxcer register into REG_0C */
	DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);

	/* Fill the written data into REG_0D & REG_0E */
	DM9000_iow(DM9000_EPDRL, (value & 0xff));
	DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
	DM9000_iow(DM9000_EPCR, 0xa);	/* Issue phyxcer write command */
	udelay(500);			/* Wait write complete */
	DM9000_iow(DM9000_EPCR, 0x0);	/* Clear phyxcer write command */
	DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value);
}



  • EEPROM 的读写

EEPROM层的读写是通过DM9000的端口寄存器转接的,转接寄存器是DM9000_EPAR   DM9000_EPCR  DM9000_EPDRH DM9000_EPDRL


void dm9000_read_srom_word(int offset, u8 *to)
{
	DM9000_iow(DM9000_EPAR, offset);
	DM9000_iow(DM9000_EPCR, 0x4);
	udelay(8000);
	DM9000_iow(DM9000_EPCR, 0x0);
	to[0] = DM9000_ior(DM9000_EPDRL);
	to[1] = DM9000_ior(DM9000_EPDRH);
}

void dm9000_write_srom_word(int offset, u16 val)
{
	DM9000_iow(DM9000_EPAR, offset);
	DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
	DM9000_iow(DM9000_EPDRL, (val & 0xff));
	DM9000_iow(DM9000_EPCR, 0x12);
	udelay(8000);
	DM9000_iow(DM9000_EPCR, 0);
}


  • dm9000_send


  • dm9000_rx 


  • 调试过程


DM9000: running in 16 bit mode
MAC: 0a:1b:2c:3d:4e:5f

ping 

Loading: dm9000_send: length: 42

dm9000_send: 00: ff ff ff ff ff ff 0a 1b   以太网帧: MAC_dst MAC_src
dm9000_send: 08: 2c 3d 4e 5f 08 06 00 01 
dm9000_send: 10: 08 00 06 04 00 01 0a 1b 
dm9000_send: 18: 2c 3d 4e 5f c0 a8 01 06 
dm9000_send: 20: 00 00 00 00 00 00 c0 a8 
dm9000_send: 28: 01 08 
transmit done

============LCD控制器=========

  • LCD简介

(1)LCD(Liquid Crystal Display)俗称液晶。液晶是一种材料,液晶这种材料具有一种特点:可以在电信号的驱动下液晶分子进行旋转,旋转时会影响透光性,

因此我们可以在整个液晶面板后面用白光照(称为背光),可以通过不同电信号让液晶分子进行选择性的透光,此时在液晶面板前面看到的就是各种各样不同的

颜色,这就是LCD显示。

(2)主动发光和被动发光:有些显示器(譬如LED显示器、CRT显示器)自己本身会发光称为主动发光,有些(LCD)本身不会发光只会透光,需要背光的协助

才能看起来是发光的,称为被动发光。

(3)LCD显示原理和特点(液晶分子透光+背光):白光其实是由各种不同颜色的光组成的,所以白光被选择性透光之后可以产生各种不同颜色的光。而LCD的背

光采用的就是白光。

(4)液晶应用领域:电视机、电脑显示屏、手机显示屏、工业显示屏等····

(5)LCD的发展史(TN/STN/TFT)

TN最早。坏处是响应性不够好,有拖尾现象。

STN是TN的升级版。有效解决拖尾现象,显示更清晰。

TFT的最大特点就是超薄。TFT技术之上发展出来很多更新的技术。



  • LCD框图


  • LCD引脚



  • LCD显示过程


这是整个一幅图的概括图,其中,深蓝色的部分为实际显示出来的部分,其余的部分是非显示部分,但是非显示部分对LCD来说也是必须的。

如图中的箭头部分,LCD是按照由上到下,由左到右的顺序显示的。图中HSYNC和VSYNC是跳转信号,在每一行结束,下一行开始的时候,会产生一个HSYNC信号,在一幅图(帧)显示完毕,要显示下一张图的时候,会发出VSYNC信号。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值