大家好我是驚覺。是的,失蹤人口回來了。最近參加了rt-thread的國產(chǎn)MCU移植活動,移植rt-thread到華大的HC32L196。rtt論壇中已有許多介紹移植到各種平臺的文章,詳細講述移植步驟,在rtt論壇搜索“國產(chǎn)MCU移植”即可閱讀。本文不介紹具體移植步驟,而是如往常一樣,分享移植的原理與方法。
移植原理
移植一款軟件,無非是獲取源碼,修改其中與硬件相關(guān)的代碼以適配目標硬件。移植rt-thread也是如此,首要任務(wù)是要明確要修改哪部分內(nèi)容。帶著這個問題,我們來分析rt-thread的源碼結(jié)構(gòu)。
rt-thread源碼結(jié)構(gòu)
rt-thread源碼根目錄結(jié)構(gòu)如下:
目錄說明
bsp板級支持包。存放各種硬件平臺的驅(qū)動代碼,初始化代碼,工程文件。
components組件。如finsh控制臺,抽象層驅(qū)動,文件系統(tǒng),網(wǎng)絡(luò)系統(tǒng)。
examples示例程序
include內(nèi)核以及l(fā)ibc的頭文件
libcpu與CPU架構(gòu)相關(guān)的接口,為操作系統(tǒng)調(diào)度提供支持。
src內(nèi)核代碼,如線程、定時器、線程間通信(互斥鎖,信號量)。
移植所涉及的目錄有兩個:bsp和libcpu,相應(yīng)的移植分為BSP移植與CPU架構(gòu)移植。其他的目錄與具體的CPU無關(guān),無須改動。
CPU架構(gòu)移植
在嵌入式領(lǐng)域有多種不同 CPU 架構(gòu),例如 Cortex-M、ARM920T、MIPS32、RISC-V 等等。為了使 RT-Thread 能夠在不同 CPU 架構(gòu)的芯片上運行,RT-Thread 提供了一個 libcpu 抽象層來適配不同的 CPU 架構(gòu)。向下提供了一套統(tǒng)一的 CPU 架構(gòu)移植接口,這部分接口包含了全局中斷開關(guān)函數(shù)、線程上下文切換函數(shù)、時鐘節(jié)拍的配置和中斷函數(shù)、Cache 等等內(nèi)容。下表是 CPU 架構(gòu)移植需要實現(xiàn)的接口和變量。
函數(shù)和變量描述
rt_base_t rt_hw_interrupt_disable(void);關(guān)閉全局中斷
void rt_hw_interrupt_enable(rt_base_t level);打開全局中斷
rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit);線程棧的初始化,內(nèi)核在線程創(chuàng)建和線程初始化里面會調(diào)用這個函數(shù)
void rt_hw_context_switch_to(rt_uint32 to);沒有來源線程的上下文切換,在調(diào)度器啟動第一個線程的時候調(diào)用,以及在 signal 里面會調(diào)用
void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);從 from 線程切換到 to 線程,用于線程和線程之間的切換
void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);從 from 線程切換到 to 線程,用于中斷里面進行切換的時候使用
rt_uint32_t rt_thread_switch_interrupt_flag;表示需要在中斷里進行切換的標志
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;在線程進行上下文切換時候,用來保存 from 和 to 線程
是不是看起來挺復(fù)雜的,其實rtt已經(jīng)支持了非常多的CPU架構(gòu)。下圖的libcpu目錄中已支持多種CPU架構(gòu)。讓我們看看對arm系列的支持情況,從低端的cortex-m0到高端的cortex-m7,甚至還有cortex-a和cortex-r系列的。大家熟知的stm32f103為cortex-m3內(nèi)核,stm32f407為cortex-m4內(nèi)核。如果要移植到的目錄芯片內(nèi)核出現(xiàn)在此目錄之中,那就無需關(guān)注libcpu,只要在配置文件中指定正確的內(nèi)核即可。
我移植的HC32L196使用cortex-m0+內(nèi)核,可使用cortex-m0的代碼,因此無須進行CPU構(gòu)架移植。
bsp結(jié)構(gòu)
由于不需要進行CPU架構(gòu)移植,所以本次移植相對簡單,唯一的工作就是在rt-thread的bsp目錄中創(chuàng)建自己硬件的bsp。
rt-thread當前支持了100多個bsp,可能大家用的最多的是stm32。不過我并不建議大家在移植時參考stm32,因為它是最復(fù)雜的一個bsp。早期rt-thread中關(guān)于stm32的bsp比較簡單,各種型號如stm32f10x, stm32f40x都是獨立的bsp。新手入門相對簡單。不過弊病也很明顯:隨著支持的stm32系列的增加,bsp的子目錄也就急劇增加,維護成本很高。可能得益于stm32的HAL庫,可以相對較低的投入將它們合為一個bsp。它們共用一份驅(qū)動代碼,其在HAL_Drivers中。可能以后國產(chǎn)MCU的bsp也會發(fā)展成這樣,不過對于移植新手,最好是先易后難。我移植的HC32L196是華大單片機,以已經(jīng)被rtt支持的hc32f4a0為模板進行移植。同時參考了swm320,以及stm32stm32l053-st-nucleo。
大多數(shù)bsp目錄結(jié)構(gòu):
目錄說明
applications用戶代碼。純凈的bsp中只需要一個main.c文件,里面定義main函數(shù)。
board板級驅(qū)動代碼(最主要的是board.c),鏈接腳本(gcc, keil, iar)。
drivers設(shè)備驅(qū)動代碼,比如gpio和uart驅(qū)動。
figures電路板照片。
Libraries芯片廠商驅(qū)動庫。
.config, rtconfig.h, KconfigKconfig配置系統(tǒng)相關(guān)文件
rtconfig.py, SConscript, SConstructscons構(gòu)建系統(tǒng)相關(guān)文件
template.uvprojx, template.uvoptxkeil模板工程
project.uvprojx, project.uvoptxkeil工程
template.eww, template.ewpiar模板工程
project.eww, project.ewpiar工程
可分為如下幾類:
代碼文件:applications, board, drivers, Libraries中的.h和.c
Kconfig配置系統(tǒng)相關(guān)文件
scons構(gòu)建系統(tǒng)相關(guān)文件
工程模板
代碼結(jié)構(gòu)
先來看看我移植后的keil工程,其打開的幾個目錄就是涉及移植的代碼目錄。applications目錄最為簡單。drivers目錄是移植的重點,不過它不是移植的首要任務(wù)。下面幾節(jié)介紹移植前最迫切需要搞清楚的內(nèi)容。
Kconfig
rtt支持通過menuconfig命令來配置內(nèi)核、組件及軟件包。執(zhí)行menuconfig命令時,其從Kconfig文件中解析菜單結(jié)構(gòu),由用戶勾選、配置各個選項,最終將配置結(jié)果寫入.config和rtconfig.h。bsp中通常有兩個Kconfig文件。一個位于根目錄,另一個位于board。根目錄中的Kconfig僅僅是導(dǎo)入了別的目錄的Kconfig,所有bsp的基本都一樣,無須修改。
mainmenu “RT-Thread Project Configuration”
config BSP_DIR
string
option env=“BSP_ROOT”
default “。”
config RTT_DIR
string
option env=“RTT_ROOT”
default “。./。.”
config PKGS_DIR
string
option env=“PKGS_ROOT”
default “packages”
source “$RTT_DIR/Kconfig”
source “$PKGS_DIR/Kconfig”
source “board/Kconfig”
board/Kconfig
menu “Hardware Drivers Config”
config MCU_HC32L196
bool
select ARCH_ARM_CORTEX_M0
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN
default y
menu “Onboard Peripheral Drivers”
endmenu
menu “On-chip Peripheral Drivers”
config BSP_USING_GPIO
bool “Enable GPIO”
select RT_USING_PIN
default y
menuconfig BSP_USING_UART
bool “Enable UART”
default y
select RT_USING_SERIAL
if BSP_USING_UART
config BSP_USING_UART0
bool “Enable UART0”
default y
config BSP_USING_UART1
bool “Enable UART1”
default n
endif
endmenu
menu “Board extended module Drivers”
endmenu
endmenu
其自動選擇了幾個必選的配置,比如RT_USING_USER_MAIN。另,定義了可配置的驅(qū)動選項,比如GPIO配置和串口配置。
上述文件對應(yīng)的串口配置菜單如下:rtt官方文檔中有對Kconfig進行詳細講解:https://www.rt-thread.org/document/site/#/development-tools/kconfig/kconfig
scons和工程模板文件
rt-thread使用scons作為構(gòu)建系統(tǒng),其用于編譯源碼,生成固件。不過呢,大家用的最多的,可能是用它生成keil工程,就是在使用menuconfig配置內(nèi)核、組件和驅(qū)動之后,使用如下命令生成keil工程:
scons --target=mdk5
其原理,以生成keil5工程為例,是scons根據(jù)rtconfig.h文件中的配置,在template.uvprojx上添加宏定義、頭文件路徑配置、文件鏈接,從而生成project.uvprojx。下圖左側(cè)為模板工程,右側(cè)為生成的rtt工程。再多說一句,rtt是如何能夠讀寫keil工程文件呢?.uvprojx其實是xml文件,rtt通過模板工程創(chuàng)建新工程,就是在讀寫xml,有興趣的話,可以閱讀rt-thread源碼根目錄下的tools/keil.py。
rtconfig.h是在Kconfig系統(tǒng)中生成,只要修改好Kconfig相關(guān)文件后,無須操心rtconfig.h。要修改的是模板工程。不過也很簡單,從其他bsp復(fù)制模板工程,修改設(shè)備類型,RAM和ROM配置就可以了。其他的配置,如下載接口等,可根據(jù)需要修改。稍復(fù)雜些的任務(wù)是修改下面三種文件:
SConstruct
rtconfig.py
SConscript
這三個文件都是python腳本,只不過它們里面調(diào)用了許多scons系統(tǒng)提供的函數(shù)。所以,如果熟悉python的話,修改起來會很輕松。
SConstruct
SConstruct是scons的入口腳本,其通過rtconfig.py以導(dǎo)入各種編譯配置,之后調(diào)用PrepareBuilding以獲取編譯對象(要編譯哪些文件)。PrepareBuilding會調(diào)用各SConscript腳本以獲取編譯對象。這文件一般不用修改,除非參考的bsp有瑕疵。
rtconfig.py
rtconfig.py中定義了各種與編譯相關(guān)的選項和參數(shù)。
頭部定義CPU架構(gòu)與型號,還記得文首提到的架構(gòu)移植嗎?對于rtt已支持的CPU架構(gòu),只需要在這里指明即可,scons系統(tǒng)會根據(jù)這里的配置選擇相應(yīng)的架構(gòu)代碼以進行編譯鏈接。
ARCH=‘a(chǎn)rm’
CPU=‘cortex-m0’
其他主要的是編譯參數(shù),比如armcc編譯系列如下。
elif PLATFORM == ‘a(chǎn)rmcc’:
# toolchains
CC = ‘a(chǎn)rmcc’
CXX = ‘a(chǎn)rmcc’
AS = ‘a(chǎn)rmasm’
AR = ‘a(chǎn)rmar’
LINK = ‘a(chǎn)rmlink’
TARGET_EXT = ‘a(chǎn)xf’
DEVICE = ‘ --cpu Cortex-M0 ’
CFLAGS = ‘-c ’ + DEVICE + ‘ --apcs=interwork --c99’
AFLAGS = DEVICE + ‘ --apcs=interwork ’
LFLAGS = DEVICE + ‘ --scatter “boardlinker_scriptslink.sct” --info sizes --info totals --info unused --info veneers --list rt-thread.map --strict’
CFLAGS += ‘ -I’ + EXEC_PATH + ‘/ARM/ARMCC/include’
LFLAGS += ‘ --libpath=’ + EXEC_PATH + ‘/ARM/ARMCC/lib’
CFLAGS += ‘ -D__MICROLIB ’
AFLAGS += ‘ --pd “__MICROLIB SETA 1” ’
LFLAGS += ‘ --library_type=microlib ’
EXEC_PATH += ‘/ARM/ARMCC/bin/’
if BUILD == ‘debug’:
CFLAGS += ‘ -g -O0’
AFLAGS += ‘ -g’
else:
CFLAGS += ‘ -O2’
CXXFLAGS = CFLAGS
POST_ACTION = ‘fromelf --bin $TARGET --output rtthread.bin
fromelf -z $TARGET’
這塊與生成keil工程無關(guān),而是在命令行下編譯源碼并生成固件??赡艽蠹移綍r不會這么編譯,都是用Keil。其實這種方法意義重大,其是持續(xù)集成的基礎(chǔ)。
適配起來很也簡單,直接把相同CPU的配置復(fù)制過來即可。我移植HC32L196,雖然主要參考HC32F4A0,然而HC32F4A0的構(gòu)架是cortex-m4,顯然不適合。所以在適配rtconfig.py時,我從stm32stm32l053-st-nucleo獲取cortex-m0的配置。
SConscript
SConscript存在于各源碼目錄下,用于決定編譯哪些文件。這些要編譯的文件也會在創(chuàng)建keil工程中時被包含進去。bsp根目錄下的SConscript用于掃描出子目錄中的SConscript并調(diào)用之,一般不用修改。
子目錄下的SConscript大致分為兩種:
將指定文件包含到編譯目標之中,或者使用Glob(‘*.c’)包含所有的C文件。
根據(jù)rtconfig.h中的配置來包含被選中的文件。
application中的為第1種,drivers為第2種。修改時依葫蘆畫瓢即可。
更多細節(jié),可參閱:https://www.rt-thread.org/document/site/#/development-tools/scons/scons
board
終于進入代碼講解環(huán)節(jié)。board目錄中通常會有一個board.c。
void rt_hw_board_clock_init(void)
{
}
void SysTick_Configuration(void)
{
}
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
void rt_hw_board_init()
{
/* Configure the System clock */
rt_hw_board_clock_init();
/* Configure the SysTick */
SysTick_Configuration();
#ifdef RT_USING_HEAP
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
}
其做了如下事情:
初始化時鐘
配置SysTick定時器
初始化rtt堆內(nèi)存模塊
初始化板級驅(qū)動,如gpio和uart
設(shè)計控制臺串口
所有bsp的board.c都差不多,上面代碼中rt_hw_board_clock_init和SysTick_Configuration空著,這就是移植時需要修改的代碼。其他部分,一般不用修改。
另,配置堆內(nèi)存時用到的宏定義在board.h之中,需要根據(jù)硬件做修改。
#define SRAM_BASE 0x20000000#define SRAM_SIZE 0x8000#define SRAM_END (SRAM_BASE + SRAM_SIZE)
boardlinker_scripts目錄中存放鏈接腳本,需要修改其中有關(guān)RAM和ROM的配置。
link.sct:keil鏈接腳本
link.lds:gcc鏈接腳本
沒做iar支持,因為我不用iar,也沒裝iar:)
Libraries
Libraries存放芯片廠商提供的驅(qū)動代碼。我移植的HC32L196基本結(jié)構(gòu)如下:
HC32L196_StdPeriph_Driver:分inc和src,存放芯片驅(qū)動,如hc32l196_adc.h和hc32l196_adc.c。
CMSISInclude:存放CMSIS相關(guān)頭文件,如core_cm0.h
CMSISDeviceHDSCHC32L196Include:雜類驅(qū)動頭文件。
CMSISDeviceHDSCHC32L196Source:雜類驅(qū)動源文件,比如system_hc32l19x.c,其內(nèi)包含匯編啟動文件會調(diào)用的SystemInit函數(shù)。
CMSISDeviceHDSCHC32L196SourceARM:keil匯編啟動文件startup_hc32l19x.s
CMSISDeviceHDSCHC32L196SourceGCC:gcc匯編啟動文件startup_hc32l19x.s
CMSISDeviceHDSCHC32L196SourceIAR:iar匯編啟動文件startup_hc32l19x.s
SConscript:包含本目錄中的代碼文件。在包含匯編啟動文件時,根據(jù)rtconfig.CROSS_TOOL來包含相應(yīng)編譯平臺的文件。
上述這些文件,除了SConscript,都來自芯片廠商的SDK,只不過其文件分布可能與上述不同。視具體情況做調(diào)整即可。
匯編啟動文件
關(guān)于Libraries中的匯編啟動文件,需要補充說明一點。對于keil版本,一般無須修改。對于gcc版本,需要把跳轉(zhuǎn)main函數(shù)的語句修改為跳轉(zhuǎn)entry函數(shù)。
stm32的啟動文件,其調(diào)用的是main函數(shù)。需要改為:
bl entry
之所以有如此差異,是因為armcc(keil編譯器)與gcc的機制不同。
armcc
armcc的匯編啟動文件相對簡單,職責(zé)如下:
定義堆空間和??臻g,初始化棧指針
定義中斷向量表
定義入口函數(shù)Reset_Handler,其先調(diào)用SystemInit,之后調(diào)用__main
初始化全局變量等工作放在了__main之中,__main完成初始化操作后會調(diào)用main函數(shù)。不過呢,armcc提供了一種函數(shù)補丁機制。如果定義了$Sub$$main函數(shù)的話,在main函數(shù)調(diào)用之前,會先調(diào)用$Sub$$main。rt-thread就是通過定義$Sub$$main函數(shù),在其中進行操作系統(tǒng)的初始化,之后調(diào)用applications中的main函數(shù)以執(zhí)行用戶代碼。
gcc
gcc匯編啟動文件職責(zé)如下:
定義中斷向量表
定義入口函數(shù)Reset_Handler,其負責(zé)初始化全局變量(data和bss),調(diào)用SystemInit,調(diào)用main函數(shù)
由于gcc沒有armcc那樣的函數(shù)補丁機制,所以要運行rt-thread的話,需要將調(diào)用main函數(shù)改為調(diào)用rt-thread入口函數(shù),即entry。
rt-thread根據(jù)編譯平臺定義了不同的入口函數(shù),armcc對應(yīng)$Sub$$main,gcc對應(yīng)entry。
#ifdef __ARMCC_VERSIONextern int $Super$$main(void);
/* re-define main function */int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
#elif defined(__ICCARM__)extern int main(void);
/* __low_level_init will auto called by IAR cstartup */extern void __iar_data_init3(void);
int __low_level_init(void)
{
// call IAR table copy function.
__iar_data_init3();
rtthread_startup();
return 0;
}
#elif defined(__GNUC__)/* Add -eentry to arm-none-eabi-gcc argument */int entry(void)
{
rtthread_startup();
return 0;
}
#endif
移植到HC32L196
如前所說,我不打算詳細講解每一步操作,僅提一些要點。
移植步驟
可分為兩步:
創(chuàng)建可以運行的bsp,這是最關(guān)鍵的一步。
填充rtt設(shè)備驅(qū)動,如gpio和uart,這是相對費時的一步。
之所以分為兩大步,是因為先完成關(guān)鍵的一步,運行成功,將給予移植者一個很大的激勵,提高信心。如果第一步失敗了,也好及時查找問題,而不是等經(jīng)歷了漫長的設(shè)備驅(qū)動移植后,在測試時發(fā)現(xiàn)rt-thread系統(tǒng)都還無法跑起來。
創(chuàng)建可以運行的bsp
所謂可以運行,是指可以讓rt-thread操作系統(tǒng)在芯片上跑起來,并不需要跑finsh控制臺,甚至不需要點亮LED燈,不需要任何外設(shè)驅(qū)動,能運行如下代碼就行。
main.c
int main(void)
{
for (uint32_t i = 0; ; i++)
{
rt_thread_delay(RT_TICK_PER_SECOND);
};
}
當然啦,沒有任何外設(shè)驅(qū)動的話,只能在調(diào)試模式下運行才能觀察效果。只要rt_thread_delay的功能正常,就說明rt-thread調(diào)度系統(tǒng)正常工作了。
在了解了移植原理后,創(chuàng)建可以運行的bsp應(yīng)該能較快完成,具體步驟如下:
復(fù)制一個bsp,將名稱改為自己的平臺。
使用芯片原廠提供的SDK替換Libraries目錄中的內(nèi)容。對其中的匯編啟動文件和鏈接腳本要稍加關(guān)注,尤其是gcc匯編。
修改board目錄源碼,主要是board.c,完成初始化時鐘和SysTick的工作。
刪除drivers中的文件,或者保留幾個驅(qū)動文件的框架,刪除硬件相關(guān)代碼。
修改模板工程。
修改Kconfig相關(guān)文件。
修改Scons相關(guān)文件。
使用menuconfig更新rtconfig.h文件。
使用scons生成rt-thread工程。10.編譯燒錄調(diào)度。
RT-Thread Studio
創(chuàng)建可以運行的bsp之后,之后就是開發(fā)驅(qū)動程序了。此時其實是可以使用RT-Thread Studio開發(fā)的,其有一個非常好用的功能:導(dǎo)入Keil或者IAR項目到工作空間中。我在之后的驅(qū)動開發(fā)環(huán)節(jié)一直使用RT-Thread Studio編寫代碼。
gpio映射表
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
int (*pin_read)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
rt_uint32_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
rt_base_t (*pin_get)(const char *name);
};
rt-thread gpio設(shè)備驅(qū)動接口使用引腳號(pin)來操作指定的引腳。早期的bsp會定義一個大數(shù)組來存儲引腳列表,下圖是swm320定義的列表。這種方式比較繁瑣。通常芯片的GPIO口有一定的規(guī)律,比如PA0-PA15,PB0-PB15,PC0-PC15,等等。這些GPIO對應(yīng)的寄存器的地址是連續(xù)的,可以通過一個公式將寄存器地址轉(zhuǎn)換為引腳序號,反之亦然。
因此出現(xiàn)了使用GET_PIN宏來計算指定GPIO引腳序號的方法,比如GET_PIN(A, 5)會計算出PA5引腳的序號??赡躶tm32 bsp最先使用這種方法,大家移植的時候可以參考一下。
支持gcc
支持編譯
HC32L196的原廠SDK中并不支持gcc。不過筆者是eclipse系列IDE的忠實用戶,既然原廠不支持,那我就自己支持吧。
首先,要創(chuàng)建匯編啟動文件:LibrariesCMSISDeviceHDSCHC32L196SourceGCCstartup_hc32l19x.s。
怎么創(chuàng)建呢,當然不需要從零開始啦。從其他cortex-m0的bsp中復(fù)制一個來修改。比如stm32的,
bspstm32librariesSTM32L0xx_HALCMSISDeviceSTSTM32L0xxSourceTemplatesgccstartup_stm32l053xx.s
修改中斷向量表和中斷函數(shù)即可。
另外要關(guān)注下rtconfig.py和boardlinker_scriptslink.lds,同樣可以參考cortex-m0的bsp。
支持燒錄
添加了對gcc的支持后,使用RT-Thread Studio創(chuàng)建開發(fā)板支持包,就可以真正使用RT-Thread Studio來開發(fā)項目了。不過在這之前,需要先編譯出固件并燒錄驗證。
使用scons命令編譯。編譯后的固件位于bsp根目錄:
可使用J-Flash燒錄:成功運行:大家在使用J-Flash創(chuàng)建工程時,可能發(fā)現(xiàn)找不到自己的硬件配置。如下圖,HC32系列只有我移植的HC32L196,而沒有HC32F4A0等,這是我自己添加進去的。怎么添加呢,可參考我之前的一篇文章:RT-Thread Studio燒寫國產(chǎn)mcu(swm320)固件的方法。
后記
本次移植過程相當漫長,不是因為移植任務(wù)本身艱難,而是我只能用碎片化的時間進行移植。有幾天我九點半準備下班回家移植,老板覺得走的太早,硬是拖到十點,這些天就沒有早于十一點到家的。大家說這樣的老板是不是很可惡?表示贊同的,支持下筆者,點個再看唄:)。
責(zé)任編輯:haq
-
芯片
+關(guān)注
關(guān)注
452文章
50206瀏覽量
420881 -
mcu
+關(guān)注
關(guān)注
146文章
16885瀏覽量
349918 -
RTThread
+關(guān)注
關(guān)注
7文章
132瀏覽量
40776
原文標題:移植RT-Thread到國產(chǎn)芯片HC32L196,原理與方法詳解!
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論