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 }
该芯片可以从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 }
类似stm32调用各自的reset中断向量就好了
就是第一部分中的
RESET : origin = 0xFFFE, length = 0x0002
RESET : origin = 0xEFFE, length = 0x0002
调用方法 asm(" br &0xEFFE;");asm(" br &0xFFFE;");
BR这个汇编命令等价于MOV dst,PC
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");//实际执行的中断 }