本文來源電子發燒友社區,作者:李先生, 帖子地址:https://bbs.elecfans.com/jishu_2306123_1_1.html
前言
對于RTOS開發我們知道,線程調度不能太頻繁,因為軟件進行上下文切換需要時間,調度太頻繁則調度時間占的比例會越來越大,實際運行用戶代碼的時間就會很少效率降低。可不可以減少這個調度時間呢,可以,感芯的MC3172就用硬件去實現了這個上下文切換個調度,使得實時性更高,用戶也不需要考慮這個軟件調度切換花掉的時間了。
MC3172這個芯片是一個非常大的創新,我們下面實際來體驗下。
資料
http://www.gxchip.cn/down/show-70.html
https://whycan.com/f_57.html
概述
CPU:MC3172,32 位RISC 處理器,個64線程同步并行運行。最高200MHz主頻,3.37coremark/MHz。
數據段與代碼段共享128K字節SRAM可配置為
96KCODE+32KDATA
64KCODE+64KDATA
32KCODE+96KDATA
開發環境
在http://www.mounriver.com/download
下載MounRiver_Studio_Setup_V181.zip
安裝沒有什么特別的,過程略。
在http://www.gxchip.cn/down/show-70.html下下載
分析
配置
時鐘源
MC3172 擁有4 個時鐘源,
- 0 內嵌 200MHz 高速RC 振蕩器 默認配置。
- 1 內嵌 8MHz 低速RC 振蕩器
- 2 外部支持 4MHz~40MHz 高速振蕩器(無源)
- 3 外部支持最高133MHz 輸入時鐘(有源)
線程配置工具_V1.exe工具中如下
對應的代碼位于thread_start.c
**#if** ROTHD_COLCK_SOURCE_SEL==0
(*(**volatile** u32*)(0x50050108))=0x00200003;
(*(**volatile** u32*)(0x50050108))=0x00200007;
(*(**volatile** u32*)(0x50050108))=0x0020000f;
(*(**volatile** u32*)(0x50050108))=0x0020010f;
**#endif**
**#if** ROTHD_COLCK_SOURCE_SEL==1
(*(**volatile** u32*)(0x50050108))=0x00300003;
(*(**volatile** u32*)(0x50050108))=0x00300007;
(*(**volatile** u32*)(0x50050108))=0x0030000f;
(*(**volatile** u32*)(0x50050108))=0x0030010f;
**#endif**
**#if** ROTHD_COLCK_SOURCE_SEL==2
(*(**volatile** u32*)(0x50050088))=0x1d00;
(*(**volatile** u32*)(0x50050090))=0xff000000;
(*(**volatile** u32*)(0x50050098))=0x00000000;
(*(**volatile** u32*)(0x50050108))=0x00000003;
(*(**volatile** u32*)(0x50050108))=0x00000007;
(*(**volatile** u32*)(0x50050108))=0x0000000f;
(*(**volatile** u32*)(0x50050108))=0x0000010f;
**for** (u8 var = 0; var < 64; ++ var)
{
(*(**volatile** u32*)(0x50050090))=0xff000000+var;
(*(**volatile** u32*)(0x50050098))=0x00000001;
(*(**volatile** u32*)(0x50050098))=0x00000203;
**while** ((((*(**volatile** u8*)(0x500500ca)))&0x80)==0);
**while** ((((*(**volatile** u8*)(0x500500ca)))&0x80)!=0);
**if** ((((*(**volatile** u16*)(0x500500c8))))>16380){ **break** ;}
}
**#endif**
**#if** ROTHD_COLCK_SOURCE_SEL==3
(*(**volatile** u32*)(0x50050108))=0x00100003;
(*(**volatile** u32*)(0x50050108))=0x00100007;
(*(**volatile** u32*)(0x50050108))=0x0010000f;
(*(**volatile** u32*)(0x50050108))=0x0010010f;
**#endif**
線程頻率
64 個線程每個線程最高可以運行在主頻的1/4,最低是主頻的1/1024,
不使用的線程可設置為空閑,空閑線程完全不運行,也不產生功耗。64 個線程分屬4 個線
程組,每個線程組的最高主頻份額不能超過主頻的1/4。
實際上可以理解為64個線程去共享主頻分時執行。
線程配置工具_V1.exe工具中如下
對應的代碼位于thread_start.c
**#ifdef** ROTHD_THREAD1_VALID
*( **int** *)(THD_TS_ADDR+8)=ROTHD_THREAD1_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD2_VALID
*( **int** *)(THD_TS_ADDR+16)=ROTHD_THREAD2_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD3_VALID
*( **int** *)(THD_TS_ADDR+24)=ROTHD_THREAD3_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD5_VALID
*( **int** *)(THD_TS_ADDR+40)=ROTHD_THREAD5_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD6_VALID
*( **int** *)(THD_TS_ADDR+48)=ROTHD_THREAD6_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD7_VALID
*( **int** *)(THD_TS_ADDR+56)=ROTHD_THREAD7_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD9_VALID
*( **int** *)(THD_TS_ADDR+72)=ROTHD_THREAD9_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD10_VALID
*( **int** *)(THD_TS_ADDR+80)=ROTHD_THREAD10_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD11_VALID
*( **int** *)(THD_TS_ADDR+88)=ROTHD_THREAD11_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD13_VALID
*( **int** *)(THD_TS_ADDR+104)=ROTHD_THREAD13_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD14_VALID
*( **int** *)(THD_TS_ADDR+112)=ROTHD_THREAD14_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD15_VALID
*( **int** *)(THD_TS_ADDR+120)=ROTHD_THREAD15_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD17_VALID
*( **int** *)(THD_TS_ADDR+136)=ROTHD_THREAD17_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD18_VALID
*( **int** *)(THD_TS_ADDR+144)=ROTHD_THREAD18_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD19_VALID
*( **int** *)(THD_TS_ADDR+152)=ROTHD_THREAD19_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD21_VALID
*( **int** *)(THD_TS_ADDR+168)=ROTHD_THREAD21_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD22_VALID
*( **int** *)(THD_TS_ADDR+176)=ROTHD_THREAD22_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD23_VALID
*( **int** *)(THD_TS_ADDR+184)=ROTHD_THREAD23_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD25_VALID
*( **int** *)(THD_TS_ADDR+200)=ROTHD_THREAD25_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD26_VALID
*( **int** *)(THD_TS_ADDR+208)=ROTHD_THREAD26_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD27_VALID
*( **int** *)(THD_TS_ADDR+216)=ROTHD_THREAD27_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD29_VALID
*( **int** *)(THD_TS_ADDR+232)=ROTHD_THREAD29_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD30_VALID
*( **int** *)(THD_TS_ADDR+240)=ROTHD_THREAD30_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD31_VALID
*( **int** *)(THD_TS_ADDR+248)=ROTHD_THREAD31_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD33_VALID
*( **int** *)(THD_TS_ADDR+264)=ROTHD_THREAD33_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD34_VALID
*( **int** *)(THD_TS_ADDR+272)=ROTHD_THREAD34_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD35_VALID
*( **int** *)(THD_TS_ADDR+280)=ROTHD_THREAD35_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD37_VALID
*( **int** *)(THD_TS_ADDR+296)=ROTHD_THREAD37_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD38_VALID
*( **int** *)(THD_TS_ADDR+304)=ROTHD_THREAD38_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD39_VALID
*( **int** *)(THD_TS_ADDR+312)=ROTHD_THREAD39_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD41_VALID
*( **int** *)(THD_TS_ADDR+328)=ROTHD_THREAD41_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD42_VALID
*( **int** *)(THD_TS_ADDR+336)=ROTHD_THREAD42_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD43_VALID
*( **int** *)(THD_TS_ADDR+344)=ROTHD_THREAD43_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD45_VALID
*( **int** *)(THD_TS_ADDR+360)=ROTHD_THREAD45_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD46_VALID
*( **int** *)(THD_TS_ADDR+368)=ROTHD_THREAD46_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD47_VALID
*( **int** *)(THD_TS_ADDR+376)=ROTHD_THREAD47_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD49_VALID
*( **int** *)(THD_TS_ADDR+392)=ROTHD_THREAD49_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD50_VALID
*( **int** *)(THD_TS_ADDR+400)=ROTHD_THREAD50_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD51_VALID
*( **int** *)(THD_TS_ADDR+408)=ROTHD_THREAD51_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD53_VALID
*( **int** *)(THD_TS_ADDR+424)=ROTHD_THREAD53_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD54_VALID
*( **int** *)(THD_TS_ADDR+432)=ROTHD_THREAD54_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD55_VALID
*( **int** *)(THD_TS_ADDR+440)=ROTHD_THREAD55_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD57_VALID
*( **int** *)(THD_TS_ADDR+456)=ROTHD_THREAD57_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD58_VALID
*( **int** *)(THD_TS_ADDR+464)=ROTHD_THREAD58_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD59_VALID
*( **int** *)(THD_TS_ADDR+472)=ROTHD_THREAD59_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD61_VALID
*( **int** *)(THD_TS_ADDR+488)=ROTHD_THREAD61_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD62_VALID
*( **int** *)(THD_TS_ADDR+496)=ROTHD_THREAD62_FREQCFG_VALUE;
**#endif**
**#ifdef** ROTHD_THREAD63_VALID
*( **int** *)(THD_TS_ADDR+504)=ROTHD_THREAD63_FREQCFG_VALUE;
**#endif**
程序/DATA空間
128KB RAM可以劃分3種配置
線程配置工具_V1.exe工具中如下
對應的代碼位于thread_start.c
實際就是寫DATA_RAM_RATIO寄存器,用于指定DATA的大小(32KBx1,32KBx2,32KBx3),
剩下的就是CODE區域。
**#if** ROTHD_DATA_RAM_VALUE==32768*3
DATA_RAM_RATIO=0x60;
**#endif**
**#if** ROTHD_DATA_RAM_VALUE==32768*2
DATA_RAM_RATIO=0x40;
**#endif**
**#if** ROTHD_DATA_RAM_VALUE==32768
DATA_RAM_RATIO=0x20;
**#endif**
棧空間
程序/DATA空間分配好后,再從DATA空間中分配棧空間
64 個線程,每個線程都有自己獨立的棧空間,且在數據空間允許的范
圍內隨意分配,只要所有非空閑線程的棧空間總和不超過數據空間的大小即可(數據空間有
192 字節的保留區不可使用),棧空間大小需要是4 字節的整數倍
線程配置工具_V1.exe工具中如下
對應的代碼位于thread_start.c
比如線程1,通過rothd_set_sp_const設置SP寄存器
**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**
}
其他線程類似
資源共享
各個線程之間共享全局變量實現通訊
執行過程分析
連接腳本
看程序的運行過程一般都是從連接腳本入手,先找入口點
再看MEMMAP等。
MC3172.lds
可以看到入口點
ENTRY(thread_start)
空間分配
MEMORY
{
CODE_SPACE (x) : ORIGIN = 0x00000010, LENGTH = 65520
DATA_SPACE (rw) : ORIGIN = 0x20000010, LENGTH = 48672
}
以下可以看到.text.thread_start放在了CODE_SPACE的開始處。后續就是DATA區域分配。所以最開始就是執行thread_start函數。
. = 0x00000010;
.text :
{
*(.text.thread_start)
*(.text)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
}
執行過程
thread_start ->
(*thread_initial_pointer[THREAD_ID])()
其中THREAD_ID寄存器指定一個運行的線程,一般是0。
則執行
thread0_initial->
進行時鐘源配置,CODE/DATA區域配置,線程頻率分配。
thread0_main->
其他線程運行
通過thread_initial_pointer查找到初始化函數
threadx_initial
進行棧配置然后
threadx_main運行
體驗
雙擊打開
MC3172資料合集_v1.12MC3172_TemplateMC3172.wvproj
打開工程瀏覽器
右鍵點擊
GPIO_GPCOM_TIMER_Example.c->Properties
按如下操作,將該文件添加到編譯。
取消
thread0_main~thread4_main相關代碼注釋
菜單欄
Project->Build ALL
生成進行鏡像位于
MC3172資料合集_v1.12MC3172_TemplateRelease
雙擊該目錄下開發板程序下載_v1.1.exe
按如下單次下載運行
上述下載到RAM中掉電不保存,也可以點擊燒錄固件到這樣可以掉電保存。
從以下可以看出GPCOM8 P2:RXD PC2 GPCOM8 P3:TXD PC3 波特率115200
GPCOM_UART_EXAMPLE(GPCOM8_BASE_ADDR);
GPCOM_SET_IN_PORT(gpcom_sel,(GPCOM_RXD_IS_P2));
GPCOM_SET_OUT_PORT(gpcom_sel,(
GPCOM_P0_OUTPUT_DISABLE|GPCOM_P3_OUTPUT_ENABLE|GPCOM_P2_OUTPUT_DISABLE|GPCOM_P1_OUTPUT_DISABLE|
GPCOM_P0_IS_HIGH |GPCOM_P3_IS_TXD |GPCOM_P2_IS_HIGH |GPCOM_P1_IS_HIGH
));
按如下接上串口線,使用串口調試助手設置為115200-8-n-1, 上位機發送數據開發板收到后原樣返回。
對應代碼如下
u8 rx_data_rp=0;
u8 rx_data=0;
rx_data_rp=GPCOM_GET_RX_WP(gpcom_sel);
while (1) {
if (rx_data_rp!=(GPCOM_GET_RX_WP(gpcom_sel))){
rx_data=GPCOM_GET_RX_DATA(gpcom_sel,rx_data_rp);
GPCOM_PUSH_TX_DATA(gpcom_sel,rx_data);
rx_data_rp++;
rx_data_rp&=0x0f;
}
}
總結
-
打開線程配置工具_V1.exe時能自動加載當前設置,這樣方便做修改,而不需要全部從頭配置。
-
64個線程共享主頻,所以實際并不是并行運行,而是硬件進行分時輪流執行,也就是并沒有64個運行環境(寄存器組等),實際是硬件完成了RTOS線程切換的上下文切換等動作,各線程執行的時間占比根據線程主頻控制器設置的共享頻率進行分配。硬件完成上下文切換時間損失很小,這樣在高調度頻率的情況就避免了上下文切換時間占比較大導致的效率低的問題,這樣比RTOS軟件實現實時性效率更高。
-
外設模塊能提供更詳細的編程手冊更好。
-
總結下從開發環境,配置工具等來看還是比較容易入手的,尤其是硬件實現線程切換調度,減少了RTOS移植,上下文調度切換的時間考慮等問題,編程更簡單,使得開發板都效率都更高,運行的實時性也更高。
發布評論請先 登錄
相關推薦
評論