文章目录

  • 一、前文
  • 二、程序起始地址
  • 三、中断向量
  • 四、串口接收
  • 五、Flash读写
  • 六、跳转APP
  • 七、其他


一、前文

第一次接触MSP430的芯片,第一次使用CCS开发环境,花了将近一个星期的时间,才把MSP430串口升级做出来。

同样分成BOOT(引导程序)、APP(主程序)、上位机(PC端工具),三个部分来讲解。

本博文是BOOT(引导程序)相关讲解。

基于CCS工程MSP430串口升级(二)

基于CCS工程MSP430串口升级(三)

二、程序起始地址

  • 在lnk_msp430fg479.cmd中修改BOOT Flash的起始地址(0xF000~0xFFE0),将近4K的Flash
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 = 0xEEE0 
    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
}

三、中断向量

  • 中断向量重映射,BOOT中断函数跳转到APP中断函数
// Timer A0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMERA0_VECTOR))) Timer_A (void)
#else
#error Compiler not supported!
#endif
{
	asm("	br &0xEFEC;");
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=SD16A_VECTOR
__interrupt void SD16ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(SD16A_VECTOR))) SD16ISR (void)
#else
#error Compiler not supported!
#endif
{
	asm("	br &0xEFEE;");
}

// Watchdog Timer interrupt service routine
#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;");
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI_A0_rx (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCI_A0_rx (void)
#else
#error Compiler not supported!
#endif
{
//	printf("%c",UCA0RXBUF);
//	if(isBoot==2)
//	{
//		u16 rxAddr = 0xBFF2  ;
//		((void (*)(void))appAddr)();
		asm("	br &0xEFF2;");
//	}
//	else
//	{
//		rx_buf[rx_buf_index++] = UCA0RXBUF;
//		if(rx_buf_index>=RX_SIZE)
//			rx_buf_index = 0;
//	}
}

四、串口接收

  • 这边需要注意的一点是,APP和BOOT的中断函数不要有冲突,有重复。比如APP有串口接收中断,BOOT就不能有串口接收中断。至于为什么,后面再解释。在这里,APP的内容比较多,必须要有串口接收中断提高实时性,那就只能委屈BOOT轮询串口缓冲。
while(1)
	{
//		delay_ms(1000);
		for(i=0;i<0x7fff;i++)
		{
			if(IFG2&UCA0RXIFG)
			{
				i=0;
				rx_buf[rx_buf_index++] = UCA0RXBUF;
				if(rx_buf_index>=RX_SIZE)
					rx_buf_index = 0;
			}
		}

		if(rx_buf_index > 5)
		{
			if(rx_buf[0]==MODBUS_DO)
			{
				crc = CRC16(rx_buf, rx_buf_index-2);
				if(crc == ((rx_buf[rx_buf_index-1]<<8)|rx_buf[rx_buf_index-2]))
				{
					switch(rx_buf[1])
					{
						case 0x03:
							Modbus_Function_3();
							break;
						case 0x10:
							Modbus_Function_10();
							break;
						case 0x45:
							Modbus_Function_45();
							break;
					}
				}
			}
			rx_buf_index = 0;
		}
	}

五、Flash读写

  • Flash读写,MSP430FG479这款MCU,一个片区512字节,所以需要整片512字节的擦除写入。每次写入前,先把该片区的512字节读取到缓存中,再将需要修改的内容填充到缓存中,最后一次将512字节写入Flash片区
void Flash_SecureWrite(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	int i=0;
	u16 offsetAddr = WriteAddr%512;
	u16 baseAddr = WriteAddr-offsetAddr;
	FLASH_Read(baseAddr, tx_buf, 512);
	for(i=0; i<NumToWrite; i++)
	{
		tx_buf[offsetAddr+i] = pBuffer[i];
	}
	FLASH_Write(baseAddr, tx_buf, 512);
}

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
}

void FLASH_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
	char *Flash_ptr;
	u32 i;
	Flash_ptr = (char *)ReadAddr;            // Initialize Flash pointer

	for(i=0; i<NumToRead; i++)
		pBuffer[i] = *Flash_ptr++;
}

六、跳转APP

  • 拷贝结束后,BOOT跳转到APP。
void Boot2App(void)
{
//	u16 appAddr = 0xBFFE  ;// 0x1200
	FLASH_Read(PROJECT_VERSION_ADDR,(u8 *)projectVersion,0x10);
	FLASH_Read(FLASH_OTA_STATUS_ADDR,(u8 *)&isBoot,2);//App(0) or Boot(1)

	if(isBoot==0)
	{
		if(strstr(projectVersion,"AquaDO"))
		{
			isBoot = 2;
			delay_ms(1000);
			rs485_send("Boot2App\r\n",strlen("Boot2App\r\n"));
			asm("	mov 	&0xEFFE,PC;");
//			asm("	mov 	#0xBFFE,PC;");
//			asm("	mov 	#0x1200,PC;");
//			asm("	br &0x1200;");
//			asm("	LB 0x1200");
//			((void (*)(void))appAddr)();
		}
	}
}

七、其他

基于CCS工程MSP430串口升级(一)

基于CCS工程MSP430串口升级(二)

基于CCS工程MSP430串口升级(三)