oldbeginner 发表于 2013-11-11 18:18:10

开源PLC学习笔记06(再从51开始 IAP)——2013_11_11

在笔记05中遇到环形队列的狙击,还好网上资料丰富,完成了初步理解。

在FX1NProcessing函数中,调用了和IAP相关的函数,因为不影响理解,所以直接跳过了IAP的细节。现在要开始理解这些细节。什么是IAP?In Application Programming 是指在应用编程,单片机程序自己可以往程序存储器里写数据或修改程序!http://zhidao.baidu.com/link?url=Ob1__CoHYLCZZ1wd0PlwuxeaMSiDHMZiGbt3mdBu-BeF885lX4193TJw18RYiDhFZwZmJAAyxn_QVPamxxUZE_

51 IAP资料比较少,因为大多数需要IAP的设计都不会选51。

IAP编程和所选的MCU密切相关,不同MCU的IAP编程代码会不相同,不过原理和步骤大概类似。因为开源PLC选用的是MPC82g516,所以就以它的手册为辅助工具。点击此处下载 ourdev_428676.pdf(文件大小:1.56M) (原文件名:MPC82G516A8位微处理器中文用户手册(第三版).pdf)
看一下结构


看了结构图,继续采用边看代码边理解功能方法。
*******************************
好在IAP.c中函数比较少,先捏软柿子,
// 函数名称: IAPFlashErasureMode
//
// 功能描述:页面擦除模式
//
// 输 入:unsigned int pageaddr
//         
// 输 出:void
void IAPFlashErasureMode(unsigned int pageaddr)
{
    ISPCR=0x83;            // ISPCR.7=1,启用ISP
                        // ISPCR=011, 假设MPC82系列运行在11.0592M
    IFMT=0x03;            // 选择页擦除模式
    IFADRH=pageaddr>>8;    // 这个页面必须在IAP存储区
    IFADRL=pageaddr;
    SCMD=0x46;            // 触发的ISP处理
    SCMD=0xb9;            // MCU将会停止运行.直到处理完成
}
我第一次看到上面的代码,不知所措,因为有许多和IAP相关的寄存器操作
一一看下,

ISPCR=0x83;            // ISPCR.7=1,启用ISP
振荡器频率6~12MHz,



    IFMT=0x03;            // 选择页擦除模式


oldbeginner 发表于 2013-11-11 18:39:29

本帖最后由 oldbeginner 于 2013-11-12 09:51 编辑



      IFADRH=pageaddr>>8;      // 这个页面必须在IAP存储区
      IFADRL=pageaddr;
pageaddr是个形参,unsigned int pageaddr,因为IFADRH和IFADRL是8位,所以用16位的赋值时,pageaddr向右移8位赋值给IFADRH是高8位。


      SCMD=0x46;                        // 触发的ISP处理
      SCMD=0xb9;                        // MCU将会停止运行.直到处理完成
根据手册也很好理解。
和手册上例子一样。


*********************************
// 函数名称: IAPFlashProgrem
//
// 功能描述:单字节写入模式(无"检查是否写入成功")
//
// 输 入:unsigned int codeaddr,unsigned char ucdata
//         
// 输 出:void
void IAPFlashProgrem(unsigned int codeaddr,unsigned char ucdata)
{
    ISPCR=0x83;            // ISPCR.7=1,启用ISP
                        // ISPCR=011, 假设MPC82系列运行在11.0592M
    IFMT=0x02;            // 进入编程模式
    IFADRH=codeaddr>>8;    // 这个字节必须在IAP存储区
    IFADRL=codeaddr;
    IFD=ucdata;            // 填写待编程的数据
    SCMD=0x46;            // 触发的ISP处理
    SCMD=0xb9;            // MCU将会停止运行.直到处理完成
}
是手册上的例子。


******************************************
//=======================================
// 函数名称: IAPFlashReadMode
//
// 功能描述:单字节读取模式
//
// 输 入:unsigned int codeaddr
//         
// 输 出:unsigned char
unsigned char IAPFlashReadMode(unsigned int codeaddr)    // 读模式
{
    ISPCR=0x83;            // ISPCR.7=1,启用ISP
                        // ISPCR=011, 假设MPC82系列运行在11.0592M
    IFMT=0x01;            // 进入读模式
    IFADRH=codeaddr>>8;    // 这个字节必须在IAP存储区
    IFADRL=codeaddr;
    SCMD=0x46;            // 触发的ISP处理
    SCMD=0xb9;            // MCU将会停止运行.直到处理完成    // 触发IAP
    return IFD;            // 读出的数据
}
也和手册一致。



