1、IAP介紹 IAP即“in applicatinprogramming”在應用編程的縮寫,指MCU可以在系統中獲取新代碼并對自己重新編程,即改變應用程序。它與我們所熟悉的ISP編程不同, LPC1768 的ISP編程接口為串口1,如果使用其他的串口或其他總線則不能對其進行編程。而我們這里所說的IAP通過下載一段引導程序Bootloader程序,如果我們想要從串口2或網口更新應用程序,在Bootloader中初始化相應的串口或網口,使其接收應用程序,將接收到的應用程序寫入到Flash里面,IAP完成后跳轉到應用程序入口執行應用程序。所以現在的IAP程序涉及到兩個概念:Bootloader和應用程序。
Bootloader:BootLoader就是在操作系統內核運行之前運行的一段小程序。通過這段小程序,我們可以初始化硬件設備、建立內存空間映射圖,從而將系統的軟硬件環境帶到一個合適狀態,以便為最終調用操作系統內核準備好正確的環境。這里我們所說的Bootloader也是系統開機前的一段小程序,其主要任務是用來初始化串口和IAP端口(網口CAN接口等)的,通過判斷狀態是否需要從IAP端口進行更新應用程序,若需要更新則從端口接收應用程序,并存放到指定的Flash里面,更新完成后則跳入到指定的Flash里面執行應用程序。 應用程序:即我們需要開發板實現功能的程序,其中應用程序主要分為兩種:hex文件和bin文件。在我們經常使用的KEIL中默認編譯生成的可執行文件(應用程序)為hex格式的,若需要編譯生成bin格式需要做如下修改,加入“D:\Keil\ARM\ARMCC\bin\fromelf.exe --bin --output ./Obj/Can_Updata.bin ./Obj/test.axf”,重新編譯生成的Can_Updata.bin文件存放在Obj文件夾下。
2、bin格式文件與hex格式文件的區別
bin格式文件是純粹的二進制文件,使用下載其將其下載到開發板時其內容完全不變,所以對于IAP下載使用bin格式文件是比較方便的,如下圖是bin文件的內容與寫入到開發板后使用仿真器觀察到Flash存放的內容(這段程序當然是可以執行的)。
Hex格式文件:Hex全稱(Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所構成的ASCII文本文件。在Intel HEX文件中,每一行包含一個HEX記錄。這些記錄由對應機器語言碼和/或常量數據的十六進制數數字組成。如下圖是hex文件的部分數據,其組成由“:CCAAAARR...ZZ ”,CC=10代表長度為16字節,AAAA=0000本條記錄中的數據在存儲區中的起始地址,RR=00,數據區,ZZ=38為校驗,這里就不做仔細說明了。
3、LPC1768 IAP原理 LPC1768復位后開始執行Boot代碼,Boot代碼可以執行ISP程序或用戶的應用代碼。發生硬件復位后,P2.10 引腳為低電平,這就被當作啟動ISP命令處理器的外部硬件請求。假定在/RESET 引腳上出現上升沿時,電源引腳出現正確的信號,那么在采樣P2.10 之前有3ms的時間決定是執行用戶代碼還是ISP 處理程序。如果P2.10 為低電平且看門狗溢出標志置位,那么忽略啟動ISP 命令處理器的外部硬件請求。在沒有ISP 命令處理器的請求(硬件復位后P2.10引腳為高電平)時,將搜索有效的用戶程序。若發現有效的用戶程序,執行控制權就被轉移給用戶程序。若沒有找到有效的用戶程序,就將調用自動波特率程序。這里不討論ISP下載及命令,有興趣的朋友可以查看LPC1768技術手冊第三十二章ISP命令。
在IAP升級中,程序正常執行即用戶代碼(這里的用戶代碼是我們所說的IAP引導程序),如下是IAP升級流程圖,程序將預留端口(這里提供有串口和CAN總線接口兩種)接收到的APP程序bin文件,將接收到的數據寫入到指定的Flash區域(例程APP地址為0x0001 0000),程序通過IAP命令將數據寫入到Flash里面,LPC1768提供了一系列IAP命令對片內Flash進行擦除編寫等 4、IAP命令 LPC1768通過IAP函數對片內Flash進行操作,IAP函數是固化在0x1FFF1FF1處的一個有傳入參數和返回參數的一個函數,在LPC1768技術手冊第三十二章IAP命令中有有詳細的說明。主要提供有如下命令:準備下操作扇區、將RAM內容復制到Flash、清除扇區、扇區查空、讀器件ID、讀boot版本、比較、重新調用ISP等。
5、串口IAP升級 本例程是根據官方提供的串口IAP更新圖片進行修改而來,直接使用官方的IAP.c文件,該文件中提供了如上圖IAP命令的各種函數,其具體參數可以參考IAP命令。根據官方例程里面將bmp圖片經過串口采用Xmodem1K協議發送到開發板存放在地址0x0001 0000,如下圖是LPC1768 Flash分配地址,第16~21扇區為應用程序存放空間。這里我們將要傳送的bmp圖片改為傳輸應用程序bin文件
6、串口IAP程序分析 例程通過按鍵對開發板進行控制,INT0鍵擦除Flash,確認鍵等待串口IAP,向上鍵顯示菜單,向下鍵執行應用程序,使用LCD來開發板狀態
當程序全部寫入到Flash后,按下向下按鍵,跳轉到應用程序,首先修改中斷向量表然后進入應用程序 void Boot( void ) { SCB->VTOR = IMG_START_SECTOR & 0x1FFFFF80; //修改中斷向量表 JMP_Boot(IMG_START_SECTOR); } 堆棧地址更新,PC地址更新 __asm void JMP_Boot( uint32_t address ){ LDR SP, [R0] ;堆棧地址更新 LDR PC, [R0, #4] ;進入應用程序 } 7、操作步驟及實驗現象 1、下載“寶馬開發板串口IAP升級”例程,插上USB轉串口線,打開超級終端,復位開發板。 2、按下按鍵INT0按鍵--擦除扇區 3、按下方向鍵確認鍵(即向下按)--等待接收串口程序 4、串口打印’C’字符等待接收數據 5、串口發送文件,選擇“1K Xmodem”協議,選擇要下載的應用程序bin文件,這里使用DAC例程作為測試。
6、點擊“發送”,發送文件 7、發送完成 8、按下方向鍵向下鍵開始執行應用程序,這時我們可以使用示波器測試P0.26口輸出正弦波信號 bin文件生成方法及設置: 打開要更新應用程序工程,這里使用“IAP升級DAC轉換”程序,設置ROM空間地址(程序下載到Flash的地址),這里也是我們應用程序的入口地址0x10000 打開User選項,利用Keil自帶的fromelf.exe生成bin文件,bin文件保存在Obj文件夾中,如下圖添加“D:\Keil\ARM\ARMCC\bin\fromelf.exe --bin --output ./Obj/app.bin ./Obj/app.axf”,輸入文件為app.axf,所以工程編譯生成輸出文件名設置為app,命令執行生成app.bin文件 打開Asm選項,定義“NO_CRP”,我們可以打開啟動文件,當定義了“NO_CRP”后,那么我們后面的代碼也就不起作用了,所以在需要加密的時候前面就一定不能再定義了代碼讀保護,也就是加密的關鍵字,經過加密后芯片再也無法擦除,由于我們這里程序需要使用到IAP升級,因此添加此定義
編譯即可生成app.bin
lpc1768 IAP疑點全解釋 IAP簡介: IAP為在應用編程的簡稱,其作用是用戶自己的程序在運行過程中對用戶程序所在的部分區域進行燒寫,目的是為了在產品發布后可以方便地通過預留的通信口對產品中的程序進行更新升級。 Lpc1768存儲器空間分配: 整體Flash布局: 地址范圍 | 地址說明 | 0x1000_0000 ~0x1000_7FFF | 片上32K通用SRAM | 0x2007_C000 ~0x2007_FFFF | 片上16K以太網/USB靜態SRAM,可用作通用SRAM | 0x2008_0000 ~0x2008_3FFF | 片上16K以太網/USB靜態SRAM,可用作通用SRAM | 0x1FFF_0000 ~0x1FFF_1FFF | 片上 8K啟動代碼區 | 0x0000_0000 ~0x0007_FFFF | 片上512K Flash存儲器 | 其他地址 | APB、AHB等寄存器映射區 |
分散加載描述文件: 分散加載描述文件是arm連接器提供的可以將程序中的代碼段、數據段定位到flash中特定的物理地址的一種機制。通過此機制我們可以把給IAP程序和用戶程序分別分配一部分空間并制定各自的起始地址以保證IAP程序和用戶程序不會重疊。關于分散加載描述文件詳細文檔,請參考《RealView編譯工具----鏈接器參考指南》第三章,對于IAP涉及到的分散加載文件的知識,我們只需知道以下幾點。以本次IAP工程為例,我們給IAP升級代碼留32K的空間(0x0000_0000~0x0000_7FFFF),剩余的給用戶程序空間(即用戶程序從地址0x0000_8000開始)。對于IAP程序部分的分散加載文件不做修改,對于用戶程序部分修改如下: 我們僅僅對第5行和第6行做了修改,改動的地方做出了標注,其具體表示意思是: Line5:0x0000_8000表示加載域的起始地址,即放在flash0x0000_8000地址處開始放置,0x0008_0000表示代碼區、數據區的總共大小的最大值,程序文件超過此值將會報錯,這里取默認值0x0008_0000即可。 Line6: 0x0000_8000表示執行域的起始地址,即程序從0x0000_8000地址處開始執行,0x0008_0000代表的意思參考上一行。 Line7:此行的作用是把中斷向量表定位在起始地址處(這里是0x0000_8000). 要使用此分散加載描述文件,還需要將Target Opitions…->Linker下的Use Memory Layout from Target Dialog前的“√”去掉。 IAP函數的使用 Iap函數是固化在Boot Rom中地址0x1FFF1FF1處的一個有傳入參數和返回參數的一個函數。對于不同的傳入參數,iap函數實現不同的功能。關于這些功能的詳細介紹,《LPC1768 user manual》32章第8節IAP commands一節中有詳細介紹,這里不贅述。遠程升級中我們常用到的幾個iap命令是:讀器件標識號、準備寫操作扇區、擦除扇區、扇區查空、將RAM內容復制到Flash、比較<地址1><地址2><字節數>。 以準備寫操作扇區為例說明iap函數的寫法。首先定義iap函數的入口地址: 1 | #define IAP_ENTER_ADR 0x1FFF1FF1/*IAP函數入口地址*/ |
接著聲明函數類型指針IAP_Entry: 1 | void (*IAP_Entry)(uint32 paramin[ ],uint32 paramout[ ]) ; |
初始化IAP函數指針使其指向IAP函數入口地址: 1 2 3 4 | void IAP_EntryInit(void) { IAP_Entry =( void(*)() )IAP_ENTER_ADR ; } |
由用戶手冊可知iap命令匯總如下圖: Iap狀態碼匯總如下圖: 據此寫出IAP命令字和狀態碼宏定義如下:(PS:Command Code中的數字10表示十進制,如:Read part ID的命令字為5410,表示其命令字為十進制的54,見上圖) 準備寫操作扇區的命令解釋如下圖: 由上圖可知準備寫操作扇區需要三個參數,分別是Command code、Param0、Param1,返回狀態碼的可能取值為CMD_SUCCESS、BUSY、INVALID_SECTOR。據此我們寫處準備寫操作扇區的命令函數如下: 1 2 3 4 5 6 7 8 9 | uint32 PreSector(uint8 arg1,uint8 arg2) { paramin[0] = IAP_SELECTOR ; //設置命令字 paramin[1] = arg1 ; //設置參數 paramin[2] = arg2 ; (*IAP_Entry)(paramin, paramout) ; //調用IAP服務程序
Return (paramout[0]) ; // 返回狀態碼 } |
其中paramin[]、paramout[]為定義的uint32型全局數組。調用此函數時只需將起始扇區號傳給arg1,結束扇區號傳給arg2即可。其他命令的函數書寫于此大同小異。 這里給出一個遠程升級的iap流程:讀取器件標識碼確定是當前芯片→確定待升級程序(用戶程序)占用的起始扇區號與結束扇區號→準備需占用扇區→擦除需占用扇區→扇區查空確定需占用扇區已成功擦除→執行將RAM復制到Flash命令將數據塊復制到Flash→執行比較命令校驗數據是否正確→如果正確執行下一數據塊的復制。 需要說明的一點是:在還行IAP命令的時候,需要關閉中斷以保證IAP命令的正確執行。幸運的是Cortex-M3提供了關閉/打開中斷的指令CPSID I 和CPSIE I,而且在core_cm3.h中也提供這樣的開關中斷的函數__enable_irq()和__disable_irq(),需要的時候直接去調用就可以。 從bootloader到UsrApp的跳轉: 這里我們把引導cpu進入用戶代碼區的程序稱作bootloader,把用戶實際實現相應功能的程序稱作UsrApp,它們是一個完整的程序,下文提到的bootloader、UsrApp均指這些。 bootloader到UsrApp的跳轉需要熟知兩方面的知識:一個是中斷向量表的重映射,另一個是一段完整的程序的入口是如何定義的。 中斷向量表重映射: 在LPC1768中,位于地址0xE000_ED08處有一個向量表偏移寄存器VTOR,通過修改此寄存器可以設定向量表基址位于Code區或是RAM區以及向量表的基址偏移域,以此達到中斷向量表重映射的目的。比如我們的UsrApp起始地址為0x8000;為使UsrApp在發生中斷行為時不會產生錯誤或異常,我們可以通過以下代碼段將中斷向量表重映射到地址0x8000處Code區。 1 | SCB->VTOR = USR_APP_START_ADDR &0x1FFFFF80; |
SCB->VTOR由core_cm3.c提供,對應向量表偏移寄存器地址0xE000_ED08。USR_APP_START_ADDR為用戶代碼區的起始地址,和數值0x1FFFFF80按位與是保證寄存器的保留位為0和向量表基址位于Code區。此寄存器的詳細說明請參考《cortex-M3技術參考手冊》第八章第二節的NVIC寄存器描述或《LPC17XX User manual》英文版34.4.3.5章節。,此處不再貼出。對于用戶程序,在bootloader中的向量表偏移設置并不起作用,需要在用戶程序中重新設置向量表偏移寄存器。原因是CM3器件進入main()函數即要求調用SystemInit(void)進行系統初始化,系統初始化的時候將向量表偏移寄存器清零了,所以需要在調用SystemInit()之后重新設置向量表偏移寄存器。有網文稱對于應用了OS的用戶程序需要這樣做,其實對于開啟了中斷的的用戶程序都需要這樣,你的簡單的IAP測試程序之所以在沒有這樣做的情況下通過了測試,是因為你的用戶程序測試代碼中并沒有用到中斷。 一個完整鏡像的程序入口: 對于在flash中存儲的一個完整的程序代碼,其起始部分應該為向量表,向量表的內容格式固定如下表(參考《cortex-M3權威指南》7.3節) 上電后的向量表: 由表可知,對于起始存儲地址為0的一段完整程序,其首地址處存放的是MSP的初始值,偏移4字節的地址處存放的是PC指針的初始值,我們要運行這段完整的程序,只需將這段完整程序的SP、PC初始值賦給SP和PC寄存器即可,具體實現的函數如下: 1 2 3 4 5 | __asm void boot_jump(uint32 address) { LDR SP, [R0] LDR PC ,[R0, #4] } |
對于此函數的解釋:__asm是MDK的編譯器提供的嵌入匯編的指令(RealView C編譯器3.0以上版本提供)。函數體中兩行匯編代碼的功能分別為: LDR SP, [R0]:把R0中的值作為地址,將此地址中的值賦給SP LDR PC ,[R0, #4]:把R0中的值加4作為地址,將此地址中的值賦給SP 這里涉及到一個問題,r0中的值是什么?我們根據ATPCS(ARM-THUMBprocedure call standard)可知,對于參數少于等于4的函數,參數是通過R0~R3傳遞的,第一個參數放在R0中,依次類推。所以這里的R0存放的正式UsrApp的起始地址,回過頭再看前面的兩行匯編代碼,它們做的事正是將UsrApp的SP、PC初始值賦給相應寄存器,達到開始運行UsrApp的目的。 UsrApp的燒寫: 因為在片內flash的起始地址處燒寫的是我們的iap處理程序,用戶程序的起始地址不是0x0000_0000,在通過keil用jlink下載程序的時候,還需做一個設置。在Option for Target→Debug→Settings→Flash Download中,設置下載程序時的起始地址為用戶程序的起始地址。如本例中用戶程序的起始地址是0x0000_8000,我們設置下載程序的起始地址為0x0000_8000,如下圖。如果不這么做的話,通過jlink下載程序的時候會從地址0x0000_0000開始擦除。 遺留的問題: 疑問1:《lpc1768 user manual》34.4.3.5章節指出中斷向量表偏移寄存器的向量表基址偏移域為[28:8]位,為什么將偏移量實際賦值給此寄存器的時候沒有做’<<8’的處理而是直接賦值過來?PS:《Cortex-M3技術參考手冊》第8章的表8-15指出中斷向量偏移寄存器的向量表基址偏移域為[28:7] 疑問2:手冊中指出使用iap的時候RAM頂部32字節空出,這該怎么理解?iap占用ram頂端32字節,即使我不去刻意留出也不影響iap使用這32字節的空間,我能想到的唯一解釋是編譯器可能會把程序中的全局變量放到ram頂端32字節區域進而調用iap函數會引起全局變量被修改,是這樣么? 參考過的文獻: 《arm匯編指令集》--------網文 《arm啟動代碼的探究-鄭遠超》 《arm體系結構與編程》------杜春雷(PS:重點第11章) 《map文件認識初步》-------網文 《匯編器指南》------RealviewMDK 《鏈接器指南》------RealviewMDK 《中斷向量表重映射與復制》------網文 《cortex-m3技術參考手冊》
之前說了stm32的iap編程,今天天氣真好,順手就來說說lpc1788的iap編程(沒看前面的請查看stm筆記下的內容) 首先是flash的算法,lpc1768并沒有寄存器來讓我們操作flash,他內置了iap的flash算法,在技術手冊的525頁有如下說明 其支持的iap命令有這些 這樣我們就能夠做出相關的flash讀寫借口呢(具體請查看lpc1768的技術手冊) unsigned param_table[5];//傳遞參數列表 unsigned result_table[5];//返回結果列表 //調用iap命令 void iap_entry(unsigned param_tab[],unsigned result_tab[]) { void (*iap)(unsigned [],unsigned []); iap = (void (*)(unsigned [],unsigned []))IAP_ADDRESS; iap(param_tab,result_tab); } 通過這種手段就能夠調用iap命令,我們演示性的看一個命令 //扇區準備好指令 //起始扇區號 結束扇區號 系統時鐘 void prepare_sector(unsigned start_sector,unsigned end_sector,unsigned cclk) { param_table[0] = PREPARE_SECTOR_FOR_WRITE; param_table[1] = start_sector; param_table[2] = end_sector; param_table[3] = cclk; iap_entry(param_table,result_table); } 該指令在寫flash和擦除flash之前必須調用 具體的完整flash代碼請查看工程文件,會在文章末尾上傳 然后依舊是五個指令 "iap_down" "iap_jump_app" "iap_over" "iap_set_flag" "iap_clear_flag" 功能和之前的stm32差不多,但是下載算法變化了,因為stm32支持的寫入是每次寫入一個十六位數據,而lpc1768每次寫入8位數據,而且每次寫入數據的量為128/256/512/1024/4096,正好沒有我們之前所用的2048,所以算法修改成如下的樣子
- u8 iapbuf[1024] = {0}; //用于緩存數據的數組
- u16 receiveDataCur = 0; //當前iapbuffer中已經填充的數據長度,一次填充滿了之后寫入flash并清零
- u32 addrCur = FLASH_APP1_ADDR; //當前系統寫入地址,每次寫入之后地址增加2048
-
- #define vu32 volatile unsigned int
-
- //開始下載
- void iap_down_s(void)
- {
- u16 i = 0;
- u16 receiveCount;
- if(erase_user_flash())
- {
- printf("error\r\n");
- return;
- }
- printf("begin,wait data download\r\n");
- receiveMode = 1;//串口進入下載接收數據模式
- while(1)
- {
- //循環接收數據,每次必須要發128個數據下來,如果沒有128,說明這是最后一包數據
- //接收到一包數據之后,返回一個小數點,發送完成,系統編程完成之后返回一個iap_over
- if(serial_Buffer_Length & 0x8000)
- {
- receiveCount = (u8)(serial_Buffer_Length&0x00ff);
- if(receiveCount == 128)//滿足一包,填充并查看是否有了1024字節,有了寫入閃存
- {
- for(i = 0; i < receiveCount; i++)
- {
- iapbuf[receiveDataCur] = serial_Buffer[i];
- receiveDataCur++;//完成之后receiveDataCur++;
- }
- receiveExpectCount = 0;//清除期望接收模式
- serial_Buffer_Length = 0;//清除串口滿標志
- printf(".");//每次接受一次數據打一個點
- //此時需要檢測receiveDataCur的值,要是放滿了,就需要寫入
- if(receiveDataCur == 1024)
- {
- //寫入flash中
- if(write_flash(100000,addrCur,(unsigned*)iapbuf,1024))
- {
- receiveMode = 0;
- addrCur = FLASH_APP1_ADDR;
- receiveDataCur = 0;
- return;
- }
- addrCur += 1024;//地址+2048
- //寫完之后receiveDataCur要清零等待下一次傳輸
- receiveDataCur = 0;
- }
- else //有可能最后一包有128個數據但是最終沒有2048個數據,此時擴展一個指令用于完成最后一個的寫入
- {
-
- }
- //還沒放滿,等待下一次數據過來
- }
- else //不滿足一包,說明數據傳送這是最后一包,寫入閃存
- {
- //沒有一包也要傳送到緩存中
- for(i = 0; i < receiveCount; i++)
- {
- iapbuf[receiveDataCur] = serial_Buffer[i];
- receiveDataCur++;//完成之后receiveDataCur++;
- }
- receiveExpectCount = 0;//清除期望接收模式
- serial_Buffer_Length = 0;//清除串口滿標志
- printf(".");//每次接受一次數據打一個點
- //要將沒接收滿的數據變成0xff
- for(i= receiveDataCur; i < 1024; i++)
- {
- iapbuf[i] = 0xff;
- }
- //之后就要將這數據寫入到閃存中
- if(write_flash(100000,addrCur,(unsigned*)iapbuf,1024))
- {
- receiveMode = 0;
- addrCur = FLASH_APP1_ADDR;
- receiveDataCur = 0;
- return;
- }
- //printf("\r\nwrite addr %x,length %d\r\n",addrCur,receiveDataCur);
- //寫完之后要把地址恢復到原來的位置
- addrCur = FLASH_APP1_ADDR;
- receiveDataCur = 0;
- //寫完之后要退出下載循環并告訴上位機,已經下載完了
- printf("download over\r\n");
- //同時,也要退出下載循環模式
- receiveMode = 0;
- return;
- }
復制代碼
因為lpc1768比較獨特的扇區分區,如下 我們要修改地址的定義,現在app代碼不能存放在0x08002000位置了,而是存儲在0x00003000的位置,我們將012三個扇區當做iap代碼的存放區域,并將2號扇區的最后一個位定義成了app固化標志存在的位置,寫入固化標志的函數如下 unsigned char iapConfigBuffer[4096];//一個扇區4K - //失敗返回1 成功返回0
- u8 Iap_Write_Config_Value(u8 value)
- {
- u32 i = 0;
- u8 *p;
- p = (u8*)SECTOR_2_START;
- //首先要將第三扇區的數據全部讀取到ram里面
- for(i = 0; i < 4096; i++)
- {
- iapConfigBuffer[i] = *p;
- p++;
- }
- //然后檢查最后一個數據和我們要設置的數據是否相等
- if(iapConfigBuffer[4095] == value)//相等,不用設置了
- {
- return 0;
- }
- else
- {
- //不等,先擦除第2扇區
- prepare_sector(2,2,100000);
- erase_sector(2,2,100000);
- if(result_table[0] != CMD_SUCCESS)
- {
- return 1;//擦除失敗
- }
- //將數組最后一個元素設置為指定值
- iapConfigBuffer[4095] = value;
- prepare_sector(2,2,100000);//根據地址找出應當準備哪一個扇區
- write_data(100000,SECTOR_2_START,(unsigned*)iapConfigBuffer,4096);
- if(result_table[0] != CMD_SUCCESS)
- {
- return 1;
- }
- return 0;
- }
- }
復制代碼
擦除一個扇區的時候必須將扇區內容保存下來,所以必須定義一個能存放4096數據的數組,寫入的時候先讀取,在擦除,防止數據丟失 Flash存放的地址修改成這樣 #define APP_CONFIG_ADDR 0X00002FFF //配置地址 #define APP_CONFIG_SET_VALUE 0X55 //設置值 #define APP_CONFIG_CLEAR_VALUE 0XFF //清零值 #define FLASH_APP1_ADDR 0x00003000 //第一個應用程序起始地址(存放在FLASH) //保留的空間為IAP使用 相應的配置就要改成如下 當然,在main函數中還是之前一樣的流程 而對于app來說,改動的位置是這些 還有在系統初始化函數SystemInit中的這個 修改成 #define VECT_TAB_OFFSET 0x3000 這樣基本就能完成了,突然發現,這樣app是編譯不過去的,原因在于startup_LPC17XX.s文件中的110行有這么一段 該段匯編代碼在flash的0x000002fc位置存放了一個0xffffffff,但是app程序從0x00003000啟動,是不能操作0x000002fc處的flash的,我們來看看這個位置存放的是什么 可以看到,這一段是進行flash讀保護的,這一段我們可以注釋掉了,因為iap部分的啟動代碼我們沒有改啊,iap代碼中已經設置了crp,那iap引導的app只要不去修改,crp就是我們在iap中定義了,放心大膽的注釋掉吧. 現在我們比一比相對于stm32的iap,lpc1788的iap有啥變化 - flash擦寫算法變了
- 程序的存儲空間變了
- 中斷向量表的位置變了
- Crp是stm32沒有的,算是一個新東西
- 因為flash的擦寫算法變了,所以我們底層接收數據處理數據的方式變了
綜上,協議沒變,我們依然可以按照之前的協議使用,那么,之前的上位機還算可以使用的 對了,該上位機需要下載bin文件,需要在keil中將axf轉換成bin文件,設置如下 Target的user界面 注意啊,這是我的工程分布,我在工程文件所在目錄里面放了一個output目錄,axf生成到了output目錄中,如果你沒有output目錄,那么將output刪除,設置生成axf的位置和工程文件的位置位于同一目錄就可以了
完整的Word格式文檔51黑下載地址:
|