天天看點

STM32L4xx基于UART的IAP實作(實驗詳解)STM32L4xx基于UART的IAP實作(實驗詳解)

STM32L4xx基于UART的IAP實作(實驗詳解)

最近剛接觸到STM32L452RET6(STM32L4xx系列)晶片,使用LL庫配置(LL庫更接近硬體層,直接操作寄存器。)可以先使用STM32CubeMX軟體生成一個基礎工程,再進一步添加配置。以下是學習了2天IAP後的總結,其實并沒有想象中的那麼難懂;

一.實作目标

實作通過MCU的UART接收來自電腦發送的bin檔案進行IAP程式更新。

二.IAP單項進入APP 實作流程

我選用的STM32L452的FLASH有512K大小,位址在0x08000000~0x08080000之間。

1.先将FLASH劃分成3塊區域,一個IAP引導程式,兩個APP應用程式:

一般IAP引導程式越小越好,給之後的APP應用程式留下更多空間,這裡我不會太刻意節省空間。

将IAP引導程式起始位址分到0x08000000,APP1應用程式1起始位址分到0x08020000,APP2應用程式2起始位址分到0x08040000。

IAP引導程式有0x00000-0x20000,有(0x20000-0x00000)/1024=128K;

APP1應用程式1有0x20000-0x40000,有(0x40000-0x20000)/1024=128K;

APP2應用程式2有0x40000-0x80000,有(0x80000-0x40000)/1024=256K;

2.建立APP應用程式獲得bin檔案:

STM32L4xx系列晶片設定中斷偏移時需要修改VECT_TAB_OFFSET,可以通過直接修改宏定義進行中斷向量表的偏移

STM32L4xx基于UART的IAP實作(實驗詳解)STM32L4xx基于UART的IAP實作(實驗詳解)
STM32L4xx基于UART的IAP實作(實驗詳解)STM32L4xx基于UART的IAP實作(實驗詳解)

例如我把APP1應用程式1起始位址定義在了0x08020000,是以把VECT_TAB_OFFSET修改成0x20000的偏移量,同時修改下圖紅色标記作為程式起始位址,橙色标記加上紅色标記是FLSAH總容量,我現在需要偏移0x20000,就改成下圖所示:

STM32L4xx基于UART的IAP實作(實驗詳解)STM32L4xx基于UART的IAP實作(實驗詳解)

接着進行設定,在RUN中寫入fromelf --bin --output F:\MyFile\Project\STM32L471VE\Project_STM32L471_IAPFLASH\OBJ\Project .bin F:\MyFile\Project\STM32L471VE\Project_STM32L471_IAPFLASH\OBJ\Project.axf,路徑寫成Output裡面生成的路徑,生成的檔案名與Output生成檔案名保持一緻,不然在編譯時會報錯:

STM32L4xx基于UART的IAP實作(實驗詳解)STM32L4xx基于UART的IAP實作(實驗詳解)

接着寫一個簡單的程式閃爍LED燈的程式:

void main(void)//APP1應用程式1
{
	LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);//LED初始化
	while(1)
	{
		LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
		LL_mDelay(200);
	}
}
           

編譯通過後會在設定的路徑裡生成程式的bin檔案;

3.編寫IAP引導程式,此時就跟平常一樣不用對Keil進行任何設定:

void IAPMain(void)
{
	u32	oldcount=0;
	u32	applenth=0;
	IAP_Usart_Init(9600);//UART初始化IAP
	while(1)
	{
		#if USE_DOG
			LL_WWDG_SetCounter(WWDG, 0X7E);//喂狗
		#endif
		if(USART3_RX_DATA_BUF_CNT)
		{
			if(oldcount == USART3_RX_DATA_BUF_CNT)//新周期内沒有資料認為接收完畢
			{
				applenth = USART3_RX_DATA_BUF_CNT;
				oldcount = 0;
				USART3_RX_DATA_BUF_CNT = 0;
				if (((*(__IO uint32_t*)(SaveAddress + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_write_appbin(AppAddress1, USART3_RxData, applenth);//更新程式,序列槽接收資料寫入APP位址
				if (((*(__IO uint32_t*)(AppAddress1 + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_load_app(AppAddress1);//跳轉到APP位址
			}
			else
				oldcount = USART3_RX_DATA_BUF_CNT;
		}
		LL_mDelay(10);
	}
}
           

大緻邏輯就是序列槽初始化,等到bin檔案通過UART接收完成後,把接收的資料寫到AppAddress1下,再進行IAP跳轉到指定位址,AppAddress1就是0x08020000;編譯後,下載下傳程式,剛開始燈時熄滅的,再通過電腦序列槽工具把之前獲得的APP1應用程式1的bin檔案通過UART發送給MCU,成功進行IAP跳轉到APP1後燈會閃爍起來,這是一個IAP->APP的單向實驗;

三.IAP單項進入APP1,APP1和APP2互相切換 實作流程

和之前的操作類似,設定Keil,main函數改成如下,通過改變#if來區分LED的快閃和慢閃程式,還有不同的跳轉位址,編譯後獲得兩個bin檔案,還是下載下傳IAP引導程式,通過UART發送bin檔案進行跳轉:

void main(void)
{
	u32	oldcount=0;
	u32	applenth=0;
	IAP_Usart_Init(9600);//初始化IAP
	LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);//LED初始化
	while(1)
	{
		LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
		#if 1  //偏移0x20000時
		LL_mDelay(200);
		if(USART3_RX_DATA_BUF_CNT)
		{
			if(oldcount == USART3_RX_DATA_BUF_CNT)//新周期内沒有資料認為接收完畢
			{
				applenth = USART3_RX_DATA_BUF_CNT;
				oldcount = 0;
				USART3_RX_DATA_BUF_CNT = 0;
				if (((*(__IO uint32_t*)(SaveAddress + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_write_appbin(AppAddress2, USART3_RxData, applenth);//更新程式,序列槽接收資料寫入APP位址
				if (((*(__IO uint32_t*)(AppAddress2 + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_load_app(AppAddress2);//跳轉到APP位址
			}
			else
				oldcount = USART3_RX_DATA_BUF_CNT;
		}
		#else	//偏移0x40000時
		LL_mDelay(1000);
		if(USART3_RX_DATA_BUF_CNT)
		{
			if(oldcount == USART3_RX_DATA_BUF_CNT)//新周期内沒有資料認為接收完畢
			{
				applenth = USART3_RX_DATA_BUF_CNT;
				oldcount = 0;
				USART3_RX_DATA_BUF_CNT = 0;
				if (((*(__IO uint32_t*)(SaveAddress + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_write_appbin(AppAddress1, USART3_RxData, applenth);//更新程式,序列槽接收資料寫入APP位址
				if (((*(__IO uint32_t*)(AppAddress1 + 0x00000004)) & 0xFF000000 ) == 0x08000000)//檢查位址是否合法
					iap_load_app(AppAddress1);//跳轉到APP位址
			}
			else
				oldcount = USART3_RX_DATA_BUF_CNT;
		}
		#endif
	}
}
           

上面的程式和IAP引導程式類似,就是序列槽讀資料,寫FLASH,再跳轉。實作IAP->APP1,再APP1->APP2,再從APP2->APP1。

隻會再在UART上連接配接上Bluetooth、RFID或者NB-Lot就可以實作遠端無線更新固件了。

這是我上傳的IAP.c和IAP.h檔案

https://download.csdn.net/download/qq_39735462/11952466