type
status
date
slug
summary
tags
category
icon
password
Todos
  • 理清PX4固件文件架构
  • 学习CMake用法
  • FreeRTOS
这篇文章尝试梳理上电、烧录、系统初始化、启动操作系统、执行Tasks到飞机起飞的过程,希望能系统性地了解飞控固件、RTOS与STM32H7如何互相搭配、协同工作;除此之外,还将有一些SITL软件仿真的内容。
工程量很大,内容较深,个人理解定有所偏颇,该文将伴随开发过程长期维护、修正、更新。可以利用评论功能一起探究~
似乎一次性记录的有点多了,打算拆成几篇文章,方便检索。

01 · NxtPX4飞控板 & 固件的烧录

师兄的这块板子选用了STM32H743VIH6这片MCU。对于一块刚生产出的NxtPX4飞控板,我们需要借助ST公司的bootloader来烧录hkust_nxt_bootloader,再借助hkust_nxt-v1_bootloader以及QGroundControl来烧录hkust_nxt飞控固件。完成这些步骤后,就可以正式接通电源,启动这块飞控板了。至于固件的编译与调试,参见上一篇文章。
notion image

Cortex-M7 & STM32H743VIH6概览

🎺Core

  • 480MHz ARM Cortex -M7
  • 片内外设
    • FPU
    • NVIC
    • Memory Protect Unit
    • SYstem Control Block
    • System timer
      • SysTick,24位宽的一个计数器,可以给RTOS提供时钟源
    • Integrated instruction and data caches
      • L1 一级片内Cache
notion image
  • 工作模式
    • Tread Mode 线程模式
      • 上电启动后的默认工作模式,用于执行应用程序代码
    • Handler Mode 处理器模式
      • 当Cortex-M7处理器接收到异常时,就会从线程模式切换到处理器模式,这时候会执行异常处理程序或中断服务程序。在该模式中,处理器会以更高的特权级别状态执行,以确保对异常的正常处理;
      • Handler mode 提供了一组特殊的寄存器,用于保存和处理异常相关的上下文信息,例如异常返回地址、堆栈指针和异常状态寄存器。这些寄存器的使用和保存方式在 Cortex-M 处理器的架构中有明确定义。
  • 特权级别
    • Unprivileged
      • 对System Register的访问受到限制
      • 不能使用CPS指令来屏蔽中断
      • 不能访问System Timer、NVIC与System control block这三种片内外设
      • 可以限制程序能够访问的内存与外设
    • Privileged
      • 程序可以使用所有指令,对片内和片上的所有资源拥有访问权
      在线程模式中,我们通过CONTROL Register来设定正在执行的程序的特权级别;在处理器模式下运行的所有程序总是为Privileged特权。只有Privileged特权级别的程序才能够读写CONTROL Register,修改线程模式下运行程序的特权级别。非特权程序可以使用 SVC 指令发起一个特权调用,以将控制权转移给特权程序。
  • Stack
    • 这款处理器有两个完整的降序堆栈 Main Stack 与 Process Stack,入栈时栈顶指针向较低地址方向移动。
PM0253 —— Table 1. Summary of processor mode, execution privilege level, and stack use
PM0253 —— Table 1. Summary of processor mode, execution privilege level, and stack use
  • 片内核心寄存器
notion image
notion image

🎺Memory

  • 代码区、数据区、寄存器和I/O设备同一编址
  • 小端模式
  • 可寻址的内存空间被划分为八个主要块,每个块大小为 512 MB。
notion image

🎺Clock

  • 三组PLL。一组给System Clock(480MHZ max),另外两组给内核时钟
  • 内部时钟
    • 64 MHz HSI clock (Default)
    • 48 MHz RC oscillator
    • 4 MHz CSI clock (低功耗内部时钟)
    • 32 kHz LSI clock
  • 外部时钟
    • HSE clock: 4-50 MHz (generated from an external source) or 4-48 MHz(generated from a crystal/ceramic resonator)
    • LSE clock: 32.768 kHz

🎺Bus

  • 一组 64位宽的AXI(Advanced eXtensible Interface)矩阵总线
    • 在存储方面,挂载了2MB的片上Flash、512KB的SRAM、FMC和QSPI,可以扩展RAM和Flash
  • 两组 32位宽的AHB(Advanced High-performance Bus)矩阵总线
    • 这两个总线上又挂载了部分SRAM
  • 还有192KB的RAM直接连在CPU上面的TCM总线:ITCM&DTCM
    • Used in Critical Real-time task
    • MDMA can be used to load code or data in ITCM or DTCM RAMs.
    •  
