<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[iot - Earth Data Labs]]></title><description><![CDATA[Sensing our World in real-time]]></description><link>https://eadalabs.com/</link><image><url>https://eadalabs.com/favicon.png</url><title>iot - Earth Data Labs</title><link>https://eadalabs.com/</link></image><generator>Ghost 3.41</generator><lastBuildDate>Mon, 23 Mar 2026 20:34:13 GMT</lastBuildDate><atom:link href="https://eadalabs.com/tag/iot/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Getting started with NuttX and Esp32 on MacOS]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>In this post, we will be looking at getting an ESP32 working with NuttX and WIFI networking enabled, using a Mac as the development platform. The ESP hardware is a LOLIN32, but any dev-kit C ESP32 hardware will work fine.</p>
<p>The inspiration for this post is based on Sara Monteiro's</p>]]></description><link>https://eadalabs.com/nuttx-esp32-macos/</link><guid isPermaLink="false">603dc687098a6941c452d838</guid><category><![CDATA[esp32]]></category><category><![CDATA[nuttx]]></category><category><![CDATA[iot]]></category><dc:creator><![CDATA[Ron J]]></dc:creator><pubDate>Sun, 28 Feb 2021 02:54:46 GMT</pubDate><media:content url="https://eadalabs.com/content/images/2021/02/nuttx-esp32-3.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://eadalabs.com/content/images/2021/02/nuttx-esp32-3.png" alt="Getting started with NuttX and Esp32 on MacOS"><p>In this post, we will be looking at getting an ESP32 working with NuttX and WIFI networking enabled, using a Mac as the development platform. The ESP hardware is a LOLIN32, but any dev-kit C ESP32 hardware will work fine.</p>
<p>The inspiration for this post is based on Sara Monteiro's <a href="https://medium.com/the-esp-journal/getting-started-with-esp32-and-nuttx-fd3e1a3d182c">nuttx+esp32 getting started article</a> article, but adapted for MacOS and extended to support WIFI networking configuration.</p>
<h1 id="environmentsetup">Environment Setup</h1>
<p>For the sake of simplicity, I will be using a environment variable to point of the folder used for this project. I am also using <a href="https://fishshell.com/">fish</a> as the default shell.</p>
<pre><code class="language-bash">export NUTTX_SPACE=(realpath ~/projects/iot/nuttxspace/)
</code></pre>
<h2 id="downloadnuttx">Download NuttX</h2>
<p>First step is to checkout the source NuttX code:</p>
<pre><code class="language-bash">cd $NUTTX_SPACE
git clone https://bitbucket.org/nuttx/tools.git
git clone https://github.com/apache/incubator-nuttx.git nuttx
git clone https://github.com/apache/incubator-nuttx-apps.git apps
</code></pre>
<p>Build <a href="https://www.kernel.org/doc/html/latest/kbuild/index.html">kconfig</a> configuration tool.</p>
<pre><code class="language-bash">cd $NUTTX_SPACE/tools/kconfig-frontends
./configure --enable-mconf
make
make install
</code></pre>
<h2 id="bootloader">Bootloader</h2>
<pre><code class="language-bash">mkdir {$NUTTX_SPACE}/esp-bins
curl -L &quot;https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/bootloader-esp32.bin&quot; -o $NUTTX_SPACE/esp-bins/bootloader-esp32.bin
curl -L &quot;https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/partition-table-esp32.bin&quot; -o $NUTTX_SPACE/esp-bins/partition-table-esp32.bin
</code></pre>
<p>Alternatively, building your own version of the boot-loader can be done quite easily, provided you have docker installed.</p>
<pre><code class="language-bash">git clone https://github.com/espressif/esp-nuttx-bootloader.git {$NUTTX_SPACE}/esp-bootloader
docker run --rm -v {$NUTTX_SPACE}/esp-bootloader:/work -w /work espressif/idf:release-v4.3 ./build.sh
</code></pre>
<p>If all works fine, you should be able to see the built files in the out_ folder:</p>
<pre><code class="language-bash">ls -la {$NUTTX_SPACE}/out/
drwxr-xr-x   8 ron  staff    256 28 Feb 10:19 ./
drwxr-xr-x  14 ron  staff    448 28 Feb 10:18 ../
-rw-r--r--   1 ron  staff  23824 28 Feb 10:17 bootloader-esp32.bin
-rw-r--r--   1 ron  staff  18528 28 Feb 10:19 bootloader-esp32c3.bin
-rw-r--r--   1 ron  staff   3072 28 Feb 10:17 partition-table-esp32.bin
-rw-r--r--   1 ron  staff   3072 28 Feb 10:19 partition-table-esp32c3.bin
-rw-r--r--   1 ron  staff  36748 28 Feb 10:17 sdkconfig-esp32
-rw-r--r--   1 ron  staff  33935 28 Feb 10:19 sdkconfig-esp32c3
</code></pre>
<h2 id="espidf">ESP-IDF</h2>
<p>Assuming that you have already installed the ESP-IDF, you should be able to</p>
<pre><code class="language-bash">export IDF_PATH=(realpath ~/projects/iot/esp-idf/)
. $IDF_PATH/export.fish
</code></pre>
<hr>
<h1 id="buildingtheapp">Building the app</h1>
<h2 id="appconfiguration">App Configuration</h2>
<p>Generate the kernel/app configuration for the ESP32 platform.</p>
<pre><code class="language-bash">cd {$NUTTX_SPACE}/nuttx
./tools/configure.sh esp32-devkitc:nsh
</code></pre>
<p>This will create the file <code>.config</code> which contains all the necessary flags for ESP32. For example, this is the generated config for the devkit-C:</p>
<pre><code class="language-bash">CONFIG_ARCH_XTENSA=y
CONFIG_ARCH=&quot;xtensa&quot;
CONFIG_ARCH_CHIP=&quot;esp32&quot;
CONFIG_ARCH_BOARD=&quot;esp32-devkitc&quot;
CONFIG_ARCH_CHIP_ESP32=y
CONFIG_ARCH_FAMILY_LX6=y
CONFIG_XTENSA_CP_INITSET=0x0001
CONFIG_XTENSA_DUMPBT_ON_ASSERT=y
CONFIG_XTENSA_BTDEPTH=50

#
# ESP32 Configuration Options
#
CONFIG_ARCH_CHIP_ESP32WROVER=y
CONFIG_ESP32_DUAL_CPU=y
CONFIG_ESP32_FLASH_4M=y
CONFIG_ESP32_PSRAM_8M=y
CONFIG_ESP32_ESP32DXWDXX=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
</code></pre>
<h2 id="build">Build</h2>
<pre><code class="language-bash">make
</code></pre>
<p>If all goes fine, you should be able to see this at the end of the compilation</p>
<pre><code class="language-bash">AR (create): libboard.a   esp32_boot.o esp32_bringup.o esp32_appinit.o
LD: nuttx
CP: nuttx.hex
CP: nuttx.bin
MKIMAGE: ESP32 binary
esptool.py --chip esp32 elf2image --flash_mode dio --flash_size &quot;4MB&quot; -o nuttx.bin nuttx
esptool.py v3.1-dev
Generated: nuttx.bin (ESP32 compatible)
</code></pre>
<h2 id="flash">Flash</h2>
<p>I am using a Wemos LOLIN32 1.0</p>
<pre><code class="language-bash">make download ESPTOOL_PORT=/dev/cu.SLAB_USBtoUART ESPTOOL_BAUD=115200 ESPTOOL_BINDIR={$NUTTX_SPACE}/esp-bins
</code></pre>
<pre><code class="language-bash">Connecting........_
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: b4:e6:2d:95:b1:05
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 23824 bytes to 14851...
Wrote 23824 bytes (14851 compressed) at 0x00001000 in 1.6 seconds (effective 118.2 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 69...
Wrote 3072 bytes (69 compressed) at 0x00008000 in 0.1 seconds (effective 454.4 kbit/s)...
Hash of data verified.
Compressed 124896 bytes to 52034...
Wrote 124896 bytes (52034 compressed) at 0x00010000 in 4.8 seconds (effective 207.1 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
</code></pre>
<h2 id="connectingtonuttxshell">Connecting to NuttX shell</h2>
<pre><code class="language-bash">screen /dev/cu.SLAB_USBtoUART 115200
</code></pre>
<p>Just write <code>help</code> and you'll should see this:</p>
<pre><code class="language-bash">help usage:  help [-v] [&lt;cmd&gt;]

  .         cd        echo      hexdump   mh        rm        time      xd
  [         cp        exec      kill      mount     rmdir     true
  ?         cmp       exit      ls        mv        set       uname
  basename  dirname   false     mb        mw        sleep     umount
  break     dd        free      mkdir     ps        source    unset
  cat       df        help      mkrd      pwd       test      usleep

Builtin Apps:
  nsh  sh
nsh&gt;
</code></pre>
<p>Voila, that's it for the basic config. Next step is to enable the WIFI connectivity.</p>
<hr>
<h1 id="enablingwifinetworking">Enabling WIFI Networking</h1>
<p>NuttX uses the <a href="https://en.wikipedia.org/wiki/UIP_(micro_IP)">uIP</a> networking stack, unlike ESP-IDF which uses <a href="https://en.wikipedia.org/wiki/LwIP">LWiP</a>.</p>
<h2 id="basicnetworkconfig">Basic Network config</h2>
<p>Enabling WIFI can be done by configuring the nuttx app:</p>
<pre><code class="language-bash">make -C {$NUTTX_SPACE}/nuttx distclean
{$NUTTX_SPACE}/nuttx/tools/configure.sh esp32-devkitc:nsh
make -C {$NUTTX_SPACE}/nuttx menuconfig
</code></pre>
<p>Go to <code>Networking Support</code> and enable it, as well as</p>
<pre><code>    * Networking Support: yes
        * Link layer support
            * Late driver initialization: yes
    * System Type
        * ESP32 Peripheral Selection
            * Wireless: yes
    * RTOS Features
        * Work queue support
            * Generic work notifier
            * High priority (kernel) worker thread
        * Pthread Options
            *  Enable mutex types
    * Device Drivers
        * Wireless Device Support
            * IEEE 802.11 Device Support
</code></pre>
<p>To make it easier to debug, I also enabled the traces from:</p>
<pre><code>    * Build Setup
        * Debug Options
            * Enable Error Output
            * Enable Debug Features
            * Network Debug Features
            * Wireless Debug Features
</code></pre>
<p>After flashing the, the following logs can be seen:</p>
<pre><code class="language-bash">I (266) boot: Disabling RNG early entropy source...
esp32_rng_initialize: Initializing RNG
esp32_net_initialize: B4:E6:2D:95:B1:05
netdev_register: Registered MAC: b4:e6:2d:95:b1:05 as dev: wlan0
I (16) wifi:wifi driver task: 5, prio:253, stack:3584, core=0
I (18) wifi:wifi firmware version: 3cc2254
I (18) wifi:wifi certification version: v7.0
I (18) wifi:config NVS flash: disabled
I (22) wifi:config nano formating: disabled
I (26) wifi:Init data frame dynamic rx buffer num: 32
I (31) wifi:Init management frame dynamic rx buffer num: 32
I (36) wifi:Init management short buffer num: 32
I (40) wifi:Init dynamic tx buffer num: 32
I (44) wifi:Init static rx buffer size: 1600
I (48) wifi:Init static rx buffer num: 10
I (52) wifi:Init dynamic rx buffer num: 32
netdev_ifr_ioctl: cmd: 1794
tcp_callback: flags: 0040
netdev_ifr_ioctl: cmd: 1796
tcp_callback: flags: 0040
netdev_ifr_ioctl: cmd: 1800
tcp_callback: flags: 0040
netdev_ifr_ioctl: cmd: 1818
wlan_ifup: Bringing up: 10.0.0.2
tcp_callback: flags: 0040

NuttShell (NSH) NuttX-10.0.1
nsh&gt; ifconfig
wlan0   Link encap:Ethernet HWaddr b4:e6:2d:95:b1:05 at UP
        inet addr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
</code></pre>
<h2 id="accessingwapi">Accessing WAPI</h2>
<p><a href="https://github.com/vy/wapi">WAPI</a> is a lightweight wrapper for iwconfig, wlanconfig, ifconfig, and route commands, and that's the command we need to use to scan the av available access points.</p>
<p>The first attempt resulted in a failure due to the missing <code>ioctl</code> support.</p>
<pre><code class="language-bash">nsh&gt; wapi scan wlan0
netdev_ifr_ioctl: cmd: 35608
ioctl(SIOCSIWSCAN): 25
ERROR: Process command (scan) failed.
</code></pre>
<p>After enabling the Wireless IOCTL</p>
<pre><code>    * Networking support
        * Network Device Operations
            * Enable Wireless ioctl()
</code></pre>
<p>Unfortunately, at the time of writing (Feb. 2021), one can notice that from the <a href="https://github.com/apache/incubator-nuttx/blob/59a5d038426de9609d386d2ea49f2ed9700bf69c/arch/xtensa/src/esp32/esp32_wlan.c#L1306">esp32_wlan.c</a>, the scan is not currently supported. So, the only possiblity is to connect manually:</p>
<pre><code class="language-bash">wapi psk wlan0 access_point_password 0
wapi essid wlan0 access_point_ssid 0
</code></pre>
<p>From my access point running OpenWRT, I could notice that the ESP32 was connected, and was allocated an IP address. However, from the NSH CLI, the IP address remmained unchanged:</p>
<pre><code class="language-bash">nsh&gt; ifconfig
wlan0   Link encap:Ethernet HWaddr b4:e6:2d:95:b1:05 at UP
        inet addr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
</code></pre>
<p>Also, pinging the device from my Mac laptop to the IP address mentionned on the OpenWRT router, would result in frames beeing dropped (or unanswered) since uIP did not get the correct IP config.</p>
<pre><code class="language-bash">nsh&gt; wlan_rxpoll: ARP frame
arp_arpin: ARP request for IP da01a8c0
</code></pre>
<h2 id="enablingdhcpsupport">Enabling DHCP support</h2>
<p>To enable the DHCP client:</p>
<pre><code>    * Networking Support
        * UDP Networking
            * UDP Networking
            * UDP broadcast Rx support
        * Socket Support
            * Socket options
    * Library Routines
        * NETDB Support
            * DNS Name resolution
    * Application
        * System Libraries and NSH Add-Ons
            * DHCP Address Renewal (NEW)
        * Wireless Libraries and NSH Add-Ons
            * IEEE 802.11 Configuration Library
                * IEEE 802.11 Command Line Tool
</code></pre>
<p>After that, and refering to <a href="https://esp32.com/viewtopic.php?f=2&amp;t=19481">this post on esp32.com</a>, it is possible to enable the DHCP for the network initlization using:</p>
<pre><code>    * Application
        * Network Utilities
            * DHCP client
            * Network initialization
                * IP Address Configuration
                    * Use DHCP to get IP address
                    * Router IPv4 address: 0xc0a80101
</code></pre>
<p>It is quite weird to have to configure the Router IPv4 address, and further more having to do it using hexadecimal (<em>0xc0a80101</em> in my case), but well, that's the only way to get things working.</p>
<p>Unfortunately, that was not enough. After trying to setup the SSID and passkey from WAPI, it always ended-up with errors:</p>
<pre><code class="language-bash">NuttShell (NSH) NuttX-10.0.1
nsh&gt; wapi psk wlan0 my-ap-password 1
netdev_ifr_ioctl: cmd: 35636
nsh&gt; wapi essid wlan0 my-ap-ssid 1
netdev_ifr_ioctl: cmd: 35610
phy_version: 4500, 0cd6843, Sep 17 2020, 15:37:07, 0, 2
wifi_set_intr: cpu_no=0, intr_source=0, intr_num=0, intr_prio=1I (6220) wifi:mode : sta (b4:e6:2d:95:b1:05)
I (6221) wifi:enable tsf
esp_event_post: Event: base=WIFI_EVENT id=2 data=0 data_size=0 ticks=4294967295
I (6231) wifi:Set ps type: 0

I (6597) wifi:new:&lt;3,0&gt;, old:&lt;1,0&gt;, ap:&lt;255,255&gt;, sta:&lt;3,0&gt;, prof:1
I (7249) wifi:state: init -&gt; auth (b0)
I (7256) wifi:state: auth -&gt; assoc (0)
I (7262) wifi:state: assoc -&gt; run (10)
I (7276) wifi:connected with my-ap-ssid, aid = 2, channel 3, BW20, bssid = ee:41:18:0c:53:dd
I (7277) wifi:security: WPA2-PSK, phy: bgn, rssi: -29
I (7278) wifi:pm start, type: 0

esp_event_post: Event: base=WIFI_EVENT id=4 data=0x3ffe5bb0 data_size=44 ticks=4294967295
nsh&gt; I (7301) wifi:AP's beacon interval = 102400 us, DTIM period = 2
</code></pre>
<p>The only way to overcome this issue was to set the SSID and passkey directly in the menu config, under <code>Application -&gt; Network Utilities -&gt; Network initialization -&gt; WAPI Configuration (SSID / Passprhase)</code>. And fortunately, after that, it was possible to the the correct IP address:</p>
<pre><code class="language-bash">nsh&gt; ifconfig
wlan0   Link encap:Ethernet HWaddr b4:e6:2d:95:b1:05 at UP
        inet addr:192.168.1.218 DRaddr:192.168.1.1 Mask:255.255.255.0
</code></pre>
<h2 id="pingingtheinternet">Pinging the Internet</h2>
<p>Unfortunately, even after having the correct IP condiguration, PING would still not work, failing with <code>socket address family unsupported</code>.</p>
<pre><code class="language-bash">nsh&gt; ping baidu.com
dns_recv_response: ID 36690
dns_recv_response: Query 128
dns_recv_response: Error 0
dns_recv_response: Num questions 1, answers 2, authrr 0, extrarr 0
dns_recv_response: Question: type=0001, class=0001
dns_parse_name: Compressed answer
dns_recv_response: Answer: type=0001, class=0001, ttl=0000bf, length=0004
dns_recv_response: IPv4 address: 220.181.38.148
dns_parse_name: Compressed answer
dns_recv_response: Answer: type=0001, class=0001, ttl=0000bf, length=0004
dns_recv_response: IPv4 address: 39.156.69.79
psock_socket: ERROR: socket address family unsupported: 2
socket: ERROR: psock_socket() failed: -106
</code></pre>
<p>The missing link was to enable <code>IPPROTO_ICMP socket support</code>  under <code>Networking Support -&gt; ICMP Networking Support</code></p>
<pre><code class="language-bash">NuttShell (NSH) NuttX-10.0.1
nsh&gt;
nsh&gt; ping baidu.com
sendto_eventhandler: Send ICMP request
sendto_request: Outgoing ICMP packet length: 84 (84)
icmp_poll_eventhandler: flags: 0002
icmp_datahandler: Buffered 81 bytes
icmp_readahead: Received 64 bytes (of 81)
56 bytes from 39.156.69.79: icmp_seq=0 time=40 ms
</code></pre>
<p>Voila, finally, it's working :-)</p>
<p>Also, just in case, I could see some random failures during the ping: <code>up_assert: Assertion failed at file:mm_heap/mm_free.c line: 170 task: ping</code></p>
<hr>
<h1 id="conclusions">Conclusions</h1>
<p>NuttX is definitely a promising solution - especially considering the eco-system that is forming arround it. However, at this stage the ESP32 support is quite limited. But the good news is that Espressif seems to be proactively adding support for their chip, so let's hope that within a few weeks WIFI - and other drivers - will be completely supported.</p>
<p><a href="https://eadalabs.com/nuttx-with-esp32-and-ethernet/">Next step</a> is to try to enable Ethernet on the <a href="http://www.wireless-tag.com/wp-content/uploads/2020/08/WT32-ETH01%E8%A7%84%E6%A0%BC%E4%B9%A6V1.2EN%EF%BC%88%E8%8B%B1%E6%96%87%EF%BC%89.pdf">W32-ETH01</a></p>
<p><img src="https://eadalabs.com/content/images/2021/03/w32-eth01.png" alt="Getting started with NuttX and Esp32 on MacOS"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>