rtthread移植到jz2440之BootLoader

来源:https://www.cnblogs.com/Ye-Jason/archive/2019/01/09/10245038.html
-Advertisement-
Play Games

從2016年第一次接觸rtthread,感覺很容易上手,記得一個項目是小飛行器上的IPC,趁著空閑,手裡有一塊jz2440的板子,準備在這塊板子上跑起來rtthread,查了很多資料,最後決定自己寫一個簡單的BootLoader啟動板子,啟動rtthread系統。下麵是簡單的BootLoader源代 ...


從2016年第一次接觸rtthread,感覺很容易上手,記得一個項目是小飛行器上的IPC,趁著空閑,手裡有一塊jz2440的板子,準備在這塊板子上跑起來rtthread,查了很多資料,最後決定自己寫一個簡單的BootLoader啟動板子,啟動rtthread系統。下麵是簡單的BootLoader源代碼。

init.c

主要是記憶體控制器初始化、串口初始化及與串口相關函數實現、nandflash初始化及讀寫功能。

/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))

/* GPIO */
#define GPHCON              (*(volatile unsigned long *)0x56000070)
#define GPHUP               (*(volatile unsigned long *)0x56000078)

/* UART registers*/
#define ULCON0              (*(volatile unsigned long *)0x50000000)
#define UCON0               (*(volatile unsigned long *)0x50000004)
#define UFCON0              (*(volatile unsigned long *)0x50000008)
#define UMCON0              (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
#define UTXH0               (*(volatile unsigned char *)0x50000020)
#define URXH0               (*(volatile unsigned char *)0x50000024)
#define UBRDIV0             (*(volatile unsigned long *)0x50000028)

unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054;

void led_on(void)
{
    /* 配置GPF4為輸出引腳 */
    *pGPFCON = 0x1500;
    /* 設置GPF4輸出0 */
    *pGPFDAT = 0;    
}

void led_off(void)
{
    /* 配置GPF4為輸出引腳 */
    *pGPFCON = 0x1500;
    /* 設置GPF4輸出0 */
    *pGPFDAT = 0xff;    
}
#define TXD0READY   (1<<2)


void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);

extern void puthex(unsigned int val);
extern void puts(char *str);
int isBootFromNorFlash(void)
{
    volatile int *p = (volatile int *)0;
    int val;

    val = *p;
    *p = 0x12345678;
    if (*p == 0x12345678)
    {
        /* 寫成功, 是nand啟動 */
        *p = val;
        return 0;
    }
    else
    {
        /* NOR不能像記憶體一樣寫 */
        return 1;
    }
}

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{    
    int i = 0;
    
    /* 如果是NOR啟動 */
    if (isBootFromNorFlash())
    {
        while (i < len)
        {
            dest[i] = src[i];
            i++;
        }
    }
    else
    {
        //nand_init();
        nand_read((unsigned int)src, dest, len);
    }
}

void clear_bss(void)
{
    extern int __bss_start, __bss_end;
    int *p = &__bss_start;
    
    for (; p < &__bss_end; p++)
        *p = 0;
}

void nand_init(void)
{
#define TACLS   0
#define TWRPH0  1
#define TWRPH1  0
    /* 設置時序 */
    NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    /* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */
    NFCONT = (1<<4)|(1<<1)|(1<<0);    
}

void nand_select(void)
{
    NFCONT &= ~(1<<1);    
}

void nand_deselect(void)
{
    NFCONT |= (1<<1);    
}

void nand_cmd(unsigned char cmd)
{
    volatile int i;
    NFCMMD = cmd;
    for (i = 0; i < 10; i++);
}

void nand_addr(unsigned int addr)
{
    unsigned int col  = addr % 2048;
    unsigned int page = addr / 2048;
    volatile int i;

    NFADDR = col & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR = (col >> 8) & 0xff;
    for (i = 0; i < 10; i++);
    
    NFADDR  = page & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR  = (page >> 8) & 0xff;
    for (i = 0; i < 10; i++);
    NFADDR  = (page >> 16) & 0xff;
    for (i = 0; i < 10; i++);    
}


void nand_wait_ready(void)
{
    while (!(NFSTAT & 1));
}

