最小bootloader的实现,完整源代码
2009-12-30 15:19
441 查看
我们整个ARM课程就分为三部分,这是第一部分,实现一个自己的最小bootloader
1.Read Me
一、实现功能
1.硬件初始化
2.延时判断加载操作系统还是进入Bootloader Shell
3.加载操作系统
4.Bootloadershell
二、Bootloader Shell 支持的命令
1.help 帮助,显示所有支持的命令,及命令格式
2.loadx 下载文件到开发板的内存,默认到0x32000000
3.led_on 点亮一个led灯
4.led_off 关闭一个led灯
5.led_test 测试所有led灯,全亮全灭循环3次
6.beep_test 测试蜂鸣器,响3声
7.seg7_test 测试7段数码管
8.dip4_test 测试4位拨码开关
9.flash_load 将NandFlash中的文件搬移到SDARAM中
10.flash_write 将SDRAM中的内容下载到NandFlash中
11.GO 跳到某地址执行,默认到0x32000000
三、文件结构
1.start.s 程序入口,负责硬件初始化,Bootloader自搬移
2.uart.c uart.h 串口驱动的实现
3.load.c 选择加载操作系统还是进入Shell
4.stdlib.h stdlib.c 标准库函数的实现
5.stdio.h stdio.c 标准输入输出函数的实现
6.shell.c shell.h shell命令的实现
7.dip4.h dip4.c 拨码开关相关底层函数
8.seg7.h seg7.c 7段数码管相关底层函数
9.copy_myself.c nan.h NandFlash底层函数
10.xmodem.h xmodem.c xmodem协议实现
11.Datatype.h 数据定义
12.os/os.c 模拟操作系统
13.Makefile
四、流程及设计思想
1.硬件初始化
2.Bootloader自搬移
3.延时,判断是否有输入
4.(1)无输入则加载操作系统,操作系统烧写于Nand Flash的第100块,即位于100*32*512 = 0x190000
操作系统加载到内存的Sdram中
(2)有输入则进入shell命令模式
5.解释命令,使用自己实现的标准库函数来匹配输入的命令
6.匹配函数,定义了一个包含字符指针以及函数指针的结构体,可以通过对应关系迅速调用命令对应的函数
所有函数为void fun(void *)形式。
五、测试条件及结果
1. 打开超级终端,给开发板上电,超级终端上打印提示信息
2. 超级终端上开始3秒倒计时,3秒内不动键盘,提示加载操作系统,模拟操作系统的闪灯程序运行,可观察到LED等一闪一灭
3. 重启开发板,3秒内按下任意键,可看到有T-Boot#提示符,程序进入Shell模式
4. 输入help,可看到10条命令的使用方法
5. 输入led_on 1可看到第一个led灯亮
6. 输入led_off 1可看到第一个led灯灭
7. 输入led_test 可看到所有led一闪一灭3次
8. 输入beep_test 可听到蜂鸣器响3声
9. 输入seg7_test 可看到7段数码管每个led循环点亮
10.输入dip4_test 拨动拨码开关可观察到7段数码管对应的LED亮
11.输入loadx,发送文件0x/0s.bin
12.输入go 0x32000000 可观察到led灯一亮一灭
13.输入flash_load 0x190000 0x32000000 0x1000 (0x190000模拟操作系统烧写位置)
14.go 0x32000000 可观察到led一亮一灭
16.输入flash_write 0x32000000 0x200000 0x1000
17.输入flash_load 0x200000 0x31500000 0x1000
18.输入go 0x31500000 可观察到led灯一亮一灭
六、函数接口及功能
1.底层接口函数
uart.h
void uart_init(void); 初始化串口
void uart_putc(char ch); 打印一个字符到终端
char uart_getc(void); 从终端接收一个字符
void uart_test(void); 串口测试
void sdram_test(void); sdram测试
nand.h
void reset_nand(void); 重置串口
void init_nand(void); 初始化串口
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);
读nand flash 第一个参数为需要存放书籍的内存首地址, 第二个参数为nand_flash的首地址,第三个参数为需要拷贝的大小
int nand_write_ll(unsigned char *buf, unsigned long start_addr, int size);
写nand flash 第一个参数为需要存放书籍的内存首地址, 第二个参数为nand_flash的首地址,第三个参数为需要拷贝的大小
dip.h
int dip_init(void); 初始化
int dip_num(void); 显示数字
int dip_test(void); 测试
seg7.h
int seg7_init(void); 初始化
int seg7_display_num(int num);显示数字
int seg7_test(void); 测试
2.库函数
stdio.h
char * uart_gets(char *buf); 打印字符串
void uart_puts(char *str); 接收字符串
void uart_printf(const char *str, ...);格式化输出
void uart_put_num(int num,int pow);打印数字
stdlib.h
int my_strcmp(char *src, char *dst);比较字符串,相等返回0
int my_atoi(char *str);转换字符串为数字
char * found_ch(char *str, char ch);在一个字符串中寻找一个字符
int my_strlen(char *str);计算字符串长度
int is_number(char ch);一个字符是否数字
int pow(int num, int power);计算num的power次方
int my_atox(char *str);将一个字符串按16进制转为数字
3.协议
xmodem.h
int xmodem_receive(int argc, char *argv);
int get_record(void);
4.其他
命令对应的解释函数,为方便调用参数均为void *
void help(void *argv);
void go(void *argv);
void loadx(void *argv);
void beep_test(void *argv);
void led_off(void *argv);
void led_on(void *argv);
void seg7_on(void *argv);
void dip4_on(void *argv);
void shell(void);
void led_test(void * argv);
void flash_load(void *argv);
void flash_write(void *argv);
void delay(int);
2.start.s
Code:
;s3c2440 bootloader
;author: tongxiaohua
;time : 2009.12.22
AREA FIRST, CODE, READONLY
ENTRY
CODE32
IMPORT uart_test
IMPORT sdram_test
START
WatchDog
;Close WatchDog
LDR R0, =0X53000000
MOV R1, #0X0
STR R1, [R0]
Led_on
;Make a Led on
LDR R2, =0x20800000
MOV R4, #0X1
STRB R4, [R2]
;BL DELAY
Beep_off
;Close Beep
;Control GPB0 output
LDR R0, =0x56000010
MOV R1, #0X1
STR R1, [R0]
LDR R0, =0X56000014
MOV R1, #0X0
STR R1, [R0]
Interrupt_off
;CLose Interrupt
LDR R0, =0X4A000008
LDR R1, =0XFFFFFFFF
STR R1, [R0]
Init_Clock
; Init Clock
; Set Mode
MRC p15,0,R1,c1,c0,0
ORR R1,R1,#0XC0000000
MCR p15,0,R1,c1,c0,0
;CAMDIVN
;When Config the register CLKDIVN Nedd This Configre
LDR R0,=0x4c000018
MOV R1,#0x0
STR R1,[r0]
;LOCKTIME PLL
LDR R0,=0x4c000000
LDR R1,=0x00ffffff
STR R1,[r0]
;UPLLCON
LDR R0,=0x4c000008
LDR R1,=0x00038022
STR R1,[R0]
NOP
NOP
NOP
NOP
NOP
NOP
NOP
;MPLLCON
LDR R0,=0x4c000004
LDR R1,=0x00044011
STR R1,[r0]
;CLKCON
;Witch divice need Clock
LDR R0,=0x4c00000c
LDR R1,=0x00fffff0
STR R1,[R0]
;CLKSLOW
;Low Clock
LDR R0,=0x4c000010
LDR R1,=0x00000004
STR R1,[R0]
;CLKDIVN
;HCLK = FCLK/3 PCLK = HCLK/2
LDR R0,=0x4c000014
LDR R1,=0x00000007
STR R1,[R0]
;Uart0
;Uart
;LDR SP, =0x1000
;LDR R2, =0x20800000
;MOV R4, #0X7
;STRB R4, [R2]
;BL uart_test
Memsetup
;SDRAM Init
ldr r1,=MEM_CTL_BASE
adrl r2,mem_cfg_val
add r3,r1,#52
1
ldr r4,[r2],#4
str r4,[r1],#4
cmp r1,r3
bne %1
nop
nop
nop
nop
MEM_CTL_BASE EQU 0X48000000
mem_cfg_val
DCD 0x22111110
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0X00018005
DCD 0X00018005
DCD 0X008E0459
DCD 0X000000B1
DCD 0X00000030
DCD 0X00000030
Nandflash
;NandFlash,Bootloader CopyMyself
ldr sp,=0x33ef0000
IMPORT copy_myself
;nand_begin=0x0
;size=0x20000
;sdram_begin=0x33f00000
BL copy_myself
ldr r1,=on_the_ram
add pc,r1,#0
nop
nop
nop
on_the_ram
;Select mode
IMPORT load
ldr sp,=0x33ef0000
BL uart_test
BL sdram_test
BL load
B .
END
2.Copy_myself.c
Code:
/* NAND Flash registers 2440*/
#include "DataType.h"
#include "stdio.h"
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCONT (*(volatile unsigned int *)0x4e000004)
#define NFCMD (*(volatile unsigned char *)0x4e000008)
#define NFADDR (*(volatile unsigned char *)0x4e00000c)
#define NFDATA (*(volatile unsigned char *)0x4e000010)
#define NFSTAT (*(volatile unsigned char *)0x4e000020)
#define NFMECC0 (*(volatile unsigned *)0x4E00002C)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1))
#define NAND_CHIP_DISABLE (NFCONT |= (1<<1))
#define NAND_CLEAR_RB (NFSTAT |= (1<<2))
#define NAND_DETECT_RB { while(! (NFSTAT&(1<<0)) );}
/* 在第一次实用NAND Flash前,复位一下NAND Flash */
#define BUSY 1
#define InitEcc() (NFCONT |= (1<<4))
#define MEccUnlock() (NFCONT &= ~(1<<5))
#define MEccLock() (NFCONT |= (1<<5))
#define SEccUnlock() (NFCONT &= ~(1<<6))
#define SEccLock() (NFCONT |= (1<<6))
/*for 8 bit nand flash, only use NFMECC0*/
#define RdNFMEcc() (NFMECC0)
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/*
inline void wait_idle(void)
{
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
*/
void reset_nand(void)
{
//int i=0;
// NFCONF &= ~0x800;
// for(; i<10; i++);
NFCONF = 0x1400;
NFCONT = 0x73;
NAND_CHIP_ENABLE;
NFCMD = 0xff; //reset command
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
/* 初始化NAND Flash */
void init_nand(void)
{
NFCONT = 0x73;
NAND_CHIP_DISABLE;
reset_nand();
}
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NAND_CLEAR_RB;
NFCMD = 0;
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
NAND_DETECT_RB;
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
NAND_CHIP_DISABLE;
return 0;
}
int NandErase(unsigned long start_addr)
{
if (start_addr & NAND_BLOCK_MASK) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
NAND_CLEAR_RB;
NFCMD = 0x60;
NFADDR = (start_addr>> 9) & 0xff;
NFADDR = (start_addr>> 17) & 0xff;
NFADDR = (start_addr>> 25) & 0xff;
NFCMD = 0xd0;
NAND_DETECT_RB;
uart_printf("Erase 0x%x/r",start_addr);
NAND_CHIP_DISABLE;
return 0;
}
int nand_write_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j, k;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
for(k = 0; k <= size / (16 * 1024); k++)
NandErase(start_addr + (k * 16 * 1024));
NAND_CHIP_ENABLE;
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
// if(k % 32 == 0) NandErase(start_addr);
NAND_CLEAR_RB;
NFCMD = 0x80;
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
NFDATA = *buf;
buf++;
}
NFCMD = 0x10;
NAND_DETECT_RB;
}
NAND_CHIP_DISABLE;
return 0;
}
void copy_myself(void)
{
unsigned char *buf = ((unsigned char *)0x33f00000);
unsigned long start_addr = 0;
int size = 0x20000;
reset_nand();
init_nand();
nand_read_ll(buf,start_addr,size);
}
3.dip.c
Code:
/*
* dip.c - dip api & driver
*
* Board: akae2440
* environment: bootloader & ADS
* Author: akaedu
* Date: 2009-5-26
* web: www.akaedu.org
*
*
* GPIO address_MAP
*
* CPLD_MAP_BASE physical address is 0x20800000
* CPLD_LED physical address is 0x20800000
* CPLD_SEG physical address is 0x20800080
* CPLD_DIP physical address is 0x208000a0
*
* GPIO port_MAP
*
* GPA_PORT~GPB_PORT(130 multi-functional input port pins)
* GPIO_BASE : GPACON : 0x56000000
*
* NAME GPIO CPLD_IN CPLD_OUT GPIO_CON MODE_bit_CON GPIO_DAT MODE_bit_DAT
* BEEP GPB0 TOUT0 BEEP 0x56000010 [1:0] 0x56000014 [0]
*
* GPIO key_scn_MAP
*
* NAME PORT_OUT PORT_IN
* KEY(sw1) KBOUT1 : GPB8 KBIN1 : ENT0 : GPF0
* KEY(sw2) KBOUT0 : GPB9 KBIN1 : ENT0 : GPF0
* KEY(sw3) KBOUT1 : GPB8 KBIN0 : ENT2 : GPF2
* KEY(sw4) KBOUT1 : GPB8 KBIN1 : ENT2 : GPF2
*
* GPIO_CON GPIO_DAT GPIO MODE_bit_CON MODE_bit_DAT
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB8 [17:16] [8]
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB9 [19:18] [9]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF0 [1:0] [0]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF2 [5:4] [2]
*
*/
#include "dip.h"
#include "seg7.h"
#define CPLD_DIP *((volatile unsigned char *)0x208000a0)
int dip_init(void)
{
return 0;
}
int dip_num(void)
{
return CPLD_DIP;
}
int dip_test(void)
{
int dip_input;
int i = 5000000;
seg7_init();
dip_init();
while(i--)
{
dip_input = dip_num();
seg7_display_num(dip_input);
}
return 0;
}
4.load.c
Code:
#include "uart.h"
#include "shell.h"
#include "stdlib.h"
#include "stdio.h"
#include "nand.h"
#define SEC 3
#define LOAD_OS 0
#define LOAD_SHELL 1
#define OS_MEM_ADDR 0x31000000
#define OS_ADDR (100 * 32 * 512) /*OS address*/
#define OS_SIZE 0x20000
/*Move OS to Sdram From NandFlash*/
void os_test(void)
{
unsigned char *buf = (unsigned char *)OS_MEM_ADDR;
unsigned long start = OS_ADDR;
int size = OS_SIZE;
uart_printf("/rcopy opration system to the sdrm from nanflash.../r");
reset_nand();
init_nand();
nand_read_ll(buf, start, size);
}
/*Wait for User Enter Any Key to Login in the Shell of Bootloader*/
int delay_p(int sec)
{
int osec = 500000, i, j;
uart_printf("Enter any key to load in the shell of bootloader:%d", sec);
for(i = 0; i < sec; i++)
{
for(j = 0; j < osec; j++)
{
if(UTRSTAT0 & UTRSTAT_R_READY){
uart_getchar();
return LOAD_SHELL;
}
}
uart_printf("/b%d", sec - i);
}
//uart_printf("return");
return LOAD_OS;
}
/*Shell or OS*/
void load(void)
{
int load_stat;
if((load_stat = delay_p(SEC)) == LOAD_OS)
{
os_test();
uart_printf("/rrun in the oprition system.../r");
go((void *)OS_MEM_ADDR);
}
else
{
shell();
}
}
5.seg7.c
Code:
/*
* seg7.c - seg7 api & driver
*
* Board: akae2440
* environment: bootloader & ADS
* Author: akaedu
* Date: 2009-5-26
* web: www.akaedu.org
*
*
* GPIO address_MAP
*
* CPLD_MAP_BASE physical address is 0x20800000
* CPLD_LED physical address is 0x20800000
* CPLD_SEG7 physical address is 0x20800080
* CPLD_DIP physical address is 0x208000a0
*
* GPIO port_MAP
*
* GPA_PORT~GPB_PORT(130 multi-functional input port pins)
* GPIO_BASE : GPACON : 0x56000000
*
* NAME GPIO CPLD_IN CPLD_OUT GPIO_CON MODE_bit_CON GPIO_DAT MODE_bit_DAT
* BEEP GPB0 TOUT0 BEEP 0x56000010 [1:0] 0x56000014 [0]
*
* GPIO key_scn_MAP
*
* NAME PORT_OUT PORT_IN
* KEY(sw1) KBOUT1 : GPB8 KBIN1 : ENT0 : GPF0
* KEY(sw2) KBOUT0 : GPB9 KBIN1 : ENT0 : GPF0
* KEY(sw3) KBOUT1 : GPB8 KBIN0 : ENT2 : GPF2
* KEY(sw4) KBOUT1 : GPB8 KBIN1 : ENT2 : GPF2
*
* GPIO_CON GPIO_DAT GPIO MODE_bit_CON MODE_bit_DAT
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB8 [17:16] [8]
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB9 [19:18] [9]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF0 [1:0] [0]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF2 [5:4] [2]
*
*/
#include "seg7.h"
#include "shell.h"
#define CPLD_SEG7 *((volatile unsigned char *)0x20800080)
/* delay for about one second */
/*static void delay(int time)
{
int i, j;
for(i = 0; i < time; i++)
for(j = 0; j < 500000; j++)
;
}*/
int seg7_init(void)
{
CPLD_SEG7 = 0x0;
return 0;
}
/* display number on seg7 */
int seg7_display_num(int num)
{
CPLD_SEG7 = 1<<num;
return 0;
}
int seg7_test(void)
{
int i;
seg7_init();
for(i = 0; i < 8; i++)
{
seg7_display_num(i);
delay(1);
}
return 0;
}
8.shell.c
Code:
#include "shell.h"
#include "uart.h"
#include "stdlib.h"
#include "stdio.h"
#include "xmodem.h"
#include "dip.h"
#include "seg7.h"
#include "nand.h"
#define START_ADDR 0x30000000
#define END_ADDR 0x34000000
#define MAX_LINE 256
#define CMD_NUM 11
#define LED_NUM 8
#define START_FLASH 0x0
#define END_FLASH 0x40000000
#define START_MEM 0x30000000
#define END_MEM 0x34000000
#define MAX_SIZE (END_MEM - START_MEM - 0x20000)
#define LED_ADDR *((volatile unsigned int *)0x20800000)
#define GPB0 *((volatile unsigned int *)0x56000010)
#define BEEP *((volatile unsigned int *)0x56000014)
/*delay*/
void delay(int sec)
{
int i, j;
for(i = 0; i < sec; i++)
{
for(j = 0; j < 500000; j++)
;
}
}
struct CMD{
char *cmd_line;
void (*fun)(void *);
}cmd[CMD_NUM] ={
{"help", help},
{"loadx", loadx},
{"go", go},
{"led_on", led_on},
{"led_off", led_off},
{"beep_test", beep_test},
{"led_test", led_test},
{"seg7_test", seg7_on},
{"dip4_test", dip4_on},
{"flash_load", flash_load},
{"flash_write", flash_write},
//{"flash_write", flash_write},
};
void flash_load(void *arg)
{
char *argv[4], *end;
int flash_start, mem_start, size;
argv[1] = arg;
uart_printf("the arg is %s/r", arg);
if((end = found_ch(arg, ' ')) == NULL)
{
uart_printf("Uaseage1: <flash_load> <flash address> <sdram address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[2] = end;
if((end = found_ch(end, ' ')) == NULL)
{
uart_printf("Uaseage2: <flash_load> <flash address> <sdram address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[3] = end;
if((flash_start = my_atox(argv[1])) < START_FLASH || (mem_start = my_atox(argv[2])) < START_MEM ||(size = my_atox(argv[3])) > MAX_SIZE || (mem_start + size) > END_MEM)
{
uart_printf("Access Violation: Please check your address/r");
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
}
else
{ uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
nand_read_ll((unsigned char *)mem_start, flash_start, size);
}
}
#if 1
void flash_write(void *arg)
{
char *argv[4], *end;
int flash_start, mem_start, size;
argv[1] = arg;
uart_printf("the arg is %s/r", arg);
if((end = found_ch(arg, ' ')) == NULL)
{
uart_printf("Uaseage1: <flash_load> <sdram address> <flash address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[2] = end;
if((end = found_ch(end, ' ')) == NULL)
{
uart_printf("Uaseage2: <flash_load> <sdram address> <flash address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[3] = end;
if((flash_start = my_atox(argv[2])) < START_FLASH || (mem_start = my_atox(argv[1])) < START_MEM ||(size = my_atox(argv[3])) > MAX_SIZE || (mem_start + size) > END_MEM)
{
uart_printf("Access Violation: Please check your address/r");
// reset_nand();
// init_nand();
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
}
else
{
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
// reset_nand();
// init_nand();
nand_write_ll((unsigned char *)mem_start, flash_start, size);
}
}
#endif
void loadx(void * argv)
{
int argc;
uart_printf("argv is %s/r",(char *)argv);
if(argv != NULL) argc = 2;
else argc = 1;
if(found_ch(argv, ' ') != NULL)
{
uart_printf("Error: Usage <loadx> <address>/r");
}
else
{
xmodem_receive(argc, argv);
uart_printf("Success!");
}
return;
}
void led_on(void * argv)
{
/*test 第3字节有效*/
// uart_printf("%dnd led is on/r", (int)argv + 1);
// LED_ADDR = 0xff0000;
LED_ADDR |= (1 << ((int)argv + 16));
}
void led_off(void * argv)
{
// uart_printf("%dnd led is off/r", (int)argv + 1);
LED_ADDR &= ~(1 << ((int)argv + 16));
}
void led_test(void * argv)
{
int i, j;
for(i = 0; i < 3; i++ )
{
for(j = 0; j < LED_NUM; j++)
{
led_on((void *)j);
}
delay(1);
for(j = 0; j < LED_NUM; j++)
{
led_off((void *)j);
}
delay(1);
}
}
void beep_test(void *argv)
{
int i;
GPB0 |= 0x1;
for(i = 0; i < 3; i++)
{
BEEP = 0x1;
delay(1);
BEEP = 0x0;
delay(1);
}
}
void seg7_on(void *argv)
{
seg7_test();
}
void dip4_on(void * argv)
{
dip_test();
}
void help(void * argv)
{
uart_printf("loadx - [address], download a file to the borad/r");
uart_printf("go - <address>, go to the addrress/r");
uart_printf("flash_load - <flash address><sdram address><size>, Move the code to sdram from nandflash/r");
uart_printf("flash_write - <sdram address><flash address><size>, Move the code to Nandflash from sdram/r");
uart_printf("led_on - <led number>, test led/r");
uart_printf("led_off - <led_number>, test_led/r");
uart_printf("led_test - test all led/r");
uart_printf("beep_test - test beep/r");
uart_printf("seg7_test - test seg/r");
uart_printf("dip4_test - test dip4, you have ten second to test it/r/r");
}
void go(void *argv)
{
int addr = (int)argv;
if(addr == 0) addr = 0x32000000;
// void (*gt)(void) = (void (*) (void))addr;
if(addr < START_ADDR || addr > END_ADDR)
{
// return -1;
}
else
{
uart_printf("in go/r");
(*(void (*) (void))addr)();
}
}
void shellcmd(char buf[])
{
char *start, *end, *argv = NULL;
int i, i_argv;
start = buf;
if((end = found_ch(buf, ' ')) != NULL)
{
*end = '/0';
argv = end + 1;
}
// uart_printf("buf is before is%s/r",buf);
// uart_printf("the command is %s", start);
// uart_printf("the command is %s", cmd[0].cmd_line);
for(i = 0; i < CMD_NUM; i++)
{
if(my_strcmp(start, cmd[i].cmd_line) == 0)
{
if(i == 3 || i == 4){
i_argv = my_atoi(argv);
// uart_printf("i_argv is %d/r", i_argv);
(* cmd[i].fun)((void *) i_argv);
}
else if(i == 2)
{ i_argv = my_atox(argv);
// uart_printf("i_argv is %x/r", i_argv);
(* cmd[i].fun)((void *) i_argv);
}
else
{
(*cmd[i].fun)((void *) argv);
}
break;
}
}
if(i == CMD_NUM)
{
uart_printf("Command not found/r");
}
}
void shell(void)
{
char buf[MAX_LINE];
while(1)
{
uart_puts("/rT-BOOT#");
uart_gets(buf);
// uart_printf("/rget the command/r");
//uart_puts(buf);
shellcmd(buf);
}
}
6.stdio.c
Code:
#include <stdarg.h>
#include "stdlib.h"
#include "uart.h"
#include "stdio.h"
void uart_puts(char *str)
{
while(*str != '/0')
{
uart_putchar(*str);
str++;
}
}
char *uart_gets(char *str)
{
int i;
if(str == NULL) return str;
for(i = 0; ; i++)
{
str[i] = uart_getchar();
/*do shomthing when '/b is input'*/
if(str[i] == '/b')
{
if(i > 0){
uart_putchar('/b');
i -= 2;
}
else
{
i = -1;
}
}
else
{
uart_putchar(str[i]);
}
if(str[i] == '/r' || str[i] == '/n')
{
str[i] = '/0';
break;
}
}
return str;
}
void uart_put_num(int num,int pow)
{
if(num != 0)
{
uart_put_num(num/pow, pow);
if(num%pow > 9)
uart_putchar((char)(num%pow - 10) + 'A');
else
uart_putchar((char)(num%pow + '0'));
}
}
void uart_printf(const char *str, ...)
{
va_list ap;
char c, ch;
char * s; int num;
va_start(ap, str);
while(c = *str++)
{
if(c != '%')
{
uart_putchar(c);
}
else
{
c = *str++;
switch(c)
{
case 'c':
ch = va_arg(ap, int);
uart_putchar((char)ch);
break;
case 's':
s = va_arg(ap, char *);
uart_puts(s);
break;
case 'd':
num = va_arg(ap, int);
uart_put_num(num, 10);
break;
case 'x':
num = va_arg(ap, int);
uart_put_num(num, 16);
break;
default:
uart_putchar(c);
}
}
}
va_end(ap);
}
6.stdlib.h
Code:
#include "stdlib.h"
#include "stdio.h"
int my_strcmp(char *src, char *dst)
{
if(src == NULL || dst == NULL) goto exit;
while(*src == *dst && *src!= '/0' && *dst != '/0')
{
src++;
dst++;
}
exit:
return (*src - *dst);
}
char *found_ch(char *str, char ch)
{
if(str == NULL) goto exit;
while(*str != ch && *str != '/0')
{
str++;
}
exit:
if(*str == ch) return str;
else return NULL;
}
int my_strlen(char *str)
{
char *p = str;
if(str == NULL) goto exit;
while(*str != '/0')
{
str++;
}
exit:
return (str - p);
}
int is_number(char ch)
{
if('0' <= ch && ch <= '9') return 1;
else return 0;
}
int pow(int num, int power)
{
/*do not care about overflow*/
int count = 1;
while(power--)
{
count *= num;
}
return count;
}
int my_atoi(char *str)
{
int len = my_strlen(str), i, count = 0;
// uart_printf("the str is %s/r", str);
// uart_printf("len = %d/r", len);
if(str == NULL) goto exit;
// if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
// str += 2;
for(i = 0; i < len; i++)
{
if(!is_number(str[i])) goto exit;
count += ((str[i] - '0')*pow(10, len - i - 1));
}
exit:
return count;
}
int my_atox(char *str)
{
int len = my_strlen(str), i, count = 0;
// uart_printf("the str is %s/r", str);
// uart_printf("len = %d/r", len);
if(str == NULL) goto exit;
if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')){
str += 2;
len -= 2;
}
for(i = 0; i < len; i++)
{
if(!is_number(str[i])) goto exit;
count += ((str[i] - '0')*pow(16, len - i - 1));
// uart_printf("the count is %x/r", count);
}
exit:
return count;
}
7.uart.c
Code:
/*Uart Driver on S3C2440*/
/*Athor: tongxiaohua */
/*Time : 2009.12.27 */
#include "uart.h"
#include "stdlib.h"
#include "stdio.h"
#include "shell.h"
/*Init Uart0*/
void uart_init(void)
{
ULCON0 |= 3; /*8N1*/
UCON0 = 5; /*Work Frequency Select PCLK, the mode of recive/send select poll*/
UTRSTAT0 &= 6; /*Set Null of recive/send Buffer*/
UBRDIV0 = 26; /*(int)50000000 / (115200*16) - 1*/
GPHCON = 0xa0; /*Set F2, F3 Function*/
UFCON0 = 0;
UMCON0 = 0;
}
/*Put a byte to the Uart0*/
void uart_putchar(char ch)
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = ch;
/*Back Space*/
if(ch == '/b')
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = ' ';
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = '/b';
}
/*Enter*/
if(ch == '/r')
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = '/n';
}
}
/*Get a byte from Uart*/
char uart_getchar(void)
{
while (!(UTRSTAT0 & UTRSTAT_R_READY));
return URX0;
}
/*Test the Uart is or not Working*/
void uart_test(void)
{
uart_init();
uart_printf("/r/rWelecom to use my bootloader/rAuthor:tong xiaohua/rBoard:s3c2440/r");
uart_printf("Time: 2009.12.27/rCPU: Arm 920T/rSRAM: 4k/rSDRAM:32M/rNAND FLASH:64M/r");
uart_printf("Uart0 is working.../r");
}
/*Test the Sdram is or Not Working*/
void sdram_test(void)
{
int testnum = 0x12345678;
*((volatile unsigned int *)0x32000000) = testnum;
testnum = *((volatile unsigned int *)0x32000000);
if(testnum == 0x12345678)
{
// uart_printf("%x/r", testnum);
uart_printf("sdram is working.../r");
// uart_printf("test.../r");
}
else
{
// uart_printf("test faild/r");
uart_printf("sdram working error.../r", testnum);
// uart_printf("test.../r");
}
}
8.xmodem.c
Code:
#include "xmodem.h"
/* 这两个头文件是你已经实现的功能函数,下面
* 代码中用到的函数如不是xmodem.c中定义的,
* 需移植你已写好的函数接口到本程序中,如
* uart0_getchar()、uart0_putchar()、
* myprintf()等
*/
#include "stdio.h"
#include "uart.h"
#include "stdlib.h"
/* global error variable */
char *xmodem_errtxt = NULL;
int get_byte_err = 0;
U8 volatile receive_buffer[BLOCK_SIZE];
//unsigned download_addr = 0x8000;
/* prototypes of helper functions */
int get_record(void);
enum
{
SAC_SEND_NAK = 0,
SAC_SENT_NAK = 1,
SAC_PAST_START_NAK = 2
};
static volatile int seen_a_char = SAC_SEND_NAK;
//static int one_nak = 0;
//static unsigned long xmodem_timeout = GET_BYTE_TIMEOUT;
char debugbuf[4096];
int db_idx = 0;
static void delay(void)
{
int j;
for (j = 0; j < 2000090; j++)
;
}
int xmodem_receive(int argc, char *argv)
{
char ochr;
int r = 0, rx_block_num = 0, error_count = 0;
int foffset = 0;
int i;
unsigned int download_addr;
char nak = NAK;
xmodem_errtxt = NULL;
seen_a_char = 0;
uart_printf("in xmodem argc = %d, argv = %s /r", argc, argv);
// if(argc > 1) download_addr = atox(argv[1]);
if(argc > 1) download_addr = my_atox(argv);
else download_addr = 0x32000000;
uart_printf("download_addr is %x," , download_addr);
UART0_putchar('9');
delay();
UART0_putchar('8');
delay();
UART0_putchar('7');
delay();
UART0_putchar('6');
delay();
UART0_putchar('5');
delay();
UART0_putchar('4');
delay();
UART0_putchar('3');
delay();
UART0_putchar('2');
delay();
UART0_putchar('1');
delay();
UART0_putchar('0');
//uart_putchar(UART0_BASE, nak);
UART0_putchar(nak);
rx_block_num = 1;
/* times to retry */
error_count = RETRIES;
do {
/* when local block number equals to the block number in the packet,
store the data into the memory which download_addr points*/
if ((r = get_record()) == (rx_block_num & 255)) {
error_count = RETRIES;
for (i = 0; i <BLOCK_SIZE; i++)
*(U8 *)(download_addr+foffset+i) = receive_buffer[i];
xmodem_errtxt = "RX PACKET";
rx_block_num++;
ochr = ACK;
foffset += BLOCK_SIZE;
} else {
switch (r) {
case -1: /* TIMEOUT */
xmodem_errtxt = "TIMEOUT";
ochr = NAK;
break;
case -2: /* Bad block */
xmodem_errtxt = "BAD BLOCK#";
/* eat teh rest of the block */
#if 0
get_byte_err = 0;
while (get_byte_err != -1) get_byte();
#endif
ochr = NAK;
break;
case -3: /* Bad checksum */
xmodem_errtxt = "BAD CHKSUM";
ochr = NAK;
break;
case -4: /* End of file */
xmodem_errtxt = "DONE";
ochr = ACK;
break;
case -5: /* Cancel */
xmodem_errtxt = "ABORTED";
ochr = ACK;
break;
default: /* Block out of sequence */
xmodem_errtxt = "WRONG BLK";
ochr = NAK;
}
error_count--;
}
UART0_putchar(ochr);
} while ((r > -3) && error_count);
if ((!error_count) || (r != -4)) {
foffset = 0; /* indicate failure to caller */
}
my_printf( "Loaded file at address 0x%x, size = %d /r/n",(int)download_addr, foffset);
return foffset;
}
/*
* Read a record in the XMODEM protocol, return the block number
* (0-255) if successful, or one of the following return codes:
* -1 = Bad byte
* -2 = Bad block number
* -3 = Bad block checksum
* -4 = End of file
* -5 = Canceled by remote
*/
int get_record(void)
{
char c;
int block_num = 0;
int i;
U32 check_sum;
/* clear the buffer */
for (i = 0; i < BLOCK_SIZE; i++)
receive_buffer[i] = 0x00;
check_sum = 0;
/* initialize i to -2,when begin to transfer,the first byte
will be store into blcok_num,and after plused one,the next
byte will be treated as a negated section */
i = -2;
//uart_getchar( UART0_BASE, &c);
c = UART0_getchar();
switch (c)
{
case SOH: /* Receive packet */
for (;;)
{
//uart_getchar( UART0_BASE, &c);
c = UART0_getchar();
switch (i)
{
case -2:
block_num = c;
break;
case -1:
#if 0
#ifdef CHECK_NEGATED_SECTNUM
if (c != (-block_num -1))
return -2;
#endif
#endif
break;
case BLOCK_SIZE:
/* check if reveived data is correct,
when correct,block num is returned,
else -3 is returned */
if ((check_sum & 0xff) != c)
return -3;
else
return block_num;
break;
default:
/* save data to buffer,and accumulate to check_sum */
receive_buffer[i] = c;
check_sum += c;
}
i++;
}
case EOT: /* end of file encountered */
return -4;
case CAN: /* cancel protocol */
return -5;
default:
return -5;
}
}
1.Read Me
一、实现功能
1.硬件初始化
2.延时判断加载操作系统还是进入Bootloader Shell
3.加载操作系统
4.Bootloadershell
二、Bootloader Shell 支持的命令
1.help 帮助,显示所有支持的命令,及命令格式
2.loadx 下载文件到开发板的内存,默认到0x32000000
3.led_on 点亮一个led灯
4.led_off 关闭一个led灯
5.led_test 测试所有led灯,全亮全灭循环3次
6.beep_test 测试蜂鸣器,响3声
7.seg7_test 测试7段数码管
8.dip4_test 测试4位拨码开关
9.flash_load 将NandFlash中的文件搬移到SDARAM中
10.flash_write 将SDRAM中的内容下载到NandFlash中
11.GO 跳到某地址执行,默认到0x32000000
三、文件结构
1.start.s 程序入口,负责硬件初始化,Bootloader自搬移
2.uart.c uart.h 串口驱动的实现
3.load.c 选择加载操作系统还是进入Shell
4.stdlib.h stdlib.c 标准库函数的实现
5.stdio.h stdio.c 标准输入输出函数的实现
6.shell.c shell.h shell命令的实现
7.dip4.h dip4.c 拨码开关相关底层函数
8.seg7.h seg7.c 7段数码管相关底层函数
9.copy_myself.c nan.h NandFlash底层函数
10.xmodem.h xmodem.c xmodem协议实现
11.Datatype.h 数据定义
12.os/os.c 模拟操作系统
13.Makefile
四、流程及设计思想
1.硬件初始化
2.Bootloader自搬移
3.延时,判断是否有输入
4.(1)无输入则加载操作系统,操作系统烧写于Nand Flash的第100块,即位于100*32*512 = 0x190000
操作系统加载到内存的Sdram中
(2)有输入则进入shell命令模式
5.解释命令,使用自己实现的标准库函数来匹配输入的命令
6.匹配函数,定义了一个包含字符指针以及函数指针的结构体,可以通过对应关系迅速调用命令对应的函数
所有函数为void fun(void *)形式。
五、测试条件及结果
1. 打开超级终端,给开发板上电,超级终端上打印提示信息
2. 超级终端上开始3秒倒计时,3秒内不动键盘,提示加载操作系统,模拟操作系统的闪灯程序运行,可观察到LED等一闪一灭
3. 重启开发板,3秒内按下任意键,可看到有T-Boot#提示符,程序进入Shell模式
4. 输入help,可看到10条命令的使用方法
5. 输入led_on 1可看到第一个led灯亮
6. 输入led_off 1可看到第一个led灯灭
7. 输入led_test 可看到所有led一闪一灭3次
8. 输入beep_test 可听到蜂鸣器响3声
9. 输入seg7_test 可看到7段数码管每个led循环点亮
10.输入dip4_test 拨动拨码开关可观察到7段数码管对应的LED亮
11.输入loadx,发送文件0x/0s.bin
12.输入go 0x32000000 可观察到led灯一亮一灭
13.输入flash_load 0x190000 0x32000000 0x1000 (0x190000模拟操作系统烧写位置)
14.go 0x32000000 可观察到led一亮一灭
16.输入flash_write 0x32000000 0x200000 0x1000
17.输入flash_load 0x200000 0x31500000 0x1000
18.输入go 0x31500000 可观察到led灯一亮一灭
六、函数接口及功能
1.底层接口函数
uart.h
void uart_init(void); 初始化串口
void uart_putc(char ch); 打印一个字符到终端
char uart_getc(void); 从终端接收一个字符
void uart_test(void); 串口测试
void sdram_test(void); sdram测试
nand.h
void reset_nand(void); 重置串口
void init_nand(void); 初始化串口
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);
读nand flash 第一个参数为需要存放书籍的内存首地址, 第二个参数为nand_flash的首地址,第三个参数为需要拷贝的大小
int nand_write_ll(unsigned char *buf, unsigned long start_addr, int size);
写nand flash 第一个参数为需要存放书籍的内存首地址, 第二个参数为nand_flash的首地址,第三个参数为需要拷贝的大小
dip.h
int dip_init(void); 初始化
int dip_num(void); 显示数字
int dip_test(void); 测试
seg7.h
int seg7_init(void); 初始化
int seg7_display_num(int num);显示数字
int seg7_test(void); 测试
2.库函数
stdio.h
char * uart_gets(char *buf); 打印字符串
void uart_puts(char *str); 接收字符串
void uart_printf(const char *str, ...);格式化输出
void uart_put_num(int num,int pow);打印数字
stdlib.h
int my_strcmp(char *src, char *dst);比较字符串,相等返回0
int my_atoi(char *str);转换字符串为数字
char * found_ch(char *str, char ch);在一个字符串中寻找一个字符
int my_strlen(char *str);计算字符串长度
int is_number(char ch);一个字符是否数字
int pow(int num, int power);计算num的power次方
int my_atox(char *str);将一个字符串按16进制转为数字
3.协议
xmodem.h
int xmodem_receive(int argc, char *argv);
int get_record(void);
4.其他
命令对应的解释函数,为方便调用参数均为void *
void help(void *argv);
void go(void *argv);
void loadx(void *argv);
void beep_test(void *argv);
void led_off(void *argv);
void led_on(void *argv);
void seg7_on(void *argv);
void dip4_on(void *argv);
void shell(void);
void led_test(void * argv);
void flash_load(void *argv);
void flash_write(void *argv);
void delay(int);
2.start.s
Code:
;s3c2440 bootloader
;author: tongxiaohua
;time : 2009.12.22
AREA FIRST, CODE, READONLY
ENTRY
CODE32
IMPORT uart_test
IMPORT sdram_test
START
WatchDog
;Close WatchDog
LDR R0, =0X53000000
MOV R1, #0X0
STR R1, [R0]
Led_on
;Make a Led on
LDR R2, =0x20800000
MOV R4, #0X1
STRB R4, [R2]
;BL DELAY
Beep_off
;Close Beep
;Control GPB0 output
LDR R0, =0x56000010
MOV R1, #0X1
STR R1, [R0]
LDR R0, =0X56000014
MOV R1, #0X0
STR R1, [R0]
Interrupt_off
;CLose Interrupt
LDR R0, =0X4A000008
LDR R1, =0XFFFFFFFF
STR R1, [R0]
Init_Clock
; Init Clock
; Set Mode
MRC p15,0,R1,c1,c0,0
ORR R1,R1,#0XC0000000
MCR p15,0,R1,c1,c0,0
;CAMDIVN
;When Config the register CLKDIVN Nedd This Configre
LDR R0,=0x4c000018
MOV R1,#0x0
STR R1,[r0]
;LOCKTIME PLL
LDR R0,=0x4c000000
LDR R1,=0x00ffffff
STR R1,[r0]
;UPLLCON
LDR R0,=0x4c000008
LDR R1,=0x00038022
STR R1,[R0]
NOP
NOP
NOP
NOP
NOP
NOP
NOP
;MPLLCON
LDR R0,=0x4c000004
LDR R1,=0x00044011
STR R1,[r0]
;CLKCON
;Witch divice need Clock
LDR R0,=0x4c00000c
LDR R1,=0x00fffff0
STR R1,[R0]
;CLKSLOW
;Low Clock
LDR R0,=0x4c000010
LDR R1,=0x00000004
STR R1,[R0]
;CLKDIVN
;HCLK = FCLK/3 PCLK = HCLK/2
LDR R0,=0x4c000014
LDR R1,=0x00000007
STR R1,[R0]
;Uart0
;Uart
;LDR SP, =0x1000
;LDR R2, =0x20800000
;MOV R4, #0X7
;STRB R4, [R2]
;BL uart_test
Memsetup
;SDRAM Init
ldr r1,=MEM_CTL_BASE
adrl r2,mem_cfg_val
add r3,r1,#52
1
ldr r4,[r2],#4
str r4,[r1],#4
cmp r1,r3
bne %1
nop
nop
nop
nop
MEM_CTL_BASE EQU 0X48000000
mem_cfg_val
DCD 0x22111110
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0X00018005
DCD 0X00018005
DCD 0X008E0459
DCD 0X000000B1
DCD 0X00000030
DCD 0X00000030
Nandflash
;NandFlash,Bootloader CopyMyself
ldr sp,=0x33ef0000
IMPORT copy_myself
;nand_begin=0x0
;size=0x20000
;sdram_begin=0x33f00000
BL copy_myself
ldr r1,=on_the_ram
add pc,r1,#0
nop
nop
nop
on_the_ram
;Select mode
IMPORT load
ldr sp,=0x33ef0000
BL uart_test
BL sdram_test
BL load
B .
END
2.Copy_myself.c
Code:
/* NAND Flash registers 2440*/
#include "DataType.h"
#include "stdio.h"
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCONT (*(volatile unsigned int *)0x4e000004)
#define NFCMD (*(volatile unsigned char *)0x4e000008)
#define NFADDR (*(volatile unsigned char *)0x4e00000c)
#define NFDATA (*(volatile unsigned char *)0x4e000010)
#define NFSTAT (*(volatile unsigned char *)0x4e000020)
#define NFMECC0 (*(volatile unsigned *)0x4E00002C)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1))
#define NAND_CHIP_DISABLE (NFCONT |= (1<<1))
#define NAND_CLEAR_RB (NFSTAT |= (1<<2))
#define NAND_DETECT_RB { while(! (NFSTAT&(1<<0)) );}
/* 在第一次实用NAND Flash前,复位一下NAND Flash */
#define BUSY 1
#define InitEcc() (NFCONT |= (1<<4))
#define MEccUnlock() (NFCONT &= ~(1<<5))
#define MEccLock() (NFCONT |= (1<<5))
#define SEccUnlock() (NFCONT &= ~(1<<6))
#define SEccLock() (NFCONT |= (1<<6))
/*for 8 bit nand flash, only use NFMECC0*/
#define RdNFMEcc() (NFMECC0)
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/*
inline void wait_idle(void)
{
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
*/
void reset_nand(void)
{
//int i=0;
// NFCONF &= ~0x800;
// for(; i<10; i++);
NFCONF = 0x1400;
NFCONT = 0x73;
NAND_CHIP_ENABLE;
NFCMD = 0xff; //reset command
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
/* 初始化NAND Flash */
void init_nand(void)
{
NFCONT = 0x73;
NAND_CHIP_DISABLE;
reset_nand();
}
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NAND_CLEAR_RB;
NFCMD = 0;
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
NAND_DETECT_RB;
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
NAND_CHIP_DISABLE;
return 0;
}
int NandErase(unsigned long start_addr)
{
if (start_addr & NAND_BLOCK_MASK) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE;
NAND_CLEAR_RB;
NFCMD = 0x60;
NFADDR = (start_addr>> 9) & 0xff;
NFADDR = (start_addr>> 17) & 0xff;
NFADDR = (start_addr>> 25) & 0xff;
NFCMD = 0xd0;
NAND_DETECT_RB;
uart_printf("Erase 0x%x/r",start_addr);
NAND_CHIP_DISABLE;
return 0;
}
int nand_write_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j, k;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
for(k = 0; k <= size / (16 * 1024); k++)
NandErase(start_addr + (k * 16 * 1024));
NAND_CHIP_ENABLE;
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
// if(k % 32 == 0) NandErase(start_addr);
NAND_CLEAR_RB;
NFCMD = 0x80;
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
NFDATA = *buf;
buf++;
}
NFCMD = 0x10;
NAND_DETECT_RB;
}
NAND_CHIP_DISABLE;
return 0;
}
void copy_myself(void)
{
unsigned char *buf = ((unsigned char *)0x33f00000);
unsigned long start_addr = 0;
int size = 0x20000;
reset_nand();
init_nand();
nand_read_ll(buf,start_addr,size);
}
3.dip.c
Code:
/*
* dip.c - dip api & driver
*
* Board: akae2440
* environment: bootloader & ADS
* Author: akaedu
* Date: 2009-5-26
* web: www.akaedu.org
*
*
* GPIO address_MAP
*
* CPLD_MAP_BASE physical address is 0x20800000
* CPLD_LED physical address is 0x20800000
* CPLD_SEG physical address is 0x20800080
* CPLD_DIP physical address is 0x208000a0
*
* GPIO port_MAP
*
* GPA_PORT~GPB_PORT(130 multi-functional input port pins)
* GPIO_BASE : GPACON : 0x56000000
*
* NAME GPIO CPLD_IN CPLD_OUT GPIO_CON MODE_bit_CON GPIO_DAT MODE_bit_DAT
* BEEP GPB0 TOUT0 BEEP 0x56000010 [1:0] 0x56000014 [0]
*
* GPIO key_scn_MAP
*
* NAME PORT_OUT PORT_IN
* KEY(sw1) KBOUT1 : GPB8 KBIN1 : ENT0 : GPF0
* KEY(sw2) KBOUT0 : GPB9 KBIN1 : ENT0 : GPF0
* KEY(sw3) KBOUT1 : GPB8 KBIN0 : ENT2 : GPF2
* KEY(sw4) KBOUT1 : GPB8 KBIN1 : ENT2 : GPF2
*
* GPIO_CON GPIO_DAT GPIO MODE_bit_CON MODE_bit_DAT
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB8 [17:16] [8]
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB9 [19:18] [9]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF0 [1:0] [0]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF2 [5:4] [2]
*
*/
#include "dip.h"
#include "seg7.h"
#define CPLD_DIP *((volatile unsigned char *)0x208000a0)
int dip_init(void)
{
return 0;
}
int dip_num(void)
{
return CPLD_DIP;
}
int dip_test(void)
{
int dip_input;
int i = 5000000;
seg7_init();
dip_init();
while(i--)
{
dip_input = dip_num();
seg7_display_num(dip_input);
}
return 0;
}
4.load.c
Code:
#include "uart.h"
#include "shell.h"
#include "stdlib.h"
#include "stdio.h"
#include "nand.h"
#define SEC 3
#define LOAD_OS 0
#define LOAD_SHELL 1
#define OS_MEM_ADDR 0x31000000
#define OS_ADDR (100 * 32 * 512) /*OS address*/
#define OS_SIZE 0x20000
/*Move OS to Sdram From NandFlash*/
void os_test(void)
{
unsigned char *buf = (unsigned char *)OS_MEM_ADDR;
unsigned long start = OS_ADDR;
int size = OS_SIZE;
uart_printf("/rcopy opration system to the sdrm from nanflash.../r");
reset_nand();
init_nand();
nand_read_ll(buf, start, size);
}
/*Wait for User Enter Any Key to Login in the Shell of Bootloader*/
int delay_p(int sec)
{
int osec = 500000, i, j;
uart_printf("Enter any key to load in the shell of bootloader:%d", sec);
for(i = 0; i < sec; i++)
{
for(j = 0; j < osec; j++)
{
if(UTRSTAT0 & UTRSTAT_R_READY){
uart_getchar();
return LOAD_SHELL;
}
}
uart_printf("/b%d", sec - i);
}
//uart_printf("return");
return LOAD_OS;
}
/*Shell or OS*/
void load(void)
{
int load_stat;
if((load_stat = delay_p(SEC)) == LOAD_OS)
{
os_test();
uart_printf("/rrun in the oprition system.../r");
go((void *)OS_MEM_ADDR);
}
else
{
shell();
}
}
5.seg7.c
Code:
/*
* seg7.c - seg7 api & driver
*
* Board: akae2440
* environment: bootloader & ADS
* Author: akaedu
* Date: 2009-5-26
* web: www.akaedu.org
*
*
* GPIO address_MAP
*
* CPLD_MAP_BASE physical address is 0x20800000
* CPLD_LED physical address is 0x20800000
* CPLD_SEG7 physical address is 0x20800080
* CPLD_DIP physical address is 0x208000a0
*
* GPIO port_MAP
*
* GPA_PORT~GPB_PORT(130 multi-functional input port pins)
* GPIO_BASE : GPACON : 0x56000000
*
* NAME GPIO CPLD_IN CPLD_OUT GPIO_CON MODE_bit_CON GPIO_DAT MODE_bit_DAT
* BEEP GPB0 TOUT0 BEEP 0x56000010 [1:0] 0x56000014 [0]
*
* GPIO key_scn_MAP
*
* NAME PORT_OUT PORT_IN
* KEY(sw1) KBOUT1 : GPB8 KBIN1 : ENT0 : GPF0
* KEY(sw2) KBOUT0 : GPB9 KBIN1 : ENT0 : GPF0
* KEY(sw3) KBOUT1 : GPB8 KBIN0 : ENT2 : GPF2
* KEY(sw4) KBOUT1 : GPB8 KBIN1 : ENT2 : GPF2
*
* GPIO_CON GPIO_DAT GPIO MODE_bit_CON MODE_bit_DAT
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB8 [17:16] [8]
* GPBCON : 0x56000010 GPBDAT : 0x56000014 GPB9 [19:18] [9]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF0 [1:0] [0]
* GPFCON : 0x56000050 GPBDAT : 0x56000054 GPF2 [5:4] [2]
*
*/
#include "seg7.h"
#include "shell.h"
#define CPLD_SEG7 *((volatile unsigned char *)0x20800080)
/* delay for about one second */
/*static void delay(int time)
{
int i, j;
for(i = 0; i < time; i++)
for(j = 0; j < 500000; j++)
;
}*/
int seg7_init(void)
{
CPLD_SEG7 = 0x0;
return 0;
}
/* display number on seg7 */
int seg7_display_num(int num)
{
CPLD_SEG7 = 1<<num;
return 0;
}
int seg7_test(void)
{
int i;
seg7_init();
for(i = 0; i < 8; i++)
{
seg7_display_num(i);
delay(1);
}
return 0;
}
8.shell.c
Code:
#include "shell.h"
#include "uart.h"
#include "stdlib.h"
#include "stdio.h"
#include "xmodem.h"
#include "dip.h"
#include "seg7.h"
#include "nand.h"
#define START_ADDR 0x30000000
#define END_ADDR 0x34000000
#define MAX_LINE 256
#define CMD_NUM 11
#define LED_NUM 8
#define START_FLASH 0x0
#define END_FLASH 0x40000000
#define START_MEM 0x30000000
#define END_MEM 0x34000000
#define MAX_SIZE (END_MEM - START_MEM - 0x20000)
#define LED_ADDR *((volatile unsigned int *)0x20800000)
#define GPB0 *((volatile unsigned int *)0x56000010)
#define BEEP *((volatile unsigned int *)0x56000014)
/*delay*/
void delay(int sec)
{
int i, j;
for(i = 0; i < sec; i++)
{
for(j = 0; j < 500000; j++)
;
}
}
struct CMD{
char *cmd_line;
void (*fun)(void *);
}cmd[CMD_NUM] ={
{"help", help},
{"loadx", loadx},
{"go", go},
{"led_on", led_on},
{"led_off", led_off},
{"beep_test", beep_test},
{"led_test", led_test},
{"seg7_test", seg7_on},
{"dip4_test", dip4_on},
{"flash_load", flash_load},
{"flash_write", flash_write},
//{"flash_write", flash_write},
};
void flash_load(void *arg)
{
char *argv[4], *end;
int flash_start, mem_start, size;
argv[1] = arg;
uart_printf("the arg is %s/r", arg);
if((end = found_ch(arg, ' ')) == NULL)
{
uart_printf("Uaseage1: <flash_load> <flash address> <sdram address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[2] = end;
if((end = found_ch(end, ' ')) == NULL)
{
uart_printf("Uaseage2: <flash_load> <flash address> <sdram address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[3] = end;
if((flash_start = my_atox(argv[1])) < START_FLASH || (mem_start = my_atox(argv[2])) < START_MEM ||(size = my_atox(argv[3])) > MAX_SIZE || (mem_start + size) > END_MEM)
{
uart_printf("Access Violation: Please check your address/r");
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
}
else
{ uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
nand_read_ll((unsigned char *)mem_start, flash_start, size);
}
}
#if 1
void flash_write(void *arg)
{
char *argv[4], *end;
int flash_start, mem_start, size;
argv[1] = arg;
uart_printf("the arg is %s/r", arg);
if((end = found_ch(arg, ' ')) == NULL)
{
uart_printf("Uaseage1: <flash_load> <sdram address> <flash address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[2] = end;
if((end = found_ch(end, ' ')) == NULL)
{
uart_printf("Uaseage2: <flash_load> <sdram address> <flash address> <size>/r");
return;
}
else
{
*end = '/0';
end++;
}
argv[3] = end;
if((flash_start = my_atox(argv[2])) < START_FLASH || (mem_start = my_atox(argv[1])) < START_MEM ||(size = my_atox(argv[3])) > MAX_SIZE || (mem_start + size) > END_MEM)
{
uart_printf("Access Violation: Please check your address/r");
// reset_nand();
// init_nand();
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
}
else
{
uart_printf("flash_start = %x/rmem_start = %x/r size = %x/r", flash_start, mem_start, size);
// reset_nand();
// init_nand();
nand_write_ll((unsigned char *)mem_start, flash_start, size);
}
}
#endif
void loadx(void * argv)
{
int argc;
uart_printf("argv is %s/r",(char *)argv);
if(argv != NULL) argc = 2;
else argc = 1;
if(found_ch(argv, ' ') != NULL)
{
uart_printf("Error: Usage <loadx> <address>/r");
}
else
{
xmodem_receive(argc, argv);
uart_printf("Success!");
}
return;
}
void led_on(void * argv)
{
/*test 第3字节有效*/
// uart_printf("%dnd led is on/r", (int)argv + 1);
// LED_ADDR = 0xff0000;
LED_ADDR |= (1 << ((int)argv + 16));
}
void led_off(void * argv)
{
// uart_printf("%dnd led is off/r", (int)argv + 1);
LED_ADDR &= ~(1 << ((int)argv + 16));
}
void led_test(void * argv)
{
int i, j;
for(i = 0; i < 3; i++ )
{
for(j = 0; j < LED_NUM; j++)
{
led_on((void *)j);
}
delay(1);
for(j = 0; j < LED_NUM; j++)
{
led_off((void *)j);
}
delay(1);
}
}
void beep_test(void *argv)
{
int i;
GPB0 |= 0x1;
for(i = 0; i < 3; i++)
{
BEEP = 0x1;
delay(1);
BEEP = 0x0;
delay(1);
}
}
void seg7_on(void *argv)
{
seg7_test();
}
void dip4_on(void * argv)
{
dip_test();
}
void help(void * argv)
{
uart_printf("loadx - [address], download a file to the borad/r");
uart_printf("go - <address>, go to the addrress/r");
uart_printf("flash_load - <flash address><sdram address><size>, Move the code to sdram from nandflash/r");
uart_printf("flash_write - <sdram address><flash address><size>, Move the code to Nandflash from sdram/r");
uart_printf("led_on - <led number>, test led/r");
uart_printf("led_off - <led_number>, test_led/r");
uart_printf("led_test - test all led/r");
uart_printf("beep_test - test beep/r");
uart_printf("seg7_test - test seg/r");
uart_printf("dip4_test - test dip4, you have ten second to test it/r/r");
}
void go(void *argv)
{
int addr = (int)argv;
if(addr == 0) addr = 0x32000000;
// void (*gt)(void) = (void (*) (void))addr;
if(addr < START_ADDR || addr > END_ADDR)
{
// return -1;
}
else
{
uart_printf("in go/r");
(*(void (*) (void))addr)();
}
}
void shellcmd(char buf[])
{
char *start, *end, *argv = NULL;
int i, i_argv;
start = buf;
if((end = found_ch(buf, ' ')) != NULL)
{
*end = '/0';
argv = end + 1;
}
// uart_printf("buf is before is%s/r",buf);
// uart_printf("the command is %s", start);
// uart_printf("the command is %s", cmd[0].cmd_line);
for(i = 0; i < CMD_NUM; i++)
{
if(my_strcmp(start, cmd[i].cmd_line) == 0)
{
if(i == 3 || i == 4){
i_argv = my_atoi(argv);
// uart_printf("i_argv is %d/r", i_argv);
(* cmd[i].fun)((void *) i_argv);
}
else if(i == 2)
{ i_argv = my_atox(argv);
// uart_printf("i_argv is %x/r", i_argv);
(* cmd[i].fun)((void *) i_argv);
}
else
{
(*cmd[i].fun)((void *) argv);
}
break;
}
}
if(i == CMD_NUM)
{
uart_printf("Command not found/r");
}
}
void shell(void)
{
char buf[MAX_LINE];
while(1)
{
uart_puts("/rT-BOOT#");
uart_gets(buf);
// uart_printf("/rget the command/r");
//uart_puts(buf);
shellcmd(buf);
}
}
6.stdio.c
Code:
#include <stdarg.h>
#include "stdlib.h"
#include "uart.h"
#include "stdio.h"
void uart_puts(char *str)
{
while(*str != '/0')
{
uart_putchar(*str);
str++;
}
}
char *uart_gets(char *str)
{
int i;
if(str == NULL) return str;
for(i = 0; ; i++)
{
str[i] = uart_getchar();
/*do shomthing when '/b is input'*/
if(str[i] == '/b')
{
if(i > 0){
uart_putchar('/b');
i -= 2;
}
else
{
i = -1;
}
}
else
{
uart_putchar(str[i]);
}
if(str[i] == '/r' || str[i] == '/n')
{
str[i] = '/0';
break;
}
}
return str;
}
void uart_put_num(int num,int pow)
{
if(num != 0)
{
uart_put_num(num/pow, pow);
if(num%pow > 9)
uart_putchar((char)(num%pow - 10) + 'A');
else
uart_putchar((char)(num%pow + '0'));
}
}
void uart_printf(const char *str, ...)
{
va_list ap;
char c, ch;
char * s; int num;
va_start(ap, str);
while(c = *str++)
{
if(c != '%')
{
uart_putchar(c);
}
else
{
c = *str++;
switch(c)
{
case 'c':
ch = va_arg(ap, int);
uart_putchar((char)ch);
break;
case 's':
s = va_arg(ap, char *);
uart_puts(s);
break;
case 'd':
num = va_arg(ap, int);
uart_put_num(num, 10);
break;
case 'x':
num = va_arg(ap, int);
uart_put_num(num, 16);
break;
default:
uart_putchar(c);
}
}
}
va_end(ap);
}
6.stdlib.h
Code:
#include "stdlib.h"
#include "stdio.h"
int my_strcmp(char *src, char *dst)
{
if(src == NULL || dst == NULL) goto exit;
while(*src == *dst && *src!= '/0' && *dst != '/0')
{
src++;
dst++;
}
exit:
return (*src - *dst);
}
char *found_ch(char *str, char ch)
{
if(str == NULL) goto exit;
while(*str != ch && *str != '/0')
{
str++;
}
exit:
if(*str == ch) return str;
else return NULL;
}
int my_strlen(char *str)
{
char *p = str;
if(str == NULL) goto exit;
while(*str != '/0')
{
str++;
}
exit:
return (str - p);
}
int is_number(char ch)
{
if('0' <= ch && ch <= '9') return 1;
else return 0;
}
int pow(int num, int power)
{
/*do not care about overflow*/
int count = 1;
while(power--)
{
count *= num;
}
return count;
}
int my_atoi(char *str)
{
int len = my_strlen(str), i, count = 0;
// uart_printf("the str is %s/r", str);
// uart_printf("len = %d/r", len);
if(str == NULL) goto exit;
// if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
// str += 2;
for(i = 0; i < len; i++)
{
if(!is_number(str[i])) goto exit;
count += ((str[i] - '0')*pow(10, len - i - 1));
}
exit:
return count;
}
int my_atox(char *str)
{
int len = my_strlen(str), i, count = 0;
// uart_printf("the str is %s/r", str);
// uart_printf("len = %d/r", len);
if(str == NULL) goto exit;
if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')){
str += 2;
len -= 2;
}
for(i = 0; i < len; i++)
{
if(!is_number(str[i])) goto exit;
count += ((str[i] - '0')*pow(16, len - i - 1));
// uart_printf("the count is %x/r", count);
}
exit:
return count;
}
7.uart.c
Code:
/*Uart Driver on S3C2440*/
/*Athor: tongxiaohua */
/*Time : 2009.12.27 */
#include "uart.h"
#include "stdlib.h"
#include "stdio.h"
#include "shell.h"
/*Init Uart0*/
void uart_init(void)
{
ULCON0 |= 3; /*8N1*/
UCON0 = 5; /*Work Frequency Select PCLK, the mode of recive/send select poll*/
UTRSTAT0 &= 6; /*Set Null of recive/send Buffer*/
UBRDIV0 = 26; /*(int)50000000 / (115200*16) - 1*/
GPHCON = 0xa0; /*Set F2, F3 Function*/
UFCON0 = 0;
UMCON0 = 0;
}
/*Put a byte to the Uart0*/
void uart_putchar(char ch)
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = ch;
/*Back Space*/
if(ch == '/b')
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = ' ';
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = '/b';
}
/*Enter*/
if(ch == '/r')
{
while (!(UTRSTAT0 & UTRSTAT_T_EMPTY));
UTX0 = '/n';
}
}
/*Get a byte from Uart*/
char uart_getchar(void)
{
while (!(UTRSTAT0 & UTRSTAT_R_READY));
return URX0;
}
/*Test the Uart is or not Working*/
void uart_test(void)
{
uart_init();
uart_printf("/r/rWelecom to use my bootloader/rAuthor:tong xiaohua/rBoard:s3c2440/r");
uart_printf("Time: 2009.12.27/rCPU: Arm 920T/rSRAM: 4k/rSDRAM:32M/rNAND FLASH:64M/r");
uart_printf("Uart0 is working.../r");
}
/*Test the Sdram is or Not Working*/
void sdram_test(void)
{
int testnum = 0x12345678;
*((volatile unsigned int *)0x32000000) = testnum;
testnum = *((volatile unsigned int *)0x32000000);
if(testnum == 0x12345678)
{
// uart_printf("%x/r", testnum);
uart_printf("sdram is working.../r");
// uart_printf("test.../r");
}
else
{
// uart_printf("test faild/r");
uart_printf("sdram working error.../r", testnum);
// uart_printf("test.../r");
}
}
8.xmodem.c
Code:
#include "xmodem.h"
/* 这两个头文件是你已经实现的功能函数,下面
* 代码中用到的函数如不是xmodem.c中定义的,
* 需移植你已写好的函数接口到本程序中,如
* uart0_getchar()、uart0_putchar()、
* myprintf()等
*/
#include "stdio.h"
#include "uart.h"
#include "stdlib.h"
/* global error variable */
char *xmodem_errtxt = NULL;
int get_byte_err = 0;
U8 volatile receive_buffer[BLOCK_SIZE];
//unsigned download_addr = 0x8000;
/* prototypes of helper functions */
int get_record(void);
enum
{
SAC_SEND_NAK = 0,
SAC_SENT_NAK = 1,
SAC_PAST_START_NAK = 2
};
static volatile int seen_a_char = SAC_SEND_NAK;
//static int one_nak = 0;
//static unsigned long xmodem_timeout = GET_BYTE_TIMEOUT;
char debugbuf[4096];
int db_idx = 0;
static void delay(void)
{
int j;
for (j = 0; j < 2000090; j++)
;
}
int xmodem_receive(int argc, char *argv)
{
char ochr;
int r = 0, rx_block_num = 0, error_count = 0;
int foffset = 0;
int i;
unsigned int download_addr;
char nak = NAK;
xmodem_errtxt = NULL;
seen_a_char = 0;
uart_printf("in xmodem argc = %d, argv = %s /r", argc, argv);
// if(argc > 1) download_addr = atox(argv[1]);
if(argc > 1) download_addr = my_atox(argv);
else download_addr = 0x32000000;
uart_printf("download_addr is %x," , download_addr);
UART0_putchar('9');
delay();
UART0_putchar('8');
delay();
UART0_putchar('7');
delay();
UART0_putchar('6');
delay();
UART0_putchar('5');
delay();
UART0_putchar('4');
delay();
UART0_putchar('3');
delay();
UART0_putchar('2');
delay();
UART0_putchar('1');
delay();
UART0_putchar('0');
//uart_putchar(UART0_BASE, nak);
UART0_putchar(nak);
rx_block_num = 1;
/* times to retry */
error_count = RETRIES;
do {
/* when local block number equals to the block number in the packet,
store the data into the memory which download_addr points*/
if ((r = get_record()) == (rx_block_num & 255)) {
error_count = RETRIES;
for (i = 0; i <BLOCK_SIZE; i++)
*(U8 *)(download_addr+foffset+i) = receive_buffer[i];
xmodem_errtxt = "RX PACKET";
rx_block_num++;
ochr = ACK;
foffset += BLOCK_SIZE;
} else {
switch (r) {
case -1: /* TIMEOUT */
xmodem_errtxt = "TIMEOUT";
ochr = NAK;
break;
case -2: /* Bad block */
xmodem_errtxt = "BAD BLOCK#";
/* eat teh rest of the block */
#if 0
get_byte_err = 0;
while (get_byte_err != -1) get_byte();
#endif
ochr = NAK;
break;
case -3: /* Bad checksum */
xmodem_errtxt = "BAD CHKSUM";
ochr = NAK;
break;
case -4: /* End of file */
xmodem_errtxt = "DONE";
ochr = ACK;
break;
case -5: /* Cancel */
xmodem_errtxt = "ABORTED";
ochr = ACK;
break;
default: /* Block out of sequence */
xmodem_errtxt = "WRONG BLK";
ochr = NAK;
}
error_count--;
}
UART0_putchar(ochr);
} while ((r > -3) && error_count);
if ((!error_count) || (r != -4)) {
foffset = 0; /* indicate failure to caller */
}
my_printf( "Loaded file at address 0x%x, size = %d /r/n",(int)download_addr, foffset);
return foffset;
}
/*
* Read a record in the XMODEM protocol, return the block number
* (0-255) if successful, or one of the following return codes:
* -1 = Bad byte
* -2 = Bad block number
* -3 = Bad block checksum
* -4 = End of file
* -5 = Canceled by remote
*/
int get_record(void)
{
char c;
int block_num = 0;
int i;
U32 check_sum;
/* clear the buffer */
for (i = 0; i < BLOCK_SIZE; i++)
receive_buffer[i] = 0x00;
check_sum = 0;
/* initialize i to -2,when begin to transfer,the first byte
will be store into blcok_num,and after plused one,the next
byte will be treated as a negated section */
i = -2;
//uart_getchar( UART0_BASE, &c);
c = UART0_getchar();
switch (c)
{
case SOH: /* Receive packet */
for (;;)
{
//uart_getchar( UART0_BASE, &c);
c = UART0_getchar();
switch (i)
{
case -2:
block_num = c;
break;
case -1:
#if 0
#ifdef CHECK_NEGATED_SECTNUM
if (c != (-block_num -1))
return -2;
#endif
#endif
break;
case BLOCK_SIZE:
/* check if reveived data is correct,
when correct,block num is returned,
else -3 is returned */
if ((check_sum & 0xff) != c)
return -3;
else
return block_num;
break;
default:
/* save data to buffer,and accumulate to check_sum */
receive_buffer[i] = c;
check_sum += c;
}
i++;
}
case EOT: /* end of file encountered */
return -4;
case CAN: /* cancel protocol */
return -5;
default:
return -5;
}
}
相关文章推荐
- 求旋转数组的最小数字算法的解析以及完整c语言代码实现
- 实现进程隐藏(完整源代码)
- (三)边做边发---产销系统---详细设计--代码实现--更新时间2007/8/1--提供整站完整源代码下载
- Prim最小生成树算法详解以及java实现源代码
- 利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包括增删改查、JavaBean反射原理,附源代码)
- Android实现记事本项目完整实例,附源代码
- Android实现记事本项目完整实例,附源代码
- 微信小程序:地图导航功能实现完整源代码附效果图,讲解
- Java实现远程控制技术完整源代码分享
- java实现电脑远程控制完整源代码(转)
- C# 实现预览dwg文件完整源代码(无需autocad环境)
- Android 用Gallery和ImageSwicher实现画廊效果,展示图片+完整源代码
- java实现电脑远程控制完整源代码
- 基于邻接矩阵存储的无向网图的创建,最小生成树算法实现完整代码
- 求无向连通图的最小割点详解以及java源代码实现
- 快速排序的基本实现(完整源代码)
- java实现电脑远程控制完整源代码
- Java实现远程控制技术(附完整源代码)
- 面试题:较为完整的atoi的实现,奶牛苹果的最小搬运次数
- jsp中完整的分页显示和页面跳转功能实现的源代码