TQ2440裸板更新程序_update

来源:互联网 发布:淘宝促销活动 编辑:程序博客网 时间:2024/06/16 22:06

以前的裸板程序都是通过u-boot下载到内存运行,今天实现更新程序update,程序运行时会输出一个菜单供选择。

系统:ubuntu 10.04.4
单板:tq2440
编译器:arm-linux-gcc-4.3.2
搭建开发环境详见ubuntu 10.04.4开发环境配置。

目标:实现自我更新程序,串口输出菜单,有以下·功能供选择

*********************************
update program with serial port
The board:TQ2440
The NAND:K9F1216U0A 256MB
The NOR:EN29LV160AB 2MB
The SRAM:HY57V561620 x2 64MB
The NET:DM9000AEP
                 date: 2013.4.26
***********************************
the menu of the update programe:
[w] write the nand flash
[r] read the nand flash
[e] erase the nand flash
[g] get file, and write to nand flash 0 block
[x] get file to ddr(0x32000000), run it
[s] reset the programe
Please enter the chose:

一、编写源代码

根据s3c2440手册编写代码,包括文件:start.S init.c main.c boot.lds Makefile

文件start.S:

#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))#define MEM_CTL_BASE    0x48000000.text.global_start_start:/*1.关看门狗*/ldr r0, =0x53000000mov r1, #0str r1, [r0]/*2.设置时钟*/ldr r0, =0x4c000014mov r1, #0x03str r1, [r0]/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */mrcp15, 0, r1, c1, c0, 0/* 读出控制寄存器 */ orrr1, r1, #0xc0000000/* 设置为“asynchronous bus mode” */mcrp15, 0, r1, c1, c0, 0/* 写入控制寄存器 *//* MPLLCON = S3C2440_MPLL_200MHZ */ldr r0, =0x4c000004ldr r1, =S3C2440_MPLL_200MHZstr r1, [r0]/*3.初始化SDRAM*/ldr r0, =MEM_CTL_BASEadr r1, sdram_config/*当前地址*/add r3, r0, #(13*4)1:ldr r2, [r1], #4str r2, [r0], #4cmp r0 ,r3bne 1b/*4.重定位:把bootloader本身代码从flash复制到他的链接地址*/ldr sp, =0x34000000bl nand_initmov r0, #0ldr r1, =_startldr r2, =__bss_startsub r2 ,r2, r1bl copy_code_to_sdrambl clear_bss/*5.执行main*///bl mainldr lr, =haltldr pc, =mainhalt:b haltsdram_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
文件init.c:

