cr81 发表于 2024-2-2 15:23:47

STC32G12K128 在线更新USB-ISP+EEPROM程序

最近测试的STC32G12K128-USB在线升级这个没问题了,按照例程配置ISP程序128K全部为EEPROM。
但是在用户程序里有用到36字节EEPROM。现在把36字节地址设置eeprom为0x01FA00 但是读出的全是0XFF。
是不是eeprom地址有偏移?请大佬帮忙分析一下。



#define   T1MS                                  (65536 - FOSC/1000)
#define   DFU_TAG                           0x12abcd34 //DFU强制执行标志
#define      IAP_BASE                              0XFF0000          //基地址
#define      EEPROM_ADDR                        0x01FA00    //读写的EEPROM地址

long xdata DfuFlag _at_ 0x1ffc;                            //DFU标志, 定义在xdata的最后4字节

u8      const default_config ={0X43,0X4C,0X41,0X56,0X48,0X50,0X20,0X01,0X10,0X0E,0X0E,0X3C,0X3C,
0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X32,0X2E,0X30,0X2E,0X30,0X00,0X00};

u8         RAM_CONFIG;                        //保存写入读出的eeprom数据


char cnt8;
int cnt300;
int cnt500;
int cnt1000;

void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    TMOD = 0x00;
    T0x12 = 1;
    TL0 = T1MS;
    TH0 = T1MS >> 8;
    TR0 = 1;
    ET0 = 1;

    DfuFlag = 0;                  //上电正常执行用户AP,时需要将DFU标志清零
}

void tm0_isr() interrupt 1                //1mS中断
{
    if (cnt1000++ >= 1000)                //1秒进入一次
    {
      cnt1000 = 0;
      P21 = ~P21;
    }


   if(P32 == 0)
    {
      if(cnt8++ >= 127)
      {
          EUSB = 0;                  //失能USB中断
          USBCON = 0x08;      //失能usb功能与时钟;DP/DM使能下拉电阻

          DfuFlag = DFU_TAG;   //当需要执行用户ISP代码时,将强制执行标志赋值到DFU标志变量中
          IAP_CONTR = 0x60;   //软复位从ISP区执行
      }
   }else{
               cnt8=0;                                                //清除计数器
         }

    if (DeviceState == DEVSTATE_CONFIGURED)          //如果USB配置没有完成,就直接退出
                USB_polling();
}

void main()
{
    sys_init();
    uart_init();

   EEPROM_read_n(EEPROM_ADDR, RAM_CONFIG,36);                        //读出配置
   if((RAM_CONFIG ==0XFF) || (RAM_CONFIG==0))
   {
      do{
                EEPROM_SectorErase(EEPROM_ADDR);
                EEPROM_write_n(EEPROM_ADDR, default_config,36);
                EEPROM_read_n(EEPROM_ADDR, RAM_CONFIG,36);      //读出配置
      }while((RAM_CONFIG ==0XFF)||(RAM_CONFIG==0));
    }

    usb_init();
    EA = 1;//全局中断使能

    while (1){}
}




///////////////////本程序是STC32G系列的内置EEPROM读写程序。/////////////////////////////////////////
#include "eeprom.h"
#define   IAP_STANDBY()IAP_CMD = 0   //IAP空闲命令(禁止)
#define   IAP_READ()      IAP_CMD = 1   //IAP读出命令
#define   IAP_WRITE()      IAP_CMD = 2   //IAP写入命令
#define   IAP_ERASE()      IAP_CMD = 3   //IAP擦除命令

#define   IAP_ENABLE()    IAP_CONTR = IAP_EN; IAP_TPS = FOSC / 1000000
#define   IAP_DISABLE()   IAP_CONTR = 0; IAP_CMD = 0; IAP_TRIG = 0; IAP_ADDRE = 0xff; IAP_ADDRH = 0xff; IAP_ADDRL = 0xff

#define IAP_EN          (1<<7)//使能eeprom操作
#define IAP_SWBS      (1<<6)
#define IAP_SWRST       (1<<5)
#define IAP_CMD_FAIL    (1<<4)//EEPROM操作状态位

