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

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

[复制链接]
  • TA的每日心情
    开心
    2024-2-1 16:06
  • 签到天数: 2 天

    [LV.1]初来乍到

    3

    主题

    6

    回帖

    51

    积分

    注册会员

    积分
    51
    发表于 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
    回复 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 08:23
  • 签到天数: 109 天

    [LV.6]常住居民II

    10

    主题

    581

    回帖

    918

    积分

    高级会员

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

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 08:23
  • 签到天数: 109 天

    [LV.6]常住居民II

    10

    主题

    581

    回帖

    918

    积分

    高级会员

    积分
    918
    发表于 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));
        }
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-2-1 16:06
  • 签到天数: 2 天

    [LV.1]初来乍到

    3

    主题

    6

    回帖

    51

    积分

    注册会员

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

    使用道具 举报

  • TA的每日心情
    开心
    2024-2-1 16:06
  • 签到天数: 2 天

    [LV.1]初来乍到

    3

    主题

    6

    回帖

    51

    积分

    注册会员

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

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

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 08:23
  • 签到天数: 109 天

    [LV.6]常住居民II

    10

    主题

    581

    回帖

    918

    积分

    高级会员

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

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

    使用道具 举报

    该用户从未签到

    551

    主题

    9459

    回帖

    1万

    积分

    管理员

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

    看 2024/2/2 的数据手册

    截图202402041051443502.jpg
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    6

    回帖

    26

    积分

    新手上路

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

    使用道具 举报

  • TA的每日心情
    开心
    昨天 10:04
  • 签到天数: 122 天

    [LV.7]常住居民III

    9

    主题

    92

    回帖

    590

    积分

    高级会员

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

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-17 05:05 , Processed in 0.069607 second(s), 63 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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