msp430 程序升级

发布者:落寞梦惊最新更新时间:2018-05-03 来源: eefocus关键字:msp430  程序升级 手机看文章 扫描二维码
随时随地手机看文章

第一篇

 
    在项目开发中,至关重要的是保证产品运行的可靠,如果遇到异常,能否恢复很重要,而不是像砖头一样,程序死在某个地方。固件升级的原理就是重写向量表,在引导区更新app区的flash,然后跳转app区。实际开发中就会有以下问题:

 
1.如果MCU复位,比如POR,PDR,WDT等复位,都会使sp指针指向复位地址。那么MCU从引导区执行,如果APP区程序有效,应该如何控制程序跳转到APP区。

 
2.如果APP区或者引导区接受新固件,在更新APP区flash时,如果此时MCU发生掉电,当再次上电后,MCU该如何执行。或许有人说,我们有外部的EEP或者外部的FLASH,会使用状态和标志去记录当时MCU操作flash的状态,当然这些状态和标志有校验,并且存储到外部EEP或FLASH。上电后我们会判断校验,然后读出来作为依据。在理想情况下,这样做非常完美,但是MCU在运行中,什么情况都可能发生。比如电源掉的很快,那么算出来的校验有什么意义,还怎么保证写到EEP或FLASH的可靠性,特别是有外部FLASH,几ma的

 
电流MCU瞬时根本扛不住。即使是EEP,就算将引导区配置成最低功耗,这种意外也是不可避免的,此时的标志和状态只是徒劳。那么会造成一种MCU假死状态,滞留在引导区,然后死循环。如果要解除,只能通过仿真器进入仿真模式,更改变量值去解除。而这样的后果就违背了升级的初衷和产品的可靠。

 
3.对于新固件的更新,是接收全部数据再更新还是接收部分数据更新FLASH,这个具体依据自己使用的硬件资源,不过重点还是在于第二点的处理。

 
4.如果升级过程中,传输数据或读取数据突然中断,或者新的固件验证失败,那么这些操作该如何恢复,而不至于MCU假死。

 

自己实践中的处理,总结了如下几条:

1.首先我们要明白MCU复位后是要从复位执行,并且MCU中断后,会跳转到实际中断向量地址,也就是向量区重写。在应用区如果有中断发生,MCU会跳转到中断原始地址,通过跳转指令执行位于应用区实际的中断处理函数。例如我使用的是MSP430的FR6972,它的FRAM分配是0x4400-0x13FFF,它的向量区地址在0xFF80-0xFFFF。假如分成两个区,引导区0xF000-0xFFFF,APP区0x7C00-0xEFFF。现在程序执行在0x7C00-0xEFFF的应用区,此时MCU响应了一个中断,假设这个中断函数的入口地址是0xEFF2,按照常理,MCU也应该执行这个地址的内容,实际上,MCU会跳转到这个中断的原始中断向量地址0xFFF2,因为0xEF80-0xEFFF只是我们虚拟的中断向量地址,0xFF80-0xFFFF才是真正的中断向量区。这也是为什么要在引导区重写中断向量,如

#pragma vector=WDT_VECTOR

__interrupt void WDT_ISR(void)                         //0xFFF2

{

 asm(" br &0xEFF2;");

}

执行中断,栈会保存sp等寄存器的内容,执行完后会恢复,继续执行APP区程序。

2.不管是引导区和APP区,MCU的寄存器地址都是固定的,ram的地址也是一样的,但是FLASH是各自独立的,不能重叠。特别注意的是,在引导区和APP区处理全局变量或静态变量时,一定要初始化,或者依据校验从存储器恢复,因为跳转(非中断跳转)会导致这些变量是乱的。

3.要明白编译出的文件格式,知道数据要写到MCU中FLASH的地址。例如MSP430编译出的文件:

@F000

01 02 03 04 05 06 07

@F008

31 40 00 24 8C 00 08 1C 3E 40 17 02 3F 4000 00

B0 13 B4 FE 8C 00 00 1C 8D 00 00 F0 3E 4007 00

……

@FFC6

38 F0 3E F0 44 F0 4A F0 50 F0 56 F0 5C F062 F0

68 F0 6E F0 74 F0 7A F0 80 F0 86 F0 8C F092 F0

98 F0 9E F0 A4 F0 AA F0 B0 F0 

@FFF2

B6 F0 BC F0 C2 F0 C8 F0 CE F0 D4 F0 08 F0 

q

@后的内容是代码段的地址,是说明段数据要写入的地址,这些地址不需要写入到FLASH中。地址的分配与link文件分配有关。

-Z(CONST)DATA16_C,DATA16_ID,TLS16_ID,DIFUNCT,CHECKSUM=F000-FF7F

-Z(CONST)DATA20_C,DATA20_ID,CODE_ID=F000-FF7F

-Z(CODE)CSTART,ISR_CODE,CODE16=F000-FF7F

-P(CODE)CODE=F000-FF7F

-Z(CONST)SIGNATURE=FF80-FF8F

-Z(CONST)JTAGSIGNATURE=FF80-FF83

-Z(CONST)BSLSIGNATURE=FF84-FF87

-Z(CONST)IPESIGNATURE=FF88-FF8F

-Z(CODE)INTVEC=FF90-FFFF

-Z(CODE)RESET=FFFE-FFFF

像-z,-p这些都是编译指令,(data)(const)(code)都是说明修饰,DATA16_C,DATA16_ID等都是数据段类型描述。

q就是结束标志。

例如stm8l编译出的我文件格式:

:108000008200FBA0820166548200FE8D82016655CB    //起始地址是0x8000

:108010008200FEA78200FEA8820126B18200F1C77D     //起始地址是0x8010

:108020008200FEA98200FEAA820113AA8200F38ABE    //起始地址是0x8020

:108030008200F5C68200F6EB8200FEAB8200EFD82C    //起始地址是0x8030

:108040008200F5F982014AE38200FEAC8200FEADB7    //起始地址是0x8040

:108050008200FEAE820136958200FEAF8201164399    //起始地址是0x8050

:108060008200FEB082012E8B8200FEB18200F24BB4    //起始地址是0x8060

:108070008200FEB28200FEB38200FEB48200FEB532    //起始地址是0x8070

……

:108610008D011DBB3D002608BE042602BE0626E9CC

:0F862000BE042602BE06260435020000B60087FF

:10862F00AE013CBF00905FAE01648D00FC0E725F27

:10863F00016435820165725F016635020167350895

……

我们可以很容易百度hex文件格式说明,Hex文件是可以烧录到MCU中,被MCU执行的一种文件格式。整个文件以行为单位,每行以冒号开头,内容全部为16进制码。例如”:1000080080318B1E0828092820280B1D0C280D2854”。

第一个字节0x10表示本行数据的长度,“80318B1E0828092820280B1D0C280D28”。

第二,三个字节0x00,0x08表示本行数据的起始地址。

第四个字节0x00表示数据类型,数据类型说明:

'00' Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录

'01' End of File Record: 用来标识文件结束,放在文件的最后,标识HEX文件的结尾

'02' Extended Segment Address Record: 用来标识扩展段地址的记录

'03' Start Segment Address Record:开始段地址记录

'04' Extended Linear Address Record: 用来标识扩展线性地址的记录

'05' Start Linear Address Record:开始线性地址记录

理解了这些文件的内容,我们就知道了向量区需要些的内容,这点很重要。同时我们可以根据自己的通信协议进行扩展,重新转换这些内容,传输到MCU中进行固件升级。

4.原始的中断向量最好与引导区在一个区域,在引导区执行,最好关闭中断响应,通过查询的标志位的方式来处理。引导区的作用就是实现APP区的FLASH更新,中断的跳转。如果将原始向量区分配到APP区,会导致需要很大的外部存储空间接受新的固件,而且程序的设计也会头重脚轻,不建议使用。

5.如何保证固件更新的成功率,和解决擦写FLASH出现的异常,最好的操作就是先擦写APP区的向量区内容,更新完APP区FLASH,最后写复位向量内容。这样可以省去很多的判断流程,即使中途更新失败,或者掉电,MCU上电后也可以继续更新固件,并且出错率很低。像MSP430,烧写FLASH或者仿真下载,如果烧写时选择默认Memmory option,那么FLASH默认的值是0xFF。当知道分配的APP区的起始地址后,就判断复位向量值是否为0xFF,如果是则说明APP区没有内容,则不跳转,接受或更新固件。如果不是,一般情况下APP区是有内容的,则执行跳转。

