本文來源電子發(fā)燒友社區(qū),作者:許鵬虎, 帖子地址:https://bbs.elecfans.com/jishu_2286915_1_1.html
UCM108E二次開發(fā)代碼啟動(dòng)分析
簡(jiǎn)介
UCM108E內(nèi)置了一顆RISC-V核心的UC8188MCU,所以其實(shí)也是在分析UC8188的啟動(dòng)過程。UC8188 是一款高性能 MCU GNSS 多模衛(wèi)星導(dǎo)航接收機(jī) SoC 芯片。 芯片集成了 RISCV 32 位通用處理器, 數(shù)字基帶處理器, 射頻前端, 具有 4Mb 內(nèi)嵌的閃存。 擁有 SPI、I2C、 UARTx2 以及其它豐富的外設(shè)。
啟動(dòng)過程分析
- MCU啟動(dòng)一般情況下是從reset中斷開始的,我們拿到的這顆MCU也是這樣,找到它的啟動(dòng)匯編代碼,找到reset中斷入口
- 分析這段啟動(dòng)代碼
/* reset 中斷入口 */
reset_handler:
csrw mtvec, x0
csrci mstatus, 0x08
/* 1. 將所有寄存器置位為0 set all registers to zero */
mv x1, x0
mv x2, x1
mv x3, x1
mv x4, x1
mv x5, x1
mv x6, x1
mv x7, x1
mv x8, x1
mv x9, x1
mv x10, x1
mv x11, x1
mv x12, x1
mv x13, x1
mv x14, x1
mv x15, x1
mv x16, x1
mv x17, x1
mv x18, x1
mv x19, x1
mv x20, x1
mv x21, x1
mv x22, x1
mv x23, x1
mv x24, x1
mv x25, x1
mv x26, x1
mv x27, x1
mv x28, x1
mv x29, x1
mv x30, x1
mv x31, x1
#ifdef ARCH_RISCV_FPU
fssr x0
fmv.s.x f0, x0
fmv.s.x f1, x0
fmv.s.x f2, x0
fmv.s.x f3, x0
fmv.s.x f4, x0
fmv.s.x f5, x0
fmv.s.x f6, x0
fmv.s.x f7, x0
fmv.s.x f8, x0
fmv.s.x f9, x0
fmv.s.x f10,x0
fmv.s.x f11,x0
fmv.s.x f12,x0
fmv.s.x f13,x0
fmv.s.x f14,x0
fmv.s.x f15,x0
fmv.s.x f16,x0
fmv.s.x f17,x0
fmv.s.x f18,x0
fmv.s.x f19,x0
fmv.s.x f20,x0
fmv.s.x f21,x0
fmv.s.x f22,x0
fmv.s.x f23,x0
fmv.s.x f24,x0
fmv.s.x f25,x0
fmv.s.x f26,x0
fmv.s.x f27,x0
fmv.s.x f28,x0
fmv.s.x f29,x0
fmv.s.x f30,x0
fmv.s.x f31,x0
#endif
/* 2. 初始化堆棧 stack initilization */
la x2, _stack_start
_start:
.global _start
/* 3. 將bss段清零 clear BSS */
la x26, _bss_start
la x27, _bss_end
bge x26, x27, zero_loop_end
zero_loop:
sw x0, 0(x26)
addi x26, x26, 4
ble x26, x27, zero_loop
zero_loop_end:
/* 4. 運(yùn)行全局初始化函數(shù) Run global initialization functions */
li a0, 1 /* set app mode */
call set_program_type
call boot_noop
call boot_strap /* 關(guān)閉全局中斷 配置時(shí)鐘和XIP */
call __libc_init_array
j main_entry /* 跳轉(zhuǎn)到main_entry 在下面*/
.section .crt0, "ax"
main_entry:
addi x10, x0, 0
/* Baud Rate 156250
*clock divider, SYSCLK/156250/16-1
*5MHZ 1; 50MHZ 19
* 103.68Mhz clk, 115200 sv model 89
* 19.6608Mhz clk, VHD model, value 4. VHD
* 196/2Mhz VHD model value 84 for 115200
*/
//addi x11, x0, 84 //98Mhz, 1152000 for sim
addi x11, x0, 70 //131.072Mhz, 115200 for sim
//addi x11, x0, 22 //26M DCXO, just leave it here, not necessary
//jal uart_set_cfg
/* jump to main program entry point (argc = argv = 0) */
addi x10, x0, 0
addi x11, x0, 0
jal x1, entry /* 跳轉(zhuǎn)到entry函數(shù) */
jal uart_wait_tx_done;
/* if program exits call exit routine from library */
jal x1, exit
-
通過以上的分析,我們看到最后是跳轉(zhuǎn)到
entry
函數(shù)去了,這個(gè)entry
就是rt-thread的入口函數(shù),接下來,我們看在這個(gè)函數(shù)里做了哪些事情
-
在entry函數(shù)里面其實(shí)就是調(diào)用了
rtthread_startup()
函數(shù),然后,我們重點(diǎn)分析一下這個(gè)函數(shù)里面都做了哪些事情
int rtthread_startup(void)
{
// 關(guān)閉全局中斷
rt_hw_interrupt_disable();
/* board level initialization
* NOTE: please initialize heap inside board initialization.
* 板子相關(guān)的初始化,主要是啟動(dòng)了systick
*/
rt_hw_board_init();
/* show RT-Thread version */
rt_show_version();
/* 系統(tǒng)定時(shí)器初始化,后續(xù)的任務(wù)切換調(diào)度都會(huì)用到這個(gè)timer,timer system initialization */
rt_system_timer_init();
/* 初始化系統(tǒng)調(diào)度器 scheduler system initialization */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* signal system initialization */
rt_system_signal_init();
#endif
/* 創(chuàng)建main線程并啟動(dòng) create init_thread */
rt_application_init();
/* 創(chuàng)建timer線程并啟動(dòng) timer thread initialization */
rt_system_timer_thread_init();
/* 創(chuàng)建空閑線程并啟動(dòng) idle thread initialization */
rt_thread_idle_init();
#ifdef RT_USING_SMP
rt_hw_spin_lock(&_cpus_lock);
#endif /*RT_USING_SMP*/
/* 啟動(dòng)調(diào)度器 start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
- 通過對(duì)以上的分析,我們大概知道rt-thread創(chuàng)建了幾個(gè)必要的線程并啟動(dòng)了調(diào)度器,這個(gè)時(shí)候就會(huì)啟動(dòng)剛才創(chuàng)建的線程,其中用戶關(guān)心的則是main線程,我們看下main線程里面做了哪些工作
/* the system main thread */
void main_thread_entry(void* parameter)
{
extern int main(void);
#ifdef RT_USING_COMPONENTS_INIT
/* RT-Thread components initialization */
rt_components_init();
#endif
#ifdef RT_USING_SMP
rt_hw_secondary_cpu_up();
#endif
/* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
{
extern int $Super$$main(void);
$Super$$main(); /* for ARMCC. */
}
#elif defined(__ICCARM__) || defined(__GNUC__) || defined(__TASKING__)
main(); // 運(yùn)行main函數(shù)
#endif
}
-
其實(shí)這個(gè)線程最終是為了調(diào)用
main
函數(shù),也就是我們用戶編程的入口函數(shù)
int main(void)
{
int_disable();
REG_INT_PEND = 0x0;
#ifdef _WTG_OPEN_
wdt_init(UC_WATCHDOG, 5000);
wdt_enable(UC_WATCHDOG);
#endif
InitUart(UART_BSP_115200);
GnssStart(get_pos, 0x7f, FALSE, NULL);
g_hTaskUartTx = rt_thread_create("Task Uart Tx", TaskUartTx, NULL, TSK_STACK_SIZE_UART_TX, 10, 10);
if(g_hTaskUartTx == RT_NULL)
printf("tx task create failed!rn");
else
{
rt_thread_startup(g_hTaskUartTx);
printf("tx task is start!rn");
}
g_hTaskUartRx = rt_thread_create("Task Uart Rx", TaskUartRx, NULL, TSK_STACK_SIZE_UART_RX, 10, 10);
if(g_hTaskUartRx == RT_NULL)
printf("rx task create failed!rn");
else
{
rt_thread_startup(g_hTaskUartRx);
printf("rx task is start!rn");
}
#ifdef _WTG_OPEN_
wdt_feed(UC_WATCHDOG);
#endif
}
-
分析到這里我們應(yīng)該清楚的知道UCM108E從上電到
main
的整個(gè)運(yùn)行流程了。
如果大家對(duì)rt-thread感興趣,可以訪問官網(wǎng)獲取更多學(xué)習(xí)資料。后續(xù)還會(huì)分享RISC-V任務(wù)切換相關(guān)知識(shí)。
-
御芯微
+關(guān)注
關(guān)注
4文章
57瀏覽量
3332 -
開發(fā)板試用
+關(guān)注
關(guān)注
3文章
301瀏覽量
2132 -
UCM108E
+關(guān)注
關(guān)注
0文章
13瀏覽量
153
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論