本文來源電子發(fā)燒友社區(qū),作者:李先生, 帖子地址:https://bbs.elecfans.com/jishu_2306123_1_1.html
前言
對(duì)于RTOS開發(fā)我們知道,線程調(diào)度不能太頻繁,因?yàn)檐浖M(jìn)行上下文切換需要時(shí)間,調(diào)度太頻繁則調(diào)度時(shí)間占的比例會(huì)越來越大,實(shí)際運(yùn)行用戶代碼的時(shí)間就會(huì)很少效率降低??刹豢梢詼p少這個(gè)調(diào)度時(shí)間呢,可以,感芯的MC3172就用硬件去實(shí)現(xiàn)了這個(gè)上下文切換個(gè)調(diào)度,使得實(shí)時(shí)性更高,用戶也不需要考慮這個(gè)軟件調(diào)度切換花掉的時(shí)間了。
MC3172這個(gè)芯片是一個(gè)非常大的創(chuàng)新,我們下面實(shí)際來體驗(yàn)下。
資料
http://www.gxchip.cn/down/show-70.html
https://whycan.com/f_57.html
概述
CPU:MC3172,32 位RISC 處理器,個(gè)64線程同步并行運(yùn)行。最高200MHz主頻,3.37coremark/MHz。
數(shù)據(jù)段與代碼段共享128K字節(jié)SRAM可配置為
96KCODE+32KDATA
64KCODE+64KDATA
32KCODE+96KDATA
開發(fā)環(huán)境
在http://www.mounriver.com/download
下載MounRiver_Studio_Setup_V181.zip
安裝沒有什么特別的,過程略。
在http://www.gxchip.cn/down/show-70.html下下載
分析
配置
時(shí)鐘源
MC3172 擁有4 個(gè)時(shí)鐘源,
- 0 內(nèi)嵌 200MHz 高速RC 振蕩器 默認(rèn)配置。
- 1 內(nèi)嵌 8MHz 低速RC 振蕩器
- 2 外部支持 4MHz~40MHz 高速振蕩器(無源)
- 3 外部支持最高133MHz 輸入時(shí)鐘(有源)
線程配置工具_(dá)V1.exe工具中如下
對(duì)應(yīng)的代碼位于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 個(gè)線程每個(gè)線程最高可以運(yùn)行在主頻的1/4,最低是主頻的1/1024,
不使用的線程可設(shè)置為空閑,空閑線程完全不運(yùn)行,也不產(chǎn)生功耗。64 個(gè)線程分屬4 個(gè)線
程組,每個(gè)線程組的最高主頻份額不能超過主頻的1/4。
實(shí)際上可以理解為64個(gè)線程去共享主頻分時(shí)執(zhí)行。
線程配置工具_(dá)V1.exe工具中如下
對(duì)應(yīng)的代碼位于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種配置
線程配置工具_(dá)V1.exe工具中如下
對(duì)應(yīng)的代碼位于thread_start.c
實(shí)際就是寫DATA_RAM_RATIO寄存器,用于指定DATA的大小(32KBx1,32KBx2,32KBx3),
剩下的就是CODE區(qū)域。
**#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空間分配好后,再?gòu)腄ATA空間中分配??臻g
64 個(gè)線程,每個(gè)線程都有自己獨(dú)立的??臻g,且在數(shù)據(jù)空間允許的范
圍內(nèi)隨意分配,只要所有非空閑線程的棧空間總和不超過數(shù)據(jù)空間的大小即可(數(shù)據(jù)空間有
192 字節(jié)的保留區(qū)不可使用),??臻g大小需要是4 字節(jié)的整數(shù)倍
線程配置工具_(dá)V1.exe工具中如下
對(duì)應(yīng)的代碼位于thread_start.c
比如線程1,通過rothd_set_sp_const設(shè)置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**
}
其他線程類似
資源共享
各個(gè)線程之間共享全局變量實(shí)現(xiàn)通訊
執(zhí)行過程分析
連接腳本
看程序的運(yùn)行過程一般都是從連接腳本入手,先找入口點(diǎn)
再看MEMMAP等。
MC3172.lds
可以看到入口點(diǎn)
ENTRY(thread_start)
空間分配
MEMORY
{
CODE_SPACE (x) : ORIGIN = 0x00000010, LENGTH = 65520
DATA_SPACE (rw) : ORIGIN = 0x20000010, LENGTH = 48672
}
以下可以看到.text.thread_start放在了CODE_SPACE的開始處。后續(xù)就是DATA區(qū)域分配。所以最開始就是執(zhí)行thread_start函數(shù)。
. = 0x00000010;
.text :
{
*(.text.thread_start)
*(.text)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
}
執(zhí)行過程
thread_start ->
(*thread_initial_pointer[THREAD_ID])()
其中THREAD_ID寄存器指定一個(gè)運(yùn)行的線程,一般是0。
則執(zhí)行
thread0_initial->
進(jìn)行時(shí)鐘源配置,CODE/DATA區(qū)域配置,線程頻率分配。
thread0_main->
其他線程運(yùn)行
通過thread_initial_pointer查找到初始化函數(shù)
threadx_initial
進(jìn)行棧配置然后
threadx_main運(yùn)行
體驗(yàn)
雙擊打開
MC3172資料合集_v1.12MC3172_TemplateMC3172.wvproj
打開工程瀏覽器
右鍵點(diǎn)擊
GPIO_GPCOM_TIMER_Example.c->Properties
按如下操作,將該文件添加到編譯。
取消
thread0_main~thread4_main相關(guān)代碼注釋
菜單欄
Project->Build ALL
生成進(jìn)行鏡像位于
MC3172資料合集_v1.12MC3172_TemplateRelease
雙擊該目錄下開發(fā)板程序下載_v1.1.exe
按如下單次下載運(yùn)行
上述下載到RAM中掉電不保存,也可以點(diǎn)擊燒錄固件到這樣可以掉電保存。
從以下可以看出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
));
按如下接上串口線,使用串口調(diào)試助手設(shè)置為115200-8-n-1, 上位機(jī)發(fā)送數(shù)據(jù)開發(fā)板收到后原樣返回。
對(duì)應(yīng)代碼如下
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;
}
}
總結(jié)
-
打開線程配置工具_(dá)V1.exe時(shí)能自動(dòng)加載當(dāng)前設(shè)置,這樣方便做修改,而不需要全部從頭配置。
-
64個(gè)線程共享主頻,所以實(shí)際并不是并行運(yùn)行,而是硬件進(jìn)行分時(shí)輪流執(zhí)行,也就是并沒有64個(gè)運(yùn)行環(huán)境(寄存器組等),實(shí)際是硬件完成了RTOS線程切換的上下文切換等動(dòng)作,各線程執(zhí)行的時(shí)間占比根據(jù)線程主頻控制器設(shè)置的共享頻率進(jìn)行分配。硬件完成上下文切換時(shí)間損失很小,這樣在高調(diào)度頻率的情況就避免了上下文切換時(shí)間占比較大導(dǎo)致的效率低的問題,這樣比RTOS軟件實(shí)現(xiàn)實(shí)時(shí)性效率更高。
-
外設(shè)模塊能提供更詳細(xì)的編程手冊(cè)更好。
-
總結(jié)下從開發(fā)環(huán)境,配置工具等來看還是比較容易入手的,尤其是硬件實(shí)現(xiàn)線程切換調(diào)度,減少了RTOS移植,上下文調(diào)度切換的時(shí)間考慮等問題,編程更簡(jiǎn)單,使得開發(fā)板都效率都更高,運(yùn)行的實(shí)時(shí)性也更高。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論