7.2 Nuttx 官方文档阅读杂记1

本文最后更新于 2025年5月24日 早上

板级配置+驱动框架+VFS

config file

nuttx的代码结构类似于linux,配置管理也通过Kconfig配置文件来处理,核心的三个配置文件分别为processor arch配置、chip/Soc配置、board配置。
处理器架构配置文件:位于arch/<arch-name>arch-name为对应的处理器架构名称,可以通过配置选项CONFIG_ARCH来选择。进一步,同一处理器架构有许多变体,例如armv7m、armv8m等,每个处理器架构变体有对应的内核实现,例如cortex-m4内核就是基于armv7m实现的,在nuttx中可以通过CONFIG_ARCH_CORTEXM4=y配置项来使能armv7-m支持。

每种处理器架构需要遵循的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<arch-name>/
|-- include/
| |--<chip-name>/
| | `-- (chip-specific header files)
| |--<other-chips>/
| |-- arch.h
| |-- irq.h
| |-- syscall.h
| `-- types.h
`-- src/
|--<chip-name>/
| `-- (chip-specific source files)
|--<other-chips>/
|-- Makefile
`-- (architecture-specific source files)

Chip/SoC配置文件:位于arch/<arch-name>目录中chip特定的子文件夹下,通过CONFIG_ARCH_CHIP选项来配置。一个SoC架构包括处理器内核+芯片特定的中断逻辑+时钟逻辑+GPIO逻辑+内置的外设控制器(UART USB等)等。
board配置文件:位于boards/<arch-name>/<chip-name>/<board-name>,通过CONFIG_ARCH_BOARD配置项来配置。板级配置文件定义了板子上其他的外设,例如led外设、外部外设控制器。其他的板级配置信息可以在该目录下获取Documentation/platforms/<arch>/<chip>/<board>

板级配置目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<board>
|-- include/
| `-- (board-specific header files)
|-- src/
| |-- Makefile (build the board specific drivers)
| `-- (board-specific source files)(board specific drivers)
|-- scripts/
| |-- ld.script
| |-- flash.ld
|-- <config1-dir>
| |-- Make.defs (This makefile fragment provides architecture and tool-specific build options) (Toolchain.defs)
| `-- defconfig (to generate include/nuttx/config.h )(.config)
|-- <config2-dir>
| |-- Make.defs
| `-- defconfig

Nuttx的移植完全依赖于板级配置文件和arch目录下的特定架构的配置文件。

nuttx-drivers

驱动类型
有三种类型的驱动:字符设备驱动、块设备驱动、非标准设备驱动。

字符设备驱动和块设备驱动
通常用设备节点来表示并位于/dev下,可以通过字符设备驱动代理来间接访问块设备驱动,处理逻辑位于bch下,从应用角度看,可以用同一接口访问字符和块设备驱动。
同样存在相反的操作,通过loop设备可以将字符设备转化成块设备访问。

非标准设备驱动(如mtd、 frramebuffer、 eth等)
MTD内存技术驱动
Mtd驱动管理像flash、eeprom等基于内存的设备。mtd类似块设备驱动,比如可以作为设备节点出现在/dev路径下,并且也可以通过字符设备来间接访问。但有一些其他不同的特性,如可以将一个MTD驱动程序堆叠在另一个之上,以扩展较低级MTD驱动程序的功能

Nuttx的驱动设计思想
Nuttx中的驱动机制相对来说比较简单,它并没有提供像Linux系统那样复杂的驱动模型机制,比如Device、Driver、Bus、Class等。Nuttx只是简单的通过驱动注册接口,将驱动注册进文件系统中,并实现file_operations操作函数集,上层应用便能通过标准的系统调用,进而调用到低层的驱动。而底层的驱动又分为了上半部分(upper_half)和下半部分(lower_half)。

1cd568cd2382e0e0ed6f3421bacef0bd.png

上半驱动和下半驱动
nuttx支持许多不同的MCU平台,这些平台有着类似但又不同的内置外设。MCU外设有独一无二的底层寄存器操作,同时又有非常类似的高层抽象。
nuttx通过Upper Half and Lower Half drivers设计来减少代码的重复,上半驱动包括通用的共享驱动,下半驱动负责特定于MCU的部分,通常实现在arch或board层级。共享的设备驱动位于drivers/目录下,

这里需要这个例子 亲自实践下 比如
ADC驱动实例:
bc8e18278a9d20674d500185c3626dad.png

How to develop a driver for NuttX

bus drivers
nuttx明确区分了bus驱动和device驱动,像SPI, PCI, PCMCIA, USB, Ethernet等都属于总线而不是设备。
总线由bus驱动管理,设备驱动使用总线驱动来和设备交互,关系如下:设备驱动->bus驱动->device on bus。

bus驱动和device驱动有以下显著的区别:应用只能和device驱动进行交互而不能与bus驱动交互。应用不能直接使用PCI, PCMCIA, USB, Ethernet, I2C, SPI, or GPIOs,应用只能通过设备驱动来使用PCI, PCMCIA, USB, Ethernet, I2C, or SPI等总线。另外,nuttx不支持用户空间驱动,而linux 是支持的,用的最6的就是英伟达了,来规避gpl 协议。

communication设备
In the case of true buses that support generic devices, the principle is a good one. But there are grey areas too.
CAN can be used as a simple character device, or as a network interface using SocketCAN.
UARTs are communication devices.
communication设备支持基础的p2p模型。spi i2c 等有host/device master/slave模型,凭此可认为它们是总线。

Os component/device driver 章节提供了对各种驱动更详细的介绍
字符设备驱动
如adc
块设备驱动
如sd 卡
特殊设备驱动
I2c
传感器驱动
网络驱动

BMP180气压传感器驱动或INA219模块为例子
todo

nuttx-fs

https://www.jianshu.com/p/887cffbc3e7d

linux VFS通用概念

为什么需要引入 VFS?

  • 解决兼容性问题:没有VFS时,每个文件系统需要单独实现系统调用,导致内核代码冗余且难以扩展。VFS 通过抽象共性与隔离差异,让新文件系统只需实现VFS的接口即可接入内核。
  • 支持特殊文件系统:VFS 不仅能管理磁盘文件系统,还能抽象内存文件系统(如procfs、sysfs)、网络文件系统(如NFS),甚至设备文件(如/dev)。
  • 简化应用开发:应用程序只需调用标准API(如fopen()),无需为每种文件系统编写适配代码。

VFS 的关键设计

  • 四大核心对象:
    • superblock:代表一个已挂载的文件系统实例(如一个磁盘分区)。
    • inode:描述文件的元数据(权限、大小、位置等),唯一标识一个文件。
    • dentry(目录项):缓存目录结构,加速路径解析(如/home/user)。
    • file:表示进程打开的文件,维护读写位置等状态。
  • 统一操作集:通过函数指针表(superblock_operations、inode_operations、file_operations、dentry_operations),将通用操作(如read())映射到具体文件系统的实现。

c441c82c10a8c8922efd113d2d7c91b5.png

文件系统注册和挂载
53d570d82fe5f0c6e974cf3960f8d18b.png

Nuttx vfs

Nuttx包含了一个可选的、可扩展的文件系统,这个文件系统可以完全省略掉,Nuttx不依赖于任何文件系统的存在。

  • 伪根文件系统
    可以通过将CONFIG_NFILE_DESCRIPTOS设置成非零值,来使能这个内存中的伪文件系统。它是一个内存文件系统,因为它不需要任何存储介质或块驱动程序的支持。文件系统内容是通过标准文件系统操作(open, close, read, write, etc.)实时生成的。在这个意义上,它是一个伪文件系统(Linux的/proc也称为伪文件系统)。
    可以通过伪文件系统访问用户提供的任何数据或逻辑。支持对字符设备驱动及块设备驱动节点在伪文件系统任何目录中的内建,不过按照惯例,都习惯放在/dev伪文件系统目录中。

  • 文件系统挂载
    简单的内存文件系统,可通过挂载块设备来扩展,这些块设备提供大容量存储设备支持以实现真正的文件系统访问。Nuttx支持标准的mount()命令,该命令允许块驱动程序将文件系统绑定到伪文件系统中的挂载点上。目前,Nuttx支持VFAT文件系统。

  • 与Linux比较
    从编程的角度来看,Nuttx文件系统看起来与Linux文件系统非常类似,但是,有一个根本的区别:Nuttx根文件系统是一个伪文件系统,而真正的文件系统可以挂载在伪文件系统中;相比之下,在典型的Linux安装中,Linux根文件系统是一个真正的文件系统,伪文件系统挂载在真正的根文件系统中。Nuttx选择的方法,旨在提供从非常小的平台到中等平台等的支持,以便具备更好的可扩展性。

Nuttx 挂载
源码路径 nuttx/fs/mount
核心函数:
int mount(FAR const char *source, FAR const char *target, FAR const char *filesystemtype, unsigned long mountflags, FAR const void *data)
其中,source表示块设备驱动路径,如/dev/emmc,没有则为NULL,target表示挂载点的路径,如/mnt/xxfs,filesystemtype表示文件系统类型,mountflags表示读写权限。

核心逻辑:
mount内部会调用nx_mount,nx_mount中针对不同文件系统类型(如基于块设备的文件系统、基于MTD的文件系统、基于内存的伪文件系统)会不同操作,以基于块设备的文件系统为例:

  1. 调用find_blockdriver函数,查找给出的块设备驱动路径对应的inode节点,以及验证该inode是否为块驱动和是否有对应权限的操作函数。
  2. 调用mount_findfs函数,根据文件系统类型查表得到挂载点操作集mountpt_operations

参考资料

NuttX guides 包括很多nuttx开发相关的参考


7.2 Nuttx 官方文档阅读杂记1
https://leelewin.github.io/p/7cb42fb0052b4788b8e9524b524319a6/
作者
liminglei
发布于
2025年2月20日
许可协议
BY_NC_SA