<object id="k0taz"><form id="k0taz"></form></object>
<pre id="k0taz"></pre>
      1. <table id="k0taz"></table>
        <bdo id="k0taz"><center id="k0taz"></center></bdo>
        <table id="k0taz"><option id="k0taz"></option></table><track id="k0taz"><ruby id="k0taz"></ruby></track>
        專注電子技術學習與研究
        當前位置:單片機教程網 >> STM32 >> 瀏覽文章

        djyos與stm32學習心得

        作者:佚名   來源:轉自李夜雪幽夢空間   點擊數:  更新時間:2014年08月29日   【字體:

         

         
        看完了DJYOS以后想把它移植到自己手中的開發板中,開發板是原子的ALIENTEK,其實自己也想買一塊論
         
        壇里講到的板子,但是自己手上目前有一塊,就沒必要浪費MONEY了,這塊板子是用的STM32F103RBT6,
         
        FLASH:128K,SRAM:20k.沒有外部SRAM,所以像GUI可能玩不了,不過現在也是初期,將系統配置簡單點應
         
        該可以應付像點燈的工作,等燈點亮了,再考慮一下串口與PC通信,看看內存能不能使用shell,如果能
         
        的話就可以試一下外圍硬件了,當然也可以不使用GUI使用一下LCD?傊窃谶@么小的SRAM中多學一點
         
        東西,當都明白了再考慮下換板子,或者自己想辦法外擴一個SRAM和NANDFLASH.
         
        因為自己雖然接觸這方面很久了,但是一直就是課余愛好還沒有做多少事之前只用avr做過一些CAN的實
         
        驗做硬件也花了不少大洋,自學過ucos,也在MEGA128上面移植過,但也沒有深入的研究應用程序,最近
         
        發現了DJYOS,對它很是感興趣,也看了它配套的資料,熱情很高,所以現在想把熱情轉為實際行動,實
         
        際的提高一下自己,現在先自己寫下來將來在發出去,呵呵,不要讓別人感覺太菜了,好了言歸正傳,
         
        我們開始實際行動吧
         
         
        因為DJYOS作者已經在STM32F103上移植過了,所以我們可能不需要費很大的力氣,只是一些配置不同而
         
        已,所以自己就想邊看作者的的移植例程邊向自己的板子上面移植,那怎么開始研究作者的例程呢?本
         
        人想從單片機上電開始依次跟蹤它的動作,當然這就要需要從上電第一步動作開始,上電后產生上電復
         
        位,復位程序將從FLASH的0x00000000處得到棧頂地址然后從FLASH的0x00000004開始執行代碼(SRAM起
         
        始地址是0x2000 0000 主閃存存儲器地址為0x0800 0000 但啟動時會映射到0x0000 0000),從
         
        Debug.lds中我們可以發現定義段時有一行
        KEEP(* (.isr_vector .isr_vector.*))
        ./src/bsp/arch/core/exceptions.o (.text .text.* .rodata .rodata.*)
        這一句是將中斷向量表定義在FLASH起始位置,向量表在exceptions.s中定義,我們可以在exceptions.s
         
        中發現
        .section    .isr_vector, "ax", %progbits
        .align 3
        .global isr_vector
        isr_vector:
        .word msp_top  聽田園說定義在.lds中
        .word cpu_init
        .word nmi_handler
        .word hardfault_handler
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   exp_svc_handler           @ SVCall Handler
            .word   0                         @ Reserved
            .word   0                         @ Reserved
            .word   0                         @ PendSV Handler
            .word   exp_systick_handler       @ SysTick Handler
        就是這個表定義了當發生復位或中斷時程序應該跳轉到哪里,復位后CPU從msp_top得到棧頂地址然后從
         
        cpu_init函數開始執行,cpu_init屬于啟動函數負責CPU的初始化工作.可以在initcpuc.c中找到,我們
         
        可以看一下,這個函數做了什么:
        1、設置了棧頂、
        2、關閉了中斷(PRIMASK:這是個只有1 個位的寄存器。當它置1 時,就關掉所有可屏蔽的異常,只剩下NMI和硬fault 可以響應。它的缺省值是0,表示沒有關中斷。FAULTMASK:這是個只有1 個位的寄存器。當它置1 時,只有NMI 才能響應,所有其它的異常,包括中斷和fault,通通閉嘴。它的缺省值也是0,表示沒有關異常)、
        3、選擇主堆棧指針特權級線程模式
         
        (CONTROL[1] 堆棧指針選擇  0=選擇主堆棧指針MSP(復位后缺省值) 1=選擇進程堆棧指針PSP,在線程或基礎級(沒有在響應異常——譯注),可以使用PSP。   在handler 模式下,只允許使用MSP,所以此時不得往該位寫1。CONTROL[0] 0=特權級的線程模式,1=用戶級的線程模式,Handler 模式永遠都是特權級的。)、
        4、cortex-m3需要將堆棧雙字對齊、
        5、設置FLASH等待周期、開啟預取、
        6設置時鐘、
        7初始化SRAM,因為我的開發板沒有外擴ram flash器件所以我的此處不需要
        8、load_preload();再下一篇我們再去看這個函數做了什么
         
        load_preload();這個函數,今天我們分析一下它做了哪些工作,這個函數作用是預加載
         
        系統,我們可以在load/si/pre_loader.c 中找到。這里我們復制過來便于觀察。
        void pre_start(void);
         
        extern struct copy_table preload_copy_table;
         
        //----預加載程序---------------------------------------------------------------
        //功能:加載主加載器、中斷管理模塊,緊急代碼
        //參數: 無。
        //返回: 無。
        //----------------------------------------------------------------------------
        //備注: 本函數移植敏感,與開發系統有關,也與目標硬件配置有關
        void load_preload(void)
        {
            void (*volatile pl_1st)(void) = pre_start;
         
            u32 *src,*des;
            u32 i, j;
            for(i=0; i
        src = (u32*) preload_copy_table.record[i].load_start_address;
        des = (u32*) preload_copy_table.record[i].run_start_address;
        if(preload_copy_table.record[i].type == 1) { //copy
            if(src != des) {
        for(j=0; j
         
        {
        *des=*src;
        j+=4;
        }
            }
        } else if(preload_copy_table.record[i].type == 0) { //zero init
        for(j=0; j
        *des=0;
        j+=4;
        }
        }
            }
         
        #if cfg_cache_used == 1
            cache_clean_data();
            cache_invalid_inst();
        #endif
            pl_1st();   //用指針做遠程調用
        }
         
        代碼一開始就申明了一個外部結構,這個結構是定義在lds文件中的,所以要熟悉lds文件,不熟悉的可
         
        以在網上搜一下相關的文檔學習一下,因為lds文件關系到代碼如何存儲以及在rom還是ram運行。
         
        pre_load函數首先定義了一個指針pl_1st指向pre_start,然后對copy_table類型的preload_copy_table
         
        結構數據進行判斷代碼是否需要從rom復制到ram,從lds文件中對preload_copy_table分析可知.text代
         
        碼段是定義在rom運行的,運行地址=加載地址 所以不需要復制,.data初始化好的數據段復制到內
         
        存,.bss未初始化的數據段將內存相應數據清零。這樣預加載程序的使命完成,最終調用pl_lst()即
         
        pre_start。下一篇看一下pre_start做了什么。
         
        pre_start屬于加載函數,我們可以在loader/si/loader.c中找到它,我們還是把它復制到這里
         
        void pre_start(void)
        {
        #ifdef debug
                loader();
        #endif
                int_init();
         
                critical();
        #ifndef debug
                loader();
        #endif
            start_sys();        //開始啟動系統
        }
         
        這里有個宏debug,debug已經在eclipse中定義具體是在工程properties > c/c++Build > Settings 
        >preprocessor中,所以一開始就要調用loader(),loader與pre_loader()功能差不多,這里是把剩余的
        需要復制到ram里的代碼段數據段復制到ram中。然后就是執行int_init()函數,這個函數是完成中斷的
        初始化,我們一會在看。繼續就是執行critical()鉤子函數,就是在啟動系統之前需要做的緊急任務在
        此完成。最后啟動系統start_sys().
        這里我們詳細看一下int_init()這個函數:
        關于中斷djyos定義了兩個結構:
        1、中斷線數據結構,每中斷一個
        //移植敏感
        struct int_line
        {
            u32 (*ISR)(ufast_t line);
            struct  event_ECB *sync_event;       //正在等待本中斷發生的事件
            ucpu_t en_counter;          //禁止次數計數,等于0時表示允許中斷
            ucpu_t int_type;            //1=實時中斷,0=異步信號
            bool_t enable_nest;         //true=本中斷響應期間允許嵌套,對硬件能力有依賴
                                        //性,也與軟件設置有關。例如cortex-m3版本,異步
                                        //信號被設置為最低優先級,從而所有異步信號都不
                                        //允許嵌套。
                                        //特別注意,實時中斷能夠無條件嵌套異步信號。
                                        //中斷響應后,由中斷引擎根據enable_nest的值使能
                                        //或禁止中斷來控制是否允許嵌套,如果在響應中斷
                                        //后,硬件沒有立即禁止中斷,將有一個小小的"窗口"
                                        //,在該窗口內,是允許嵌套的。例如cm3的實時中斷
         
            uint16_t my_evtt_id;
            u32  prio;                  //優先級,含義由使用者解析
        };
         
        2.中斷總控數據結構.
        struct int_master_ctrl
        {
            //中斷線屬性位圖,0=異步信號,1=實時中斷,數組的位數剛好可以容納中斷數量,與
            //中斷線數據結構的int_type成員含義相同。
            ucpu_t  property_bitmap[cn_int_bits_words];
            ucpu_t nest_asyn_signal;   //中斷嵌套深度,主程序=0,第一次進入中斷=1,依次遞加
            ucpu_t nest_real;   //中斷嵌套深度,主程序=0,第一次進入中斷=1,依次遞加
            //中斷線使能位圖,1=使能,0=禁止,反映相應的中斷線的控制狀態,
            //與總開關/異步信號開關的狀態無關.
            ucpu_t  enable_bitmap[cn_int_bits_words];
        //    bool_t  en_trunk;           //1=總中斷使能,  0=總中斷禁止
        //    bool_t  en_asyn_signal;         //1=異步信號使能,0=異步信號禁止
            ucpu_t en_trunk_counter;   //全局中斷禁止計數,=0表示允許全局中斷
            ucpu_t en_asyn_signal_counter; //異步信號禁止計數,=0表示允許異步信號
        };
         
        熟悉了以上兩個結構我們看一下中斷初始化函數,過程已經詳細注釋,函數主要初始化了向量表,初始化
         
        了中斷線數據結構,初始化中斷總控數據結構
         
        //----初始化中斷---------------------------------------------------------------
        //功能:初始化中斷硬件,初始化中斷線數據結構
        //      2.異步信號保持禁止,它會在線程啟動引擎中打開.
        //      3.總中斷允許,
        //      用戶初始化過程應該遵守如下規則:
        //      1.系統開始時就已經禁止所有異步信號,用戶初始化時無須擔心異步信號發生.
        //      2.初始化過程中如果需要操作總中斷/實時中斷/異步信號,應該成對使用.禁止使
        //        異步信號實際處于允許狀態(即異步和總中斷開關同時允許).
        //      3.可以操作中斷線,比如連接、允許、禁止等,但應該成對使用.
        //      4.建議使用save/restore函數對,不要使用enable/disable函數對.
        //參數:無
        //返回:無
        //-----------------------------------------------------------------------------
        void int_init(void)
        {
            ufast_t ufl_line;
            int_cut_trunk();    //關總中斷                                     
            int_echo_all_line();//此行動作for(ufl=0; ufl < cn_int_bits_words; ufl++)                                               //pg_int_reg->clrpend[ufl] = 0xffffffff;
                                //清除全部中斷線的掛起
            pg_scb_reg->CCR |= 1<<bo_scb_ccr_usersetmpend;//USERSETMPEND  如果寫成1,那么用戶代碼可
                                                         //以寫軟件觸發中斷寄存器以觸發(掛起)一個主異
                                                         //常,該異常是和主堆棧指針相聯系的。
            for(ufl_line=0;ufl_line <= cn_int_line_last;ufl_line++)
            {
                tg_int_lookup_table[ufl_line] = (ufast_t)cn_limit_ufast;
                u32g_vect_table[ufl_line] = (u32)__start_asyn_signal;  //全部初始化為異步信號 此數組為中斷                    //向量表,預加載時已經加載到RAM,現在是將數組全部初始化為異步信號處理的入口地址
            }
            for(ufl_line=0;ufl_line < ufg_int_used_num;ufl_line++)
            {
                tg_int_lookup_table[tg_int_used[ufl_line]] = ufl_line;
                tg_int_table[ufl_line].en_counter = 1;                   //禁止中斷,計數為1
                tg_int_table[ufl_line].int_type = cn_asyn_signal;        //設為異步信號
                                                                         //所有中斷函數指針指向空函數
                tg_int_table[ufl_line].ISR = (u32 (*)(ufast_t))NULL_func;
                tg_int_table[ufl_line].sync_event = NULL;                //同步事件空
                tg_int_table[ufl_line].my_evtt_id = cn_invalid_evtt_id;  //不彈出事件
                pg_int_reg->pri[ufl_line] = 0xff;                        //異步信號優先級最低
            }
            for(ufl_line=0; ufl_line < cn_int_bits_words; ufl_line++)
            {
                pg_int_reg->clrena[ufl_line]=0xffffffff;     //全部禁止
                pg_int_reg->clrpend[ufl_line]=0xffffffff;    //全部清除掛起狀態
                //屬性位圖清零,全部置為異步信號方式
                tg_int_global.property_bitmap[ufl_line] = 0;
                //中斷使能位圖清0,全部處于禁止狀態
                tg_int_global.enable_bitmap[ufl_line] = 0;
            }
            tg_int_global.nest_asyn_signal =0;
            tg_int_global.nest_real=0;
         
        //    tg_int_global.en_asyn_signal = false;
            tg_int_global.en_asyn_signal_counter = 1;   //異步信號計數
            int_cut_asyn_signal();
        //    tg_int_global.en_trunk = true;
            tg_int_global.en_trunk_counter = 0;       //總中斷計數
            int_contact_trunk();                    //接通總中斷開關
            cm3_cpsie_f();                           //接通所有異常開關
        }
         
         
        這里介紹一個eclipse的快捷鍵,Ctrl+h  可以調出查詢對話框,可以在工作區查找字符串 函數等,很方便.
        中斷初始化已經完成,接下來就是開始啟動系統了,下一篇我們再看.有些底層函數我們可能到系統啟動
        完成都沒有涉及到,是因為必須有中斷或者調用才會涉及到,以后的時間我們看一下,現在主要是看一
        下系統是怎樣啟動的。
         
        關閉窗口
        欧美国产伦久久久久_亚洲爽爽一区二区三区_一色屋精品视频在线观看免费_久久伊人成色777综合网
        <object id="k0taz"><form id="k0taz"></form></object>
        <pre id="k0taz"></pre>
          1. <table id="k0taz"></table>
            <bdo id="k0taz"><center id="k0taz"></center></bdo>
            <table id="k0taz"><option id="k0taz"></option></table><track id="k0taz"><ruby id="k0taz"></ruby></track>