关于STM32 IAP
轉眼間天亮了......
然后就想起了一個朋友QQ的個性簽名:年輕人總是要為一些自己認為有意義的事情而廢寢忘食,通宵達旦,直至白發方休........
對了這篇文章一定會介紹的很詳細,請細嚼慢咽.......嗯,我是這樣認為的,,,,,,
?
上面是昨天寫的,應該說是今天寫的,,今天發現發現博客又不能復制粘貼圖片了!!!!然后就睡了一覺,,麻煩。。。。是不是因為我寫的博客有太多的圖片而把我屏蔽了。能讓人一目了然的就是圖片。。。。
?
說一下自己是如何做的,,,
?
先說一下實現的功能
IAP程序的功能
再看自己的用戶程序--用戶程序自己也做了些設置
?
?
?
對了關于我為什么拷貝到Flash里面------自己用的單片機的RAM不夠用,存不了用戶程序,所以自己就定義了一個小點的數組(環形隊列),串口一邊接收,一邊往Flash里面寫,環形隊列可是幫了大忙了,,,,
?
把IAP升級程序下進去,以后就直接通過串口發送自己的用戶程序就行了...什么都不需要做了,先說一下操作過程吧!最后有自己的源碼
IAP程序軟件不需要任何配置
?
波特率太快的話,數據來不及寫入Flash,環形隊列容易溢出,,太慢的話,程序發送的慢。。。
用戶程序軟件需要一些配置
8006000告訴編譯器我的用戶程序打算在這里開始,你幫我設置一下吧,默認是在8000000開始的
0x1A000,就是告訴編譯器我的程序空間有這么大。
我的用戶程序里面也是設置的6000,這個一定要和程序設置的一樣哈
關于這個我后面會說為什么這樣設置。。。當然也可以百度一下。
其實我的本來是
20000換成十進制就是131072個字節? 除以1024 等于128
由于我先把IAP程序下進去了,IAP程序也需要空間來運行,,,我就給了他6000 換成十進制就是24576? 除以1024就是24K
我的總共是128K然后去掉IAP暫用的24K就是? 128-24 = 104K? = 106496個字節?? 換成16進制就是 1A000
所以我上面寫了1A000
對了如果您的板子是大容量的如果您非常明白就自己隨意修改把,別忘了修改程序里的那個,,,
如果不是很明白按照上面修改就行,后面會讓您明白
這個呢就是讓Keil軟件幫忙生成bin文件
F:\Keil4&&MDK4.70A\ARM\ARMCC\bin\fromelf.exe?? --bin -o? .\Progect\Progect.bin? ..\Progect\output\Progect.axf
F:\Keil4&&MDK4.70A\ARM\ARMCC\bin\fromelf.exe?? --bin -o?? 這個是執行的命令,就是生成bin文件,根據自己的安裝路徑找哈
.\Progect\Progect.bin?就是告訴他把生成的bin文件放在哪個地方
..\Progect\output\Progect.axf 這個就是自己工程編譯的時候產生的.axf文件,根據自己的找到
./當前目錄
../上一級目錄
../../上上一級目錄
關于Bin文件和Hex文件
?http://blog.sina.com.cn/s/blog_6b94d5680100lo2h.html
這是我的用戶程序的Hex與Bin
咱們自己設置好寫到哪里了,所以前頭的就不需要了,后面的校驗也不需要了,,不過呢應該向他那樣加上校驗,數據對了再寫進去!!!!
好生成了bin文件
然后
?
?
?
?
假設修改了程序了,再升級
您再升級就再升級把!!
再升級
?
不要老是升級哈!!!玩壞了Flash可就不好玩了
?
?
自己用的F103RBT6單片機的RAM只有?5000 也就是20480個字節,,但是自己的程序已經超過了這個字節數
所以自己就不能先定義一個很大的數組然后然后把程序先存在里面了,列如很多都是:
u8 USART_RX_BUF[USART_REC_LEN]? __attribute__ ((at(0X20001000)));//接收緩沖,最大USART_REC_LEN個字節,起始地址為0X20001000.//把數據固定的存在以0X20001000為起始地址的RAM里面
自己呢就是用的環形隊列一邊接收,一邊寫入,,,關于環形隊列可以看我的環形隊列的文章,,,
http://www.cnblogs.com/yangfengwu/p/6822984.html
就再說一下自己的程序的一些地方
串口接收的
?
void USART1_IRQHandler(void) //串口1中斷服務程序 {u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾) {Res =USART_ReceiveData(USART1); //讀取接收到的數據PutData(&Res,1); //把數據存入隊列Usart1RecCnt ++; //數據個數 } }?
用的系統定時器中斷來檢測的串口空閑,判斷接沒接收到一條完整的數據--方法呢是看到人家的一種方法,感覺比自己以前的好,所以直接拿過來用了
關于單片機空閑中斷可以看一下自己以前的
http://www.cnblogs.com/yangfengwu/p/6746403.html
?
/*系統定時器中斷*/ void SysTick_Handler(void) { SysTickCnt ++;SysTickCnt1++;SysTickCnt2++;if(SysTickCnt1>=10)//每隔10毫秒檢測一次{SysTickCnt1 = 0;if(Usart1RecCnt)//如果接收到數據了{if(IdleCnt == Usart1RecCnt)//10ms時間數據沒了變化{Usart1RecCntCopy = Usart1RecCnt;//拷貝數據個數Usart1RecCnt = 0;//清零數據個數IdleCnt = 0;//清零Usart1Flage = 1;//接收到一條數據 // rbDelete(&pRb);測試的時候銷毀 // rbCreate(&pRb,ReceBuff,USART_REC_LEN);//創建接收環形隊列 }else{IdleCnt = Usart1RecCnt;}}} }我的IAP的接收的數據往Flash里面寫和用戶程序的往Flash里面寫有一點不同,其實用戶程序的往Flash里面寫的程序是后期的改進...
先看我的IAP的
?
if(rbCanRead(&pRb)>1)//如果環形隊列里面的數據個數大于1{rbRead(&pRb, &ReadDat, 2);//讀取兩個數據ReadDat16 = (u16)ReadDat[1]<<8;ReadDat16 = ReadDat16|ReadDat[0];STMFLASH_Write(addr2,&ReadDat16,1); addr2+=2;}if(rbCanRead(&pRb)>1)
因為一次性要往Flash里面寫16位數據,所以才會判斷數據個數大于一個的時候再往里面寫.
雖然現在程序沒有問題,但是我還在想如果程序的個數是奇數個就完啦!但是好像程序的個數總是偶數個....其實可以在判斷接收完成的里面
做一下判斷,如果數據還殘留一個,那就寫進去....
好,那就看一下判斷接收完程序
?
if(Usart1Flage == 1)//數據接收完成 {addr2 = FLASH_APP2_ADDR;//存儲數據的地址Usart1Flage =0;//清零if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//判斷是否為0X08XXXXXX. { printf("準備執行APP代碼!!\r\n");UserDataAddr = FLASH_DATA_ADDR;//存儲其余的數據地址ReadDat16 = 0x55;//寫入標志告訴IAP程序有可更新的用戶程序STMFLASH_Write(UserDataAddr,&ReadDat16,1);UserDataAddr+=2;printf("寫入0x55標志!!\r\n");ReadDat16 = (u16)((Usart1RecCntCopy>>16)&0xffff);//存儲接收到多少數據高位STMFLASH_Write(UserDataAddr,&ReadDat16,1);UserDataAddr+=2;ReadDat16 = (u16)(Usart1RecCntCopy&0xffff);//存儲接收到多少數據低位STMFLASH_Write(UserDataAddr,&ReadDat16,1);UserDataAddr+=2;Usart1RecCntCopy = 0;printf("開始復位重啟!!\r\n");Reset_MCU();}else {printf("非FLASH應用程序,無法執行!\r\n");}// printf("Cnt=%d\r\n",Usart1RecCntCopy); // for(i=0;i<Usart1RecCntCopy/2;i++) // { // STMFLASH_Read(addr1,&ReadDat16,1); // addr1+=2;//偏移2048 16=2*8.所以要乘以2. // if((ReadDat16&0x00ff)<=15) // { // printf("0%x ",ReadDat16&0x00ff); // } // else // { // printf("%x ",ReadDat16&0x00ff); // } // // if((ReadDat16>>8)<=15) // { // printf("0%x ",ReadDat16>>8); // } // else // { // printf("%x ",ReadDat16>>8); // } // } // addr1 = FLASH_APP1_ADDR; // for(i=0;i<40;i++) // { // STMFLASH_Erase(addr1,1024);//擦除FLASH_APP1_ADDR地址以及以上40頁 // addr1 +=2048; // } // addr1 = FLASH_APP1_ADDR;}后邊屏蔽的是測試的時候,看一下寫入的數據,然后和源數據對比一下,看一下寫入的對不對
if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)
這句話
先問一個問題,怎么知道接收過來的是用戶程序呢????要是別的數據怎么辦???,,必須有一個判斷依據才行對吧!!
就必須找到用戶程序中永恒不變的變量....
然后呢,我是看別人的程序說,數據的第一個4個字節為棧頂地址,數據的第二個4字節為復位中斷向量的入口地址
FLASH_APP2_ADDR+4指針就移動到了IAP升級程序的E9或者說電壓電流采集程序的D5上
(*(vu32*)(FLASH_APP2_ADDR+4))然后強制型的轉成32位的,然后取出來,就是IAP升級程序的E9 20 00 08
或者說電壓電流采集程序的D5 7E 00 08
還有一件事就是STM32是小端模式,,,,所謂小端模式就是低位在低地址,高位在高地址
舉個例子
把60000存到STM32的Flash的,60000轉換成16進制是EA60? EA是高8位,60是低八位,,存到Flash里面就是60EA這樣存的
60存到了低地址,EA存到了高地址,,,,,當然有小端模式就有大端模式,,,大端模式就是低位在高地址,高位在低地址,電腦就是這樣...
說到這里就要說一下共用體
?
typedef union Resolver_I {long Data;char Data_Table[4]; }Resolver_iData;typedef union Resolver_f {float Data;char Data_Table[4]; }Resolver_fData;Resolver_iData Resolver_7758;? //解析7758數據
Resolver_fData Resolver_Usart; //解析串口數據
一個整形數據快速的轉換成16進制存到數組里面
Resolver_7758.Data = 60000;
那么Resolver_7758.Data_Table[0] = 0x60;
????? Resolver_7758.Data_Table[1] = 0xEA;
????? Resolver_7758.Data_Table[2] = 0x00;
????? Resolver_7758.Data_Table[3] = 0x00;
一個浮點型的數據轉換成16進制存到數組里面--其實也是按照IEEE754規約來計算的
Resolver_Usart.Data = 220.5;
那么Resolver_Usart.Data_Table[0] = 0x00;
????? Resolver_Usart.Data_Table[1] = 0x80;
????? Resolver_Usart.Data_Table[2] = 0x5C;
????? Resolver_Usart.Data_Table[3] = 0x43;
所以說上面的數據取出來就是08 00 20 E9然后&0xFF000000?肯定就等于 0x08000000啦
其實這樣還有一個原因是因為32的地址是從08000000開始的,復位中斷向量的地址的最高兩位肯定是08啦!!!!
然后還有個if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)?//檢查棧頂地址是否合法.
這個......難道棧頂地址的最高位就是20......以后等看到相關的資料再說吧
有人這樣介紹的--仔細看,細細品味....
http://blog.csdn.net/yx_l128125/article/details/12992773
?對了說一下中斷向量表
就從我的MSP430的文章中摘抄過來
原文地址
http://www.cnblogs.com/yangfengwu/p/6064129.html
?突然想起來一句話,知識是相通的....
32也有中斷向量表,就像上面的430的似的,
只不過呢!32的中斷函數的入口地址是可以改變的!!!(F0好像固定,但是看過一篇文章好像也能通過某種方式改改)
我們寫入IAP程序后單片機內部就有了一個中斷向量表,這個呢是其內部一開始的固定的,
如果跳轉到用戶程序,用戶程序肯定會有自己的中斷函數吧!如串口,,定時器,,等等,,,,如果不改變中斷向量表的話!!!產生的中斷
豈不是跑到了IAP那邊去了,IAP那邊有自己的中斷函數,,,亂了,徹底亂了,,,,,所以必須得讓中斷向量表改變改變,好讓自己產生的
中斷,執行自己的中斷函數......
那就加一句話,或者修改一個地方
再看我的用戶程序的一個地方,,感覺自己羅嗦了
?
if(AppFlage == 1)//接收到更新程序 {if(rbCanRead(&pRb)>1){rbRead(&pRb, &ReadDat, 2);//讀取兩個數據ReadDat16 = (u16)ReadDat[1]<<8;ReadDat16 = ReadDat16|ReadDat[0];STMFLASH_Write(addr2,&ReadDat16,1); addr2+=2;}}else if(AppFlage == 0){if(rbCanRead(&pRb)==8){rbRead(&pRb, &TestData, 8);//讀取數據if(TestData[3] == 0x20 && TestData[7] == 0x08)//判斷是否是更新程序 {AppFlage = 1;//要更新程序for(i=0;i<4;i++)//先寫入這八位數據 {ReadDat16 = (u16)TestData[(i<<1)+1]<<8;ReadDat16 = ReadDat16|TestData[i<<1];STMFLASH_Write(addr2,&ReadDat16,1); addr2+=2;}}}}畢竟是用戶程序,串口1可能要參與別的通信,,,所以自己加了一個判斷是否是要更新程序的數據,,,是的話才往Flash里面寫
自己的源碼
鏈接:http://pan.baidu.com/s/1bJtc78 密碼:nobu
這兩天發現了自己程序的Bug
1,如果用戶程序主函數加入延時,那么程序就來不及讀出然后寫到Flash里面,串口卻不停的往環形隊列里面寫,從而造成環形隊列溢出....
再者如果寫入的時候,設置的串口助手的波特率太快,,,,同樣也會造成環形隊列溢出(就是往環形隊列寫的太快了)....
自己把寫Flash的程序放在了定時器里面,50Us進入一次的定時器,看著網上說往Flash寫一個字節大約16Us,,,,加上其余的程序整體應該不會超過50Us
如果有溢出程序不在往環形隊列里面寫了
?
void USART1_IRQHandler(void) //串口1中斷服務程序 {u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾) {Res =USART_ReceiveData(USART1); //讀取接收到的數據if(Overflow==0){if(PutData(&Res,1) == -1){Overflow = 1;} }Usart1RecCnt ++; } }最后接收完如果判斷溢出過,直接復位重啟,復位重啟更方便直接...
?
if(Usart1Flage == 1)//串口1接收完成 {addr2 = FLASH_APP2_ADDR;Usart1Flage =0;if(Overflow==1)//如果中途溢出了 {printf("程序中途溢出,準備復位重啟!!\r\n");Reset_MCU();//復位重啟CPU}?
2,如果寫了一些后,突然因為某些原因停止了寫入,,,,,本想在程序中觀察末尾有什么固定的數據沒有,,,,或者自己最后加一些標志位
但是這個現在程序好像能判斷出來....但是自己一直沒有明白程序為什么可以判斷出來............應該判斷不出來的......
后來一想現在反正是自己去更新程序,真不行可以直接燒,,,,就先放一放,,,,
更改后的
鏈接:http://pan.baidu.com/s/1slnWFVJ 密碼:mts7
?
總結
以上是生活随笔為你收集整理的关于STM32 IAP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RIDE使用介绍
- 下一篇: Django框架 from django