Debugging ESP32 with JTAG Adapter on Linux

Although Espressif’s website provides detailed instructions, this post offers a quick overview on steps required to setup a JTAG debugger adapter for ESP32 NodeMCU development board on Linux platform.


JTAG (Joint Test Action Group) is a useful interface for debugging and programming electronic devices such as microcontrollers and digital signal processors for several reasons:

  1. Non-Intrusive: JTAG is a non-intrusive interface, meaning it can be used to test and debug a device without affecting its normal operation. It provides a way to access the internal circuitry of a device, which is typically not accessible through other interfaces.
  2. Boundary Scan: JTAG includes a feature called boundary scan that allows designers to test and debug connections on printed circuit boards (PCBs). The boundary scan feature allows to test and diagnose problems with individual components or connection.
  3. In-System Programming: JTAG can be used to program a device while it is still mounted on a PCB or other system, which is known as in-system programming. This can be useful for updating firmware or debug device without needing to remove it from the system.
  4. Standardized Protocol: JTAG uses a standardized protocol defined by the IEEE 1149.1 standard, which ensures compatibility between devices and tools from different manufacturers.
  5. Semi-hosting: Provides a access to Host Resources, redirect “printf” or access to files on the host system as if they were on the local device, making it easier to test and debug software that relies on file input/output.
  6. Low-Cost: JTAG is a low-cost interface that is widely available on many microcontrollers and other electronic devices. This makes it a popular choice for developers and engineers who need to test and debug electronic systems.


  1. Linux host machine, in my case Linux Mint 21.1 distribution is adopted, but any modern Linux distribution should work.
  2. OpenOCD compatible JTAG debugger hadware, in my case FT2232D that was left over from a previous plug computer project.
    Reference design for this JTAG interface and connection schematics:
  3. Esp32 NodeMCU development board:

Setup OpenOCD

Because the version of OpenOCD available in this Linux release is outdated and lacks Xtensa support, install the latest release from the official repository:

For detailed instruction on howto build and install OpenOCD:

~/esp32$ git clone openocd-code
Cloning into 'openocd-code'...
remote: Enumerating objects: 77625, done.
Resolving deltas: 100% (64682/64682), done. 

Run “./bootstrap” when building from the git repository

~/esp32$ cd openocd-code/
~/esp32/openocd-code$ ./bootstrap
+ aclocal --warnings=all
+ libtoolize --automake --copy
+ autoconf --warnings=all
libjaylink/ installing 'build-aux/depcomp'
Bootstrap complete. Quick build instructions:
./configure ....

Now we can set some build options like hardware interface support, verbosity, installation directories and disable/enable other features.

~/esp32/openocd-code$ ./configure --enable-ftdi
checking for makeinfo... no
configure: WARNING: Info documentation will not be built.
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
OpenOCD configuration summary
MPSSE mode of FTDI based devices        yes
ST-Link Programmer                      yes (auto)
TI ICDI JTAG Programmer                 yes (auto)
Keil ULINK JTAG Programmer              yes (auto)
Altera USB-Blaster II Compatible        yes (auto)
Bitbang mode of FT232R based devices    yes (auto)
Versaloon-Link JTAG Programmer          yes (auto)
TI XDS110 Debug Probe                   yes (auto)
CMSIS-DAP v2 Compliant Debugger         yes (auto)
OSBDM (JTAG only) Programmer            yes (auto)
eStick/opendous JTAG Programmer         yes (auto)
Olimex ARM-JTAG-EW Programmer           yes (auto)
Raisonance RLink JTAG Programmer        yes (auto)
USBProg JTAG Programmer                 yes (auto)
Espressif JTAG Programmer               yes (auto)
CMSIS-DAP Compliant Debugger            no
Nu-Link Programmer                      no
Cypress KitProg Programmer              no
Altera USB-Blaster Compatible           yes (auto)
ASIX Presto Adapter                     yes (auto)
OpenJTAG Adapter                        yes (auto)
Linux GPIO bitbang through libgpiod     no
SEGGER J-Link Programmer                no
Bus Pirate                              yes (auto)
Use Capstone disassembly framework      yes (auto)

Then make and install as usual, be careful about conflicts with existing OpenOCD installation, remove or add prefix/suffix to the new OpenOCD executable.

~/esp32/openocd-code$ make -j16
~/esp32/openocd-code$ sudo make install

Add udev rules:

~/esp32/openocd-code$ nano /etc/udev/rules.d/10-ft2322D_jtag.rules
UBSYSTEMS=="usb", ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666"

Add user to dialout group:

~/esp32/openocd-code$ sudo usermod -aG dialout $USER

JTAG connections:

ESP32 pinJTAG pin#J6
3V3VTRef (3.3V)1
Esp32 to JTAG connections
Sheevaplug JTAG pinout

Detailed description for JTAG configuration can be found on this page:

For ESP32 pinout refer to this page:

OpenOCD Configuration and Testing

Now if we run openocd binary we will se somethink like this:

~/esp32/bare_v1$ openocd 
Open On-Chip Debugger v0.11.0-esp32-20221026 (2022-10-26-14:47)
Licensed under GNU GPL v2
For bug reports, read
embedded:startup.tcl:28: Error: Can't find openocd.cfg
in procedure 'script' 
at file "embedded:startup.tcl", line 28
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Error: Debug Adapter has to be specified, see "adapter driver" command
embedded:startup.tcl:28: Error: 
in procedure 'script' 
at file "embedded:startup.tcl", line 28

This error, because of unknown adapter. We need to instruct OpenOCD about our hardware interface and target. This can be done by creating a configuration file named ‘esp32_jtag.cfg’ with next settings:

# FT2232D JTAG Adapter Configuration 
adapter driver ftdi
ftdi device_desc "SheevaPlug JTAGKey FT2232D B"
ftdi vid_pid 0x9e88 0x9e8f
ftdi channel 0
ftdi layout_init 0x0608 0x0f1b
ftdi layout_signal nTRST -data 0x0200 -noe 0x0100
ftdi layout_signal nSRST -data 0x0800 -noe 0x0400

# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they
# do not relate to OpenOCD trying to read from a memory range without physical
# memory being present there), you can try lowering this.
# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz
# if CPU frequency is 160MHz or 240MHz.
adapter speed 1000

# flash 3.3 V for ESP32-WROOM-32 

# Load esp32 target configuration
source [find target/esp32.cfg]

You can find a list of available interfaces and targets in the ‘openocd-code/tcl’ folder.

Running JTAG debugger

After launching the debugger, we should see something like this:

~/esp32$ openocd -f esp32_jtag.cfg
Open On-Chip Debugger 0.12.0+dev-00078-gfc30feb51 (2023-03-11-15:26)
Licensed under GNU GPL v2
For bug reports, read
force hard breakpoints
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 1000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : starting gdb server for esp32.cpu0 on 3333
Info : Listening on port 3333 for gdb connections
Info : Set GDB target to 'esp32.cpu0'

Open your favorite telnet console on localhost at port 4444

~$ telnet localhost 4444
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> help

Brief command list:

help [command_name]Show full command help; command can be multiple tokens. (command valid any time)
versionshow program version (command valid any time)
reset [run|halt|init]Reset all targets into the specified mode. Default reset mode is run, if not given.
halt [milliseconds]request target to halt, then wait up to the specified number of milliseconds (default 5000) for it to complete
targets [target]change current default target (one parameter) or prints table of all targets (no parameters) (command valid any time)
flash banksDisplay table with information about flash banks. (command valid any time)
reg [(number|name)]
reg [(value|’force’)]
display (reread from target with “force”) or set a register; with no arguments, displays all registers and their values
resume [address]resume target execution from current PC or address
scan_chainprint current scan chain configuration (command valid any time) script
shutdownClose the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option
error is used, OpenOCD will return a non-zero exit code to the parent process.
If user types CTRL-C or kills OpenOCD, the command shutdown will be automati-
cally executed to cause OpenOCD to exit.
arm semihosting [‘enable’|’disable’]Set the base directory for semihosting I/O.DEPRECATED! use arm activate support for semihosting operations
arm semihosting_basedir [dir]set the base directory for semihosting I/O operations
arm semihosting_fileio [‘enable’|’disable’]activate support for semihosting fileio operations
arm semihosting_redirect (disable | tcp [‘debug’|’stdio’|’all’])redirect semihosting IO
initInitializes configured targets and servers. Changes command mode from CONFIG to EXEC. Unless ‘noinit’ is called, this command is called automatically at the end of startup. (command valid any time)

RTL-SDR decoding digital voice

Another great tool for RTL dongle is “Digital Speech Decoder”:
Installation instructions:

# Save to wave file
$ socat stdout udp-listen:7355 | dsd -i - -w voice.wav

# Real-time voice decoding
$ socat stdout udp-listen:7355 | padsp dsd -i -

# Command line variant
rtl_fm -f 430.785M -M fm -s 70K -r 48K -E dc | padsp dsd -fr -i -

Rewritten decoder library:

Siglent oscilloscope USB connection Linux and Python

Simple way to connect Siglent Oscilloscope to your Linux PC is PyVisa package and USB interface.
Install PyVisa lib for python:

Add permission for USB oscilloscope device:

$ sudo nano /etc/udev/rules.d/99-siglent.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="f4ed", ATTR{idProduct}=="ee3a", MODE="0666"

Python code to list connected devices and query for name:

import pyvisa

rm = pyvisa.ResourceManager('@py')
res_list = rm.list_resources()
for res in res_list:
    dev = rm.open_resource(res)

Output looks like this:

Siglent Technologies,SDS1202X-E,SDS1EDED3R1234,1.3.2

Screen capture command “SCDP” fall into some sort of packet structure error in “pyvisa-py” implementation.
Issue on this thread:
And this one:

Hmm…. not fully compatible USB interface. Similar issue for RIGOL oscilloscopes.

Low cost Logic Level Analyzer on Linux.

FT232R USB UART IC provides really cheap device, capable to sample about 10Mhz for 8 digital channels. This FTDI IC can be found on many embedded solutions like Arduino boards and many other development boards, primary acts as USB to serial UART converter. Another way to use this IC is Logic Signal Analyzer. Linux OS is required for control GUI and signal visualization / decoding. For this purpose install developed by sigrok.

List of supported hardware can be found at this link:

For example connecting IR receiver, taken from old set-top box to the FTDI module permits infrared signal visualization from any TV remote controller.

FT232R datasheet:

IR receiver datasheet:

Find more details on Bit-Bang operating mode:

Libftdi programming documentation:

Python libftdi programming example:

Arduino ATMega and PulseView solution works with 2Mhz or 4Mhz samplerate:

More about Logic Sniffers:

Linux from scratch

How to easily cross-build custom Linux Distribution entirely from source code. Normally it is not an easy task, because you have to deal with lot of different aspects of software development and integration; from infinite configuration options to the strange compiler errors. From hardware specifications to the device drivers and file-systems, I/O console, Task scheduler and almost everything is involved. So, all of this is not simple, but buildroot project may help us. This fantastic tool is able to solve many really complex and boring tasks. – “Buildroot is a simple, efficient and easy to use tool to generate embedded Linux systems through cross-compilation.”

# My host build system is:
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.3 LTS
Release:	18.04
Codename:	bionic

This is an example on how to build LinuxOS for Olimex low cost board with 64MB RAM and 450Mhz CPU.

$ git clone git:// buildroot_mx23
Cloning into 'buildroot_mx23'...
remote: Enumerating objects: 351177, done.
remote: Counting objects: 100% (351177/351177), done.
remote: Compressing objects: 100% (111770/111770), done.
remote: Total 351177 (delta 245634), reused 342867 (delta 237974)
Receiving objects: 100% (351177/351177), 74.68 MiB | 1.50 MiB/s, done.
Resolving deltas: 100% (245634/245634), done.

Get the list of all configured boards:

 $ make list-defconfigs
Built-in configs:
  aarch64_efi_defconfig               - Build for aarch64_efi
  acmesystems_aria_g25_128mb_defconfig - Build for acmesystems_aria_g25_128mb
  acmesystems_aria_g25_256mb_defconfig - Build for acmesystems_aria_g25_256mb
  acmesystems_arietta_g25_128mb_defconfig - Build for acmesystems_arietta_g25_128mb
  acmesystems_arietta_g25_256mb_defconfig - Build for acmesystems_arietta_g25_256mb
  amarula_a64_relic_defconfig         - Build for amarula_a64_relic
  amarula_vyasa_rk3288_defconfig      - Build for amarula_vyasa_rk3288
  andes_ae3xx_defconfig               - Build for andes_ae3xx
  arcturus_ucls1012a_defconfig        - Build for arcturus_ucls1012a
  arcturus_ucp1020_defconfig          - Build for arcturus_ucp1020
  armadeus_apf27_defconfig            - Build for armadeus_apf27
  armadeus_apf28_defconfig            - Build for armadeus_apf28
  armadeus_apf51_defconfig            - Build for armadeus_apf51
  arm_foundationv8_defconfig          - Build for arm_foundationv8
  arm_juno_defconfig                  - Build for arm_juno
  asus_tinker_rk3288_defconfig        - Build for asus_tinker_rk3288
  at91sam9260eknf_defconfig           - Build for at91sam9260eknf
  at91sam9g20dfc_defconfig            - Build for at91sam9g20dfc
  at91sam9g45m10ek_defconfig          - Build for at91sam9g45m10ek
  at91sam9rlek_defconfig              - Build for at91sam9rlek
  at91sam9x5ek_defconfig              - Build for at91sam9x5ek
  at91sam9x5ek_dev_defconfig          - Build for at91sam9x5ek_dev
  at91sam9x5ek_mmc_defconfig          - Build for at91sam9x5ek_mmc
  at91sam9x5ek_mmc_dev_defconfig      - Build for at91sam9x5ek_mmc_dev
  atmel_sama5d27_som1_ek_mmc_dev_defconfig - Build for atmel_sama5d27_som1_ek_mmc_dev
  atmel_sama5d2_xplained_mmc_defconfig - Build for atmel_sama5d2_xplained_mmc
  atmel_sama5d2_xplained_mmc_dev_defconfig - Build for atmel_sama5d2_xplained_mmc_dev
  atmel_sama5d3xek_defconfig          - Build for atmel_sama5d3xek
  atmel_sama5d3_xplained_defconfig    - Build for atmel_sama5d3_xplained
  atmel_sama5d3_xplained_dev_defconfig - Build for atmel_sama5d3_xplained_dev
  atmel_sama5d3_xplained_mmc_defconfig - Build for atmel_sama5d3_xplained_mmc
  atmel_sama5d3_xplained_mmc_dev_defconfig - Build for atmel_sama5d3_xplained_mmc_dev
  atmel_sama5d4_xplained_defconfig    - Build for atmel_sama5d4_xplained
  atmel_sama5d4_xplained_dev_defconfig - Build for atmel_sama5d4_xplained_dev
  atmel_sama5d4_xplained_mmc_defconfig - Build for atmel_sama5d4_xplained_mmc
  atmel_sama5d4_xplained_mmc_dev_defconfig - Build for atmel_sama5d4_xplained_mmc_dev
  bananapi_m1_defconfig               - Build for bananapi_m1
  bananapi_m2_plus_defconfig          - Build for bananapi_m2_plus
  bananapi_m2_ultra_defconfig         - Build for bananapi_m2_ultra
  bananapi_m64_defconfig              - Build for bananapi_m64
  bananapro_defconfig                 - Build for bananapro
  beagleboardx15_defconfig            - Build for beagleboardx15
  beagleboneai_defconfig              - Build for beagleboneai
  beaglebone_defconfig                - Build for beaglebone
  beaglebone_qt5_defconfig            - Build for beaglebone_qt5
  beelink_gs1_defconfig               - Build for beelink_gs1
  chromebook_snow_defconfig           - Build for chromebook_snow
  ci20_defconfig                      - Build for ci20
  csky_gx6605s_defconfig              - Build for csky_gx6605s
  cubieboard2_defconfig               - Build for cubieboard2
  engicam_imx6qdl_icore_defconfig     - Build for engicam_imx6qdl_icore
  engicam_imx6qdl_icore_qt5_defconfig - Build for engicam_imx6qdl_icore_qt5
  engicam_imx6qdl_icore_rqs_defconfig - Build for engicam_imx6qdl_icore_rqs
  engicam_imx6ul_geam_defconfig       - Build for engicam_imx6ul_geam
  engicam_imx6ul_isiot_defconfig      - Build for engicam_imx6ul_isiot
  freescale_imx28evk_defconfig        - Build for freescale_imx28evk
  freescale_imx6dlsabreauto_defconfig - Build for freescale_imx6dlsabreauto
  freescale_imx6dlsabresd_defconfig   - Build for freescale_imx6dlsabresd
  freescale_imx6qsabreauto_defconfig  - Build for freescale_imx6qsabreauto
  freescale_imx6qsabresd_defconfig    - Build for freescale_imx6qsabresd
  freescale_imx6sxsabresd_defconfig   - Build for freescale_imx6sxsabresd
  freescale_imx7dsabresd_defconfig    - Build for freescale_imx7dsabresd
  freescale_imx8mmevk_defconfig       - Build for freescale_imx8mmevk
  freescale_imx8mqevk_defconfig       - Build for freescale_imx8mqevk
  freescale_imx8qxpmek_defconfig      - Build for freescale_imx8qxpmek
  freescale_p1025twr_defconfig        - Build for freescale_p1025twr
  freescale_t1040d4rdb_defconfig      - Build for freescale_t1040d4rdb
  freescale_t2080_qds_rdb_defconfig   - Build for freescale_t2080_qds_rdb
  friendlyarm_nanopi_a64_defconfig    - Build for friendlyarm_nanopi_a64
  friendlyarm_nanopi_neo2_defconfig   - Build for friendlyarm_nanopi_neo2
  friendlyarm_nanopi_neo_plus2_defconfig - Build for friendlyarm_nanopi_neo_plus2
  galileo_defconfig                   - Build for galileo
  grinn_chiliboard_defconfig          - Build for grinn_chiliboard
  grinn_liteboard_defconfig           - Build for grinn_liteboard
  hifive_unleashed_defconfig          - Build for hifive_unleashed
  imx23evk_defconfig                  - Build for imx23evk
  imx6-sabreauto_defconfig            - Build for imx6-sabreauto
  imx6-sabresd_defconfig              - Build for imx6-sabresd
  imx6-sabresd_qt5_defconfig          - Build for imx6-sabresd_qt5
  imx6slevk_defconfig                 - Build for imx6slevk
  imx6sx-sdb_defconfig                - Build for imx6sx-sdb
  imx6ulevk_defconfig                 - Build for imx6ulevk
  imx6ulpico_defconfig                - Build for imx6ulpico
  imx7dpico_defconfig                 - Build for imx7dpico
  imx7d-sdb_defconfig                 - Build for imx7d-sdb
  imx8mmpico_defconfig                - Build for imx8mmpico
  imx8mpico_defconfig                 - Build for imx8mpico
  lafrite_defconfig                   - Build for lafrite
  lego_ev3_defconfig                  - Build for lego_ev3
  licheepi_zero_defconfig             - Build for licheepi_zero
  linksprite_pcduino_defconfig        - Build for linksprite_pcduino
  minnowboard_max_defconfig           - Build for minnowboard_max
  minnowboard_max-graphical_defconfig - Build for minnowboard_max-graphical
  mx25pdk_defconfig                   - Build for mx25pdk
  mx51evk_defconfig                   - Build for mx51evk
  mx53loco_defconfig                  - Build for mx53loco
  mx6cubox_defconfig                  - Build for mx6cubox
  mx6sx_udoo_neo_defconfig            - Build for mx6sx_udoo_neo
  mx6udoo_defconfig                   - Build for mx6udoo
  nanopi_m1_defconfig                 - Build for nanopi_m1
  nanopi_m1_plus_defconfig            - Build for nanopi_m1_plus
  nanopi_neo_defconfig                - Build for nanopi_neo
  nexbox_a95x_defconfig               - Build for nexbox_a95x
  nitrogen6sx_defconfig               - Build for nitrogen6sx
  nitrogen6x_defconfig                - Build for nitrogen6x
  nitrogen7_defconfig                 - Build for nitrogen7
  nitrogen8m_defconfig                - Build for nitrogen8m
  odroidxu4_defconfig                 - Build for odroidxu4
  olimex_a10_olinuxino_lime_defconfig - Build for olimex_a10_olinuxino_lime
  olimex_a13_olinuxino_defconfig      - Build for olimex_a13_olinuxino
  olimex_a20_olinuxino_lime2_defconfig - Build for olimex_a20_olinuxino_lime2
  olimex_a20_olinuxino_lime_defconfig - Build for olimex_a20_olinuxino_lime
  olimex_a20_olinuxino_micro_defconfig - Build for olimex_a20_olinuxino_micro
  olimex_a33_olinuxino_defconfig      - Build for olimex_a33_olinuxino
  olimex_a64_olinuxino_defconfig      - Build for olimex_a64_olinuxino
  olimex_imx233_olinuxino_defconfig   - Build for olimex_imx233_olinuxino
  openblocks_a6_defconfig             - Build for openblocks_a6
  orangepi_lite2_defconfig            - Build for orangepi_lite2
  orangepi_lite_defconfig             - Build for orangepi_lite
  orangepi_one_defconfig              - Build for orangepi_one
  orangepi_one_plus_defconfig         - Build for orangepi_one_plus
  orangepi_pc2_defconfig              - Build for orangepi_pc2
  orangepi_pc_defconfig               - Build for orangepi_pc
  orangepi_pc_plus_defconfig          - Build for orangepi_pc_plus
  orangepi_plus_defconfig             - Build for orangepi_plus
  orangepi_prime_defconfig            - Build for orangepi_prime
  orangepi_r1_defconfig               - Build for orangepi_r1
  orangepi_win_defconfig              - Build for orangepi_win
  orangepi_zero_defconfig             - Build for orangepi_zero
  orangepi_zero_plus2_defconfig       - Build for orangepi_zero_plus2
  pandaboard_defconfig                - Build for pandaboard
  pc_x86_64_bios_defconfig            - Build for pc_x86_64_bios
  pc_x86_64_efi_defconfig             - Build for pc_x86_64_efi
  pine64_defconfig                    - Build for pine64
  pine64_sopine_defconfig             - Build for pine64_sopine
  qemu_aarch64_virt_defconfig         - Build for qemu_aarch64_virt
  qemu_arm_versatile_defconfig        - Build for qemu_arm_versatile
  qemu_arm_versatile_nommu_defconfig  - Build for qemu_arm_versatile_nommu
  qemu_arm_vexpress_defconfig         - Build for qemu_arm_vexpress
  qemu_arm_vexpress_tz_defconfig      - Build for qemu_arm_vexpress_tz
  qemu_csky610_virt_defconfig         - Build for qemu_csky610_virt
  qemu_csky807_virt_defconfig         - Build for qemu_csky807_virt
  qemu_csky810_virt_defconfig         - Build for qemu_csky810_virt
  qemu_csky860_virt_defconfig         - Build for qemu_csky860_virt
  qemu_m68k_mcf5208_defconfig         - Build for qemu_m68k_mcf5208
  qemu_m68k_q800_defconfig            - Build for qemu_m68k_q800
  qemu_microblazebe_mmu_defconfig     - Build for qemu_microblazebe_mmu
  qemu_microblazeel_mmu_defconfig     - Build for qemu_microblazeel_mmu
  qemu_mips32r2el_malta_defconfig     - Build for qemu_mips32r2el_malta
  qemu_mips32r2_malta_defconfig       - Build for qemu_mips32r2_malta
  qemu_mips32r6el_malta_defconfig     - Build for qemu_mips32r6el_malta
  qemu_mips32r6_malta_defconfig       - Build for qemu_mips32r6_malta
  qemu_mips64el_malta_defconfig       - Build for qemu_mips64el_malta
  qemu_mips64_malta_defconfig         - Build for qemu_mips64_malta
  qemu_mips64r6el_malta_defconfig     - Build for qemu_mips64r6el_malta
  qemu_mips64r6_malta_defconfig       - Build for qemu_mips64r6_malta
  qemu_nios2_10m50_defconfig          - Build for qemu_nios2_10m50
  qemu_or1k_defconfig                 - Build for qemu_or1k
  qemu_ppc64_e5500_defconfig          - Build for qemu_ppc64_e5500
  qemu_ppc64le_pseries_defconfig      - Build for qemu_ppc64le_pseries
  qemu_ppc64_pseries_defconfig        - Build for qemu_ppc64_pseries
  qemu_ppc_g3beige_defconfig          - Build for qemu_ppc_g3beige
  qemu_ppc_mac99_defconfig            - Build for qemu_ppc_mac99
  qemu_ppc_mpc8544ds_defconfig        - Build for qemu_ppc_mpc8544ds
  qemu_ppc_virtex_ml507_defconfig     - Build for qemu_ppc_virtex_ml507
  qemu_riscv32_virt_defconfig         - Build for qemu_riscv32_virt
  qemu_riscv64_virt_defconfig         - Build for qemu_riscv64_virt
  qemu_sh4eb_r2d_defconfig            - Build for qemu_sh4eb_r2d
  qemu_sh4_r2d_defconfig              - Build for qemu_sh4_r2d
  qemu_sparc64_sun4u_defconfig        - Build for qemu_sparc64_sun4u
  qemu_sparc_ss10_defconfig           - Build for qemu_sparc_ss10
  qemu_x86_64_defconfig               - Build for qemu_x86_64
  qemu_x86_defconfig                  - Build for qemu_x86
  qemu_xtensa_lx60_defconfig          - Build for qemu_xtensa_lx60
  qemu_xtensa_lx60_nommu_defconfig    - Build for qemu_xtensa_lx60_nommu
  raspberrypi0_defconfig              - Build for raspberrypi0
  raspberrypi0w_defconfig             - Build for raspberrypi0w
  raspberrypi2_defconfig              - Build for raspberrypi2
  raspberrypi3_64_defconfig           - Build for raspberrypi3_64
  raspberrypi3_defconfig              - Build for raspberrypi3
  raspberrypi3_qt5we_defconfig        - Build for raspberrypi3_qt5we
  raspberrypi4_defconfig              - Build for raspberrypi4
  raspberrypi_defconfig               - Build for raspberrypi
  riotboard_defconfig                 - Build for riotboard
  rock64_defconfig                    - Build for rock64
  roseapplepi_defconfig               - Build for roseapplepi
  s6lx9_microboard_defconfig          - Build for s6lx9_microboard
  sheevaplug_defconfig                - Build for sheevaplug
  snps_aarch64_vdk_defconfig          - Build for snps_aarch64_vdk
  snps_arc700_axs101_defconfig        - Build for snps_arc700_axs101
  snps_archs38_axs103_defconfig       - Build for snps_archs38_axs103
  snps_archs38_haps_defconfig         - Build for snps_archs38_haps
  snps_archs38_hsdk_defconfig         - Build for snps_archs38_hsdk
  snps_archs38_vdk_defconfig          - Build for snps_archs38_vdk
  socrates_cyclone5_defconfig         - Build for socrates_cyclone5
  solidrun_clearfog_defconfig         - Build for solidrun_clearfog
  solidrun_clearfog_gt_8k_defconfig   - Build for solidrun_clearfog_gt_8k
  solidrun_macchiatobin_mainline_defconfig - Build for solidrun_macchiatobin_mainline
  solidrun_macchiatobin_marvell_defconfig - Build for solidrun_macchiatobin_marvell
  stm32f429_disco_defconfig           - Build for stm32f429_disco
  stm32f469_disco_defconfig           - Build for stm32f469_disco
  stm32mp157c_dk2_defconfig           - Build for stm32mp157c_dk2
  toradex_apalis_imx6_defconfig       - Build for toradex_apalis_imx6
  ts4900_defconfig                    - Build for ts4900
  ts5500_defconfig                    - Build for ts5500
  ts7680_defconfig                    - Build for ts7680
  wandboard_defconfig                 - Build for wandboard
  warp7_defconfig                     - Build for warp7
  warpboard_defconfig                 - Build for warpboard
  zynq_microzed_defconfig             - Build for zynq_microzed
  zynqmp_zcu106_defconfig             - Build for zynqmp_zcu106
  zynq_zc706_defconfig                - Build for zynq_zc706
  zynq_zed_defconfig                  - Build for zynq_zed

Select Olimex i.mx233 board configuration:

$ make olimex_imx233_olinuxino_defconfig
# configuration written to /home/iwi/Documents/buildroot_mx23/.config

Now just build and wait. That’s all.

$ make

INFO: hdimage(sdcard.img): adding partition 'u-boot' (in MBR) from '' ...
INFO: hdimage(sdcard.img): adding partition 'kernel' (in MBR) from 'boot.vfat' ...
INFO: hdimage(sdcard.img): adding partition 'rootfs' (in MBR) from 'rootfs.ext2' ...
INFO: hdimage(sdcard.img): writing MBR

Successful build looks like this, otherwise please check carefully your host system pre-requisites:

The first build may take some time to download all the required source code, build cross-compiler and all host system tools and libraries, than you can build just newly selected packages, but hacking with tool-chain options, requires clean rebuild of everything.

# Insert SD card and unmount all auto-mounted partitions
$ umount /dev/sdX2
$ umount /dev/sdX3

# Write image file to SD card
$ sudo dd if=output/images/sdcard.img of=/dev/sdX bs=1M
97517568 bytes (98 MB, 93 MiB) copied, 12.0944 s, 8.1 MB/s

# Flush all disks buffers

Default board configuration provides Linux OS with minimal set of features and programs tailored for embedded systems. This lightweight Linux system provides excellent starting point for any smart IoT device.

U-Boot 2017.11 (Dec 07 2019 - 04:29:38 +0100)

CPU:   Freescale i.MX23 rev1.4 at 454 MHz
DRAM:  64 MiB
No arch specific invalidate_icache_all available!
__led_init: failed requesting GPIO59!
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   Net Initialization Skipped
No ethernet found.
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
** Unable to read file boot.scr **
reading uImage   
5292296 bytes read in 1640 ms (3.1 MiB/s)
Booting from mmc ...
reading imx23-olinuxino.dtb
10286 bytes read in 29 ms (345.7 KiB/s)
## Booting kernel from Legacy Image at 42000000 ...
   Image Name:   Linux-4.19.2
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    5292232 Bytes = 5 MiB
   Load Address: 42000000
   Entry Point:  42000000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 41000000
   Booting using the fdt blob at 0x41000000
   Loading Kernel Image ... OK
   Loading Device Tree to 43b75000, end 43b7a82d ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.19.2 (iwi@nqdev) (gcc version 8.3.0 (Buildroot 2020.02-git-00204-g2ca0accc21)) #1 Sat Dec 7 04:31:14 CET 2019
[    0.000000] CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=0005317f
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] OF: fdt: Machine model: i.MX23 Olinuxino Low Cost Board
[    0.000000] Memory policy: Data cache writeback
[    0.000000] random: get_random_bytes called from start_kernel+0x84/0x474 with crng_init=0
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 16256
[    0.000000] Kernel command line: console=ttyAMA0,115200 root=/dev/mmcblk0p3 rw rootwait
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 46644K/65536K available (7200K kernel code, 633K rwdata, 2364K rodata, 364K init, 7454K bss, 18892K reserved, 0K cma-reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xc4800000 - 0xff800000   ( 944 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0x(ptrval) - 0x(ptrval)   (7202 kB)
[    0.000000]       .init : 0x(ptrval) - 0x(ptrval)   ( 364 kB)
[    0.000000]       .data : 0x(ptrval) - 0x(ptrval)   ( 634 kB)
[    0.000000]        .bss : 0x(ptrval) - 0x(ptrval)   (7455 kB)
[    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] Running RCU self tests
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] clocksource: mxs_timer: mask: 0xffff max_cycles: 0xffff, max_idle_ns: 911346093 ns
[    0.000000] Console: colour dummy device 80x30
[    0.000000] Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar
[    0.000000] ... MAX_LOCKDEP_SUBCLASSES:  8
[    0.000000] ... MAX_LOCK_DEPTH:          48
[    0.000000] ... MAX_LOCKDEP_KEYS:        8191
[    0.000000] ... CLASSHASH_SIZE:          4096
[    0.000000] ... MAX_LOCKDEP_ENTRIES:     32768
[    0.000000] ... MAX_LOCKDEP_CHAINS:      65536
[    0.000000] ... CHAINHASH_SIZE:          32768
[    0.000000]  memory used by lock dependency info: 4655 kB
[    0.000000]  per task-struct memory footprint: 1536 bytes
[    0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 21474836475000000ns
[    0.070000] Calibrating delay loop... 226.09 BogoMIPS (lpj=1130496)
[    0.070000] pid_max: default: 32768 minimum: 301
[    0.070000] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.070000] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.080000] CPU: Testing write buffer coherency: ok
[    0.090000] Setting up static identity map for 0x40008400 - 0x40008458
[    0.100000] devtmpfs: initialized
[    0.140000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.140000] futex hash table entries: 256 (order: 1, 11264 bytes)
[    0.150000] pinctrl core: initialized pinctrl subsystem
[    0.160000] NET: Registered protocol family 16
[    0.170000] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.320000] Serial: AMBA PL011 UART driver
[    0.320000] 80070000.serial: ttyAMA0 at MMIO 0x80070000 (irq = 17, base_baud = 0) is a PL011 rev2
[    0.530000] console [ttyAMA0] enabled
[    0.640000] mxs-dma 80004000.dma-apbh: initialized
[    0.660000] mxs-dma 80024000.dma-apbx: initialized
[    0.670000] SCSI subsystem initialized
[    0.680000] usbcore: registered new interface driver usbfs
[    0.690000] usbcore: registered new interface driver hub
[    0.690000] usbcore: registered new device driver usb
[    0.700000] pps_core: LinuxPPS API ver. 1 registered
[    0.710000] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <>
[    0.710000] PTP clock support registered
[    0.720000] Advanced Linux Sound Architecture Driver Initialized.
[    0.740000] clocksource: Switched to clocksource mxs_timer
[    1.790000] NET: Registered protocol family 2
[    1.800000] tcp_listen_portaddr_hash hash table entries: 128 (order: 0, 5120 bytes)
[    1.810000] TCP established hash table entries: 1024 (order: 0, 4096 bytes)
[    1.820000] TCP bind hash table entries: 1024 (order: 3, 36864 bytes)
[    1.820000] TCP: Hash tables configured (established 1024 bind 1024)
[    1.830000] UDP hash table entries: 256 (order: 2, 20480 bytes)
[    1.840000] UDP-Lite hash table entries: 256 (order: 2, 20480 bytes)
[    1.850000] NET: Registered protocol family 1
[    1.860000] RPC: Registered named UNIX socket transport module.
[    1.870000] RPC: Registered udp transport module.
[    1.870000] RPC: Registered tcp transport module.
[    1.880000] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    1.910000] Initialise system trusted keyrings
[    1.910000] workingset: timestamp_bits=30 max_order=14 bucket_order=0
[    2.020000] NFS: Registering the id_resolver key type
[    2.030000] Key type id_resolver registered
[    2.030000] Key type id_legacy registered
[    2.040000] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[    2.100000] jitterentropy: Initialization failed with host not compliant with requirements: 2
[    2.110000] Key type asymmetric registered
[    2.120000] Asymmetric key parser 'x509' registered
[    2.120000] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 248)
[    2.130000] io scheduler noop registered (default)
[    2.140000] io scheduler mq-deadline registered
[    2.140000] io scheduler kyber registered
[    2.160000] 8006c000.serial: ttyAPP0 at MMIO 0x8006c000 (irq = 147, base_baud = 1500000) is a 8006c000.serial
[    2.170000] mxs-auart 8006c000.serial: Found APPUART 3.0.0
[    2.210000] libphy: Fixed MDIO Bus: probed
[    2.220000] usbcore: registered new interface driver asix
[    2.230000] usbcore: registered new interface driver ax88179_178a
[    2.240000] usbcore: registered new interface driver cdc_ether
[    2.240000] usbcore: registered new interface driver smsc95xx
[    2.250000] usbcore: registered new interface driver net1080
[    2.260000] usbcore: registered new interface driver cdc_subset
[    2.260000] usbcore: registered new interface driver zaurus
[    2.270000] usbcore: registered new interface driver cdc_ncm
[    2.280000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    2.280000] usbcore: registered new interface driver usb-storage
[    2.300000] imx_usb 80080000.usb: Linked as a consumer to regulator.1
[    2.310000] ci_hdrc ci_hdrc.0: EHCI Host Controller
[    2.320000] ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1
[    2.360000] ci_hdrc ci_hdrc.0: USB 2.0 started, EHCI 1.00
[    2.380000] hub 1-0:1.0: USB hub found
[    2.390000] hub 1-0:1.0: 1 port detected
[    2.410000] stmp3xxx-rtc 8005c000.rtc: rtc core: registered 8005c000.rtc as rtc0
[    2.420000] i2c /dev entries driver
[    2.440000] stmp3xxx_rtc_wdt stmp3xxx_rtc_wdt: initialized watchdog with heartbeat 19s
[    2.450000] mxs-mmc 80010000.ssp: 80010000.ssp supply vmmc not found, using dummy regulator
[    2.460000] mxs-mmc 80010000.ssp: Linked as a consumer to regulator.0
[    2.500000] mxs-mmc 80010000.ssp: initialized
[    2.510000] random: fast init done
[    2.530000] imx23-pinctrl 80018000.pinctrl: pin SSP1_DETECT already requested by 80010000.ssp; cannot claim for leds
[    2.540000] imx23-pinctrl 80018000.pinctrl: pin-65 (leds) status -22
[    2.540000] imx23-pinctrl 80018000.pinctrl: could not request pin 65 (SSP1_DETECT) from group led_gpio2_1.0  on device 80018000.pinctrl
[    2.560000] leds-gpio leds: Error applying setting, reverse things back
[    2.560000] leds-gpio: probe of leds failed with error -22
[    2.580000] mxs-dcp 80028000.dcp: Failed to register sha1 hash!
[    2.590000] mxs-dcp: probe of 80028000.dcp failed with error -22
[    2.610000] usbcore: registered new interface driver usbhid
[    2.610000] usbhid: USB HID core driver
[    2.630000] mmc0: host does not support reading read-only switch, assuming write-enable
[    2.650000] mmc0: new high speed SDHC card at address aaaa
[    2.680000] NET: Registered protocol family 17
[    2.690000] mmcblk0: mmc0:aaaa SU16G 14.8 GiB
[    2.700000] Key type dns_resolver registered
[    2.720000] registered taskstats version 1
[    2.730000] Loading compiled-in X.509 certificates
[    2.750000]  mmcblk0: p1 p2 p3
[    2.840000] stmp3xxx-rtc 8005c000.rtc: setting system clock to 1970-01-01 00:00:51 UTC (51)
[    2.850000] cfg80211: Loading compiled-in X.509 certificates for regulatory database
[    2.890000] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
[    2.900000] ALSA device list:
[    2.900000]   No soundcards found.
[    2.910000] uart-pl011 80070000.serial: no DMA platform data
[    2.920000] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
[    2.930000] cfg80211: failed to load regulatory.db
[    2.950000] EXT4-fs (mmcblk0p3): mounting ext2 file system using the ext4 subsystem
[    3.000000] EXT4-fs (mmcblk0p3): mounted filesystem without journal. Opts: (null)
[    3.010000] VFS: Mounted root (ext2 filesystem) on device 179:3.
[    3.020000] devtmpfs: mounted
[    3.040000] Freeing unused kernel memory: 364K
[    3.040000] This architecture does not have kernel memory protection.
[    3.050000] Run /sbin/init as init process
[    3.350000] EXT4-fs (mmcblk0p3): re-mounted. Opts: block_validity,barrier,user_xattr
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting mdev... OK
Initializing random number generator: OK
Saving random seed: [   12.930000] random: dd: uninitialized urandom read (512 bytes read)
Starting network: OK

Welcome to Buildroot
buildroot login: 

Login is “root”, without password.

# Customize user prompt, save to "~/.profile" 
$ nano ~/.profile
PS1="\\u@\\h:\\w$ "

Directory listing for binaries

root@buildroot:/bin$ ls
arch           dnsdomainname  linux64        nuke           sh
ash            dumpkmap       ln             pidof          sleep
base64         echo           login          ping           stty
busybox        egrep          ls             pipe_progress  su
cat            false          lsattr         printenv       sync
chattr         fdflush        mkdir          ps             tar
chgrp          fgrep          mknod          pwd            touch
chmod          getopt         mktemp         resume         true
chown          grep           more           rm             umount
cp             gunzip         mount          rmdir          uname
cpio           gzip           mountpoint     run-parts      usleep
date           hostname       mt             sed            vi
dd             kill           mv             setarch        watch
df             link           netstat        setpriv        zcat
dmesg          linux32        nice           setserial

root@buildroot:/sbin$ ls
arp                init               makedevs           setconsole
blkid              insmod             mdev               start-stop-daemon
devmem             ip                 mkdosfs            sulogin
fdisk              ipaddr             mke2fs             swapoff
freeramdisk        iplink             mkswap             swapon
fsck               ipneigh            modprobe           switch_root
fstrim             iproute            nameif             sysctl
getty              iprule             pivot_root         syslogd
halt               iptunnel           poweroff           tc
hdparm             klogd              reboot             udhcpc
hwclock            ldconfig           rmmod              uevent
ifconfig           loadkmap           route              vconfig
ifdown             losetup            run-init           watchdog
ifup               lsmod              runlevel

