freetech

HCS08单片机改写FLASH参数之——下位机程序

0
阅读(3435)

单片机端实现动态改写FLASH参数或更新程序要具备以下2个条件:

1、单片机支持在应用编程IAP。

2、有一种通信接口可以传递要改写的内容。

HCS08系列单片机是支持在应用编程IAP的,并且官方提供了操作代码,是汇编写的,提供了API接口的3个函数:

void FlashErase(const unsigned char * flash_destination);
void FlashProg(const unsigned char * flash_destination, unsigned char data);
unsigned char FlashProgBurst(const unsigned char * flash_destination, unsigned char * ram_source, unsigned char length);

我们通过调用上述函数即可实现FLASH擦除和写入。更多信息参见AN3942。

本例是通过串口实现内容传递,飞思卡尔官方提供了Freemaster来实现上、下位机之间传递变量和内存数据。还留了一条自定义命令方便用户扩展。我们就是用自定义命令实现写FLASH命令。

该示例是一个波形发生器,功能是:

1、2路数字波形输出

2、第一路波形的高电平时间和低电平时间可调

3、第二路波形的上升沿相对第一路的下降沿有一个延时,该延时可调。

(VLC]SYY7%4K5OTG_]_3]`P[4]

上位机的界面是这样的:

image

为了实现上述功能,需在我们的程序之外加入下列文件:

image

main.c里有个myhandler函数是处理我们自定义协议的,加入以下代码:

FMSTR_APPCMD_RESULT myhandler(FMSTR_APPCMD_CODE nAppcmd, FMSTR_APPCMD_PDATA pData, FMSTR_SIZE nDataLen)
{
    byte *datapointer;
    volatile word target_address;
    if(nAppcmd == 0x0a){
      target_address = ((word)(pData[2])<<8) | pData[3];
      switch(pData[0]){
        case 1:{   // erase command    
          FlashErase((unsigned char *)(target_address));
          break;     
        }
        case 2:{   // program command
          datapointer = pData + 4;
          FlashProgBurst((unsigned char *)(target_address), datapointer, pData[1]);
          break;
        }
        default:{
          break;
        }
      }
    }// the return value is used as the application command result code
    return 0x10;   
}

在main,c顶部定义3个全局变量,对应界面中的3个值:

 

#pragma CONST_SEG MY_DATA

volatile const unsigned long int hi_time = 100;//计到该值时变低
volatile const unsigned long int duty_time = 200;//计到该值时变高,并重新计
volatile const unsigned long int delay_time = 50;//计到该什是变高hi_time+delay_time时变低
#pragma CONST_SEG DEFAULT

红色代码是存储器定位用的,以便把变量放在我们希望的位置。

修改PRM文件,把需擦写的FLASH单独划分出来,下面的红色代码是新加的,绿色代码是有所改动的:

/* This is a linker parameter file for the mc9s08ac16 */

NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */

SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
    Z_RAM                    =  READ_WRITE   0x0070 TO 0x00FF;
    RAM                      =  READ_WRITE   0x0100 TO 0x046F;
    ROM                      =  READ_ONLY    0xC000 TO 0xDFFF;
    MY_ROM                   =  READ_ONLY    0xE000 TO 0xFFAF;
    ROM1                     =  READ_ONLY    0xFFC0 TO 0xFFC5;
/* INTVECTS                 =  READ_ONLY    0xFFC6 TO 0xFFFF; Reserved for Interrupt Vectors */
END

PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
    DEFAULT_RAM,                        /* non-zero page variables */
                                        INTO  RAM;

    _PRESTART,                          /* startup code */
    STARTUP,                            /* startup data structures */
    ROM_VAR,                            /* constant variables */
    STRINGS,                            /* string literals */
    VIRTUAL_TABLE_SEGMENT,              /* C++ virtual table segment */
    DEFAULT_ROM,
    COPY                                /* copy down information: how to initialize variables */
                                        INTO  ROM; /* ,ROM1: To use "ROM1" as well, pass the option -OnB=b to the compiler */
    MY_DATA                             INTO  MY_ROM;
    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END

STACKSIZE 0x80

VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */

上面介绍修改FLASH内容的方法。波形的形成是通过定时器实现的,下面是初始化的中断函数:

//=======================================================================================================
//函数名:Init_tpm2_counter
//作用:初始化TPM2,内部时钟工作于自时钟模式,总线频率4M;自由计数;溢出时间间隔=65536/(4000/64)近似1048ms
//========================================================================================================
void Init_tpm2_counter(void)
{
    TPM2SC=0x48;//TPM2时钟源为总线时钟;分频系数为8;溢出中断允许
    TPM2MOD = 2000;
    TPM2CNTH=0;//任意时刻对TPM2CNTH或TPM2CNTL的写操作将计数寄存器的计数值复位(清零)
}
//==================计数器2溢出中断服务程序==========================
interrupt VectorNumber_Vtpm2ovf void TPM2_OVF_ISR(void)
{
  static unsigned long int cnt = 0;
    if((TPM2SC & 0x80)==0x80)
    {
        TPM2SC_TOF=0;
    }
    cnt++;
    if(cnt >= duty_time)
    {
      cnt = 0;
      OUT_1 = 1;
    }
    if(cnt == hi_time)
    {
      OUT_1 = 0;
    }
    if(cnt == delay_time)
    {
      OUT_2 = 1;
    }
    if(cnt == hi_time + delay_time)
    {
      OUT_2 = 0;
    }
}