|
鉴于大家学习方便,现给出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)();
}
|
|