电子大神的日记本,供应链专家的功夫茶盘,在这里记录、分享与共鸣。

登录以开始

C8051F340 BOOTLOADER 固件升级的的实现过程

实现过程:

一:内部flash 的空间划分

0XFFFF

保留区

应用程序区

BOOTLOADER可操作区域

0XF000

0X1000

0X1000

0X0000

二:中断向量软件映射

MCU中断向量分布在复位(0x0000)以后,按规则排布,若改变编译器设置,如51,可改变程序在FLASH中的位置,可改变中断向量起始点,如改到这样0X1000,即:就是将0X0000地址内容映射到0X1000,把0X1000作为一个虚拟的复位地址,编译后,中断向量安装在0X1000后。但是,硬件跳转是不能改变的。就是说中断发生后,仍然进入以0X0000为复位地址的向量表。但是,这个向量表中,不再是直接跳转到中断服务程序,而是需要手动跳转到虚拟中断向量表,再由虚拟中断向量表跳转到中断服务程序。但是其原始向量表可能为空,所以需要加入程序判进行手动跳转到新向量表。
       所以编译的时候,将APP程序中断向量表虚拟,BOOT程序使用原始的向量表。所以任何时候中断发生后,将执行BOOT中断服务程序。在BOOT中断服务程序中判断当前程序是执行BOOT区还是APP区,如果是执行APP区,就跳转到APP中断服务程序即可(入口向量已经规则地排布在0X1000以后)。

51的中断向量排布规则是:  LJMP   3+8*INTERRUPT_VECTOR_NUMBER

图解:

原始地址(向量表)
作用
描述

0000H
RESET
POWER UP ENTRY

0003H
INTERRUPT 0入口

000BH
INTERRUPT 1入口

0013H
INTERRUPT 2入口



虚拟后地址(向量表)
作用
描述

1000H
虚拟复位地址

1003H
INTERRUPT 0虚拟入口
进入中断

100BH
INTERRUPT 1虚拟入口
进入中断



注意:中断向量虚拟后,并不是说发生中断程序就转入虚拟后的向量表。而是:中断向量表的实质是一条跳转指令,跳转到相关ISR,虚拟后,这个跳转指令被放在了新的地址,而不是原始默认地址。所以,需要在原始地址处再放一辅助向量表(中断发生后,硬件挑到此处),用于跳转到新的向量表。这个辅助向量表有BOOT区完成。

1:STARTUP.A51文件设置:

;vector_base           EQU     01000h

;vector

CSEG    AT      03h

LJMP    vect + 03h            ;// 0 外部中断0 (/INT0)

;user_address     EQU     01000h

user_process:

LJMP    vect;user_address

CSEG    AT      0bh

LJMP    vect + 0bh            ;// 1 定时器0溢出

CSEG    AT      13h

LJMP    vect + 013h          ;// 2 外部中断1 (/INT1)

CSEG    AT      1bh

LJMP    vect + 01bh          ;// 3 定时器1溢出

CSEG    AT      23h

LJMP    vect + 023h          ;// 4 UART0

CSEG    AT      2bh

LJMP    vect + 02bh          ;// 5 定时器2溢出

CSEG    AT      33h

LJMP    vect + 033h          ;// 6 SPI0

CSEG    AT      3bh

LJMP    vect + 03bh          ;// 7 SMB0

CSEG    AT      43h

LJMP    vect + 043h          ;// 8 USB0

CSEG    AT      4bh

LJMP    vect + 04bh          ;// 9 ADC0窗口比较

CSEG    AT      53h

LJMP    vect + 053h          ;// 10 ADC0转换结束

CSEG    AT      5bh

LJMP    vect + 05bh          ;// 11 可编程计数器阵列

CSEG    AT      63h

LJMP    vect + 063h          ;// 12 比较器0

CSEG    AT      6bh

LJMP    vect + 06bh          ;// 13 比较器1

CSEG    AT      73h

LJMP    vect + 073h          ;// 14 定时器3溢出

CSEG    AT      7bh

LJMP    vect + 07bh          ;// 15 VBUS电平

CSEG    AT      83h

LJMP    vect + 083h          ;// 16 UART1

CSEG    AT      000h

?C_STARTUP:     LJMP    STARTUP1

2:应用程序区工程设置:

3:bootloader程序和 APP 应用程序的初始化时钟必须是一致的, 否则容易造成死机的现象

三:BOOTLOADER 程序

1:主程序的编写

main(void)

{

uint8 uartRX;

uint16 timeout;

void (*boot)( void);

Sys_Clk_Init();  // 初始化设备

PORT_Init();

UART0_Init();

FLSCL = 0x86;

if (1) {

Uart_Print("\n");

Uart_Print("**************BootLoader v1.0***************\n");

Uart_Print(">Please press 's' to start programming.\n");

while (1)

{

for(timeout=0;timeout<4000;timeout++)

{

if(RI0)

{

uartRX=SBUF0;

RI0=0;

break;

}

delay_ms(10);

}

if (uartRX=='s')

{RTload();

uartRX = 0;

}

else if(vect == 0x02)

{

goto USE_CODE;

}

}

}

USE_CODE:

user_process();

while(1)

{

}

2:片内FLASH的 操作

unsigned char FLASH_ByteRead (FLADDR addr)

{

bit EA_SAVE = EA;

char code * data pread;

unsigned char byte;

EA = 0;

pread = (char code *) addr;

byte = *pread;

EA = EA_SAVE;

return byte;

}

void FLASH_ByteWrite (FLADDR addr, char byte)

{

bit EA_SAVE = EA;

char xdata * data pwrite;

EA = 0;

pwrite = (char xdata *) addr;

PFE0CN = PFE0CN & 0xFE;

PSCTL  = 0x01;

FLKEY  = 0xA5;

FLKEY  = 0xF1;

*pwrite = byte;

PSCTL = 0;

EA = EA_SAVE;

}

void FLASH_PageErase (FLADDR addr)

{

bit EA_SAVE = EA;

char xdata * data pwrite;

EA = 0;

pwrite = (char xdata *) addr;

FLKEY  = 0xA5;

FLKEY  = 0xF1;

PSCTL  = 0x03;

*pwrite = 0;

PSCTL = 0;

EA = EA_SAVE;

}

可以正常使用串口更新程序, 有需要的, 可以给我留言,一起起步!

博主
081010
081010's Blog
081010
点击跳转