原创 C8051F340 Bootloader 代码

2009-8-1 00:17 5717 13 17 分类: MCU/ 嵌入式

鉴于大家学习方便,现给出C8051F340 Bootloader的代码架构,由于涉及商业信息,所以不能给出整个工程,请谅解!


相关文档信息,请参看blog: http://blog.ednchina.com/zhurunping/239751/message.aspx#



// 项目名称: C8051F340 BootLoader
// 版本介绍:
// 1.4.2 该程序仅作学习测试使用, 请勿用作其他.
//   介意使用内部晶振.


/** 擦除一个分区 */
#define flash_erase(addr)  D_MACRO_BEGIN \
         FLKEY = 0xA5; \
         FLKEY = 0xF1; \
         PSCTL  = 0x03; \
         *addr = 0x00; \
         PSCTL = 0x00; \
        D_MACRO_END


/** 写入Flash一个字节*/
#define flash_write(addr, x) D_MACRO_BEGIN \
         FLKEY = 0xA5; \
         FLKEY = 0xF1; \
         *(addr) = x; \
        D_MACRO_END


/** 串口查询方式发送一字节数据*/
#define Uart_PutCh(dat)   D_MACRO_BEGIN \
         SBUF1 = dat; \
         while ((SCON1&0x02) == 0); \
         SCON1 &= 0xFD; \
        D_MACRO_END


#define D_APP_START  0x0000    // APP区起始地址
#define D_APP_LIMIT  0xEE00    // APP区结束地址
#define D_RUN_ADDRESS 0xEE00    // APP运行地址(只使用3Byte)
#define D_BOOT_ADDR  0xF000    // Boot程序存储地址
#define D_BOOT_LIMIT 0xF800    // Boot区结束地址
#define D_FLASH_LIMIT 0xFA00    // FLASH可操作区结束地址



/** 本地变量*/
uint8 rst_addr[3];      // 用以保存启动向量


uint8 xdata *pwrite;     // 指向代码区的指针
uint8 code *pread;      // 指向代码区的指针
uint8 dat;


/** @func RTload
* @brief 载入函数
*/
static void
RTload(void)
{
 uint8 dat, tmp[4];
 uint16 i, size, dnCS, CheckSum;


 Uart_Print(">Start erasing flash...\n");


 /** 1. 保存boot入口地址, 最后回写 */
 pread = 0;
 rst_addr[0] = *pread++;
 rst_addr[1] = *pread++;
 rst_addr[2] = *pread++;


 /** 2. 准备扇区 */
 for (pwrite=0; pwrite<D_APP_LIMIT; pwrite+=0x200) { // APP区
  flash_erase(pwrite);
 }


 pwrite = D_RUN_ADDRESS;    // 启动参数区
 flash_erase(pwrite);
 Uart_Print(">Erasing complete.\n");


 /** 3. 回写boot入口地址 */
 PSCTL = 0x01;
 pwrite = 0;
 flash_write(pwrite++, rst_addr[0]);
 flash_write(pwrite++, rst_addr[1]);
 flash_write(pwrite++, rst_addr[2]);


 /** 4. 通知主机发送代码 */
 SCON1 |= B_REN1;
 Uart_Print(">Please transmit bin file...\n");


 /** 5. 读接收数据长度 */
 for (i=0; i<4; i++) {
  while ((SCON1&0x01) == 0);
  SCON1 &= 0xFE;
  tmp = SBUF1;
 }
 size = ((tmp[1]<<8)+tmp[0]) - 4 - 2;
 if (size > D_APP_LIMIT) {
  PSCTL = 0x00;
  Uart_Print(">Error: no enough space for your app!\n");
  return;
 }


 /** 6. 开始接收数据, 同时写入Flash APP区*/
 CheckSum= 0;
 pwrite = D_RUN_ADDRESS;    // 启动地址(3Byte)
 for (i=0; i<3; i++) {
  while ((SCON1&0x01) == 0);
  SCON1 &= 0xFE;
  dat = SBUF1;
  CheckSum += dat;
  flash_write(pwrite++, dat);
 }
 pwrite = 3;       // 程序区
 for (i=3; i<size; i++) {
  while ((SCON1&0x01) == 0);
  SCON1 &= 0xFE;
  dat = SBUF1;
  CheckSum += dat;
  flash_write(pwrite++, dat);
 }
 PSCTL = 0x00;       // 禁止Flash操作


 /** 7. 读校验和 */
 for (i=0; i<2; i++) {
  while ((SCON1&0x01) == 0);
  SCON1 &= 0xFE;
  tmp = SBUF1;
 }
 dnCS = (tmp[1]<<8) + tmp[0];
 Uart_Print(">Transmit complete.\n");


 /** 8. 校验数据*/
 if (dnCS != CheckSum) {
  Uart_Print(">CheckSum error!\n");
 } else {
  Uart_Print(">Programming Complete.\n");
  Uart_Print(">You have to restart the device to use the new firmware.\n");
 }
}


