Category: Senza categoria

Linux from scratch

Or how-to easily cross-build any 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 compiler errors. From hardware specifications to device drivers and file-systems and I/O console and Task scheduler and almost everything is involved. Then this is not easy…, but we have one fantastic tool, which is able to solve many really boring tasks. – “Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation.”

This is an example, 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.

For the list of already configured boards:  

 $ make list-defconfigs

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 automounted sdX 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 disk 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 smart IoT device development.

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, a small swap file is always a good idea:

# 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 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” or DSR – “Data Set Ready” or RI – “Ring Indicator”. Signals used especially for synchronization with ancient and slow terminals with small buffers. Now, 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 device 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 entire 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 simple file, but port configuration procedure is dependent on OS / HW nor language used.

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 and 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: