Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Bootloader
rtthread移植到jz2440之BootLoader
发布于 2019-01-10 23:10:05 浏览:2931
订阅该版
从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* = src*; 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
"); puthex(buf[0]); puts("
"); puts("device id
"); puthex(buf[1]); puts("
"); puts("3rd byte
"); puthex(buf[2]); puts("
"); puts("4th byte
"); puthex(buf[3]); puts("
"); puts("page size
"); puthex(1 << (buf[3] & 0x03)); puts("
"); puts("block size
"); puthex(64 << ((buf[3] >> 4) & 0x03)); puts("
"); puts("5th byte
"); 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* = 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
"); return 0; } if (len & (0x1FFFF)) { puts("nand_erase err, len is not block align
"); 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*) { putc(str*); 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); } }```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```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++; } 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
"); nand_read(0x0, (unsigned char *)0x30000000, 0x100000); puts("
"); led_off(); /* 3. 跳转执行 */ puts("Boot rtthread
"); theKernel = (void (*)(unsigned int))0x30000000; theKernel(0x30000000); puts("Error!
"); /* 如果一切正常, 不会执行到这里 */ return -1; }```boot.lds链接脚本```SECTIONS { . = 0x33f80000; .text : { *(.text) } . = ALIGN(4); .rodata : {*(.rodata*)} . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) *(COMMON) } __bss_end = .; }```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 $@ [ DISCUZ_CODE_42 ]lt; %.o:%.S ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ [ DISCUZ_CODE_42 ]lt; clean: rm -f *.o *.bin *.elf *.dis```
查看更多
6
个回答
默认排序
按发布时间排序
XQQ
2019-01-11
这家伙很懒,什么也没写!
顶一下
lukgeeker
2019-01-12
这家伙很懒,什么也没写!
顶之~~~mark,,,
zwl818
2019-03-25
这家伙很懒,什么也没写!
您好,我想问下您,您RT-Thread操作系统是怎么实现移植的呀?我有一块TQ210的开发板,也想在上面做RT-Thread开发
flyboy
2019-03-26
Do my self();
>您好,我想问下您,您RT-Thread操作系统是怎么实现移植的呀?我有一块TQ210的开发板,也想在上面做RT-Threa ... --- 推荐您先用 RT-Thread 官网上手指南里面的开发板学习一下,熟悉之后,再弄移植会简单很多。 在RTT出的新书《嵌入式实时操作系统RT-Thread设计与实现》里面有芯片级别的移植章节,可以参考。
我夏了夏天
认证专家
2019-03-26
Life isn't about finding yourself, life is about creating yourself.
会玩
zwl818
2019-03-28
这家伙很懒,什么也没写!
>推荐您先用 RT-Thread 官网上手指南里面的开发板学习一下,熟悉之后,再弄移植会简单很多。 > >在RTT出的新 ... --- 好的,谢谢
撰写答案
登录
注册新账号
关注者
0
被浏览
2.9k
关于作者
Jason-Ye
这家伙很懒,什么也没写!
提问
4
回答
11
被采纳
0
关注TA
发私信
相关问题
1
Linux下通过USBTinyISP为Arduino开发板烧?写Bootloader
2
请教修改NVIC后RTT调度函数失效的问题[已解决 bootloader中打开了不必要的中断]
3
进入bootloader的方式探讨
4
求助:IAP里的APP使用的RTT,跳转后出错。[已解决]
5
有没有人在STM32F103上用UART IAP跑过RT-Thread?
6
想做网口的IAP远程升级,不知可不可行
7
IAP问题
8
[已解决]请教基于RTT的IAP程序切换到应用程序不成功的问题(基于STM32F4)?
9
stm32f4xx-----IAP移植APP程序需要注意的地方
10
在调试IAP网络升级遇到跳转之后bootloader程序网络不通
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
RT-Thread项目助手v0.2.0 - 支持Env Windows
2
RttreadV5.10上,GD32F450Z RTC时间显示问题
3
rt-smart启动流程分析
4
EtherKit快速上手PROFINET
5
RTThread USB转串口无法接收数据
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部