Table of content
* Introduction
* System packages
* NuttX sources and tools
* Configuration of devkit project, compilation and flash
* Connexion to NSH via (USB) serial
* The ostest and other basic sets (UPDATE)
* The apps examples (UPDATE)
* GPIO (UPDATE)
* SPIflash, SMARTFS and file fsystems (UPDATE)
* TMPFS (UPDATE)
* NSH scripting (UPDATE)
Introduction
Apache NuttX is a POSIX embedded system available on a lot of microcontrollers boards and architectures. After seeing some articles from Lup Yuen Lee, installing and working with NuttX on Bouffalo BL602 and BL604 RISC-V microcontroller boards, I discovered it can be installed on one of my boards. So I tried and managed to install it this evening on my recently acquired 3.5€ ESP32-C3S SoC nodeMCU board. ESP32-C3 is a SoC with RISC-V RV32IMC microcontroller, integrated 2.4GHz WiFi and Bluetooth LTE. The board contains a CH340 serial-USB converter, so it can easily be used/flashed/debugged from a computer. I already made a post about installing ESP-IDF tools and flashing examples on this RISC-V board.
For people that already know Espressif SoCs, here is a table of the power usage of some of their ESP models:
SoC Modem sleep Light sleep mode Deep sleep mode
ESP8266 20 mA 2,000 µA 20 µA
ESP32 20 mA 800 µA 20 µA
ESP32-C3 20 mA 130 µA 5 µA
This article explains the procedure to prepare environment, on Arch Linux in November 2021. This is for x86_64, but should work on ARM too, only RISC-V toolchains are missing on ALARM, can be compiled, by using x86_64 versions of PKGBUILD (riscv32-elf-binutils, riscv64-elf-gcc). You can find the pricompiled binaries in my ArchLinux ARM archives including a little text about the order of compilation (binlib, gcc-bootstrap, newlib, gcc (and optionnaly, gcc and newlib again). Direct link to the three most usefull archives:
* riscv32-elf-binutils-2.36.1-2-armv7h.pkg.tar.xz
* riscv64-elf-gcc-11.1.0-1-armv7h.pkg.tar.xz
* riscv64-elf-newlib-4.1.0-1-any.pkg.tar.xz
Latest GIT version is needed In November 2021 for ESP32-C3, some other RISC-V architectures are already in stable releases. This is followed by an example of flashing and connect to the NSH shell, via serial on USB terminal. The dependencies for Debian based Linux on the official page, some parts could be incomplete. Some aspects of the NuttX, POSIX compatible Filesystem. OStest, GPIO and SPIflash included examples are also shortly described.
↑ System packages
General system dependencies for NuttX:
sudo pacman -S --needed base-devel ncurses5-compat-libs gperf pkg-config \
gmp libmpc mpfr libelf expat picocom uboot-tools util-linux git wget
Just press enter to select all packages on the base-devel
packages group.
You also need some AUR packages, I still use obsolete Pacaur that some say is obsolete:
pacaur -S --needed isl kconfig-frontends genromfs
Sadly for my case, there is currently a conflict between kendryte-toolchain-bin (used for Kendryte K210 RV64 SoC), that depend on isl19, currently conflicting with isl, I uninstalled kendryte-toolchain-bin package, hope it would still work from binary archive with last isl version (0.24 now), didn't managed to compile kendryte-toolchain from sources with it.
Specific RISC-V and ESP32 tools, riscv64 GCC
is used to compile for both RV64 and RV32 architectures, but we need RV32 specific version of binutils
here.:
sudo pacman -S --needed esptool riscv64-elf-gcc riscv32-elf-binutils
Specific RISC-V and ESP32 tools, AUR part (we don't use it in this article, but OpenOCD (Open On-Chip Debugger) can be useful for debugging):
pacaur -S openocd-esp32
You will need a special trick with GNU compilation toolchain, as the current version of NuttX search for riscv64-unknown-elf-*
and Arch Linux call them riscv64-elf-*
(without unknown-
. I just created symlinks in /usr/bin/
. Need root privileges for this (UPDATE: g++ was also needed by some optional examples applications):
sudo bash
for tool in gcc ar ld nm objcopy g++
do
if [ ! -e /usr/bin/riscv64-unknown-elf-${tool} ]; then
ln -s riscv64-elf-${tool} /usr/bin/riscv64-unknown-elf-${tool}
fi
done
Or a more radical solution, to have a link for all existing riscv64-elf-* tools:
sudo bash
cd /usr/bin/
ls riscv64-elf-* | while read bin
do tool=${bin//riscv64-elf-}
if [ ! -e riscv64-unknown-elf-${tool} ]
then
ln -s ${bin} riscv64-unknown-elf-${tool}
fi
done
↑ NuttX sources and tools
Choose a directory where you will install the tools. I choose a directory called nuttx here:
mkdir nuttx
cd nuttx
Some binaries are needed to creating the file system. The booting partition and the partition table. You can compile them by yourself, but I here just chosen to download already compiled ones, I would maybe update this post with compilation process:
wget https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/bootloader-esp32c3.bin
wget https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/partition-table-esp32c3.bin
We will just use bootloader
and partition-table
binaries here, but there is also mcuboot binary in the repository, not sure I will need it later, but I downloaded it to have everything for working in my archives:
wget https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/mcuboot-esp32.bin
NuttX sources are also needed:
git clone https://github.com/apache/incubator-nuttx nuttx
git clone https://github.com/apache/incubator-nuttx-apps apps
Update November 26, version 10.2.0 stable is out this week with ">esp32-c3 available by default, NuttX and NuttX-apps tarballs (list + download link for each version), Warning they are both called nuttx-version.tar.gz (Github is stupid), but they contain respectively incubator-nuttx-nuttx-version
and incubator-nuttx-apps-nuttx-version
files trees
So you can just download them this way to avoid problems:
wget -O incubator-nuttx-nuttx-10.2.0.tar.gz https://github.com/apache/incubator-nuttx/archive/refs/tags/nuttx-10.2.0.tar.gz
wget -O incubator-nuttx-apps-nuttx-10.2.0.tar.gz https://github.com/apache/incubator-nuttx-apps/archive/refs/tags/nuttx-10.2.0.tar.gz
And unarchive them this way:
tar xf incubator-nuttx-nuttx-10.2.0.tar.gz
tar xf incubator-nuttx-apps-nuttx-10.2.0.tar.gz
ln -s incubator-nuttx-nuttx-10.2.0 nuttx
ln -s incubator-nuttx-apps-nuttx-10.2.0 apps
So they can be usable the standard way.
↑ Configuration of devkit project, compilation and flash
We have now all necessaries tools to prepare and install a bootable and functional system. We now enter in the nuttx directory:
cd nuttx
This is time to choose a project. You can see a list of existing ones for ESP32-C3 by typing:
./tools/configure.sh -L | grep esp32c3
esp32c3-devkit:adc
esp32c3-devkit:autopm
esp32c3-devkit:ble
esp32c3-devkit:bmp180
esp32c3-devkit:efuse
esp32c3-devkit:elf
esp32c3-devkit:gpio
esp32c3-devkit:lvgl
esp32c3-devkit:mcuboot_confirm
esp32c3-devkit:module
esp32c3-devkit:nsh
esp32c3-devkit:oneshot
esp32c3-devkit:ostest
esp32c3-devkit:pm
esp32c3-devkit:pwm
esp32c3-devkit:random
esp32c3-devkit:romfs
esp32c3-devkit:rtc
esp32c3-devkit:sotest
esp32c3-devkit:spiflash
esp32c3-devkit:sta_softap
esp32c3-devkit:tickless
esp32c3-devkit:timer
esp32c3-devkit:uid
esp32c3-devkit:usbconsole
esp32c3-devkit:wapi
esp32c3-devkit:watchdog
esp32c3-devkit:watcher
Description of some of them are available in the ESP32 (not C3) specific part of the doc
I choose "usbconsole
" that contain NSH shell and allow to easily connect via USB using ttyUSB
.
./tools/configure.sh -l esp32c3-devkit:usbconsole
Then you can tune some advanced parameters but I didn't used it, looks like ESP32-C3 is generic enough to not have to do anything special depending on board, so can be passed.
make menuconfig
You can quit it by pressing 2 times esc
key.
Time to compile it now. We can compile it with only one CPU core of the computer:
make
Or to compile faster (if you don't have too low memory, else it could be slower), you can can add for example -j4 to use 4 cores or your computer:
make -j4
A long compilation sequence will be printed, ending by the names of the binaries (in colour here). This will be the system to be flashed.
CP: nuttx.hex
CP: nuttx.bin
MKIMAGE: ESP32-C3 binary
esptool.py -c esp32c3 elf2image -fs 4MB -fm dio -ff 40m -o nuttx.bin nuttx
esptool.py v3.2
Generated: nuttx.bin (ESP32-C3 compatible)
For flashing it, you need to first plug your ESP32-C3 based board on your computer, then use esptool.py
flashing command. Parameters needed are chip type, (here an esp32c3), serial port where board is connected to (here ttyUSB0) and transfer rate (921600). Following parameters are the memory address where the binaries will be flashed followed by their names (binary files names are coloured here). So bootloader start at 0
, partition table start at 0x8000
and NuttX binary we just compiled start at 0x10000
. Warning: bootloader and partition-table need to be flashed only when you install for the first time NuttX, the number of write cycle of a flash is limited so only flash what you need:
esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 write_flash \
0x0 ../bootloader-esp32c3.bin \
0x8000 ../partition-table-esp32c3.bin \
0x10000 nuttx.bin
Here is the displayed upload, I coloured (and masked) the MAC address. It can be useful to keep it for later. also colored the flashing of the 3 binaries.
esptool.py v3.2
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: XX:XX:XX:XX:XX:XX
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00004fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x00010000 to 0x00030fff...
Compressed 19120 bytes to 11416...
Wrote 19120 bytes (11416 compressed) at 0x00000000 in 0.5 seconds (effective 324.4 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 69...
Wrote 3072 bytes (69 compressed) at 0x00008000 in 0.1 seconds (effective 433.2 kbit/s)...
Hash of data verified.
Compressed 131264 bytes to 51049...
Wrote 131264 bytes (51049 compressed) at 0x00010000 in 1.9 seconds (effective 542.5 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
Et voilà! The board is flashed (and restarted). In case of errors here, I wrote few lines about most common problems when flashing microcontrollers or FPGA boards using USB on Linux.
Update: I found a new possible problem. If you are already connected to the board by a terminal, the fuse will fail with the following error:
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Just have to quit the terminal application, and restart the previous esptool.py
command, everything should run fine now.
↑ Connexion to NSH via (USB) serial
You can now connect with any serial terminal tool like screen
(yes it has this functionality too), gtkterm
(with a GUI), or lot of others. I used Picocom
as proposed by NuttX documentation.
One of the interesting aspect of NuttX, is that you have an integrated shell called NSH (for NuttShell).
picocom -b 115200 /dev/ttyUSB0
To escape from Picocom you need to type: ctrl-a
then ctrl-x
. Picocom man page contains all the needed shortcuts.
After connecting to the terminal, just type on enter
key to have a NSH prompt, you have an integrated help, with the help
command. See the more detailed NSH commands description in the official documentation.
nsh> help
help usage: help [-v] []
. cd echo hexdump mv set truncate
[ cp exec kill printf sleep uname
? cmp exit ls ps source umount
basename dirname false mkdir pwd test unset
break dd free mkrd rm time usleep
cat df help mount rmdir true xd
Builtin Apps:
nsh sh
NuttX is POSIX, so as any UniX environment, every device can be accessed via files. Like on Linux, you have the 2 important directories; /dev
containing the devices files, and /proc
containing system and devices parameters.
Update: If you are stuck for any reason, you can send a reset signal to the board by pressing two times the F7
function key in the terminal.
nsh> ls
/:
dev/
proc/
nsh> ls -l /dev
/dev:
crw-rw-rw- 0 console
crw-rw-rw- 0 null
crw-rw-rw- 0 ttyS0
crw-rw-rw- 0 zero
nsh> ls -l /proc
/proc:
dr--r--r-- 0 0/
dr--r--r-- 0 1/
-r--r--r-- 0 meminfo
dr--r--r-- 0 fs/
dr--r--r-- 0 self/
-r--r--r-- 0 uptime
-r--r--r-- 0 version
In the included commands, mkrd
allow to create a RAMDISK file system
Update: This was the NuttX version 10.2.0-RC0 c7e604b20b-dirty
after cat /proc/version
.
↑ The ostest and other basic sets (UPDATE)
The sources of the demo programs can be found in boards/risc-v/esp32c3/esp32c3-devkit/src/
subdirectory and the .config settings, that can also be changed with make menuconfig
, for each demo are located in the boards/risc-v/esp32c3/esp32c3-devkit/configs/
directory.
For my second test, I tried esp32c3-devkit:ostest
receipe. The system include a command called ostest
, that try different systems usage, including memory allocation, timers or multithreading.
If you have already compiled a project and try to compile another one you will have an alert:
Already configured!
Please 'make distclean' and try again.
You only need to follow the instruction and make a distclean to be able to compile another one:
make distclean
[...] <- lot of cleaning
./tools/configure.sh -l esp32c3-devkit:ostest
As we already flashed the boot en partition table and number of write cycle of flash are limited (to some thousand of times, look at the flash eprom specification), you can limit the flash to the nuttx.bin part itself:
esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 write_flash \
0x10000 nuttx.bin
You will only be able to see the name of the command by typing help
:
nsh> help
help usage: help [-v] []
[...] <- standard commands
Builtin Apps:
nsh ostest sh
When the ostest finish on this system image, you will see memory used. and the filesystem will have a new directory /var
with a subdirectory /var/mqueue
added.
nsh> ostest
[...] <= lot of tests
barrier_func: Thread 6 done
barrier_test: Thread 5 completed with result=0
barrier_test: Thread 6 completed with result=0
barrier_test: Thread 7 completed with result=0
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena 5d2e0 5d2e0
ordblks 8 8
mxordblk 56710 53ab0
uordblks 5de0 9640
fordblks 57500 53ca0
Final memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena 5d2e0 5d2e0
ordblks 2 8
mxordblk 58ae0 53ab0
uordblks 47f0 9640
fordblks 58af0 53ca0
user_main: Exiting
ostest_main: Exiting with status 0
nsh> ls var/
/var:
mqueue/
As with Linux, you can know the total, used and free memory by displaying the content of /proc/meminfo
. The builtin command free
do the same thing.
nsh> cat /proc/meminfo
total used free largest nused nfree
Umem: 382752 6128 376624 376624 32 1
Among the other tests, some demos that interest me are:
* esp32c3-devkit:gpio
to access to GPIO (general purpose Input/Output) via command line.
* esp32c3-devkit:spiflash
to access the flash disk using NuttX SMART Flash file system via SPI1. The command mksmartfs
can be used to make the FS, and the FS can be mounted the POSIX way (like Linux for example) by typing mount -t smartfs /dev/... /mntpoint
. It add mksmartfs
command and flash_eraseall
and fstest
builtin apps.
* esp32c3-devkit:lvgl
demo, LVGL is a small graphic and GUI library that help to make interfaces in small memory embedded board systems. Demos include drivers for Sitronix ST7735 (262K Color Single-Chip TFT Controller/Driver) and ST7789 SPI displays controllers in esp32c3_st7735.c
and esp32c3_st7789.c
in boards/risc-v/esp32c3/esp32c3-devkit/src/
. I need to figure out how to connect one. Breadboards will help for this test. Another solution is probably to try it using Qemu?? With this demo the RGB led of the board is set to orange. There is a Youtube video of this demo on an ESP32 (Xtensa) version monothread and multithread, side by side. The ESP32-C3 has only one core. The command in the system is called lvgldemo
. Nothing appear on terminal console, so I don't know at all what this demo do. There are some documentation about NuttX and LVGL on the LVGL documentation site. There is also LVGL.academy tutorial site.
↑ The apps examples (UPDATE)
We previously downloaded the git apps repository beside the nuttx repository. The apps, contains examples beyond the basic vital functionalities of the system. These resources can be set in the .config
file (flags starting with CONFIG_EXAMPLES_
) or by using make menuconfig
.
In the menu config the apps are in the last entry. Go down with cursor keys and when you are on the last entry, just press enter:
Then the application configuration submenu will display. Warning, you have generally limited resources on the board, select options with parsimony. The best is to first choose the already prepared set for your platform and then to activate some if they work:
* Cryptographic Library Support contains LibTomCrypt and Mbed TLS Cryptography libraries support.
* The Examples subset contains interesting tools like, audio generator (need external dependencies), uIP web server (implementation on uIP TCP/IP stack, that include a DHCP client), tools to blink LEDs (warning PowerLED needs external dependencies), battery monitor, camera driver, the LVGdemo, pdcurses (a GUI text lib).
* The filesystem utilities contains mkgpt, mkbr (for managing fs), a password file support (need external dependencies) etc... :
* The network utilities contains, a chat tool, a sJSON and CODEC libraries, an FTP client, MQTT-C (a MQTT messages client), and a remote execution server and client.
* The NSH library allow you to tune NSH parameters, including MOTD management, a more heavy and complete Command Line Editor, instead of the minimal readline(), or backslash of characters.
* The System Libraries of NSH add-ons, allow to enable system() interface (and so call of NSH function from C), Terminal Curses control support an hexadecimal file editor, or a minimal CU terminal editor. There are also options to use Emacs, VIM or Ncurses mode interface. Zmodem and GPIO u-Block modem., SPI tools, etc...
* Wireless Libraries and NSH Add-ons, contains Bluetoot and IEEE 802.15.4 applications including both version of "Swiss army knife".
↑ GPIO (UPDATE)
The esp32c3-devkit:gpio
add a command to access to GPIO (general purpose Input/Output) via command line. It can be set in make menuconfig
by Application configuration ---> Examples ---> [*] GPIO driver example
, or by setting the .config
file.
To have GPIO activated:
CONFIG_ESP32C3_GPIO_IRQ=y
# IO Expander/GPIO Support
CONFIG_DEV_GPIO=y
CONFIG_DEV_GPIO_NSIGNALS=1
To have the command example:
CONFIG_EXAMPLES_GPIO=y
CONFIG_EXAMPLES_GPIO_PROGNAME="gpio"
CONFIG_EXAMPLES_GPIO_PRIORITY=100
CONFIG_EXAMPLES_GPIO_STACKSIZE=2048
With this a new gpio command appear, if you type it without arguments, it will help you (-h
argument works too):
nsh> gpio
ERROR: Missing required arguments
USAGE: gpio [-w ] [-o ]
gpio -h
Where:
: The full path to the GPIO pin driver.
-w : Wait for an signal if this is an interrupt pin.
-o : Write this value (0 or 1) if this is an output pin.
-h: Print this usage information and exit.
You can list the available devices (driver path in the help). Here is a long (-l
) listing, and you can see they are character devices files with the initial c:
nsh> ls -l /dev
/dev:
crw-rw-rw- 0 console
crw-rw-rw- 0 gpint0
crw-rw-rw- 0 gpout0
crw-rw-rw- 0 gpout1
crw-rw-rw- 0 null
crw-rw-rw- 0 ttyS0
crw-rw-rw- 0 zero
In the example source boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_gpio.c
, we can see than the pins 1 and 2 are set to the two first gpout
, here gpout0
and gpout1
and that only the pin 9 is used for the interrupts gpint0
:
/* Pin 1 and 2 are used for this example as GPIO outputs. */
#define GPIO_OUT1 1
#define GPIO_OUT2 2
[...]
/* Interrupt pins. GPIO9 is used as an example, any other inputs could be
* used.
*/
#define GPIO_IRQPIN 9
Here is a map of the pins on my board, thanks to J-C. François, licence CC-BY-SA:
The pins 1 and 2 are at the upper left, and the pin 9 at the upper right
The current state of a GPIO can be know by a cat. here for example 0 state (the result is without return carriage so just touch by nsh:
nsh> cat /dev/gpout0
0nsh>
Writing a value 1 to the first pin defined (so pin 1) the example display the current value, then change it and verify its state:
nsh> >gpio -o 1 /dev/gpout0
Driver: /dev/gpout0
Output pin: Value=0
Writing: Value=1
Verify: Value=1
↑ SPIflash, SMARTFS and file systems (UPDATE)
The SPIflash recipe ( esp32c3-devkit:spiflash ), add the commands mksmartfs
and the builtin apps flash_eraseall
and fstest
.
To use fstest
, you need to prepare the fs and mount it.
In the default included commands, mkrd
allow to create a RAMDISK file system. It can be used for tests and avoid to waste flash writing cycles.
The syntax is (help mkrd
to display it):
mkrd usage: mkrd [-m ] [-s ]
Default secteur size is 512 bytes. We can simply create a 10KB RAM disk, so 512×20 = 10240 bytes = 10 kilobytes
bytes, by typing:
mkrd 20
A ramdisk device will appear in /dev
called ram0
. Filesystems are blocks devices (shown by the initial b, c is character device):
nsh> ls -l /dev
/dev:
crw-rw-rw- 0 console
crw-rw-rw- 0 null
brw-rw-rw- 10240 ram0
brw-rw-rw- 983040 smart0
crw-rw-rw- 0 ttyS0
crw-rw-rw- 0 zero
You can also see the smart0
device corresponding to the disk, is also available with the SPIflash recipe. sadly RAM disk isn't supported by smartFS so it can't be formatted as is. VFat is supported, but need to add it at configure time. You can activate TMPFS (see below) that also use RAM, as on Linux, for working on temporary RAM disk.
* SmartFS support can be activated by make menuconfig
in File Systems ---> -*- SMART file system
* smartfs
application can be selected by make menuconfig
in Application Configuration ---> File System Utilities ---> mksmartfs
.
Flags set in .config
, for SMARTFS support:
CONFIG_ESP32C3_SPIFLASH_SMARTFS=y
CONFIG_FS_SMARTFS=y
CONFIG_SMARTFS_ERASEDSTATE=0xff
CONFIG_SMARTFS_MAXNAMLEN=48
# CONFIG_SMARTFS_MULTI_ROOT_DIRS is not set
# CONFIG_SMARTFS_ALIGNED_ACCESS is not set
# CONFIG_FS_PROCFS_EXCLUDE_SMARTFS is not set
And for command utilities:
CONFIG_FSUTILS_MKSMARTFS=y
# CONFIG_NSH_DISABLE_MKSMARTFS is not set
smart0 need to be formated before mounting it. The data will be kept on it after reboot, or flashing a new code.
nsh> mksmartfs /dev/smart0
In POSIX systems, we need to create an empty directory used as a mount point, then mount the partition. The type of filesystem isn't auto-detected, so we need to pass it to mount command here:
mkdir /mnt
mount -t smartfs /dev/smart0 /mnt
It will make a test loop of 100 iterations, of writing and then deleting files in the mountpoint, I put the ouput. If you really want to test the fs you can use it, but you will waste write cycles of the flash :
The commande is:
fstest
Here is a sample of the output, I stopped it by resetting the card (2 times F7
:
=== FILLING 4 =============================
[...]
168. Type[8]: File Name: iJaUkEIwgSG4cAyl8J
169. Type[8]: File Name: FNLd0XaTSYF8TV3YtO
170. Type[8]: File Name: SV0Lrtmigq9Yg4SauoD4f
171. Type[8]: File Name: GJfbQ0bFaowO0ep
[...]
Total file size: 427496
=== DELETING 4 ============================
Deleted some files
Number of files: 215
Number deleted: 108
Directory:
1. Type[8]: File Name: PRMIRHz9ZwgHga
2. Type[8]: File Name: 9LH4Uf67RL4bFXVCykg3
Total file size: 427496
File System:
Block Size: 1024
No. Blocks: 960
Free Blocks: 457
Avail. Blocks: 457
No. File Nodes: 0
Free File Nodes: 457
End of loop memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena 58fb0 58fb0
ordblks 41 57
mxordblk 510a0 510a0
uordblks 77d0 6f40
fordblks 517e0 52070[...]
As I stopped it during the loop the files are still on the fs. Wildcard are not supported by the rm
command.
As we can see with the df
(disk free) command, after deleting some file, this still uses lot of blocks:
nsh> df
Block Number
Size Blocks Used Available Mounted on
1024 960 725 235 /mnt
0 0 0 0 /proc
I used the flash_eraseall
builtin app to erase evrything:
nsh> flash_eraseall /dev/smart0
This remove the files but don't free the blocks. I needed to force a mksmartfs with the option -f to free the blocks:
It removed the files but didn't cleaned the block. I need to format again the device using:
nsh> mksmartfs -f /dev/smart0
Now All the blocks are available again:
nsh> df
Block Number
Size Blocks Used Available Mounted on
1024 960 10 950 /mnt
0 0 0 0 /proc
For example, write a single file to be kept after reboot. we can write the content of the file with cat
or echo
commands for example. I write here a simple sentence this is kept datas
in the test.txt
file, using the file redirection character (>
):
nsh> echo "this is kept datas" >/mnt/test.txt
nsh> df
Block Number
Size Blocks Used Available Mounted on
1024 960 11 949 /mnt
0 0 0 0 /proc
As you can see this took an entire 512 bytes block even if it's an only 18 bytes string file. Every file written use a full block, so try to choose the sector-size when you use mksmartfs
.
After rebooting the device (2 times F7
) or unplug/replug it. You can still see the data on the file. Note that after each reboot, you need to mount afain the filesystem:
nsh> mount -t smartfs /dev/smart0 /mnt
nsh> cat /mnt/test.txt
this is kept datas
Removing files by rm command effectively free the blocks:
nsh> rm test.txt
nsh> df
Block Number
Size Blocks Used Available Mounted on
1024 960 10 950 /mnt
Among the other available file systems in NuttX, there is LittleFS, CNX-Software made an article about it. It is very compact and reliable, but there is no utilies to manage them in applications, need to use libs or code a shell compatible command. The Source Git repository shows an exemple usage in C
By make menuconfig
select Board Selection ---> [*] Mount SPI Flash MTD on bring-up (LittleFS) ---> (X) LittleFS
(Only one file system can be set at a time here), and
In the .config
, if the file sustem is not set for the board:
# CONFIG_ARCH_CHIP_LITEX is not set
# CONFIG_ESP32C3_SPIFLASH_LITTLEFS is not set
or if set: CONFIG_ESP32C3_SPIFLASH_LITTLEFS=y
For the more general LITTLEFS support, by make menuconfig
, in File Systems ---> -*- LITTLEFS File System
(several can be selected in this part).
Options in .config
:
CONFIG_FS_LITTLEFS=y
CONFIG_FS_LITTLEFS_BLOCK_FACTOR=4
CONFIG_FS_LITTLEFS_BLOCK_CYCLE=200
With this setting (after selecting SPIflash), there is a esp32c3flash
device that replace smart0
.
And The smartFS can't be mounted. The error message is a bit erroneous:
nsh> mount -t smartfs /dev/esp32c3flash /mnt
nsh: mount: mount failed: No such device
↑ TMPFS (UPDATE)
If you choose in make menuconfig
the option File Systems -> [*] TMPFS file system
Default TMPFS option in .config
CONFIG_FS_TMPFS=y
CONFIG_FS_TMPFS_BLOCKSIZE=512
CONFIG_FS_TMPFS_DIRECTORY_ALLOCGUARD=64
CONFIG_FS_TMPFS_DIRECTORY_FREEGUARD=128
CONFIG_FS_TMPFS_FILE_ALLOCGUARD=512
CONFIG_FS_TMPFS_FILE_FREEGUARD=1024
You will see an automounted /tmp, it is 512 blocks wide on my board (so 512×512/1024=512/2=256KB of RAM disk. 1 block is used for the file system root directory (mounted in /tmp):
nsh> df Block Number Size Blocks Used Available Mounted on 0 0 0 0 /proc 512 1 1 0 /tmp
TMPfs allow to use the free memory, but don't really use it until your write files inside:
nsh> cat /proc/meminfo
total used free largest nused nfree
Umem: 364464 10016
354448 354448 38 1
I cd
(change directory) in /tmp
here and write a file, it will take one more 512 bytes block and so, 10016 + 512 (block) + 176 (probably some references in filesystem dictionnary) = 10704 bytes of memory will be used. The size of the refs vary it took only 96 bytes on another test.
nsh> cd /tmp
nsh> echo "This is a test" >test
nsh> df
Block Number
Size Blocks Used Available Mounted on
0 0 0 0 /proc
512 2 0 2 /tmp
nsh> cat /proc/meminfo
total used free largest nused nfree
Umem: 364464 10704 353760 353744 42 2
NSH scripting (UPDATE)
You can make simple shell script in NSH. For exemple this one lie exemple test if /dev/ram0
exists and then print the result of the test.
if [ -e /dev/ram0 ]; then echo "ram0 exists"; else echo "no ram0"; fi
Variable can be set
and unset
nsh> set foo bar
nsh> echo $foo
bar
script can be put in files. I didn't found an easy way to put them. The cat
function, seems to be limited to go from one file to another, it doesn't manage STDIN
a standard way, and there is no editor. The only solution is to echo
line by line, or to transfer files by network or serial (need to search more).
If you have activated the TMPFS as explained previously or formatted and mounted SMARTFS partition, you can write files inside. Here is an exempla with TMPFS, available in /tmp
by default I removed the initial nsh>
here, so it will be easier to copy paste:
echo if [ -e /dev/ram0 ] >/tmp/script.sh
echo then >>/tmp/script.sh
echo " echo ram0 exists" >>/tmp/script.sh
echo else >>/tmp/script.sh
echo " echo ram0 doesn't exist" >>/tmp/script.sh
echo fi >>/tmp/script.sh
The >>
symbol means you append lines to an existing file instead of overwriting it.
you can now see the script by a cat:
nsh> cat /tmp/script.sh
if [ -e /dev/ram0 ]
then
echo ram0 exists
else
echo ram0 doesn't exist
fi
And it can be executed by two means, sh
or source
, the difference,
nsh> sh /tmp/script.sh
ram0 doesn't exist
Now, if we create ram0
by using mkrd:
nsh> mkrd 20
nsh> sh /tmp/script.sh
ram0 exists