// 函数名称: IAPFlashProgremMode
//
// 功能描述:单字节写入模式(含有"检查是否写入成功")
//
// 输 入:unsigned int codeaddr,unsigned char ucdata
//         
// 输 出:void
IAPFlashProgremMode是个比较繁琐的函数,要逐步分析,

1、首先,void IAPFlashProgremMode(unsigned int codeaddr,unsigned char ucdata)        // 编程模式
   codeaddr是地址,ucdata是待编程的数据。

2、        unsigned char checkdata=0;
               checkdata=IAPFlashReadMode(codeaddr);
      把所写的数据赋值给checkdata,因为ucdata是待编程数据,所以两者应该相等。(具体原理还不清楚)

3、while(checkdata!=ucdata)
   {
      纠正措施;
      }
   如果不相等,如何解决。暂时跳过。

**********************************
要返回FX1NProcessing函数,去了解当时略过的几个IAP函数。

oldbeginner 发表于 2013-11-12 09:42:52

本帖最后由 oldbeginner 于 2013-11-12 11:39 编辑

oldbeginner 发表于 2013-11-11 18:39 static/image/common/back.gif
IFADRH=pageaddr>>8;      // 这个页面必须在IAP存储区
      IFADRL=pageaddr;
pageaddr是 ...
在IAP中存储非易失性数据,
//    IAP 空间分配如下:(31K)                                       ----ASCII转HEX后存储.
//      1.IAP起始页 0x8000    ~    0xbfff                     存储PLC程序 -- 对应PLC 的0x8000~0xbfff 地址共8000步程序空间
//      2.IAP最后一页0 地址                                       存储    PLC类型标识核实标志    共 1 个字节
//      3.IAP最后一页1    ~    PLCTypeArrayLenMAX      存储    PLC类型标识            共 PLCTypeArrayLen 个字节 PLCTypeArrayLen
//      4.IAP倒数第二页                                             缓存空间    不许被其他数据占用!
//      5.其他                                                             保留



为什么这样分布还不是很清楚,先看代码,看是否能从中理解空间分布。

// 函数名称: WriteFlash
//FX1N.c
// 功能描述:HEX 转 ASCII
//
// 输 入:unsigned int WriteAddr,unsigned char *Buf,unsigned int WriteLen
//         
// 输 出:void
void WriteFlash(unsigned int WriteAddr,unsigned char *Buf,unsigned int WriteLen)
{
    unsigned int i;
    unsigned char wrdata=0;
    for(i=0;i<WriteLen*2;i+=2)    //    由原来的每页写512字节,改为每页写256个字节.存储地址不连续; 由原来存储ASCII码格式,改为存储HEX格式.
    {
      wrdata=asctohex((unsigned char *)(Buf+i));
      IAPFlashProgremMode(WriteAddr++,wrdata);
    }
}

这里调用了(含有"检查是否写入成功")单字节写入模式,只看代码也比较难理解,画个图看看,


注释中:由原来的每页写512字节,改为每页写256个字节。感觉有问题,因为WriteAddr++,所以还是512个字节,而且还是连续的,反而被存储的内容不连续了。
如果改成i++,Writeaddr+=2,则好像符合1、由原来的每页写512字节,改为每页写256个字节。2、存储地址不连续。
感觉这里源程序的注释和代码不一致。

至于为何要改成256个字节,应该和页面缓冲区有关(由RAM决定),可以猜测MPC82G516的RAM是256字节。

oldbeginner 发表于 2013-11-12 12:59:37

oldbeginner 发表于 2013-11-12 09:42 static/image/common/back.gif
在IAP中存储非易失性数据,
//    IAP 空间分配如下:(31K)                                       ---- ...

// 函数名称: ErasurePLC
//
// 功能描述:PLC擦除IAP空间
//
// 输 入:unsigned char allorcode
//         
// 输 出:void
这个函数的代码有点多,逐次了解,
********************************************

void ErasurePLC(unsigned char allorcode)
    unsigned int i;
    unsigned char ucdata=0;
*****************************************************************

1、全部擦除
    if(allorcode==ErasureALL)
    {
      for(i=0;i<MCUIAPFLASHSIZE;i+=512)            //    全部擦除    初始PLC程序为空
      {
            IAPFlashErasureMode(PLCIAPCODEAddr+i);
      }
    }

找到FX1N.c中的定义
#define    ErasureALL      0
#define ErasureCODE      1

#define MCUFLASHSIZE      64*1024                              //    64K
#define MCUIAPFLASHSIZE      31*1024                              //    31K
#define MCUISPFLASHSIZE      1*1024                              //    1K

而注释是
//    默认当前MPC82G516A的设置为
//    1KISP Code
//    31K    IAP Code
//    32K Flash Code
注释应该改为64K Flash(其中包括1K ISP和 31K IAP)

