板子上的MCU是個很有意思的東西——并行多線程處理器MC3172 。
通俗地說,這顆MCU的內(nèi)部實現(xiàn)了類似RTOS多線程的功能。但是MC3172 編程與RTOS編程的最大區(qū)別就是:
MC3172多線程絕對并行運(yùn)行,沒有切換抖動及開銷。
MC3172無線程優(yōu)先級、優(yōu)先級反轉(zhuǎn)、死鎖等概念。
MC3172所有中斷都可以安排專門線程處理,沒有中斷嵌套和延遲。
MC3172各線程同步并行運(yùn)行,互不阻塞,互不干擾。
MC3172線程響應(yīng)的確定性相對于RTOS更為精確。
MC3172簡介
MC3172 是廈門感芯科技的一款32 位 RISC并行多線程實時處理器?;?a target="_blank">RISC-V RV32IMC 指令集, 100%單周期指令, 最高200MHz主頻, 3.37coremark/MHz。可以代替實時操作系統(tǒng), 實現(xiàn)程序的模塊化與復(fù)用性。
MC3172 特性:
MC3172實踐
MC3172的開發(fā)環(huán)境使用的是國產(chǎn)軟件——MounRiver Studio。
我們簡單看一下MC3172的demo工程:
1、MC3172文件夾
MC3172存放MC3172編程核心文件。
線程配置工具可對各線程進(jìn)行配置:
MC3172支持64路線程同步并行運(yùn)行, ?其中分為4個線程組,每個線程組16線程,每個線程組里的線程編號如上圖所示。其中,不使用的線程可以設(shè)置為空閑線程,空閑線程完全不運(yùn)行,不產(chǎn)生功耗。
每個線程都有自己獨(dú)立的??臻g ,在數(shù)據(jù)空間允許范圍內(nèi)可隨意分配,但需要確保所有非空閑線程所占的數(shù)據(jù)空間不超過數(shù)據(jù)空間的大小。
MC3172.h存放外設(shè)地址相關(guān)宏定義及其配置宏,如:
類似于ST的stm32fxxx.h。
thread_config.h為線程配置文件,由線程配置工具生成:
MC3172.lds為鏈接腳本,由線程配置工具生成
thread_start.c為啟動線程相關(guān)的源文件:
?
#ifndef?THREAD_START_C #define?THREAD_START_C #include?"./MC3172.h" #include?"./thread_config.h" void?thread1_initial(void) { #ifdef?ROTHD_THREAD1_VALID extern?void?thread1_main(void); ????rothd_set_sp_const(ROTHD_THREAD1_STACKCFG_VALUE|0x20000000); ????thread1_main(); #endif } void?thread2_initial(void) { #ifdef?ROTHD_THREAD2_VALID extern?void?thread2_main(void); ????rothd_set_sp_const(ROTHD_THREAD2_STACKCFG_VALUE|0x20000000); ????thread2_main(); #endif } //?省略部分代碼...... void?(*thread_initial_pointer[64])?(void)={ ???????????????????????????????????????????????&thread0_initial, ???????????????????????????????????????????????&thread1_initial, ???????????????????????????????????????????????&thread2_initial //?省略部分代碼...... } void?thread_start(void) { ????(*thread_initial_pointer[THREAD_ID])(); }
?
程序運(yùn)行的入口函數(shù)為:thread_start ,從鏈接腳本里可以知道:
thread_start里的THREAD_ID為線程ID值,直接從0x50000000地址中讀出:
?
#define?THREAD_ID?(*(volatile?u8*)(0x50000000))
?
猜測:0x50000000地址里的ID值會不斷變化,通過某種機(jī)制跳轉(zhuǎn),遍歷執(zhí)行thread_initial_pointer函數(shù)指針數(shù)組里的各個線程函數(shù)。
threadx_initial里初始化線程棧,并執(zhí)行線程主體,如
?
void?thread_end(void) { ????while(1); } void?thread1_main(void) { ????while(1){ ????????//user?code?section ????} ????thread_end(); }
?
這是用戶代碼,我們可以在各個線程主體函數(shù)里邊編寫我們的應(yīng)用代碼。
2、Release文件夾
Release文件夾里存放的是編譯生成的固件程序,通過 開發(fā)板程序下載工具 可進(jìn)行下載:
3、USER_CODE文件夾
USER_CODE文件夾存放用戶代碼:
MC3172 是一顆并行并行多線程實時處理器,我們下面來看看其多線程并行執(zhí)行的特性。
我們編寫兩個線程,線程進(jìn)行相同的配置,兩個線程分別對兩個IO進(jìn)行翻轉(zhuǎn),測試代碼如:
?
void?LED0_GPIOA_PIN0_TEST(void) { ?//?啟動GPIOA并設(shè)置特權(quán)組及時鐘頻率 ????INTDEV_SET_CLK_RST(GPIOA_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2)); ????//?使能GPIOA?PIN0引腳 ????GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,?GPIO_PIN0,?GPIO_SET_ENABLE); ????while(1) ????{ ?????//?GPIOA?PIN0輸出1 ?????GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,?GPIO_PIN0); ?????//?延時 ????????for?(u32?var?=?0;?var?5000;?++var) ????????{ ????????????NOP(); ????????} ????????//?GPIOA?PIN0輸出0 ?????GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,?GPIO_PIN0); ?????//?延時 ????????for?(u32?var?=?0;?var?5000;?++var) ????????{ ????????????NOP(); ????????} ????} } void?LED1_GPIOA_PIN1_TEST(void) { ?//?啟動GPIOA并設(shè)置特權(quán)組及時鐘頻率 ????INTDEV_SET_CLK_RST(GPIOA_BASE_ADDR,(INTDEV_RUN|INTDEV_IS_GROUP0|INTDEV_CLK_IS_CORECLK_DIV2)); ????//?使能GPIOA?PIN1引腳 ????GPIO_SET_OUTPUT_EN_VALUE(GPIOA_BASE_ADDR,?GPIO_PIN1,?GPIO_SET_ENABLE); ????while(1) ????{ ?????//?GPIOA?PIN1輸出1 ?????GPIO_SET_OUTPUT_PIN_TO_1(GPIOA_BASE_ADDR,?GPIO_PIN1); ?????//?延時 ????????for?(u32?var?=?0;?var?5000;?++var) ????????{ ????????????NOP(); ????????} ????????//?GPIOA?PIN1輸出0 ?????GPIO_SET_OUTPUT_PIN_TO_0(GPIOA_BASE_ADDR,?GPIO_PIN1); ?????//?延時 ????????for?(u32?var?=?0;?var?5000;?++var) ????????{ ????????????NOP(); ????????} ????} } //////////////////////////////////////////////////////////// void?thread_end(void) { ????while(1); } //////////////////////////////////////////////////////////// void?thread0_main(void) { ????while(1){ ????????//user?code?section ????} ????thread_end(); } //////////////////////////////////////////////////////////// void?thread1_main(void) { ????while(1){ ????????//user?code?section ?????LED0_GPIOA_PIN0_TEST(); ????} ????thread_end(); } //////////////////////////////////////////////////////////// void?thread2_main(void) { ????while(1){ ????????//user?code?section ?????LED1_GPIOA_PIN1_TEST(); ????} ????thread_end(); }
?
燒錄程序,使用邏輯分析儀抓取GPIOA_PIN0及GPIOA_PIN1引腳電平變化如:
可見,這兩個波形是完全同步的,CPU同時在干兩件事情,實現(xiàn)了與RTOS多線程同樣的效果。
心得與總結(jié)
嵌入式開發(fā),是軟件+硬件結(jié)合,兩者互補(bǔ)。如果硬件功能很強(qiáng)大,則軟件可能可以設(shè)計得比較簡單;如果硬件功能有限,則軟件方面可能得考慮比較多的方面。
比如:
一些軟件算法,需要多傳感器數(shù)據(jù)輸入進(jìn)行融合,則功能實現(xiàn)可能比較簡單,但實際可能為了降成本,減少一些傳感器,這時候需要實現(xiàn)穩(wěn)定可靠的功能,則軟件算法上得下更大的功夫。
對于一些不太復(fù)雜的數(shù)字信號處理,在通用的MCU上就可以處理,但對于一些比較復(fù)雜的數(shù)字信號處理,則可能使用一些帶有DSP處理器的MCU。
特別的,對于芯片內(nèi)部IC電路來說,如果內(nèi)部有相關(guān)模塊可以實現(xiàn)某些功能的話,則對應(yīng)的軟件編程會簡單很多,而且硬件實現(xiàn)的比軟件實現(xiàn)的效率要高。
硬件實現(xiàn)的多線程編程確實優(yōu)于RTOS編程,但實際開發(fā)中產(chǎn)品軟硬件架構(gòu)需要考慮多個方面,比如芯片的穩(wěn)定性以及軟件生態(tài)等方面。
并行多線程實時處理器是個好東西,但目前并行多線程實時處理器還處于起步階段,還有很多東西需要完善,需要我們多支持與傳播,只有生態(tài)起來了,將來我們才有機(jī)會用得上。
審核編輯:劉清
評論
查看更多