MSP430FG479芯片的 IAP

MSP430以一款TI出品的16位超低功耗、具有精简指令集(RISC)的混合信号处理器,优点就是低功耗,运算快。在公司内用在一款开发中的低功耗传感器上,主要开发人员出国旅游一段时间,暂时给我代码熟悉一下,方便在旅游期间仪器暴露出来的问题帮忙解决。
第一个要搞明白的就是msp芯片的IAP,方便远程升级的功能。
参考资料:http://www.ti.com.cn/cn/lit/ug/slau056l/slau056l.pdf
开发使用TI官方出品的开发环境Code Composer Studio (CCS) 集成开发环境 。

IAP几个比较重要的点
1.APP和bootloader地址分配
2.APP程序FLASH写入
3.bootloader和app的相互跳转
4.Bootloader和app中断向量表重映射

程序地址分配

CCS IDE 修改CMD文件即可,0FFFFh to 01100h为代码区,0FFFFh to 0FFE0h为中断向量表,这里我将bootloader地址设置为0xF000h to 0xFFFFH,app地址0x11000h to 0xF000h,具体如下:
app

MEMORY
{
    SFR                     : origin = 0x0000, length = 0x0010
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
    RAM                     : origin = 0x0200, length = 0x0800
    INFOA                   : origin = 0x10C0, length = 0x0040
    INFOB                   : origin = 0x1080, length = 0x0040
    INFOC                   : origin = 0x1040, length = 0x0040
    INFOD                   : origin = 0x1000, length = 0x0040
    FLASH                   : origin = 0x1100, length = 0xDEE0
    INT00                   : origin = 0xEFE0, length = 0x0002
    INT01                   : origin = 0xEFE2, length = 0x0002
    INT02                   : origin = 0xEFE4, length = 0x0002
    INT03                   : origin = 0xEFE6, length = 0x0002
    INT04                   : origin = 0xEFE8, length = 0x0002
    INT05                   : origin = 0xEFEA, length = 0x0002
    INT06                   : origin = 0xEFEC, length = 0x0002
    INT07                   : origin = 0xEFEE, length = 0x0002
    INT08                   : origin = 0xEFF0, length = 0x0002
    INT09                   : origin = 0xEFF2, length = 0x0002
    INT10                   : origin = 0xEFF4, length = 0x0002
    INT11                   : origin = 0xEFF6, length = 0x0002
    INT12                   : origin = 0xEFF8, length = 0x0002
    INT13                   : origin = 0xEFFA, length = 0x0002
    INT14                   : origin = 0xEFFC, length = 0x0002
    RESET                   : origin = 0xEFFE, length = 0x0002
}

bootloader

MEMORY
{
    SFR                     : origin = 0x0000, length = 0x0010
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
    RAM                     : origin = 0x0200, length = 0x0800
    INFOA                   : origin = 0x10C0, length = 0x0040
    INFOB                   : origin = 0x1080, length = 0x0040
    INFOC                   : origin = 0x1040, length = 0x0040
    INFOD                   : origin = 0x1000, length = 0x0040
    FLASH                   : origin = 0xF000, length = 0x0FE0
    INT00                   : origin = 0xFFE0, length = 0x0002
    INT01                   : origin = 0xFFE2, length = 0x0002
    INT02                   : origin = 0xFFE4, length = 0x0002
    INT03                   : origin = 0xFFE6, length = 0x0002
    INT04                   : origin = 0xFFE8, length = 0x0002
    INT05                   : origin = 0xFFEA, length = 0x0002
    INT06                   : origin = 0xFFEC, length = 0x0002
    INT07                   : origin = 0xFFEE, length = 0x0002
    INT08                   : origin = 0xFFF0, length = 0x0002
    INT09                   : origin = 0xFFF2, length = 0x0002
    INT10                   : origin = 0xFFF4, length = 0x0002
    INT11                   : origin = 0xFFF6, length = 0x0002
    INT12                   : origin = 0xFFF8, length = 0x0002
    INT13                   : origin = 0xFFFA, length = 0x0002
    INT14                   : origin = 0xFFFC, length = 0x0002
    RESET                   : origin = 0xFFFE, length = 0x0002
}

FLASH擦写

该芯片可以从ram和flash执行写操作,但ram执行cpu不会被阻塞,因此必须判断busy标志位防止一些不可预知的错误。flash执行则会阻塞cpu。

Any erase cycle can be initiated from within flash memory or from RAM. When
a flash segment erase operation is initiated from within flash memory, all timing
is controlled by the flash controller, and the CPU is held while the erase cycle
completes. After the erase cycle completes, the CPU resumes code execution
with the instruction following the dummy write.
在这里插入图片描述
官网文档提供的汇编函数

MOV #WDTPW+WDTHOLD,&WDTCTL ; Disable WDT
MOV #FWKEY+FSSEL1+FN0,&FCTL2 ; SMCLK/2
MOV #FWKEY,&FCTL3 ; Clear LOCK
MOV #FWKEY+ERASE,&FCTL1 ; Enable segment erase
CLR &0FC10h ; Dummy write, erase S1
MOV #FWKEY+LOCK,&FCTL3 ; Done, set LOCK

另外提一下,flash写入会擦除,调用 FLASH_Write应当先把当前segment的其他数据读出来,根据规格书code memory一个segment512字节

void FLASH_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	char *Flash_ptr;                          // Flash pointer
	unsigned int i;
	Flash_ptr = (char *)WriteAddr;            // Initialize Flash pointer
	FCTL3 = FWKEY;                            // Clear Lock bit
	FCTL1 = FWKEY + ERASE;                    // Set Erase bit
	*Flash_ptr = 0;                           // Dummy write to erase Flash seg

	FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation

	for (i = 0; i < NumToWrite; i++)
	{
	  *Flash_ptr++ = pBuffer[i];                   // Write value to flash
	}

	FCTL1 = FWKEY;                            // Clear WRT bit
	FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
}

bootloader和app跳转

类似stm32调用各自的reset中断向量就好了
就是第一部分中的
RESET : origin = 0xFFFE, length = 0x0002
RESET : origin = 0xEFFE, length = 0x0002
调用方法 asm(" br &0xEFFE;");asm(" br &0xFFFE;");
BR这个汇编命令等价于MOV dst,PC
在这里插入图片描述

bootloader和app中断向量表偏移

stm32中中断向量表偏移通过配置SCB->VTOR寄存器即可,如下systeminit函数中VECT_TAB_OFFSET宏定义控制偏移位置。

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif

但所使用的这块芯片没有找到类似的配置寄存器,也就是说中断服务函数进的都是bootloader的中断,只能在bootloader里用asm(" br &0xXXXX;")命令跳转到APP实际的中断服务函数,例如
boot

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(WDT_VECTOR))) watchdog_timer (void)
#else
#error Compiler not supported!
#endif
{
	asm("	br &0xEFF4;"); //地址根据APP的cmd配置
}

app

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(WDT_VECTOR))) watchdog_timer (void)
#else
#error Compiler not supported!
#endif
{
	printf("watchdog_timer\r\n");//实际执行的中断
}