UART Daisy Chain

This article explains how to use multiple UART ports on ODROID-C2 with the Android OS.

We used three UART ports and implemented a data flow like a ring. We call it Daisy Chain.
TX port(the first UART) ⇒ RX port (the second UART) TX port ⇒ RX port (the third UART) TX port ⇒ back to the RX port of the first UART.
You have to use the latest Android 6.0.1 image version 3.6 or higher to use three UART ports simultaneously.

Hardware


☛ Download Frizing : uart_daisychain.fzz

Check J2 2×20 pins out this link
odroid-c2:hardware:expansion_connectors#j2_-_2x20_pins

PORT PIN
TX RX
UART_A (ttyS1) 8 10
UART_B (ttyS2) 3 5
UART_C (ttyS3) 32 26

Software setup

Modify Device-Tree file

You have to modify Device-Tree file to enable UART_B(ttyS2) and UART_C(ttyS3) since our stock Android image enables only one UART_A(ttyS1) port by default.
Other pins for ttyS2 and ttyS3 are used for other purpose like GPIO/I2C.

If you download our Android kernel source tree, you can find the Device-Tree file in this directory.
kernel/arch/arm64/boot/dts/meson64_odroidc2.dts

Disable I2C
diff --git a/arch/arm64/boot/dts/meson64_odroidc2.dts b/arch/arm64/boot/dts/meson64_odroidc2.dts
index e6a25b0..db09b04 100755
--- a/arch/arm64/boot/dts/meson64_odroidc2.dts
+++ b/arch/arm64/boot/dts/meson64_odroidc2.dts
@@ -813,18 +813,6 @@
 
 };
 
-&i2c_a {
-       status = "okay";
-
-       /* Hardkernel I2C RTC */
-       pcf8563: pcf8563@51     {
-               status = "disabled";
-               compatible = "nxp,pcf8563";
-               reg = <0x51>;
-               #clock-cells = <0>;
-       };
-};
-
 &i2c_b {
        status = "okay";
Add UART_B and UART_C definitions
diff --git a/arch/arm64/boot/dts/meson64_odroidc2.dts b/arch/arm64/boot/dts/meson64_odroidc2.dts
index e6a25b0..fd41552 100755
--- a/arch/arm64/boot/dts/meson64_odroidc2.dts
+++ b/arch/arm64/boot/dts/meson64_odroidc2.dts
@@ -31,6 +31,8 @@
        aliases {
                serial0 = &uart_AO;
                serial1 = &uart_A;
+               serial2 = &uart_B;
+               serial3 = &uart_C;
        };
 
        gpu_dvfs_tbl: gpu_dvfs_tbl {
@@ -459,6 +461,32 @@
                pinctrl-0 = <&a_uart_pins>;
        };
 
+       uart_B: serial@c11084dc {
+               compatible = "amlogic, meson-uart";
+               reg = <0x0 0xc11084dc 0x0 0x18>;
+               interrupts = <0 75 1>;
+               status = "okay";
+               clocks = <&clock CLK_XTAL>;
+               clock-names = "clk_uart";
+               fifosize = < 64 >;
+               pinctrl-names = "default";
+               pinctrl-0 = <&b_uart_pins>;
+               resets = <&clock GCLK_IDX_UART1>;
+       };
+
+       uart_C: serial@c1108700 {
+               compatible = "amlogic, meson-uart";
+               reg = <0x0 0xc1108700 0x0 0x14>;
+               interrupts = <0 93 1>;
+               status = "okay";
+               clocks = <&clock CLK_XTAL>;
+               clock-names = "clk_uart";
+               fifosize = < 64 >;
+               pinctrl-names = "default";
+               pinctrl-0 = <&c_uart_pins>;
+               resets = <&clock GCLK_IDX_UART2>;
+       };
+
        canvas {
                compatible = "amlogic, meson, canvas";
                dev_name = "amlogic-canvas";

meson64_odroidc2.dts

Compile dts to dtb

$ make odroidc2_[i2c_]defconfig
KBUILD_CFLAGS_MODULE:-DMODULE
#
# configuration written to .config
#

#### make completed successfully  ####

[~/projects/c2/marshmallow/kernel]$ make dtbs
KBUILD_CFLAGS_MODULE:-DMODULE
KBUILD_CFLAGS_MODULE:-DMODULE
scripts/kconfig/conf --silentoldconfig Kconfig
KBUILD_CFLAGS_MODULE:-DMODULE  
  WRAP    arch/arm64/include/generated/asm/bug.h
  WRAP    arch/arm64/include/generated/asm/bugs.h
  WRAP    arch/arm64/include/generated/asm/checksum.h
  WRAP    arch/arm64/include/generated/asm/clkdev.h
  WRAP    arch/arm64/include/generated/asm/cputime.h
  WRAP    arch/arm64/include/generated/asm/current.h
  WRAP    arch/arm64/include/generated/asm/delay.h
  WRAP    arch/arm64/include/generated/asm/div64.h
  WRAP    arch/arm64/include/generated/asm/dma.h
  WRAP    arch/arm64/include/generated/asm/emergency-restart.h
  WRAP    arch/arm64/include/generated/asm/early_ioremap.h
  WRAP    arch/arm64/include/generated/asm/errno.h
  WRAP    arch/arm64/include/generated/asm/ftrace.h
  WRAP    arch/arm64/include/generated/asm/hw_irq.h
  WRAP    arch/arm64/include/generated/asm/ioctl.h
  WRAP    arch/arm64/include/generated/asm/ioctls.h
  WRAP    arch/arm64/include/generated/asm/ipcbuf.h
  WRAP    arch/arm64/include/generated/asm/irq_regs.h
  WRAP    arch/arm64/include/generated/asm/kdebug.h
  WRAP    arch/arm64/include/generated/asm/kmap_types.h
  WRAP    arch/arm64/include/generated/asm/kvm_para.h
  WRAP    arch/arm64/include/generated/asm/local.h
  WRAP    arch/arm64/include/generated/asm/local64.h
  WRAP    arch/arm64/include/generated/asm/mman.h
  WRAP    arch/arm64/include/generated/asm/msgbuf.h
  WRAP    arch/arm64/include/generated/asm/mutex.h
  WRAP    arch/arm64/include/generated/asm/pci.h
  WRAP    arch/arm64/include/generated/asm/poll.h
  WRAP    arch/arm64/include/generated/asm/posix_types.h
  WRAP    arch/arm64/include/generated/asm/resource.h
  WRAP    arch/arm64/include/generated/asm/scatterlist.h
  WRAP    arch/arm64/include/generated/asm/sections.h
  WRAP    arch/arm64/include/generated/asm/segment.h
  WRAP    arch/arm64/include/generated/asm/sembuf.h
  WRAP    arch/arm64/include/generated/asm/serial.h
  WRAP    arch/arm64/include/generated/asm/shmbuf.h
  WRAP    arch/arm64/include/generated/asm/simd.h
  WRAP    arch/arm64/include/generated/asm/sizes.h
  WRAP    arch/arm64/include/generated/asm/socket.h
  WRAP    arch/arm64/include/generated/asm/sockios.h
  WRAP    arch/arm64/include/generated/asm/switch_to.h
  WRAP    arch/arm64/include/generated/asm/swab.h
  WRAP    arch/arm64/include/generated/asm/termbits.h
  WRAP    arch/arm64/include/generated/asm/termios.h
  WRAP    arch/arm64/include/generated/asm/topology.h
  WRAP    arch/arm64/include/generated/asm/trace_clock.h
  WRAP    arch/arm64/include/generated/asm/types.h
  WRAP    arch/arm64/include/generated/asm/unaligned.h
  WRAP    arch/arm64/include/generated/asm/user.h
  WRAP    arch/arm64/include/generated/asm/vga.h
  WRAP    arch/arm64/include/generated/asm/xor.h
  WRAP    arch/arm64/include/generated/asm/preempt.h
  WRAP    arch/arm64/include/generated/asm/hash.h
  WRAP    arch/arm64/include/generated/uapi/asm/kvm_para.h
  HOSTCC  scripts/dtc/checks.o
  HOSTCC  scripts/dtc/data.o
  SHIPPED scripts/dtc/dtc-lexer.lex.c
  SHIPPED scripts/dtc/dtc-parser.tab.h
  HOSTCC  scripts/dtc/dtc-lexer.lex.o
  SHIPPED scripts/dtc/dtc-parser.tab.c
  HOSTCC  scripts/dtc/dtc-parser.tab.o
  HOSTCC  scripts/dtc/dtc.o
  HOSTCC  scripts/dtc/flattree.o
  HOSTCC  scripts/dtc/fstree.o
  HOSTCC  scripts/dtc/livetree.o
  HOSTCC  scripts/dtc/srcpos.o
  HOSTCC  scripts/dtc/treesource.o
  HOSTCC  scripts/dtc/util.o
  HOSTLD  scripts/dtc/dtc
  CC      scripts/mod/empty.o
  HOSTCC  scripts/mod/mk_elfconfig
  MKELF   scripts/mod/elfconfig.h
  CC      scripts/mod/devicetable-offsets.s
  GEN     scripts/mod/devicetable-offsets.h
  HOSTCC  scripts/mod/file2alias.o
  HOSTCC  scripts/mod/modpost.o
  HOSTCC  scripts/mod/sumversion.o
  HOSTLD  scripts/mod/modpost
  HOSTCC  scripts/selinux/genheaders/genheaders
  HOSTCC  scripts/selinux/mdp/mdp
  HOSTCC  scripts/kallsyms
  HOSTCC  scripts/pnmtologo
  HOSTCC  scripts/conmakehash
  HOSTCC  scripts/bin2c
  HOSTCC  scripts/recordmcount
  HOSTCC  scripts/sortextable
  DTC     arch/arm64/boot/dts/meson64_odroidc2.dtb
Warning (reg_format): "reg" property in /spi-gpio/spi-gpio@0 has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
Warning (avoid_default_addr_size): Relying on default #address-cells value for /spi-gpio/spi-gpio@0
Warning (avoid_default_addr_size): Relying on default #size-cells value for /spi-gpio/spi-gpio@0

#### make completed successfully (4 seconds) ####

Pre-compiled dtb file for this project. meson64_odroidc2.dtb

Install modified dtb file

You need to connect a micro-USB cable between your host PC and C2 board for fastboot protocol interface.

$ sudo fastboot flash dtb out/target/product/odroidc2/obj/KERNEL_OBJ/arch/arm64/boot/dts/meson64_odroidc2.dtb

You have to edit [/storage]/internal/boot.ini file to load an alternative Kernel image

There is an alternative kernel image to switch the I2C function to UART.

#movi read boot 0 ${loadaddr}                              
fatload mmc 0:1 ${loadaddr} Image_android

Edit ueventd.odroidc2.rc

Change the permission of ttyS2 and ttyS3 for system access.

shell@odroidc2:/ $ su
root@odroidc2:/ # mount -o rw,remount /
[ 1243.002784@2] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
root@odroidc2:/ # vi /ueueventd.odroidc2.rc ueventd.rc          
root@odroidc2:/ # vi /ueventd.odroidc2.rc  

/dev/ttyS*   0666    system             system

Download and build an Android app example code

Download NDK library and App project from github.

$ sudo apt install git
$ git clone https://github.com/codewalkerster/example-wiringPi -b odroid-c_3_uart

You can build the project with Android Studio. Refer this another example for building a NDK app.
Having a fun with GPIO on Android!

What we can see and learn

Wire connection for three UART ports in Daisy Chain loop

Type a string to send

Result of test