chenyl 发表于 2023-6-29 19:51:00

STC8H8K64U单片机bootloader无法跳转app程序

经过验证我已经把外置flash的程序copy到eeprom的0x400地址上,

我在bootloader程序定义:

typedef void (*FunctionPointer)(void);
FunctionPointer entry_app = (FunctionPointer)0x0400;


然后在main函数中执行
entry_app();

并没有和想象中一样会跳转到这个地址执行我的代码。
求大牛们指点一下

zhp 发表于 2023-6-29 20:57:54

1、下载时EEPROM设置为多大?
      这关系到EEPROM的地址和ROM地址关系,EEPROM的地址0x400并不一定等于ROM的地址0x400
2、你存放在外部flash中的代码,在编译时目标地址是多少?
3、外置flash中的代码中是否有绝对调用(ACALL/LCALL)或者绝度跳转(AJMP/LJMP)指令?

上面的3点都有可能导致外部flash代码复制到EEPROM后无法正常运行

chenyl 发表于 2023-6-30 09:15:39

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:35:46

本帖最后由 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"
我直接改上面这里启动是可以运行我拷过来的代码的,正常流程跳转的话要怎么改呢

zhp 发表于 2023-6-30 18:07:46

chenyl 发表于 2023-6-30 11:35
我直接改上面这里启动是可以运行我拷过来的代码的,正常流程跳转的话要怎么改呢 ...

根据你的情况,你的EEPROM必须设置为64K,让EEPROM和ROM完全重合
才能保证EEPROM的0x400地址对应到ROM的0x400

chenyl 发表于 2023-6-30 18:39:44

zhp 发表于 2023-6-30 18:07
根据你的情况,你的EEPROM必须设置为64K,让EEPROM和ROM完全重合
才能保证EEPROM的0x400地址对应到ROM的0 ...

我刚刚试了,把EEPROM设置大小设置成64K,拷贝应用程序的地址挪到了0x5000,还是没跑起来{:4_205:}

zhp 发表于 2023-7-1 19:21:13

chenyl 发表于 2023-6-30 18:39
我刚刚试了,把EEPROM设置大小设置成64K,拷贝应用程序的地址挪到了0x5000,还是没跑起来 ...

将你的示例代码发出来看一下

chenyl 发表于 2023-7-2 22:29:33

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();
}

chenyl 发表于 2023-7-2 22:30:18

zhp 发表于 2023-7-1 19:21
将你的示例代码发出来看一下

大概是这样,麻烦帮看一下

zhp 发表于 2023-7-3 08:56:07

chenyl 发表于 2023-7-2 22:30
大概是这样,麻烦帮看一下

主要是要看你放到外部Flash中的代码、项目设置以及
你将外置代码写入到外部Flash中的一些步骤
页: [1] 2
查看完整版本: STC8H8K64U单片机bootloader无法跳转app程序