TS-4100
Note: | The TS-4100 is currently under development. This means software and features are very likely to change on the TS-4100. There may also be some features that are currently not implemented or not fully tested, please see the Revisions and changes for more information. |
Product Page | |
Product Images | |
Specifications | |
Documentation | |
---|---|
REV A Schematic | |
Mechanical Drawing | |
FTP Path | |
Processor | |
Freescale i.MX6ul 528MHz or 696MHz | |
i.MX6ul Product Page | |
CPU Documentation |
Overview
The TS-4100 is a TS-SOCKET Macrocontroller Computer on Module designed for extremely low power applications.
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.
Booting up the board
Power input to the TS-4100 TS-SOCKET requires a single 5 V source from the baseboard (which may be regulated from other voltage ranges). Refer to the TS-SOCKET Connector section for information on power pins.
The TS-4100 can also be powered standalone from 5 V via the micro USB AB port labeled "P1" when in standalone and not attached to a baseboard. The "P1" connector is mechanically locked out on many of our baseboards to prevent powering the device from multiple sources. For more information on how to operate the TS-4100 in standalone mode see section on Standalone Mode.
Once power is applied to the system, there will be output on the debug console port. The connecting to a console section of the manual provides information on getting the serial console connected. The first output is from U-Boot and will resemble the following when booting from SD card:
U-Boot 2016.03-00367-gb3ce405827 (Jul 02 2019 - 16:40:10 -0700) CPU: Freescale i.MX6UL rev1.1 at 396 MHz Reset cause: POR Board: Technologic Systems TS-4100 FPGA: Rev 11 Silab: Rev 2 I2C: ready DRAM: 1 GiB MMC: FSL_SDHC: 0, FSL_SDHC: 1 Baseboard ID: 0x8 Baseboard Rev: 0 Net: FEC0 [PRIME] Press Ctrl+C to abort autoboot in 1 second(s) starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found USB1: USB EHCI 1.00 scanning bus 1 for devices... 1 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found No storage devices, perhaps not 'usb start'ed..? Booting from the SD card ... ** File not found /boot/boot.scr ** ** File not found /boot/ts4100-fpga.vme ** 29205 bytes read in 146 ms (195.3 KiB/s) 8 detected 5244088 bytes read in 390 ms (12.8 MiB/s) Kernel image @ 0x80800000 [ 0x000000 - 0x5004b8 ] ## Flattened Device Tree blob at 83000000 Booting using the fdt blob at 0x83000000 Using Device Tree in place at 83000000, end 8300a214 Starting kernel ...
Note: | The "*** Warning - bad CRC, using default environment" message can be safely ignored when the unit is first booted. This means that no environment variables have been saved to disk, and U-Boot is falling back to the default. If "env save" is run, this will save the environment to disk, and this message will go away unless there are further issues. |
The default U-Boot boot process will check for a bootable USB drive, and then will check the "SD Boot" jumper state if it exists. If the "SD boot" jumper is set, it will boot to the Linux on the SD card, otherwise it will boot to the eMMC. Details about the bootup process, features, and other U-Boot information can be found in the U-Boot sections.
Get a Console
The console UART (ttymxc0) is a TTL UART at 115200 baud, 8n1 (8 data bits, no parity, 1 stop bit), and no flow control. On the macrocontroller this is CN2_93 (TX), CN2_95 (RX). Various baseboards bring this out using different methods. For example, the TS-8550 baseboard brings out a DB-9 connector with the console as RS-232. Other baseboards have a jumper to switch between the console port and another serial port. Some baseboards require an adapter board like the TS-9449. Refer to the baseboard model you are using here for more information on any specific jumpers or ports to connect to for console. Additionally, the TS-4100 console can be accessed via the USB micro connector, P2, on the TS-4100. Note that due to the location of the port and the height of the TS-4100 above a baseboard, this may not be a viable option for all applications.
Console from Linux
There are many serial terminal applications for Linux, three common used applications are picocom
, screen
, and minicom
. These examples demonstrate all three applications and assume that the serial device is "/dev/ttyUSB0" which is common for USB adapters. Be sure to replace the serial device string with that of the device on your workstation.
picocom
is a very small and simple client.
sudo picocom -b 115200 /dev/ttyUSB0
screen
is a terminal multiplexer which happens to have serial support.
sudo screen /dev/ttyUSB0 115200
Or a very commonly used client is minicom
which is quite powerful but requires some setup:
sudo minicom -s
- Navigate to 'serial port setup'
- Type "a" and change location of serial device to "/dev/ttyUSB0" then hit "enter"
- If needed, modify the settings to match this and hit "esc" when done:
E - Bps/Par/Bits : 115200 8N1 F - Hardware Flow Control : No G - Software Flow Control : No
- Navigate to 'Save setup as dfl', hit "enter", and then "esc"
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.
U-Boot
Note: | This section is incomplete at this time. |
This platform includes U-Boot as the bootloader to load and boot the full operating system. The i.MX6UL processor loads U-Boot from the eMMC flash at power-on. U-Boot allows booting images from the microSD, eMMC, NFS, or USB. U-Boot is a general purpose bootloader that is capable of booting into common Linux distributions, Android, QNX, or others.
On a normal boot, output from U-Boot will be similar to the following:
U-Boot 2016.03-00367-gb3ce405827 (Jul 02 2019 - 16:40:10 -0700) CPU: Freescale i.MX6UL rev1.1 at 396 MHz Reset cause: POR Board: Technologic Systems TS-4100 FPGA: Rev 11 Silab: Rev 2 I2C: ready DRAM: 1 GiB MMC: FSL_SDHC: 0, FSL_SDHC: 1 Baseboard ID: 0x8 Baseboard Rev: 0 Net: FEC0 [PRIME] Press Ctrl+C to abort autoboot in 1 second(s) starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found USB1: USB EHCI 1.00 scanning bus 1 for devices... 1 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found No storage devices, perhaps not 'usb start'ed..? Booting from the SD card ... ** File not found /boot/boot.scr ** ** File not found /boot/ts4100-fpga.vme ** 29205 bytes read in 146 ms (195.3 KiB/s) 8 detected 5244088 bytes read in 390 ms (12.8 MiB/s) Kernel image @ 0x80800000 [ 0x000000 - 0x5004b8 ] ## Flattened Device Tree blob at 83000000 Booting using the fdt blob at 0x83000000 Using Device Tree in place at 83000000, end 8300a214 Starting kernel ...
When running standalone, the TS-4100 will default to booting from eMMC. This behavior can be changed by modifying the U-Boot environment variable "force_jpsdboot". Normally this variable does not exist in the U-Boot environment, if it does exist, setting it to a value of 1 will force U-Boot to attempt to boot from microSD. If it is set to a value of 0, then U-Boot will attempt to boot from eMMC. Additionally, running U-Boot commands are used direct booting to another source such as NFS, USB, or microSD.
Many of our compatible baseboards offer an "SD Boot" jumper to control the behavior between SD and eMMC. See the specific baseboard manual for the combination being used for more detailed information. If designing a custom baseboard, we recommend reviewing our custom baseboard design recommendations for better controlling boot flow with U-Boot.
Entering U-Boot Shell
The U-Boot shell is a powerful tool. It allows modification of the environment, as well as the ability to run commands directly.
Under most circumstances the U-Boot environment is set up to handle most boot situations, however it may be necessary to modify the environment. When using any of the following methods to enter the U-Boot shell, this will cause U-Boot to read a script file from an attached USB mass storage device before dropping to the U-Boot shell. This will happen regardless even if USB boot is disabled for normal boot.
When the TS-4100 is booted standalone, a prompt is provided by U-Boot to press ctrl+c
followed by a 1 second window. If ctrl+c
is found incoming on the serial terminal within this time window then U-Boot will drop to its shell. This behavior can be modified by setting the U-Boot environment variable force_bootdelay
. Normally this variable does not exist in U-Boot environment, if it does, it will force the timeout for pressing ctrl+c
to be however many seconds the variable is set to. If it is set to 0, then the ctrl+c
prompt is skipped.
Note: | Use caution when setting "force_bootdelay", a value of 0 means it is no longer possible to enter the U-Boot shell without booting the device on a compatible baseboard that has a "U-Boot" jumper! |
On our compatible baseboards or custom designed baseboards there are two ways to break in to the U-Boot shell. Note that some compatible baseboards may still offer a prompt as outlined above. See the specific baseboard manual for the combination being used for more detailed information.
The baseboard has a "U-Boot" jumper. When set, this will cause U-Boot to read a script file from an attached USB mass storage device before dropping to the U-Boot shell. When the jumper is not set, the unit will boot as normal. See our custom baseboard design recommendations for information on how the U-Boot jumper should be set up in order to be supported by our default U-Boot configuration.
The baseboard offers a push switch which is broken out from pin 9 on CN1 of the TS-4100. This button can be held down before applying power, and at least 5 seconds after power is applied.
This allows for out of the box functionality and customized production via a USB drive. In order to provide increased security, the push switch entry to U-Boot can be disabled via the U-Boot environment variable rstuboot
. The following U-Boot commands can be used to disable the push switch check, thereby preventing it from being able to enter the U-Boot shell.
env set rstuboot 0
env save
Removing the rstuboot
environment variable, or setting it to a 1, will re-enable the ability for the push switch to interrupt U-Boot and drop to its shell. See our custom baseboard design recommendations for information on how the push switch should be set up in order to be supported by our default U-Boot configuration.
On baseboards that support both a jumper and the push switch, disabling the push switch will still allow the jumper method of entering the U-Boot shell.
U-Boot Environment
The eMMC flash contains both the U-Boot executable binary and U-Boot environment. Our default build has 2 MiB of environment space which can be used for variables and boot scripts. The following commands are examples of how to manipulate the U-Boot environment:
# 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 environment changes to the SPI flash
# Otherwise changes are lost
env save
# Restore environment to default
env default -a
# Remove a variable
env delete emmcboot
U-Boot Commands
# The most important command is
help
# This can also be used to see more information on a specific command
help i2c
# This is a command added to U-Boot by TS to read the baseboard ID on our
# System on Module devices
bbdetect
echo ${baseboard} ${baseboardid}
# The echo will return something similar to:
# TS-8390 2
# Boots into the binary at $loadaddr. The loaded file needs to have
# the U-Boot header from mkimage. A uImage already contains this.
bootm
# Boots into the binary at $loadaddr, skips the initrd, specifies
# the FDT addrress so Linux knows where to find the device tree
bootm ${loadaddr} - ${fdtaddr}
# Boot a Linux zImage loaded at $loadaddr
bootz
# Boot in to a Linux zImage at $loadaddr, skip initrd, specifies
# the FDT address to Linux knows where to find the device tree
bootz ${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 can set fuses in the processor
# Setting fuses can brick the unit, will void the warranty,
# and should not be done in most cases
fuse
# GPIO can be manipulated from U-Boot. Keep in mind that the IOMUX
# in U-Boot is only setup enough to boot the device, so not all pins will
# be set to GPIO mode out of the box. Boot to the full operating system
# for more GPIO support.
# GPIO are specified in bank and IO in this manual. U-Boot uses a flat numberspace,
# so for bank 2 DIO 25, this would be number (32*1)+25=89
# The formula thus being (32*(bank-1)+dio)=flattened_dio
# Note that on some products, bank 1 is the first bank
# Set 2_25 low
gpio clear 83
# Set 2_25 high
gpio set 83
# Read 2_25
gpio input 83
# 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
# Load kernel from USB
usb start
load usb 0:1 ${loadaddr} /boot/uImage
# Load kernel from SATA
sata init
load sata 0:1 ${loadaddr} /boot/uImage
# View the FDT from U-Boot
load mmc 0:1 ${fdtaddr} /boot/imx6q-ts4900.dtb
fdt addr ${fdtaddr}
fdt print
# It is possible to blindly jump to any memory location
# This is similar to bootm, but it does not require
# the use of 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, 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
# SPI access is through the SF command
# Be careful with sf commands since
# this is where U-Boot and the FPGA bitstream exist
# Improper use can render the board unbootable
sf probe
# Delay in seconds
sleep 10
# 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 sf probe
# Print U-Boot version/build information
version
Modify Linux Kernel cmdline
The Linux kernel cmdline can be customized by modifying the cmdline_append variable. If new arguments are added, the existing value should also be included with the new arguments.
env set cmdline_append rw rootwait console=ttymxc0,115200 quiet
env save
The kernel command line can also be modified from from within Linux by creating a U-Boot script. From the Linux shell prompt run the following commands to install the necessary tools and create the script:
apt-get update && apt-get install u-boot-tools -y
echo "env set cmdline_append rw rootwait console=ttymxc0,115200 quiet" > /boot/boot.source
mkimage -A arm -T script -C none -n 'tsimx6ul boot script' -d /boot/boot.source /boot/boot.scr
The boot.source includes the plain text commands to be run in U-Boot on startup. The mkimage tool adds a checksum and header to the output file which then can be loaded by U-Boot. The .scr file should not be edited directly.
By default, every boot to SD, eMMC, and NFS will look for the file "/boot/boot.scr" and attempt to load and run it if it exists. This allows for modification of the boot process dynamically every boot without having to enter the U-Boot shell and modify it.
Booting From NFS
U-Boot's NFS support can be used to load a kernel, device tree binary, and root filesystem. The default scripts include an example NFS boot script. Because of the way U-Boot tries to infer server data, the script we use will bypass this, making it more straightforward to use an NFS root that will not be heavily dependent on a particular network configuration.
# Set this to your NFS server IP
env set nfsip 192.168.0.1
# Set this to your NFS root path
env set nfsroot /path/to/nfs/rootfs/
env save
To boot to NFS root once the server details are set:
# Boot to NFS once
run nfsboot;
# To make the NFS boot the persistent default
env set bootcmd run nfsboot;
env save
Note: | 'bootcmd' is used to test for whether the system should stop at the U-Boot shell or continue, the above will make it difficult to get back to the U-Boot shell as it will always attempt to boot regardless of jumper status. |
On the TS-4100, U-Boot will only boot to the network from the first physical port. The port that Linux considers to be "eth1".
Booting From USB
By default, U-Boot will attempt to read a U-Boot script from a USB drive on every bootup. This process copies /tsinit.scr
from the first partition of the USB drive into memory and jumps in to the script. If the drive or script do not exist, then this process is bypassed and U-Boot will continue its boot flow.
This process is attempted on every boot unless it is disabled. It can be disabled by modifying the U-Boot environment variable usbboot
. If usbboot
is set to 0 then this step will be bypassed on normal boot cycles. It is enabled by default to allow for a custom production process to be used.
If the U-Boot shell is entered by holding the push switch or using the U-Boot jumper (on baseboards with either a push switch or U-Boot jumper), this process will always run before dropping to the U-Boot shell regardless of the state of the usbboot
variable. If the U-Boot shell is entered by pressing ctrl+c
(on boaseboards without a U-Boot jumper or TS-4100 standalone), then this process is never run since autoboot is aborted and the shell is immediately entered. In this state, the USB boot process can always be manually started with the command run usbprod
.
For information on creating a USB drive to write existing images to either SD and/or eMMC, see the section on our custom production process for more details on the process.
To make a bootable USB drive that boots in to the same environment as SD or eMMC, create a single ext3 partition on a USB drive and unpack the rootfs tarball located here.
Additionally, a U-Boot script file, /tsinit.scr
, must be created and placed in the root folder of this partition. In order to do this, a script must be created and converted to the U-Boot .scr
format. This process requires a set of U-Boot specific tools. These tools are available on most every Linux distribution, the instructions below are for Debian, either on a host PC or on the device itself. See the package installation documentation for other respective distributions.
Install U-Boot tools in Debian
apt-get update && apt-get install u-boot-tools -y
Create the file "tsinit.source" in the root of the USB drive with the Linux filesystem:
# Prepare with:
# mkimage -A arm -T script -C none -n 'imx6ul usb' -d tsinit.source tsinit.scr
# DO NOT MANUALLY EDIT THE .scr FILE
if load usb 0:1 ${loadaddr} /boot/ts${model}-fpga.vme;
then fpga load 0 ${loadaddr} ${filesize};
fi;
if load usb 0:1 ${fdtaddr} /boot/imx6ul-ts${model}-${baseboardid}.dtb;
then echo "${baseboardid} detected;"
else echo "Booting default device tree";
load usb 0:1 ${fdtaddr} /boot/imx6ul-ts${model}.dtb;
fi;
load usb 0:1 ${loadaddr} /boot/zImage;
setenv bootargs root=/dev/sda1 rootwait rw ${cmdline_append} bbid=0x${baseboardid} bbrev=0x${baseboardrev};
run silowaitcharge;
bootz ${loadaddr} - ${fdtaddr};
fi;
Then in the same directory generate the tsinit.scr file:
mkimage -A arm -T script -C none -n 'imx6ul usb' -d tsinit.source tsinit.scr
Update U-Boot
WARNING: | Installing a custom U-Boot is not recommended and may cause the device to fail to boot. |
The TS-4100 uses slightly different U-Boot binaries for the 512 MB and 1 GB RAM variants. This is due to different DDR timing that needs to be set up at the start of U-Boot. When updating U-Boot, be sure to use the script that exists in U-Boot discussed below as it will use the correct file name and will reduce any potential issues
The latest U-Boot binary can be downloaded from the TS-4100 FTP site. Copy these files to /boot/ on the 1st partition of the SD card (or eMMC). The U-Boot binary can be updated by inserting that SD card in to the TS-4100, setting the jumpers to boot from SD, power up the unit, and enter the U-Boot shell. At the U-Boot prompt, the following command can be used:
run update-uboot
The above script will use the /boot/u-boot-${imx_type}.imx file from the SD card or eMMC, depending on the state of the SD Boot jumper.
Note that when running the TS-4100 standalone, the "update-uboot" command will default to searching the eMMC. Setting the environment variable "jpsdboot" to "on" (do not save the environment to disk otherwise it may cause booting issues later!), and then running the 'run update-uboot' command will cause U-Boot to look in "/boot" on the first SD card partition for the update files necessary.
U-Boot Development
We do provide our U-Boot sources, but we do not recommend rebuilding a custom U-Boot binary as it can leave the system in an unbootable state.
If proceeding with building a custom U-Boot, use the "tsimx_v2016.03_4.1.15_2.0.0_ga" branch from our github repo: https://github.com/embeddedTS/u-boot-imx this can be executed with the following command:
git clone https://github.com/embeddedTS/u-boot-imx.git -b tsimx_v2016.03_4.1.15_2.0.0_ga u-boot-ts4100
When compiling, we recommend using ONLY this cross-compiler, the use of any other compiler may cause issues or may leave the system in an unbootable state! Specifically, we have experienced RAM problems when using a more recent cross compiler to build this version of U-Boot. The tarball can be extracted with the following:
mkdir /opt/toolchains/ts4100/
tar -xf tsimx6ul-glibc-gnueabihf-4.9.4.tar.xz -C /opt/toolchains/ts4100/
Once the tarball has been properly extracted set up the following variables and run the build script:
export ARCH=arm
export CROSS_COMPILE=/path/to/folder/bin/arm-tsimx6ul-linux-gnueabihf-
After the environment variables have been set up as shown above the build is now ready to be executed:
cd /path/to/u-boot-imx
./build-imx6ul.sh ts4100
This will output binaries for 1 GB and 512 MB RAM variants in "/u-boot-imx/out/" that can be written to the device using the steps in Update U-Boot.
Note: | If the following error message is received: "error while loading shared libraries: libmpfr.so.4: cannot open shared object file:" create the following symbolic link in Debian:
sudo ln -s /usr/lib/x86_64-linux-gnu/libmpfr.so.6 /usr/lib/x86_64-linux-gnu/libmpfr.so.4
|
POST
The TS-4100 U-Boot includes a simple POST test. This is normally used in production to verify basic functionality rapidly before continuing to more thorough testing. By default, this is not enabled on every boot, but it can be added via U-Boot scripting if there is a need for additional confidence in the application. The POST test quickly verifies basic functionality of: USB, RTC (if present), Ethernet PHY, WiFi/BT module (if present), eMMC (see warning below), RAM, and the supervisory microcontroller.
The post test can be run with the following command in U-Boot:
post
WARNING: | The 'post' command has an optional "-d" argument; when this argument is passed it does a write and readback test of the eMMC and any other soldered down flash media on the TS-4100 or baseboards which is DESTRUCTIVE to the data on the disk! Note that it will not modify the boot sector contents of the eMMC which is needed by U-Boot. The eMMC chip is still tested for basic functionality without the argument passed, but no data is read or written from the disk itself. |
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 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 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 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
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
These instructions assume the TS-4100 is booted from SD card all the way to Linux. They also assume that the eMMC is unmodified, with a single partition. If the partition table has been modified, 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", the "GPT" partition table format is not supported by U-Boot.
# Verify nothing else has the partition mounted
umount /dev/mmcblk1p1
mkfs.ext3 /dev/mmcblk1p1
mount /dev/mmcblk1p1 /mnt/emmc
wget http://ftp.embeddedTS.com/ftp/ts-socket-macrocontrollers/ts-4100-linux/distributions/debian/ts4100-armhf-stretch-latest.tar.xz
tar -xf ts4100-armhf-stretch-latest.tar.xz -C /mnt/emmc
umount /mnt/emmc
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. |
Once written, the files on disk can be verified to ensure they are the same as the source files in the archive. To do so, run the following commands:
mount /dev/mmcblk1p1 /mnt/emmc
cd /mnt/emmc/
md5sum --quiet -c md5sums.txt
cd -
umount /mnt/emmc
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.
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-lts
# To do a shallow clone of just the latest snapshot of the linux-4.9.y branch, which results in a smaller download size and size on disk, the following command can be used:
# git clone --depth 1 https://github.com/embeddedTS/linux-lts -b 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
Baseboard ID
All of our off the shelf baseboards contain a hard-wired 8-input multiplexer to indicate the baseboard model. This is not required to implement in custom baseboards, but it can be useful to identify the board model in software. The baseboard model is determined in the bootloader and the proper device tree is selected for the respective baseboard. For example, the TS-8551-4100 would use the "imx6ul-ts4100-16.dtb" device tree file. In U-Boot the device tree IDs are specified in hex, so 0x16 (U-Boot defaults to using base 16 for number representations) will match baseboard ID 22. If a board does not have a specific device tree, it will fall back to the default device tree which is "imx6ul-ts4100.dtb".
4 DIO pins are used to obtain the baseboard model ID. The red LED (CN2_06), green LED (CN2_08), BUS_DIR (CN1_98), and BD_ID_DATA (CN1_83) are used for this purpose. All of these IO pins can be used normally outside of acquiring the ID number.
The 6 least significant input pins (Y0 - Y5) are used to define the baseboard model. The upper two inputs (Y6 and Y7) define board revision.
For custom baseboards we have reserved the address 42 which will never be used by our standard products.
ID | Baseboard |
---|---|
0 | TS-8200 |
1 | Reserved, do not use |
2 | TS-TPC-8390 |
4 | TS-8500 |
5 | TS-8400 |
6 | TS-8160 |
7 | TS-8100 |
8 | TS-8820-BOX |
9 | TS-8150 |
10 | TS-TPC-8900 |
11 | TS-8290 |
13 | TS-8700 |
14 | TS-8280 |
15 | TS-8380 |
16 | TS-AN20 |
17 | TS-TPC-8920 |
19 | TS-8550 |
20 | TS-TPC-8950 |
22 | TS-8551 |
42 | Reserved for customer use, never used by us |
63 | TS-8200 |
Bluetooth
CAN
The i.MX6UL CPU has two FlexCAN ports that use the linux SocketCAN implementation. The ports can be set up and used with the following commands:
ip link set can0 up type can bitrate 1000000
ip link set can1 up type can bitrate 1000000
At this point the ports can be used with standard SocketCAN libraries. The default Debian distribution ships with "can-utils" installed by default in order to test the ports or as a simple packet send/receive tool. The 'candump' utility can be used to dump all data packets from the CAN network, while the 'cansend' utility will send out packets.
# To print all incoming CAN packets
candump can0
# To send out a CAN packet
cansend can1 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 FPGA includes a crossbar to select where UARTs are routed so these can be changed. Below are the default mappings.
Port Name | Device | TX | RX | TXEN |
---|---|---|---|---|
UART0 | ttymxc0 | CN2_93 | CN2_95 | N/A |
UART1 | ttymxc1 | CN2_82 | CN2_84 | N/A |
UART2 | ttymxc2 | Onboard Bluetooth RX | Onboard Bluetooth TX | N/A |
UART3 | ttymxc3 | CN2_78 | CN2_80 | N/A |
UART4 | ttymxc4 | CN2_90 | CN2_92 | N/A |
UART6 | ttymxc6 | CN2_86 | CN2_88 | N/A |
The #FPGA includes a crossbar to select where UARTs are routed so these can be changed, but these are the default mappings: todo
CPU
eMMC
Ethernet Port
This platform includes two Ethernet devices using the dual in-CPU MACs and external PHYs. The MAC addresses are assigned from the Technologic System's OUI of 00:D0:69:xx:xx:xx, and the two MAC addresses assigned will always be sequential. These MAC addresses are burned into the CPU's fuses during production.
U-Boot supports only the ethernet port on CN1_01-11 (odd numbered pins); once booted to Linux, this is eth1
. The CN2_16-24 (even numbered pins) provide eth0
in Linux.
Note: | Ethernet Magnetics should be placed as close to CN2 as possible on the base board. |
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.
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 |
- ↑ 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".
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 |
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. Documentation on these tools 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 switch on the TS-8551-4100 which is connected to FPGA DIO_9:
gpioget 5 46
Multiple pins in the same chip can be read simultaneously by passing multiple pin numbers separated by spaces.
To write to a pin, the gpioset
command is used. For example, to set LCD_D02:
gpioset 2 7=0
Multiple pins in the same chip can be set simultaneously by passing multiple <pin>=<value>
pairs separated by spaces.
If a call to gpioset
or gpioget
fails with the message Device or resource busy
that means that specific GPIO is claimed by another device. The command cat /sys/kernel/debug/gpio
can be used to get a list of all of the system GPIO and what has claimed them.
The gpiomon
tool can be used to monitor pins for changes.
CPU GPIO Table
Chip | Pin | Functions | Location |
---|---|---|---|
0 | 0 | (USB1 OTG ID) / GPIO | CN2_074 |
0 | 1 | (GPIO) / ADC input | CN2_012 |
0 | 8 | (PWM0) / ADC input / GPIO | CN1_057 |
0 | 9 | (PWM1) / ADC input / GPIO | CN2_091 |
0 | 10 | (Ethernet PHY power en.) / GPIO | CN2_046 |
0 | 11 | (I2S Master Clock) / GPIO | CN2_054 |
0 | 12 | (I2S TX Sync) / GPIO | CN2_038 |
0 | 13 | (I2S TX Bit Clock) / GPIO | CN2_036 |
0 | 14 | (I2S RX Data) / GPIO | CN2_042 |
0 | 15 | (I2S TX Data) / GPIO | CN2_040 |
0 | 16 | (Console UART TXD) / GPIO | CN2_093 / Microcontroller |
0 | 17 | (Console UART RXD) / GPIO | CN2_095 / Microcontroller |
0 | 18 | (GPIO) | FPGA Crossbar SPARE_1 |
0 | 19 | (GPIO) | FPGA Crossbar SPARE_2 |
0 | 20 | (UART1 TXD) / GPIO | CN2_082 |
0 | 21 | (UART1 RXD) / GPIO | CN2_084 |
0 | 22 | (CAN1 TX) / GPIO | CN1_071 |
0 | 23 | (CAN1 RX) / GPIO | CN1_069 |
0 | 24 | (UART2 TXD) / GPIO | FPGA Crossbar UART2_TXD |
0 | 25 | (UART2 RXD) / GPIO | FPGA Crossbar UART2_RXD |
0 | 26 | (UART2 CTS) / GPIO | FPGA Crossbar UART2_CTS |
0 | 27 | (UART2 RTS) / GPIO | FPGA Crossbar UART2_RTS |
0 | 28 | (UART3 TXD) / GPIO | FPGA Crossbar UART3_TXD |
0 | 29 | (UART3 RXD) / GPIO | FPGA Crossbar UART3_RXD |
0 | 30 | (UART4 TXD) / GPIO | CN2_090 |
0 | 31 | (UART4 RXD) / GPIO | CN2_092 |
2 | 0 | (GPIO) / LCD CLK | CN1_049 |
2 | 1 | (GPIO) / LCD DE | CN1_055 |
2 | 2 | (GPIO) / LCD HSYNC | CN1_051 |
2 | 3 | (GPIO) / LCD VSYNC | CN1_053 |
2 | 7 | (GPIO) / LCD D02 | CN1_028 |
2 | 8 | (GPIO) / LCD D03 | CN1_030 |
2 | 9 | (GPIO) / LCD D04 | CN1_032 |
2 | 10 | (GPIO) / LCD D05 | CN1_034 |
2 | 11 | (GPIO) / LCD D06 | CN1_038 |
2 | 12 | (GPIO) / LCD D07 | CN1_040 |
2 | 13 | (CAN0 TX) / GPIO | CN2_097 |
2 | 14 | (CAN0 RX) / GPIO | CN2_099 |
2 | 15 | (GPIO) / LCD D10 | CN1_023 |
2 | 16 | (GPIO) / LCD D11 | CN1_025 |
2 | 17 | (GPIO) / LCD D12 | CN1_027 |
2 | 18 | (GPIO) / LCD D13 | CN1_031 |
2 | 19 | (GPIO) / LCD D14 | CN1_033 |
2 | 20 | (GPIO) / LCD D15 | CN1_035 |
2 | 21 | (UART6 TXD) / GPIO | FPGA Crossbar UART6_TXD |
2 | 22 | (UART6 RXD) / GPIO | FPGA Crossbar UART6_RXD |
2 | 23 | (PWM4) / GPIO / LCD D18 | CN1_041 |
2 | 24 | (PWM5) / GPIO / LCD D19 | CN1_043 |
2 | 25 | (GPIO) / LCD D20 | CN1_045 |
2 | 26 | (GPIO) / LCD D21 | CN1_042 |
2 | 27 | (GPIO) / LCD D22 | CN1_044 |
2 | 28 | (GPIO) / LCD D23 | CN1_046 |
3 | 10 | (SPI2 Offboard CS#) / GPIO | CN2_065 / HD1_13 |
3 | 11 | (GPIO) | FPGA_RESET# |
3 | 12 | (SPI2 FPGA CS#) / GPIO | FPGA |
3 | 13 | (SPI2 CLK) / GPIO | CN2_071 / HD1_15 / FPGA |
3 | 14 | (SPI2 MOSI) / GPIO | CN2_067 / HD1_11 / FPGA |
3 | 15 | (SPI2 MISO) / GPIO | CN2_069 / HD1_9 / FPGA |
3 | 16 | (GPIO) | FPGA Crossbar SPARE_3 |
3 | 17 | (GPIO) / Camera MCLK | CN2_034 |
3 | 18 | (GPIO) / Camera PIXCLK | CN2_032 |
3 | 19 | (GPIO) / Camera VSYNC | CN2_072 |
3 | 20 | (GPIO) / Camera HSYNC | CN2_070 |
3 | 21 | (GPIO) / Camera D0 | CN2_052 |
3 | 22 | (GPIO) / Camera D1 | CN2_056 |
3 | 23 | (GPIO) / Camera D2 | CN2_058 |
3 | 24 | (GPIO) / Camera D3 | CN2_060 |
3 | 25 | (GPIO) / Camera D4 | CN2_062 |
3 | 26 | (GPIO) / Camera D5 | CN2_064 |
3 | 27 | (GPIO) / Camera D6 | CN2_066 |
3 | 28 | (GPIO) / Camera D7 | CN2_068 |
4 | 0 | POWER_FAIL[1] | N/A |
4 | 1 | ZPU IRQ | FPGA |
4 | 8 | (Wi-Fi IRQ) / GPIO | FPGA Crossbar SPARE_4 |
- ↑ Asserted when external power input falls below valid input range.
FPGA GPIO Table
- ↑ GPIO pins are formatted in "<chip>_<pin>" notation.
I2S Audio
The i.MX6ul includes an I2S bus. Under Linux this normally connects to a compatible audio codec like the SGTL5000 to provide audio support. See the TS-TPC-8390 schematic sheet 5 and dtb as an example.
Under Linux this is compatible with alsa/pulseaudio, and more commonly accessed by application developers using apis like gstreamer.
Interrupts
The i.MX6UL CPU GPIO are also able to function as interrupts on rising and falling edges. This is accessible from the kernel as well as userspace. Userspace IRQs and handled via libgpiod.
LCD Interface
LEDs
The LEDs available to the TS-4100 are dependent on the baseboard that is used. However, all of our compatible baseboards will at lease provide a green and a red LED that is used for status as well as can be controlled by end applications. Note that when used standalone, the TS-4100 does not provide controllable status LEDs.
The kernel provides access to control the LEDs using the sysfs interface:
# Set Red led on
echo 1 > /sys/class/leds/red-led/brightness
# Set Red led off
echo 0 > /sys/class/leds/red-led/brightness
# Set Green led on
echo 1 > /sys/class/leds/green-led/brightness
# Set Green led off
echo 0 > /sys/class/leds/green-led/brightness
The kernel provides various triggers that can be useful for debugging purposes. The trigger
file for a given LED is in its named sub-directory, e.g.
echo "heartbeat" > /sys/class/leds/red-led/trigger
Trigger value | LED toggles on |
---|---|
none | Default, no action, manually controlled by brightness file
|
rc-feedback | IR Reciever trigger [1] |
can0-tx | CAN0 transmit activity |
can0-rx | CAN0 receive activity |
can0-rxtx | CAN0 activity |
can1-tx | CAN1 transmit activity |
can1-rx | CAN1 receive activity |
can1-rxtx | CAN1 activity |
mmc0 | microSD activity |
mmc1 | eMMC activity |
timer | 2hz blink |
oneshot | Blinks after delay. [2] |
heartbeat | Similar to timer, but varies the period based on system load |
backlight | Toggles on FB_BLANK |
gpio | Toggle based on a specified gpio. [3] |
cpu0 | Blink on CPU core 0 activity |
default-on | Only turns on by default. Only useful for device tree. |
transient | Specify on/off with time to turn off. [4] |
- ↑ There is no IR directly on the TS-4100, this would be from a USB peripheral.
- ↑ See the Kernel documentation for more details on "oneshot" operation.
- ↑ When this trigger is set, a "gpio" file appears in the same directory which can be used to specify what GPIO to follow when it blinks
- ↑ See the Kernel documentation for more details on "transient" operation.
Reading the contents of the trigger
will list all compatible triggers as well as the current trigger set. The currently set trigger is indicated by surrounding brackets, e.g. none [timer] cpu ...
Status LED Behavior
The following applies to the stock TS-4100 bootup process, from U-Boot to fully booted. Note that when used standalone, the TS-4100 does not provide these status LEDs.
Green | Red | Meaning |
---|---|---|
Solid On | Off | System is booted and running. |
Off | Solid On | The TS-4100 is in U-Boot. If the LEDs remain in this state for longer than a few seconds, U-Boot may be unable to find a proper boot device, or booting of the kernel failed. The green LED will flash briefly at power-on. |
Off | Off | The device is not able to boot. Typically, either too low of an input voltage is provided or the unit has been otherwise damaged. If a stable voltage is being provided as per the power input specifications and the input power is able to meet the device's power consumption requirements, an RMA may be needed to have the unit diagnosed by our repair team. |
TS-4100 LED
The TS-4100 SoM has a single LED on the module itself. This is directly controlled by the supervisory microcontroller and is used to indicate its status.
At power-on of the microcontroller, when USB serial is connected or 5 VDC input to the module is valid, the green LED on the TS-4100 will flash once.
When the TS-SILO supercapacitors are charging, the green LED on the TS-4100 will be solidly lit. As the capacitors near their full charge value then LED will turn off. As the microcontroller tops up the charge to keep them at or as close to 100% as possible, this LED will turn on and off while charging is enabled and input power remains valid.
MicroSD Card Interface
The i.MX6UL SDHCI driver supports microSD (0-2 GB), microSDHC (2-32 GB), and microSDXC(32-2048 GB). 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.
See the i.MX6UL 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 performing 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-12 TB 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 100 TB of writes. Higher end SD cards can also extend this, but industrial grade SD cards typically carry a cost much higher than the eMMC.
SD cards in general should not be powered down during a write/erase cycle, doing so will eventually lead to 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
RTC
USB
USB OTG
USB Host
The TS-4100 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.
SPI
The default kernel sets up two SPI controllers. One to the Onboard WIFI, and the other to the FPGA and offboard chip selects. SPI is accessible through either specific kernel drivers, or userspace using the /dev/spi interface. See the kernel compile guide here for more details.
Open the baseboard dts from arch/arm/boot/dts/imx6ul-ts4100-<baseboardid>.dtsi, or the generic imx6ul-ts4100.dtsi. The kernel requires a spidev device be added to the relevant ECSPI controller. For example:
&ecspi3 {
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio4 12 0>, <&gpio4 10 0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";
spidevfpga: spi@0 {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <1000000>;
};
spioffbd: spi@1 {
compatible = "spidev";
reg = <1>;
spi-max-frequency = <1000000>;
};
};
In this case the two spidev devices are set to 1MHz. To adjust this further you will need to modify the kernel for your device. Linux will create two devices for the above spidev nodes:
- /dev/spidev2.0 #FPGA
- /dev/spidev2.1 #offboard
The FPGA SPI is left to custom ZPU code. You can also add additional CPU GPIO to the cs-gpios section to create more chip selects. For further information on the SPI programming see the kernel example code and documentation:
TWI
Watchdog
The kernel provides an interface to the watchdog driver at /dev/watchdog. Refer to the kernel documentation for more information:
WIFI
This board uses an 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
TS-Socket
The TS-SOCKET macrocontrollers all use two high density 100 pin connectors for power and all I/O. These follow a common pinout for various external interfaces so new modules can be dropped in to lower power consumption or use a more powerful processor. The male connector is on the baseboard, and the female connector is on the macrocontroller. You can find the datasheet for the baseboard's male connector here. This can be ordered from the TS-Socket macrocontroller product page as CN-TSSOCKET-M-10 for a 10 pack, or CN-TSSOCKET-M-100 for 100 pieces.
In our schematics and our table layout below, we refer to pin 1 from the male connector on the baseboard. For designing a custom carrier board for the TS-4100 we recommend using the TS-8550 as a base: https://www.embeddedarm.com/documentation/ts-8550-schematic.pdf
- ↑ 1.0 1.1 1.2 1.3 The FPGA JTAG pins are not recommended for use and are not supported.
- ↑ EXT_RESET# is an input used to reboot the CPU. Do not drive active high, use open drain.
- ↑ This is an output which can be manipulated as a GPIO. This pin can optionally be connected to control a FET to a separate 5 V rail for USB to allow software to reset USB devices. Many of our baseboards implement this.
- ↑ OFF_BD_RESET# is an output from the SoM that automatically sends a reset signal when the unit powers up or reboots. It can be connected to any IC on the base board that requires a reset.
- ↑ 5.0 5.1 This interface is for programming the on-board microcontroller, this should be left unconnected on a baseboard.
- ↑ 6.0 6.1 6.2 6.3 The power pins should each be provided with a 5 V source.
- ↑ This is a multi-purpose pin, part of the FPGA Crossbar MUX. The CPU and FPGA pins are connected in parallel.
- ↑ When low, overrides the microcontroller power control and enables 5 V rail on the TS-4100. Leave unconnected for normal use.
- ↑ This is an output that can be manipulated as a GPIO.
- ↑ 10.0 10.1 Allows the supervisory microcontroller to measure USB VBUS for the OTG port.
- ↑ When held high during CPU startup, enables i.MX6UL USB Boot bootloader.
- ↑ 12.0 12.1 12.2 12.3 This pin is part of the FPGA Crossbar MUX. Its default Crossbar assignment is listed first, with the Crossbar name in parenthesis.
Revisions and Changes
TS-4100 PCB Revisions
Revision | Changes |
---|---|
A |
|
B |
|
C |
|
U-Boot Changelog
Revision | Changes |
---|---|
July 2, 2019 | Initial pre-production release |
December 18, 2020 |
|
September 8th, 2021 |
|
November 5th, 2021 |
|
FPGA Changelog
Revision | Changes |
---|---|
0x0A | Initial pre-production release |
0x0B |
|
Software Images
Debian Changelog
Revision | Changes |
---|---|
ts4100-armhf-stretch-20190702.tar.xz | Initial pre-production release. |
ts4100-armhf-stretch-20191122.tar.xz |
|
ts4100-armhf-stretch-20210111.tar.xz |
|
ts4100-armhf-stretch-20210817.tar.xz |
|
ts4100-armhf-stretch-20211013.tar.xz |
|
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.