前言:由于单片机如果不支持USB等方式在线升级,每次升级会设计拆机升级单片机,这对于一个成熟的产品是很鸡肋的。所以记录一下本次研发升级功能的过程以及所需要的问题。
一、升级程序设计
二、内存重新分配
1.芯片原有内存分配
原有内存分配主要关心FRAM到中断结束,从0x8000~0xFFFF
/******************************************************************************
*
* Copyright (C) 2012 - 2021 Texas Instruments Incorporated - http://www.ti.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Default linker command file for Texas Instruments MSP430FR2155
*
*****************************************************************************/
/******************************************************************************/
/* */
/* Usage: lnk430 <obj files...> -o <out file> -m <map file> lnk.cmd */
/* cl430 <src files...> -z -o <out file> -m <map file> lnk.cmd */
/* */
/*----------------------------------------------------------------------------*/
/* These linker options are for command line linking only. For IDE linking, */
/* you should set your linker options in Project Properties */
/* -c LINK USING C CONVENTIONS */
/* -stack 0x0100 SOFTWARE STACK SIZE */
/* -heap 0x0100 HEAP AREA SIZE */
/* */
/*----------------------------------------------------------------------------*/
/* 1.213 */
/*----------------------------------------------------------------------------*/
/****************************************************************************/
/* SPECIFY THE SYSTEM MEMORY MAP */
/****************************************************************************/
MEMORY
{
TINYRAM : origin = 0x6, length = 0x1A
BSL0 : origin = 0x1000, length = 0x800
INFO : origin = 0x1800, length = 0x200
TLVMEM : origin = 0x1A00, length = 0x200
BOOTCODE : origin = 0x1C00, length = 0x400
RAM : origin = 0x2000, length = 0x1000
FRAM : origin = 0x8000, length = 0x7F80
ROMLIB : origin = 0xFAC00, length = 0x5000
BSL1 : origin = 0xFFC00, length = 0x400
JTAGSIGNATURE : origin = 0xFF80, length = 0x0004, fill = 0xFFFF
BSLSIGNATURE : origin = 0xFF84, length = 0x0004, fill = 0xFFFF
BSLCONFIGURATIONSIGNATURE: origin = 0xFF88, length = 0x0002, fill = 0xFFFF
BSLCONFIGURATION : origin = 0xFF8A, length = 0x0002, fill = 0xFFFF
BSLI2CADDRESS : origin = 0xFFA0, length = 0x0002, fill = 0xFFFF
INT00 : origin = 0xFFA2, length = 0x0002
INT01 : origin = 0xFFA4, length = 0x0002
INT02 : origin = 0xFFA6, length = 0x0002
INT03 : origin = 0xFFA8, length = 0x0002
INT04 : origin = 0xFFAA, length = 0x0002
INT05 : origin = 0xFFAC, length = 0x0002
INT06 : origin = 0xFFAE, length = 0x0002
INT07 : origin = 0xFFB0, length = 0x0002
INT08 : origin = 0xFFB2, length = 0x0002
INT09 : origin = 0xFFB4, length = 0x0002
INT10 : origin = 0xFFB6, length = 0x0002
INT11 : origin = 0xFFB8, length = 0x0002
INT12 : origin = 0xFFBA, length = 0x0002
INT13 : origin = 0xFFBC, length = 0x0002
INT14 : origin = 0xFFBE, length = 0x0002
INT15 : origin = 0xFFC0, length = 0x0002
INT16 : origin = 0xFFC2, length = 0x0002
INT17 : origin = 0xFFC4, length = 0x0002
INT18 : origin = 0xFFC6, length = 0x0002
INT19 : origin = 0xFFC8, length = 0x0002
INT20 : origin = 0xFFCA, length = 0x0002
INT21 : origin = 0xFFCC, length = 0x0002
INT22 : origin = 0xFFCE, length = 0x0002
INT23 : origin = 0xFFD0, length = 0x0002
INT24 : origin = 0xFFD2, length = 0x0002
INT25 : origin = 0xFFD4, length = 0x0002
INT26 : origin = 0xFFD6, length = 0x0002
INT27 : origin = 0xFFD8, length = 0x0002
INT28 : origin = 0xFFDA, length = 0x0002
INT29 : origin = 0xFFDC, length = 0x0002
INT30 : origin = 0xFFDE, length = 0x0002
INT31 : origin = 0xFFE0, length = 0x0002
INT32 : origin = 0xFFE2, length = 0x0002
INT33 : origin = 0xFFE4, length = 0x0002
INT34 : origin = 0xFFE6, length = 0x0002
INT35 : origin = 0xFFE8, length = 0x0002
INT36 : origin = 0xFFEA, length = 0x0002
INT37 : origin = 0xFFEC, length = 0x0002
INT38 : origin = 0xFFEE, length = 0x0002
INT39 : origin = 0xFFF0, length = 0x0002
INT40 : origin = 0xFFF2, length = 0x0002
INT41 : origin = 0xFFF4, length = 0x0002
INT42 : origin = 0xFFF6, length = 0x0002
INT43 : origin = 0xFFF8, length = 0x0002
INT44 : origin = 0xFFFA, length = 0x0002
INT45 : origin = 0xFFFC, length = 0x0002
RESET : origin = 0xFFFE, length = 0x0002
}
/****************************************************************************/
/* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY */
/****************************************************************************/
SECTIONS
{
GROUP(ALL_FRAM)
{
GROUP(READ_WRITE_MEMORY)
{
.TI.persistent : {} /* For #pragma persistent */
.cio : {} /* C I/O Buffer */
.sysmem : {} /* Dynamic memory allocation area */
} PALIGN(0x0400), RUN_START(fram_rw_start) RUN_END(fram_rx_start)
GROUP(READ_ONLY_MEMORY)
{
.cinit : {} /* Initialization tables */
.pinit : {} /* C++ constructor tables */
.binit : {} /* Boot-time Initialization tables */
.init_array : {} /* C++ constructor tables */
.mspabi.exidx : {} /* C++ constructor tables */
.mspabi.extab : {} /* C++ constructor tables */
.const : {} /* Constant data */
}
GROUP(EXECUTABLE_MEMORY)
{
.text : {} /* Code */
.text:_isr : {} /* Code ISRs */
}
} > FRAM
#ifdef __TI_COMPILER_VERSION__
#if __TI_COMPILER_VERSION__ >= 15009000
.TI.ramfunc : {} load=FRAM, run=RAM, table(BINIT)
#endif
#endif
.jtagsignature : {} > JTAGSIGNATURE
.bslsignature : {} > BSLSIGNATURE
.bslconfigsignature : {} > BSLCONFIGURATIONSIGNATURE
.bslconfig : {} > BSLCONFIGURATION
.bsli2caddress : {} > BSLI2CADDRESS
.bss : {} > RAM /* Global & static vars */
.data : {} > RAM /* Global & static vars */
.TI.noinit : {} > RAM /* For #pragma noinit */
.stack : {} > RAM (HIGH) /* Software system stack */
.tinyram : {} > TINYRAM /* Tiny RAM */
/* MSP430 INFO memory segments */
.info : type = NOINIT{} > INFO
/* MSP430 interrupt vectors */
.int00 : {} > INT00
.int01 : {} > INT01
.int02 : {} > INT02
.int03 : {} > INT03
.int04 : {} > INT04
.int05 : {} > INT05
.int06 : {} > INT06
.int07 : {} > INT07
.int08 : {} > INT08
.int09 : {} > INT09
.int10 : {} > INT10
.int11 : {} > INT11
.int12 : {} > INT12
.int13 : {} > INT13
.int14 : {} > INT14
.int15 : {} > INT15
.int16 : {} > INT16
.int17 : {} > INT17
.int18 : {} > INT18
.int19 : {} > INT19
.int20 : {} > INT20
.int21 : {} > INT21
PORT4 : { * ( .int22 ) } > INT22 type = VECT_INIT
PORT3 : { * ( .int23 ) } > INT23 type = VECT_INIT
PORT2 : { * ( .int24 ) } > INT24 type = VECT_INIT
PORT1 : { * ( .int25 ) } > INT25 type = VECT_INIT
.int26 : {} > INT26
.int27 : {} > INT27
ECOMP0_ECOMP1: { * ( .int28 ) } > INT28 type = VECT_INIT
ADC : { * ( .int29 ) } > INT29 type = VECT_INIT
EUSCI_B1 : { * ( .int30 ) } > INT30 type = VECT_INIT
EUSCI_B0 : { * ( .int31 ) } > INT31 type = VECT_INIT
EUSCI_A1 : { * ( .int32 ) } > INT32 type = VECT_INIT
EUSCI_A0 : { * ( .int33 ) } > INT33 type = VECT_INIT
WDT : { * ( .int34 ) } > INT34 type = VECT_INIT
RTC : { * ( .int35 ) } > INT35 type = VECT_INIT
TIMER3_B1 : { * ( .int36 ) } > INT36 type = VECT_INIT
TIMER3_B0 : { * ( .int37 ) } > INT37 type = VECT_INIT
TIMER2_B1 : { * ( .int38 ) } > INT38 type = VECT_INIT
TIMER2_B0 : { * ( .int39 ) } > INT39 type = VECT_INIT
TIMER1_B1 : { * ( .int40 ) } > INT40 type = VECT_INIT
TIMER1_B0 : { * ( .int41 ) } > INT41 type = VECT_INIT
TIMER0_B1 : { * ( .int42 ) } > INT42 type = VECT_INIT
TIMER0_B0 : { * ( .int43 ) } > INT43 type = VECT_INIT
UNMI : { * ( .int44 ) } > INT44 type = VECT_INIT
SYSNMI : { * ( .int45 ) } > INT45 type = VECT_INIT
.reset : {} > RESET /* MSP430 reset vector */
}
/****************************************************************************/
/* FRAM WRITE PROTECTION SEGMENT DEFINITONS */
/****************************************************************************/
#ifdef _FRWP_ENABLE
__mpu_enable=1;
start_protection_offset_address = (fram_rx_start - fram_rw_start) >> 10;
program_fram_protection = 0x1;
#ifdef _INFO_FRWP_ENABLE
info_fram_protection = 0x1;
#else
info_fram_protection = 0x0;
#endif
#endif
/****************************************************************************/
/* INCLUDE PERIPHERALS MEMORY MAP */
/****************************************************************************/
-l msp430fr2155.cmd
2. APP和BOOT 内存重新分配
APP和BOOT的内存分配如下图所示。
三、中断映射
如果内存中同时存在APP和BOOT的中断程序,那么在进入APP后,触发APP的中断实际上触发的BOOT的中断处理函数(这里可能是因为BOOT使用的是默认的寄存器关系,没有去深究,在查阅大量资料后,大家的处理方式都是将BOOT中的中断转发到APP中断对应的寄存器地址)。所以需要将BOOT中的中断转发到APP中,并在程序进入BOOT后关闭中断。
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A1_VECTOR)))
#endif
void USCI_A1_ISR (void)
{
// 根据app端对应的中断地址进行转发
asm(" br &0xDFE2;");
}
将BOOT端的中断禁用了,那么BOOT端只有在主循环中使用寄存器的方式进行数据的接受和处理了。
// 主循环接受数据
void receiveData(void)
{
uint8_t readData;
uint8_t resData;
uint8_t flag2;
flag2= UCA1IFG;
if (flag2& UCRXIFG)
{
readData = UCA1RXBUF;
// spi_packetLogic 为数据处理,这里就不贴对应的代码了
// 各位老铁自行编写吧
resData = spi_packetLogic(readData);
UCA1TXBUF = resData;
}
}
四、程序跳转
- BOOT->APP
通过上面的内存分配,我们知道APP的RESET的地址是0xDFFE,所以直接跳转到该地址,触发一个reset事件,就让程序成功进入APP。
这里补充一点,目前我知道的办法只有触发reset事件,便可以在APP和BOOT之间相互跳转,然后触发reset事件的方法有很多,比如函数指针、官方提供的函数(例:PMM_trigBOR();
)、汇编等。我这里选择是汇编方式。
asm(" mov &0xDFFE,PC;");
- APP->BOOT
和上面的跳转方式一样,直接触发reset事件完成跳转
asm(" mov &0xFFFE,PC;");
补充:上述能完成程序之间的跳转,但是有一个现象,在APP->BOOT中,触发了0xFFFE的reset。这里设备断电重启了,由于程序里面的flag已经被设置为BOOT的状态,所以重启后就在BOOT中运行了。不确定是不是正常的或者用户手册中有说明这个reset会做更多的事。希望有懂的大佬评论区指导指导。