unsigned char nand_data(void)
{
    return NFDATA;
}
void nand_chip_id(void)
{ 
    unsigned char buf[5]={0};
    
    nand_select(); 
    nand_cmd(0x90);
    nand_addr(0x00);

    buf[0] = nand_data();
    buf[1] = nand_data();    
    buf[2] = nand_data();
    buf[3] = nand_data();
    buf[4] = nand_data();    
    nand_deselect();     

    puts("maker id\n\r");
    puthex(buf[0]);    
    puts("\n\r");
    puts("device id\n\r");
    puthex(buf[1]);    
    puts("\n\r");
    puts("3rd byte\n\r");
    puthex(buf[2]);    
    puts("\n\r");
    puts("4th byte\n\r");
    puthex(buf[3]);        
    puts("\n\r");        
    puts("page  size\n\r");
    puthex(1  <<  (buf[3] & 0x03));    
    puts("\n\r");
    puts("block size\n\r");
    puthex(64 << ((buf[3] >> 4) & 0x03));
    puts("\n\r");    
    puts("5th byte\n\r");
    puthex(buf[4]);            
}

void nand_w_data(unsigned char val)
{
    NFDATA = val;
}

void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int col = addr % 2048;
    int i = 0;
        
    /* 1. 選中 */
    nand_select();

    while (i < len)
    {
        /* 2. 發出讀命令00h */
        nand_cmd(0x00);

        /* 3. 發出地址(分5步發出) */
        nand_addr(addr);

        /* 4. 發出讀命令30h */
        nand_cmd(0x30);

        /* 5. 判斷狀態 */
        nand_wait_ready();

        /* 6. 讀數據 */
        for (; (col < 2048) && (i < len); col++)
        {
            buf[i] = nand_data();
            i++;
            addr++;
        }
        
        col = 0;
    }

    /* 7. 取消選中 */        
    nand_deselect();
}

void nand_addr_byte(unsigned char addr)
{
    volatile int i;
    NFADDR = addr;
    for(i=0; i<10; i++);
}


int nand_erase(unsigned int addr, unsigned int len)
{
    int page = addr / 2048;

    if (addr & (0x1FFFF))
    {
        puts("nand_erase err, addr is not block align\n\r");
        return 0;
    }
    
    if (len & (0x1FFFF))
    {
        puts("nand_erase err, len is not block align\n\r");
        return 0;
    }
    
    nand_select(); 

    while (1)
    {
        page = addr / 2048;
        
        nand_cmd(0x60);
        /* row/page addr */
        nand_addr_byte(page & 0xff);
        nand_addr_byte((page>>8) & 0xff);
        nand_addr_byte((page>>16) & 0xff);
        nand_cmd(0xD0);
        nand_wait_ready();

        len -= (128*1024);
        if (len == 0)
            break;
        addr += (128*1024);
    }
    
    nand_deselect();     
    return 1;
}

void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
{
    int page = addr / 2048;
    int col  = addr & (2048 - 1);
    int i = 0;

    nand_select(); 

    while (1)
    {
        nand_cmd(0x80);

        nand_addr(addr);

        /* 發出數據 */
        for (; (col < 2048) && (i < len); )
        {
            nand_w_data(buf[i++]);
        }
        nand_cmd(0x10);
        nand_wait_ready();

        if (i == len)
            break;
        else
        {
            /* 開始下一個迴圈page */
            col = 0;
            page++;
        }
        
    }
    
    nand_deselect();     
}

#define PCLK            50000000    // init.c中的clock_init函數設置PCLK為50MHz
#define UART_CLK        PCLK        //  UART0的時鐘源設為PCLK
#define UART_BAUD_RATE  115200      // 波特率
#define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)

/*
 * 初始化UART0
 * 115200,8N1,無流控
 */
void uart0_init(void)
{
    GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    GPHUP   = 0x0c;     // GPH2,GPH3內部上拉

    ULCON0  = 0x03;     // 8N1(8個數據位,無較驗,1個停止位)
    UCON0   = 0x05;     // 查詢方式,UART時鐘源為PCLK
    UFCON0  = 0x00;     // 不使用FIFO
    UMCON0  = 0x00;     // 不使用流控
    UBRDIV0 = UART_BRD; // 波特率為115200
}

/*
 * 發送一個字元
 */
void putc(unsigned char c)
{
    /* 等待,直到發送緩衝區中的數據已經全部發送出去 */
    while (!(UTRSTAT0 & TXD0READY));
    
    /* 向UTXH0寄存器中寫入數據,UART即自動將它發送出去 */
    UTXH0 = c;
}

void puts(char *str)
{
    int i = 0;
    while (str[i])
    {
        putc(str[i]);
        i++;
    }
}

void puthex(unsigned int val)
{
    /* 0x1234abcd */
    int i;
    int j;
    
    puts("0x");

    for (i = 0; i < 8; i++)
    {
        j = (val >> ((7-i)*4)) & 0xf;
        if ((j >= 0) && (j <= 9))
            putc('0' + j);
        else
            putc('A' + j - 0xa);
        
    }
    
}
View Code

start.S

    a、 初始化硬體:關看門狗、設置時鐘、設置SDRAM、初始化NAND FLASH     b、如果bootloader比較大,要把它重定位到SDRAM     c、把內核從NAND FLASH讀到SDRAM    e、設置"要傳給內核的參數"  
#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
#define MEM_CTL_BASE    0x48000000

.text
.global _start
_start:

/* 1. 關看門狗 */
    ldr r0, =0x53000000
    mov r1, #0
    str r1, [r0]
    
/* 配置GPF4為輸出引腳
 * 把0x100寫到地址0x56000050
 */
    ldr r1, =0x56000050
    ldr r0, =0x1500    /* mov r0, #0x100 */
    str r0, [r1]
/* 設置GPF4輸出高電平 
 * 把0寫到地址0x56000054
 */
    ldr r1, =0x56000054
    ldr r0, =0    /* mov r0, #0 */
    str r0, [r1]
/* 2. 設置時鐘 */
    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        /* 寫入控制寄存器 */

    /* 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


/* 3. 初始化SDRAM */
    ldr r0, =MEM_CTL_BASE
    adr r1, sdram_config     /* sdram_config的當前地址 */
    add r3, r0, #(13*4)
1:
    ldr r2, [r1], #4
    str r2, [r0], #4
    cmp r0, r3
    bne 1b

/* 4. 重定位 : 把bootloader本身的代碼從flash複製到它的鏈接地址去 */
    ldr sp, =0x34000000

    bl nand_init

    mov r0, #0
    ldr r1, =_start
    ldr r2, =__bss_start
    sub r2, r2, r1
    
    bl copy_code_to_sdram
    bl clear_bss
    
/* 5. 執行main */
    ldr lr, =halt
    ldr pc, =main
halt:
    b halt

sdram_config:
    .long 0x22011110     //BWSCON
    .long 0x00000700     //BANKCON0
    .long 0x00000700     //BANKCON1
    .long 0x00000700     //BANKCON2
    .long 0x00000700     //BANKCON3  
    .long 0x00000700     //BANKCON4
    .long 0x00000700     //BANKCON5
    .long 0x00018005     //BANKCON6
    .long 0x00018005     //BANKCON7
    .long 0x008C04F4     // REFRESH
    .long 0x000000B1     //BANKSIZE
    .long 0x00000030     //MRSRB6
    .long 0x00000030     //MRSRB7
View Code

boot.c

實現把rtthread從nandflash讀到SDRAM

extern void uart0_init(void);
extern void nand_read(unsigned int addr, unsigned char *buf, unsigned int len);
extern void puts(char *str);
extern void puthex(unsigned int val);
extern void led_on(void);
extern void led_off(void);

int strlen(char *str)
{
    int i = 0;
    while (str[i])
    {
        i++;
    }
    return i;
}

void strcpy(char *dest, char *src)
{
    while ((*dest++ = *src++) != '\0');
}

