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

一、前文

第一次接触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串口升级(三)

在这里插入图片描述

以下是一个MSP430串口通信UART的代码示例,包括CCS (Code Composer Studio)工程的设置和配置。 首先,确保你已经安装了CCS并设置好了MSP430开发环境。 在CCS中创建一个新工程,选择MSP430微控制器系列和型号。然后选择合适的文件夹和工程名。 在工程资源视图中,右键点击"Source Files"文件夹,选择"New" -> "Source File",输入文件名并点击"Finish"。 在新创建的源文件中,输入以下代码: ```c #include <msp430.h> void uart_init() { // 设置串口波特率 UCA0BR0 = 6; UCA0BR1 = 0; UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // 使能串口接收和发送 UCA0CTL1 &= ~UCSWRST; UCA0IE |= UCRXIE; } void uart_send_byte(uint8_t data) { // 等待上一次发送完成 while (!(UCA0IFG & UCTXIFG)); // 发送数据 UCA0TXBUF = data; } int main(void) { // 停用看门狗定时器 WDTCTL = WDTPW + WDTHOLD; // 配置P1.1和P1.2为UART模式 P1SEL |= BIT1 + BIT2; P1SEL2 |= BIT1 + BIT2; // 初始化串口 uart_init(); while(1) { // 通过串口发送数据 uart_send_byte(0x55); // 延时一段时间 __delay_cycles(1000000); } } ``` 这段代码首先定义了使用的函数:`uart_init()`用于初始化串口,`uart_send_byte()`用于发送一个字节的数据。 在`main()`函数中,首先停用看门狗定时器,然后将P1.1和P1.2配置为UART模式。接下来初始化串口,并在一个无限循环中通过串口发送数据0x55,并延时1秒。 确保你的MSP430开发板正确连接,在CCS中点击菜单中的"Build"编译代码。 然后点击"Debug"按钮或按F11进行调试。调试成功后,你可以通过串口助手或者其他串口工具,连接到MSP430开发板的串口端口,就可以接收到发送的数据了。 希望这个代码示例能够帮助你进行MSP430串口通信的开发!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小康师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值