6.在实现固件升级时,最好测试指针类型长度,因为选择的数据模式不同,访问不到0x10000以上的地址。比如MSP430的,如果选择mid,所有的指针类型长度占2byte,这样能访问的最大地址是0xFFFF,只有选择large,才可以访问0x10000以上的地址,但是相应的代码面会增加,因为函数列表的内容就扩大了一倍多,还有其他指针操作。Stm8l区分的就是near和far,就052r8分好几种大小的flash,可以在stm8l15x.h中更改宏。还有就是对内存的操作,需要注意对齐补齐,特别是32位机,像cortex-0内核。比如我经常使用

#define M8(adr)          (*((FAR uint8_t* )(adr)))

#define M16(adr)         (*((FAR uint16_t* )(adr)))

#define M32(adr)         (*((FAR uint32_t* )(adr)))

FAR只是一种修饰。可以省略,也可以使用volitale。

7.合并引导区和APP区文件,然后通过烧程器烧录完整文件。关键就是只保留一个结束标志。
第二篇

以下我会通过实例代码来说明,如果有不足,请大家提出建议。

这是stm8L引导区的main()函数。

void main()

{

//禁止中断使能

 disableInterrupts();

 Clk_Config();

 IO_Config();

 LCD_Config();

 //解锁FLASH操作

 FLASH->PUKR = FLASH_RASS_KEY1;

 FLASH->PUKR = FLASH_RASS_KEY2;

 //从存储区读出数据

 FLASH_ByteRead(start_EEPROM1ADDR,(uint8_t*)&ImagePara,sizeof(Image));

 //使用CRC校验,返回0没错误

 if(TestAdjust((uint8_t *)&ImagePara,sizeof(Image))==0)

jumpflasg=1;

 //0x01初始化状态,判断口状态,因为我使用的CPU卡

 if((jumpflasg==1)&&(ImagePara.CurState==0x01)&&((GPIOC->IDR&0x02)==0))

 {

   //擦除APP区向量

FLASHEraseBlock(APPST_BLOCK_NUM,FLASH_MemType_Program);

//擦除整个APP区

   FlashErase(APPST_BLOCK_NUM,0xEF80);

 }

 //如果向量地址有效,跳转引导区

 if(ResetVectorValid()==1)

 {

   asm("LDW X,   SP");

   asm("LD  A,   $FF");

   asm("LD  XL,  A");

   asm("LDW SP,  X");

   asm("JPF      $9000");

 }

 //显示boot

 {

   LCD->RAM[3]=0x40;

   LCD->RAM[4]=0x10;

   LCD->RAM[7]=0xFC;

   LCD->RAM[8]=0x01;

   LCD->RAM[10]=0xC0;

   LCD->RAM[11]=0x3F;

 }

 while(1)

 {

   //禁止中断

disableInterrupts();

//实时判校验

   if(TestAdjust((uint8_t *)&ImagePara,sizeof(Image)))

     FLASH_ByteRead(start_EEPROM1ADDR,(uint8_t*)&ImagePara,sizeof(Image));

   //如果有卡标志

   if((GPIOC->IDR&0x02)==0)  

{

  //如果读卡没错误

     if(carderr!=1)

     {

       Delayms(10);

       //读卡第一个块内容,包含我的块个数和校验和

       carderr=Read_ImageInfo();

       if(carderr!=1)

       {  

             //更新flash,按块操作      

         while((++ImagePara.Block_dyn)<=ImagePara.Block_static)

         {

            //读CPU卡内容,更新flash

           if(Read_Image(ImagePara.Block_dyn)==FALSE)

            {

              carderr=1;

              break;

            }

         }

         if(carderr!=1)

         {

            //最后写入向量区

            if(Get_Vector()==FALSE)

            {

              carderr=1;

            }

         }

         if(carderr!=1)

         {

            //验证块的状态

            if(Verify_Image()==FALSE)

            {

              //校验失败

              ImagePara.CurState=0x02;

            }

            else

            {

              //校验成功

              ImagePara.CurState=0x03;

            }

                     //算校验,更新数据

            adjust_write((uint8_t*)&ImagePara,start_EEPROM1ADDR,sizeof(Image));

         }

       }

     }

   }

   else

{

     if(ImagePara.CurState==0x02)

     {

       memset((uint8_t *)&ImagePara,0,sizeof(Image));

       ImagePara.CurState=0x01;

       adjust_write((uint8_t *)&ImagePara,start_EEPROM1ADDR,sizeof(Image));

     }

     carderr=0;

   }

   if(carderr==1)

     LCD->RAM[12]=0x40;

   else

     LCD->RAM[12]=0x00;

   if(ImagePara.CurState==0x03)

   {

      asm("LDW X,   SP");

      asm("LD  A,   $FF");

      asm("LD  XL,  A");

      asm("LDW SP,  X");

      asm("JPF      $9000");

   }

 }

}

这是MSP430引导区main()函数

void main()

{

 WDTCTL = WDTPW | WDTHOLD;

 Init_cmu();

 Init_uart_Mbus();

 Init_uart_HW();

 Test_Image();

 if(TestAdjust((uint8*)&ImagPara,sizeof(Image))==0)

   jumpflag=1;

 if((jumpflag==1)&&(ImagPara.curstate==0x04))

   Flash_Erase(APP_VECSTARTADDR,APP_VECLEN);

 if(ResetVectorValid()==1)

   asm("mov &0xEFFE,PC;");

 while(1)

  {

   __disable_interrupt();

   Test_Image();

   CommPara_Mbus.chbuff=&Buff_MBUS[0];

   CommPara_HW.chbuff=&Buff_HW[0];

   if(UCA1IFG & UCRXIFG)

    {

     UCA1IFG &= ~UCRXIFG;

     StreamHandler_putChar((CommData*)&CommPara_Mbus,UCA1RXBUF);

    }

   if(UCA0IFG & UCRXIFG)

    {

     UCA0IFG &= ~UCRXIFG;

     StreamHandler_putChar((CommData*)&CommPara_HW,UCA0RXBUF);

    }

   ApplayerHandler();

    if(ImagPara.curstate==0x04)

    {

     Flash_Erase(APP_VECSTARTADDR,APP_VECLEN);

     Flash_Erase(APP_CODESTARTADDR,APPSIZE);

     EEP_TO_FRAM();

     if(Flash_check()==0)

     {

       ImagPara.curstate=0x05;

     }

     else

     {

       ImagPara.curstate=0x06;

     }

     adjust_write((uint8*)&ImagPara,IMAGE_ADDR,sizeof(Image));

    }

   if(ImagPara.curstate==0x06)

    {

     asm("mov &0xEFFE,PC;");

    }

  }

}

关键字:msp430  程序升级 引用地址:msp430 程序升级

上一篇:SPI时序解析
下一篇:msp430程序升级方法

推荐阅读最新更新时间:2024-03-16 16:01

msp430软件安装破解过程
ew430-ev-320a 安装破解过程 第一步: 把安装文件放到一个目录下(不要用中文、目录尽量短) 第二步: 开始 运行 cmd 第三步: 进入安装文件目录下 第四步: 查找机器代码: iarid.exe 第五步: 生成密钥 iarkg.exe machine code /0x26386 code.txt 第六步: 进入到 code 记事本中 查找 关于 msp430的 key Ctrl + F -- 430 第七步: 开始安装 操作如下: Microsoft Windows XP (C) 版权所有 1985-2001 Microsoft Corp. C:
[单片机]
基于MSP430和Zigbee的无线抄表终端电路设计
电路原理:核心处理器采用TI公司的MSP430F149单片机。为实现低功耗的要求,电路中采用高速和低速两个晶振,由高速晶振产生频率较高的MCL-K,以满足 CPU高速数据运算的要求,在不需要CPU工作时关闭高速晶振,由低速晶振产生频率较低的ACLK,运行实时时钟。日历时钟芯片采用PHILIPS公司的 PCF8563。此芯片支持IIC总线接口,采用低功耗CMOS技术,具有较宽的工作电压范围1.0V~5.5V,在3.0V供电条件下,工作电流和休眠电流的典型值都为0.25μA,能记录世纪、年、月、日、周、时、分、秒,具有定时、报警和频率输出功能。存储器采用复旦微电子的FM24C04。此芯片是两线制串行EEPROM,兼容IIC总线接口,采
[单片机]
基于<font color='red'>MSP430</font>和Zigbee的无线抄表终端电路设计
初识畅学系列MSP430F149单片机开发板
1、畅学MSP430单片机核心板 畅学系列六合一MSP430单片机核心板板载贴片封装的MSP430F149单片机芯片,芯片IO全部引出2组,既可以直接插到畅学系列多功能开发学习板/实验箱底板直接扩展为多功能开发学习板,也可以单独作为一个MSP430最小系统核心板使用。 畅学系列六合一MSP430单片机核心板-标配一个MSP 430149单片机,核心板集成BSL下载器,一条USB线即可实现供电和BSL方式程序下载,还可以通过USB线实现串口通讯。。 板载BSL下载模块,可以方便的直接通过USB线在供电同时还可以下载程序。 板载BSL下载模块,还可以作为串口通讯模块使用,可以通过USB供电同时和PC机进行串口通
[单片机]
初识畅学系列<font color='red'>MSP430</font>F149单片机开发板
MSP430F449的时钟问题
当发生上电复位(POR)或者上电清除(PUC)信号时,系统各寄存器会发生复位。 注意:系统时钟相关的几个寄存器在复位后,其初始值不是0. SCFQCTL 寄存器 bit 7 bit6~0 SCFQ_M N 复位后,初始值为:0x001F bit7:0:使能 DCO(频率调整器)1:禁止 DCO N是倍频,系数,决定DCO的最终频率输出。F=D(N+1)*fcrystal.由N初值为1F可以知道。N=31 其中D是由FLL_CTL0的最高位DCOPLUS决定,其为0时不分频即D=1。DCOPLUS为1时DCO信号经锁频环反馈环节分频,即有由SCFI0的FLLDX位决定D的值。初始值为0。 其中fcrystal值位
[单片机]
采用MSP430单片机的开关稳压电源设计方案
  MSP430系列单片机是美国TI公司生产的新一代16位单片机,是一种超低功耗的混合信号处理器(MixedSignal Processor),它具有低电压、超低功耗、强大的处理能力、系统工作稳定、丰富的片内外设、方便开发等优点,具有很高的性价比,在工程控制等领域有着极其广泛的应用范围。开关Boost稳压电源利用开关器件控制、无源磁性元件及电容元件的能量存储特性,从输入电压源获取分离的能量,暂时把能量以磁场的形式存储在电感器中,或以电场的形式存储在电容器中,然后将能量转换到负载。对DC-DC主回路采用Boost升压斩波电路。 系统结构和总设计方案   本开关稳压电源是以MSP430F449为主控制器件,它是 TI 公司生产的
[单片机]
采用<font color='red'>MSP430</font>单片机的开关稳压电源设计方案
MSP430F2274 端口操作
/******************************************************************************************************************************************* * 功能 : P1.0用来控制LED的亮灭,软件延时50000,来翻转P1.0 * * * *
[单片机]
GPS9808模块在汽车防盗系统中的应用
1 GPS9808的功能与特点 GPS9808是一款功能强大、性能卓越的OEM模块。它在保持以前oEM模块优点的基础上进行了改良,是结构小巧、性能优良的低功耗12通道模块。它的热启动时间小于8 s,重捕时间小于0.1 s;定位精度在差分模式(DGPS)下小于5 m;接口采用串行TTL电平,数据格式支持标准NMEA—0183、SiRF二进制协议。模块外部的射频金属保护保证了在嘈杂环境下同样具有最佳性能,外型尺寸为24mm×20mm×2.6mm,功耗仅为215mW,非常适合在汽车电子等对功耗体积要求较高的系统中应用。GPS9808引脚分布如图1,各引脚的功能表1所列。 2 GPS9808在汽车防盗系统中的硬件设计 该
[单片机]
GPS9808模块在汽车防盗系统中的应用
基于MSP430行驶车辆检测器的设计
利用环形线圈、MSP430F1121A单片机与输出接口,组成低功耗行驶车辆检测系统,并能根据用户预先设定的灵敏度、工作方式、输出方式进行车辆检测与信号输出。 还应用软件动态刷新基准的方法提高了检测的可靠性和准确性。实验表明:该系统具有结构简单、功耗低、调节方便等优点。 引言 近年来,车辆检测器作为交通信息采集的重要前端部分,越来越受到业内人士的关注。鉴于公路交通现代化管理和城市交通现代化管理的发展需要, 对于行驶车辆的动态检测技术——车辆检测器的研制在国内外均已引起较大重视。车辆检测器以机动车辆为检测目标,检测车辆的通过或存在状况,其作用是为智能交通控制系统提供足够的信息以便进行最优的控制。 目前,常用的行驶车辆检测器主要有磁感应
[汽车电子]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved