最近没有分析飞控的代码,转而研究Nuttx实时操作系统的移植。入门一个操作的移植还是挺有难度的,首先代码的框架能理清楚就很不容易了,尤其是Nuttx这种相对小众的操作系统,参考资料比较少,中文资料更少。
因为目的是学习Nuttx的移植,所以不想简单地用pixhawk飞控作为开发板来实验,那样的话总是会局限在现有的代码中。正好手头有块飞凌的开发板,对s5pv210这款mcu又比较熟悉了,避免了学习硬件的麻烦。
从零开始移植到一款新的mcu难度还是挺大的,所以最好在现有的代码中找到一款跟自己使用的相似的作为参考的对象。我就选择了am335x作为依据,先分析下Nuttx的代码结构,和针对am335x需要改的代码。
移植主要关注三个文件夹,即arch\arm\src\am335x arch\arm\src\armv7-a 和 boards\arm\am335x\beaglebone-black三个文件夹。第一个文件夹主要负责am335x的gpio,i2c,irq等片上外设的初始化。第二个文件夹主要负责mmu和运行环境等的初始化。第三个文件夹主要就是开发板相关的初始化了,包括按钮、led、lcd等的外设的初始化。
arch\arm\src\armv7-a文件夹中的arm_head.S文件的_start函数是整个程序的入口函数。下面贴出_start函数的开始的实现:
mov r0, #(PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT)
msr cpsr_c, r0
//关闭mmu和cache
mrc CP15_SCTLR(r0)
bic r0, r0, #(SCTLR_M | SCTLR_C)
bic r0, r0, #(SCTLR_I)
mcr CP15_SCTLR(r0)
//清除页表
ldr r5, .LCppgtable /* r5=phys. page table */
#ifndef CONFIG_ARCH_ROMPGTABLE
mov r0, r5
mov r1, #0
add r2, r0, #PGTABLE_SIZE
.Lpgtableclear:
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
teq r0, r2
bne .Lpgtableclear
#ifdef ARMV7A_PGTABLE_MAPPING
/* If the page table does not lie in the same address space as does the
* mapped RAM in either case. So we will need to create a special
* mapping for the page table.
*
* Load information needed to map the page table. After the ldmia, we
* will have
*
* R1 = The aligned, physical base address of the page table
* R2 = The aligned, virtual base address of the page table
* R3 = The MMU flags to use with the .text space mapping
* R5 = The physical address of the L1 page table (from above)
*
* The value in R1 could have been obtained by simply masking R5.
*/
//加载LCptinfo地址
adr r0, .LCptinfo /* Address of page table description */
ldmia r0, {r1, r2, r3} /* Load the page table description */
/* A single page is sufficient to map the page table */
orr r0, r1, r3 /* OR MMU flags into physical address */
str r0, [r5, r2, lsr #18] /* Map using the virtual address as an index */
#endif
/* Load information needed to map the .text region. After the ldmia, we
* will have:
*
* R1 = Aligned, physical address of the start of the .text region
* R2 = Aligned, virtual address of the start of the .text region
* R3 = MMU flags associated with the .txt region
* R4 = The number of 1MB sections in the mapping
* R5 = The physical address of the L1 page table (from above)
*/
//加载textinfo地址
adr r0, .LCtextinfo /* Address of text info */
ldmia r0, {r1, r2, r3, r4} /* Load the text description */
#ifndef CONFIG_IDENTITY_TEXTMAP
/* Create identity mapping for first MB of the .text section to support
* this start-up logic executing out of the physical address space. This
* identity mapping will be removed by .Lvstart (see below). Of course,
* we would only do this if the physical-virtual mapping is not already
* the identity mapping.
*/
orr r0, r1, r3 /* OR MMU flags into physical address */
str r0, [r5, r1, lsr #18] /* Identity mapping */
#endif
/* Map the entire .text region. We do this before enabling caches so
* we know that the data will be in place in the data cache. We map the
* entire text region because we don't know which parts are needed for
* start-up.
*
* The page table base address is in R5. Each 32-bit page table entry
* maps 1 MB of address space and is indexed by the lower 20 bits of
* the virtual address in R2
*/
add r2, r5, r2, lsr #18 /* R2=Offset page table address */
/* Now loop until each page table entry has been written for the .text
* region.
*/
.Lpgtextloop:
orr r0, r1, r3 /* R0: OR MMU flags into physical address */
subs r4, r4, #1 /* R4: Decrement the section count */
str r0, [r2], #4 /* Save page table entry, increment page table address */
add r1, r1, #(1024*1024) /* R1: Increment the physical address */
bne .Lpgtextloop /* Loop while R4 is non-zero */
#if defined(CONFIG_BOOT_RUNFROMFLASH) && !defined(CONFIG_BOOT_SDRAM_DATA)
/* If we are executing from FLASH, then we will need additional mappings for
* the primary RAM region that holds the .data, .bss, stack, and heap memory.
*
* Here we expect to have:
* r5 = Address of the base of the L1 table
*
* Load information needed to map the .text region. After the ldmia, we
* will have:
*
* R1 = Aligned, physical address of the start of the .text region
* R2 = Aligned, virtual address of the start of the .text region
* R3 = MMU flags associated with the .txt region
* R4 = The number of 1MB sections in the mapping
* R5 = The physical address of the L1 page table (from above)
*/
//加载LCraminfo地址
adr r0, .LCraminfo /* Address of primary RAM info */
ldmia r0, {r1, r2, r3, r4} /* Load the primary RAM description */
add r2, r5, r2, lsr #18 /* R2=Offset page table address */
/* Loop until each page table entry has been written for the primary RAM
* region.
*/
.Lpgramloop:
orr r0, r1, r3 /* R0: OR MMU flags into physical address */
subs r4, r4, #1 /* R4: Decrement the section count */
str r0, [r2], #4 /* Save page table entry, increment page table address */
add r1, r1, #(1024*1024) /* R1: Increment the physical address */
bne .Lpgramloop /* Loop while R4 is non-zero */
#endif /* CONFIG_BOOT_RUNFROMFLASH && !CONFIG_BOOT_SDRAM_DATA */
#endif /* CONFIG_ARCH_ROMPGTABLE */
其中的LCppgtable、LCptinfo、LCtextinfo、LCraminfo在后面都有定义,这里我整理出来
LCppgtable->待整理
LCptinfo->PGTABLE_BASE_PADDR和PGTABLE_BASE_VADDR->AM335X_OCMCO_PADDR和AM335X_0CMC0_VADDR->(AM335X_0CMC0_PSECTION+AM335X_0CMC0_OFFSET)->(0X40300000+0X00000000)
LCtextinfo->NUTTX_TEXT_PADDR和NUTTX_TEXT_VADDR->(CONFIG_RAM_START&0XFFF00000)->(0X8a000000&0xfff00000)
LCraminfo->NUTTX_RAM_PADDR和NUTTX_RAM_VADDR->
arm_head.S文件主要完成内存相关的初始化后,接着就是bl arm_data_initialize和bl arm_boot完成其它的初始化。
arch\arm\src\am335x文件夹中的内容都是跟mcu相关的,很多很细的东西,现在暂时不分析,等到移植成功后再分析。
boards\arm\am335x\beaglebone-black文件夹中,
configs下lcd和nsh分别都有一个defconfig文件,该文件是在make config时的配置文件,根据选择的不同的模式会复制对应的defconfig文件到.config文件中。
include文件夹中主要是board.h文件。该文件定义了led和button的引脚。
scripts文件夹中有Make.defs和sdram.ld文件。由名称可知,分别是makefile文件和链接脚本文件。makefile文件就是指定编译用到的各个文件。
sdram.ld文件中,主要的代码是
MEMORY
{
isram (W!RX) : ORIGIN = 0x402F0400, LENGTH = 63K
ocmc0 (W!RX) : ORIGIN = 0x40300000, LENGTH = 64K -16K
ddr (W!RX) : ORIGIN = 0x8a000000, LENGTH = 512M - 160M
}
这个地址的指定和上面的_start函数的地址对应上就能理解整个内存分布情况了。说明的是isram和ocmc0是am335x内部自带的内存的地址,移植的时候要注意自己采用的mcu是否有这块地址,或者对应的地址是多少。
大体的框架分析差不多了,下面就是得动手移植了。
静待佳音,我移植成功了再分享一下具体的移植过程及移植代码。
有兴趣的小伙伴可以联系我 qq:530655014
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)