天天看點

2021-06-13stm32f103簡易bootloader實作

stm32f103簡易bootloader實作

      因為之前調試代碼時經常要插線燒錄,覺得麻煩,就想結合下手頭的ESP8266做個無線燒錄器,這就需要在stm32上做個bootloader。

關于bootloader,網上有很多資料,結合開發闆例程做了個簡易的BootLoader。bootloader的核心就是如何在運作時

跳轉到設定的應用程式段,其他的跟平常寫程式沒什麼差別。主要步驟如下:

   1、配置設定bootloader和APP的記憶體

看你想要配置設定多少記憶體給BootLoader

bootloader:

2021-06-13stm32f103簡易bootloader實作

APP:

2021-06-13stm32f103簡易bootloader實作

編譯完後可以去Map檔案下檢視是否設定成功,輕按兩下工程目錄就會彈出來

2021-06-13stm32f103簡易bootloader實作
2021-06-13stm32f103簡易bootloader實作

這樣就設定好了。如果不是這樣的話,去Linker檢視又沒有設定好,我之前就是因為這個浪費了半天時間

2021-06-13stm32f103簡易bootloader實作

沒√選的話也可以手動設定,将0x08000000修改一下也行。

2、設定中斷向量表偏移量

     中斷向表得預設起始位址是0x08000000,因為APP程式位址改變了,APP程式想要進入中斷的話,對應的中斷向量表也要相應偏移。

VECT_TAB_OFFSET就是偏移量,預設是0。在system_stm32f10x.c檔案下将VECT_TAB_OFFSET修改成設定的偏移量,就行了

2021-06-13stm32f103簡易bootloader實作
2021-06-13stm32f103簡易bootloader實作

3、跳轉到APP程式

其主要是從FLASH中讀出程式起始位址,然後跳轉,主要靠下面兩個函數進行

typedef void (*APP_FUNC)(void);//void類型的函數指針

_asm  void MSR_MSP(vu32 addr)  //設定堆棧指針
{
	MSR MSP, r0
	BX r14
}

//跳轉到應用程式段
//appaddr:使用者代碼起始位址.
void iap_load_app(u32 appaddr)
{
	int i;
	APP_FUNC jump2app;
	if(((*( vu32*)appaddr)&0x2FFE0000)==0x20000000)	//檢查棧頂位址是否合法.不同的型号可能會有所不同
	{ 
		
		jump2app=(APP_FUNC)*( vu32*)(appaddr+4);		//使用者代碼區第二個字為程式開始位址(複位位址)		
		MSR_MSP(*( vu32*)appaddr);					//初始化APP堆棧指針(使用者代碼區的第一個字用于存放棧頂位址)
		
		for(i = 0; i < 8; i++)
		{			
			NVIC->ICER[i] = 0xFFFFFFFF;	// 在跳轉是最好關閉中斷
			NVIC->ICPR[i] = 0xFFFFFFFF;	// 清除中斷标志位
		}
		jump2app();									//跳轉到APP.
		
	}
	else 
		printf("沒有APP\r\n");
 
}
           

4、生成APP代碼的Bin檔案

因為下載下傳Flash的檔案要是Bin格式的。user下寫入fromelf --bin -o "[email protected]" "#L"

2021-06-13stm32f103簡易bootloader實作

User下設定成這樣就好了。

最後進行簡單測試,從序列槽處下載下傳APP的bin檔案并運作程式,看看是否跑通。

bootloader主函數

int main()
{
	u32 countold=0,applen;
	u8 flag=0,i=0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Systick_Init(72);
	ALL_GPIO_Init();
	LED=0;
	delay_ms(500);
	USART1_Init(115200);
	printf("進入bootloader\r\n");
	printf("s---開始序列槽下載下傳APP\r\nr---讀取flash中的APP\r\n");
	while(1)
	{
		if(USART_RX_CNT&&flag==2)
		{
			if(countold==USART_RX_CNT&&USART_RX_CNT>3)
			{
				applen=USART_RX_CNT;
				countold=0;
				USART_RX_CNT=0;
				printf("使用者程式接收完成!\r\n");
				printf("代碼長度:%dBytes\r\n",applen);
				iap2_write_app(0x08003000,&USART_REC_BUF[1],applen);//将序列槽接收的bin檔案寫入flash
				printf("檔案寫入完成\r\n");
				flag=1;
			}
		else 
			countold=USART_RX_CNT;
		}
		
		if(USART_REC_BUF[0]=='s')//接收數組第一位作為控制指令
		{
			
			USART_REC_BUF[0]=0;
			flag=2;
			printf("開始接收APP檔案\r\n");
		}
		if(flag==1||USART_REC_BUF[0]=='r')
		{
			  
			  printf("5s後開始運作APP\r\n");
				delay_ms(1000);
				delay_ms(1000);
				delay_ms(1000);
				delay_ms(1000);
				delay_ms(1000);
				iap_load_app(0x08003000);
		}
			
		
		if(i==5)
		{
			i=0;
		  LED=!LED;
		}
		i++;
		delay_ms(100);
	}
}
           

APP測試函數:

int main()
{
	__enable_irq();//打開中斷
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Systick_Init(72);
	ALL_GPIO_Init();
	LED=0;
	delay_ms(500);
	USART1_Init(115200);
	printf("歡迎來到應用程式區域!\r\n");
	while(1)
	{
		LED=!LED;
		printf("hello hello\r\n");
		delay_ms(1000);
	}
}
           

結果:

2021-06-13stm32f103簡易bootloader實作

成功跳轉。