首先,查看#define MCUIAPFLASHSIZE      31*1024               //    31K
可知 IAP code容量为31K。

然后,#define PLCIAPCODEAddr      (MCUFLASHSIZE-MCUIAPFLASHSIZE-MCUISPFLASHSIZE)
根据字面意思就是,PLC IAP地址为,64*1024 - 31*1024 - 1*1024 = 32 * 1024 =64 * 512
地址的格式没见到过,是不是相对地址,先继续。

调用            IAPFlashErasureMode(PLCIAPCODEAddr+i);来执行擦除。
又由于一个循环for(i=0;i<62 * 512 ;i+=512)
                                  IAPFlashErasureMode(64 * 512 + i);
从第64页开始,一共擦除62页。最后2页没有擦除。
*********************************************************

2、else if(allorcode==ErasureCODE),只擦除程序

3、擦除IAP缓存备份空间
IAPFlashErasureMode(PLCTempAddr);
查看 #define PLCTempAddr      (MCUFLASHSIZE-MCUISPFLASHSIZE-1024)    //    IAP倒数第二页地址
PLCTempAddr= 64 * 1024 - 1 * 1024 - 1024 = 62 * 1024 = 124 * 512,IAP倒数第二页是第124页。

4、备份PLC 0x8000~0x805c 地址的数据,0x8000 =40 * 512第40页上的数据
         for(i=0;i<0x5c;i++)                            //    备份PLC 0x8000~0x805c 地址的数据
      {
            ucdata=IAPFlashReadMode(i+0x8000);
            IAPFlashProgremMode(i+PLCTempAddr,ucdata);
      }
0x5c小于512字节,所以IAP倒数第二页可以放下。


5、擦除PLC程序空间
      for(i=PLCIAPCODEAddr;i<PLCTempAddr;i+=512)    //    擦除PLC程序空间
      {
            IAPFlashErasureMode(i);
      }

6、还原PLC 0x8000~0x805c 地址的数据
      for(i=0;i<0x5c;i++)                            //    还原PLC 0x8000~0x805c 地址的数据
      {
            ucdata=IAPFlashReadMode(i+PLCTempAddr);
            IAPFlashProgremMode(i+0x8000,ucdata);
      }
**************************************
上述IAP更新步骤遵循了手册上说明。

oldbeginner 发表于 2013-11-12 14:45:48

oldbeginner 发表于 2013-11-12 12:59 static/image/common/back.gif
// 函数名称: ErasurePLC
//
// 功能描述:PLC擦除IAP空间

Read code中涉及IAP的代码

Readdat=IAPFlashReadMode(ReadAddr+i-1);    //    读FlashData
其中,ReadAddr是通过接收到的报文获得的,详细理解在笔记04中。这里复习一下,

*******************************************
                  //    计算得到读取地址:
                  for(i=4;i<8;i++)
                        Buffer=ascto0F(UartReceiveBuffer);

                  ReadAddr =Buffer<<12;
                  ReadAddr+=Buffer<<8;
                  ReadAddr+=Buffer<<4;
                  ReadAddr+=Buffer;
*********************************************
把i=1带入,看看结果
Readdat=IAPFlashReadMode(ReadAddr+i-1);

即Readdat=IAPFlashReadMode(ReadAddr);
然后调用IAP函数
    IFADRH=ReadAddr>>8;    // 这个字节必须在IAP存储区
    IFADRL=ReadAddr;
然后
    Readdat=IFD;

IFD保存着对应地址的数值,赋值给Readdat。
************************************************
1、首先,WriteAddr是通过报文得到的
                  //    计算得到写入地址:
                  for(i=4;i<8;i++)Buffer=ascto0F(eBuffer);
                  WriteAddr =Buffer<<12;
                  WriteAddr+=Buffer<<8;
                  WriteAddr+=Buffer<<4;
                  WriteAddr+=Buffer;

*************************************************
2、Write code中涉及IAP的代码
                  if(WriteAddr==0x8000)
                                     ErasurePLC(ErasureCODE);    //    擦除PLC程序区
                   刚理解过如何擦除程序区
***************************************************

3、WriteFlash(WriteAddr,(unsigned char *)Buffer+10),(unsigned char)WriteLen);    //    写 flash
                  
      Buffer+10,指向报文的指令,是是由上位机发送的。

存储格式及报文发送格式说明:http://www.amobbs.com/thread-3303497-1-1.html

