S32k144 簡易 Bootloader

轉自:https://www.jianshu.com/p/1461fc7486b7

內容目錄

一、理論
1、 復位流程
2、 內存分佈
二、 實戰 — boot
1、 工具:keil JLINK
2、 新建工程
3、 修改腳本
4、 修改代碼
5、 編譯下載
6、現象
三、 實戰 — app
1、 新建工程
2、 修改腳本
3、 修改代碼
4、 編譯下載
5、 在線仿真
注意:
問題:
總結
參考文獻:

一、理論

1、 復位流程

在離開復位狀態後,Cortex-M 做的第一件事就是讀取下列兩個 32 位整數的值:
1、從地址 0x0000,0000 處取出 MSP 的初始值。</li>
2、從地址 0x0000,0004 處取出 PC 的初始值——這個值是復位向量,LSB 必須是1,然後從這個值所對應的地址處取指。

圖 1.1 復位序列.jpg

在 0 地址處提供 MSP 的初始值,然後緊跟着就是向量表。向量表中的數值是 32位的地址,而不是跳轉指令。向量表的第一個條目指向復位後應執行的第一條指令。

圖 1.2 初始化MSP及PC初始化一個範例.jpg

因爲 Cortex-M 使用的是向下生長的滿棧,所以 MSP 的初始值必須是堆棧內存的末地址加1。舉例來說,如果你的堆棧區域在 0x20007C00-0x20007FFF 之間,那麼 MSP 的初始值就必須是 0x20008000。
向量表跟隨在 MSP 的初始值之後——也就是第 2 個表目。要注意因爲 cortex-m 是在Thumb 態下執行,所以向量表中的每個數值都必須把 LSB 置1(也就是奇數)。正是因爲這個原因,圖 1.2 中使用 0x101 來表達地址 0x100。當 0x100 處的指令得到執行後,就正式開始了程序的執行。在此之前初始化 MSP 是必需的,因爲可能第1條指令還沒來得及執行,就發生了 NMI 或是其它 fault。MSP 初始化好後就已經爲它們的服務例程準備好了堆棧。

2、 內存分佈

圖 1.3 flash 內存分配圖.jpg

需要修改工程中內存分配的腳本實現以上效果,這裏是使用兩個工程設計,一個爲 bootloader 工程,一個爲 app 工程。

二、 實戰 — boot

1、 工具:keil JLINK

使用 S32DS 開發也可以,但是 S32DS 使用 jlink 下載程序的時候,芯片容易鎖死,而且飛思卡爾的芯片鎖死之後,解鎖都比較麻煩,所以暫時選擇 keil 開發。

2、 新建工程

使用 keil 建立 s32k144 工程並不難,只是 s32k144 與其他的芯片稍微有點不一樣,除了有一個彙編文件的啓動文件之外,還有幾個源文件,源文件的作用主要是從 flash 複製代碼到 ram 中,初始化 bss 段,關閉看門狗,配置時鐘等。

圖 2.1 新建工程.jpg

圖 2.2 保存工程.jpg

圖 2.3 選擇芯片類型.jpg

圖 2.4 選擇固件以及啓動代碼.jpg

上圖紅色部分務必勾選。

圖 2.5 工程目錄結構.jpg

紅色框部分即使內存分配腳本,這是待會兒需要修改的。工程建立好了之後,還需要進行一些配置。

圖 2.6 內存配置.jpg

在搞 STM32 的時候,有時候修改的就是這裏,這裏可以修改內存分配,但是我們這次使用的是用戶腳本,不是默認內存配置,所以這裏不需要修改。當然還有生成 hex 文件、調試工具的選擇、輸出目錄等配置也需要進行,這裏就不一一列舉了,

圖 2.7 用戶腳本選擇.jpg

紅色部分不要勾選,紫色部分需要手動找到這個腳本,我們把代碼下載到 flash 就選擇 flash 腳本,下載到 ram 就選擇 ram 腳本。

