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 = 0x0010PERIPHERALS_8BIT : origin = 0x0010, length = 0x00F0PERIPHERALS_16BIT : origin = 0x0100, length = 0x0100RAM : origin = 0x0200, length = 0x0800INFOA : origin = 0x10C0, length = 0x0040INFOB : origin = 0x1080, length = 0x0040INFOC : origin = 0x1040, length = 0x0040INFOD : origin = 0x1000, length = 0x0040FLASH : origin = 0x1100, length = 0xDEE0INT00 : origin = 0xEFE0, length = 0x0002INT01 : origin = 0xEFE2, length = 0x0002INT02 : origin = 0xEFE4, length = 0x0002INT03 : origin = 0xEFE6, length = 0x0002INT04 : origin = 0xEFE8, length = 0x0002INT05 : origin = 0xEFEA, length = 0x0002INT06 : origin = 0xEFEC, length = 0x0002INT07 : origin = 0xEFEE, length = 0x0002INT08 : origin = 0xEFF0, length = 0x0002INT09 : origin = 0xEFF2, length = 0x0002INT10 : origin = 0xEFF4, length = 0x0002INT11 : origin = 0xEFF6, length = 0x0002INT12 : origin = 0xEFF8, length = 0x0002INT13 : origin = 0xEFFA, length = 0x0002INT14 : origin = 0xEFFC, length = 0x0002RESET : origin = 0xEFFE, length = 0x0002
}
bootloader
MEMORY
{SFR : origin = 0x0000, length = 0x0010PERIPHERALS_8BIT : origin = 0x0010, length = 0x00F0PERIPHERALS_16BIT : origin = 0x0100, length = 0x0100RAM : origin = 0x0200, length = 0x0800INFOA : origin = 0x10C0, length = 0x0040INFOB : origin = 0x1080, length = 0x0040INFOC : origin = 0x1040, length = 0x0040INFOD : origin = 0x1000, length = 0x0040FLASH : origin = 0xF000, length = 0x0FE0INT00 : origin = 0xFFE0, length = 0x0002INT01 : origin = 0xFFE2, length = 0x0002INT02 : origin = 0xFFE4, length = 0x0002INT03 : origin = 0xFFE6, length = 0x0002INT04 : origin = 0xFFE8, length = 0x0002INT05 : origin = 0xFFEA, length = 0x0002INT06 : origin = 0xFFEC, length = 0x0002INT07 : origin = 0xFFEE, length = 0x0002INT08 : origin = 0xFFF0, length = 0x0002INT09 : origin = 0xFFF2, length = 0x0002INT10 : origin = 0xFFF4, length = 0x0002INT11 : origin = 0xFFF6, length = 0x0002INT12 : origin = 0xFFF8, length = 0x0002INT13 : origin = 0xFFFA, length = 0x0002INT14 : origin = 0xFFFC, length = 0x0002RESET : 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 pointerunsigned int i;Flash_ptr = (char *)WriteAddr; // Initialize Flash pointerFCTL3 = FWKEY; // Clear Lock bitFCTL1 = FWKEY + ERASE; // Set Erase bit*Flash_ptr = 0; // Dummy write to erase Flash segFCTL1 = FWKEY + WRT; // Set WRT bit for write operationfor (i = 0; i < NumToWrite; i++){*Flash_ptr++ = pBuffer[i]; // Write value to flash}FCTL1 = FWKEY; // Clear WRT bitFCTL3 = 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_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->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");//实际执行的中断
}