int main(void)
{
    void (*theKernel)( unsigned int params);
    unsigned int *p = 0x30000000;
    /* 0. 幫內核設置串口: 內核啟動的開始部分會從串口列印一些信息,但是內核一開始沒有初始化串口 */
    uart0_init();
    
    /* 1. 從NAND FLASH里把內核讀入記憶體 */
    puts("Copy kernel from nand\n\r");
    nand_read(0x0, (unsigned char *)0x30000000, 0x100000);
    puts("\n\r");
    led_off();
    
    /* 3. 跳轉執行 */
    puts("Boot rtthread\n\r");
    theKernel = (void (*)(unsigned int))0x30000000;
    theKernel(0x30000000);  
    puts("Error!\n\r");
    /* 如果一切正常, 不會執行到這裡 */

    return -1;
}
View Code

boot.lds

鏈接腳本

SECTIONS {
    . = 0x33f80000;
    .text : { *(.text) }
    
    . = ALIGN(4);
    .rodata : {*(.rodata*)} 
    
    . = ALIGN(4);
    .data : { *(.data) }
    
    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss)  *(COMMON) }
    __bss_end = .;
}
View Code

Makefile

CC      = arm-linux-gcc
LD      = arm-linux-ld
AR      = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump

CFLAGS         := -Wall -O2
CPPFLAGS       := -nostdinc -nostdlib -fno-builtin

objs := start.o init.o boot.o

boot.bin: $(objs)
    ${LD} -Tboot.lds -o boot.elf $^
    ${OBJCOPY} -O binary -S boot.elf $@
    ${OBJDUMP} -D -m arm boot.elf > boot.dis
    
%.o:%.c
    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S
    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:
    rm -f *.o *.bin *.elf *.dis
    
View Code

 


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

-Advertisement-
Play Games
更多相關文章
  • 基礎知識 相信大家應該都知道linux的文件基本許可權,使用ls -l命令可以顯示文件的基本許可權,"-rwxrwxrwx.",第一位表示文件的屬性(是文件- ,目錄d等),後面每隔三位為屬主、屬組、其他用戶 對應的讀寫執行許可權。這個比較簡單很容易理解。 文件特殊許可權 單純的讀寫執行許可權無法滿足我們的基 ...
  • Xshell連接上Linux伺服器後經常自動中斷連接,報錯如下圖: 解決方法如下,進入/etc/ssh目錄打開sshd_config文件,找到下圖兩個參數並設置下圖所示的值: 重啟sshd即可解決,如下圖: ...
  • 直奔主題,在代理伺服器的Nginx配置(yourWebsite.conf)的location /中添加: 在業務伺服器的Nginx配置(yourWebsite.conf)的location中添加: 配置到這,可以用HTTP_X_FORWARDED_FOR獲取客戶端真實IP,以PHP為例,$_SERV ...
  • 目錄Diy智能家居-1.基於esp8266的語音控制系統(開篇) https://blog.csdn.net/arno1988/article/details/82628589 Diy智能家居-2.基於esp8266的語音控制系統(硬體篇) https://blog.csdn.net/arno198 ...
  • 本文收錄在容器技術學習系列文章總目錄 1、瞭解Docker Registry 1.1 介紹 registry 用於保存docker 鏡像,包括鏡像的層次結構和元數據。 啟動容器時,docker daemon會試圖從本地獲取相關的鏡像;本地鏡像不存在時,其將從registry中下載該鏡像並保存到本地; ...
  • Linux iptables 防火牆配置規則 前言:把網上我感覺不錯iptables的訪問規則都統一在這裡,以後做參考。 modprobe ipt_MASQUERADE modprobe ip_conntrack_ftp modprobe ip_nat_ftp iptables -F iptable ...
  • 一 Zabbix簡介 1.1 概述 Zabbix是一個企業級的高度集成開源監控軟體,提供分散式監控解決方案。可以用來監控設備、服務等可用性和性能。 1.2 所支持監控方式 目前由zabbix提供包括但不限於以下事項類型的支持 二 Zabbix優勢 自由開放源代碼產品,可以對其進行任意修改和二次開發, ...
  • 一、開發背景 運用博客園許久,相信大家一定發覺這個與別的平臺有一些不一樣的地方,那就是缺少了用戶打賞功能。作為一個程式員的博客,這些東西肯定是該要自己 來寫的,以此來說明學習程式,便捷自身。以下我就來說一說如何設置自己的打賞功能。 二、起步 1、第一就是需要先申請好博客園設置里的js許可權 打開博客園 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...