存储格式为字型,低在先,高在后(如指令END,指令码为00 0F,存储为0F 00。指令LDX002,指令码为24 02,存储为02 24)。
在报文发送时,以字为单位传送,低字节在先。在字节传送过程中,高位在先,低位在后,转换成 ASCII 码 后传送(即以存储格式传送)。
指令LDX002,指令码为24 02,存储格式为02 24,转换成 ASCII 码传送为30 32 32 34。

以 LD X002为例,则Buffer='0' ,Buffer='2',Buffer='2',Buffer='4',并且WriteLen=4。




oldbeginner 发表于 2013-11-12 16:28:59

本帖最后由 oldbeginner 于 2013-11-12 16:54 编辑

oldbeginner 发表于 2013-11-12 14:45 static/image/common/back.gif
Read code中涉及IAP的代码

Readdat=IAPFlashReadMode(ReadAddr+i-1);    //    读FlashData




从上图中可以看出,FX1NProcessing是把三菱命令映射到相应Flash的核心。
从中也可看出,FX1NProcessing有两个关键功能,
1、接收电脑来的报文;
2、将报文写入Flash。

虽然main函数中也涉及到IAP功能,放在后面再理解。因为IAP的步骤是规定的,所以发挥空间不大。第1遍理解暂时到这里,因为芯片原因,后面还要移植,必定需要把IAP理解一清二楚。

下一步分析指令LD OUT SET RST是如何传递和实现功能的。
http://www.amobbs.com/thread-5558798-1-1.html

oldbeginner 发表于 2013-11-15 19:35:08

oldbeginner 发表于 2013-11-12 16:28 static/image/common/back.gif
从上图中可以看出,FX1NProcessing是把三菱命令映射到相应Flash的核心。
从中也可看出,FX1NProcessing ...

IAP主要补充相关硬件知识,不同芯片操作过程不太一致。

*******************************************************
先搜一下简单区别,http://zhidao.baidu.com/question/151117377.html?qbl=relate_question_1
ISP(In-system programmable)是在系统可编程:
指的是不需要把单片机从目标系统板上取下来就可以直接从PC往单片机里面烧录程序。

IAP(In-Application programmable)是在应用可编程:
指的是可以通过单片机自身的程序修改单片机该程序区的内容;

EEPROM功能是:
在程序区1中的程序可以修改程序区2中的内容;通常程序区2中的内容不可以执行,只能当数据使用,功能相当于EEPROM;

区别:
ISP:从PC机修改单片机程序区的内容(即烧录)
IAP:单片机自己修改自己程序区的内容
EEPROM:单片机程序区1中的程序可以修改程序区2中的内容
****************************************************************
http://www.ndiy.cn/archiver/tid-5836.html
ISP是指可以在板级上进行编程,也就是不用拆芯片下来,写的是整个程序,一般是通过ISP接口线来写。
IAP虽然同样也是在板级上进行编程,但是是自已对自已进行编程,在应用中进行编程,也即可以只是更改某一部分而不影响系统的其它部分,另外接口程序是自已写的,这样可以进行远程升级而不影响应用。
打个比喻吧:
1、ISP是把房子拆了再重造一间,那么在造好之前当然是不能住人的啦!
2、IAP是在造好的房子里边进行一些装修,当然人可以继续住啦!

*******************************************************
    通常在用户需要实现IAP功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信管道(如USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在User Flash中,当芯片上电后,首先是第一个项目代码开始运行,它作如下操作:
1)检查是否需要对第二部分代码进行更新
2)如果不需要更新则转到4)
3)执行更新操作
4)跳转到第二部分代码执行

    对于STM32来说,因为它的中断向量表位于程序存储器的最低地址区,为了使第一部分代码能够正确地响应中断,通常会安排第一部分代码处于Flash的开始区域,而第二部分代码紧随其后。
   在第二部分代码开始执行时,首先需要把CPU的中断向量表映像到自己的向量表,然后再执行其他的操作。
**********************************************************



oldbeginner 发表于 2013-11-15 20:11:40

本帖最后由 oldbeginner 于 2013-11-15 20:16 编辑

oldbeginner 发表于 2013-11-15 19:35 static/image/common/back.gif
IAP主要补充相关硬件知识,不同芯片操作过程不太一致。

********************************************* ...
考虑到资料的丰富程度和通用性,STM32是用来理解IAP比较好的入门芯片,而不是51。
第四十八章 串口IAP实验
http://www.openedv.com/posts/list/11494.htm

STM32 IAP   设计实例 (一)
http://blog.csdn.net/qq236106303/article/details/9977191



ruzi 发表于 2017-4-20 13:30:47

谢谢楼主!学习了!

xukaiming 发表于 2017-4-20 20:23:43

我还以为xuyiyi回来了呢
页: [1]
查看完整版本: 开源PLC学习笔记06(再从51开始 IAP)——2013_11_11