当前位置: 首页 > 工具软件 > NuttX > 使用案例 >

nuttx linux 编译,nuttx系统编译配置及启动流程

孟健
2023-12-01

--------转载请注明出处文中使用的是nuttx-7.17

Nuttx系统编译(主要针对arm体系结构):

编译离不开工具链,而arm工具链是在各体系结构下的Toolchain.defs文件中定义的,arm7/9在nuttx\arch\arm\src\arm文件中,Cortex-M3/M4/M7在nuttx\arch\arm\src\armv7-m文件中,Cortex-M0在nuttx\arch\arm\src\armv6-m文件中。

而编译器选择相关的配置在nuttx\configs\xxx\nsh目录的defconfig文件中定义,同时这个文件会被重命名为.config和该目录下的Make.defs、setenv.sh文件一起复制到根目录下。这一步可以通过在nuttx\tool中执行 ./configure.sh /来完成,其中就是nuttx\configs中的目录名,而是包含上述三个文件的目录。

CONFIG_HOST_LINUX=y定义主机环境

CONFIG_ARCH_ARM=y定义开发板架构

CONFIG_ARCH_CHIP_STM32=y定义芯片厂商

CONFIG_ARCH_CORTEXM3=y定义芯片内核

CONFIG_ARCH_FAMILY="armv7-m"定义芯片的体系结构

CONFIG_ARM_TOOLCHAIN_GNU=y

CONFIG_ARMXXX_TOOLCHAIN?_XXX定义使用的工具链:

CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT=y: NuttX buildroot under Linux or Cygwin

(default)

CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIL=y: Generic GCC ARM EABI toolchain for

Linux

CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIW=y: Generic GCC ARM EABI toolchain for

Windows

以上这些宏定义都辅助Toolchain.defs文件来判断具体使用的交叉工具链。

总之,开始编译前nuttx\configs\xxx\nsh目录中Make.defs、setenv.sh文件被复制到根目录下。setenv.sh文件会将编译工具目录加到系统环境变量中。Make.defs指定了编译相关的选项,同时也指定了链接脚本的路径,该脚本的主要目的是指定了如何把输入文件中的节(sections)映射到输出文件中,并控制输出文件的存储布局。这里的输出文件可以认为就是bin文件。deconfig会重命名为.config文件复制到根目录,编译过程中会根据该文件自动生成nuttx\include\nuttx目录中的config.h文件,该文件中定义了各种宏是系统编译的基础。

NuttX启动流程

本文以stm32的cm3内核为例介绍,cortex-m3内核在上电后,首先会把中断向量表中偏移地址0处的值赋给SP指针,然后把偏移地址04地址(即Reset vector)的值赋给PC进入该函数开始执行。这里用到偏移地址是因为CM3的中断向量表基址是可以通过NVIC中的一个寄存器,称为“向量表偏移寄存器”(0xE000_ED08)来配置的。

要追踪系统的启动流程就必须知道程序的入口,而要知道程序入口只要找到链接脚本就可以,链接脚本目录是通过Make.defs中的变量ARCHSCRIPT指定的即在目录nuttx\configs\XXX\scripts中,

点击(此处)折叠或打开

.text : {

_stext = ABSOLUTE(.);

*(.vectors)

*(.text .text.*)

*(.fixup)

*(.gnu.warning)

*(.rodata .rodata.*)

*(.gnu.linkonce.t.*)

*(.glue_7)

*(.glue_7t)

*(.got)

*(.gcc_except_table)

*(.gnu.linkonce.r.*)

_etext = ABSOLUTE(.);

} > flash

对于CM3核该文件首先加载的是*(.vectors),即中断向量表。该向量表是选择位于nuttx\arch\arm\src\stm32\gnu目录中的stm32_vectors.S中,还是nuttx\arch\arm\src\目录中的up_vectors.c中,这个需要查看nuttx-7.17\arch\arm\src\stm32目录中的Make.defs文件

点击(此处)折叠或打开

ifeq ($(CONFIG_ARMV7M_CMNVECTOR),y)

HEAD_ASRC =

else

HEAD_ASRC = stm32_vectors.S

endif

CMN_UASRCS =

CMN_UCSRCS =

CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S

CMN_ASRCS += up_testset.S vfork.S

CMN_CSRCS = up_assert.c up_blocktask.c up_copyfullstate.c

CMN_CSRCS += up_createstack.c up_mdelay.c up_udelay.c up_exit.c

CMN_CSRCS += up_initialize.c up_initialstate.c up_interruptcontext.c

CMN_CSRCS += up_memfault.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c

CMN_CSRCS += up_releasepending.c up_releasestack.c up_reprioritizertr.c

CMN_CSRCS += up_schedulesigaction.c up_sigdeliver.c up_stackframe.c

CMN_CSRCS += up_systemreset.c up_unblocktask.c up_usestack.c up_doirq.c

CMN_CSRCS += up_hardfault.c up_svcall.c up_vfork.c

ifeq ($(CONFIG_ARMV7M_STACKCHECK),y)

CMN_CSRCS += up_stackcheck.c

endif

ifeq ($(CONFIG_ARMV7M_CMNVECTOR),y)

ifeq ($(CONFIG_ARMV7M_LAZYFPU),y)

CMN_ASRCS += up_lazyexception.S

else

CMN_ASRCS += up_exception.S

endif

CMN_CSRCS += up_vectors.c

endif

通过该文件可以知道如果在.config文件中没有配置CONFIG_ARMV7M_CMNVECTOR宏就会选择stm32_vectors.S,否则选择up_vectors.c,不论如何配置0x04地址对应的__start函数位于nuttx-7.17\arch\arm\src\stm32目录的stm32_start.c文件中

点击(此处)折叠或打开

void __start(void)

{

const uint32_t *src;

uint32_t *dest;

#ifdef CONFIG_ARMV7M_STACKCHECK

/* Set the stack limit before we attempt to call any functions */

__asm__ volatile ("sub r10, sp, %0" : : "r" (CONFIG_IDLETHREAD_STACKSIZE - 64) : );

#endif

/* Configure the UART so that we can get debug output as soon as possible */

stm32_clockconfig();

stm32_fpuconfig();

stm32_lowsetup();

stm32_gpioinit();

showprogress('A');

/* Clear .bss. We'll do this inline (vs. calling memset) just to be

* certain that there are no issues with the state of global variables.

*/

for (dest = _START_BSS; dest < _END_BSS; )

{

*dest++ = 0;

}

showprogress('B');

/* Move the initialized data section from his temporary holding spot in

* FLASH into the correct place in SRAM. The correct place in SRAM is

* give by _sdata and _edata. The temporary location is in FLASH at the

* end of all of the other read-only data (.text, .rodata) at _eronly.

*/

for (src = _DATA_INIT, dest = _START_DATA; dest < _END_DATA; )

{

*dest++ = *src++;

}

showprogress('C');

#ifdef CONFIG_ARMV7M_ITMSYSLOG

/* Perform ARMv7-M ITM SYSLOG initialization */

itm_syslog_initialize();

#endif

/* Perform early serial initialization */

#ifdef USE_EARLYSERIALINIT

up_earlyserialinit();

#endif

showprogress('D');

/* For the case of the separate user-/kernel-space build, perform whatever

* platform specific initialization of the user memory is required.

* Normally this just means initializing the user space .data and .bss

* segments.

*/

#ifdef CONFIG_BUILD_PROTECTED

stm32_userspace();

showprogress('E');

#endif

/* Initialize onboard resources */

stm32_boardinitialize();

showprogress('F');

/* Then start NuttX */

showprogress('\r');

showprogress('\n');

#ifdef CONFIG_STACK_COLORATION

/* Set the IDLE stack to the coloration value and jump into os_start() */

go_os_start((FAR void *)&_ebss, CONFIG_IDLETHREAD_STACKSIZE);

#else

/* Call os_start() */

os_start();

/* Shoulnd't get here */

for (; ; );

#endif

}

完成一系列初始化后调用nuttx\sched\init目录os_start.c中的os_start()函数,进入nutxx内核初始化和启动过程中。

 类似资料: