为了方便代码的升级,常常会在代码里面增加自动升级代码的部分单片机的内部的 FLASH 。将 FLASH 分成 LDROM 和 APPROM。
LDROM
LDROM是加载引导
APPROM
APROM是应用程序
解决方案
在开机的时候我们检测是否要升级程序,如果不用升级就直接跳转到 APPROM 里面,在新唐的单片机里面是通过软件复位跳转到APPROM,在 arm 的架构里面在不同的 Flash 上面是通过跳转指令直接跳转到应用程序。
code
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright(c) 2018 Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
//***********************************************************************************************************
// File Function: ML51 UART0 ISP demo code
//***********************************************************************************************************
#include "ML51.H"
/************************************************************************************************************
* Main function
************************************************************************************************************/
#pragma save
#pragma optimize (8)
void IAP_goSet(void)
{
TA=0xAA;
TA=0x55;
IAPTRG|=SET_BIT0;
}
void IAP_Enable(void)
{
TA=0xAA;
TA=0x55;
CHPCON|=SET_BIT0;
}
void IAP_uEnable(void)
{
TA=0xAA;
TA=0x55;
IAPUEN|=SET_BIT0;
}
void IAP_clrCHPCON(void)
{
TA=0xAA;
TA=0x55;
CHPCON&=CLR_BIT6;
}
void ISP_Reboot2Approm(void)
{
TA=0xAA;
TA=0x55;
CHPCON = 0x00;
TA=0xAA;
TA=0x55;
CHPCON = 0x80; //set boot from AP
}
#pragma restore
#undef set_IAPTRG_IAPGO
#define set_IAPTRG_IAPGO IAP_goSet()
#undef set_CHPCON_IAPEN
#define set_CHPCON_IAPEN IAP_Enable()
#undef set_IAPUEN_APUEN
#define set_IAPUEN_APUEN IAP_uEnable()
#undef clr_CHPCON_IAPFF
#define clr_CHPCON_IAPFF IAP_clrCHPCON()
void main (void)
{
//uart initial for ISP programmer GUI, always use 115200 baudrate
SFRS=0x01;P1UP|=SET_BIT5;
UART0_ini_115200();
TM0_ini();
g_timer0Over=0;
g_timer0Counter=5000;
g_progarmflag=0;
if (P1 & (1<<5))
goto _APROM;
while(1)
{
if(bUartDataReady == TRUE)
{
EA=0; //DISABLE ALL INTERRUPT
if(g_progarmflag==1)
{
for(count=8;count<64;count++)
{
IAPCN = BYTE_PROGRAM_AP; //program byte
IAPAL = flash_address&0xff;
IAPAH = (flash_address>>8)&0xff;
IAPFD=uart_rcvbuf[count];
set_IAPTRG_IAPGO;
IAPCN = BYTE_READ_AP; //program byte verify
set_IAPTRG_IAPGO;
if(IAPFD!=uart_rcvbuf[count])
while(1);
if (CHPCON==0x43) //if error flag set, program error stop ISP
while(1);
g_totalchecksum=g_totalchecksum+uart_rcvbuf[count];
flash_address++;
if(flash_address==AP_size)
{
g_progarmflag=0;
goto END_2;
}
}
END_2:
Package_checksum();
uart_txbuf[8]=g_totalchecksum&0xff;
uart_txbuf[9]=(g_totalchecksum>>8)&0xff;
Send_64byte_To_UART0();
if (g_progarmflag == 0)
{
goto _APROM;
}
}
switch(uart_rcvbuf[0])
{
case CMD_CONNECT:
case CMD_SYNC_PACKNO:
{
Package_checksum();
Send_64byte_To_UART0();
g_timer0Counter=0; //clear timer 0 for no reset
g_timer0Over=0;
break;
}
case CMD_RUN_APROM:
{
goto _APROM;
break;
}
case CMD_UPDATE_APROM:
{
set_CHPCON_IAPEN;
set_IAPUEN_APUEN;
IAPFD = 0xFF; //Erase must set IAPFD = 0xFF
IAPCN = PAGE_ERASE_AP;
AP_size=0;
AP_size=uart_rcvbuf[12];
AP_size|=(uart_rcvbuf[13]<<8);
for(flash_address=0x0000;flash_address>8)&0xff;
IAPFD=uart_rcvbuf[count];
clr_CHPCON_IAPFF;
set_IAPTRG_IAPGO;
IAPCN = BYTE_READ_AP; //program byte verify
set_IAPTRG_IAPGO;
if(IAPFD!=uart_rcvbuf[count])
while(1);
if (CHPCON==0x43) //if error flag set, program error stop ISP
while(1);
g_totalchecksum=g_totalchecksum+uart_rcvbuf[count];
flash_address++;
if(flash_address==AP_size)
{
g_progarmflag=0;
goto END_1;
}
}
END_1:
Package_checksum();
uart_txbuf[8]=g_totalchecksum&0xff;
uart_txbuf[9]=(g_totalchecksum>>8)&0xff;
Send_64byte_To_UART0();
break;
}
}
bUartDataReady = FALSE;
bufhead = 0;
EA=1;
}
//For connect timer out
if(g_timer0Over==1)
{
goto _APROM;
}
//for uart time out or buffer error
if(g_timer1Over==1)
{
if((bufhead<64)&&(bufhead>0)||(bufhead>64))
{
bufhead=0;
}
}
}
_APROM:
ISP_Reboot2Approm();
while(1);
}
对部分代码的说明
#pragma save
#pragma optimize (8)
/*.
. 中间的代码的优化等级设计为8,其他代码的优化等级在后面会进行恢复
.*/
#pragma restore
遇到问题的总结
- 1.单片机设置成上拉模式需要时间,如果初始化完成就去检测会检测不到
SFRS=0x01;
P1UP|=SET_BIT5;
UART0_ini_115200();
TM0_ini();
g_timer0Over=0;
g_timer0Counter=5000;
g_progarmflag=0;
if (P1 & (1<<5))
goto _APROM;
上面代码的功能是开机的时候进行检测按键是否已经按下,如果没有按下直接进行软件复位 ,这里面的判断加载初始话后面的主要原因是为了等待内部上拉,如果直接加在
SFRS=0x01;
P1UP|=SET_BIT5;
后面就会出现错误
- 2 编译器的优化等级太高的时候对于连续的赋值会出现被优化的情况,这样连续的赋值在大多数情况下是可以被优化的,但是当这些和硬件的'时序有关的时候,硬件之间的通信就会出现不正常的现象。
#pragma optimize (8)
void IAP_goSet(void)
{
TA=0xAA;
TA=0x55;
IAPTRG|=SET_BIT0;
}
...
和时序有关的代码可以适当的降低优先级
里面的代码是根据新唐的支持包进行修改的,为了节省空间,将里面的部分的功能删除,最后将代码的空间缩小到 1K 以内