TS-7180

From embeddedTS Manuals
Revision as of 17:19, 28 February 2017 by Ian (talk | contribs)
TS-7180
ts-7180.gif
Product Page
Product Images
Specifications
Documentation
Schematic
Mechanical Drawing
FTP Path
Processor
Freescale i.MX6ul 696MHz
i.MX6ul Product Page
CPU Documentation

Overview

The TS-7180 is an SBC designed for low power systems and is ideal for remote deployment and fleet tracking.

Getting Started

A Linux PC is recommended for development, and will be assumed for this documentation. For users in Windows or OSX we recommend virtualizing a Linux PC. Most of our platforms run Debian and if there is no personal distribution preference this is what we recommend for ease of use.

Virtualization

Suggested Linux Distributions

It may be possible to develop using a Windows or OSX system, but this is not supported. Development will include accessing drives formatted for Linux and often Linux based tools.

Getting Console and Powering up

WARNING: Be sure to take appropriate Electrostatic Discharge (ESD) precautions. Disconnect the power source before moving, cabling, or performing any set up procedures. Inappropriate handling may cause damage to the device.

Get console input by plugging a USB type B cable into P4. Connect the host side to a workstation for development. Console can be viewed before or after power is applied. Boot messages will only be printed once the device is powered on.


The cp210x (USB Serial) driver is included in most popular distributions. This will show up as /dev/ttyUSB0. For other operating systems:

The serial console is provided through this port at 115200 baud, 8n1, with no flow control. Picocom is the recommended linux client to use which can be run with the following command:

sudo picocom -b 115200 /dev/ttyUSB0

This will output some serial setting information and then "Terminal ready". Any messages after this point will be from the device via the serial output. The terminal is now ready and power can be applied in order to boot up the device. Power is applied through the power connector, CN7. This accepts an 8-28 VDC input.

Once power is applied, the device will output information via the console. The first output is from U-Boot:

U-Boot 2016.03-14506-gfee2f5b (Jan 13 2017 - 12:29:29 -0700)                    
                                                                                
CPU:   Freescale i.MX6UL rev1.1 at 396 MHz                                      
Reset cause: POR                                                                
Board: Technologic Systems TS-7180                                              
FPGA:  Rev 0                                                                    
I2C:   ready                                                                    
DRAM:  512 MiB                                                                  
MMC:   FSL_SDHC: 0, FSL_SDHC: 1                                                 
*** Warning - bad CRC, using default environment                                
                                                                                
Net:   FEC0 [PRIME]
Press Ctrl+C to abort autoboot in 1 second(s) 

You may break into U-Boot at this point, by pressing Control+C at your terminal; otherwise, U-Boot will proceed to load the system.

The "SD Boot" jumper, when installed, will cause U-Boot to boot to SD; otherwise, U-Boot will boot to eMMC.

20170224 140329.jpg

Note: The "*** Warning - bad CRC, using default environment" can be safely ignored. This indicates that u-boot scripts are not being customized. Typing "env save" will hide these messages, but this is not essential.

Console from Windows

Putty is a small simple client available for download here. Open up Device Manager to determine your console port. See the putty configuration image for more details.

Device Manager Putty Configuration

U-Boot

U-Boot Environment

The U-Boot environment on the TS-7180 is stored in the on-board eMMC flash.

# Print all environment variables
env print -a

# Sets the variable bootdelay to 5 seconds
env set bootdelay 5;

# Variables can also contain commands
env set hellocmd 'led red on; echo Hello world; led green on;'

# Execute commands saved in a variable
env run hellocmd;

# Commit env changes to the spi flash
# Otherwise changes are lost
env save

# Restore env to default
env default -a

# Remove a variable
env delete emmcboot

Accessing the U-Boot Environment from Linux

Recent Debian releases from embeddedTS include the u-boot-tools package, which provides the fw_printenv and fw_setenv commands. They are analogous to the env print and env set commands in U-Boot.

One important difference is that to alter the U-Boot Environment, the boot partition must first be made writable. For an environment in the on-board eMMC, this is how to do so:

DEV_NAME=$(basename $(awk '/^\// {print $1;exit;}' /etc/fw_env.config))
echo 0 > /sys/block/${DEV_NAME}/force_ro

From that point up until when a 1 is written in the above example instead of 0 (or until after a reboot), all uses of fw_setenv will immediately update the environment. There is no need for (nor equivalent to) env save command.

Note that the /etc/fw_env.config provided with our Debian releases expects to find the environment in the boot partition of our boards' eMMC flash. That is expected to match where U-Boot keeps its environment.

U-Boot Commands

# The most important command is 
help
# This can also be used to see more information on a specific command
help i2c

# Boots into the binary at $loadaddr.  This file needs to have
# the uboot header from mkimage.  A uImage already contains this.
bootm
# Boots into the binary at $loadaddr, skips the initrd, specifies
# the fdtaddr so Linux knows where to find the board support
bootm ${loadaddr} - ${fdtaddr}

# Get a DHCP address
dhcp
# This sets ${ipaddr}, ${dnsip}, ${gatewayip}, ${netmask}
# and ${ip_dyn} which can be used to check if the dhcp was successful

# These commands are used for scripting:
false # do nothing, unsuccessfully
true # do nothing, successfully

# This command lets you set fuses in the processor
# Setting fuses can brick your board, will void your warranty,
# and should not be done in most cases
fuse

# Control LEDs
led red on
led green on
led all off
led red toggle

# This command is used to copy a file from most devices
# Load kernel from SD
load mmc 0:1 ${loadaddr} /boot/uImage
# Load Kernel from eMMC
load mmc 1:1 ${loadaddr} /boot/uImage


# You can view the fdt from u-boot with fdt
load mmc 0:1 ${fdtaddr} /boot/imx6ul-ts7180.dtb
fdt addr ${fdtaddr}
fdt print

# You can blindly jump into any memory
# This is similar to bootm, but it does not use the 
# u-boot header
load mmc 0:1 ${loadaddr} /boot/custombinary
go ${loadaddr}

# Browse fat,ext2,ext3,or ext4 filesystems:
ls mmc 0:1 /

# Access memory like devmem in Linux, you can read/write arbitrary memory
# using mw and md
# write
mw 0x10000000 0xc0ffee00 1
# read
md 0x10000000 1

# Test memory.
mtest

# Check for new SD card
mmc rescan
# Read SD card size
mmc dev 0
mmcinfo
# Read eMMC Size
mmc dev 1
mmcinfo

# The NFS command is like 'load', but used over the network
dhcp
env set serverip 192.168.0.11
nfs ${loadaddr} 192.168.0.11:/path/to/somefile

# Test ICMP
dhcp
ping 192.168.0.11

# Reboot
reset

# Delay in seconds
sleep 10

# You can load HUSH scripts that have been created with mkimage
load mmc 0:1 ${loadaddr} /boot/ubootscript
source ${loadaddr}

# Most commands have return values that can be used to test
# success, and HUSH scripting supports comparisons like
# test in Bash, but much more minimal
if load mmc 1:1 ${fdtaddr} /boot/uImage;
	then echo Loaded Kernel
else
	echo Could not find kernel
fi

# Commands can be timed with "time"
time bdinfo

# Print U-boot version/build information
version

Debian

Debian Stretch(9)

Getting Started

The stock image uses a Debian Stretch distribution and Linux kernel version 4.9. The latest image can be downloaded below.

This image can then be written to a microSD card or the on-board eMMC flash in order to be booted on the TS-4100.

Debian Networking

Note: The first physical port on the TS-4100 (or on Baseboards with a single port) is given the name "eth1", while the second port is "eth0".


By default, Debian Stretch does not configure or bring up any interfaces.

Debian can automatically set up the networking based on the contents of "/etc/network/interfaces.d/" files. For example, to enable DHCP for "eth0" by default on startup:

echo "auto eth0
iface eth0 inet dhcp" > /etc/network/interfaces.d/eth0

To set up a static IP:

echo "auto eth0
iface eth0 inet static
    address 192.168.0.50
    netmask 255.255.255.0
    gateway 192.168.0.1" > /etc/network/interfaces.d/eth0
echo "nameserver 1.1.1.1" > /etc/resolv.conf

To make this take effect immediately for either option:

service networking restart

To configure other interfaces, replace "eth0" with the other network device name. Some interfaces may use predictable interface names. For example, the traditional name for an ethernet port might be "eth1", but some devices may use "enp1s0" for PCIe, or "enx00D069C0FFEE" (the MAC address appended) for USB ethernet interfaces. Run 'ifconfig -a' or 'ip a' to get a complete list of interfaces, including the ones that are not configured.


Debian Wi-Fi Client

Note: The latest image for this platform as of April 28th, 2022 has known issues with the Wi-Fi driver due to incompatibility with cfg80211 powersave modes.

If using Wi-Fi, it is strongly recommended to bring up the Wi-Fi interface, and then run iw wlan0 set power_save off to disable powersave modes.

This issue will be addressed in future images and has already been addressed in our kernel sources. We will continue to provide updates as we receive them from the Wi-Fi module manufacturer.


Wireless interfaces are also managed with configuration files in "/etc/network/interfaces.d/". For example, to connect as a client to a WPA network with DHCP. Note some or all of this software may already be installed on the target SBC.

Install wpa_supplicant:

apt-get update && apt-get install wpasupplicant -y

Run:

wpa_passphrase youressid yourpassword

This command will output information similar to:

 network={
 	ssid="youressid"
 	#psk="yourpassword"
 	psk=151790fab3bf3a1751a269618491b54984e192aa19319fc667397d45ec8dee5b
 }

Use the hashed PSK in the specific network interfaces file for added security. Create the file:

/etc/network/interfaces.d/wlan0

allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-ssid youressid
    wpa-psk 151790fab3bf3a1751a269618491b54984e192aa19319fc667397d45ec8dee5b

To have this take effect immediately:

service networking restart

For more information on configuring Wi-Fi, see Debian's guide here.


Debian Wi-Fi Access Point

Note: The latest image for this platform as of April 28th, 2022 has known issues with the Wi-Fi driver due to incompatibility with cfg80211 powersave modes.

If using Wi-Fi, it is strongly recommended to bring up the Wi-Fi interface, and then run iw wlan0 set power_save off to disable powersave modes.

This issue will be addressed in future images and has already been addressed in our kernel sources. We will continue to provide updates as we receive them from the Wi-Fi module manufacturer.


This section will discuss setting up the WiFi device as an access point that is bridged to an ethernet port. That is, clients can connect to the AP and will be connected to the ethernet network through this network bridge. The ethernet network must provide a DHCP server; this will be passed through the bridge to WiFi client devices as they connect.

It is also possible to run a DHCP client on the platform itself. In this case the hostapd.conf file needs to be set up without bridging and a DHCP server needs to be configured. Refer to Debian's documentation for more details on DHCP server configuration.

The 'hostapd' utility is used to manage the access point of the device. This is usually installed by default, but can be installed with:

apt-get update && apt-get install hostapd -y


Note: The install process may start an unconfigured 'hostapd' process. This process must be killed before moving forward.


Modify the file "/etc/hostapd/hostapd.conf" to have the following lines:

ssid=YourWiFiName
wpa_passphrase=Somepassphrase
interface=wlan0
bridge=br0
auth_algs=3
channel=7
driver=nl80211
hw_mode=g
logger_stdout=-1
logger_stdout_level=2
max_num_sta=5
rsn_pairwise=CCMP
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


The access point can be started and tested by hand:

hostapd /etc/hostapd/hostapd.conf


Systemd auto-start with bridge to eth0

It is possible to configure the auto-start of 'hostapd' through systemd. The configuration outlined below will set up a bridge with "eth0", meaning the Wi-Fi connection is directly connected to the ethernet network. The ethernet network is required to have a DHCP server present and active on it to assign Wi-Fi clients an IP address. This setup will allow Wi-Fi clients access to the same network as the ethernet port, and the bridge interface will allow the platform itself to access the network.


Set up hostapd

First, create the file "/etc/systemd/system/hostapd_user.service" with the following contents:

[Unit]
Description=Hostapd IEEE 802.11 AP
Wants=network.target
Before=network.target
Before=network.service
After=sys-subsystem-net-devices-wlan0.device
After=sys-subsystem-net-devices-br0.device
BindsTo=sys-subsystem-net-devices-wlan0.device
BindsTo=sys-subsystem-net-devices-br0.device

[Service]
Type=forking
PIDFile=/run/hostapd.pid
ExecStart=/usr/sbin/hostapd /etc/hostapd/hostapd.conf -P /run/hostapd.pid -B

[Install]
WantedBy=multi-user.target

Then enable this in systemd:

systemctl enable hostapd_user.service
systemctl enable systemd-networkd


Set up bridging

Create the following files with the listed contents.


"/etc/systemd/network/br0.netdev"

[NetDev]
Name=br0
Kind=bridge


"/etc/systemd/network/br0.network"

[Match]
Name=br0

[Network]
DHCP=yes


"/etc/systemd/network/bridge.network"

[Match]
Name=eth0

[Network]
Bridge=br0


Debian Wi-Fi Concurrent Client / Access Point

Note: The latest image for this platform as of April 28th, 2022 has known issues with the Wi-Fi driver due to incompatibility with cfg80211 powersave modes.

If using Wi-Fi, it is strongly recommended to bring up the Wi-Fi interface, and then run iw wlan0 set power_save off to disable powersave modes.

This issue will be addressed in future images and has already been addressed in our kernel sources. We will continue to provide updates as we receive them from the Wi-Fi module manufacturer.


The Wi-Fi device on this platform supports concurrent operation of client and access point (STA and AP). Please see the "Wi-Fi Client" section above first to connect the Wi-Fi module, in STA mode, to an external AP. This demo showcases the Wi-Fi module starting its own AP mode via hostapd with a simple static IP address while also being concurrently connected to a separate AP.

The 'hostapd' utility is used to manage the access point of the device. This is usually installed by default, but can be installed with:

apt-get update && apt-get install hostapd -y


Note: The install process may start an unconfigured 'hostapd' process. This process must be killed before moving forward.


Modify the file /etc/hostapd/hostapd.conf to have the following lines:

ssid=YourWiFiName
wpa_passphrase=Somepassphrase
interface=p2p0
auth_algs=3
channel=<channel>
driver=nl80211
hw_mode=g
logger_stdout=-1
logger_stdout_level=2
max_num_sta=5
rsn_pairwise=CCMP
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
Note: The channel used for AP must match the channel the STA is using! Be sure to set 'channel=...' in the above file to a proper channel number.
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


In order for the concurrent modes to work, a separate virtual wireless device must first be created. Note that hostapd.conf above lists interface=p2p0, a second interface with this name must be created:

iw wlan0 interface add p2p0 type managed

The access point can then be started and tested by hand:

hostapd /etc/hostapd/hostapd.conf &

An IP address can be set to p2p0:

ifconfig p2p0 192.168.0.1

From this point, other Wi-Fi clients can connect to the SSID YourWiFiName with the WPA2 key Somepassphrase with a static IP in the range of 192.168.0.0/24, and will be able to access the platform at 192.168.0.1. More advanced configurations are also possible, including bridging, routing/NAT, or simply separate networks with the Wi-Fi module connecting to a network and hosting its own private network with DHCP.

Debian Application Development

Debian Stretch Cross Compiling

Debian Stretch provides cross compilers from the Debian apt repository archive for Debian Stretch. An install on a workstation can build for the same release on other architectures. A Linux desktop or laptop PC, virtual machine, or chroot will need to be used for this. Debian Stretch for a workstation can be downloaded from here.

From a Debian workstation (not the target), run these commands to set up the cross compiler:

# Run "lsb_release -a" and verify Debian 9.X is returned.  These instructions are not
# expected to work on any other version or distribution.
su root
# Not needed for the immediate apt-get install, but used
# so we can install package:armhf for cross compiling
dpkg --add-architecture armhf
apt-get update
apt-get install curl build-essential crossbuild-essential-armhf -y

This will install a toolchain that can be used with the prefix "arm-linux-gnueabihf-". The standard GCC tools will start with that name, eg "arm-linux-gnueabihf-gcc".

The toolchain can now compile a simple hello world application. Create hello-world.c on the Debian workstation:

#include <stdio.h>
int main(){
    printf("Hello World\n");
}

To compile this:

arm-linux-gnueabihf-gcc hello-world.c -o hello-world
file hello-world

This will return that the binary created is for ARM. Copy this to the target platform to run it there.

Debian Stretch supports multiarch which can install packages designed for other architectures. On workstations this is how 32-bit and 64-bit support is provided. This can also be used to install armhf packages on an x86 based workstation.

This cross compile environment can link to a shared library from the Debian root. The package would be installed in Debian on the workstation to provide headers and libraries. This is included in most "-dev" packages. When run on the arm target it will also need a copy of the library installed, but it does not need the -dev package.

apt-get install libcurl4-openssl-dev:armhf

# Download the simple.c example from curl:
wget https://raw.githubusercontent.com/bagder/curl/master/docs/examples/simple.c
# After installing the supporting library, curl will link as compiling on the unit.
arm-linux-gnueabihf-gcc simple.c -o simple -lcurl

Copy the binary to the target platform and run on the target. This can be accomplished with network protocols like NFS, SCP, FTP, etc.

If any created binaries do not rely on hardware support like GPIO or CAN, they can be run using 'qemu'.

# using the hello world example from before:
./hello-world
# Returns Exec format error
apt-get install qemu-user-static
./hello-world


Debian Installing New Software

Debian provides the apt-get system which allows management of pre-built applications. The apt tools require a network connection to the internet in order to automatically download and install new software. The update command will download a list of the current versions of pre-built packages.

apt-get update

A common example is installing Java runtime support for a system. Find the package name first with search, and then install it.

root@ts:~# apt-cache search openjdk
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
default-jdk-headless - Standard Java or Java compatible Development Kit (headless)
default-jre - Standard Java or Java compatible Runtime
default-jre-headless - Standard Java or Java compatible Runtime (headless)
jtreg - Regression Test Harness for the OpenJDK platform
libreoffice - office productivity suite (metapackage)
openjdk-8-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-8-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-8-doc - OpenJDK Development Kit (JDK) documentation
openjdk-8-jdk - OpenJDK Development Kit (JDK)
openjdk-8-jdk-headless - OpenJDK Development Kit (JDK) (headless)
openjdk-8-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-8-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
openjdk-8-jre-zero - Alternative JVM for OpenJDK, using Zero/Shark
openjdk-8-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-8 - Java plugin for uWSGI (OpenJDK 8)
uwsgi-plugin-jwsgi-openjdk-8 - JWSGI plugin for uWSGI (OpenJDK 8)
uwsgi-plugin-ring-openjdk-8 - Closure/Ring plugin for uWSGI (OpenJDK 8)
uwsgi-plugin-servlet-openjdk-8 - JWSGI plugin for uWSGI (OpenJDK 8)
java-package - Utility for creating Java Debian packages

In this case, the wanted package will likely be the "openjdk-8-jre" package. Names of packages can be found on Debian's wiki pages or the packages site.

With the package name apt-get install can be used to install the prebuilt packages.

apt-get install openjdk-8-jre
# More than one package can be installed at a time.
apt-get install openjdk-8-jre nano vim mplayer

For more information on using apt-get refer to Debian's documentation here.


Debian Setting up SSH

To install the SSH server, install the package with apt-get:

apt-get install openssh-server


Debian Stretch by default disallows logins directly from the user "root". Additionally, SSH will not allow remote connections without a password or valid SSH key pair. This means in order to SSH to the device, a user account must first be created, and a password set:

useradd --create-home --shell /bin/bash newuser
passwd newuser


After this setup it is now possible to connect to the device as user "newuser" from a remote PC supporting SSH. On Linux/OS X this is the "ssh" command, or from Windows using a client such as PuTTY.


Debian Starting Automatically

A systemd service can be created to start up headless applications. Create a file in /etc/systemd/system/yourapp.service

[Unit]
Description=Run an application on startup

[Service]
Type=simple
ExecStart=/usr/local/bin/your_app_or_script

[Install]
WantedBy=multi-user.target

If networking is a dependency add "After=network.target" in the Unit section. Once you have this file in place add it to startup with:

# Start the app on startup, but will not start it now
systemctl enable yourapp.service

# Start the app now, but doesn't change auto startup
systemctl start yourapp.service
Note: See the systemd documentation for in depth documentation on services.

Backup / Restore

MicroSD Card

MicroSD8GB.png Click to download the latest tarball.

These instructions assume an SD card with one partition. Most SD cards ship this way by default, but if there are modified partitions, a utility such as 'gparted' or 'fdisk' may be needed to remove the existing partition table and recreate it with a single partition.

Note: That the partition table must be "MBR" or "msdos", as the "GPT" partition table format is NOT supported by U-Boot.

Using other OSs

At this time, we're unable to provide assistance with writing SD cards for our products from non-Linux based operating systems. We acknowledge however, that there are methods to write images and files from a variety of difference operating systems. If a native installation of Linux is unavailable, we recommend using a Virtual Machine. See the Getting Started section for links to common virtualization software and Linux installation.

Using a Linux workstation

An SD card can be written to allow it to be bootable. Download the above file and write this from a Linux workstation using the information below. A USB SD adapter can be used to access the card; or if the workstation supports direct connection of SD cards, that can be used instead. Once inserted in to the workstation, it is necessary to discover which /dev/ device corresponds with the inserted SD card before the image can be written.

Option 1: using 'lsblk'


Newer distributions include a utility called 'lsblk' which allows simple identification of the intended card.

Note: This command may need to be run as the root user:
$ lsblk

NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdY      8:0    0   400G  0 disk 
├─sdY1   8:1    0   398G  0 part /
├─sdY2   8:2    0     1K  0 part 
└─sdY5   8:5    0     2G  0 part [SWAP]
sr0     11:0    1  1024M  0 rom  
sdX      8:32   1   3.9G  0 disk 
├─sdX1   8:33   1   7.9M  0 part 
├─sdX2   8:34   1     2M  0 part 
├─sdX3   8:35   1     2M  0 part 
└─sdX4   8:36   1   3.8G  0 part