/* 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 UFSTAT0             (*(volatile unsigned long *)0x50000018)#define UTXH0               (*(volatile unsigned char *)0x50000020)#define URXH0               (*(volatile unsigned char *)0x50000024)#define UBRDIV0             (*(volatile unsigned long *)0x50000028)#define TXD0READY   (1<<2)void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len);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 int src, unsigned int dest, unsigned int len){  int i = 0;  unsigned char *src_start = (unsigned char *)src;  unsigned char *dest_start = (unsigned char *)dest;  /*如果是Nor启动*/  if(isBootFromNorFlash())    {      while (i < len){  //dest[i] = src[i];  dest_start[i] = src_start[i];  i++;}      }  else    {      //nand_init();      //nand_resd(src, dest, len)      nand_read(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_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 wait_ready(void){while (!(NFSTAT & 1));}unsigned char nand_get_data(void){return NFDATA;}void nand_send_data(unsigned char data){  NFDATA = data;}void nand_reset(void){  /* 选中 */  nand_select();  /* 发出0xff命令 */  nand_cmd(0xff);  /* 等待就绪 */  wait_ready();  /* 取消选中 */  nand_deselect();}void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len){unsigned int addr = nand_start;int col = addr % 2048;int i = 0;unsigned char *dest = (unsigned char *)ddr_start;/* 1. 选中 */nand_select();while (i < len){/* 2. 发出读命令00h */nand_cmd(0x00);/* 3. 发出地址(分5步发出) */nand_addr(addr);/* 4. 发出读命令30h */nand_cmd(0x30);/* 5. 判断状态 */wait_ready();/* 6. 读数据 */for (; (col < 2048) && (i < len); col++){dest[i] = nand_get_data();i++;addr++;}col = 0;}/* 7. 取消选中 */nand_deselect();}void nand_erase_block(unsigned long addr){  int page = addr / 2048;    nand_select();  nand_cmd(0x60);    nand_addr(page & 0xff);  nand_addr((page >> 8) & 0xff);  nand_addr((page >> 16) & 0xff);  nand_cmd(0xd0);  wait_ready();  nand_deselect();}void nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len){  unsigned long count = 0;  unsigned long addr  = nand_start;  int i = nand_start % 2048;  //int left = i;    nand_select();  while (count < len)    {      nand_cmd(0x80);      nand_addr(addr);      //for (; i < (2048-left) && count < len; i++)      for (; i < 2048 && count < len; i++){  /*if(addr<16384)//写前2K    {      if(i<(2048-left))//前2页每页只能写2K{  nand_send_data(buf[count++]);}    }  else    {      nand_send_data(buf[count++]);      }*/  nand_send_data(buf[count++]);  addr++;}      nand_cmd(0x10);      wait_ready();      i = 0;      //left = i;    }  nand_deselect();  }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);  nand_reset();}#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)#define ENABLE_FIFO static void delay(void){  volatile int i = 10;  while (i--);}/* * 初始化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    #ifdef ENABLE_FIFOUFCON0 = 0x07; /* FIFO enable */    #elseUFCON0 = 0x00; /* FIFO disable */    #endif    UMCON0  = 0x00;     // 不使用流控    UBRDIV0 = UART_BRD; // 波特率为115200}/* * 发送一个字符 */void putc(unsigned char c){    /* 等待,直到发送缓冲区中的数据已经全部发送出去 */    //while (!(UTRSTAT0 & TXD0READY));    #ifdef ENABLE_FIFO    while (UFSTAT0 & (1<<14))delay();    #else    while ((UTRSTAT0 & (1<<2)) == 0);#endif       /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */    UTXH0 = c;}/* * 接收字符 */unsigned char getc(void){    /* 等待,直到接收缓冲区中的有数据 */    //while (!(UTRSTAT0 & RXD0READY));    #ifdef ENABLE_FIFO    while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)delay();    #else    while ((UTRSTAT0 & (1<<0)) == 0);#endif       /* 直接读取URXH0寄存器,即可获得接收到的数据 */    return URXH0;}int getc_nowait(unsigned char *pChar){#ifdef ENABLE_FIFO  if ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)#else    if ((UTRSTAT0 & (1<<0)) == 0)#endif      {return -1;      }    else      {*pChar = URXH0;return 0;      }}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);      elseputc('A' + j - 0xa);    }}void putbyte(unsigned char val){  /* 0x1234abcd */  int i;  int j;  puts("0x");  for (i = 0; i < 2; i++)    {      j = (val >> ((1-i)*4)) & 0xf;      if ((j >= 0) && (j <= 9))putc('0' + j);      elseputc('A' + j - 0xa);    }}
文件main.c:

extern void uart0_init(void);extern void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len);extern void putc(char c);extern void puts(char *str);extern void puthex(unsigned int val);extern unsigned char getc(void);extern int getc_nowait(unsigned char *pChar);extern void putbyte(unsigned char val);extern void nand_erase_block(unsigned long addr);extern void nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len);int strlen(char *str){int i = 0;while (str[i]){i++;}return i;}void nand_write_test(void){  char buf[20] = {"abcd1234ABCD"};  unsigned long addr;  unsigned long size;    puts("enter the start address:0x80000 ");  //scanf("%s", buf);  //addr = strtoul(buf, NULL, 0);  addr = 0x80000;  puts("enter the string:abcd1234ABCD ");  //scanf("%s", buf);  size = strlen(buf) + 1;  puts(" size= ");  puthex(size);  puts("\n\r");  nand_write(addr, buf, size);  }void nand_read_test(void){  int i;  char buf[100];  unsigned long addr;  unsigned long size;   puts("enter the start address: 0x80000");  //scanf("%s", buf);  //addr = strtoul(buf, NULL, 0);  addr = 0x80000;  //puts("read addr = 0x%x\n\r", addr);  puts("enter the size: 0x60");  //scanf("%s", buf);  //size = strtoul(buf, NULL, 0);  size = 0x60;  if (size > 100)    {      puts("the max size is 100\n\r");      size = 100;    }  nand_read(addr, buf, size);  puts("datas: \n\r");  for (i = 0; i < size; i++)    {      // printf("%02x ", buf[i]);      putbyte(buf[i]);      puts("\t");      if ((i+1) % 8 == 0){  puts("\n\r");}    }  puts("\n\r");}void nand_erase_test(void){  //char buf[100];  unsigned long addr;    puts("enter the start address: ");  //scanf("%s", buf);  //addr = strtoul(buf, NULL, 0);  addr = 0x80000;  puts("erase addr = ");  puthex(addr);  puts("\n\r");  nand_erase_block(addr);  }void update_program(void){  unsigned char *buf = (unsigned char *)0x32000000;  //unsigned char *buf = (unsigned char *)0xD0036000;  unsigned long len = 0;  int have_begin = 0;  int nodata_time = 0;  unsigned long erase_addr;  char c;  int i;  /* 璇讳覆鍙h幏寰楁暟鎹?*/  puts("\n\ruse V2.2.exe/gtkterm to send file\n\r");  while (1)    {      if (getc_nowait(&buf[len]) == 0){  have_begin = 1;  nodata_time = 0;  len++;}      else{  if (have_begin)    {      nodata_time++;    }}      if (nodata_time == 1000){  break;}    }  puts("\n\rhave get data:");  puthex(len);  puts(" bytes\n\r");  puts("the first 16 bytes data: \n\r");  for (i = 0; i < 16; i++)    {      // put("%02x ", buf[i]);      putbyte(buf[i]);      puts("\t");    }  puts("\n\r");  puts("Press Y to program the flash: \n\r");  c = getc();  putc(c);  puts("\n\r");  if (c == 'y' || c == 'Y')    {      /* 鐑у啓鍒皀and flash block 0 */      for (erase_addr = 0; erase_addr < ((len + 0x1FFFF) & ~0x1FFFF); erase_addr += 0x20000){  nand_erase_block(erase_addr);}      nand_write(0, buf, len);            puts("update program successful\n\r");    }  else    {      puts("Cancel program!\n\r");    }}void run_program(void){  unsigned char *buf = (unsigned char *)0x32000000;  //unsigned char *buf = (unsigned char *)0xD0036000;  unsigned long len = 0;  int have_begin = 0;  int nodata_time = 0;  void (*theProgram)(void);  int i;  /* 璇讳覆鍙h幏寰楁暟鎹?*/  puts("\n\r use gtkterm to send file\n\r");  while (1)    {      if (getc_nowait(&buf[len]) == 0){  have_begin = 1;  nodata_time = 0;  len++;}      else{  if (have_begin)    {      nodata_time++;    }}      if (nodata_time == 10000){  break;}    }  //printf("have get %d bytes data\n\r", len);  puts("\n\r have get data:");  puthex(len);  puts(" bytes\n\r");  puts("the first 16 bytes data: \n\r");  for (i = 0; i < 16; i++)    {      // put("%02x ", buf[i]);                                                                           putbyte(buf[i]);      puts("\t");      //putc('\0');    }  puts("\n\r");  puts("jump to 0x32000000 to run it\n\r");    theProgram = (void (*)(void))0x32000000;  theProgram();}int main(void){  char c;  uart0_init();  puts("\n\r*********************************\n\r");  puts("update program with serial port\n\r");  puts("The board:TQ2440\n\r");  puts("The NAND:K9F1216U0A 256MB\n\r");  puts("The NOR:EN29LV160AB 2MB\n\r");  puts("The SRAM:HY57V561620 x2 64MB\n\r");  puts("The NET:DM9000AEP\n\r");  puts("                 date: 2013.4.26\n\r");  puts("***********************************\n\r");  while (1)    {      puts("the menu of the update programe:\n\r");      puts("[w] write the nand flash\n\r");      puts("[r] read the nand flash\n\r");      puts("[e] erase the nand flash\n\r");      puts("[g] get file, and write to nand flash 0 block\n\r");      puts("[x] get file to ddr(0x32000000), run it\n\r");      puts("[s] reset the programe\n\r");      puts("Please enter the chose:\n\r");      do {c = getc();if (c == '\n' || c == '\r')  {    puts("\n\r");  }else  {    putc(c);  }      } while (c == '\n' || c == '\r');            switch (c){case 'w':case 'W':  {    nand_write_test();    break;  }case 'r':case 'R':  {    nand_read_test();    break;  }case 'e':case 'E':  {    nand_erase_test();    break;  }case 'g':case 'G':  {    update_program();    break;  }case 'x':case 'X':  {    run_program();    break;  }case 's':case 'S':  {    void (*theProgram)(void);    theProgram = (void (*)(void))0x33f80000;    theProgram();    break;  }}    }  return 0;}
文件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-gccLD      = arm-linux-ldAR      = arm-linux-arOBJCOPY = arm-linux-objcopyOBJDUMP = arm-linux-objdumpCFLAGS := -Wall -O2CPPFLAGS   := -nostdinc -nostdlib -fno-builtinobjs := start.o init.o main.oupdate.bin: $(objs)${LD} -Tboot.lds -o boot.elf $^${OBJCOPY} -O binary -S boot.elf $@${OBJDUMP} -D -m arm boot.elf > update.dis%.o:%.c${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<%.o:%.S${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<clean:rm -f *.o *.bin *.elf *.dis
二、编译源代码

change@change:~$ cd Si/TQ2440/update/
change@change:~/Si/TQ2440/update$ make clean
rm -f *.o *.bin *.elf *.dis
change@change:~/Si/TQ2440/update$ ls
boot.lds  init.c  main.c  Makefile  start.S
change@change:~/Si/TQ2440/update$ make
arm-linux-gcc -nostdinc -nostdlib -fno-builtin -Wall -O2 -c -o start.o start.S
arm-linux-gcc -nostdinc -nostdlib -fno-builtin -Wall -O2 -c -o init.o init.c
arm-linux-gcc -nostdinc -nostdlib -fno-builtin -Wall -O2 -c -o main.o main.c
main.c: In function 'nand_write_test':
main.c:38: warning: pointer targets in passing argument 2 of 'nand_write' differ in signedness
main.c: In function 'nand_read_test':
main.c:69: warning: passing argument 2 of 'nand_read' makes integer from pointer without a cast
arm-linux-ld -Tboot.lds -o boot.elf start.o init.o main.o
arm-linux-objcopy -O binary -S boot.elf update.bin
arm-linux-objdump -D -m arm boot.elf > update.dis
change@change:~/Si/TQ2440/update$ cp update.bin /home/change/work/tftpboot/
change@change:~/Si/TQ2440/update$

三、烧写、测试

单板从NOR flash启动,用u-boot下载上面编译的程序update.bin到NAND Flash

U-Boot 1.1.6 (Mar 24 2012 - 03:44:51)


DRAM:  64 MB
Flash:  2 MB
NAND:  256 MiB
In:    serial
Out:   serial
Err:   serial
Hit any key to stop autoboot:  0 
TQ2440 # set ipaddr 172.16.1.133
TQ2440 # set gatewayip 172.16.1.1
TQ2440 # set serverip 172.16.1.131
TQ2440 # tftp 0x32000000 update.bin
dm9000 i/o: 0x20000000, id: 0x90000a46 
MAC: 00:80:00:80:00:80
could not establish link
TFTP from server 172.16.1.131; our IP address is 172.16.1.133
Filename 'update.bin'.
Load address: 0x32000000
Loading: ##
done
Bytes transferred = 5136 (1410 hex)
TQ2440 # nand erase 0 0x40000


NAND erase: device 0 offset 0x0, size 0x40000
Erasing at 0x20000 -- 100% complete.
OK
TQ2440 # nand write 0x32000000 0 0x40000


NAND write: device 0 offset 0x0, size 0x40000
 262144 bytes written: OK
TQ2440 # save
Saving Environment to NAND...
Erasing Nand...Writing to Nand... done
TQ2440 # 

程序烧写完毕,接着单板断电从NAND启动,设置串口115200 8 n 1输出如下:

*********************************
update program with serial port
The board:TQ2440
The NAND:K9F1216U0A 256MB
The NOR:EN29LV160AB 2MB
The SRAM:HY57V561620 x2 64MB
The NET:DM9000AEP
                 date: 2013.4.26
***********************************
the menu of the update programe:
[w] write the nand flash
[r] read the nand flash
[e] erase the nand flash
[g] get file, and write to nand flash 0 block
[x] get file to ddr(0x32000000), run it
[s] reset the programe
Please enter the chose:

下面开始用串口v2.2.exe测试更新程序:

*********************************
update program with serial port
The board:TQ2440
The NAND:K9F1216U0A 256MB
The NOR:EN29LV160AB 2MB
The SRAM:HY57V561620 x2 64MB
The NET:DM9000AEP
                 date: 2013.4.26
***********************************
the menu of the update programe:
[w] write the nand flash
[r] read the nand flash
[e] erase the nand flash
[g] get file, and write to nand flash 0 block
[x] get file to ddr(0x32000000), run it
[s] reset the programe
Please enter the chose:

手动发送g
g
use V2.2.exe/gtkterm to send file

选择要发送的程序文件eg:boot.bin,并发送文件
have get data:0x000008BC bytes
the first 16 bytes data: 
0x53 0x04 0xA0 0xE3 0x00 0x10 0xA0 0xE3 0x00 0x10 0x80 0xE5 0x98 0x00 0x9F 0xE5

Press Y to program the flash: 
y

此时需谨慎,手动发送y,会擦除以前的程序,向NAND写新的程序
update program successful

这表明程序更新完毕,断电重启就会启动上面发送文件程序,这里串口输出如下:

Copy kernel from nand
0x1234ABCD
0x7D98ACBA
Set boot params
Boot kernel

测试OK,程序跑起来了。

原创粉丝点击