04.移植u-boot

来源:http://www.cnblogs.com/Lwd-linux/archive/2017/02/03/6363564.html
-Advertisement-
Play Games

1.讀readme獲取信息 1.1 由Building the Software可知,需修改頂層makefile,指定架構和編譯器 ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?= arm-linux- endif ARCH = arm CROSS_COMPIL ...



1.讀readme獲取信息
    1.1 由Building the Software可知,需修改頂層makefile,指定架構和編譯器
    ifeq ($(HOSTARCH),$(ARCH))
    CROSS_COMPILE ?= arm-linux-
    endif

    ARCH = arm
    CROSS_COMPILE = arm-linux-
2.新建一個單板
    cd board/samsung/
 cp smdk2410 smdk2440 -rf
  cd ../../include/configs/
 cp smdk2410.h smdk2440.h
3.仿造smdk2410修改文件
    具體做法為
    grep "smdk2410" * -nR建立並修改相應的文件
4.實驗並燒寫,查看結果    
    make smdk2440_config
    make
5.下載到開發板後沒有任何輸出,閱讀代碼發現不足
    在u-boot-2016.11\arch\arm\cpu\arm920t\start.S出了問題沒有對MPLL
    進行初始化/設置時鐘,而是在board_init_f中board_early_init_f初始化
    的,但是之前是按照64MHz設置的,而現在的2440只工作在12MHz,這樣是
    無法正常工作,所以應該把board_early_init_f里對MPLL的設置給註釋掉,
    在start.S關閉看門狗後進行時鐘的設置。
    5.2處理措施:
    #if 0
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
 #else
        /* 2. 設置時鐘 400MHz */
        ldr r0, =0x4c000014
        //  mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
        mov r1, #0x05;            // FCLK:HCLK:PCLK=1:4:8
        str r1, [r0]
        /* 如果HDIVN非0,CPU的匯流排模式應該從“fast bus mode”變為“asynchronous bus mode” */
        mrc p15, 0, r1, c1, c0, 0       /* 讀出控制寄存器 */
        orr r1, r1, #0xc0000000         /* 設置為“asynchronous bus mode” */
        mcr p15, 0, r1, c1, c0, 0       /* 寫入控制寄存器 */
    
        #define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
        /* MPLLCON = S3C2440_MPLL_400MHZ */
        ldr r0, =0x4c000004
        ldr r1, =S3C2440_MPLL_400MHZ
        str r1, [r0]
 
        /* 啟動ICACHE */
        mrc p15, 0, r0, c1, c0, 0   @ read control reg
        orr r0, r0, #(1<<12)
        mcr p15, 0, r0, c1, c0, 0   @ write it back
  #endif

6.
    ①依照上述下載到2440開發板,串口輸出亂碼,這表示2440工作了,這時候出現
亂碼應該是串口方面的問題,在board_init_f函數中調用了init_sequence_f數組
裡面有一個串口初始化serial_init,點進去,裡面有個get_current函數,再進
裡面default_serial_console函數,再進,在這個函數所在的c文件(serial_s3c24x0.c)
中有個_serial_setbrg函數中裡面有個get_PCLK函數進去該函數中有這麼一句
”#ifdef CONFIG_S3C2440”但是這個巨集沒有被定義,這個代表定義它就支持了2440,我們就
在include/configs/smdk2440.h中定義一下就可以了.然後再重新編譯,編譯出來的u-boot_04.bin
下載到2440中我們就可以看到串口列印出信息了
    ②改完後編譯,燒寫,串口有輸出了,但是亂碼,估計是波特率的問題。分析代碼
board_init_r
    init_sequence_r
        initr_serial
            serial_initialize
                s3c24xx_serial_initialize
                    serial_register(&s3c24xx_serial0_device)
                        s3c24xx_serial0_device
                            INIT_S3C_SERIAL_STRUCTURE
                                s3serial##port##_setbrg
                                    serial_setbrg_dev
                                        _serial_setbrg
                                            get_PCLK
                                                get_HCLK(#ifdef CONFIG_S3C2440)

7.支持NOR FLASH
    board_init_r
        init_sequence_r
            initr_flash
                flash_init
                    if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
                    flash_get_size(cfi_flash_bank_addr(i), i);    
                            //用老方法檢測是否識別出來,否則就用新方法
為什麼老方法無法識別出nor flash?
flash_detect_legacy
    jedec_flash_match
        jedec_table//該數組裡沒有我們需要的nor flash的型號和參數,需要手動輸入
        
        {                                                                                 
        .mfr_id     = (u16)MX_MANUFACT,                                               
        .dev_id     = 0x2249,                                                         
        .name       = "MX29LV160D",                                                   
        .uaddr      = {                                                               
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */  
         },                                                                            
        .DevSize    = SIZE_2MiB,                                                      
        .CmdSet     = P_ID_AMD_STD,                                          
        .NumEraseRegions= 4,                                                          
        .regions    = {                                                               
            ERASEINFO(0x10000, 31),                                                   
            ERASEINFO(0x08000, 1),                                                    
            ERASEINFO(0x02000, 2),                                                    
            ERASEINFO(0x04000, 1),                                                    
        }                                                                             
    },  
測試下norflash能否正確讀寫,用以下u-boot命令:
cp.b 0 30000000 80
cmp.b 0 30000000 80
發現讀norflash沒有問題。再用以下幾條命令測試寫norflash:
mw.b 30000000 12 3
protect off all
erase 0 ffff
cp.b 30000000 0 3
md.b 0 3;
發現也是121212;因此寫norflash成功,至此u-boot已經支持JZ2440開發板的nor flash;

8.支持nand flash
    支持了norflash後,發現nandflash未識別出來,啟動uboot顯示NAND: 0 Byte。在代碼
    中搜索"NAND:",定位到common目錄中的board_r.c的initr_nand函數:
    nand_init
    nand_init_chip
        board_nand_init
            設置nand_chip結構體, 提供底層的操作函數
        nand_scan
            nand_scan_ident
                nand_set_defaults
                    chip->select_chip = nand_select_chip;
                    chip->cmdfunc = nand_command;
                    chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
                    
                nand_get_flash_type
                    chip->select_chip
                    chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
                            nand_command()  // 即可以用來發命令,也可以用來發列地址(頁內地址)、行地址(哪一頁)
                                chip->cmd_ctrl
                                        s3c2440_hwcontrol
                                
                    chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                    *maf_id = chip->read_byte(mtd);
                    *dev_id = chip->read_byte(mtd);
board_nand_init函數主要與單板有關的初始化,uboot的開發人員已經把與單板無關的一些
    協議設置完成了,而把與單板有關的初始化單獨列為一層,我們需要做的僅僅是把單板相關的
這一層移植即可。因此這裡主要關註board_nand_init函數。我們的board_nand_init函數在
drivers/mtd/nand/s3c2410_nand.c中定義了。進入其中仔細分析代碼,發現對nfconf寄存器
的初始化,2410的設置並不適用於2440,於是修改代碼如下:
//cfg = S3C2410_NFCONF_EN;  
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);  
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);  
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);  
writel(cfg, &nand_reg->nfconf);  

#define S3C2410_NFCONF_TACLS(x)    ((x)<<12)  
#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<8)  
#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<4)  
往下看,後面設置了2410的nandflash的底層函數,其中selcet_chip被設置為NULL了,我們在
nand_scan里往下看,nand_scan_ident到nand_set_defaults,如果某個底層函數是空,則會
為其分配一個預設的函數,其中的預設的select_chip函數並不完整,不能用,並且後面的代碼
調用到select_chip函數,因此這裡需要我們自己寫一個select_chip函數。
在s3c2410_nand.c中定義如下:

static void s3c24x0_nandselect(struct mtd_info *mtd, int chipnr)                      
 {                                                                                     
     struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();                          
     switch (chipnr) {                                                                 
     case -1:                                                                          
     writel(readl(&nand_reg->nfcont) | (1 << 1),&nand_reg->nfcont);                    
         break;                                                                        
     case 0:                                                                           
     writel(readl(&nand_reg->nfcont) & ~(1 << 1),&nand_reg->nfcont);                   
         break;                                                                        
     default:                                                                          
         BUG();                                                                        
     }                                                                                 
 }  
在board_nand_init函數中設置select_chip函數

nand->select_chip = s3c24x0_nandselect;  
繼續往下分析,發現s3c24x0_hwcontrol函數不適用於2440,修改如下:

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)       
{                                                                                     
    struct nand_chip *chip = mtd->priv;                                               
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();                              
                                                                                     
    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);                                 
                                                                                      
    if (ctrl & NAND_CTRL_CHANGE) {                                                    
        ulong IO_ADDR_W = (ulong)nand;                                                
                                                                                      
        if (!(ctrl & NAND_CLE))                                                       
            IO_ADDR_W |= S3C2410_ADDR_NCLE;//NFADDR                                   
        if (!(ctrl & NAND_ALE))                                                       
            IO_ADDR_W |= S3C2410_ADDR_NALE;//NFCMD                                    
                                                                                      
        chip->IO_ADDR_W = (void *)IO_ADDR_W;                                          
                                                                                      
        if (ctrl & NAND_NCE)                                                          
            writel(readl(&nand->nfcont) & ~(1<<1),                                    
                   &nand->nfcont);//chip select                                       
        else                                                                          
            writel(readl(&nand->nfcont) | (1<<1),                                     
                   &nand->nfcont);//deselcet                                          
    }                                                                                 
                                                                                     
     if (cmd != NAND_CMD_NONE)                                                         
         writeb(cmd, chip->IO_ADDR_W);                                                 
     else //若cmd = NAND_CMD_NONE,寫地址要恢復為nfdata   
    chip->IO_ADDR_W = (void *)&nand->nfdata;  
}  
這個s3c24x0_hwcontrol函數可以根據crtl值的不同更改寫指針chip->IO_ADDR_W,
從而實現既能寫地址,又能寫命令,當crtl & NAND_CRTL_CHANGE=1時,chip->ADDR_W
就會被賦一次值。在nand_set_defaults中,chip->cmdfunc = nand_command,這個
函數里會多次調用chip->cmd_crtl(即我們的s3c24x0_hwcontrol函數)來實現發命令
和發地址。由於s3c2410_nand.c中未定義chip->cmdfunc,就會使用預設的nand_command。
這裡最好將nand_command改為 nand_command_lp,因為我們的nandflash是大頁的,每頁數據
有2K+64個位元組。仔細閱讀nand_command_lp你就會瞭解s3c24x0_hwcontrol應該實現的功能。
在nand_command_lp中,我們發現每個階段調用chip->cmd_crtl之後,最後都會調用
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE)(寫地址結束後調用一次,寫命令結束後調用一次),
仔細思考你就會想到,chip->IO_ADDR_W在board_nand_init中是被初始化為指向nfdata的,
如果我們調用完s3c24x0_hwcontrol,chip->IO_ADDR_W是指向nfaddr或nfcmd,是否要將其還原呢
,否則下次如果要想寫數據不是會出錯嗎(寫數據不用調用chip->cmd_ctrl),
因此chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE)的用意應該是還原
chip->IO_ADDR_W為nfdata,所以上面的s3c24x0_hwcontrol的最後我加上了個else分支。經過實驗,
不加這一句,nandflash讀寫會出錯。
另外,S3C2410_ADDR_NCLE和S3C2410_ADDR_NALE兩個巨集要修改為如下:
#define S3C2410_ADDR_NALE  8  
#define S3C2410_ADDR_NCLE  0xC  

這裡使用到了NFCONT寄存器,而2410並無該寄存器,之前未對其進行初始化,因此在
board_nand_init中要對該寄存器進行初始化設置:
/* 初始化ECC,禁止片選,使能NAND Flash控制器 */  
writel((1<<4)|(1<<1)|(1<<0),&nand_reg->nfcont);  
同時,s3c24x0_nand結構體中由於原來定義了CONFIG_S3C2410巨集,導致沒有NFCONT等寄存器,
因此在smdk2410.h中去掉該巨集。編譯,燒寫到開發板,識別出nandflash為256M。我們再試試
Nandflash的讀寫。首先試試寫nandflash,用以下命令:

nand erase 0 4

mw.l 30000000 12345678

nand write 30000000 0 4

nand dump 0

發現nandflash寫入12345678成功。然後再試讀nandflash,使用命令:
mw.l 30000000 22222222

md.l 30000000

nand read 30000000 0 4

md.l 30000000

發現成功讀出12345678。至此u-boot已經成功支持JZ2440的nandflash。