In this case the, SD card is 4GB, so sdX is the target device and already contains 4 partitions. Note that sdX is not a real device, it could be sda, sdb, mmcblk0, etc. Technologic Systems is not responsible for any damages cause by using the improper device node for imaging an SD card. The instructions below to write to the device will destroy the partition table and any existing data!

Option 2: Using 'dmesg'


After plugging in the device, the 'dmesg' command can be used to list recent kernel events. When inserting a USB adapter, the last few lines of 'dmesg' output will be similar to the following (note that this command may need to be run as the root user):

$ dmesg
...
scsi 54:0:0:0: Direct-Access     Generic  Storage Device   0.00 PQ: 0 ANSI: 2
sd 54:0:0:0: Attached scsi generic sg2 type 0
sd 54:0:0:0: [sdX] 3862528 512-byte logical blocks: (3.97 GB/3.84 GiB)
...

In this case, sdX is shown as a 3.97GB card with a single partition. Note that sdX is not a real device, it could be sda, sdb, mmcblk0, etc. Technologic Systems is not responsible for any damages cause by using the improper device node for imaging an SD card. The instructions below to write to the device will destroy the partition table and any existing data!

Running these commands will write the SD card to our default latest image.

# Verify nothing else has the disk mounted with 'mount'
# If partitions are mounted automatically, they can be unmounted with
sudo umount /dev/sdX1

sudo mkfs.ext3 /dev/sdX1
sudo mkdir /mnt/sd
sudo mount /dev/sdX1 /mnt/sd/
wget https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4100-linux/distributions/debian/ts4100-armhf-stretch-latest.tar.xz

sudo tar -xJf ts4100-armhf-stretch-latest.tar.xz -C /mnt/sd
sudo umount /mnt/sd
sync
Note: The ext4 filesystem can be used instead of ext3, but it may require additional options. U-Boot does not support the 64bit addressing added as the default behavior in recent revisions of mkfs.ext4. If using e2fsprogs 1.43 or newer, the options "-O ^64bit,^metadata_csum" must be used with ext4 for proper compatibility. Older versions of e2fsprogs do not need these options passed nor are they needed for ext3.


After the image is written, the files can all be verified on disk against the original files created in the tarball. Reinsert the disk to verify any block cache is gone, then run the following:

mount /dev/sdX1 /mnt/sd
cd /mnt/sd/
sudo md5sum --quiet -c md5sums.txt
umount /mnt/sd
sync

The 'md5sum' command will report any differences between files and their checksums. Any differences are an indication of failure to write data or a damaged disk.

eMMC

The simplest way to backup/restore the eMMC is by booting to the SD card and then writing the eMMC image to removable media such as a USB stick.

sudo mkdir /mnt/emmc/
sudo mount /dev/mmcblk1p1 /mnt/emmc/
cd /mnt/emmc/
tar -c . | bzip2 > /path/to/ts7180-backup-image.tar.bz2
cd ../
umount /mnt/emmc/
sync

To write a new filesystem to the TS-7180, first boot to an SD card or USB stick. Then re-image the eMMC:

# The eMMC is /dev/mmcblk1.
#
# Ensure the media has an MBR (not GPT) partition table with exactly one partition.
# Re-partition the device with fdisk or gparted if it isn't already partitioned correctly.

sudo mkdir /mnt/emmc/

sudo mkfs.ext4 -O ^metadata_csum,^64bit /dev/mmcblk1p1
# If the above command fails, complaining of an invalid filesystem option, it is fine to omit that flag:
# An older mkfs.ext4 that doesn’t understand it also can’t create a backwards compatibility issue.

sudo mount /dev/mmcblk1p1 /mnt/emmc/
bzcat /path/to/ts7180-new-image.tar.bz2 | tar -xhf -C /mnt/emmc
umount /mnt/emmc/
sync

Compile the Kernel

Linux 4.9.y (stock)

Compiling the kernel requires an armhf toolchain. We recommend development under Debian Stretch which includes an armhf compiler in the repositories. See the Debian Stretch cross compilation section for instructions on installing a proper cross compiler.

# Install dependencies for kernel build
# The following command is for Ubuntu / Debian workstations. If using a different
# distribution, please consult distribution docs for the proper commands to install
# new packages/tools/libraries/etc.
apt-get install libncurses5-dev bc

# Clone the kernel repository
git clone https://github.com/embeddedTS/linux-4.9.y
cd linux-4.9.y

# Set necessary environment variables for building
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export LOADADDR=0x80800000

# The following defconfig is the same kernel configuration the unit ships with
make tsimx6ul_defconfig

## Make any changes in "make menuconfig" or driver modifications, then compile
make && make zImage && make modules

To install the kernel and modules to an SD card, attach it to the PC and assuming the the SD card shows up as "/dev/sdX", where "X" is the letter drive corresponding to the SD card.

export DEV=/dev/sdX1
sudo mount "$DEV" /mnt/sd
sudo cp arch/arm/boot/zImage  /mnt/sd/boot/zImage
sudo cp arch/arm/boot/dts/imx6ul*ts*.dtb /mnt/sd/boot/
INSTALL_MOD_PATH="/mnt/sd" sudo -E make modules_install 
sudo -E make headers_install INSTALL_HDR_PATH="/mnt/sd/usr"
sudo umount /mnt/sd/
sync
Note: Shutting down and coming back or operating from another shell instance will require re-exporting the environment variables.


Linux 5.10.y

Note: At this time we do not have an updated userspace more recent than our Debian Stretch distribution. The Debian Stretch disk image can be used as a base and is compatible with the 5.10 kernel. If a newer userspace is needed, we recommend our Buildroot repository for building a complete system image which includes the 5.10 kernel.


A compatible armhf cross compiler is needed for building the 5.10 kernel. We recommend using the cross compiler available in Debian distributions (the linked instructions are for Debian Stretch but will work on more recent Debian distributions as well). It is also possible to use our Buildroot repository to build a compatible cross compiler.


Download and Configure

These steps assume a host Linux workstation with an appropriate cross compiler. While on most platforms the kernel can be downloaded, built, and installed all on the device, we recommend against this due to the amount of time, memory, and disk space that can be needed for a build.


Prerequisites

In addition to a cross compiler, a number of host tools are required.

# Install dependencies for kernel build
# The following command is for Ubuntu / Debian workstations. If using a different
# distribution, please consult distribution docs for the proper commands to install
# new packages/tools/libraries/etc.
apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
Note: The above prerequisite libraries and tools may not be the complete list, depending on the workstation's distribution and age. It may be necessary to install additional packages to support kernel compilation.


Download kernel repo on a host Linux workstation:

git clone -b linux-5.10.y https://github.com/embeddedTS/linux-lts

# Alternatively, a shallow clone can instead be performed to save space on disk. This makes the source smaller and faster to clone, but can make development and updating from remote more complex.
# git clone --depth 1 -b linux-5.10.y https://github.com/embeddedTS/linux-lts

cd linux-lts/


Configure environment variables needed for building. This specifies the architecture, the cross compiler that is being used, and to set up building the kernel modules for the WILC3000 Wi-Fi/BLE module:

export CROSS_COMPILE=arm-linux-gnueabihf-  # This may be different if using a different compiler!
export ARCH=arm
export WILC=y


The WILC3000 Wi-Fi/BLE drivers are maintained and built externally out of the kernel tree. Clone this tree inside of the linux-lts/ directory (this is built later):

git clone https://github.com/embeddedTS/wilc3000-external-module/


Next, set the default configuration for this platform. Note that a minimal defconfig and a full-feature defconfig are available. The minimal defconfig contains options for supporting the device and a few common peripherals and technologies. While the full defconfig includes much more support for things like USB devices, a more broad range of netfilter/iptables filter module support, etc.

make tsimx6ul_defconfig

# The minimal defconfig can alternately be used with:
# make tsimx6ul_minimal_defconfig


Build and Install

The following will build the kernel and modules, and install the kernel, modules, and headers to a folder and create a tarball from that. This tarball can be unpacked to bootable media, e.g. microSD, eMMC, USB, etc., to update an existing bootable disk.

The script below is most easily saved as a text file and run from the command line as a script. Most terminal emulators will accept the whole script copy/pasted in to the terminal. But it is also possible to copy paste each line of text in to a terminal. In any case, the following is an example of how to compile the kernel. The script or commands used can be modified as needed to suit a specific build pipeline.

The script assumes the following environment variables are set before it is run. See the above sections for what these variables should be set to for this specific platform.

ARCH
Used to indicate the target CPU architecture.
CROSS_COMPILE
Used to point to an appropriate cross toolchain for the target platform.
LOADADDR [Optional]
Used on some platforms to tell U-Boot where to load the file.
WILC [Optional]
Set to "y" to build and install the WILC3000 Wi-Fi/BLE external modules.
#!/bin/bash -e

# Always build zImage, most common. If LOADADDR is set, then uImage is also built
TARGETS="zImage"
if [ -n "${LOADADDR}" ]; then TARGETS+=" uImage"; fi

# Build the actual kernel, binary files, and loadable modules.
# Use as many CPUs to do this as possible.
make -j"$(nproc)" && make ${TARGETS} && make modules

# Create a temporary directory to install the kernel to in order to use that as a base directory for a tarball.
# Also creates a temporary file that is used as the tarball name.
TEMPDIR=$(mktemp -d)
TEMPFILE=$(mktemp)
mkdir "${TEMPDIR}/boot/"

# Adds "arch/arm/boot/" path prefix to each TARGET
cp $(for i in ${TARGETS}; do echo arch/arm/boot/$i; done) "${TEMPDIR}"/boot/

# Copy the full .config file to the target, this is optional and can be removed
cp .config "${TEMPDIR}"/boot/config