notion image
  • SRAM为什么要这样拆开放在不同总线上?
    • F401上只有一组AHB矩阵总线,H7多出来的AXI总线是为了扩展Memory而专门设计。详细参见Cortex-M7示意图,是有一个转额的AXIM拿来连上AXIBus,扩展Memory
    • 只有AXI和一组AHB矩阵总线连到了CPU,还有一条AHB连的是AXI

Cortex-M7 如何启动?

由于硬件设计,通电后MCU从地址0x00000000处开始取指令执行。下文中的BootModes就是用来选择将哪一个地址的代码映射到0x0处,从而实现从指定地址开始执行。映射其实就是对应的意思。事实上存储器本身并不具备地址,将芯片理论上的地址分配给存储器,这就是存储器映射。
在以前 ARM7/ARM9 内核的控制器在复位后,CPU 会从存储空间的绝对地址0x00000000 取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x00000000(PC = 0x00000000) ,同时中断向量表的位置也是固定的。而 Cortex-M7内核复位后的起始地址和中断向量表的位置可以被重映射。
上文中的“🎺Memory”一节中所介绍的存储器对应的地址,即是STM32H7默认的存储器映射关系。下文中介绍的Boot Mode其是一种存储器重映射的过程。将默认的ITM->0x00000000映射关系更改为UserFlash->0x0000 0000 或者 SystemFlash->0x0000 0000,这之后MCU再从0x0000 0000启动。
至于存储器映射是如何实现的,还没有深入了解。

🎺从哪儿启动?——Boot Mode

Boot Address是一个特殊的存储器地址,用于指定上电/复位后执行的第一行代码的位置。引导加载程序负责初始化系统的硬件环境、加载和执行应用程序或操作系统。在stm32H7中,通过BOOTPin和BOOT_ADDxoption bytes来决定Boot Address,可以指定的地址范围是0x0000 0000 到 0x3FFF FFFF,包含了Table7中的代码区和RAM区:
  • 完整的的Flash地址空间
  • 完整的RAM地址空间
  • The System memory bootloader
使用寄存器来存储启动地址给了用户很大的自由度,"BOOT_ADD0 / BOOT_ADD1"可以在复位后修改,以便在下次复位时从任意其他引导地址启动。
notion image
  • BOOT为0时,从BOOT_ADD0寄存器中存储的地址开始执行第一行代码(默认为0x0800 0000,User Falsh Memory Bank1)
  • BOOT为1时,从BOOT_ADD1寄存器中存储的地址开始执行第一行代码(默认为0x1FF0 0000,128KB的System Flash Memory)
  • 当用户指定的启动地址不合法时(超出了可指定的地址范围/指定在Reserved区),系统会从以下两个默认地址开始启动:
    • Boot address 0: User FLASH at 0x0800 0000
    • Boot address 1: ITCM-RAM at 0x0000 0000
  • 当启用 Flash level 2 protection 时,只能从Flash存储器启动。
    • 如果在BOOT_ADD0 / BOOT_ADD1选项字节中已编程的引导地址超出了存储器范围或属于RAM地址范围,则会强制从Flash存储器的地址0x0800 0000处进行默认读取。
在默认情况下,用户编写的应用程序等代码都会存储在User Flash中,选择BOOT0启动将从这段用户书写的代码开始执行——systeminit、启动操作系统、执行系列Task;
如果选择了从BOOT1启动,那么将默认从SystemMemory启动,进行系列systeminit后执行到ST公司开发的Embedded BootLoader。

⚠️如何启动?—— RESET中断

  • RESET中断的优先级是-3(所有中断中的最高优先级)
    • 当复位信号被激活时,处理器的运行停止,可能停在指令的任意一个点上。这意味着正在执行的指令可能无法完成,处理器的状态被重置为初始状态。
    • 当复位信号被取消激活时,处理器的执行将从向量表中复位入口指定的地址重新开始。执行重新以特权模式和线程模式进行。
每当Reset中断被触发时(上电复位,硬件复位和软件复位),Cortex-M7内核要做的事就是读取下面两个32位整数的值:
  • 从 0x00000000 处取出堆栈指针SP的初始值,该值即为栈顶地址
  • 从 0x00000004 处取出程序计数器指针PC的初始值,该值指向复位后执行的第一条指令。