9.支持DM9000
啟動uboot,列印出Net: CS8900-0,而我們的網卡是DM9000,於是在代碼中搜索“Net:”,
定位到common/board_r.c的initr_net函數,一路追蹤eth_initialize,eth_common_init,
一直到board\samsung\smdk2410\smdk2410.c的board_eth_init函數:
int board_eth_init(bd_t *bis)  
{  
    int rc = 0;  
#ifdef CONFIG_CS8900  
    rc = cs8900_initialize(0, CONFIG_CS8900_BASE);  
#endif  
    return rc;  
}  
這裡是對CS8900進行了初始化,我們要對DM9000進行初始化,通過查看
drivers/net/Makefile,發現要包含dm9000x.c的文件,要定義CONFIG_DRIVER_DM9000
這個巨集,我們也要註釋掉CONFIG_CS8900巨集。同時查看dm9000x.c,裡面有一個
dm9000_initialize函數,於是仿照cs8900來寫dm9000的初始化函數。

int board_eth_init(bd_t *bis)  
{  
    int rc = 0;  
#ifdef CONFIG_CS8900  
    rc = cs8900_initialize(0, CONFIG_CS8900_BASE);  
#endif  
 
#ifdef CONFIG_DRIVER_DM9000  
        rc = dm9000_initialize(bis);    
#endif  
    return rc;  
}  
配置文件smdk2410.h修改如下:

//#define CONFIG_CS8900     /* we have a CS8900 on-board */                           
//#define CONFIG_CS8900_BASE    0x19000300  
//#define CONFIG_CS8900_BUS16   /* the Linux driver does accesses as shorts */        
#define CONFIG_DRIVER_DM9000  
保存,編譯,提示一大堆錯誤,提示dm9000x.c中的'DM9000_DATA' undeclared, 'DM9000_IO' undeclared等等,
結合上面的CS8900的一些巨集,看來這些巨集需要我們自己在smdk2410.h中定義,在linux中使用grep "DM9000_DATA" * -nR
命令搜索,看看其他板子的配置文件是如何定義這些巨集的,可以適當參考下,結合原理圖和2440手冊,smdk.h中定義如下:

#define CONFIG_DRIVER_DM9000  
#define CONFIG_DM9000_BASE   0x20000000  
#define DM9000_IO        CONFIG_DM9000_BASE  
#define DM9000_DATA      (CONFIG_DM9000_BASE + 4)       
#define CONFIG_DM9000_USE_16BIT        1  
第四行之所以加4是因為DM9000上的CMD引腳接到了LADDR2上。

編譯,下載到開發板,提示錯誤Error: dm9000 address not set.

在代碼中搜索“address not set”,有兩個函數會列印這句話,分別是net/eth.c里的
eth_post_probe函數和eth_write_hwaddr函數。這個eth_post_probe函數是uboot里網卡
驅動的probe函數,而eth_write_hwaddr會在eth_initialize里被調用,因此這裡應該是
eth_write_hwaddr列印出來的。閱讀這個函數的代碼,發現應該是未設置ethaddr即網卡
的MAC地址導致報錯。進入到eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr)里分析:

int eth_getenv_enetaddr_by_index(const char *base_name, int index,  
                 uchar *enetaddr)  
{  
    char enetvar[32];  
    sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);  
    return eth_getenv_enetaddr(enetvar, enetaddr);  
}  
分析得知,這個函數最終將存放MAC地址的環境變數的值存入env_enetaddr數組中,那麼這個
環境變數名稱由
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index)確定。在eth_initialize里eth_write_hwaddr是這樣被調用的:
eth_write_hwaddr(dev, "eth", dev->index)。上面的basename應該對應於"eth"。結合上面的sprintf函數,如果index函數存在,則
環境變數名稱為eth<index>addr,否則為ethaddr。這裡index的值即為eth_write_hwaddr(dev, "eth", dev->index)傳入的dev->index,
在eth.c中搜索dev->index,看在哪裡設置它的值。結果發現eth_register里會設置:

int eth_register(struct eth_device *dev)  
{  
    struct eth_device *d;  
    static int index;  
 
    assert(strlen(dev->name) < sizeof(dev->name));  
 
    if (!eth_devices) {  
        eth_devices = dev;  
        eth_current = dev;  
        eth_current_changed();  
    } else {  
        for (d = eth_devices; d->next != eth_devices; d = d->next)  
            ;  
        d->next = dev;  
    }  
 
    dev->state = ETH_STATE_INIT;  
    dev->next  = eth_devices;  
    dev->index = index++;  
 
    return 0;  
}  
那麼這個函數什麼時候會被調用呢,搜索發現每一款網卡的文件里會調用這個函數來註冊網卡,我們的DM9000x.c里也有,我們只有一個網卡,
因此只會調用一次,index是靜態變數,未賦初始值則預設初始值為0,因此dev->index = index++(註意計算順序),dec->index = 0,所以
環境變數名稱為ethaddr。所以我們需要定義一個名為ethaddr環境變數。在include/env_default.h中有預設環境變數的設置,我們在其中
加入ethaddr環境變數的預設值,這個值我是參照電腦網卡MAC地址隨便寫的。

#elif defined(DEFAULT_ENV_INSTANCE_STATIC)                                            
static char default_environment[] = {                                                 
#else                                                                                 
const uchar default_environment[] = {                                                 
#endif                                                                                
#ifdef CONFIG_ETHADDR                                                                 
    "ethaddr=" CONFIG_ETHADDR   "\0"                                                  
#endif                                                                                
#ifdef  CONFIG_ENV_CALLBACK_LIST_DEFAULT                                              
    ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"                        
#endif  
在smdk2410.h中設置CONFIG_ETHADDR巨集:

#define CONFIG_ETHADDR          "00:0c:29:91:dc:5f"  
保存,編譯,燒寫,啟動Uboot,網卡正常啟動。設置一下開發板ip:set ipaddr 192.168.0.2。網線連接開發板和路由器,ping一下主機ip:

ping 192.168.0.100,能夠Ping通。再試試能不能用tftp下載文件,

set serverip 192.168.0.100

tftp 30000000 u-boot.bin

使用tftp下載文件也成功,至此,DM9000網卡已經支持。

10.設置nand分區

在下載內核或文件系統時,我們可以直接在命令中寫明燒到nandflash
的具體地址,但較麻煩,我們可以給nandflash分區,這樣就可直接寫
燒到那個分區就行了,較為方便。如何設置呢?首先我們在uboot中輸入
mtdparts命令,看看預設的分區,結果提示mtdids not defined, no default present。
搜索"mtdids not defined",定位到common/cmd_mtdparts.c的mtdparts_init函數中,
分析發現是mtdids_default為空。mtdids以及另一個重要的變數mtdparts定義如下:

#if defined(MTDIDS_DEFAULT)  
static const char *const mtdids_default = MTDIDS_DEFAULT;  
#else  
 $ static const char *const mtdids_default = NULL;  
#endif  
 
#if defined(MTDPARTS_DEFAULT)  
static const char *const mtdparts_default = MTDPARTS_DEFAULT;  
#else  
static const char *const mtdparts_default = NULL;  
#endif  
因此,我們需要在smdk2410.h中定義MTDIDS_DEFAULT,MTDPARTS_DEFAULT這兩個巨集。如何定義這兩個巨集呢,cmd_mtdparts.c中註釋里有例子示範了:

/* Examples:
 *
 * 1 NOR Flash, with 1 single writable partition:
 * mtdids=nor0=edb7312-nor
 * mtdparts=mtdparts=edb7312-nor:-
 *
 * 1 NOR Flash with 2 partitions, 1 NAND with one
 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
 *
 */  
結合例子和其他開發板的配置文件,我們的定義如下:

#define MTDIDS_DEFAULT          "nand0=s3c2440-nand.0"  
#define MTDPARTS_DEFAULT        "mtdparts=s3c2440-nand.0:256k(bootloader),"\         
                                "128k(params),2m(kernel),"\                          
                                 "-(rootfs)"   
保存,編譯,燒寫。啟動u-boot後執行mtdparts命令,提示mtdparts variable not set, see 'help mtdparts',no partitions defined

那就執行help mtdparts命令看看,發現這麼一句:mtdparts default - reset partition table to defaults

可能要執行一下mtdparts default,執行後發現不再提示錯誤。但總不能每次都要手動執行一次命令吧。於是,我們在代碼里執行這麼一個命令。
在board_r.c的run_main_loop里修改如下:



static int run_main_loop(void)  
{  
#ifdef CONFIG_SANDBOX  
    sandbox_main_loop_init();  
#endif  
    /* main_loop() can return to retry autoboot, if so just run it again */  
     run_command("mtdparts default",0);//添加這一行代碼  
     for (;;)  
        main_loop();  
     return 0;  
編譯燒寫後,啟動u-boot執行mtdparts命令,不再提示錯誤,直接列出了分區,我們試著往kernel分區里燒寫uImage,同時要想啟動內核,
必須要設置預設參數bootargs和bootcmd,根據environment.h文件,我們要在smdk2410.h里設置CONFIG_BOOTARGS和CONFIG_BOOTCOMMAND兩個巨集,如下:

#define CONFIG_BOOTARGS        "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"  
#define CONFIG_BOOTCOMMAND    "nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0"  
編譯燒寫,啟動u-boot,使用tftp下載uImage到30000000,使用下麵的命令

nand erase.chip

nand write.jffs2 30000000 kernel 1c08e8

下載內核到kernel分區成功,並且已經可以啟動內核了。

  之前我們設置環境變數,都未執行save命令,因為我們還未設置環境變數保存地址,現在我們想讓環境變數保存在我們設置的params分區上。
搜索saveenv函數,發現env_flash.c和env_nand.c都有這個函數,通過查看common/Makefile發現要通過定義CONFIG_ENV_IS_IN_NAND才能包含env_nand.c,
從而將環境變數保存在nandflash上。同時還要設置CMD_SAVEENV,CONFIG_ENV_RANGE,CONFIG_ENV_OFFSET等巨集,修改配置文件如下:


#define CONFIG_ETHADDR          "00:0c:29:91:dc:5f"                                  
//#define CONFIG_ENV_ADDR         (CONFIG_SYS_FLASH_BASE + 0x070000)                   
//#define CONFIG_ENV_IS_IN_FLASH                                                       
//#define CONFIG_ENV_SIZE         0x10000     
#define     CMD_SAVEENV  
#define  CONFIG_ENV_IS_IN_NAND  
#define  CONFIG_ENV_SIZE     0x20000  
#define  CONFIG_ENV_OFFSET   0  
編譯燒寫後,執行命令:

set ipaddr 192.168.0.2

set serverip 192.168.0.100

save

然後reset,發現原來一直提示的一個警告Warning - bad CRC, using default environment已經沒了,因為我們自己保存了環境變數。print一下,環境變數和我們設置的一樣。


11.

    之前我們的u-boot已經能夠啟動內核了,現在我們試試能不能掛載文件系統,首先先下載jffs2格式的文件系統到30000000。然後使用命令
nand write.jffs2 30000000 rootfs 59ad78燒寫到nandflash的rootfs分區,在bootargs環境變數里添加rootfstype=jffs2,然後重啟開發板,
發現內核能夠掛載文件系統,證明我們的uboot支持燒寫jffs2文件系統。
    再試試yaffs2文件系統,同樣下載到30000000,使用nand write.yaffs2 或nand write.yaffs發現都沒有這個命令,於是我們進入nand的命令文件common/cmd_nand.c,
在do_nand函數里,有nand read或write的代碼,而其中有對jffs2的支持,卻並沒有對yaffs2的支持。以前的老版本uboot是有對yaffs文件系統燒寫的支持的,於是我們參考老版本
的uboot代碼,在do_nand函數里的nand write/read部分加上一段代碼,如下:

#ifdef CONFIG_CMD_NAND_TRIMFFS  
        } else if (!strcmp(s, ".trimffs")) {  
            if (read) {  
                printf("Unknown nand command suffix '%s'\n", s);  
                 return 1;  
            }  
            ret = nand_write_skip_bad(nand, off, &rwsize, NULL,  
                        maxsize, (u_char *)addr,  
                        WITH_DROP_FFS | WITH_WR_VERIFY);  
#endif  
#ifdef CONFIG_CMD_NAND_YAFFS  
        } else if (!strcmp(s, ".yaffs")) {  
            if (read) {  
                printf("Unknown nand command suffix '%s'.\n", s);  
                return 1;  
            }  
            ret = nand_write_skip_bad(nand, off, &rwsize,NULL,//這裡參數和老版比要修改下  
                        maxsize,(u_char *)addr,  
                        WITH_YAFFS_OOB);  
#endif  
在nand_help_text[]里添加nand write.yaffs的幫助信息:

"nand read.raw - addr off|partition [count]\n"  
    "nand write.raw - addr off|partition [count]\n"  
    "    Use read.raw/write.raw to avoid ECC and access the flash as-is.\n"  
#ifdef CONFIG_CMD_NAND_YAFFS  
    "nand write.yaffs - addr off|partition size\n"  
    "    write 'size' bytes starting at offset 'off' with yaffs format\n"  
    "    from memory address 'addr', skipping bad blocks.\n"  
#endif  
nand_write_skip_bad函數內部也要修改:

if (actual)  
        *actual = 0;   
#ifdef CONFIG_CMD_NAND_YAFFS                                                         
     if (flags & WITH_YAFFS_OOB) {                                                    
        if (flags & ~WITH_YAFFS_OOB)                                                 
            return -EINVAL;                                                          
                                                                                     
        int pages;                                                                   
        pages = nand->erasesize / nand->writesize;                                   
        blocksize = (pages * nand->oobsize) + nand->erasesize;                       
        if (*length % (nand->writesize + nand->oobsize)) {                           
            printf ("Attempt to write incomplete page"                               
                " in yaffs mode\n");                                                 
            return -EINVAL;                                                          
        }                                                                            
    } else                                                                           
#endif                                                                               
    {                                                                                
        blocksize = nand->erasesize;                                          

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Oracle 註意Oracle分成兩個文件,下載完後,將兩個文件解壓到同一目錄下即可。 路徑名稱中,最好不要出現中文,也不要出現空格等不規則字元。 官方下地址: http://www.oracle.com/technetwork/database/enterprise-edition/downl ...
  • 類別 「網站分類」SQL Server SQLServer行版本控制 一併發控制 1.1併發控制定義 併發控制分為樂觀併發控制和悲觀併發控制這2種併發控制模型,如果2個進程試圖在同一時刻修改同一數據時都會發生衝突。區別在於,悲觀併發是在衝突前進行防止,樂觀併發是在發生後採用某種方法來處理衝突。 1. ...
  • 在剛剛畢業的時候,當時的領導就問了一個問題——個性化推薦與精準營銷的區別,當時朦朦朧朧回答不出。現在想想,他們可以說是角度不同。精準營銷可以理解為幫助物品尋找用戶,而個性化推薦則是幫助用戶尋找物品。 什麼是推薦系統? 那麼什麼是推薦系統呢?簡單的來說,就是幫助用戶和物品聯繫起來,讓信息展現在對他感謝 ...
  • /*自定義oracle的分割函數*//*定義一個type,用戶接收返回的數據集合*/create or replace type splitType as table of varchar2(4000); /* 參數1: 被分割的字元串 參數2:分割字元串,預設是英文逗號*/create or re ...
  • 當創建一個表時,需要為表的各個列指定數據類型,Oracle的數據類型主要有5種,字元類型、數值類型、日期時間類型、LOB類型和偽列。 一、字元類型 1、CHAR類型 定長字元串,長度為1~2000位元組,如果定義時未指定大小,預設為1,使用時,若存儲的值大小小於指定的長度,則用空格填充剩餘長度, 若大 ...
  • 當你開始編寫 Apache Spark 代碼或者瀏覽公開的 API 的時候,你會遇到各種各樣術語,比如transformation,action,RDD 等等。 瞭解到這些是編寫 Spark 代碼的基礎。 同樣,當你任務開始失敗或者你需要透過web界面去瞭解自己的應用為何如此費時的時候,你需要去瞭解 ...
  • 非電腦專業,導師基本做單片機的項目,所以基本靠自學,經過兩年實踐,證明該學習路線基本可靠 所以分亨給對嵌入式Linux感興趣的學弟學妹 要學的東西真的很多,這裡僅提供入門之道,分為基礎知識和實踐兩個部分 第一部分,專業知識 C語言學習 《C和指針》 《C專家編程》 《C陷阱與缺陷》 上面三本書,認 ...
  • 1、安裝kernel-debuginfo-common 和 kernel-debuginfo(下載地址:http://debuginfo.centos.org/6/x86_64/),安裝之前,先通過uname -r 確認內核版本 [root@xxxmysqlbkuat01 ~]# uname -r ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...