//========================================================================
// 函数: void      ISP_Disable(void)
// 描述: 禁止访问ISP/IAP.
// 版本: V1.0, 2012-10-22
//========================================================================
void      DisableEEPROM(void)      //禁止访问EEPROM
{
      IAP_CONTR = 0;                        //禁止ISP/IAP操作
      IAP_CMD   = 0;                        //去除ISP/IAP命令
      IAP_TRIG= 0;                        //防止ISP/IAP命令误触发
      IAP_ADDRE = 0xff;   //将地址设置到非 IAP 区域
      IAP_ADDRH = 0xff;                //清0地址高字节
      IAP_ADDRL = 0xff;                //清0地址低字节,指向非EEPROM区,防止误操作
}

//========================================================================
// 函数: void EEPROM_Trig(void)
// 描述: 触发EEPROM操作.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_Trig(void)
{
    F0 = EA;    //保存全局中断
    EA = 0;   //禁止中断, 避免触发命令无效
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;                  //先送5AH,再送A5H到IAP触发寄存器,每次都需要如此
                                        //送完A5H后,IAP命令立即被触发启动
                                        //CPU等待IAP完成后,才会继续执行程序。
    _nop_();   //由于STC32G是多级流水线的指令系统,触发命令后建议加4个NOP,保证IAP_DATA的数据完成准备
    _nop_();
    _nop_();
    _nop_();
    EA = F0;    //恢复全局中断
}

//========================================================================
// 函数: void EEPROM_SectorErase(u32 EE_address)
// 描述: 擦除一个扇区.
// 参数: EE_address:要擦除的EEPROM的扇区中的一个字节地址.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_SectorErase(u32 EE_address)
{
    IAP_ENABLE();                     //宏调用, 设置等待时间,允许IAP操作,送一次就够
    IAP_ERASE();                        //宏调用, 送扇区擦除命令,命令不需改变时,不需重新送命令
                                        //只有扇区擦除,没有字节擦除,512字节/扇区。
                                        //扇区中任意一个字节地址都是扇区地址。
    IAP_ADDRE = (u8)(EE_address >> 16); //送扇区地址高字节(地址需要改变时才需重新送地址)
    IAP_ADDRH = (u8)(EE_address >> 8);//送扇区地址中字节(地址需要改变时才需重新送地址)
    IAP_ADDRL = (u8)EE_address;         //送扇区地址低字节(地址需要改变时才需重新送地址)
    EEPROM_Trig();                      //触发EEPROM操作
    DisableEEPROM();                  //禁止EEPROM操作
}

//========================================================================
// 函数: void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u8 lenth)
// 描述: 读N个字节函数.
// 参数: EE_address:要读出的EEPROM的首地址.
//       DataAddress: 要读出数据的指针.
//       length:      要读出的长度
// 返回: 0: 写入正确.1: 写入长度为0错误.2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u8 length)
{
    IAP_ENABLE();                           //设置等待时间,允许IAP操作,送一次就够
    IAP_READ();                           //送字节读命令,命令不需改变时,不需重新送命令
    do
    {
      IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节(地址需要改变时才需重新送地址)
      IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
      EEPROM_Trig();                      //触发EEPROM操作
      *DataAddress = IAP_DATA;            //读出的数据送往
      EE_address++;
      DataAddress++;
    }while(--length);

    DisableEEPROM();
}

void IAPRead(u32 EE_address, u8 *DataAddress,u8 length)
{
      u32 EEaddress;
         do
    {
      EEaddress=(EE_address&0X1FFFF)/IAP_BASE;
      *DataAddress =*(u8 far*)EEaddress;
         EE_address++;
      DataAddress++;
   }while(--length);
}


//========================================================================
// 函数: u8 EEPROM_write_n(u32 EE_address,u8 *DataAddress,u8 length)
// 描述: 写N个字节函数.
// 参数: EE_address:要写入的EEPROM的首地址.
//       DataAddress: 要写入数据的指针.
//       length:      要写入的长度
// 返回: 0: 写入正确.1: 写入长度为0错误.2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//========================================================================
u8 EEPROM_write_n(u32 EE_address,u8 *DataAddress,u8 length)
{
    u8i;
    u16 j;
    u8*p;

    if(length == 0) return 1;   //长度为0错误

    IAP_ENABLE();                     //设置等待时间,允许IAP操作,送一次就够
    i = length;
    j = EE_address;
    p = DataAddress;
    IAP_WRITE();                            //宏调用, 送字节写命令
    do
    {
      IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节(地址需要改变时才需重新送地址)
      IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
      IAP_DATA= *DataAddress;         //送数据到IAP_DATA,只有数据改变时才需重新送
      EEPROM_Trig();                      //触发EEPROM操作
      EE_address++;                     //下一个地址
      DataAddress++;                      //下一个数据
    }while(--length);                     //直到结束

    EE_address = j;
    length = i;
    DataAddress = p;
    i = 0;
    IAP_READ();                           //读N个字节并比较
    do
    {
      IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节(地址需要改变时才需重新送地址)
      IAP_ADDRL = (u8)EE_address;         //送地址低字节(地址需要改变时才需重新送地址)
      EEPROM_Trig();                      //触发EEPROM操作
      if(*DataAddress != IAP_DATA)      //读出的数据与源数据比较
      {
            i = 2;
            break;
      }
      EE_address++;
      DataAddress++;
    }while(--length);

    DisableEEPROM();
    return i;
}



21cnsound 发表于 2024-2-2 17:18:23

#define      IAP_BASE                              0XFF0000    //基地址
基地址应该是0XFE0000吧?

21cnsound 发表于 2024-2-3 10:52:36


重新看了手册,IAP访问确实不用基地址,虽然基地址应该是0XFE0000。
但手册上说的EEPROM是FLASH的低64KB,地址范围是0x00 0000-0x00 FFFF,代码中IAP读写擦除使用的EEPROM_ADDR=0x01FA00超出了EEPROM范围,也就是说应该就没写入成功,所以读出的还是默认的0xFF。

#define      IAP_BASE                              0XFF0000          //基地址
#define      EEPROM_ADDR                        0x01FA00    //读写的EEPROM地址


   EEPROM_read_n(EEPROM_ADDR, RAM_CONFIG,36);                        //读出配置
   if((RAM_CONFIG ==0XFF) || (RAM_CONFIG==0))
   {
      do{
                EEPROM_SectorErase(EEPROM_ADDR);
                EEPROM_write_n(EEPROM_ADDR, default_config,36);
                EEPROM_read_n(EEPROM_ADDR, RAM_CONFIG,36);      //读出配置
      }while((RAM_CONFIG ==0XFF)||(RAM_CONFIG==0));
    }

cr81 发表于 2024-2-3 13:27:21

上图USB-ISP自动更新设置的128K全部为eeporm,IAP地址应该是从0x00至0x1FFFF,实际地址0xFE0000至0xFFFFFF

cr81 发表于 2024-2-3 13:33:33

本帖最后由 cr81 于 2024-2-3 13:38 编辑

不知道stc-ISP软件里芯片型号选择32G12K128-Beta和32G12K128有什么区别?usb用户自动更新程序里要选择尾缀Beta

21cnsound 发表于 2024-2-4 09:25:31

cr81 发表于 2024-2-3 13:27
上图USB-ISP自动更新设置的128K全部为eeporm,IAP地址应该是从0x00至0x1FFFF,实际地址0xFE0000至0xFFFFFF ...

在低64K的EEPROM中读写正常吗?

神农鼎 发表于 2024-2-4 10:52:11


看 2024/2/2 的数据手册


nian 发表于 2024-2-13 09:56:03

STC8C2K32S4 可以只编写EEPROM文件吗?

lzzasd 发表于 2024-3-6 19:00:28

这个问题我也问过   得到的答案是 :读写eeporm函数是一样的,只是读写地址为--要保存数据的eeporm的物理地址   不是偏移地址就行      实际暂时没这方面应用我也没有测试
页: [1]
查看完整版本: STC32G12K128 在线更新USB-ISP+EEPROM程序