1. 程式人生 > >嘗試IAR下建立stm32新工程及bootloader

嘗試IAR下建立stm32新工程及bootloader

之前在iar下開發都是在官方例程或網路中下載的例程,開發時IAR直接跳入main中執行c程式碼,最近想建立個新的stm32工程來寫一些彙編檔案瞭解下CM3彙編指令,於是痛苦摸索了很多天。

起初建立了IAR新工程,使用的stm32f103x,加入了官方提供的iar工程檔案:startup.s,原本想將keil下的startup檔案直接copy過來,然而現實是keil和iar使用的一些彙編偽指令差別很大,一個百行的startup.s就有一萬個錯誤,直接爆炸。不過官方分別提供了keil iar gcc對應的工程及啟動檔案,可以按需求使用。

startup.s檔案中最重要的自然是__vector_table,一個異常向量表,表中記錄了所有異常的入口地址

除第一個外,其它都是入口地址。CM3將第一個視為晶片復位後MSP的值,這裡我一直有個猜測但還沒有實驗,CM3的MSP不需要手動配置,而是復位後預設去flash的0x80000000地址去取 (我的stm32f103 flash首地址從0x80000000開始,似乎也會被對映位0x0,兩個地址都可用,但相對的都是flash的0地址。也就是說工程生成的bin檔案前四個位元組就是MSP的復位值),這樣的話是不是CM3的bootloader不一定非要使用匯編來寫,直接跑c也是可以的?如果說彙編能夠使用16位指令來節省空間,那麼c在編譯時不會生成16位指令嗎?

加入啟動檔案還要根據晶片選擇官方提供的.ICF檔案,ICF檔案主要用來告訴編譯器晶片的RAM ROM地址範圍以及程式中的不同段在儲存器中的存放位置。

IAR中有一些段的內部關鍵字如CSTACK,HEAP等

使用的ICF中將向量表放在flash的首地址

place at address mem:0x80000000 { readonly section .intvec };

startup.s中__vector_table自然是被放在.intvec段:

SECTION .intvec:CODE:NOROOT(2)

在IAR生成的map檔案中可以清晰的看到

至於A1 P1 字樣,IAR解釋為A是絕對位置,P則是相對位置

這兩個檔案新增完成後執行編譯發現報錯:__iar_program_start沒有定義,

在IAR option中看到了他的身影:

IAR執行連線時預設去找__iar_program_start入口,最開始第一個鉤我沒有勾上,導致無法連線入IAR提供的.S檔案,__iar_program_start自然不會被找到。這個入口也可以選擇被重新定義完全由開發者重新命名重寫。

IAR安裝目錄下提供了很多種類晶片的.S檔案,其中一些是啟動檔案和初始化檔案,CM3的__iar_program_start被放在cstartup_M.s中。

起初我嘗試了重寫__iar_program_start入口,這個模組中主要去初始化全域性段以及對一些未賦值的全域性變數段清零就可以了,後來發現IAR  .map檔案中有

Region$$Table$$Base     0x00000000         --   Gb  - Linker created -
Region$$Table$$Limit    0x00000000         --   Gb  - Linker created -

字樣,查閱了一些資料有說這兩個符號標誌了一塊記憶體,裡面存放了多個段的資訊。實際上到最後我也沒摸索出該怎麼使用它們,主要是全域性變數所在的段如何與ICF檔案對應起來成了問題。如果pass這一過程那麼C程式碼中則不允許有全域性變數,彙編中不能使用DCB之類的開闢記憶體,有的話IAR則會報出__iar_data_init3錯誤,一直搞不懂全域性變數為什麼和__iar_data_init3會有關。

 這個__iar_data_init3模組在官方提供的__iar_program_start裡面被呼叫過,由於沒有找到__iar_data_init3原始碼,只看到了__iar_data_init函式,所以一直猜測__iar_data_init3就是__iar_data_init。

至於__iar_data_init程式碼是c寫的:

裡面確實和RegionTable有關聯,至於怎麼實現的,將全域性變數從ROM搬到RAM 我在原始碼中實在看不出來。

最後繞不過全域性段初始化這個檻,還是勾上使用IAR提供的.s選項,使用iar的__iar_program_start,程式可以正常跳轉執行。。。。