第一次接触MSP430的芯片,第一次使用CCS开发环境,花了将近一个星期的时间,才把MSP430串口升级做出来。
同样分成BOOT,APP,上位机,三个部分来讲解。
BOOT
- 在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读写,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
- 拷贝结束后,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
",strlen("Boot2App
"));
asm(" mov &0xEFFE,PC;");
// asm(" mov #0xBFFE,PC;");
// asm(" mov #0x1200,PC;");
// asm(" br &0x1200;");
// asm(" LB 0x1200");
// ((void (*)(void))appAddr)();
}
}
}