notion image
notion image

什么是DFU模式?

DFU(Device Firmware Update)是一个用于设备固件升级的模式,换句话说,也就是烧录新的应用程序到板子里。较于使用SWD、JTAG来烧录代码,DFU模式的优点是方便、易于使用,无需额外的硬件设备(如STLink)即可进行固件升级。它适用于简单的固件更新和调试。之前我们在Keil里,利用STLink连接到板子上的SWDIO和SCLK的烧录方法可以直接把程序烧录到Flash中去,烧录的目的地址是在Keil5的小魔术棒里设置好的。
DFU模式烧录代码实际上是利用芯片出厂自带的BootLoader实现。换句话说,进入DFU模式其实就是从SystemMemory启动,并执行里面的Embedded BootLoader,利用USB通信来烧写代码。

🎺上电进入DFU模式

  • 按住boot上电(BOOT高电平,默认从System Memory启动),下图说明了这样上电后芯片的工作流程:
notion image
  • 默认的启动位置是从0x1FF0 0000,128KB的System Flash Memory,在这一片区域里,就存储了由ST公司开发的,出厂自带的Embedded BootLoader,它位于 0x1FF0 9800 。换句话说,如果以默认的BOOT1模式启动,就会执行ST公司的BootLoader。
  • H743系列的Embedded BootLoader支持通过IIC、SPI、USART、FDCAN和DFU将引导用户将代码下载到User Flash中(0x8000 0000),可选择的通信方式非常多。在按住这块飞控板的boot键上电后,将以左图所示启动
    • RESET
    • 初始化时钟源头
    • 系统初始化
    • USB、IIC、SPI初始化
    • 循环扫描选择bootloader通信接口

🎺执行程序进入DFU模式

  • 上电后执行已有的固件,我们可以写一个函数来让程序跳转到EmbeddedBootloder(0x1FF0 9800),进入DFU模式。在QGroundControl软件中,就能一键升级PX4固件,或许使用的就是这个方法🤔

烧录bootloader与hkust_nxt固件

生产出一块新板子,我们按住BOOT上电,从system memory,进入DFU模式,烧录hkust_nxt_bootloader到Flash中。虽然有出场自带的bootloader,但为更方便的烧录固件,我们自定义的编写了hkust_nxt_bootloader。

🎺DFU烧录hkust_nxt_bootloader

STM32Cube 软件家族中的 STM32CubeProgrammer 是 STM32 MCU 专用编程工具。它支持通过STLink的SWD/JTAG调试接口对STM32 MCU的片上存储器进行擦除和读写操作;或者通过UART,USB, I2C,SPI,CAN等通信接口,利用出厂时固化在芯片内部的系统bootloader,对STM32 MCU的片上存储器进行擦除和读写操作。
https://blog.csdn.net/Simon223/article/details/104657167

🎺QGC烧录hkust_nxt飞控固件 ✅

  • QGroundControl, (QGC)上提供了一种操作很简单的图形化界面来实现烧录PX4系列周边固件(前提是板子里有px4的bootloader,比如hkust_nxt_bootloader)。只需要启动该软件,进入该界面,用USB连接飞控板即可,详细步骤见下文。

到这里,飞控板上电就能正常运行了。但是飞控固件的烧录其实还有很多细节内容,这就涉及到编译原理以及STM32内存管理的内容了:在编写完代码后,我们需要编写.ld文件来将不同的代码烧录到指定的位置。这部分内容属于下一章节代码编写的内容,故不在此处赘述。
notion image

02 · PX4-Autopilot 体系架构

完整PX4-AutoPilot的软件覆盖面很广,为四个层面提供软件支持:飞控固件Flight Controller、机载电脑Mission Computer、飞行模拟器Simulator、地面控制站Ground Station。位于地面的Ground Station以及机载电脑支持一些高性能计算和控制飞行器飞行的功能,飞控板接收控制信号,并综合传感器数据调控电机,实现飞行器的飞行。
notion image
  • Flight Controller
    • 运行PX4的飞控固件,通常包含了内置的IMU、指南针和磁力计等
  • ESC & Motors
    • 链接到PWM outputs, DroneCAN (支持双向通信) 或其它的电机驱动方式
  • Sensors
    • Distance sensors, barometers, optical flow, barometers, ADSB transponders, etc.) connected via I2C, SPI, CAN, UART etc.
  • 相机或者其它的Payload
    • Cameras can be connected to PWM outputs or via MAVLink
  • Telemetry radios
    • 连接到ground station computer /software
  • RC Control System
    • Manual control
  • Ground station computer typically runs QGroundControl, MAVSDK or ROS.
下面从飞控固件Flight Controller、机载电脑Mission Computer、飞行模拟器Simulator、地面控制站Ground Station四个方面展开讨论

Flight Controller——NxtPt4飞控固件&NuttX😵💫😵💫😵💫

在第一学期的综合设计课程里,我们的四轴飞行器是基于前后台系统实现了各个模块的实现;而这里引入多任务系统,通过一系列任务调度策略与机制来调度执行各项任务;RTOS可以简单认为是功能强大的主控程序,它嵌入在目标代码中,系统复位后首先执行:它负责负责在硬件基础上为应用软件建立一个强大的运行环境,用户的应用程序都是建立在RTOS之上。在这个意义上,RTOS的作用过是为用户提供一台等价的扩展计算机,它比底层硬件更容易编程操作。
RTOS内含一个实时内核,完成最基本却又必不可少的功能:CPU、中断、时钟、I/O等资源的管理,为用户提供一个标准的编程接口;并可以根据各个任务的优先级,合理的在不同任务间分配CPU资源。在此意义上,RTOS的作用相当于系统资源管理器。
经过上面的系列操作后,hkust_nxt飞控固件已经被烧录到了Flash上,并且上电默认从这里开始执行。下面的内容尝试梳理这个飞控固件的代码架构逻辑程序运行逻辑。
整个飞控固件是由NuttX OS这一嵌入式实时操作系统撑起来的。所以下面关于飞控固件的代码架构和程序运行逻辑的研究,本质上也就是对NuttX的研究。
https://nuttx.apache.org/docs/latest/introduction/about.html
Question哭
  • 怎么确定一个app是属于用户态还是内核态?我们引入的bmi088的驱动程序是属于用户态还是内核态?与NuttX自带的一些驱动程序有何区别?

🎺代码架构逻辑

相较于上学期综设里用的前后台系统,NuttX实时操作系统的引入使得代码架构更加的清晰明了。代码编写也围绕着NuttX展开:移植NuttX到STM32、编写适配NuttX的应用程序,包含了硬件、OS内核程序与App应用程序。硬件部分,已经在01 · NxtPX4飞控板 & 固件的烧录」中做出详尽描述。
依目前的理解,结合「微内核 」的RTOS架构,我将代码按下面的思路划分(略去makefile、cmake等文件)
NuttX文档中写这个系统可以被选择编译为微内核,正好H741芯片又是支持特权模式与非特权模式,对应操作系统的内核态和用户态。依然没有找到代码来确定他是否为特权模式。
  • 两个部分(图中虚线框)
    • NuttX部分,位于/platform&/board
    • PX4 Application部分,位于/src
  • 这两部分细分为七层(图中红色/黄色圆角矩形)
    • 硬件抽象层
    • kernel内核
    • 系统调用接口syscall
    • NuttX Subsystem
    • 传感器驱动Drivers
    • 中间层Middleware
    • 应用程序/模组
  • 七层分属两个态(图中蓝色紫色分界线)
    • 前两层属于Kernel-mode内核态
    • 后五层属于User-mode用户态。
 
 
 
notion image
 
这里的Kernel-modeUser-mode对应了前面STM32H7的特权级别Privileged & UnPrivileged,后者能使用的指令是有限的。两态的转换请参考 01· NxtPX4飞控板&固件的烧录
刚开机时,MCU为Kernel-mode内核
编译器是如何知道UnPrivileged程序不能使用哪些程序?如何知道它正在编译的代码的特权级别?
图中每一个绿色和紫色圆角矩形都是完成指定功能的一部分代码/程序。其中紫色的代码/程序代表编写过程与硬件体系架构直接相关;同一个功能,在不同的芯片上由不同的代码实现。绿色的代码/程序则代表编写过程与硬件解耦,通过硬件抽象层提供的接口统一编写代码操纵硬件。
下面的内容将按照代码层级逐一探讨🤔,不过在这之前,有一些需要提前了解的东西:
  • 驱动程序 Drivers
    • 驱动程序比较复杂,在上面的代码逻辑示意图中,出现了三处Drivers
    • 按照所驱动的设备分类,可以分成三种:Character Device(字符型设备)、Block Device(块型设备)与 Specialized Decive。此处的设备既可以是ADC、I2C等外设,也可以是SD卡、显示屏、摄像头等设备。
    • 而驱动某一个设备的代码,是有不同层级的。不同的代码具有不同的运行逻辑(App-logic / OS-logic,对应用户态和内核态)以及与底层芯片的解耦性。这时候,就要将某一个设备的驱动代码分为了三个层级——以MPU6050为例子——配置IIC通信总线相关代码属于Layer.1 的Peripheral Drivers,这需要直接操纵寄存器;使用IIC通信发送/接收字节相关代码属于Layer.2 的IIC Device Drivers;读取MPU6050测得的加速度数据相关代码属于Layer.5 中的Device Drivers。
本文的主要目的是理清代码架构,简要了解原理。至于代码实现细节,参考“嵌入式操作系统笔记”

✨NuttX部分

这里面包含了一个操作系统起到联系上层软件与下层硬件的必要代码。它们均位于/platform与/board
(根目录的/board 实际上是/platform/nuttX/NuttX/nuttx/board中的内容,这一长串路径下装载的代码是NuttX官方为支持的board平台书写的代码。将/borad代码提出到根目录只是为了方便)
Layer1. 硬件抽象层 [Kernel-mode]
这是与具体硬件结合的最紧密的一层,分为两部分。它对板子上的MCU、引脚、所连接的元件做出初始化配置,并向上提供基本函数,是将开发工作从具体硬件中抽离出的第一步。它也是NuttX中最底层的部分。
  • MCU/Soc等C级的外设库函数
    • 直接与MCU打交道,与具体芯片密切相关。用过往开发经验类比,这一层类似于“HAL库”、“标准外设库函数”,而这些库函数是由NuttX提供的
    • 根目录:platform/nuttx/NuttX/nuttx/arch
      • 在这个目录里:
      • /<arc-name> :在arch目录里有众多以「芯片架构」命令的文件夹。NuttX系统支持很多架构的芯片,比如常见的ARM、MIPS、X86等等。对于NxtPX4,这里应该进入到/arm
      • /<arc-name>内的/src/include:这里面就是各种各样片内、片外外设的库函数了,比如默认时钟树配置、gpio等各种外设的初始化。在这个目录下
notion image
  • Peripheral Drivers(Architecture-Related,OS-logic)
    • 调用上面的库函数,设计出一套通用的外设初始化等等与芯片具体体系架构解耦的接口,方便更高层的驱动程序调用。
    • 根目录:platforms/nuttx/NuttX/nuttx/drivers
      • 在这个目录里:
      • /<Peripheral-name>这drivers目录里有各个外设命名的文件夹,调用/arch文件夹里提供的函数,为上层提供与具体硬件架构解耦的通用函数。以i2c_driver为例,提供初始化、总线选择等等接口。
  • 板级的引脚、元件配置
    • 通过简单的config来告诉NuttX:板子的MCU型号、需要用到哪些外接设备、这些设备用了哪些外设、连在哪些针脚上、初始化参数等配置。
    • 位于 board 文件夹内:boards/hkust/nxt-v1,包含了三种config文件
      • Processor architecture specific files (ARM Cortex-7)
      • Chip/SoC specific files (STM32-H743)
      • Board specific configurations (NxtPt4)
notion image
 
notion image
 
 
 
notion image
 
 
 
notion image



Layer2. Kernel 内核 [Kernel-mode]
在PX4的体系中,选用了NuttX这一实时操作系统。这款操作系统采用的是微内核结构。NuttX是一个基于微内核结构的实时操作系统。它被设计成一个可裁剪、可配置的操作系统,具有小巧、可移植性强的特点。NuttX的核心采用了微内核结构,将操作系统的核心功能保持精简,而将更复杂的功能移出内核,以模块或服务的形式在用户空间运行。
NuttX的微内核部分提供了最基本的任务调度、内存管理和进程间通信等核心功能。它负责管理系统资源、提供任务调度、中断处理、设备驱动程序等关键功能。而其他功能如文件系统、网络协议栈、设备驱动和通信协议等则以可插拔的模块或服务的形式运行在用户空间。
一方面,它向下与具体板子的CPU、定时器、中断等结合;另一方面,它向上提供一套与具体硬件解耦、无关的标准API,可以大大简化上层应用的编程。这一层的代码客观上使应用软件与下层硬件环境无关,便于嵌入式系统软件系统的移植。
NuttX与一众RTOS一样,具有足够小的体积以及很好的可裁剪性与灵活性,以便于嵌入到系统资源有限的设备上。在这些系统资源有限的嵌入式设上,它们并不像生活中常见的那样预装操作系统与设备驱动程序。因此,最常见的RTOS应用原则是:将RTOS与上层应用程序捆绑成一个完整的可执行程序,下载到目标系统中;当目标系统启动时,首先引导RTOS执行,再控制管理其它应用软件模块。
  • 任务调度
    • 位于 platform 文件夹内:
      • platforms/nuttx/NuttX/nuttx/sched
      sched是scheduler的缩写,这个文件夹里的装载的是“The files forming core of the NuttX RTOS reside here.” 包括时钟管理、系统启动、中断处理等一个RTOS必备的基本代码。去掉这个目录中的任何一个文件都会导致系统异常运行,甚至无法启动。
      notion image
  • 内存、I/O管理以及文件系统
    • 位于 platform 文件夹内:
      • platforms/nuttx/NuttX/nuttx//mm/fs
内存是嵌入式系统中非常重要的资源,RTOS同样需要内存管理功能,用于对内存资源进行管理和分配。但由于RTOS对实时性的要求,其内存管理的方法更简单快速。
嵌入式设备又有显示屏、键盘、网络等输入输出设备,系统同样需要对这些外围设备进行管理和控制,并提供统一的接口。
嵌入式文件系统作为一个可扩展的模块,能在硬件资源支持的环境下更高效的存储、管理数据。NuttX的文件系统与Linux十分相似,并且还支持配置环境变量。
这一层应该还有更多细节,到时候新开一篇文章仔细研究下。
notion image
(TODO)理清sched目录下的每一个子文件夹是干什么的,有何联系。
  • 相较于生活中常见的通用操作系统,实时操作系统有何特点呢?
    • 强调实时性与确定性:在指定时间内,保证完整任务
    • 强调可嵌入性、可裁剪性:大多数嵌入式设备的系统资源都很有限,要求操作系统能按照需求被灵活的裁剪

