关于写自己的升级程序时碰到的一个问题!~
首先,官方的示例代码中使用的DFU保存在xdata中,如果升级程序到一半出错,下次启动就要按P33来启动到bootloader中了,但并不是所有产品都适合做按铵那么在bootloader中,把状态写进EEPROM无疑是最佳的办法了。。。
也就是说单片机通电,启动到bootloader中,先读取EEPROM特定位置,状态字节为0xff,那么就启动到正常的程序中执行、
正常程序检测到上位机发来升级命令,先修改EEPROM特定位置,状态字节改为1,然后切换到bootloader中,等待上位机发送升级内容,
升级完成后,修改状态字节为0xff,重启,升级成功!即使升级到一半中断了,由于状态字节为1,下次启动还是会进入bootloader中,接着升级就好了。。。
但是问题就是,在bootloader 与 普通程序中,如何写addr的地址,才能保证两块程序都能定位到同一个扇区的相同位置的EEPROM呢???
在bootloader 与 普通程序中,操作EEPROM的地址是相同的,可设置地址在程序空间后面。
例如普通程序空间60K,前面50K存放程序,最后10K作为EEPROM存储数据。
那么EEPROM起始地址为:1024*50 = 0xC800 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-4-23 09:52
STC32G144K246与AI8051U有专门的用户系统区,用法跟其它芯片不一样。
STC32G144K246用户系统区从EEPROM空 ...
那么用户ISP程序中,使用的是绝对地址,在用户APP程序中,读写eeprom时,地址为0x000000时,其实是读到了哪个地址上的数据呢?
其实我就想知道,在用户ISP程序中,与用户APP程序中,能同时读写到EEPROM同一地址的同一位置就解决问题了,可是不知道两个地址怎么写,我使用的是STC32G144K246。
用户ISP区操作EEPROM使用Flash绝对地址,用户程序区操作EEPROM地址需要从用户ISP区(4K)地址后面开始
附件例子供参考:
乘风飞扬 发表于 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开始的位置,如何写代码实现呢?我之前一直是这么理解的。
先直接用例子测试,功能验证正常后再进行修改或者移植。
例子按照说明书设置用户系统区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: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);
}
这两块地址是不是重复了呢?
例子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 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]