root@buildroot:/usr/bin$ ls
[            du           killall      nproc        sha512sum    unlink
[[           eject        last         nslookup     shred        unlzma
ar           env          ldd          od           sort         unlzop
awk          expr         less         openvt       strings      unxz
basename     factor       logger       passwd       svc          unzip
bc           fallocate    logname      paste        svok         uptime
bunzip2      find         lsof         patch        tail         uudecode
bzcat        flock        lspci        printf       tee          uuencode
chrt         fold         lsscsi       readlink     telnet       vlock
chvt         free         lsusb        realpath     test         w
cksum        fuser        lzcat        renice       tftp         wc
clear        getconf      lzma         reset        time         wget
cmp          head         lzopcat      resize       top          which
crontab      hexdump      md5sum       seq          tr           who
cut          hexedit      mesg         setfattr     traceroute   whoami
dc           hostid       microcom     setkeycodes  truncate     xargs
deallocvt    id           mkfifo       setsid       ts           xxd
diff         install      mkpasswd     sha1sum      tty          xz
dirname      ipcrm        nl           sha256sum    uniq         xzcat
dos2unix     ipcs         nohup        sha3sum      unix2dos     yes

root@buildroot:/usr/sbin$ ls
addgroup     delgroup     fdformat     i2cset       nologin      ubirename
adduser      deluser      fsfreeze     i2ctransfer  partprobe
arping       dnsd         i2cdetect    inetd        rdate
chroot       ether-wake   i2cdump      killall5     readprofile
crond        fbset        i2cget       loadfont     setlogcons

Disk and RAM reports:

root@buildroot:/$ df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                58.1M      5.6M     49.5M  10% /
devtmpfs                 22.8M         0     22.8M   0% /dev
tmpfs                    23.0M         0     23.0M   0% /dev/shm
tmpfs                    23.0M     20.0K     22.9M   0% /tmp
tmpfs                    23.0M     20.0K     22.9M   0% /run

root@buildroot:/$ cat /proc/meminfo 
MemTotal:          47008 kB
MemFree:           26812 kB
MemAvailable:      36784 kB
Buffers:             232 kB
Cached:             2004 kB
SwapCached:            0 kB
Active:             2072 kB
Inactive:            684 kB
Active(anon):        544 kB
Inactive(anon):       16 kB
Active(file):       1528 kB
Inactive(file):      668 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                28 kB
Writeback:             0 kB
AnonPages:           536 kB
Mapped:             1068 kB
Shmem:                40 kB
Slab:              14296 kB
SReclaimable:      11204 kB
SUnreclaim:         3092 kB
KernelStack:         280 kB
PageTables:           88 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       23504 kB
Committed_AS:       1780 kB
VmallocTotal:     966656 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
Percpu:               32 kB

Disk space is not a big issue, but RAM memory is really limiting factor for this system. Also CPU is low profile ARM926 Running at 454 MHz. This computational power is just enough for mp3 player or light web server or something like photo frame, also because current linux support for this architecture is incomplete and can’t take full advantages of all available peripherals. Anyhow, fast or slow is your system, everything depends on what you intent to do with this system.

root@buildroot:/$ cat /proc/cpuinfo 
processor       : 0
model name      : ARM926EJ-S rev 5 (v5l)
BogoMIPS        : 226.09
Features        : swp half thumb fastmult edsp java 
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 5

Hardware        : Freescale MXS (Device Tree)
Revision        : 0000
Serial          : 0000000000000000

Back to buildroot configuration. This setup lacks of wifi support and some useful tools like nano and mc. Moreover if you want to adapt kernel configuration to your hardware, add extra drivers and packages:

# Buildroot configuration
$ make menuconfig

# For kernel and drivers configuration
$ make linux-menuconfig

# For busybox configuration
$ make busybox-menuconfig

Useful tool-chain and system settings:

# Select full featured GNU stdc library
Toolchain  ---> C library (glibc)  ---> (X) glibc
# Enable c++ compiler
[*] Enable C++ support
# Select kernel version
Custom kernel headers series (5.4.x)  ---> (X) 5.4.x
# Remote system debugging  
[*] Build cross gdb for the host

Select Python, c++, gdb, sudo, mc, ecc...

Network connecction:

# Wifi network
root@mx23:~$ wpa_passphrase ESSID_NAME ESSID_PASS > /root/home_conn.conf

# Connect to home network 
root@mx23:~$ wpa_supplicant -B -i wlan0 -c /root/home_conn.conf

# Run DHCP client
root@mx23:~$ udhcpc -i wlan0
# Enable root login for open SSH server 
root@mx23:~$ nano /etc/ssh/sshd_config
PermitRootLogin yes

Finally, set swap file:

# Make 128 MB swapfile
root@mx23:~$ fallocate -l 128M /swapfile
root@mx23:~$ chmod 600 /swapfile
root@mx23:~$ mkswap /swapfile
root@mx23:~$ swapon /swapfile

# Add swap info to fstab 
root@mx23:~$ nano /etc/fstab
/swapfile       none            swap    defaults        0       0

Code::blocks IDE and Remote debugging
OpenOCD and Serial JTAG

Serial UART console

Most simple and common way to connect almost any embedded device is serial UART port. You can find one inside any Smart TV or Media Center, WiFi Router and almost any kind of complex electronic device provides this port. The reason to expose this port may be different, but usually is used for maintenance, debug and diagnostics. Be careful with [un] authorized accesses to any device: please check device documentation and contact support first.

For everything you would like to know about serial communication please refer to this article:

Original specification for DB9 and DB25 connectors defines a lot of control and synchronization signals like DTR – “Data Terminal Ready”, DSR – “Data Set Ready” or RI – “Ring Indicator”. Signals used especially for synchronization with ancient and slow terminals with small buffers. Currently many devices successfully use only TX and RX pins for serial communication and all other pins are simply useless.

Actually there are many ways to connect to the serial port, for example you can use “USB to Serial” converter or “Serial Bluetooth” module; almost any embedded development kit should support UART / USART connection. Before selecting your converter, check signal levels, is common to find 5v and 3.3v devices. Do not mix unless your 3.3Volt device is specifically tolerant to 5volt signals, otherwise signal level converter is required. Some old devices or also special purpose serial devices may use +/-12 volt signal.

This kind of serial connection is not intended for high bandwidth or long range communications. Rather that it’s simple and robust enough to fulfill most of the basic but essential communication tasks.

Common baud-rates and maximum theoretical data throughput:

7bit data
No parity
8bit data
No parity
8bit data
1bit parity

Although simple serial console I/O is powerful enough for many tasks where the error is negligible, big data transfer requires error handling and synchronization, like XON / XOFF or parity bit. Is also a good practice to add CRC to the transmitted data block, over then simple parity check. Because this type of communication may suffer of erasures and multi bit errors.

A lot of software and protocols was developed to support serial communication remote console and file transfer, like “[X|Y|Z]MODEM” or “Kermit”, “minicom” and “Putty” and many others more or less famous.

A simple and elegant way to connect router’s serial console is through HC-06 Slave bluetooth module.
This module exposes the SPP (Serial Port Profile) protocol for remote devices. Then, any Bluetooth Master near the router can connect it, obviously knowing the correct pin.

TL-MR3220 serial port connected to bluetooth HC-06 module. Supply of 3.3v is provided by router board red wire. Black is ground, TX and RX (Green and White) for serial I/O.

Router board console via bluetooth with Putty.

First, configure HC-06 module for 115200 bps 8 bit data, no parity bit and one stop bit, then connect it to the router. If provided power supply is sufficient to power-up bluetooth module, we will see blinking red led. Module consumption under 3.3v is around 4mA – 8mA for idle state and 20mA – 40mA for normal operation.

Python setup script for HC-06 serial bluetooth module:

Bluetooth module connection with level shifter (5v to 3.3v) and FTDI Serial to USB converter
$ python3 /dev/ttyUSB0 -p N --set-pin 1234 --set-name BTS00 --set-rate 115200 --set-parity N

 Guessing bit-rate and parity on /dev/ttyUSB0 …
   Rate: 1200, parity: N 
   Rate: 2400, parity: N 
   Rate: 4800, parity: N 
   Rate: 9600, parity: N 
   Rate: 19200, parity: N 
   Rate: 38400, parity: N 
   Rate: 57600, parity: N 
   Rate: 115200, parity: N 
 AT device detected.
 Open serial port: /dev/ttyUSB0, bit-rate: 115200, parity: N 
 Device version: linvorV1.8 
 Set name OK
 Set pin OK
 Set baud 115200 
 Set parity  None

Deal with serial ports from source code is pretty straightforward, like write and read any simple file except seek function which is not applicable. Other things, like serial port name and configuration procedures are OS and language specific.

Example Python script for basic serial I/O:

#!/usr/bin/env python

# Import pySerial library
from serial import *

# Open serial port at "115200,8,N,1", timeout 3s 
ser = Serial(port='/dev/ttyUSB0',

# Write a string

# Read 30 bytes

# Close port

This Python demo script should work on both, Linux and Windows platforms, just change device name to “COM1” on Windows.

Another way to deal with serial communication is “kermit” from:
Old-school scriptable tool for almost any modem communication related tasks.

; Kermit script for router firmware update via serial line
; Router: TL-MR3220 v1.2 (original bootloader)
; File: "wrt_ser_upload.ksc"

set line /dev/rfcomm3
set speed 115200
set carrier-watch off
set flow-control none
set handshake none
set prefixing all

; Echo serial line to console

; Clear console input buffer
; Wait for console prompt
INPUT 3 :/#
; System reboot request 
LINEOUT reboot

; Wait for U-Boot prompt 
INPUT 180 Autobooting in 1 seconds
; Login into u-boot console

; Wait for u-boot prompt
INPUT 3 ar7240>
; Prepare U-Boot for incomming file
LINEOUT loadb 0x81000000

; Wait for u-boot ACK
INPUT 3 Ready for binary (kermit) download
; Send new firmware file
SEND ~/openwrt-18.06/bin/targets/ar71xx/tiny/openwrt-ar71xx-tiny-tl-mr3220-v1-squashfs-factory.bin

; Wait for u-boot prompt
INPUT 3 ar7240>
; Erase target flash memory 
LINEOUT erase 0x9f020000 +0x3c0000
; Erase completed  
INPUT 60 Erased 60 sectors

; Wait for u-boot prompt
INPUT 3 ar7240>
; Write new firmware to flash
LINEOUT cp.b 0x81000000 0x9f020000 0x3c0000
; Wait for done
INPUT 60 done

; Wait for u-boot prompt
INPUT 3 ar7240>
; Boot into new system 
LINEOUT bootm 0x9f020000

; Quit

This Kermit script updates OpenWRT firmware for TL-MR3220 router v1.2

Kermit file transfer

Router documentation:
Kermit documentation:
HC-06 bluetooth module documentation:
HC-06 Firmware reference:

TP-Link MR3420 setup OpenWRT v18.06

OpenWrt is a powerful Linux distribution for embedded devices. Especially for routers with reduced memory and performance. This objective has contributed to an extreme level of optimization of this distribution, allowing also a high margin of flexibility and really easy setup.
This distribution usually fits on many embedded devices, the complete list can be found at this link:

Don’t expect magics from this configuration, you can’t install all the available software, simply because we don’t have enough RAM / ROM memory. Sometimes it is possible to overcome some limitations, for example extending the RAM memory with the ZRAM or SWAP file, extending the root filesystem with a USB flash memory device. However, a stable and robust configuration requires a careful evaluation of the installed services and their impact on system resources. Software as imagemagick or ffmpeg, which tries to allocate a large amount of memory, will likely fail with the segmentation error.
However, everything comes from source and everything is customizable. You can even avoid to install web interface and configure everything by ssh console and UCI command line tool, or build your own web GUI or Service supported by a solid and flexible cross-build system.
Thanks to the excellent work of all OpenWrt team, time to time, we have a new and fresh release to build.
Check your system requirements first:
This new release includes linux kernel updates, different security and bug fixes.

Clone v18.06 branche:

git clone -b openwrt-18.06 git:// openwrt-18.06

Or master branche:

git clone git:// openwrt

Next, update feeds:

cd openwrt-18.06/
./scripts/feeds update -a

Configure build system:

make menuconfig

Select router options:
Install LUCI web interface:

./scripts/feeds install luci

Select Luci web interface from menuconfig:

LuCI --->  1. Collections --->  <*> luci

Choose packages carefully, because we have only 4mb of storage. This amount of memory is enough for many specialized device with a limited set of features like a router or AP. In order to take advantage of many of the packages provided by OpenWrt, it is essential to extend the memory with external USB storage. Blockmount package and root overlay filesystem can do this trick:

Select block-mount:

Base system --->  <*> block-mount
Kernel modules --->  USB Support --->  <*> kmod-usb-storage
Kernel modules --->  Filesystems --->  <*> kmod-fs-ext4

Another solution is to remove all ip-v6 support. Is configured by default and also supported from kernel side. Hacking on Kernel configuration is especially useful when support for specific hardware is required or simply to enable debugging features or disable something to save space. 

Linux kernel configuration:

make kernel_menuconfig

Careful with kernel settings, most of them are unsafe. Don’t touch things, if you are not aware about what are they really doing. At best, you’ll get a slow kernel with a lot of useless code.

Build firmware:

make -j8

Finally, we can find all binary files in “bin/targets/ar71xx/tiny/”

1,2K giu 13 12:04 config.seed
2,8K giu 13 12:07 openwrt-ar71xx-tiny-device-tl-mr3420-v1.manifest
2,7M giu 13 12:07 openwrt-ar71xx-tiny-root.squashfs
3,8M giu 13 12:07 openwrt-ar71xx-tiny-tl-mr3420-v1-squashfs-factory.bin
3,6M giu 13 12:07 openwrt-ar71xx-tiny-tl-mr3420-v1-squashfs-sysupgrade.bin
1,2M giu 13 12:07 openwrt-ar71xx-tiny-uImage-lzma.bin
3,5M giu 13 12:07 openwrt-ar71xx-tiny-vmlinux.bin
3,5M giu 13 12:07 openwrt-ar71xx-tiny-vmlinux.elf
1,2M giu 13 12:07 openwrt-ar71xx-tiny-vmlinux.lzma
1,2M giu 13 12:07 openwrt-ar71xx-tiny-vmlinux-lzma.elf
4,0K giu 13 12:07 packages
1,1K giu 13 12:07 sha256sums

To program the device for the first time is sufficient to upload “factory.bin” to the router, from it’s own classic web interface as usual. For subsequent upgrades from LUCI web interface use “sysupgrade.bin”.

Wait for the router to reboot, connect to “” with any browser or ssh, then you will be able to set up root password. First Login:

Next topics:
1) Serial debug console
2) Customize your build
3) Remote development

All documentation and howto:
Multiple builds in one single checkout:
Detailed build instructions:
Easy patch management:
Creating packages:

TP-LINK MR3420 hardware

TL-MR3420 is Wireless N Router with USB 2.0 Port for UMTS/HSPA/EVDO USB Modem.

Model Name
6.9 x 4.4 x 1.2 in. (174 x 111 x 30 mm)
9VDC / 0.85A
#1 – USB 2.0
#1 – Ethernet WAN 10/100Mbps
#4 – Ethernet LAN 10/100Mbps
#2 – 3dBi Detachable Omni Directional Antennas
Wireless Transmit Power
20dBm (Max. EIRP)
Atheros AR7241@400MHz
32 MB
4 MB

Arduino Nano v3 internal temperature sensor

Calibration data:

Download data & formulas in excel.
Atmega documentation says:
The voltage sensitivity is approximately 1 mV/°C and the accuracy of the temperature measurement is +/- 10°C.
Measured temperature is a sum of ambient temperature and chip’s TDP.

In fact it rises up for few minutes after the chip is powered and may change in base of load.

// Read Atmega328P internal temperature sensor //
long read_temp()
  // Read temperature sensor against 1.1V reference
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  // Start AD conversion
  // Detect end-of-conversion
  while (bit_is_set(ADCSRA,ADSC));
  // return raw data
  return ADCL | (ADCH << 8);

// Convert raw temperature data to °C
double conv_temp(long raw_temp)
  // f(x) = (raw - offset) / coeff
  return((raw_temp - 324.31) / 1.22);

void setup()

void loop()
  Serial.println(conv_temp(read_temp()), 1);

Datasheet Atmega 328P –

It is a curious fact that putting chips in the freezer, after a few minutes when the temperature drops below zero, the chip stops working.

Gentoo default Python interpreter

Gentoo default Python interpreter is set to version 3.1:
~ # eselect python list
Available Python interpreters:
[1] python2.6
[2] python3.1 *

Command to change default interpreter:
~ # eselect python set 1
And now interpreter version is 2.6:
~ # eselect python list
Available Python interpreters:
[1] python2.6 *
[2] python3.1

Installing version 2.7:
~ # nano /etc/portage/package.accept_keywords
^X (Ctrl+X) --> exit & save
~ # emerge --ask =dev-lang/python-2.7*

Rebuild Python modules:
~ # python-updater
* Starting Python Updater...
* Main active version of Python: 2.7
* Active version of Python 2: 2.7
* Active version of Python 3: 3.1

Happy python coding!