STC8H8K64U单片机bootloader无法跳转app程序
经过验证我已经把外置flash的程序copy到eeprom的0x400地址上,我在bootloader程序定义:
typedef void (*FunctionPointer)(void);
FunctionPointer entry_app = (FunctionPointer)0x0400;
然后在main函数中执行
entry_app();
并没有和想象中一样会跳转到这个地址执行我的代码。
求大牛们指点一下
1、下载时EEPROM设置为多大?
这关系到EEPROM的地址和ROM地址关系,EEPROM的地址0x400并不一定等于ROM的地址0x400
2、你存放在外部flash中的代码,在编译时目标地址是多少?
3、外置flash中的代码中是否有绝对调用(ACALL/LCALL)或者绝度跳转(AJMP/LJMP)指令?
上面的3点都有可能导致外部flash代码复制到EEPROM后无法正常运行 zhp 发表于 2023-6-29 20:57
1、下载时EEPROM设置为多大?
这关系到EEPROM的地址和ROM地址关系,EEPROM的地址0x400并不一定等于RO ...
1、eeprom设置40k,片内flash大小是64k,这需要加上这24k的偏移吗,IAP访问eeprom的话我的代码就是放在0x400这个位置
2、外部代码编译时没有做其他任何设置
3、也没有调用跳转的命令,就正常编译出来一个bin文件
本帖最后由 chenyl 于 2023-6-30 11:38 编辑
zhp 发表于 2023-6-29 20:57
1、下载时EEPROM设置为多大?
这关系到EEPROM的地址和ROM地址关系,EEPROM的地址0x400并不一定等于RO ...
"C:\Users\chen\Desktop\企业微信截图_16880960118897.png"
我直接改上面这里启动是可以运行我拷过来的代码的,正常流程跳转的话要怎么改呢 chenyl 发表于 2023-6-30 11:35
我直接改上面这里启动是可以运行我拷过来的代码的,正常流程跳转的话要怎么改呢 ...
根据你的情况,你的EEPROM必须设置为64K,让EEPROM和ROM完全重合
才能保证EEPROM的0x400地址对应到ROM的0x400 zhp 发表于 2023-6-30 18:07
根据你的情况,你的EEPROM必须设置为64K,让EEPROM和ROM完全重合
才能保证EEPROM的0x400地址对应到ROM的0 ...
我刚刚试了,把EEPROM设置大小设置成64K,拷贝应用程序的地址挪到了0x5000,还是没跑起来{:4_205:} chenyl 发表于 2023-6-30 18:39
我刚刚试了,把EEPROM设置大小设置成64K,拷贝应用程序的地址挪到了0x5000,还是没跑起来 ...
将你的示例代码发出来看一下 zhp 发表于 2023-7-1 19:21
将你的示例代码发出来看一下
// 定义EEPROM的起始地址和大小
#define EEPROM_START_ADDRESS 0x5000
#define EEPROM_SIZE 0x5000
// 定义接收和发送数据的缓冲区
#define BUFFER_SIZE 256
uint8_t recv_buf;
uint8_t send_buf;
typedef void (*FunctionPointer)(void);
FunctionPointer entry_app = (FunctionPointer)0x5000;
void IapProgram(int addr, int dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置等待参数12MHz
IAP_CMD = 2; //设置IAP写命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_DATA = dat; //写IAP数据
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
// 接收一个字节的数据
uint8_t receive_byte() {
SPDAT = 0xff;
while((SPSTAT & SPIF) == 0) ;
SPSTAT = SPIF + WCOL; //清0 SPIF和WCOL标志
return (SPDAT);
}
// 定义一个函数从外置SPI Flash中读取数据
void read_flash(uint32_t address, uint8_t *dat, uint32_t sz)
{
if(sz == 0) return;
while(CheckFlashBusy() > 0); //Flash忙检测
SPI_CS = 0; //enable device
send_byte(0x03); //read command
send_byte(((u8 *)&address)); //设置起始地址
send_byte(((u8 *)&address));
send_byte(((u8 *)&address));
do{
*dat = receive_byte(); //receive byte and store at buffer
dat++;
}while(--sz); //read until no_bytes is reached
SPI_CS = 1; //disable device
}
// 定义一个函数将应用程序从外置SPI Flash中拷贝到EEPROM中
void copy_app_to_eeprom() {
uint32_t app_size;
uint16_t addr;
uint16_t rev;
uint32_t k;
uint32_t offset;
uint32_t sz;
uint8_t TEST = 0x55;
Get_App_Size((unsigned int*)&app_size);
// 擦除EEPROM
for (addr = EEPROM_SIZE; addr <EEPROM_SIZE+ EEPROM_SIZE; )
{
IapErase(addr);
addr = addr+512;
}
app_size = 0x4800;//暂时手动设置读取的大小
sz = BUFFER_SIZE;
for (k = 0; k < app_size; ) {
offset = 0 + k;
read_flash(offset, recv_buf, sz);
for (rev = 0; rev < sz; rev++) {
IapProgram(EEPROM_START_ADDRESS + k + rev, recv_buf);
}
k += BUFFER_SIZE;
}
}
void SPI_init(void)
{
P2M0 &= ~0x3e;
P2M1 &= ~0x3e;
SPCTL |=(1 << 7); //忽略 SS 引脚功能,使用 MSTR 确定器件是主机还是从机
SPCTL |=(1 << 6); //使能 SPI 功能
SPCTL &= ~(1 << 5); //先发送/接收数据的高位( MSB)
SPCTL |=(1 << 4); //设置主机模式
SPCTL &= ~(1 << 3); //SCLK 空闲时为低电平,SCLK 的前时钟沿为上升沿,后时钟沿为下降沿
SPCTL &= ~(1 << 2); //数据 SS 管脚为低电平驱动第一位数据并在 SCLK 的后时钟沿改变数据
SPCTL = (SPCTL & ~3) | 3; //SPI 时钟频率选择, 0: 4T, 1: 8T,2: 16T,3: 32T
P_SW1 = (P_SW1 & ~(3<<2)) | (1<<2); //IO口切换. 0: P1.2/P5.4 P1.3 P1.4 P1.5, 1: P2.2 P2.3 P2.4 P2.5, 2: P5.4 P4.0 P4.1 P4.3, 3: P3.5 P3.4 P3.3 P3.2
SPI_CLK = 0; // set clock to low initial state
SPI_SI = 1;
SPSTAT = SPIF + WCOL; //清0 SPIF和WCOL标志
}
void main() {
// 初始化SPI
SPI_init();
// FlashCheckID();
// FlashCheckID();
should_copy_app_to_eeprom = 1;// 判断是否需要将应用程序拷贝到EEPROM中
if (should_copy_app_to_eeprom) {
copy_app_to_eeprom();
}
// 跳转到应用程序的地址
EA = 0;
entry_app();
} zhp 发表于 2023-7-1 19:21
将你的示例代码发出来看一下
大概是这样,麻烦帮看一下 chenyl 发表于 2023-7-2 22:30
大概是这样,麻烦帮看一下
主要是要看你放到外部Flash中的代码、项目设置以及
你将外置代码写入到外部Flash中的一些步骤
页:
[1]
2