圖 2.8 下載配置.jpg

紅色部分最好不勾選,因爲如果直接使用在 keil 下載的話,這個選項在下載 app 代碼的時候,會全部擦除 flash,這時候 boot 會遭殃,會導致起不來,配置基本配置好了,接下來就是修改腳本了。

3、 修改腳本

Boot 的腳本基本不用怎麼修改,就是修改一下 Boot 結束地址,這裏開闢給 boot 的大小是 0x4000,相當於 16K 的大小。

 

#if (defined(__ram_vector_table__))
#define __ram_vector_table_size__    0x00000400
#else
#define __ram_vector_table_size__    0x00000000
#endif

#define m_interrupts_start             0x00000000
#define m_interrupts_size              0x00000400

#define m_flash_config_start           0x00000400
#define m_flash_config_size            0x00000010

#define m_text_start                   0x00000410
//#define m_text_size                    0x0007FBF0
#define m_text_size                    0x00002000

#define m_interrupts_ram_start         0x1FFF8000
#define m_interrupts_ram_size          __ram_vector_table_size__
#define m_data_start       (m_interrupts_ram_start+m_interrupts_ram_size)
#define m_data_size                  (0x00008000 - m_interrupts_ram_size)
#define m_data_2_start                 0x20000000
#define m_data_2_size                  0x00007000

4、 修改代碼

代碼的修改主要是集中在,跳轉函數,需要定義一個函數指針類型,還要注意 Cortex-m 復位跳轉序列。

 

#include "S32K144.h" /* include peripheral declarations S32K144 */
#include "clocks_and_modes.h"
#include "gpio_led.h"



#define APP_ADDR  0x00004000

/******************************************************************************
*Local variables
******************************************************************************/
typedef void (*bootloader_fun)(void);
bootloader_fun jump2app;


void delay(volatile int cycles)
{
    /* Delay function - do nothing for a number of cycles */
    while(cycles--);
}


int main(void)
{
    
      SOSC_init_8MHz();       /* Initialize system oscilator for 8 MHz xtal */
      SPLL_init_160MHz();     /* Initialize SPLL to 160 MHz with 8 MHz SOSC */
      NormalRUNmode_80MHz();  /* Init clocks: 80 MHz sysclk & core, 40 MHz bus, 20 MHz flash */
    
      LED_PORT_init();
    
    for(;;){

        for(int i = 0;i < 5;i++){
        led_triggle(2,1);              /* turn on red LED */
        led_triggle(1,0);              /* turn on green LED */
        led_triggle(0,0);              /* turn on blue LED */       

            delay(720000);
            delay(720000);
        
        led_triggle(2,0);              /* turn on red LED */
        led_triggle(1,0);              /* turn on green LED */
        led_triggle(0,0);              /* turn on blue LED */   
            delay(720000);
            delay(720000);
        }
        
        
        jump2app = (bootloader_fun)*(uint32_t*)(APP_ADDR + 4);
        jump2app();
            
    }
    
    
    return 0;
}

重點應該就是這句話:
jump2app = (bootloader_fun)(uint32_t)(APP_ADDR + 4);
APP 地址加上 4 ,就是因爲 CORTEX-M 復位序列的 PC 指針位置的偏移量就是偏移 4,(uint32_t)(APP_ADDR + 4) 進行強制類型轉換,(bootloader_fun)(uint32_t*)(APP_ADDR+4) 取址,相當於取 0x4004 地址的值,放到 PC 指針,可能需要主義的還有一個就是 C 語言的語法,C 語言裏面,函數名稱就是函數的入口地址,也就是說函數名稱其實也是一個指針,所以後面一句:jump2app();就是相當於執行一個函數。這樣就可以跳轉了。

5、 編譯下載

編譯就沒啥問題,下載就有兩種方式,一種是直接在keil 上下載,這個很簡單了,例外一個就是單獨打開 segger 下載,這時候需要配置一下這個軟件:

圖 2.9 segger 配置.jpg

