找回密码
 立即注册
查看: 1442|回复: 8

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

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2024-02-01 16:06:56

6

主题

6

回帖

69

积分

注册会员

积分
69
发表于 2024-2-2 15:23:47 | 显示全部楼层 |阅读模式
最近测试的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[36] ={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[36];                          //保存写入读出的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[0] ==0XFF) || (RAM_CONFIG[0]==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[0] ==0XFF)||(RAM_CONFIG[0]==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)
{
    u8  i;
    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;
}



截图202402021523176721.jpg
截图202402021523306462.jpg
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:452
  • 最近打卡:2025-05-01 06:20:50
已绑定手机

13

主题

1257

回帖

2971

积分

金牌会员

积分
2971
发表于 2024-2-2 17:18:23 | 显示全部楼层
#define        IAP_BASE                                0XFF0000    //基地址
基地址应该是0XFE0000吧?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:452
  • 最近打卡:2025-05-01 06:20:50
已绑定手机

13

主题

1257

回帖

2971

积分

金牌会员

积分
2971
发表于 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[0] ==0XFF) || (RAM_CONFIG[0]==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[0] ==0XFF)||(RAM_CONFIG[0]==0));
    }
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2024-02-01 16:06:56

6

主题

6

回帖

69

积分

注册会员

积分
69
发表于 2024-2-3 13:27:21 来自手机 | 显示全部楼层
上图USB-ISP自动更新设置的128K全部为eeporm,IAP地址应该是从0x00至0x1FFFF,实际地址0xFE0000至0xFFFFFF
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2024-02-01 16:06:56

6

主题

6

回帖

69

积分

注册会员

积分
69
发表于 2024-2-3 13:33:33 来自手机 | 显示全部楼层
本帖最后由 cr81 于 2024-2-3 13:38 编辑

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:452
  • 最近打卡:2025-05-01 06:20:50
已绑定手机

13

主题

1257

回帖

2971

积分

金牌会员

积分
2971
发表于 2024-2-4 09:25:31 | 显示全部楼层
cr*** 发表于 2024-2-3 13:27
上图USB-ISP自动更新设置的128K全部为eeporm,IAP地址应该是从0x00至0x1FFFF,实际地址0xFE0000至0xFFFFFF ...

在低64K的EEPROM中读写正常吗?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15613
发表于 2024-2-4 10:52:11 | 显示全部楼层

看 2024/2/2 的数据手册

截图202402041051443502.jpg
回复 支持 反对

使用道具 举报 送花

0

主题

6

回帖

26

积分

新手上路

积分
26
发表于 2024-2-13 09:56:03 | 显示全部楼层
STC8C2K32S4 可以只编写EEPROM文件吗?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:372
  • 最近打卡:2025-05-01 10:53:48

12

主题

125

回帖

1685

积分

金牌会员

积分
1685
发表于 2024-3-6 19:00:28 | 显示全部楼层
这个问题我也问过   得到的答案是 :读写eeporm函数是一样的,只是读写地址为--要保存数据的eeporm的物理地址   不是偏移地址就行      实际暂时没这方面应用我也没有测试
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 04:23 , Processed in 0.131356 second(s), 103 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表