Layer3. Syscall [User-mode]
  • NuttX的两种构建模式:
    • 若将NuttX构建为单独的内核(使用CONFIG_BUILD_PROTECTED=yCONFIG_BUILD_KERNEL=y),则将构建此目录。该目录保存了一个用于User-mode应用程序与kernel-mode内核程序之间通信的系统调用接口
      可以使用正则表达式^(/*)*text 来在VScode里排除在注释中的搜索答案。
      ^(/*)*(CONFIG_BUILD_PROTECTED=y|CONFIG_BUILD_KERNEL=y)
    • 在大多数微控制器(MCU)中,NuttX被构建为一个扁平的、单一的可执行映像,其中包含了NuttX实时操作系统和所有应用程序代码。RTOS代码和应用程序在同一个地址空间和相同的内核模式特权下运行。
    • 为了利用某些处理器的安全功能,还支持另一种构建模型:NuttX可以作为一个单独构建的内核模式模块,应用程序可以作为单独构建的用户模式模块添加进来。
  • 什么是Syscall系统调用?
    • 操作系统作为用户和计算机之间的接口,需要向上提供一些简单易用的服务。主要包括命令接口和程序接口。一些系统调用会被封装为库函数更加方便的调用,如果你选择构建“NuttX Libraries”的话,即可使用一些memset、printf等函数。
notion image
在上层的Application进行系统调用的方案是执行一个一个“陷入指令(访管指令)”,这条指令会触发一个中断,此时,MCU将从用户态转为内核态。
在NUttX的这个目录中,所提供的系统调用层是作为从用户态应用程序到内核态RTOS的通信层。从用户模式切换到内核模式是通过软件中断(Software Interrupt,SWI)实现的。不同的制造商对于SWI的实现方式和命名可能不同,1但原理基本相同:在用户模式下执行特殊的指令,导致软件生成的中断。软件生成的中断在内核中被捕获并在内核模式下处理。
  • 位于 platform 文件夹内的 inlcude syscall 文件夹内
    • platforms/nuttx/NuttX/nuttx/include
    • platforms/nuttx/NuttX/nuttx/syscall

Layer4. NuttX Subsystem [User-mode] U
包括音频处理、GUI渲染、硬件加密等等扩展功能,作为Subsystem出现。用到的时候再来填这个坑。

✨PX4 Application部分

依个人目前的理解,整个开发构架是“基于具体硬件(NxtPX4)适配操作系统(NuttX)”与“基于操作系统(NuttX)开发应用程序(PX4)”两部分,分别对应本节所言的“NuttX部分”和“PX4 Application”部分。
PX4能够运行在支持POSIX-API的操作系统上(Linux、macOS、NuttX与QuRT),并且要求系统支持一些实时性的调度策略(比如FIFO)
上面的黄色标题都是基于具体硬件(NxtPX4),进行有关操作系统的开发,均位于/platform(根目录的/board 实际上是/platform/nuttX/NuttX/nuttx/board中的内容)
从下面红色标题部分开始是基于具体操作系统(NuttX)进行的开发,是PX4-AutoPilot在“如何控制飞行器”这一功能上的核心代码了。就像运行在iOS上的“飞书”一般,它们是运行在NuttX这一操作系统上的应用软件。包括了硬件的驱动程序、飞控应用程序、信息交流程序。
Layer5~7的整体架构图如右图所示。它们的代码位于 /src 内。
notion image
 
源代码被拆分为许多相互独立的模块/程序 (图中使用 monospace 字体表示)。 通常来说一个图中的积木块对应一个功能模块。
右图中的箭头表示的是各个模块之间 最重要的 信息流连接。 实际运行时各模块之间信息流的连接数目比图中展示出来的要多很多,且部分数据(比如:配置参数)会被大部分模块访问。The arrows show the information flow for the most important connections between the modules
飞行控制栈是针对自主无人机设计的导航、制导和控制算法的集合。
Layer5. Device Drivers(Architecture- independent,Application-logic) [User-mode]
这一层的驱动程序属于高层的应用程序,与之前提到的驱动程序不同。它类似于把logi鼠标插到电脑的USB口后,提示安装的“logi option+"驱动程序一般,是基于操作系统NuttX开发,而非基于具体飞控板硬件架构开发。
  • 位于 src 文件夹内的driverssrc/drivers
    • 如右图所示,里面有很多元件,比如将控制信号转换为物理机械运动的Actuator、ADC、磁力计、加速度计等
    • 这里为什么会有bootloader?而且看不懂里面的功能是干嘛的🤔
      notion image

Layer6. Middleware [User-mode]
Middleware主要负责信息交流——Message Bus。通过Middleware实现进程之间的信息交流。
在PX4里面,由uORB担当uORB的职责。

Layer7. Flight Stack Application [User-mode]
是用户编写的一些应用程序,比如姿态解算、控制电机油门。这部分代码位于 src 文件夹内的modules中:src/modules,比如这里面的ekf2文件夹里就是姿态解算的代码。
notion image

🎺程序运行逻辑

晕晕的
Scheduling
Task Communication
Interuption

Ground Station——QGroundControl

这部分用做一个简单的积累部分

Simulator——jmavSim

“前面的区域,以后再来探索吧~”

Mission Computer

“前面的区域,以后再来探索吧~”
固件在/board/hkust
extras:放了bootloader
init:板子启动时的初始化参数
驱动硬件——nuttx-config
/bootloader:告诉Nuttx有哪些硬件需要启动
/nsh:里面的deconfig:启动哪些外设
如何指定外设里面的GPIO:/include/board.h
通过/script中的链接文件来指导固件和bootloader的编译,并指定下载到板子上的地址,如何分配flash、qspi
下面上面一层的src放了辅助的启动函数,使用用来拉起具体的硬件。bootloader结束后就会运行init.c
重点看mtd.cpp 写了外部flash的驱动;sdio.c是SD卡功能的实现;timer_config.cpp用来搞PWM波,还用了DMA,有一个驱动电机的协议Dshoot
nuttx把UASRT 映射到tts4,
根目录的/src放了嵌入式相关的驱动drivers,/module放了算法相关的应用,可以把矩阵运算丢到DSP里去
notion image
[CVPR2024]Generate Like Experts: Multi-Stage Font Generation by Incorporating Font Transfer Process into Diffusion ModelsPX4·开发环境搭建
Loading...