圖 2.10 選擇芯片.jpg

然後把編譯生成的 hex 文件,直接拖到頁面裏面就可以了,按 F5 就可以下載了,boot的下載沒有什麼特別的要求,兩個都可以下載。

圖 2.11 編譯完成.jpg

6、現象

下載之後,可以看到小燈閃了 5 下就不閃了,說明執行到了後面的跳轉程序。

三、 實戰 — app

1、 新建工程

建立工程和 boot 一樣的過程,這裏就不再贅述了。

圖 3.1 app 目錄結構.jpg

2、 修改腳本

腳本位置:$(工程目錄)144_app\RTE\Device\S32K144UAxxxLLx 下

 

#if (defined(__ram_vector_table__))
#define __ram_vector_table_size__    0x00000400
#else
#define __ram_vector_table_size__    0x00000000
#endif

//#define m_interrupts_start             0x00000000
#define m_interrupts_start             0x00004000
#define m_interrupts_size              0x00000400

//#define m_flash_config_start           0x00000400
#define m_flash_config_start           0x00004400
#define m_flash_config_size            0x00000010

//#define m_text_start                   0x00000410
#define m_text_start                   0x00004410
//#define m_text_size                    0x0007FBF0
#define m_text_size                    0x0002FBF0

#define m_interrupts_ram_start         0x1FFF8000
#define m_interrupts_ram_size          __ram_vector_table_size__

#define m_data_start            (m_interrupts_ram_start + m_interrupts_ram_size)
#define m_data_size                    (0x00008000 - m_interrupts_ram_size)

#define m_data_2_start                 0x20000000
#define m_data_2_size                  0x00007000

App 腳本的修改稍微多一點,每個對應的偏移地址都需要改,向量表的地址,text 段的地址等。

3、 修改代碼

代碼基本就是正常的代碼,不用做任何的操作就可以了。

4、 編譯下載

編譯和 boot 一樣,下載的話,如果沒勾選 erase full chip ,可以直接下載,也可以使用 segger 下載。

5、 在線仿真

如果 app 的代碼只是下載,那每次調試都會比較麻煩,都得編譯成 hex 文件再下載才能驗證,因爲腳本修改了向量表的地址,直接在線調試是不行的,這樣就很不方便開發了,網路上有網友通過修改一個腳本,讓 keil 識別到我們已經修改過的向量表的地址,在工程目錄新建 flashoffset.ini 文件,內容如下:

圖 3.2 app 在線調試腳本.jpg

在 keil 配置裏面導入這個文件

圖 3.3 導入在線調試腳本.jpg

這樣就可以就行在線調試了,就和正常開發一樣方便了。

注意:

每個工程編譯完了之後,最好是查看 .map 文件,看一下內存分配是否都在劃定的內存裏面

圖 3.4 app 工程的 .map 文件.jpg

也算是一種調試信息手段吧。

問題:

這個 bootloader 整個流程雖然可以走通,但是還有問題,如果 app 工程開啓了中斷,app 的程序會跑飛。原因是什麼呢?這個就是第一節說的 cortex-m 復位序列。

1、 boot 中斷未關;
2、接收升級文件驅動未提供;
3、Flash 驅動未提供;
4、App 程序重新定位向量表的基地址未修改。

總結

雖然上述通過 keil 軟件,以及它的分散腳本實現了簡單的 bootloader 和 app 在線調試功能,這個只是一個簡易的 bootloader,還有很多功能未添加,也有很多地方還需要完善,目前這個只是能跑一個簡單的流程,只是幫助理解一下。

參考文獻:

《Cortex-M3 權威指南》

代碼下載:
https://pan.baidu.com/s/1fF3N_qpvMNtZOFGcB-HuIQ 密碼: 3ouv
https://pan.baidu.com/s/1TsZtd38C8hcLsVjJ113G5w 密碼:3tqg



作者:Depthkernelcore
鏈接:https://www.jianshu.com/p/1461fc7486b7
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章