void
main(void)
{
 uint8 dat;
 uint16 timeout;
 void (*boot)( void);


 Init_Device();       // 初始化设备


 FLSCL = ((FLSCL&0xF0) | 0x09);  // 设置FLASH预分频器
 PFE0CN = PFE0CN & 0xFE;    // FLASH按字节写入


 // 此处读取Loader使能按键
 // ...


 if (1) { // 用户设置为下载模式
  /** 创建握手过程*/
  Uart_Print("\n");
  Uart_Print("****************ZBoot v1.4.2*****************\n");
  Uart_Print(">Please press 's' to start programming.\n");


  while (1) {
   //  此处判断读入's'
   // ...


   if ("键入正确") {
    RTload();     // Download
   } else if ("超时") {
    goto boot_out;
   }
  }
 }
boot_out:
 pread = D_RUN_ADDRESS;
 if (*pread != 0x02) {
  Uart_Print(">Error: no app program for run!\n");
  while (1);
 }
 boot = D_RUN_ADDRESS;
 (*boot)();
}

PARTNER CONTENT

文章评论4条评论)

登录后参与讨论

用户377235 2014-9-17 16:28

楼主,你的app启动地址(也就是接受的app的前三个字节)是怎么确定的,还是编译器自己产生的?谢谢

用户377235 2014-5-6 13:38

hao

用户813340 2009-12-15 11:14

收藏了。谢谢博主。

tengjingshu_112148725 2009-8-1 14:31

收藏了,为我打开了一扇窗口
相关推荐阅读
用户1156376 2014-08-18 17:23
[博客大赛]MDK下代码的分段管理 续3
继续写点分段管理的问题。 设计思想主要是设计一个通用的BSP,固化后只需要修改APP代码就可以,这适用于远程升级的系统或是进行二次开发的系统。 考虑到编译器链接的时候会把没有使用的代码段(...
用户1156376 2014-02-27 18:14
Freescale MCU SPI
Freescale S12 SPI: 0. 以下所述为查询模式使用SPI 1. SPI控制器有两个中断, 数据发送(SPTEF)和数据接收(SPIF) 2. 数据发送(SPTEF)标志...
用户1156376 2014-02-26 09:17
Freescale MCU摘记
仅用于记录Freescale的点滴记录: 1. 把AD口用作IO口的方法: 除了正常的设置外,还需要把 ATDDIEN 寄存器写为0xFF, 这样使能了数字IO。否则默认为AD输入。 ...
用户1156376 2013-12-14 11:33
[STM32]MDK下代码的分段管理 续2
前文所述的代码分段,限定比较大,对于使用 #pragma arm section code=".ARM.__at_0x8100000" 固定地址的方式,每个文件都需要指定不同的地址以区别。...
用户1156376 2013-12-09 18:12
[STM32]MDK下代码的分段管理
编译大型的程序时,可能某一段代码固定之后不再改变(比如BSP),而应用部分经常修改。在这种情况下,如果使用在线升级或是Bootloader的方式升级程序时,你就觉得每次升级的代码有一部分是重复的(...
用户1156376 2012-10-14 09:10
【uCOS-III移植笔记】OS启动过程
(1) 关闭系统中断 (2) CPU_Init(); 初始化CPU服务(时间戳、中断时间测量、CPU信息初始化等) (3) OSInit(); 初始化系统(系统变量、系统任务...
EE直播间
更多
我要评论
4
13
关闭 站长推荐上一条 /3 下一条