# Copy all of the generated FDT binary files to the target
cp arch/arm/boot/dts/*ts*.dtb  "${TEMPDIR}"/boot/

# Install kernel modules to the target
INSTALL_MOD_PATH="${TEMPDIR}" make modules_install

# Install kernel headers to the target, this is optional in most cases and can be removed to save space on the target
make headers_install INSTALL_HDR_PATH="${TEMPDIR}"

# If WILC is set to "y", then build the external module for the WILC300 Wi-Fi/BLE device.
# Note that this expects the source to be available as a subfolder in the kernel. See the above sections 
# for details on getting the driver source if it is used on this specific platform.
if [ "${WILC}" == "y" ]; then
    CONFIG_WILC_SPI=m INSTALL_MOD_PATH="${TEMPDIR}" make M=./wilc3000-external-module modules modules_install
fi

# Use fakeroot to properly set permissions on the target folder as well as create a tarball from this.
fakeroot sh -c "chmod 755 ${TEMPDIR};
        chown -R root:root ${TEMPDIR};
        tar czf ${TEMPFILE}.tar.gz -C ${TEMPDIR} .";

# Create a final output tarball and cleanup all of the temporary files and folder.
cp ${TEMPFILE}.tar.gz embeddedTS-linux-lts-"$(date +"%Y%m%d")"-"$(git describe --abbrev=8 --dirty --always)".tar.gz
rm -rf "${TEMPDIR}" "${TEMPFILE}"


At this point, the tarball can be unpacked to a bootable media for the device. This can be done from a booted device, or by mounting removable media from a host Linux workstation. For example, if the root folder of the target filesystem to be updated is mounted to /mnt/, the following can be used to unpack the above tarball:

# Ensure the target filesystem is mounted to /mnt first!

# Extract kernel tarball to target filesystem, 
tar xhf embeddedTS-linux-lts-*.tar.gz -C /mnt
Note: The h argument to tar is necessary on recent distributions that use paths with symlinks. Not using it can potentially render the whole filesystem no longer bootable.


This will correctly unpack the kernel, modules, and headers to the target filesystem which can then be booted as normal.

Features

ADC

The TS-7180 has four ADC channels, whose inputs are available on the P3 connector as AN_IN_1 through AN_IN_4. Each input may be configured to measure voltage in either one of two ranges (0-2.5V and 0-10.9V) or a 20mA current-loop. Voltage measurements outside those ranges can be accomplished by adding an external voltage divider and then also making corresponding adjustments to the scaling applied in the code examples below.

These ADCs are accessed through the IIO layer in Linux. This provides ADC samples up to 6ksps between all channels. The simplest API for slow speed acquisition is through /sys/:

cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw

To switch to the 10.9V input range, the appropriate enable must be set high. Each input AN_IN_1 through AN_IN_4 has its own enable, EN_ADC1_10V through EN_ADC4_10V, and these are controlled by GPIO #10 through #13. For example, to switch AN_IN_1 to the 10.9V range, run the following command:

gpioset 5 10=1

Note that the result must now be multiplied by (10.9/2.5). Note also that the input impedance will now be around 2k ohms.

To switch to the 20mA current-loop mode, the appropriate enable must be set high. These are EN_CL_1 through EN_CL_4, and are controlled by GPIO #6 through #9.

# Select 2.5V
gpioset 5 10=0
# Asssert EN_CL_1
gpioset 5 6=1
ADC Table
# 'raw' 2.5/10.9V Select 20mA Loop Select
AN_IN_1 in_voltage4_raw gpio bank 5 io 10 gpio bank 5 io 6
AN_IN_2 in_voltage5_raw gpio bank 5 io 11 gpio bank 5 io 7
AN_IN_3 in_voltage8_raw gpio bank 5 io 12 gpio bank 5 io 8
AN_IN_4 in_voltage9_raw gpio bank 5 io 13 gpio bank 5 io 9
Note: The four ADC inputs use the CPU ADC inputs 4,5,8, and 9, corresponding with the 'raw' entries in the above table.

The libiio library provides simple access to the IO. The fastest API is in C which will get about 6ksps.

/* Build with gcc adc-test.c -o adc-test -liio 
 * Gets ~6ksps
 * At the time of writing this does not support the buffer interface */

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <iio.h>

uint32_t scale_mv(uint32_t raw)
{
	/* scale a 0-4095 raw reading to 0-2500 mV */
	uint32_t val = raw * 5000 / (4095 * 2);

	return val;
}

int main(int argc, char **argv)
{
	static struct iio_context *ctx;
	static struct iio_device *dev;
	static struct iio_channel *chn[4];
	int i, ret;
	long long sample;

	ctx = iio_create_default_context();
	assert(ctx);
	dev = iio_context_find_device(ctx, "2198000.adc");
	assert(dev);

	chn[0] = iio_device_find_channel(dev, "voltage4", false);
	chn[1] = iio_device_find_channel(dev, "voltage5", false);
	chn[2] = iio_device_find_channel(dev, "voltage8", false);
	chn[3] = iio_device_find_channel(dev, "voltage9", false);

	for (i = 0; i < 4; i++) {
		ret = iio_channel_attr_read_longlong(chn[i], "raw", &sample);
		assert(!ret);
		printf("AN_CH%d_mv=%d\n", i, scale_mv((uint32_t)sample));
	}

	return 0;
}

The python bindings currently achieve about 2ksps with similar code.

#!/usr/bin/env python

import iio

ctx = iio.Context('local:')
dev = ctx.find_device('2198000.adc')

scan_channels = ["voltage4", "voltage5", "voltage8", "voltage9"]

for n, chan_name in enumerate(scan_channels, start=1):
	chn = dev.find_channel(chan_name)
	raw = int(chn.attrs['raw'].value)

	# Scale 0-4095 raw value to 0-2500(mV)
	scaled = raw * (2.5/4095)

	print('AN_CH{}_V={:.3f}'.format(n, scaled))

Bluetooth

TS-4100 Bluetooth

CAN

The i.MX6UL includes 2 CAN controllers which support the SocketCAN interface, and these are presented on the P3 & P5 connectors (custom populations may differ).

Before proceeding with the examples, see the Kernel's CAN documentation here.

Note: The EN_CAN_XVR# line must be set low, by executing the following command: tshwctl -a 20 -w 1

This board comes preinstalled with can-utils which can be used to communicate over a CAN network without writing any code. The candump utility can be used to dump all data on the network

## First, set the baud rate and bring up the device:
ip link set can0 type can bitrate 250000
ip link set can0 up

## Dump data & errors:
candump can0 &

## Send the packet with:
#can_id = 0x7df
#data 0 = 0x3
#data 1 = 0x1
#data 2 = 0x0c
cansend can0 -i 0x7DF 0x3 0x1 0x0C
## Some versions of cansend use a different syntax.  If the above
## commands gives an error, try this instead:
#cansend can0 7DF#03010C

The above example packet is designed to work with the Ozen Elektronik myOByDic 1610 ECU simulator to read the RPM speed. In this case, the ECU simulator would return data from candump with:

 <0x7e8> [8] 04 41 0c 60 40 00 00 00 
 <0x7e9> [8] 04 41 0c 60 40 00 00 00 

In the output above, columns 6 and 7 are the current RPM value. This shows a simple way to prove out the communication before moving to another language.

The following example sends the same packet and parses the same response in C:

#include <stdio.h>
#include <pthread.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main(void)
{
	int s;
	int nbytes;
	struct sockaddr_can addr;
	struct can_frame frame;
	struct ifreq ifr;
	struct iovec iov;
	struct msghdr msg;
	char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
	char *ifname = "can0";
 
	if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
		perror("Error while opening socket");
		return -1;
	}
 
	strcpy(ifr.ifr_name, ifname);
	ioctl(s, SIOCGIFINDEX, &ifr);
	addr.can_family  = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;
 
	if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("socket");
		return -2;
	}
 
 	/* For the ozen myOByDic 1610 this requests the RPM guage */
	frame.can_id  = 0x7df;
	frame.can_dlc = 3;
	frame.data[0] = 3;
	frame.data[1] = 1;
	frame.data[2] = 0x0c;
 
	nbytes = write(s, &frame, sizeof(struct can_frame));
	if(nbytes < 0) {
		perror("write");
		return -3;
	}

	iov.iov_base = &frame;
	msg.msg_name = &addr;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = &ctrlmsg;
	iov.iov_len = sizeof(frame);
	msg.msg_namelen = sizeof(struct sockaddr_can);
	msg.msg_controllen = sizeof(ctrlmsg);  
	msg.msg_flags = 0;

	do {
		nbytes = recvmsg(s, &msg, 0);
		if (nbytes < 0) {
			perror("read");
			return -4;
		}

		if (nbytes < (int)sizeof(struct can_frame)) {
			fprintf(stderr, "read: incomplete CAN frame\n");
		}
	} while(nbytes == 0);

	if(frame.data[0] == 0x4)
		printf("RPM at %d of 255\n", frame.data[3]);
 
	return 0;
}

See the Kernel's CAN documentation here. Other languages have bindings to access CAN such as Python, Java using JNI.

In production use of CAN we also recommend setting a restart-ms for each active CAN port.

ip link set can0 type can restart-ms 100

This allows the CAN bus to automatically recover in the event of a bus-off condition.

COM Ports

The TS-7180 provides three standard RS-232 ports, and one RS-485 port. A fourth RS-232 port is a non-standard option. All of these ports are presented on the P5 connector. The RS-485 port has auto-transmit-enable and an on-board terminator that may be enabled by installing the "485" jumper (adjacent to the RTC battery).

RS-232 ports 1 through 3

UART Linux /dev Connection on Terminal Block P5-A To "steal [1]" TX pin RX pin
UART2 ttymxc1 TX2/RX2 5 6
UART5 ttymxc4 TX1/RX1 2 3
UART7 ttymxc6 TX3/RX3 (unless "stolen") 4 7 8
  1. Writing this value to FPGA address 307 or 308 takes over this UART device for the cell modem or HD12, respectively. While "stolen", this physical RS-232 connection no longer possesses a UART device.
Note: The RS-232 transceiver chip on the board must be enabled before those ports can be used. This is done by running the command tshwctl -a 21 -w 3.

RS-485

UART 485+ 485-
ttymxc3 P5-13 P5-14

RS-485 on the P5 terminal block is accessible via /dev/ttymxc3, unless that device is "stolen" for RS-232 on the XBee/Nimbelink/MultiTech sockets or the HD12 header.

RS-232 port 4 (optional)

Custom boards may provide a fourth RS-232 port on P5, taking over the pins that by default are assigned to the second CAN controller. In this case, the pinout of the additional RS-232 port is:

UART TX RX
ttymxc7 P5-10 P5-11


The daughter-card interface (HD12 header) contains TTL-level TX/RX pins that may be used to connect to a CPU UART, with the caveat that to do so, one of the assigned UARTs must be reassigned to the header. The reassignment is done by writing to the register at address 308 in the FPGA. The table in the FPGA Registers section shows which UARTs may be reassigned. By default, the HD12 TX/RX pins are not connected to any UART.

CPU

TS-4100 CPU

eMMC

This board includes a Micron eMMC module. Our off-the-shelf builds are 4GiB, but up to 64GiB are available for larger builds. The eMMC flash appears to Linux as an SD card at /dev/mmcblk1. Our default programming will include one partition programmed with our Debian image.

eMMC also provides ways to estimate the wear on the module. First, determine your eMMC chipset revision:

root@tsimx6:~# mmc extcsd read /dev/mmcblk1 | grep "CSD rev"
[64446.059203]  mmcblk1: p1
  Extended CSD rev 1.7 (MMC 5.0)

or

root@tsimx6:~# mmc extcsd read /dev/mmcblk1 | grep "CSD rev"
[64446.059203]  mmcblk1: p1
  Extended CSD rev 1.5 (MMC 4.41)

In eMMC revision 5.0 and above, part of the specification includes a way to estimate lifetime of the chipset. For example:

root@tsimx6:~# mmc extcsd read /dev/mmcblk1 | grep -e EXT_CSD_DEVICE_LIFE_TIME -e PRE_EOL
[64618.159298]  mmcblk1: p1
eMMC Life Time Estimation A [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]: 0x01
eMMC Life Time Estimation B [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]: 0x01
eMMC Pre EOL information [EXT_CSD_PRE_EOL_INFO]: 0x01

If you have reconfigured your device as SLC, use TYP_A. If you are using the default MLC setting, use TYP_B. These LIFE_TIME_EST values indicate in 10s of percent how much of the reserve blocks are still available. The 0x1 value indicates < 10%. 0x7 would indicate < 70%.

EXT_CSD_PRE_EOL_INFO can also be used as an early warning indicator.

EXT_CSD_PRE_EOL_INFO values
Value Description
0x1 Normal (< 80% blocks used)
0x2 Warning (> 80% blocks used)
0x3 Urgent (>90% blocks used)

If this is below 5.0, you must use a vendor specific utility. Micron eMMC uses the emmcparm utility. Refer to Micron's TN-FC-25 for the emmcparm utility and related documentation.


Ethernet Ports

The NXP iMX6.UL processor implements two 10/100 Ethernet controllers via external Microchip/Micrel KSZ8081 PHYs and dual RJ45 jacks at the edge of the board. Their MAC addresses will always be sequential and are assigned from a Technologic Systems pool (e8:1a:58 or 00:d0:69).

Support is built into U-Boot as well as the Linux kernel, where standard utilities such as ifconfig/ip can be used to control these interfaces. See the Configuring the Network section for more details. The Precision Time Protocol (PTP) is also supported. For further specifics of this controller, see the CPU manual.

TS-7180-EthernetPorts.png

When the optional TS-DC767-POE daughter-card is installed, Power-over-Ethernet (PoE) may be received only via eth1 (ethernet@2188000 in U-Boot), which is the second port in the picture above.

FPGA

FPGA Registers

The TS-4100 FPGA provides additional DIO (that are connected to a Crossbar MUX), some miscellaneous system peripherals, and the 32-bit ZPU microcontroller. The FPGA is a Lattice MachXO2.

See the GPIO section for information on accessing the FPGA DIO.

The FPGA registers are accessed via an I2C bus. The FPGA emulates an I2C EEPROM, allowing for a simple and standard communication protocol to the FPGA. The FPGA is available at I2C addresses 0x28-0x2F. Accessing individual registers requires a chip address write, a 16-bit register address write, then 8-bit data values. A read or write stream can occur; every every byte read or written the internal register pointer moves to the next sequential register. This allows for reading or writing multiple registers without having to re-issue the chip and register address sequence.

We provide a simple access mechanism to the FPGA using the tshwctl utility. This utility can read or write arbitrary registers, return some information about the FPGA, as well as configure the Crossbar MUX. Sources for tshwctl and other utilities specific to the TS-4100 can be found in the TS-4100 utilities github repository.

The register map is broken in to a few different sections:

Section Address Bits Description
GPIOn 0x0000-0x007F 7:3 Reserved (Write 0)
2 GPIOn Input Data
1 GPIOn Output Data
0 GPIOn Output Enable
CROSSBARn 0x0080-0x00FF 7 CROSSBARn GPIO mode
6:0 CROSSBARn Value
BANKn 0x0100-0x010F 7:0 GPIOn Bank Input
0x0110-0x011F 7:0 GPIOn Bank Output Data
0x0120-0x012F 7:0 GPIOn Bank Output Enable
Misc 0x0130 7:0 Model Number MSB (0x41)
0x0131 7:0 Model Number LSB (0x00)
0x0132 7:0 FPGA Rev
0x0133-0x1FFF 7:0 Reserved
ZPU 0x1FFF-0x2FFF 7:0 ZPU RAM access

GPIOn

Registers 0x00-0x7F provide DIO control. The GPIO can be manipulated via the sysfs GPIO interface, information on this can be found in the GPIO section which is the recommended way to manipulate these pins. Each register in this section manipulates a different DIO pin. See the "FPGA I/O" table below for the register offset for this section. For example, to set "DIO_1" to a low output, the value 0x1 would be written to FPGA register 0x26 (the I/O number of "DIO_1").

Note: The sysfs GPIO interface is recommended because it guarantees a clean state transition. When setting a GPIOn register, modifying multiple bits simultaneously creates a race condition between the output and output enable bits. This may result in a short glitch on the pin as it transitions. The sysfs GPIO driver will only manipulate a single bit at a time resulting in a clean and guaranteed transition.


CROSSBARn

Registers 0x80-0xFF provide control for the Crossbar MUX. Like GPIOn above, each register represents a single DIO pin which are listed in the "FPGA I/O" table below. In order to change the MUX setting of any individual pin, its corresponding register is written to. For example, to set "UARTA_TXD" to output the data from "UART2_TXD", write the value of 0x5 (the I/O number of "UART2_TXD") to register (0x80+0x21) = 0xA1 (the I/O number of "UARTA_TXD" plus the CROSSBARn section starting register). The 'tshwctl' utility provides an easy abstraction for this process. See the Crossbar MUX section for more information on this process as well as a breakdown of Crossbar assignments.


BANKn

Registers 0x100-0x12F provide banked DIO access. The banked DIO allows for manipulating multiple pins simultaneously. Each bank register has 8 bits that represent 8 DIO pins. There are 48 bank registers total, 16 for GPIO input, 16 for GPIO output, and 16 for GPIO output enable. The bank and bit position of any given DIO listed in the "FPGA I/O" table below can be calculated by dividing the I/O number by 8 to get the bank number and then taking the modulus of that same calculation to get the bit position. The BANKn registers are not intended for normal use and exist to allow the ZPU to readily manipulate GPIO pins.


Misc

Registers 0x130-0x132 provide the model number and FPGA software revision. Registers 0x133-0x1FFF are reserved.


ZPU

Registers 0x2000-0x3FFF are RAM intended for use by the ZPU. Normally unused unless the ZPU is loaded and run, these registers can be used for volatile storage if wanted.


FPGA I/O
I/O Number Signal name Direction
0x01 SPARE_1 I/O
0x02 SPARE_2 I/O
0x03 SPARE_3 I/O
0x04 SPARE_4 I/O
0x05 UART2_TXD Input
0x06 UART2_CTS# Input
0x07 UART3_TXD Input
0x08 UART6_TXD Input
0x09 UART2_RXD Output
0x0A UART2_RTS# Output
0x0B UART3_RXD Output
0x0C UART6_RXD Output
0x0D WIFI_RXD Input
0x0E WIFI_RTS Input
0x0F WIFI_IRQ# Input
0x10 WIFI_TXD Output
0x11 WIFI_CTS Output
0x12 ZPU_BREAK Input
0x13 ZPU_RESET Output
0x14 EN_WIFI_PWR Output
0x15 WIFI_RESET# Output
0x16 EN_USB_HOST_5V Output
0x17 EN_LCD_3V3 Output
0x18 ETH_PHY_RESET# Output
0x19 OFF_BD_RESET# Output
0x1B GREEN_LED# Output
0x1C RED_LED# Output
0x1D UARTA_RXD I/O
0x1E UARTB_RXD I/O
0x1F UARTC_RXD I/O
0x20 UARTD_RXD I/O
0x21 UARTA_TXD I/O
0x22 UARTB_TXD I/O
0x23 UARTC_TXD I/O
0x24 UARTD_TXD I/O
0x25 DIO_0 I/O
0x26 DIO_1 I/O
0x27 DIO_2 I/O
0x28 DIO_3[1] I/O
0x29 DIO_4 I/O
0x2A DIO_5 I/O
0x2B DIO_6 I/O
0x2C DIO_7 I/O
0x2D DIO_8 I/O
0x2E DIO_9 I/O
0x31 DIO_12 I/O
0x32 DIO_13 I/O
0x33 DIO_14 I/O
0x34 DIO_15 I/O
0x35 DIO_16 I/O
0x36 DIO_17 I/O
0x37 DIO_18 I/O
0x38 DIO_19 I/O
0x39 DIO_20 I/O
0x3A DIO_21 I/O
0x3B DIO_22 I/O
0x3C DIO_23 I/O
0x3D DIO_24 I/O
0x3E DIO_25 I/O
0x3F DIO_26 I/O
0x40 DIO_27 I/O
0x41 DIO_28 I/O
0x42 DIO_29 I/O
0x43 DIO_30 I/O
0x44 DIO_31 I/O
0x45 DIO_32 I/O
0x46 DIO_33 I/O
0x47 DIO_34 I/O
0x48 DIO_35 I/O
0x49 DIO_36 I/O
0x4A DIO_37 I/O
0x4B DIO_38 I/O
0x4C DIO_39 I/O
0x4E DIO_41 I/O
0x4F DIO_42 I/O
0x50 DIO_43 I/O
0x51 DIO_44 I/O
0x52 DIO_45 I/O
0x53 DIO_46 I/O

DIO_3 Clock Override

DIO_3 has special modes that override the normal output and places a clock frequency on it. This is required for compatibility with certain TS-8XXX baseboards with MUXBUS functionality. See the ZPU section for more information on MUXBUS and TS-8XXX baseboards. The override consists of two registers, and only the Output Data bits in each register.

0x57:0x58 OD bit DIO_3 output
b00 DIO_3
b01 14.3 MHz clock
b10 12.5 MHz clock
b11 12.5 MHz clock
  1. For compatibility with various TS-8XXX baseboards, this pin has a special mode that allows it to output a clock. See I/O register 0x57 and 0x58.


Crossbar

The TS-4100 implements a limited crossbar MUX. This allows functional reassignment of pins to serve other purposes. For example, it is possible to connect different UARTs to different locations which can be used to repurpose otherwise unused UART ports. Additionally it can be used to connect a passthrough from a CPU GPIO to a pin that is only otherwise available from the FPGA.

Due to space constraints of the FPGA, there is a limitation of how pins can be assigned. The "Crossbar Assignable" column of the FPGA I/O table below lists the type of input assignment a pin will accept. The table also lists the default assignment of every pin.

  • All FPGA I/O pins listed in the table can have their input assigned as "GPIO". Note that even with an input assignment of "GPIO", some pins are still limited to being an input or output only GPIO. Pins assigned to an input of "GPIO" are controlled by the standard GPIO interface and numbered according to the FPGA GPIO table. Also note that if an invalid assignment is given to a pin, it will default back to the "GPIO" assignment.
  • An input of "GPIO" means that the logical input to the switching block comes directly from its associated pin. For example, the "UART2_TXD" signal is set to "GPIO" as its input. This means that the input to this switchable signal comes from the pin, which is connected to the CPU UART2_TXD signal. The "WIFI_TXD" signal has its input set to "UART2_TXD", with the "WIFI_TXD" physical pin connecting directly to the UART input of the Wi-Fi/BT module. This full path connects the CPU UART output, to the FPGA pin, to the "UART2_TXD" switching block, to the "WIFI_TXD" output pin, to the UART RX on the Wi-Fi/BT module.
  • No matter which FPGA I/O is assigned, the output signal must have its data direction set to out and the input signal must have its data direction set to in. Without these set properly the physical pins themselves will be unable to properly MUX signals.
  • The FPGA I/O pins compatible with an "Any" input assignment can be assigned any other pin in the table as an input.
  • The FPGA I/O pins compatible with "Input only" assignment can only be assigned "GPIO" as an input. They can, however, be used as inputs in to other pins that are able to accept it as an input. Attempting to set this pin to any other input assignment will result it in automatically reverting to "GPIO".
  • The FPGA I/O pins compatible with "UART only" assignments can only be assigned I/O numbers 0x01 through 0x08 inclusive. Attempting to assign any other input will automatically set the pin to "GPIO".


FPGA I/O
I/O Number Signal name Crossbar Assignable Default Input Assignment
0x01 SPARE_1 Any GPIO
0x02 SPARE_2 Any GPIO[1]
0x03 SPARE_3 Any GPIO[2]
0x04 SPARE_4 Any WIFI_IRQ#
0x05 UART2_TXD Input only GPIO
0x06 UART2_CTS# Input only GPIO
0x07 UART3_TXD Input only GPIO
0x08 UART6_TXD Input only GPIO
0x09 UART2_RXD Any WIFI_RXD
0x0A UART2_RTS# Any WIFI_RTS#
0x0B UART3_RXD Any UARTA_RXD
0x0C UART6_RXD Any UARTB_RXD
0x0D WIFI_RXD Input only GPIO
0x0E WIFI_RTS# Input only GPIO
0x0F WIFI_IRQ# Input only GPIO
0x10 WIFI_TXD UART only UART2_TXD
0x11 WIFI_CTS# UART only UART2_CTS#
0x12 ZPU_BREAK Input only GPIO
0x13 ZPU_RESET Input only GPIO
0x14 EN_WIFI_PWR Input only SPARE_2
0x15 WIFI_RESET# Input only SPARE_3
0x16 EN_USB_HOST_5V Input only GPIO
0x17 EN_LCD_3V3 Input only GPIO
0x18 ETH_PHY_RESET# Input only GPIO
0x19 OFF_BD_RESET# Input only GPIO
0x1B GREEN_LED# Input only GPIO
0x1C RED_LED# Input only GPIO
0x1D UARTA_RXD UART only GPIO
0x1E UARTB_RXD UART only GPIO
0x1F UARTC_RXD UART only GPIO
0x20 UARTD_RXD UART only GPIO
0x21 UARTA_TXD UART only UART3_TXD
0x22 UARTB_TXD UART only UART6_TXD
0x23 UARTC_TXD UART only GPIO
0x24 UARTD_TXD UART only GPIO
0x25 DIO_0 UART only GPIO
0x26 DIO_1 UART only GPIO
0x27 DIO_2 UART only GPIO
0x28 DIO_3 UART only GPIO
0x29 DIO_4 UART only GPIO
0x2A DIO_5 UART only GPIO
0x2B DIO_6 UART only GPIO
0x2C DIO_7 UART only GPIO
0x2D DIO_8 UART only GPIO
0x2E DIO_9 UART only GPIO
0x31 DIO_12 UART only GPIO
0x32 DIO_13 UART only GPIO
0x33 DIO_14 UART only GPIO
0x34 DIO_15 UART only GPIO
0x35 DIO_16 UART only GPIO
0x36 DIO_17 UART only GPIO
0x37 DIO_18 UART only GPIO
0x38 DIO_19 UART only GPIO
0x39 DIO_20 UART only GPIO
0x3A DIO_21 UART only GPIO
0x3B DIO_22 UART only GPIO
0x3C DIO_23 UART only GPIO
0x3D DIO_24 UART only GPIO
0x3E DIO_25 UART only GPIO
0x3F DIO_26 UART only GPIO
0x40 DIO_27 UART only GPIO
0x41 DIO_28 UART only GPIO
0x42 DIO_29 UART only GPIO
0x43 DIO_30 UART only GPIO
0x44 DIO_31 UART only GPIO
0x45 DIO_32 UART only GPIO
0x46 DIO_33 UART only GPIO
0x47 DIO_34 UART only GPIO
0x48 DIO_35 UART only GPIO
0x49 DIO_36 UART only GPIO
0x4A DIO_37 UART only GPIO
0x4B DIO_38 UART only GPIO
0x4C DIO_39 UART only GPIO
0x4E DIO_41 UART only GPIO
0x4F DIO_42 UART only GPIO
0x50 DIO_43 UART only GPIO
0x51 DIO_44 UART only GPIO
0x52 DIO_45 UART only GPIO
0x53 DIO_46 UART only GPIO
0x80 GPIO[3] N/A N/A
  1. While assigned to GPIO by default, this is used as an input to EN_WIFI_PWR
  2. While assigned to GPIO by default, this is used as an input to WIFI_RESET#
  3. Special assignment that sets a pin to GPIO control rather than crossbar MUX path

Modify Crossbar Assignments

All of the crossbar assignments are managed through the FPGA syscon registers, in the bank of registers labeled as "CROSSBARn". However, this can more easily be managed through the 'tshwctl' utility. The 'tshwctl' utility provides a pair of flags that make it quick to assign an input to an FPGA I/O. For example, normally UART 2 is set up to connect to the on-board Bluetooth module. However, if a model of TS-4100 does not have this module present, or it is not needed in a particular application, it can be assigned to another unused set of UART pins on the TS-SOCKET interface, like UARTC:

tshwctl --out 0x9 --in 0x1f  # Set UART2_RXD's input assignment to be UARTC_RXD. The UART2_RXD signal in the FPGA is connected directly to UART2_RXD on the CPU.
tshwctl --out 0x23 --in 0x5  # Set UARTC_TXD's input assignment to be UART2_TXD. The UART2_TXD signal in the FPGA is connected directly to UART2_TXD on the CPU.
tshwctl --out 0x10 --in 0x80 # Set WIFI_TXD's input assignment to GPIO. This prevents UART2_TXD data from appearing on this pin when unwanted.
tshwctl --out 0x11 --in 0x80 # Set WIFI_CTS's input assignment to GPIO. This prevents UART2_RTS data from appearing on this pin when unwanted.
Note: Using 'tshwctl' to set crossbar assignments also sets the the GPIO direction. The I/O number passed as --out is set to a low output, and the I/O number passed as --in is set to an input.


The latest sources for 'tshwctl' and other utilities can be found in the TS-4100 utilities github repository.

GPIO

The i.MX6UL CPU and FPGA GPIO are exposed using a kernel character device. This interface provides a set of files and directories for interacting with GPIO which can be used from any language that interact with special files in linux using ioctl() or similar. For our platforms, we pre-install the "libgpiod" library and binaries package. Documentation on this package can be found here. This section only covers using these userspace tools and does not provide guidance on using the libgpiod library in end applications. Please see the libgpiod documentation for this purpose.

A user with suitable permissions to read and write /dev/gpiochip* files can immediately interact with GPIO pins. For example, to read the push_sw:

gpioget 2 18 # Returns 0 when pressed, 1 when not

Multiple pins in the same chip can be read simultaneously by passing multiple pin numbers separated by spaces.

This GPIO interface also provides labels for all the I/O. To get a reference from the board of all GPIO run:

gpioinfo

The TS-7180 provides seven IO ports that can sink up to 500mA, or withstand up to 30V at the input. These are available on the P3 connector. DIO_1 through DIO_7 appear as GPIO bank 5 io 37 through 43 (when used as inputs), and as GPIO bank 5 io 22 through 28 (when used as outputs). For example, to read the state of DIO_1, enter the following command:

gpioget 5 37

To drive enable the 500mA sink, enter the following command:

gpioset 5 22=1
gpiochip0 - 32 lines:
	line   0: "BOOT_MODE_0" unused input active-high 
	line   1:      unnamed       unused   input  active-high 
	line   2:  "I2C_1_CLK"       unused   input  active-high 
	line   3:  "I2C_1_DAT"       unused   input  active-high 
	line   4:      "ADC_1"       unused   input  active-high 
	line   5:      "ADC_2"       unused   input  active-high 
	line   6:   "ETH_MDIO"       unused   input  active-high 
	line   7:    "ETH_MDC"       unused   input  active-high 
	line   8:      "ADC_3"       unused   input  active-high 
	line   9:      "ADC_4"       unused   input  active-high 
	line  10:      unnamed       unused   input  active-high 
	line  11:      unnamed       unused   input  active-high 
	line  12:      unnamed       unused   input  active-high 
	line  13:      unnamed       unused   input  active-high 
	line  14:      unnamed       unused   input  active-high 
	line  15:      unnamed       unused   input  active-high 
	line  16: "CONSOLE_TXD" unused input active-high 
	line  17: "CONSOLE_RXD" unused input active-high 
	line  18:    "SPARE_1"       unused   input  active-high 
	line  19:     "EN_485"       unused   input  active-high 
	line  20:  "UART2_TXD"       unused   input  active-high 
	line  21:  "UART2_RXD"       unused   input  active-high 
	line  22:  "CAN_2_TXD"       unused   input  active-high 
	line  23: "CAN2_RXD_3V" unused input active-high 
	line  24:  "UART3_TXD"       unused   input  active-high 
	line  25:  "UART3_RXD"       unused   input  active-high 
	line  26: "UART3_CTS#"       unused   input  active-high 
	line  27: "UART3_RTS#"       unused   input  active-high 
	line  28:  "UART4_TXD"       unused   input  active-high 
	line  29:  "UART4_RXD"       unused   input  active-high 
	line  30:  "UART5_TXD"       unused   input  active-high 
	line  31:  "UART5_RXD"       unused   input  active-high 
gpiochip1 - 32 lines:
	line   0: "ENET1_RX_DATA0" unused input active-high 
	line   1: "ENET1_RX_DATA1" unused input active-high 
	line   2: "ENET1_RX_EN" unused input active-high 
	line   3: "ENET1_TX_DATA0" unused input active-high 
	line   4: "ENET1_TX_DATA1" unused input active-high 
	line   5: "ENET1_TX_EN" unused input active-high 
	line   6: "ENET1_TX_CLK" unused input active-high 
	line   7: "ENET1_RX_ER" unused input active-high 
	line   8: "ENET2_RX_DATA0" unused input active-high 
	line   9: "ENET2_RX_DATA1" unused input active-high 
	line  10: "ENET2_RX_EN" unused input active-high 
	line  11: "ENET2_TX_DATA0" unused input active-high 
	line  12: "ENET2_TX_DATA1" unused input active-high 
	line  13: "ENET2_TX_EN" unused input active-high 
	line  14: "ENET2_TX_CLK" unused input active-high 
	line  15: "ENET2_RX_ER" unused input active-high 
	line  16:     "SD_CMD"       unused   input  active-high 
	line  17:     "SD_CLK"       unused   input  active-high 
	line  18:      "SD_D0"       unused   input  active-high 
	line  19:      "SD_D1"       unused   input  active-high 
	line  20:      "SD_D2"       unused   input  active-high 
	line  21:      "SD_D3"       unused   input  active-high 
	line  22:      unnamed       unused   input  active-high 
	line  23:      unnamed       unused   input  active-high 
	line  24:      unnamed       unused   input  active-high 
	line  25:      unnamed       unused   input  active-high 
	line  26:      unnamed       unused   input  active-high 
	line  27:      unnamed       unused   input  active-high 
	line  28:      unnamed       unused   input  active-high 
	line  29:      unnamed       unused   input  active-high 
	line  30:      unnamed       unused   input  active-high 
	line  31:      unnamed       unused   input  active-high 
gpiochip2 - 32 lines:
	line   0: "HD1_SPI_CS"    "spi_imx"  output  active-high [used]
	line   1: "JTAG_FPGA_TCK" unused input active-high 
	line   2: "JTAG_FPGA_TMS" unused input active-high 
	line   3: "JTAG_FPGA_TDI" unused input active-high 
	line   4:      "WDOG#"       unused   input  active-high 
	line   5:  "I2C_3_DAT"       unused   input  active-high 
	line   6:  "I2C_3_CLK"       unused   input  active-high 
	line   7:      unnamed       unused   input  active-high 
	line   8: "HD1_I2C_CLK" "scl" output active-high [used]
	line   9: "HD1_I2C_DAT" "sda" output active-high [used]
	line  10: "HD1_DIG_INPUT" unused input active-high 
	line  11: "NO_CHRG_JMP#" unused input active-high 
	line  12: "EN_NIM_USB#" unused input active-high 
	line  13:  "CAN_1_TXD"       unused   input  active-high 
	line  14: "CAN1_RXD_3V" unused input active-high 
	line  15:  "XBEE_CTS#"       unused   input  active-high 
	line  16: "U_BOOT_JMP#" unused input active-high 
	line  17:      unnamed       unused   input  active-high 
	line  18: "PUSH_SW_CPU#" unused input active-high 
	line  19: "NIMBEL_PWR_ON" unused input active-high 
	line  20:      unnamed       unused   input  active-high 
	line  21:  "UART7_TXD"       unused   input  active-high 
	line  22:  "UART7_RXD"       unused   input  active-high 
	line  23:        "ID4"       unused   input  active-high 
	line  24: "JTAG_FPGA_TDO" unused input active-high 
	line  25:  "UART8_TXD"       unused   input  active-high 
	line  26:  "UART8_RXD"       unused   input  active-high 
	line  27:        "ID1"       unused   input  active-high 
	line  28: "ETH_PHY_RESET#" unused input active-high 
	line  29:      unnamed       unused   input  active-high 
	line  30:      unnamed       unused   input  active-high 
	line  31:      unnamed       unused   input  active-high 
gpiochip3 - 32 lines:
	line   0:   "EMMC_CLK"       unused   input  active-high 
	line   1:   "EMMC_CMD"       unused   input  active-high 
	line   2:    "EMMC_D0"       unused   input  active-high 
	line   3:    "EMMC_D1"       unused   input  active-high 
	line   4:    "EMMC_D2"       unused   input  active-high 
	line   5:    "EMMC_D3"       unused   input  active-high 
	line   6:  "SPI_4_CLK"       unused   input  active-high 
	line   7: "SPI_4_MOSI"       unused   input  active-high 
	line   8: "SPI_4_MISO"       unused   input  active-high 
	line   9:  "SPI_4_CS#"    "spi_imx"  output  active-high [used]
	line  10:  "MAG_N_IRQ"       unused   input  active-high 
	line  11: "FPGA_RESET#" unused input active-high 
	line  12: "SPI_3_FPGA_CS#" "spi_imx" output active-high [used]
	line  13:  "SPI_3_CLK"       unused   input  active-high 
	line  14: "SPI_3_MOSI"       unused   input  active-high 
	line  15: "SPI_3_MISO"       unused   input  active-high 
	line  16:      "PWM_5"       unused   input  active-high 
	line  17:  "UART6_TXD"       unused   input  active-high 
	line  18:  "UART6_RXD"       unused   input  active-high 
	line  19:        "ID5"       unused   input  active-high 
	line  20:   "GYRO_INT"       unused   input  active-high 
	line  21: "6UL_FORCE_5V_ON" unused input active-high 
	line  22: "EN_EMMC_3.3V#" "?" output active-low [used]
	line  23: "EN_YEL_LED#" "?" output active-low [used]
	line  24: "EN_RED_LED#" "?" output active-low [used]
	line  25: "EN_GRN_LED#" "?" output active-low [used]
	line  26: "EN_BLU_LED"          "?"  output  active-high [used]
	line  27: "FRAM_SPI_CS#" "spi_imx" output active-high [used]
	line  28: "SD_VSEL_1.8V" unused input active-high 
	line  29:      unnamed       unused   input  active-high 
	line  30:      unnamed       unused   input  active-high 
	line  31:      unnamed       unused   input  active-high 
gpiochip4 - 32 lines:
	line   0: "POWER_FAIL"       unused   input  active-high 
	line   1:   "FPGA_IRQ"       unused   input  active-high 
	line   2:      unnamed       unused   input  active-high 
	line   3:  "GPIO_DVFS"          "?"  output  active-high [used]
	line   4:      unnamed       unused   input  active-high 
	line   5: "SILAB_C2_CLK" unused input active-high 
	line   6: "SILAB_C2_DATA" unused input active-high 
	line   7: "SILAB_C2_RESET" unused input active-high 
	line   8:    "SPARE_4"       unused   input  active-high 
	line   9:      unnamed       unused   input  active-high 
	line  10:      unnamed       unused   input  active-high 
	line  11:      unnamed       unused   input  active-high 
	line  12:      unnamed       unused   input  active-high 
	line  13:      unnamed       unused   input  active-high 
	line  14:      unnamed       unused   input  active-high 
	line  15:      unnamed       unused   input  active-high 
	line  16:      unnamed       unused   input  active-high 
	line  17:      unnamed       unused   input  active-high 
	line  18:      unnamed       unused   input  active-high 
	line  19:      unnamed       unused   input  active-high 
	line  20:      unnamed       unused   input  active-high 
	line  21:      unnamed       unused   input  active-high 
	line  22:      unnamed       unused   input  active-high 
	line  23:      unnamed       unused   input  active-high 
	line  24:      unnamed       unused   input  active-high 
	line  25:      unnamed       unused   input  active-high 
	line  26:      unnamed       unused   input  active-high 
	line  27:      unnamed       unused   input  active-high 
	line  28:      unnamed       unused   input  active-high 
	line  29:      unnamed       unused   input  active-high 
	line  30:      unnamed       unused   input  active-high 
	line  31:      unnamed       unused   input  active-high 
gpiochip5 - 64 lines:
	line   0: "WIFI_RESET#" unused output active-high 
	line   1: "EN_WIFI_PWR" unused output active-high 
	line   2:      unnamed       unused   input  active-high 
	line   3:      unnamed       unused   input  active-high 
	line   4:      unnamed       unused   input  active-high 
	line   5:   "FRAM_WP#"       unused   input  active-high 
	line   6:    "EN_CL_1"       unused   input  active-high 
	line   7:    "EN_CL_2"       unused   input  active-high 
	line   8:    "EN_CL_3"       unused   input  active-high 
	line   9:    "EN_CL_4"       unused   input  active-high 
	line  10: "EN_ADC1_10V" unused input active-high 
	line  11: "EN_ADC2_10V" unused input active-high 
	line  12: "EN_ADC3_10V" unused input active-high 
	line  13: "EN_ADC4_10V" unused input active-high 
	line  14: "EN_SD_POWER" "?" output active-high [used]
	line  15: "EN_USB_HOST_5V" unused input active-high 
	line  16: "EN_OFF_BD_5V" unused input active-high 
	line  17: "EN_AUX_PWR"       unused   input  active-high 
	line  18: "EN_NIMBEL_3.3V" unused input active-high 
	line  19: "EN_GPS_PWR#" unused input active-high 
	line  20: "EN_CAN_XVR#" "en-can" output active-high [used]
	line  21: "EN_232_XVR"       unused   input  active-high 
	line  22: "EN_LS_OUT_1" unused input active-high 
	line  23: "EN_LS_OUT_2" unused input active-high 
	line  24: "EN_LS_OUT_3" unused input active-high 
	line  25: "EN_LS_OUT_4" unused input active-high 
	line  26: "EN_LS_OUT_5" unused input active-high 
	line  27: "EN_LS_OUT_6" unused input active-high 
	line  28: "EN_LS_OUT_7" unused input active-high 
	line  29:      unnamed       unused   input  active-high 
	line  30:      unnamed       unused   input  active-high 
	line  31:      unnamed       unused   input  active-high 
	line  32:   "DIG_IN_1"       unused   input  active-high 
	line  33:   "DIG_IN_2"       unused   input  active-high 
	line  34:   "DIG_IN_3"       unused   input  active-high 
	line  35:   "DIG_IN_4"       unused   input  active-high 
	line  36: "SD_BOOT_JMP#" unused input active-high 
	line  37:   "DIO_1_IN"       unused   input  active-high 
	line  38:   "DIO_2_IN"       unused   input  active-high 
	line  39:   "DIO_3_IN"       unused   input  active-high 
	line  40:   "DIO_4_IN"       unused   input  active-high 
	line  41:   "DIO_5_IN"       unused   input  active-high 
	line  42:   "DIO_6_IN"       unused   input  active-high 
	line  43:   "DIO_7_IN"       unused   input  active-high 
	line  44:      unnamed       unused   input  active-high 
	line  45:      unnamed       unused   input  active-high 
	line  46:      unnamed       unused   input  active-high 
	line  47:         "N7"       unused   input  active-high 
	line  48:         "P7"       unused   input  active-high 
	line  49:      unnamed       unused   input  active-high 
	line  50:      unnamed       unused   input  active-high 
	line  51:      unnamed       unused   input  active-high 
	line  52:      unnamed       unused   input  active-high 
	line  53:      unnamed       unused   input  active-high 
	line  54:      unnamed       unused   input  active-high 
	line  55:      unnamed       unused   input  active-high 
	line  56:      unnamed       unused   input  active-high 
	line  57:      unnamed       unused   input  active-high 
	line  58:      unnamed       unused   input  active-high 
	line  59:      unnamed       unused   input  active-high 
	line  60:      unnamed       unused   input  active-high 
	line  61:      unnamed       unused   input  active-high 
	line  62:      unnamed       unused   input  active-high 
	line  63:      unnamed       unused   input  active-high 

GPIOs into the CPU, such as those on the push switch near the row of LEDs (PUSH_SW_CPU#) and internal headers can generate interrupts and be used with gpiomon(1):

root@tsimx6:~# gpiomon 2 18
event: FALLING EDGE offset: 18 timestamp: [1643650592.848516846]
event:  RISING EDGE offset: 18 timestamp: [1643650593.225238304]
^Croot@tsimx6:~# 

One way of turning that into something useful would be by running it in a shell script:

while true ; do
      event=$(gpiomon --num-events=1 --falling-edge 2 18)
      echo "received $event"
      # do something
done
Note: DIO lines on the FPGA (gpiochip5) don't have their own interrupts, thus the gpiomon(1) command does not normally work for them.

CPU GPIO Table

TS-7180 CPU DIO Table

FPGA GPIO Table

TS-7180 FPGA DIO Table

I2S Audio

TS-7180 I2S Audio

Interrupts

TS-7180 interrupts

LEDs

There are four LEDS on the TS-7180 that may be controlled by the user through the sysfs interface. These are colored yellow, green, red, and blue.

To turn an LED on, write a 1 to 'brightness'. To turn it off again, write a 0.

# Example:  Turn on the Blue LED...
echo 1 > /sys/class/leds/blue-led/brightness

# Turn it off again...
echo 0 > /sys/class/leds/blue-led/brightness

A number of triggers are also available for each LED, including timers, disk activity, and heartbeat. These allow the LEDs to represent various system activities as they occur. See the kernel LED documentation for more information on triggers and general use of LED class devices.

MicroSD Card Interface

The i.MX6ul SDHCI driver supports MicroSD (0-2GB), MicroSDHC (4-32GB), and MicroSDXC(64GB-2TB). The cards available on our website on average support up to 16MB/s read, and 22MB/s write using this interface. Sandisk Extreme cards with UHS support have shown 58MB/s Read and 59MB/s write. The linux driver provides access to this socket at /dev/mmcblk0 as a standard Linux block device.

This graph shows our SD write endurance test for 40 TS-7553 boards running a doublestore stress test on 4GB Sandisk MicroSD cards. A failure is marked on the graph for a card once a single bit of corruption is found.

Seethe IMX6ul reference manual for more information on this controller.

We have performed compatibility testing on the Sandisk MicroSD cards we provide, and we do not suggest switching brands/models without your own qualification testing. Though SD cards in theory will all follow the standard and just work, in practice cards vary significantly and can fail in subtle ways. We do not recommend ATP or Transcend MicroSD cards specifically due to known corruption issues that can occur after many GB of written data.

Our testing has shown that on average microSD cards will last between 6-12TB of written data before showing a single bit of corruption. This is enough for most applications to write for years and not see any issues, but for more reliable consider the eMMC which is expected to last over 100TB of writes. Higher end SD cards can also extend this, but industrial grade SD cards typically carry a cost much higher than the eMMC.

MicroSD cards should not be powered down during a write/erase cycle or you will eventually experience disk corruption. It is not always possible for fsck to recover from the types of failures that will be seen with SD power loss. The system should be designed to avoid power loss to SD cards, or the eMMC module should be used for storage instead which can be configured to be resilient to power loss.

Power Consumption

TS-7180 Power Consumption

RTC

The TS-7180 includes an ST M41T00S low-power serial real-time clock (RTC) with battery-backup. This is /dev/rtc0 in our images, and is accessed using the standard hwclock command.

USB

USB Host

The TS-7180 provides a standard USB 2.0 host supporting 480Mb/s. Typically this is interfaced with by using standard Linux drivers, but low level USB communication is possible using libusb.

USB DEVICE

The USB type B device port is connected to the onboard Silabs for USB to serial console.

SPI

The i.MX6UL CPU has a native SPI peripheral that is used in a number of places on the TS-7180. Additionally, kernel spidev support is added to allow SPI access from userspace. User SPI can be used fora generic SPI connection on HD12, as well as user accessible FRAM.

The ECSPI peripheral in the i.MX6UL CPU is highly flexible and can even support SPI slave mode. For more information on the peripheral itself, please see the CPU reference manual.


The SPI peripheral is accessible as /dev/spidev2.x, where "x" is one of the three chip select lines. Additional chip select lines can be implemented if needed by adding them to the kernel device-tree by using GPIO.

CS Device
0 Reserved for FPGA
1 HD12
2 FRAM

See the kernel spidev documentation for more information on interfacing with the SPI peripherals.

TWI

The i.MX6 supports standard I²C at 100 kHz, or using fast mode for 400 kHz operation. The CPU is connected to two I²C buses on the TS-7180.

I2C1 is internal to the TS-7180 and connects to the onboard Silabs supervisory microcontroller at 100 kHz; and to the onboard ST M41T00S real-time clock (RTC).

/dev/i2c-0
Address Device
0x4a #Silabs
0x68 #RTC

The second I²C bus, I2C3, is connected to the onboard FPGA, for communication between it and the CPU. This bus also runs at 400 kHz by default.

/dev/i2c-2
Address Device
0x28-0x2f #FPGA


In addition to the CPU I²C buses, a bit-banged I²C interface is available on the daughter-card interface, using gpio. The following command will instantiate (create a device node for) a new ssd1306 display at I²C address 0x3C:

  echo ssd1306 0x3c > /sys/bus/i2c/devices/i2c-4/new_device

Once this is done, i2c-tools can manipulate the I²C device, or a the downstream developer can write their own client. Technologic Systems has provided a simple client program for writing to an SSD1306 OLED display connected to the HD12 connector. The photo below shows output on the display.

Download the source-code tarball here: File:Ssd1306-demo.tar.gz


Note: It is also possible to request the kernel to bitbang additional I²C buses as needed. See an example here.

The kernel makes the I²C available at /dev/i2c-#, where "#" is 0, 2, or 4. You can use the i2c-tools (i2cdetect, i2cget, i2cset), or you can write your own client.

Watchdog

The kernel provides an interface to the watchdog driver at /dev/watchdog. Refer to the kernel documentation for more information:

WIFI

The TS-7180 uses an Atmel ATWILC3000-MR110CA IEEE 802.11 b/g/n Link Controller Module With Integrated Bluetooth® 4.0. Linux provides support for this module using the wilc3000 driver.

Summary features:

  • IEEE 802.11 b/g/n RF/PHY/MAC SOC
  • IEEE 802.11 b/g/n (1x1) for up to 72 Mbps PHY rate
  • Single spatial stream in 2.4GHz ISM band
  • Integrated PA and T/R Switch Integrated Chip Antenna
  • Superior Sensitivity and Range via advanced PHY signal processing
  • Advanced Equalization and Channel Estimation
  • Advanced Carrier and Timing Synchronization
  • Wi-Fi Direct and Soft-AP support
  • Supports IEEE 802.11 WEP, WPA, and WPA2 Security
  • Supports China WAPI security
  • Operating temperature range of -40°C to +85°C


External Interfaces

Terminal Blocks

The TS-7180 includes four removable terminal blocks (OSTTJ0811030) for UARTs, CAN, ADC, and other general purpose IO.

TS-7180 Terminal Blocks-8.png
P5-A
Pin # Description
1 Ground
2 RS-232_STC_TXD (/dev/ttymxc4)
3 RS-232_STC_RXD (/dev/ttymxc4)
4 Ground
5 RS-232_STC_TXD (/dev/ttymxc1)
6 RS-232_STC_RXD (/dev/ttymxc1)
7 RS-232_STC_TXD (/dev/ttymxc6)
8 RS-232_STC_RXD (/dev/ttymxc6)
P5-B
Pin # Description
1 Ground
2 STC_CAN_2_H (can2 interface)[1]
3 STC_CAN_2_L (can1 interface)[2]
4 Ground
5 STC_485+ (/dev/ttymxc3)
6 STC_485- (/dev/ttymxc3)
7 Ground
8 WAKE-UP / gpio bank 2 io 18
  1. RS-232_STC_TXD (/dev/ttymxc5) depending on option
  2. RS-232_STC_RXD (/dev/ttymxc5) depending on option
TS-7180 Terminal Blocks-12.png
P3-A
Pin # Description
1 DIO_1_IN gpio bank 5 io 37 / EN_LS_OUT_1 gpio bank 5 io 21 [1]
2 DIO_2_IN gpio bank 5 io 38 / EN_LS_OUT_2 gpio bank 5 io 22 [1]
3 DIO_3_IN gpio bank 5 io 39 / EN_LS_OUT_3 gpio bank 5 io 23 [1]
4 DIO_4_IN gpio bank 5 io 40 / EN_LS_OUT_4 gpio bank 5 io 24 [1]
5 DIO_5_IN gpio bank 5 io 41 / EN_LS_OUT_5 gpio bank 5 io 25 [1]
6 DIO_6_IN gpio bank 5 io 42 / EN_LS_OUT_6 gpio bank 5 io 26 [1]
7 DIO_7_IN gpio bank 5 io 43 / EN_LS_OUT_7 gpio bank 5 io 27 [1]
8 DIG_IN_3_STC gpio bank 5 io 0
9 DIG_IN_3_STC gpio bank 5 io 1
10 Ground
11 Ground
12 Ground
P3-B
Pin # Description
1 STC_CAN_1_H (can1 interface)
2 STC_CAN_1_L (can1 interface)
3 AN_IN_1 (ADC)
4 AN_IN_2 (ADC)
5 AN_IN_3 (ADC)
6 AN_IN_4 (ADC)
7 DIG_IN_3_STC gpio bank 5 io 2
8 DIG_IN_4_STC gpio bank 5 io 3
9 5V
10 Ground
11 Ground
12 Ground
  1. 1.0 1.1 1.2 1.3 1.4 1.5 1.6 These low side switches can sink 500mA. Set the output gpio to 1 to enable the sink, or 0 to disable or read the 0-30V input.

Revisions and Changes

TS-7180 PCB Revisions

Revision Description
C Initial sampling revision
D All Rev C fixes plus SD card socket moved slightly for clearance.

U-Boot Changelog

TS-7180 U-boot changelog

FPGA Changelog

Version Description
13 Engineering Sampling release version.
14 REV C board support
15 GPS PPS passthrough to FPGA_IRQ to support the pps_gpio driver
16
  • MT_RESET#, with pull-up, for better Multi-Tech modem support.
  • Mux of eight P3 pins into CPU GPIO chip 0 line 18, enabling their transactions to be detected via gpiomon.

Software Images

Debian Changelog

TS-7180 Debian Changelog

Product Notes

FCC Advisory

This equipment generates, uses, and can radiate radio frequency energy and if not installed and used properly (that is, in strict accordance with the manufacturer's instructions), may cause interference to radio and television reception. It has been type tested and found to comply with the limits for a Class A digital device in accordance with the specifications in Part 15 of FCC Rules, which are designed to provide reasonable protection against such interference when operated in a commercial environment. Operation of this equipment in a residential area is likely to cause interference, in which case the owner will be required to correct the interference at his own expense.

If this equipment does cause interference, which can be determined by turning the unit on and off, the user is encouraged to try the following measures to correct the interference:

Reorient the receiving antenna. Relocate the unit with respect to the receiver. Plug the unit into a different outlet so that the unit and receiver are on different branch circuits. Ensure that mounting screws and connector attachment screws are tightly secured. Ensure that good quality, shielded, and grounded cables are used for all data communications. If necessary, the user should consult the dealer or an experienced radio/television technician for additional suggestions. The following booklets prepared by the Federal Communications Commission (FCC) may also prove helpful:

How to Identify and Resolve Radio-TV Interference Problems (Stock No. 004-000-000345-4) Interface Handbook (Stock No. 004-000-004505-7) These booklets may be purchased from the Superintendent of Documents, U.S. Government Printing Office, Washington, DC 20402.

Limited Warranty

See our Terms and Conditions for more details.