乘简 发表于 2026-4-22 17:11:29

关于写自己的升级程序时碰到的一个问题!~

首先,官方的示例代码中使用的DFU保存在xdata中,如果升级程序到一半出错,下次启动就要按P33来启动到bootloader中了,但并不是所有产品都适合做按铵

那么在bootloader中,把状态写进EEPROM无疑是最佳的办法了。。。

也就是说单片机通电,启动到bootloader中,先读取EEPROM特定位置,状态字节为0xff,那么就启动到正常的程序中执行、

正常程序检测到上位机发来升级命令,先修改EEPROM特定位置,状态字节改为1,然后切换到bootloader中,等待上位机发送升级内容,

升级完成后,修改状态字节为0xff,重启,升级成功!即使升级到一半中断了,由于状态字节为1,下次启动还是会进入bootloader中,接着升级就好了。。。


但是问题就是,在bootloader 与 普通程序中,如何写addr的地址,才能保证两块程序都能定位到同一个扇区的相同位置的EEPROM呢???

乘风飞扬 发表于 2026-4-22 18:58:59

在bootloader 与 普通程序中,操作EEPROM的地址是相同的,可设置地址在程序空间后面。
例如普通程序空间60K,前面50K存放程序,最后10K作为EEPROM存储数据。
那么EEPROM起始地址为:1024*50 = 0xC800

乘风飞扬 发表于 2026-4-23 09:52:32

STC32G144K246与AI8051U有专门的用户系统区,用法跟其它芯片不一样。

STC32G144K246用户系统区从EEPROM空间前面划分(Flash 超过64K的芯片EEPROM空间从前往后划分)。
例如EEPROM大小设置12K,用户系统区设置8K(地址0000H~1FFFH),那么实际的EEPROM空间是12K后面的4K(地址1FFFH~2FFFH)大小。


AI8051U用户系统区从EEPROM空间后面划分(Flash 64K以内的芯片EEPROM空间从后往前划分)。
例如EEPROM大小设置12K,用户系统区设置8K(地址1000H~2FFFH),那么实际的EEPROM空间是12K前面的4K(地址0000H~0FFFH)大小。


乘简 发表于 2026-5-8 14:25:41

乘风飞扬 发表于 2026-4-23 09:52
STC32G144K246与AI8051U有专门的用户系统区,用法跟其它芯片不一样。

STC32G144K246用户系统区从EEPROM空 ...
那么用户ISP程序中,使用的是绝对地址,在用户APP程序中,读写eeprom时,地址为0x000000时,其实是读到了哪个地址上的数据呢?

其实我就想知道,在用户ISP程序中,与用户APP程序中,能同时读写到EEPROM同一地址的同一位置就解决问题了,可是不知道两个地址怎么写,我使用的是STC32G144K246。

乘风飞扬 发表于 2026-5-8 18:11:30

用户ISP区操作EEPROM使用Flash绝对地址,用户程序区操作EEPROM地址需要从用户ISP区(4K)地址后面开始



附件例子供参考:

乘简 发表于 2026-5-9 09:46:18

乘风飞扬 发表于 2026-5-8 18:11
用户ISP区操作EEPROM使用Flash绝对地址,用户程序区操作EEPROM地址需要从用户ISP区(4K)地址后面开始



可能不太对,当我下载程序的时候,设置用户系统区大小为4K,设置用户EEPROM区大小为2K,我测试的结果与你的不同,我单片机断电重启,数据就全部恢复0xff,也就是User ISP Read=0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff


我又改设置,用户系统区大小为4K,用户EEPROM区大小也为4K,数据还是不行,断电就全0xff

只有当用户EEPROM区大小大于4K,数据才对,但下载软件上没有任何提示,而且即使不勾 下次下载程序时擦除EEPROM区的数据,只要重新下载程序,数据全部清除。。。



还有个疑问,就是用户ISP程序,会固定下载到FF:0000开始的位置,大小为4K(可设置),用户APP程序下载到FF:0000+4K的位置,用户的EEPROM,保存到FC:2800开始的位置,如何写代码实现呢?我之前一直是这么理解的。

乘风飞扬 发表于 2026-5-9 10:16:13

先直接用例子测试,功能验证正常后再进行修改或者移植。
例子按照说明书设置用户系统区4K,用户EEPROM大小8K:



修改用户系统区大小后,ISP程序"config.h"里面 LDR_SIZE 要跟着修改:
#define LDR_SIZE                (4 * 1024UL)                //用户系统ISP空间大小(4K字节)

用户APP程序里面的EEPROM起始地址也要跟着修改:
#define OFFSET          0x1000L         //操作EEPROM的起始地址,用户应用程序区操作EEPROM地址需要从用户ISP区(4K)地址后面开始

乘简 发表于 2026-5-9 10:45:16

乘风飞扬 发表于 2026-5-9 10:16
先直接用例子测试,功能验证正常后再进行修改或者移植。
例子按照说明书设置用户系统区4K,用户EEPROM大小8 ...

问题就是,在你的userisp程序中,你的User ISP Read=的地址定义为IAP_BASE地址
#define OFFSET      (IAP_BASE)//操作EEPROM的起始地址,用户ISP操作EEPROM使用Flash绝对地址而这里又有一段代码的地址是addr += IAP_BASE;
BOOL iap_write_byte(DWORD addr, BYTE dat)
{
    if (!iap_check_addr(addr))
      return 0;
    addr += IAP_BASE;

    IAP_CMD = 2;
    IAP_ADDRE = BYTE2(addr);
    IAP_ADDRH = BYTE1(addr);
    IAP_ADDRL = BYTE0(addr);
    IAP_DATA = dat;
    IAP_TRIG = 0x5a;
    IAP_TRIG = 0xa5;
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    return (iap_read_byte(addr) == dat);
}
这两块地址是不是重复了呢?


乘风飞扬 发表于 2026-5-9 11:58:32

例子ISP程序只用到读EEPROM功能,如果要在ISP程序里面写EEPROM的话,就不要再加偏移地址
BYTE iap_read_byte(DWORD addr)
{
    IAP_CMD = 1;
    IAP_ADDRE = BYTE2(addr);
    IAP_ADDRH = BYTE1(addr);
    IAP_ADDRL = BYTE0(addr);
    IAP_TRIG = 0x5a;
    IAP_TRIG = 0xa5;
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    return IAP_DATA;
}

BOOL iap_write_byte(DWORD addr, BYTE dat)
{
    if (!iap_check_addr(addr))
      return 0;
    addr += IAP_BASE;

    IAP_CMD = 2;
    IAP_ADDRE = BYTE2(addr);
    IAP_ADDRH = BYTE1(addr);
    IAP_ADDRL = BYTE0(addr);
    IAP_DATA = dat;
    IAP_TRIG = 0x5a;
    IAP_TRIG = 0xa5;
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    return (iap_read_byte(addr) == dat);
}

乘简 发表于 2026-5-9 13:51:30

乘风飞扬 发表于 2026-5-9 11:58
例子ISP程序只用到读EEPROM功能,如果要在ISP程序里面写EEPROM的话,就不要再加偏移地址
...

发现个有意思的问题。。。我在你的代码前面加了一段

      if(P33 == 0)
      {
            printf("Read0=");   //增加的代码
            for(i=0;i<10;i++)
            {
                a = IapRead(0+i);
                printf("0x%02x ",a);
            }
            printf("\r\n");

            printf("Read1=");   //读取EEPROM原先的内容
            for(i=0;i<10;i++)
            {
                a = IapRead(OFFSET+i);
                printf("0x%02x ",a);
                if(a == 0xff) a = i;//如果内容为空,则写入初始化数据
                else a++;    //如果内容非空,在原先基础上加1
            }
            printf("\r\n");

            IapErase(OFFSET);
//            IapErase(OFFSET+512);//跨扇区擦除下一个扇区
            printf("Read2=");   //擦除、重写后,读取EEPROM现在的内容
            for(i=0;i<10;i++)
            {
                IapProgram(OFFSET+i, a);
                a = IapRead(OFFSET+i);
                printf("0x%02x ",a);
            }
            printf("\r\n");
            while(!P33);
      }

下面这里是userisp的代码的内容


程序运行后,,,结果把userisp的内容给读出来了。。。


说明官方出的未例代码中的文档中,权限这一是错的。。。
页: [1]
查看完整版本: 关于写自己的升级程序时碰到的一个问题!~