TS-7970

From embeddedTS Manuals
TS-7970
ts-7970.gif
Product Page
Product Images
Specifications
Documentation
Schematic
Mechanical Drawing
FTP Path
Processor
NXP i.MX6ul Arm® Cortex®-A9 Quad core or Solo processor
i.MX6 Quad Product Page
i.MX6 Solo Product Page
IMX6Q Reference Manual
IMX6S Reference Manual

Getting Started

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

Virtualization

Suggested Linux Distributions

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

Getting Console and Powering up

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

A USB serial console is provided via the supervisory microcontroller to allow capture of all startup messages. Console is redirected to the USB device port when the "CON EN" jumper is set. Connect the USB device port, P2, to a host computer via a USB cable. This console can be opened and viewed before or after power is applied. Boot messages will only be printed once the device is powered on.

The USB Serial port can show up in a number of different ways. On Windows it will show up as an additional COM port, assigned an incremental COM number. In Linux, both the Silabs and Renesas drivers are included in most popular distributions. If you have the SiLabs microntroller, this will show up as /dev/ttyUSB0. If you have the Renesas microcontroller, this will show up as /dev/ttyACM0.

Note: Under Linux it is recommended to run this command once:
echo "ATTR{idVendor}==\"35b0\",  ENV{ID_MM_DEVICE_IGNORE}=\"1\"" > /etc/udev/rules.d/75-embeddedts-mm.rules
This prevents modemmanager from probing the ACM device as a cellular modem.

Windows 8.1, 10, and 11 use their own built-in driver, it is not necessary to install a new USB-Serial driver on these platforms for either Silabs- or Renesas-based console interfaces.

For other operating systems device drivers are available from Silicon Labs (eg. Windows):

For Windows 7, when using the Renesas-equipped TS-7970, the driver download process starts from here:

Most newer versions of the Microsoft Windows operating system have an appropriate driver already built-in, however note that for Windows 7 the Synergy driver must be installed manually. Use the Device Manager control panel and find the TS-7970 Console device, right click and select properties -> driver updates -> browse my computer -> let me pick -> "have disk" -- then locate the location where the Synergy driver was extracted to.

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

# REV H and newer PCBs:
sudo picocom -b 115200 /dev/ttyACM0

# Older Silabs based boards (Before REV H)
sudo picocom -b 115200 /dev/ttyUSB0

The picocom tool will output some serial setting information and then "Terminal ready". Any messages after this point will be from the device via the serial output. The terminal is now ready and power can be applied in order to boot up the device. Power is applied through the removable terminal block. The TS-7970 can be powered with 5 VDC or 8-28 VDC input. Only a single power input may be connected at any time.

A power supply should be prepared to provide 15 W for most uses. The devices's power consumption will average around 3 W on an idle quad core. See the specifications for further details on power requirements.

P1-A, the top row of headers, are used in the following pin designations. For 5 VDC input, connect pin 7 to a 5 VDC source and pin 8 to ground. For 8-28 VDC in, connect pin 6 to the voltage source and pin 8 to ground. See the terminal blocks section for more information on this header.

Once power is applied to either the 5 VDC or 8-28 VDC input, the device will begin printing messages to the console. The first output is from U-Boot:

U-Boot 2015.04-07892-g9a2f707 (Jan 11 2017 - 16:14:53)

CPU:   Freescale i.MX6Q rev1.2 at 792 MHz
CPU:   Temperature 52 C
Reset cause: WDOG
Board: TS-7970 REV D
I2C:   ready
DRAM:  2 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
SF: Detected N25Q64 with page size 256 Bytes, erase size 4 KiB, total 8 MiB
In:    serial
Out:   serial
Err:   serial
FPGA Rev: 7
SilabRev: 2
Net:   using phy at 1
FEC [PRIME]

Boot will continue immediately unless SW1 is pressed before power is applied and held for a few seconds after. When SW1 is depressed at power on, U-Boot to drop to its internal shell. This will also cause U-Boot to check for a USB production script.

The "SD Boot" jumper will cause U-Boot to boot to the microSD card when set, otherwise U-Boot will boot to the eMMC flash. If SW1 is not depressed, then U-Boot will boot to the selected media immediately.


Note: The "*** Warning - bad CRC, using default environment" message in U-Boot can be safely ignored. This indicates that U-Boot environment has never been previously saved to disk. Typing "env save" will hide these messages, but this is not needed.

First Linux Boot

U-Boot is always loaded from the onboard SPI flash. U-Boot has the ability to boot Linux, Android, QNX, or other operating systems on the SD or eMMC. The eMMC and SD cards shipped with the unit are pre-programmed with our Debian Jessie image. See other OS sections for information on the various OS options that we provide: Yocto, Ubuntu, Android, QNX.

 [  OK  ] Started Serial Getty on ttymxc0.
 [  OK  ] Reached target Login Prompts.
 [  OK  ] Started SLiM Simple Login Manager.
 [  OK  ] Created slice user-0.slice.
          Starting LSB: RPC portmapper replacement...
          Starting User Manager for UID 0...
 [  OK  ] Started User Manager for UID 0.
 [  OK  ] Started LSB: RPC portmapper replacement.
 [  OK  ] Reached target RPC Port Mapper.
          Starting Authenticate and Authorize Users to Run Privileged Tasks...
 
 Debian GNU/Linux 8 ts-imx6 ttymxc0
 
 ts-imx6 login: 

By default, the startup output is verbose and includes kernel messages and systemd output. The display, if connected, will boot to a minimalistic XFCE desktop. This is provided as a demo and is not intended for use in development or a shipping application. See the Debian automatic startup section for information on booting to a single application.

Note: During development it is recommended to leave on verbose messages for debugging. The non-error output can be disabled by modifying the kernel cmdline.

Once booted up, the serial port will display a login prompt which asks for a username/password. Under Debian this is "root" with no password which will allow the initial login. See the Debian section to continue on with Debian application development.

Comparison of Distributions

We currently offer Debian, Ubuntu, Yocto, QNX, and Android OSs for the TS-7970. Each of these have advantages and disadvantages, the major points are outlined below. We recommend Debian if the user does not need GPU support. Yocto is recommended for QT Creator, Eclipse support, or significant distribution customization.

Distribution Advantages Disadvantages
Debian
  • Cross compilation requires running the same Debian release on a host
  • Not patched for hardware support
    • No OpenGL or 2D acceleration from GPU. 2D applications through the framebuffer are still supported.
Ubuntu
  • Cross compilation requires running the same Ubuntu release on a host
  • Not patched for hardware support
    • No OpenGL or 2D acceleration from GPU. 2D applications through the framebuffer are still supported.
Yocto
  • Large focus on up to date packages
  • Allows rebuilding all packages with changes
  • Supports portable toolchain packages that integrate with QT Creator and Eclipse
  • Includes all patches needed for graphics support.
  • Distribution can be rebuilt to include specific needs.
  • Short life cycles
  • Does not support any online repository of prebuilt applications. Adding packages requires rebuilding Yocto or building the required package.
  • Less examples and documentation available online
Android
  • Simple well defined API using well documented tools
  • Allows existing apps to be run without huge customization
  • Under Android it is difficult to access hardware that is not found on an Android tablet/phone. This includes interfaces such as UARTs, GPIO, or ADC
    • A common method is to write a C application which communicates over a localhost socket to an Andoird application in order to interface with hardware
  • Slow boot time
  • Poor documentation for OS customization
QNX Neutrino RTOS
  • Real time OS allowing determinitic response times in an application
  • Commercial application support available through QNX
  • Eclipse support
  • License fee required through QNX
  • Not as much driver support as Linux

U-Boot

This platform uses U-Boot as the bootloader to launch the full operating system. The i.MX6 processor loads U-Boot from the on-board 8 MiB SPI flash. U-Boot provides support for loading data from various mediums; this allows booting a kernel from SD, eMMC, SATA, NFS, or USB. U-Boot is a general purpose bootloader that is capable of booting into common Linux distributions, Android, Windows, or custom software OSes.

On a normal boot the output should be similar to the output below:

U-Boot 2014.10-gee73348 (Oct 07 2015 - 11:12:20)

I2C:   ready
DRAM:  1 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
SF: Detected N25Q64 with page size 256 Bytes, erase size 4 KiB, total 8 MiB
In:    serial
Out:   serial
Err:   serial
Net:   using phy at 7
FEC [PRIME]

By default the device will boot to SD or eMMC depending on the status of the "SD Boot" jumper on startup.

To break into the U-Boot console, press and hold the SW1 button while the unit is being powered up. This mode will also check for a USB mass storage device to use for production purposes.

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. The variable contents are clobbered when set, so be sure to specify the full desired cmdline string.

env set cmdline_append console=ttymxc0,115200 init=/sbin/init quiet
env save

The kernel command line can also be modified from from the on-board Linux. Debian (and other distributions) provide a U-Boot utilities package that contains the tools necessary to create a U-Boot script:

apt-get update && apt-get install u-boot-tools -y
echo "env set cmdline_append console=ttymxc0,115200 init=/sbin/init quiet" > /boot/boot.scr
mkimage -A arm -T script -C none -n 'tsimx6 boot script' -d /boot/boot.scr /boot/boot.ub

The boot.scr includes the plain text commands to be run in U-Boot on startup. The mkimage tool adds a checksum and header to this file which can be loaded by U-Boot. The .ub file should not be edited directly.

U-Boot Recovery

U-Boot handles CPU and RAM setup/configuration that needs to be run every boot. Due to these configurations separate binaries are maintained for each CPU grade, RAM part, and RAM size; the correct binary must be used for any given device configuration. The specific device variant can be obtained in U-Boot via the command 'env print imx_type'.

On startup, the TS-7970 checks the SPI flash for a valid boot header in SPI flash. If it is unable to locate a valid boot header, the CPU falls back to the "serial downloader" which allows the CPU to execute code sent via USB. If the unit has a valid but damaged or incorrect U-Boot binary programmed in to SPI flash, an RMA return will be required in order to properly recover it. Please contact us for assistance with this.

1) Download the U-Boot binary for the correct imx_type variant from the list here: https://files.embeddedTS.com/ts-arm-sbc/ts-7970-linux/u-boot/. See the U-Boot Changelog for information on the changes between released versions.

2) Download and build/install the "imx_usb" loader

3) Disconnect power from the device.

4) Remove the "CON EN" jumper.

5) Apply power to the device.

6) Plug a USB type B cable into the P2 connector on the device and connect it to a host PC.

7) Check 'dmesg' or 'lsusb' on the host PC for a new USB connection. This should show a HID device listing NXP or Freescale as the manufacturer. For example:

hid-generic 0003:15A2:0054.0006: hiddev0,hidraw3: USB HID v1.10 Device [Freescale SemiConductor Inc  SE Blank ARIK] on usb-0000:00:14.0-6.4.2/input0

If it does not show the above output, an RMA return will be required in order to properly recover the unit. Please contact us for assistance with this.

8) Hold down SW1.

9) Run 'imx_usb path/to/u-boot.imx' on the host PC while holding down SW1. Continue holding SW1 for a few seconds after the command is run. This is to force the unit to stop in U-Boot after 'imx_usb' has uploaded the U-Boot binary and the unit has begun booting.

10) Disconnect the USB cable on P2.

11) Set the "CON EN" jumper.

12) Re-insert the USB cable into P2.

At this point, the USB serial device should show up on the host, opening it will reveal that the unit is stopped at the U-Boot prompt. Follow the steps in Update U-Boot to reinstall U-Boot on the SPI flash.

Booting From NFS

U-Boot's NFS support can be used to load a kernel, device tree binary, and root filesystem over the network. The default scripts include an example NFS boot script.

# Set this to your NFS root path.  The server root should be accessible at this path.
env set nfsroot 192.168.0.36:/mnt/storage/imx6/
env save

To boot to an NFS root:

# Boot to NFS once
run nfsboot;

# To make the NFS boot the persistent default
env set bootcmd run nfsboot;
env save

Booting From USB

With the push button held down before power on and a few seconds after, U-Boot will attempt to read a U-Boot script named /tsinit.ub from a USB drive. If present on the USB drive, U-Boot will automatically load this script in to memory and execute it. For our bootable USB disk images, no further action is needed.

To make a bootable drive from scratch, create a single ext3 partition on a USB drive and copy over your preferred rootfs just like you would with an SD card. This is described in the Debian and Yocto sections.

The one addition is to create the /tsinit.ub file in the root of the USB drive in order to allow U-Boot to boot from the drive's contents.

Create the file /tsinit.scr in the root of the USB drive with the Linux filesystem:

# Prepare with:
# mkimage -A arm -T script -C none -n 'mx6 usb' -d tsinit.scr tsinit.ub

# DO NOT MANUALLY EDIT THE .UB FILE

# If loading files from a partition other than the first partition on disk, change
# the second number to the partition number
env set bootpart 0:1

if test ${model} = '4900';
	then load usb 0:1 ${loadaddr} /boot/ts4900-fpga.bin;
	ice40 ${loadaddr} ${filesize};

	bbdetect;

	# Check rev, attempt to load the best dtb file for compatibility. If Rev E files
	# are not found, attempt to boot prior dtb. If not Rev E, just boot prior dtb.
	if test ${rev} > 'D'; then
		if load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900-reve-${baseboardid}.dtb
			then echo Baseboard $baseboardid detected;
		elif load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900-reve.dtb
			then echo Booting default Rev E device tree;
		elif load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900-${baseboardid}.dtb
			then echo Baseboard $baseboardid detected;
		elif load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900.dtb
			then echo Booting default device tree;
		fi
	else
		if load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900-${baseboardid}.dtb
			then echo Baseboard $baseboardid detected;
		elif load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts4900.dtb
			then echo Booting default device tree;
		fi
	fi

	load usb ${bootpart} ${loadaddr} ${uimage};
	setenv bootargs root=/dev/sda1 rootwait rw ${cmdline_append};
	bootm ${loadaddr} - ${fdtaddr};

elif test ${model} = '7970'; then
	# Check for Rev F or newer. If so, load that dtb. If Rev F dtb does not exist
	# fall back to a prior dtb. If earlier Rev PCB, use prior dtb.
	if test ${rev} > 'E'; then
		if load usb ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts7970-revf.dtb; then
			echo Loaded TS-7970 Rev F device tree;
		elif load usb ${bootdev} ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts7970.dtb; then
			echo Loaded TS-7970 device tree;
		fi
	else
		if load usb ${bootdev} ${bootpart} ${fdtaddr} /boot/imx6${cpu}-ts7970.dtb; then
			echo Loaded TS-7970 device tree;
		fi
	fi

	load usb 0:1 ${loadaddr} ${uimage};
	setenv bootargs root=/dev/sda1 rootwait rw ${cmdline_append};
	bootm ${loadaddr} - ${fdtaddr};
fi

Then in the same directory generate the tsinit.ub file:

mkimage -A arm -T script -C none -n 'mx6 usb' -d tsinit.scr tsinit.ub

You may need to install u-boot-tools or the equivalent package for your distribution.

Update U-Boot

WARNING: Installing a custom U-Boot is not recommended and may cause the device to fail to boot.

U-Boot requires a different build for Quad/Dual and Solo/Duallite. When booted to the U-Boot shell, run 'env print imx_type' and it will return the correct U-Boot build that should be used. Copy the built u-boot.imx file or the pre-built binary from our FTP site to the SD card as "/u-boot.imx", and run the following U-Boot commands:

mmc dev 0
load mmc 0:1 ${loadaddr} /u-boot.imx
sf probe
sf erase 0 0x80000
sf write ${loadaddr} 0x400 $filesize

U-Boot Development

We do provide our U-Boot sources but we do not recommend rebuilding a custom U-Boot if it can be avoided. Custom built U-Boot binaries will not have the latest up to date settings. Specifically, the largest concern is with RAM timing settings. Memory technology is expanding rapidly and we may need to use different parts through the shipping lifetime of the device itself. If RAM timings change, then we update our factory shipped U-Boot to have the proper settings. A custom U-Boot would need to be re-built if any of these settings change.

Our U-Boot includes a variable "imx_type". If loading a custom U-Boot binary, make sure to check the value of this before writing. If we are forced to update the RAM configuration we will change this variable. We will also send out a product change to anyone who is subscribed to our PCS system.

If you still need to proceed with building a custom U-Boot, use the imx_v2015.04_3.14.52_1.1.0_ga branch from the github here: https://github.com/embeddedTS/u-boot-imx

Boot up a TS-7970 into u-boot and run "echo ${imx_type}". This will show you the u-boot config to use for the correct RAM timing. We use the same GCC 6.2 used from Yocto Morty to compile the u-boot binary. This toolchain can be found here.

export ARCH=arm
export CROSS_COMPILE=/opt/poky/2.2.1/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-

git clone https://github.com/embeddedTS/u-boot-imx.git -b imx_v2015.04_3.14.52_1.1.0_ga
cd u-boot-imx

# For example, one of the quad core variants.  Replace this with your imx_type
make ts7970-s-1g-800mhz-i_defconfig
make -j4

This will output a u-boot.imx file that can be written to the SPI flash following the instructions in the update U-Boot section.

Access U-Boot Environment from Linux

A utility called 'fw_printenv' is available which can set/read environment variables from Linux. This must be built and provided with a config file before it will work.

On the board first boot to U-Boot by holding SW1 during power on and startup. At the prompt run:

U-Boot > env print imx_type
imx_type=<Output is dependent on specific configuration>

Save the output of the command then boot to Linux to build the 'fw_printenv' tool.

cd /usr/src/
git clone --depth 1 https://github.com/embeddedTS/u-boot-imx.git -b imx_v2015.04_3.14.52_1.1.0_ga
cd u-boot-imx


For example, if U-Boot returned "imx_type=ts7970-s-1g-800mhz-i", then the example defconfig is ts7970-s-1g-800mhz-i_defconfig. Be sure to use the correct imx_type defconfig!

# These next 2 commands should only be used if gcc --version is greater than 9
cp include/linux/compiler-gcc6.h include/linux/compiler-gcc9.h
sed --in-place 's/march=armv5)/march=armv5te)/g' arch/arm/Makefile

make ts7970-s-1g-800mhz-i_defconfig
make -j4 env
cp tools/env/fw_printenv /usr/bin/
# The same utility sets environment variables when
# called as fw_setenv
ln -s /usr/bin/fw_printenv /usr/bin/fw_setenv

The utility will also need a config file to know where to load the environment. Create the file, "/etc/fw_env.config", with the following contents:

# SPI flash on the TS-7970/TS-7990
# MTD device name	Device offset	Env. size	Flash sector size	Number of sectors
/dev/mtdblock0		0x100000	0x2000		0x1000			2
/dev/mtdblock0		0x180000	0x2000		0x1000			2

From here, "fw_printenv" can be run to read the environment variables. If first line of output is:

Warning: Bad CRC, using default environment

Then the environment saved is blank, and the utility output is loading the environment compiled into the U-Boot binary. This is normal and how units are shipped from the factory.

You can modify variables with this command as well:

# Set cmdline_append to include "quiet"
fw_setenv cmdline_append console=ttymxc0,115200 ro init=/sbin/init quiet


Buildroot

The full-featured Debian image may be too cumbersome for some applications. Applications that require faster bootup time or a smaller root filesystem will benefit greatly from using a lighter distribution like Buildroot. Using Buildroot for generating images makes it easy to keep software up to date, both userspace and kernel. Additionally, the use of Buildroot allows for building full images completely from source, with semi-reproducable builds, and full software license reports.

To assist customers heading down this path, we maintain our own Buildroot br2-external tree. This tree includes upstream Buildroot as a submodule, which eases updating between Buildroot releases. See the Buildroot manual for more information on Buildroot and br2-external trees.

In order to provide an easy transition from a larger Linux distribution to Buildroot, we provide and maintain two levels of configurations:

  • The base configuration for each device brings in hardware support to get the unit booted, but offers minimal software support and relies mostly on tools provided by BusyBox.
  • An "extra packages" defconfig that can be merged in with any of the base configurations in order to provide many additional packages to create an environment that is more consistent with larger Linux distributions.

The larger Buildroot configuration averages about 10 seconds of boot time, much of which is spent on networking. The base configurations can reduce this time significantly.

Our Buildroot br2-external currently uses the linux-5.10.y branch of our Linux LTS kernel repository for the majority of its supported platforms.


Note: Note that our base configurations include that device's utilities package where possible. Normally, these utilities (e.g. tshwctl, tsmicroctl, etc.) list the git hash of the build source in the help output. However, due to the Buildroot process, the git hash in these utilities reflects the git hash of Buildroot-ts, NOT of the utilities repository. There is no way to work around this without building the utilities outside of Buildroot.


Buildroot - Installing

When building Buildroot from source, the output files can be used to create a bootable microSD card and a bootable eMMC for the TS-4900. The output files are also compatible with our USB Image Replicator.

The default configuration was designed to be as close to our stock Debian distribution. This includes our ts4900-utils like tsmicroctl, drivers, firmware, and software for the Wi-Fi and Bluetooth module, etc.


Buildroot - Building

Buildroot is intended to be completely cross-compiled from a host Linux workstation. This process creates a cross-compiler which is then used to build all target applications, kernel, etc., and then output a bootable image / tarball. The following instructions will create a bootable image / tarball for the target system:

Clone the repository:

git clone --recurse-submodules https://github.com/embeddedTS/buildroot-ts.git
cd buildroot-ts/

Configure the build:

# The following command uses a Buildroot script to merge two config files.
# The extra_packages_defconfig includes more usual packages to match our stock images
./buildroot/support/kconfig/merge_config.sh technologic/configs/extra_packages_defconfig technologic/configs/tsimx6_defconfig 

# A smaller base image can be made with bare hardware support using:
# make tsimx6_defconfig

At this point, the default configuration can be modified if desired:

make menuconfig

And finally, start the build process:

make


The Buildroot process can take a large amount of time to build depending on available system resources. Note that if any changes occur in the config file, it is recommended to clean the build tree and start the process over. Buildroot ccache is not enabled by default, but can be to help speed up repeated builds. See the Buildroot manual for more information about ccache and Buildroot.

Once it is finished building, Buildroot will output a filesystem tarball to buildroot/output/images/rootfs.tar.xz. This file can be used with the Installing Buildroot instructions to get this tarball booted on the target device.


Buildroot - Cross Compiling

In order to generate a cross-compiler from Buildroot, first configure the target build as outlined in the first steps of the build instructions. Once configured, a separate make command can be issued to generate a tarball package of the cross-compiler. This can be unpacked to any location on the host Linux workstation's filesystem and then used to cross-compile additional applications for the target. The build, setup, and use of the cross-compiler can be done with the following steps:

# Be sure the target is configured first!
# The following command will output the cross-compiler package as well as build the target image completely if not built already
make sdk

# Unpack the tarball to new directory in the users home directory
# Note that the tarball name may be slightly different depending on how the toolchain is configured in Buildroot
mkdir ~/buildroot-toolchain
tar xf buildroot/output/images/arm-buildroot-linux-gnueabihf_sdk-buildroot.tar.gz -C ~/buildroot-toolchain/

# Update the path information for the toolchain (must be done when the tarball is unpacked, or if the root folder of the toolchain is moved!)
# Note that, as above, the path for the compiler may be slightly different depending on how the toolchain is configured in Buildroot
~/buildroot-toolchain/arm-buildroot-linux-gnueabihf_sdk-buildroot/relocate-sdk.sh

# Create a simple Hello World application source
cat << EOF > hello.c
#include <stdio.h>
void main(void) { printf("Hello!\n"); }
EOF

# Build a binary from the Hello World source that can be run on the target device
~/buildroot-toolchain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/arm-linux-gcc hello.c -o hello

# This cross compiler can be added to the user's PATH variable for easy access
export PATH=$PATH:~/buildroot-toolchain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
arm-linux-gcc hello.c -o hello

The hello binary can then be copied to the target device and executed on it.

Note that the make sdk command can be run at any time to generate the toolchain tarball. Even after Buildroot has generated the output image.


Buildroot is extremely flexible in its generation and use of a cross-compiler. See the Buildroot manual for more information on advanced use of the Buildroot generated toolchain as well as using Buildroot's generated cross-compiler as an external compiler for Buildroot.


Buildroot - Configuring Network

Buildroot implements the ip, ifconfig, route, etc., commands to manipulate the settings of interfaces. The first Ethernet interface is set up to come up automatically with our default configuration. The interfaces can also be manually set up:

# Bring up the CPU network interface
ifconfig eth0 up

# Set an IP address (assumes 255.255.255.0 subnet mask)
ifconfig eth0 192.168.0.50

# Set a specific subnet
ifconfig eth0 192.168.0.50 netmask 255.255.0.0

# Configure a default route. This is the server that provides an internet connection.
route add default gw 192.168.0.1

# Edit /etc/resolv.conf for the local DNS server
echo "nameserver 192.168.0.1" > /etc/resolv.conf

Most commonly, networks will offer DHCP which can be set up with one command:

# To setup the default CPU Ethernet port
udhcpc -i eth0
# All Ethernet ports can be made active and request DHCP addresses with:
udhcpc


To have network settings take effect on startup in Buildroot, edit /etc/network/interfaces:

# interface file auto-generated by Buildroot

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
  pre-up /etc/network/nfs_check
  wait-delay 15

Note that the default network startup may timeout on some networks, e.g. network protocols such as STP can delay packet movement. This can be resolved in Buildroot by adding network configuration options to fail after a number of attempts (rather than a timeout) or retry for a DHCP lease indefinitely. For example, adding one of the following lines under the iface eth0 inet dhcp section:

  • udhcpc_opts -t 0 to infinitely retry
  • udhcpc_opts -t 5 to fail after five attempts.

See the man page for interfaces(5) for further information on the syntax of the interfaces file and all of the options that can be passed.

For more information on network configuration in general, Debian provides a great resource here that can be readily applied to Buildroot in most cases.


Buildroot - Installing New Software

Buildroot does not include a package manager by default (though it is possible to enable one). This means installing software directly on the platform can be cumbersome and is not the intended path when using Buildroot. It is recommended to modify the Buildroot configuration to include additional packages. See the Building Buildroot section for information on modifying the configuration to build additional packages.

If a desired package is not available in Buildroot, there are a number of options available moving forward. It is possible to add packages to the build process, though this does require some knowledge of Buildroot internals. Another option is to use the cross compiler that is output by Buildroot in order to compile packages on a host system and then copy them over to the target. It is also possible to install a toolchain directly on the device, and compile applications natively. The last option is the least recommended as it greatly increases the final image size and adds unnecessary complexity.


Buildroot - Setting Up SSH

The default configuration has Dropbear set up. Dropbear is a lightweight SSH server.

Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password set. The default configuration does not set a password for the root user, nor are any other users configured.

passwd root

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


Buildroot - Starting Automatically

Buildroot defaults to using the BusyBox init system, and all of our provided configurations use this as well. The following custom startup script uses this format. For information on other init systems that Buildroot can use, as well as creating startup scripts for these, see the Buildroot manual.

The most straightforward way to add an application to startup is to create a startup script. This example startup script that will toggle the red LED on during startup, and off during shutdown. In this case the script is named customstartup which can be changed as needed.

Create the file /etc/init.d/S99customstartup with the following contents. Be sure to set the script as executable!

#! /bin/sh
# /etc/init.d/customstartup

case "$1" in
  start)
    echo 1 > /sys/class/leds/red-led/brightness
    ## If you are launching a daemon or other long running processes
    ## this should be started with
    # nohup /usr/local/bin/yourdaemon &
    ;;
  stop)
    # if you have anything that needs to run on shutdown
    echo 0 > /sys/class/leds/red-led/brightness
    ;;
  *)
    echo "Usage: customstartup start|stop" >&2
    exit 3
    ;;
esac
  
exit 0
Note: The $PATH variable is not set up by default in init scripts so this will either need to be done manually or the full path to your application must be included.

Buildroot provides numerous mechanisms to create this file in the target filesystem at build time. See the Buildroot manual for more information on this.

This script will be automatically called at startup and shutdown thanks to the file location and naming. However, it can also be manually started or stopped:

/etc/init.d/S99customstartup start
/etc/init.d/S99customstartup stop


Debian

Debian is a community run Linux distribution. Debian provides tens of thousands of precompiled applications and services. This distribution is known for stability and large community providing support and documentation.

Debian 12 - Bookworm

Debian 12 - Getting Started

This Debian release is available in 3 flavors with various packages.

Image Estimated Size Description
debian-armhf-bookworm-x11-latest.tar.bz2 925 MiB
  • Includes 6.6 kernel with tsimx6_defconfig that includes broad driver support
  • Base Debian with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
  • Includes X11 that launches matchbox and xterm on startup
  • Includes touchscreen support
debian-armhf-bookworm-headless-latest.tar.bz2 681 MiB
  • Includes 6.6 kernel with tsimx6_defconfig that includes broad driver support
  • Base Debian with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
debian-armhf-bookworm-minimal-latest.tar.bz2 223 MiB
  • Includes 6.6 kernel with tsimx6_minimal_defconfig that includes bare minimum driver support and kernel options required by Debian.
  • Includes base Debian rootfs adding only what is required for Ethernet support.

The default login is root with no password.

To write this to an SD card, first partition the SD card to have one large ext3, or ext4 partition. See the guide here for more information. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf debian-armhf-bookworm-x11-latest.tar.bz2 -C /mnt/sd
sudo umount /mnt/sd
sync

To rewrite the eMMC, boot to the SD card. You cannot rewrite the emmc while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedts.com/ts-arm-sbc/ts-7970-linux/distributions/debian/debian-armhf-bookworm-x11-latest.tar.bz2 | tar --numeric-owner -xj -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.

Debian 12 - Networking

The network in Debian is configured with /etc/network/interfaces. For complete documentation, see Debian's documentation here

Some common examples are shown below. On this release network interfaces follow the predictible network interface names. Run ip addr show to get a list of the network interfaces.

Most commonly:

  • end0 - Ethernet device 0 (CPU Ethernet)
  • enp1s0 - Ethernet PCIe port 1 slot 0 ethernet
  • usb<mac> - USB ethernet
  • wlan0 - WIFI

DHCP on end0. Edit the file /etc/network/interfaces and add:

auto end0
allow-hotplug end0
iface end0 inet dhcp

Static IP on end0. Edit the file /etc/network/interfaces and add:

auto end0
iface end0 inet static
    address 192.0.2.7/24
    gateway 192.0.2.254

These will take effect on the next boot, or by restarting the networking service:

service networking restart

Debian 12 - WIFI Client

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 12 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Debian 12 - 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@tsa38x:~# 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-11-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-11-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-11-doc - OpenJDK Development Kit (JDK) documentation
openjdk-11-jdk - OpenJDK Development Kit (JDK)
openjdk-11-jdk-headless - OpenJDK Development Kit (JDK) (headless)
openjdk-11-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-11-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
openjdk-11-jre-zero - Alternative JVM for OpenJDK, using Zero
openjdk-11-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-11 - Java plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-jwsgi-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-ring-openjdk-11 - Closure/Ring plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-servlet-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
java-package - Utility for creating Java Debian packages

In this case, the wanted package will likely be the "openjdk-11-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-11-jre
# More than one package can be installed at a time.
apt-get install openjdk-11-jre nano vim mplayer

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

Debian 12 - Setting up SSH

Openssh is installed in our default Debian image, but by default openssh does not permit root logins, and requires a password to be set. Additionally, a host key is required if one hasn't already been created on the target board. To allow remote root login:

sed --in-place 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart ssh.service
passwd root # Set any password

If you ssh to this system it will now support ssh as root.

Debian 12 - Starting Automatically

Bookwoorm Startup Scripts

Debian 12 - Cross Compiling

Debian provides cross toolchains within their distribution for different architectures.

For best portability we recommend using a container like docker to run a Debian 12 rootfs for the toolchain. This will allow a consistent toolchain to run from almost any Linux system that can run Docker. Keep in mind that while docker does run under OSX and Windows, these are run under a case insensitive filesystem which will cause problems with complex builds like the Linux kernel so a Linux host is still recommended.

  • Ubuntu/Debian:
sudo apt-get install docker.io -y
  • Fedora
sudo dnf install docker -y

After installing docker on any distribution make sure your user is in the docker group:

# Add your user to the docker group.  You may need to logout/log back in.
sudo usermod -aG docker $USER

Make sure you can run docker's hello world image as your user to verify it is working:

docker run hello-world

Now create a file Dockerfile:

sudo mkdir -p /opt/docker-toolchain/docker-debian-bookworm-armhf
# Use any preferred editor, vim/emacs/nano/etc
sudo nano /opt/docker-toolchain/docker-debian-bookworm-armhf/Dockerfile
# syntax = docker/dockerfile:1.2

FROM debian:bookworm

RUN dpkg --add-architecture armhf

RUN apt-get update && apt-get install -y \
    autogen \
    automake \
    bash \
    bc \
    bison \
    build-essential \
    bzip2 \
    ca-certificates \
    ccache \
    chrpath \
    cpio \
    curl \
    diffstat \
    fakeroot \
    file \
    flex \
    gawk \
    gcc-arm-linux-gnueabihf \
    git \
    gzip \
    kmod \
    libgpiod-dev:armhf \
    libncursesw5-dev \
    libssl-dev \
    libtool \
    libyaml-dev \
    locales \
    lz4 \
    lzop \
    make \
    multistrap \
    ncurses-dev \
    pkg-config \
    python3 \
    python3-cbor \
    python3-pexpect \
    python3-pip \
    qemu-user-static \
    rsync \
    runit \
    socat \
    srecord \
    swig \ 
    texinfo \
    u-boot-tools \
    zstd \
    unzip \
    vim \
    wget \
    xz-utils

# Provide a more friendly name
ENV debian_chroot debian_bookworm
RUN echo "PS1='\${debian_chroot}\\[\033[01;32m\\]@\\H\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ '" >> /etc/bash.bashrc

# Set up locales
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
        echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
        dpkg-reconfigure --frontend=noninteractive locales && \
        update-locale LANG=en_US.UTF-8
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

Next make a shell script to enter into this docker container. Create /usr/local/bin/docker-debian-bookworm:

# Use any preferred editor, vim/emacs/nano/etc
sudo nano /usr/local/bin/docker-debian-bookworm
#!/bin/bash -e

# Enters a docker running Debian 12 Bookworm
# Any arguments are run in the docker, or if no arguments it runs a shell

export TAG=debian-bookworm-armdev
SCRIPTPATH=$(readlink -f "$0")
DOCKERPATH=/opt/docker-toolchain/docker-debian-bookworm-armhf/

DOCKER_BUILDKIT=1 docker build --tag "$TAG" "$DOCKERPATH" --quiet

exec docker run --rm \
	-it \
	--volume "$(pwd)":/work \
	--user $(id -g):$(id -u) \
	-w /work \
	-e HOME=/tmp \
	"$TAG" \
	$@;

Make this executable, and call it:

sudo chmod a+x /usr/local/bin/docker-debian-bookworm

# dont run as root
docker-debian-bookworm

The first time this runs it will download a base Debian image, and run the above apt-get commands which may take around 10 or so minutes depending on your internet connection and disk speed. After it has run once, it will stay cached and adds almost no overhead to run.

This docker can be thought of as a very low overhead virtual machine that only has access to the directory where it is run.

For example, to build a simple c project, create a ~/Desktop/hello-world/hello.c:

mkdir -p ~/Desktop/hello-world/

In ~/Desktop/hello-world/hello.c:

#include <stdio.h>

int main() {
    printf("Hello world!\n");
    return 0;
}

We can now use the docker in that directory to use Debian's cross compiler to create a binary that targets armhf:

user@hostname:~$ cd ~/Desktop/hello-world/
user@hostname:~/Desktop/hello-world$ docker-debian-bookworm
sha256:a92e70c3d7346654b34c0442da20ae634901fd25d1a89dd26517e7d1c1d00c47
debian_bookworm@a8ddfa54989f:/work$ ls
hello.c
debian_bookworm@a8ddfa54989f:/work$ arm-linux-gnueabihf-gcc hello.c -o hello
debian_bookworm@a8ddfa54989f:/work$ arm-linux-gnueabihf-strip hello
debian_bookworm@a8ddfa54989f:/work$ file hello
hello: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=ffda981721a1531418ed1da27238707851ae0126, for GNU/Linux 3.2.0, stripped

Debian 11 - Bullseye

Debian 11 - Getting Started

The Debian images apply to the TS-4900, TS-7970, and TS-TPC-7990.

Image Size Kernel config Description
debian-armhf-bullseye-latest.tar.bz2 1346 MB ts4900_defconfig Contains gcc, vim, X11, slim, and will autologin to an xfce4 desktop.

Once installed the default user on either image is "root" with no password.

To prepare an SD card, use partitioning tools such as 'fdisk' 'cfdisk' or 'gparted' in linux to create a single linux partition on the SD card. Once the partition is created and formatted, extract the above tarball with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf debian-armhf-bullseye-latest.tar.bz2 -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.

To rewrite the eMMC the unit must be booted to SD or any other media that is not eMMC. Once booted, run the following commands.:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/debian/debian-armhf-bullseye-latest.tar.bz2 | tar xj -C /mnt/emmc/
umount /mnt/emmc
sync

The same commands can be used to write a SATA drive by substituting /dev/mmcblk2p1 with /dev/sda1.

Debian 11 - Networking

The network in Debian is configured /etc/network/interfaces.d/. For complete documentation, see Debian's documentation here

Some common examples are shown below.

DHCP on eth0. Create the file: /etc/network/interfaces.d/eth0

auto eth0
allow-hotplug eth0
iface eth0 inet dhcp

Static IP on eth0. Create the file /etc/network/interfaces.d/eth0

auto eth0
iface eth0 inet static
    address 192.0.2.7/24
    gateway 192.0.2.254

These will take effect on the next boot, or by restarting the networking service:

service networking restart

Debian 11 - WIFI Client

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 11 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Debian 11 - 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@tsa38x:~# 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-11-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-11-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-11-doc - OpenJDK Development Kit (JDK) documentation
openjdk-11-jdk - OpenJDK Development Kit (JDK)
openjdk-11-jdk-headless - OpenJDK Development Kit (JDK) (headless)
openjdk-11-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-11-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
openjdk-11-jre-zero - Alternative JVM for OpenJDK, using Zero
openjdk-11-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-11 - Java plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-jwsgi-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-ring-openjdk-11 - Closure/Ring plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-servlet-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
java-package - Utility for creating Java Debian packages

In this case, the wanted package will likely be the "openjdk-11-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-11-jre
# More than one package can be installed at a time.
apt-get install openjdk-11-jre nano vim mplayer

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

Debian 11 - Setting up SSH

Openssh is installed in our default Debian image, but by default openssh does not permit root logins, and requires a password to be set. Additionally, a host key is required if one hasn't already been created on the target board. To allow remote root login:

sed --in-place 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart ssh.service
/bin/ls /etc/ssh/ssh_host*key >/dev/null 2>&1  || ssh-keygen -A
passwd root # Set any password

If you ssh to this system it will now support ssh as root.

Debian 11 - 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.

Debian 11 - Cross Compiling

Debian only provides their cross compiler for their distribution. Our examples will set up a Docker for Debian to use for development. If using Debian 11 Bullseye directly, or through a VM then the docker usage can be skipped.

Create a file called "Dockerfile" with these contents:

FROM debian:bullseye

RUN dpkg --add-architecture armhf

RUN apt-get update && apt-get install -y \
    autogen \
    automake \
    bash \
    bc \
    bison \
    build-essential \
    bzip2 \
    ca-certificates \
    ccache \
    chrpath \
    cpio \
    curl \
    diffstat \
    fakeroot \
    file \
    flex \
    gawk \
    gcc-arm-linux-gnueabihf \
    git \
    gzip \
    kmod \
    libgpiod-dev:armhf \
    libncursesw5-dev \
    libssl-dev \
    libtool \
    locales \
    lzop \
    make \
    multistrap \
    ncurses-dev \
    pkg-config \
    python \
    python3 \
    python3-pip \
    python3-pexpect \
    qemu-user-static \
    rsync \
    socat \
    runit \
    texinfo \
    u-boot-tools \
    unzip \
    vim \
    wget \
    xz-utils

# To make a more readable PS1 to show we are in the Docker
ENV debian_chroot debian_bullseye
RUN echo "PS1='\${debian_chroot}\\[\033[01;32m\\]@\\H\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ '" >> /etc/bash.bashrc

# Set up locales.  Needed by yocto.
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
        echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
        dpkg-reconfigure --frontend=noninteractive locales && \
        update-locale LANG=en_US.UTF-8

ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

In the same directory as the file named "Dockerfile" run:

docker build --tag armhf-bullseye-toolchain .

When this has finished the docker can be used with:

docker run --rm -it --volume $(pwd):/work armhf-bullseye-toolchain bash

This will map the current directory to /work.

At this point the Debian Docker is ready to compile armhf binaries. For example, create a hello world in your home folder at ~/hello.c

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

To compile this enter the docker with:

docker run -it --volume $(pwd):/work armhf-bullseye-toolchain bash
# Then from the docker:
cd /work/
arm-linux-gnueabihf-gcc hello.c -o hello

Check "file hello" to verify the binary type:

debian_bullseye@b720b8ba6c1e:/work# file hello
hello: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=fc6389ca8da310bb5d0b87e5998b59894c078d9f, for GNU/Linux 3.2.0, not stripped

This can also be used to develop against dynamic libraries from Debian. The armhf packages can be installed in the Docker. For example, to link against curl:

# Enter the Docker:
docker run -it --volume $(pwd):/work armhf-bullseye-toolchain bash
cd /work/

apt-get install libcurl4-openssl-dev:armhf
# Download curl's simple.c example
wget https://raw.githubusercontent.com/bagder/curl/master/docs/examples/simple.c
arm-linux-gnueabihf-gcc simple.c -o simple -lcurl

The "simple" binary is now built for armhf and links dynamically to curl.

This will only retain the armhf libcurl package until the docker is exited. To make the changes permanent, add the package to the Dockerfile and rerun:

docker build --tag armhf-bullseye-toolchain .

Debian 10 - Buster

Debian 10 - Getting Started

The Debian images apply to the TS-4900, TS-7970, and TS-TPC-7990.

Image Size Kernel config Description
debian-armhf-buster-latest.tar.bz2 1113 MB ts4900_defconfig Contains gcc, vim, X11, slim, and will autologin to an xfce4 desktop.

Once installed the default user on either image is "root" with no password.

To prepare an SD card, use partitioning tools such as 'fdisk' 'cfdisk' or 'gparted' in linux to create a single linux partition on the SD card. Once the partition is created and formatted, extract the above tarball with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf debian-armhf-buster-latest.tar.bz2 -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.

To rewrite the eMMC the unit must be booted to SD or any other media that is not eMMC. Once booted, run the following commands.:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- ftp://ftp.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/debian/debian-armhf-buster-latest.tar.bz2 | tar xj -C /mnt/emmc/
umount /mnt/emmc
sync

The same commands can be used to write a SATA drive by substituting /dev/mmcblk2p1 with /dev/sda1.

Debian 10 - Networking

The network in Debian is configured /etc/network/interfaces.d/. For complete documentation, see Debian's documentation here

Some common examples are shown below.

DHCP on eth0. Create the file: /etc/network/interfaces.d/eth0

auto eth0
allow-hotplug eth0
iface eth0 inet dhcp

Static IP on eth0. Create the file /etc/network/interfaces.d/eth0

auto eth0
iface eth0 inet static
    address 192.0.2.7/24
    gateway 192.0.2.254

These will take effect on the next boot, or by restarting the networking service:

service networking restart

Debian 10 - WIFI Client

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 10 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Debian 10 - 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@tsa38x:~# 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-11-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-11-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-11-doc - OpenJDK Development Kit (JDK) documentation
openjdk-11-jdk - OpenJDK Development Kit (JDK)
openjdk-11-jdk-headless - OpenJDK Development Kit (JDK) (headless)
openjdk-11-jre - OpenJDK Java runtime, using Hotspot JIT
openjdk-11-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless)
openjdk-11-jre-zero - Alternative JVM for OpenJDK, using Zero
openjdk-11-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-11 - Java plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-jwsgi-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-ring-openjdk-11 - Closure/Ring plugin for uWSGI (OpenJDK 11)
uwsgi-plugin-servlet-openjdk-11 - JWSGI plugin for uWSGI (OpenJDK 11)
java-package - Utility for creating Java Debian packages

In this case, the wanted package will likely be the "openjdk-11-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-11-jre
# More than one package can be installed at a time.
apt-get install openjdk-11-jre nano vim mplayer

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

Debian 10 - Setting up SSH

Openssh is installed in our default Debian image, but by default openssh does not permit root logins, and requires a password to be set. Additionally, a host key is required if one hasn't already been created on the target board. To allow remote root login:

sed --in-place 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart ssh.service
/bin/ls /etc/ssh/ssh_host*key >/dev/null 2>&1  || ssh-keygen -A
passwd root # Set any password

If you ssh to this system it will now support ssh as root.

Debian 10 - 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.

Debian 10 - Cross Compiling

Debian only provides their cross compiler for their distribution. Our examples will set up a Docker for Debian to use for development. If using Debian 10 Buster directly, or through a VM then the docker usage can be skipped.

Create a file called "Dockerfile" with these contents:

FROM debian:buster

RUN dpkg --add-architecture armhf

RUN apt-get update && apt-get install -y \
    autogen \
    automake \
    bash \
    bc \
    bison \
    build-essential \
    bzip2 \
    ca-certificates \
    ccache \
    chrpath \
    cpio \
    curl \
    diffstat \
    fakeroot \
    file \
    flex \
    gawk \
    gcc-arm-linux-gnueabihf \
    git \
    gzip \
    kmod \
    libgpiod-dev:armhf \
    libncursesw5-dev \
    libssl-dev \
    libtool \
    locales \
    lzop \
    make \
    multistrap \
    ncurses-dev \
    pkg-config \
    python \
    python3 \
    python3-pip \
    python3-pexpect \
    qemu-user-static \
    rsync \
    socat \
    runit \
    texinfo \
    u-boot-tools \
    unzip \
    vim \
    wget \
    xz-utils

# To make a more readable PS1 to show we are in the Docker
ENV debian_chroot debian_buster
RUN echo "PS1='\${debian_chroot}\\[\033[01;32m\\]@\\H\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ '" >> /etc/bash.bashrc

# Set up locales.  Needed by yocto.
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
        echo 'LANG="en_US.UTF-8"'>/etc/default/locale && \
        dpkg-reconfigure --frontend=noninteractive locales && \
        update-locale LANG=en_US.UTF-8

ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

In the same directory as the file named "Dockerfile" run:

docker build --tag armhf-buster-toolchain .

When this has finished the docker can be used with:

docker run --rm -it --volume $(pwd):/work armhf-buster-toolchain bash

This will map the current directory to /work.

At this point the Debian Docker is ready to compile armhf binaries. For example, create a hello world in your home folder at ~/hello.c

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

To compile this enter the docker with:

docker run -it --volume $(pwd):/work armhf-buster-toolchain bash
# Then from the docker:
cd /work/
arm-linux-gnueabihf-gcc hello.c -o hello

Check "file hello" to verify the binary type:

user@host:~/$ file hello
hello: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=8a8cee3341d3ef76ef6796f72d5722ae9d77c8ea, not stripped

This can also be used to develop against dynamic libraries from Debian. The armhf packages can be installed in the Docker. For example, to link against curl:

# Enter the Docker:
docker run -it --volume $(pwd):/work armhf-buster-toolchain bash
cd /work/

apt-get install libcurl4-openssl-dev:armhf
# Download curl's simple.c example
wget https://raw.githubusercontent.com/bagder/curl/master/docs/examples/simple.c
arm-linux-gnueabihf-gcc simple.c -o simple -lcurl

The "simple" binary is now built for armhf and links dynamically to curl.

This will only retain the armhf libcurl package until the docker is exited. To make the changes permanent, add the package to the Dockerfile and rerun:

docker build --tag armhf-buster-toolchain .

Debian 9 - Stretch

Debian 9 - Getting Started

We provide two images for Debian Stretch which apply to our TS-4900, TS-7970, and TS-TPC-7990. If you are unsure which image to pick, use the larger image which contains more development tools and drivers.

Image Size Kernel config Description
debian-armhf-stretch-latest.tar.bz2 1279MB ts4900_defconfig Contains gcc, vim, X11, slim, and will autologin to an xfce4 desktop.
debian-armhf-stretch-minimal-latest.tar.bz2 184MB ts4900_tiny_defconfig Stripped down Debian containing bare minimal hardware support, very limited peripheral support, and only the core debian packages.

Once installed the default user on either image is "root" with no password.

To prepare an SD card, use partitioning tools such as 'fdisk' 'cfdisk' or 'gparted' in linux to create a single linux partition on the SD card. Once the partition is created and formatted, extract the above tarball with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf debian-armhf-stretch-latest.tar.bz2 -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.

To rewrite the eMMC the unit must be booted to SD or any other media that is not eMMC. Once booted, run the following commands.:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- ftp://ftp.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/debian/debian-armhf-stretch-latest.tar.bz2 | tar xj -C /mnt/emmc/
umount /mnt/emmc
sync


The same commands can be used to write a SATA drive by substituting /dev/mmcblk2p1 with /dev/sda1.

Debian 9 - Networking

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 9 - WIFI Client

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 9 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Debian 9 - Application Development

Debian 9 - 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 9 - 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 9 - 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 9 - 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.

To start an application on bootup with X11 instead change the x-session-manager. By default the system starts xfce:

root@ts:~# ls -lah /usr/bin/x-session-manager 
lrwxrwxrwx 1 root root 35 May 26  2015 /usr/bin/x-session-manager -> /etc/alternatives/x-session-manager
root@ts:~# ls -lah /etc/alternatives/x-session-manager
lrwxrwxrwx 1 root root 19 May 26  2015 /etc/alternatives/x-session-manager -> /usr/bin/startxfce4

The x-session can be modified to only start specified processes. Create the file /usr/bin/mini-x-session with these contents:

#!/bin/bash
matchbox-window-manager -use_titlebar no &

exec xfce4-terminal

You may need to "apt-get install matchbox-window-manager." first. This is a tiny window manager which also has a few flags that simplify embedded use. Now enable this session manager and restart slim to restart x11 and show it now.

chmod a+x /usr/bin/mini-x-session
rm /etc/alternatives/x-session-manager
ln -s /usr/bin/mini-x-session /etc/alternatives/x-session-manager
service slim restart

If the x-session-manager process ever closes x11 will restart. The exec command allows a new process to take over the existing PID. In the above example xfce4-terminal takes over the PID of x-session-manager. If the terminal is closed with commands like exit the slim/x11 processes will restart.

Debian 8 - Jessie

Debian 8 - Getting Started

Once installed, the default user is "root" with no password.

Note: This is a shared image that supports the TS-4900, TS-7970, and TS-TPC-7990.


To prepare an SD card, use partitioning tools such as 'fdisk' 'cfdisk' or 'gparted' in linux to create a single linux partition on the SD card. Once the partition is set up and formatted, extract the above tarball with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf debian-armhf-jessie-latest.tar.bz2 -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.

To rewrite the eMMC the unit must be booted to SD or any other media that is not eMMC. Once booted, run the following commands.:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/debian/debian-armhf-jessie-latest.tar.bz2 | tar xj -C /mnt/emmc/
umount /mnt/emmc
sync


The same commands can be used to write a SATA drive by substituting /dev/mmcblk2p1 with /dev/sda1.

Debian 8 - Networking

From almost any Linux system you can use 'ip' command or the 'ifconfig' and 'route' commands to initially set up the network.

# Bring up the CPU network interface
ifconfig eth0 up

# Or if you're on a baseboard with a second ethernet port, you can use that as:
ifconfig eth1 up

# Set an ip address (assumes 255.255.255.0 subnet mask)
ifconfig eth0 192.168.0.50

# Set a specific subnet
ifconfig eth0 192.168.0.50 netmask 255.255.0.0

# Configure your route.  This is the server that provides your internet connection.
route add default gw 192.168.0.1

# Edit /etc/resolv.conf for your DNS server
echo "nameserver 192.168.0.1" > /etc/resolv.conf

Most networks will offer a DHCP server, an IP address can be obtained from a server with a single command in linux:

Configure DHCP in Debian:

# To setup the default CPU ethernet port
dhclient eth0
# Or if you're on a baseboard with a second ethernet port, you can use that as:
dhclient eth1
# You can configure all ethernet ports for a dhcp response with
dhclient


Systemd provides a networking configuration option to allow for automatic configuration on startup. Systemd-networkd has a number of different configuration files, some of the default examples and setup steps are outlined below.

/etc/systemd/network/eth.network

[Match]
Name=eth*

[Network]
DHCP=yes

To use DHCP to configure DNS via systemd, start and enable the network name resolver service, systemd-resolved:

systemctl start systemd-resolved.service 
systemctl enable systemd-resolved.service
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf


For a static config create a network configuration for that specific interface.

/etc/systemd/network/eth0.network

[Match]
Name=eth0

[Network]
Address=192.168.0.50/24
Gateway=192.168.0.1
DNS=192.168.0.1

For more information on networking, see Debian and systemd's documentation:

Debian 8 - WIFI Client

If connecting to a WPA/WPA2 network, a wpa_supplicant config file must first be created:

wpa_passphrase yournetwork yournetworkpassphrase > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf


Create the file /lib/systemd/system/wpa_supplicant@.service with these contents

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service


Create the file /etc/systemd/network/wlan0.network with:

[Match]
Name=wlan0

[Network]
DHCP=yes

See the systemctl-networkd example for setting a static IP for a network interface. The wlan0.network can be configured the same way as an eth.network.


To enable all of the changes that have been made, run the following commands:

systemctl enable wpa_supplicant@wlan0
systemctl start wpa_supplicant@wlan0
systemctl restart systemd-networkd

Debian 8 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Debian 8 - Application Development

Debian 8 - Jessie Cross Compiling

Debian Jessie previously provided cross compilers via the Emdebian project. However, Emdebian has been unmaintained for a number of years and is no longer able to provide a viable install package. In order to cross compile from a Debian Jessie workstation, a third party cross compiler is required.

A Debian Jessie install on a workstation has the ability to build for the same release on other architectures using Debian binary libraries. A PC, virtual machine, or chroot will need to be used for this. Install Debian Jessie for your workstation here.

From a Debian workstation (not the target), run the following commands to set up the cross compiler. Note that this expects a 64-bit Debian Jessie install on the workstation. 32-bit installations are not supported at this time.

# Run "lsb_release -a" and verify Debian 8.X is returned.  These instructions are not
# expected to work on any other version or distribution.

cd ~
wget http://ftp.embeddedTS.com/ftp/ts-arm-sbc/ts-7553-V2-linux/cross-toolchains/gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf.tar.xz
# The above toolchain is from Linaro. Other cross compilers can be used but have not been tested.
mkdir cross_compiler
tar xvf gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf.tar.xz -C ~/cross_compiler
export PATH=$PATH:~/cross_compiler/gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf/bin/
# The 'export' command needs to be run every time the user logs in. It is possible to add this command to the user's ".bashrc" file
# in their home directory to ensure it is automatically run every time the user is logged in.
su root
dpkg --add-architecture armhf
apt-get update
apt-get install build-essential

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 Jessie 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 ".so" files. 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. Note that since the cross compiler used is 3rd party and not directly from Debian, some compile commands that include libraries will need additional arguments to tell the compiler and linker where on the workstation to find the necessary headers and libraries. Usually, the additional arguments will look like the following string, however adjustments may need to be made depending on the application.

 -I/usr/include -L/usr/lib/arm-linux-gnueabihf -L/lib/arm-linux-gnueabihf -Wl,-rpath=/usr/lib/arm-linux-gnueabihf,-rpath=/lib/arm-linux-gnueabihf


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 -I/usr/include -L/usr/lib/arm-linux-gnueabihf -L/lib/arm-linux-gnueabihf -Wl,-rpath=/usr/lib/arm-linux-gnueabihf,-rpath=/lib/arm-linux-gnueabihf 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 8 - 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.

Older Debian releases are moved to a different server to indicate it is no longer getting security updates. To download packages for these older distributions, edit /etc/apt/sources.list to only have the following lines:

Jessie:

deb http://archive.debian.org/debian/ jessie main
deb-src http://archive.debian.org/debian/ jessie main

Wheezy:

deb http://archive.debian.org/debian/ wheezy main
deb-src http://archive.debian.org/debian/ wheezy main

After modifying that file, be sure to update the package list:

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
jvm-7-avian-jre - lightweight virtual machine using the OpenJDK class library
freemind - Java Program for creating and viewing Mindmaps
icedtea-7-plugin - web browser plugin based on OpenJDK and IcedTea to execute Java applets
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
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)
icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
openjdk-7-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-7-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-7-doc - OpenJDK Development Kit (JDK) documentation
openjdk-7-jdk - OpenJDK Development Kit (JDK)
openjdk-7-jre - OpenJDK Java runtime, using Hotspot Zero
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot Zero (headless)
openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries)
openjdk-7-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7)
uwsgi-plugin-jwsgi-openjdk-7 - JWSGI plugin for uWSGI (OpenJDK 7)
                                                       

In this case you will want the openjdk-7-jre package. Names of packages are on Debian's wiki or the packages site.

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

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

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

Debian 8 - Setting up SSH

To install ssh, install the package as normal with apt-get:

apt-get install openssh-server


Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password or a valid SSH key pair.

passwd root
Note: The default OpenSSH server will not permit root to login via SSH as a security precaution. To allow root to log in via ssh anyway, edit the /etc/ssh/sshd_config file and add the line PermitRootLogin yes in the authentication section. This change will take effect after reboot or after sshd service restart.

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

Note: If a DNS server is not present on the target network, it is possible to save time at login by adding "UseDNS no" in /etc/ssh/sshd_config.

Debian 8 - 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.

To start an application on bootup with X11 instead change the x-session-manager. By default the system starts xfce:

root@ts:~# ls -lah /usr/bin/x-session-manager 
lrwxrwxrwx 1 root root 35 May 26  2015 /usr/bin/x-session-manager -> /etc/alternatives/x-session-manager
root@ts:~# ls -lah /etc/alternatives/x-session-manager
lrwxrwxrwx 1 root root 19 May 26  2015 /etc/alternatives/x-session-manager -> /usr/bin/startxfce4

The x-session can be modified to only start specified processes. Create the file /usr/bin/mini-x-session with these contents:

#!/bin/bash
matchbox-window-manager -use_titlebar no &

exec xfce4-terminal

You may need to "apt-get install matchbox-window-manager." first. This is a tiny window manager which also has a few flags that simplify embedded use. Now enable this session manager and restart slim to restart x11 and show it now.

chmod a+x /usr/bin/mini-x-session
rm /etc/alternatives/x-session-manager
ln -s /usr/bin/mini-x-session /etc/alternatives/x-session-manager
service slim restart

If the x-session-manager process ever closes x11 will restart. The exec command allows a new process to take over the existing PID. In the above example xfce4-terminal takes over the PID of x-session-manager. If the terminal is closed with commands like exit the slim/x11 processes will restart.

Ubuntu

Ubuntu is a distribution provided by Canonical which is based on Debian. Ubuntu often has more recent packages but follows a shorter release cycle. The image we provide is based on Ubuntu. We use the root filesystem, but the kernel is not provided by Ubuntu or in any way associated with Canonical.

This image includes support for the TS-4900, TS-7970, and TS-TPC-7990.

Ubuntu 24.04 - Noble

Ubuntu 24.04 - Getting Started

This Ubuntu release is available in 3 flavors with various packages.

Image Estimated Size Description
ubuntu-armhf-24.04-x11-latest.tar.bz2 1091 MiB
  • Includes 6.6.y kernel with tsimx6_defconfig that includes broad driver support
  • Base Ubuntu with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
  • Includes X11 that launches matchbox and xterm on startup
  • Includes touchscreen support
ubuntu-armhf-24.04-headless-latest.tar.bz2 866 MiB
  • Includes 6.6.y kernel with tsimx6_defconfig that includes broad driver support
  • Base Ubuntu with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
ubuntu-armhf-24.04-minimal-latest.tar.bz2 190 MiB
  • Includes 6.6.y kernel with tsimx6_minimal_defconfig that includes bare minimum driver support and kernel options required by Ubuntu.
  • Includes base Ubuntu rootfs adding only what is required for Ethernet support.

The default login is "user/user" which includes sudo permissions.

To write this to an SD card, first partition the SD card to have one large ext3, or ext4 partition. See the guide here for more information. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf ubuntu-armhf-24.04-latest.tar.bz2 -C /mnt/sd
sudo umount /mnt/sd
sync

To rewrite the eMMC, boot to the SD card. You cannot rewrite the emmc while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/ubuntu/ubuntu-armhf-24.04-x11-latest.tar.bz2 | tar --numeric-owner -xj -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.

Ubuntu 24.04 - Networking

The network in Ubuntu is configured netplan. For complete documentation, see Netplan's documentation here

Some common examples are shown below. On this release network interfaces follow the predictible network interface names. Run ip addr show to get a list of the network interfaces.

Most commonly:

  • end0 - Ethernet device 0 (CPU Ethernet)
  • enp1s0 - Ethernet PCIe port 1 slot 0 ethernet
  • usb<mac> - USB ethernet
  • wlan0 - WIFI

DHCP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
      dhcp4: true
      dhcp6: true

Static IP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
     dhcp4: no
     addresses: [192.168.0.50/24]
     gateway4: 192.168.0.1
     nameservers:
       addresses: [8.8.8.8,8.8.4.4]

After creating the yaml file, set the appropriate permissions and apply the netplan:

sudo chmod 600 /etc/netplan/*.yaml
sudo netplan apply

Ubuntu 24.04 - WIFI Client

Wireless configuration under Ubuntu, similar to Ethernet, also uses netplan for configuration. For example, create /etc/netplan/wifi.yaml:

network:
  version: 2
  renderer: networkd
  wifis:
    wlan0:
      dhcp4: yes
      dhcp6: yes
      access-points:
        "yourssid":
          password: yourpassphrase"

After creating the yaml file, set the appropriate permissions and apply the netplan:

sudo chmod 600 /etc/netplan/*.yaml
sudo netplan apply

Ubuntu 24.04 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Ubuntu 24.04 - Installing New Software

Ubuntu provides the apt-get system which lets you manage pre-built applications. Before you do this you need to update Ubuntu's list of package versions and locations. This assumes you have a valid network connection to the internet.

apt-get update

For example, lets say you wanted to install openjdk for Java support. You can use the apt-cache command to search the local cache of Debian's packages.

root@ts-imx6:~# apt-cache search openjdk
jvm-7-avian-jre - lightweight virtual machine using the OpenJDK class library
freemind - Java Program for creating and viewing Mindmaps
icedtea-7-plugin - web browser plugin based on OpenJDK and IcedTea to execute Java applets
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
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)
icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
openjdk-7-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-7-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-7-doc - OpenJDK Development Kit (JDK) documentation
openjdk-7-jdk - OpenJDK Development Kit (JDK)
openjdk-7-jre - OpenJDK Java runtime, using Hotspot Zero
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot Zero (headless)
openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries)
openjdk-7-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7)
uwsgi-plugin-jwsgi-openjdk-7 - JWSGI plugin for uWSGI (OpenJDK 7)                                              

In this case you will likely want openjdk-7-jre to provide a runtime environment, and possibly openjdk-7-jdk to provide a development environment.

Once you have the package name you can use apt-get to install the package and any dependencies. This assumes you have a network connection to the internet.

apt-get install openjdk-7-jre
# You can also chain packages to be installed
apt-get install openjdk-7-jre nano vim mplayer

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

Ubuntu 24.04 - Setting up SSH

To install ssh, install the package as normal with apt-get:

apt-get install openssh-server


Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password or a valid SSH key pair.

passwd root
Note: The default OpenSSH server will not permit root to login via SSH as a security precaution. To allow root to log in via ssh anyway, edit the /etc/ssh/sshd_config file and add the line PermitRootLogin yes in the authentication section. This change will take effect after reboot or after sshd service restart.

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

Note: If a DNS server is not present on the target network, it is possible to save time at login by adding "UseDNS no" in /etc/ssh/sshd_config.

Ubuntu 24.04 - 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.

Ubuntu 23.04 - Lunar

Ubuntu 23.04 - Getting Started

This Ubuntu release is available in 3 flavors with various packages.

Image Estimated Size Description
ubuntu-armhf-23.04-x11-latest.tar.bz2 1068 MiB
  • Includes 5.10 kernel with tsimx6_defconfig that includes broad driver support
  • Base Ubuntu with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
  • Includes X11 that launches matchbox and xterm on startup
  • Includes touchscreen support
ubuntu-armhf-23.04-headless-latest.tar.bz2 845 MiB
  • Includes 5.10 kernel with tsimx6_defconfig that includes broad driver support
  • Base Ubuntu with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
ubuntu-armhf-23.04-minimal-latest.tar.bz2 207 MiB
  • Includes 5.10 kernel with tsimx6_minimal_defconfig that includes bare minimum driver support and kernel options required by Ubuntu.
  • Includes base Ubuntu rootfs adding only what is required for Ethernet support.

The default login is "user/user" which includes sudo permissions.

To write this to an SD card, first partition the SD card to have one large ext3, or ext4 partition. See the guide here for more information. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf ubuntu-armhf-23.04-latest.tar.bz2 -C /mnt/sd
sudo umount /mnt/sd
sync

To rewrite the eMMC, boot to the SD card. You cannot rewrite the emmc while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/ubuntu/ubuntu-armhf-23.04-x11-latest.tar.bz2 | tar --numeric-owner -xj -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.

Ubuntu 23.04 - Networking

The network in Ubuntu is configured netplan. For complete documentation, see Netplan's documentation here

Some common examples are shown below. On this release network interfaces follow the predictible network interface names. Run ip addr show to get a list of the network interfaces.

Most commonly:

  • end0 - Ethernet device 0 (CPU Ethernet)
  • enp1s0 - Ethernet PCIe port 1 slot 0 ethernet
  • usb<mac> - USB ethernet
  • wlan0 - WIFI

DHCP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
      dhcp4: true
      dhcp6: true

Static IP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
     dhcp4: no
     addresses: [192.168.0.50/24]
     gateway4: 192.168.0.1
     nameservers:
       addresses: [8.8.8.8,8.8.4.4]

After creating the yaml file, set the appropriate permissions and apply the netplan:

sudo chmod 600 /etc/netplan/*.yaml
sudo netplan apply

Ubuntu 23.04 - WIFI Client

Wireless configuration under Ubuntu, similar to Ethernet, also uses netplan for configuration. For example, create /etc/netplan/wifi.yaml:

network:
  version: 2
  renderer: networkd
  wifis:
    wlan0:
      dhcp4: yes
      dhcp6: yes
      access-points:
        "yourssid":
          password: yourpassphrase"

After creating the yaml file, set the appropriate permissions and apply the netplan:

sudo chmod 600 /etc/netplan/*.yaml
sudo netplan apply

Ubuntu 23.04 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Ubuntu 23.04 - Installing New Software

Ubuntu provides the apt-get system which lets you manage pre-built applications. Before you do this you need to update Ubuntu's list of package versions and locations. This assumes you have a valid network connection to the internet.

apt-get update

For example, lets say you wanted to install openjdk for Java support. You can use the apt-cache command to search the local cache of Debian's packages.

root@ts-imx6:~# apt-cache search openjdk
jvm-7-avian-jre - lightweight virtual machine using the OpenJDK class library
freemind - Java Program for creating and viewing Mindmaps
icedtea-7-plugin - web browser plugin based on OpenJDK and IcedTea to execute Java applets
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
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)
icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
openjdk-7-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-7-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-7-doc - OpenJDK Development Kit (JDK) documentation
openjdk-7-jdk - OpenJDK Development Kit (JDK)
openjdk-7-jre - OpenJDK Java runtime, using Hotspot Zero
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot Zero (headless)
openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries)
openjdk-7-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7)
uwsgi-plugin-jwsgi-openjdk-7 - JWSGI plugin for uWSGI (OpenJDK 7)                                              

In this case you will likely want openjdk-7-jre to provide a runtime environment, and possibly openjdk-7-jdk to provide a development environment.

Once you have the package name you can use apt-get to install the package and any dependencies. This assumes you have a network connection to the internet.

apt-get install openjdk-7-jre
# You can also chain packages to be installed
apt-get install openjdk-7-jre nano vim mplayer

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

Ubuntu 23.04 - Setting up SSH

To install ssh, install the package as normal with apt-get:

apt-get install openssh-server


Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password or a valid SSH key pair.

passwd root
Note: The default OpenSSH server will not permit root to login via SSH as a security precaution. To allow root to log in via ssh anyway, edit the /etc/ssh/sshd_config file and add the line PermitRootLogin yes in the authentication section. This change will take effect after reboot or after sshd service restart.

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

Note: If a DNS server is not present on the target network, it is possible to save time at login by adding "UseDNS no" in /etc/ssh/sshd_config.

Ubuntu 23.04 - 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.

Ubuntu 20.04 - Focal

Ubuntu 20.04 - Getting Started

The latest release is available here:

The login is either "root" with no password, or username "ubuntu" with the password "ubuntu". The ubuntu user is allowed to run sudo.

To write this to an SD card, first partition the SD card to have one large ext3, or ext4 partition. See the guide here for more information. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf ubuntu-armhf-20.04-latest.tar.bz2 -C /mnt/sd
sudo umount /mnt/sd
sync

To rewrite the eMMC, boot to the SD card. You cannot rewrite the emmc while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/ubuntu/ubuntu-armhf-20.04-latest.tar.bz2 | tar --numeric-owner -xj -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.

Ubuntu 20.04 - Networking

The network in Ubuntu is configured netplan. For complete documentation, see Netplan's documentation here

Some common examples are shown below. On this release network interfaces follow the predictible network interface names. Run ip addr show to get a list of the network interfaces.

Most commonly:

  • end0 - Ethernet device 0 (CPU Ethernet)
  • enp1s0 - Ethernet PCIe port 1 slot 0 ethernet
  • usb<mac> - USB ethernet
  • wlan0 - WIFI

DHCP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
      dhcp4: true
      dhcp6: true

Static IP on end0. Edit the file /etc/netplan/ethernet.yaml and add:

network:
  version: 2
  renderer: networkd
  ethernets:
    end0:
     dhcp4: no
     addresses: [192.168.0.50/24]
     gateway4: 192.168.0.1
     nameservers:
       addresses: [8.8.8.8,8.8.4.4]

After creating the yaml file, set the appropriate permissions and apply the netplan:

sudo chmod 600 /etc/netplan/*.yaml
sudo netplan apply

Ubuntu 20.04 - WIFI Client

If connecting to a WPA/WPA2 network, a wpa_supplicant config file must first be created:

wpa_passphrase yournetwork yournetworkpassphrase > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf


Create the file /lib/systemd/system/wpa_supplicant@.service with these contents

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

Next, enable the service to start up on boot:

systemctl enable wpa_supplicant@wlan0

Create the file /etc/systemd/network/wlan0.network with:

[Match]
Name=wlan0

[Network]
DHCP=yes

Enable networkd to run dhcp on startup:

systemctl enable systemd-networkd

See the systemctl-networkd example for setting a static IP for a network interface. The wlan0.network can be configured the same way as an eth.network. To enable all of the changes that have been made, run the following commands:

systemctl enable wpa_supplicant@wlan0
systemctl start wpa_supplicant@wlan0
systemctl restart systemd-networkd

Ubuntu 20.04 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Ubuntu 20.04 - Installing New Software

Ubuntu provides the apt-get system which lets you manage pre-built applications. Before you do this you need to update Ubuntu's list of package versions and locations. This assumes you have a valid network connection to the internet.

apt-get update

For example, lets say you wanted to install openjdk for Java support. You can use the apt-cache command to search the local cache of Debian's packages.

root@ts-imx6:~# apt-cache search openjdk
jvm-7-avian-jre - lightweight virtual machine using the OpenJDK class library
freemind - Java Program for creating and viewing Mindmaps
icedtea-7-plugin - web browser plugin based on OpenJDK and IcedTea to execute Java applets
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
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)
icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
openjdk-7-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-7-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-7-doc - OpenJDK Development Kit (JDK) documentation
openjdk-7-jdk - OpenJDK Development Kit (JDK)
openjdk-7-jre - OpenJDK Java runtime, using Hotspot Zero
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot Zero (headless)
openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries)
openjdk-7-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7)
uwsgi-plugin-jwsgi-openjdk-7 - JWSGI plugin for uWSGI (OpenJDK 7)                                              

In this case you will likely want openjdk-7-jre to provide a runtime environment, and possibly openjdk-7-jdk to provide a development environment.

Once you have the package name you can use apt-get to install the package and any dependencies. This assumes you have a network connection to the internet.

apt-get install openjdk-7-jre
# You can also chain packages to be installed
apt-get install openjdk-7-jre nano vim mplayer

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

Ubuntu 20.04 - Setting up SSH

To install ssh, install the package as normal with apt-get:

apt-get install openssh-server


Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password or a valid SSH key pair.

passwd root
Note: The default OpenSSH server will not permit root to login via SSH as a security precaution. To allow root to log in via ssh anyway, edit the /etc/ssh/sshd_config file and add the line PermitRootLogin yes in the authentication section. This change will take effect after reboot or after sshd service restart.

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

Note: If a DNS server is not present on the target network, it is possible to save time at login by adding "UseDNS no" in /etc/ssh/sshd_config.

Ubuntu 20.04 - 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.

Ubuntu 18.04 - Xenial

Ubuntu 18.04 - Getting Started

The latest release is available here:

The login is either "root" with no password, or username "ubuntu" with the password "ubuntu". The ubuntu user is allowed to run sudo.

To write this to an SD card, first partition the SD card to have one large ext3, or ext4 partition. See the guide here for more information. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xjf ubuntu-armhf-18.04-latest.tar.bz2 -C /mnt/sd
sudo umount /mnt/sd
sync

To rewrite the eMMC, boot to the SD card. You cannot rewrite the emmc while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/ubuntu/ubuntu-armhf-18.04-latest.tar.bz2 | tar --numeric-owner -xj -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.

Ubuntu 18.04 - Networking

From almost any Linux system you can use "ip" or the ifconfig/route commands to set up the network.

# Bring up the CPU network interface
ifconfig eth0 up

# Or if you're on a baseboard with a second ethernet port, you can use that as:
ifconfig eth1 up

# Set an ip address (assumes 255.255.255.0 subnet mask)
ifconfig eth0 192.168.0.50

# Set a specific subnet
ifconfig eth0 192.168.0.50 netmask 255.255.0.0

# Configure your route.  This is the server that provides your internet connection.
route add default gw 192.168.0.1

# Edit /etc/resolv.conf for your DNS server
echo "nameserver 192.168.0.1" > /etc/resolv.conf

Most networks will offer DHCP which can be set up with one command:

# To setup the default CPU ethernet port
dhclient eth0
# Or if you're on a baseboard with a second ethernet port, you can use that as:
dhclient eth1
# You can configure all ethernet ports for a dhcp response with
dhclient

To make DHCP run on startup systemd's networking will need to be configured.

In /etc/systemd/network/eth.network

[Match]
Name=eth*

[Network]
DHCP=yes

Then, if you intend to use DHCP to configure your DNS, start and enable the network name resolver service:

systemctl start systemd-resolved.service 
systemctl enable systemd-resolved.service
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

For a static configuration create a config file for that specific interface. /etc/systemd/network/eth0.network

[Match]
Name=eth0

[Network]
Address=192.168.0.50/24
Gateway=192.168.0.1
DNS=192.168.0.1

For more information on networking, see Ubuntu and systemd's documentation:

Ubuntu 18.04 - WIFI Client

If connecting to a WPA/WPA2 network, a wpa_supplicant config file must first be created:

wpa_passphrase yournetwork yournetworkpassphrase > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf


Create the file /lib/systemd/system/wpa_supplicant@.service with these contents

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

Next, enable the service to start up on boot:

systemctl enable wpa_supplicant@wlan0

Create the file /etc/systemd/network/wlan0.network with:

[Match]
Name=wlan0

[Network]
DHCP=yes

Enable networkd to run dhcp on startup:

systemctl enable systemd-networkd

See the systemctl-networkd example for setting a static IP for a network interface. The wlan0.network can be configured the same way as an eth.network. To enable all of the changes that have been made, run the following commands:

systemctl enable wpa_supplicant@wlan0
systemctl start wpa_supplicant@wlan0
systemctl restart systemd-networkd

Ubuntu 18.04 - WIFI Access Point

First, hostapd needs to be installed in order to manage the access point on the device:

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


Note: The install process will start an unconfigured hostapd process. This process must be killed and restarted before a new hostapd.conf will take effect.

Edit /etc/hostapd/hostapd.conf to include the following lines:

interface=wlan0
driver=nl80211
ssid=YourAPName
channel=1
Note: Refer to the kernel's hostapd documentation for more wireless configuration options.


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

This will start up an access point that can be detected by WIFI clients. A DHCP server will likely be desired to assign IP addresses. Refer to Debian's documentation for more details on DHCP configuration.

Ubuntu 18.04 - Installing New Software

Ubuntu provides the apt-get system which lets you manage pre-built applications. Before you do this you need to update Ubuntu's list of package versions and locations. This assumes you have a valid network connection to the internet.

apt-get update

For example, lets say you wanted to install openjdk for Java support. You can use the apt-cache command to search the local cache of Debian's packages.

root@ts-imx6:~# apt-cache search openjdk
jvm-7-avian-jre - lightweight virtual machine using the OpenJDK class library
freemind - Java Program for creating and viewing Mindmaps
icedtea-7-plugin - web browser plugin based on OpenJDK and IcedTea to execute Java applets
default-jdk - Standard Java or Java compatible Development Kit
default-jdk-doc - Standard Java or Java compatible Development Kit (documentation)
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)
icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM
openjdk-7-dbg - Java runtime based on OpenJDK (debugging symbols)
openjdk-7-demo - Java runtime based on OpenJDK (demos and examples)
openjdk-7-doc - OpenJDK Development Kit (JDK) documentation
openjdk-7-jdk - OpenJDK Development Kit (JDK)
openjdk-7-jre - OpenJDK Java runtime, using Hotspot Zero
openjdk-7-jre-headless - OpenJDK Java runtime, using Hotspot Zero (headless)
openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries)
openjdk-7-source - OpenJDK Development Kit (JDK) source files
uwsgi-app-integration-plugins - plugins for integration of uWSGI and application
uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7)
uwsgi-plugin-jwsgi-openjdk-7 - JWSGI plugin for uWSGI (OpenJDK 7)                                              

In this case you will likely want openjdk-7-jre to provide a runtime environment, and possibly openjdk-7-jdk to provide a development environment.

Once you have the package name you can use apt-get to install the package and any dependencies. This assumes you have a network connection to the internet.

apt-get install openjdk-7-jre
# You can also chain packages to be installed
apt-get install openjdk-7-jre nano vim mplayer

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

Ubuntu 18.04 - Setting up SSH

To install ssh, install the package as normal with apt-get:

apt-get install openssh-server


Make sure the device is configured on the network and set a password for the remote user. SSH will not allow remote connections without a password or a valid SSH key pair.

passwd root
Note: The default OpenSSH server will not permit root to login via SSH as a security precaution. To allow root to log in via ssh anyway, edit the /etc/ssh/sshd_config file and add the line PermitRootLogin yes in the authentication section. This change will take effect after reboot or after sshd service restart.

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

Note: If a DNS server is not present on the target network, it is possible to save time at login by adding "UseDNS no" in /etc/ssh/sshd_config.

Ubuntu 18.04 - 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.

To start an application on bootup with X11 instead change the x-session-manager. By default the system starts xfce:

root@ts:~# ls -lah /usr/bin/x-session-manager 
lrwxrwxrwx 1 root root 35 May 26  2015 /usr/bin/x-session-manager -> /etc/alternatives/x-session-manager
root@ts:~# ls -lah /etc/alternatives/x-session-manager
lrwxrwxrwx 1 root root 19 May 26  2015 /etc/alternatives/x-session-manager -> /usr/bin/startxfce4

The x-session can be modified to only start specified processes. Create the file /usr/bin/mini-x-session with these contents:

#!/bin/bash
matchbox-window-manager -use_titlebar no &

exec xfce4-terminal

You may need to "apt-get install matchbox-window-manager." first. This is a tiny window manager which also has a few flags that simplify embedded use. Now enable this session manager and restart slim to restart x11 and show it now.

chmod a+x /usr/bin/mini-x-session
rm /etc/alternatives/x-session-manager
ln -s /usr/bin/mini-x-session /etc/alternatives/x-session-manager
service slim restart

If the x-session-manager process ever closes x11 will restart. The exec command allows a new process to take over the existing PID. In the above example xfce4-terminal takes over the PID of x-session-manager. If the terminal is closed with commands like exit the slim/x11 processes will restart.

Ubuntu Core

Ubuntu Core is a new distribution provided by Canonical targetted towards embedded/IoT projects. This requires users to generate "snap" packages for their application, but provides a mechanism for save remote updates to the OS and packages. Our kernel is based on Ubuntu 16's 4.4 based kernel to provide the best compatibility and support. Bug fixes to units using our kernel snap are provided through the ubuntu core app store.

Read more about Ubuntu Core here.

Getting Started with Ubuntu Core

Download our latest image here. The image unpacks to 1 GB, an SD card of equal or larger size must be used.

Write this to an SD card with:

wget ftp://ftp.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions\
/ubuntu-core/ubuntu-core-16-latest.img.bz2
bzip2 -d ubuntu-core-16-latest.img.bz2
# Assuming /dev/sdd is your SD card.  Check dmesg after inserting for your device.
# Make sure this is the block device (/dev/sdd) and not a partition (/dev/sdd1).
dd if=/path/to/ubuntu-core-16-latest.img bs=4M of=/dev/sdd conv=fsync && sync

This can be written to emmc using the Image Replicator.

Next make an Ubuntu SSO account. Generate SSH keys and upload your SSH keys to your account.

Once written to either boot media start up the TS-4900. Upon first boot there is a configuration tool that must be run to link up with the Ubuntu SSO system. The first boot requires a connection to the serial console in order to work through the configuration steps. It is highly recommended to make an account and upload SSH keys as outlined above before booting up the system the first time. Additionally, we recommend you connect the TS-4900 to a local wired network before running the configuration utility. It is possible to set up a WiFi connection during the configuration stage if desired rather than a wired connection.

When Ubuntu Core is booted on the TS-4900 for the first time, the following prompt will be given on the serial console:

Press Enter to Configure

Ubuntu core has no default username/password, the configuration tool will import the SSH keys to allow login.

Press enter and it will have you confirm DHCP, or use a static network configuration. Once configured it will ask for your Ubuntu SSO username. This will create an account on the Ubuntu Core image and allow access only with your SSH keys present on the store. After it has fetched the keys it will print out the command to connect to your unit which will allow password-less access only from the approved hosts.

Connect to the board with:

ssh <ubuntu SSO username>@<IP of board>
Note: This must be run a host that has been approved through the Ubuntu SSO system. That is, SSH keys created on it and uploaded through the Ubuntu SSO system.

Once connected, a normal linux shell prompt is given. From here, the system can be interacted with. See http://snapcraft.io/ for more information on developing and installing snaps for your application. Custom snaps can be created and uploaded through the Ubuntu snap store. Custom snaps can be made private or public. The Ubuntu SSO system links the previously created account to the http://snapcraft.io/ website, linking everything together.


Note: The first boot of the Ubuntu Core image will modify U-Boot environment. Reverting back to an image that has never been booted will cause U-Boot to error. This can be fixed in U-Boot by running the command "run clearenv" and then rebooting the unit.

Ubuntu Core Reference Links

Yocto

Yocto is our recommended distribution for graphics packages as the software includes patches to support the GPU. X11 in Yocto includes drivers for providing 2D support as well. Support is also provided for OpenGLES 1&2, as well as GStreamer acceleration, included standalone or with Qt. Yocto also provides cross toolchains that include the rootfs. This toolchain allows integration with the Qt Creator IDE and Eclipse.

Yocto does not provide binary security updates. This distribution also does not have any remote repository of pre-built applications. For either of these we features we recommend using Debian.

Our current Yocto support is based off of Yocto 3.0 "Zeus".

Getting Started with Yocto

Yocto itself is a set of scripts and tools used to build a custom distribution. In our default images we try to include all the common utilities requested by users. Rebuilding Yocto should not be necessary for many users, but is possible if needed. See the Custom Build Yocto section for information on this process.


Our Yocto rootfs tarball is available here:

Yocto Download Links
Yocto Image Download Link
ts-x11-image (Yocto Zeus) Download

To write this to an SD card, first partition the SD card to have one large ext3 partition. Most SD cards include one MBR partition by default. Cards can also be partitioned with fdisk, cfdisk, or the graphical gparted utility. This should be an MBR partition table, not GPT. Once it is partitioned, format the SD and extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext3 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -jxf ts-x11-image-tsimx6-latest.rootfs.tar.bz2 -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.

To rewrite the eMMC, boot to the SD card. You cannot rewrite the eMMC while it is mounted elsewhere, or used to currently boot the system. Once booted to the SD, run:

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/yocto/zeus/ts-x11-image-tsimx6-latest.rootfs.tar.bz2 | tar --numeric-owner xj -C /mnt/emmc/
umount /mnt/emmc
sync

The same commands can be used to write SATA by substituting /dev/mmcblk2p1 with /dev/sda1.

First Boot

The stock Yocto image provides a single login of root with no password. With Zeus, the wired ethernet interface will attempt to acquire an IP address via DHCP automatically. However, it is not possible to log in via the network at this time due to security of the device requiring a password for SSH access. Initial login to the device must first be done on the serial console.

Yocto Networking

Our Yocto image uses systemd which stores its network files in /etc/systemd/network/. Yocto will automatically enable DHCP on its wired interfaces. This can be overridden to set a static IP or enable other options for DHCP. The only requirement is that this file is named /etc/systemd/network/XX-wired.network Where "XX" is a number smaller than 80, e.g. /etc/systemd/network/79-wired.network This format must be used for all eth* and en* named network interfaces. The lower file names will take priority.

An example of a static configuration would be:

/etc/systemd/network/42-wired.network

[Match]
Name=eth0

[Network]
Address=192.168.0.50/24
Gateway=192.168.0.1
DNS=192.168.0.1

DNS will be loaded from /etc/resolv.conf. To make this use a static DNS:

rm /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/resolv.conf

To use the DNS assigned by DHCP, run:

ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

For more information on what options are available to configure the network, see the systemd network documentation.

Yocto Wireless

Yocto uses systemd to start wpa_supplicant, and systemd-networkd to set an IP address via a static setting or DHCP.

Scan for a network

ifconfig wlan0 up

# Scan for available networks
iw wlan0 scan

An example of connecting to an open network with an SSID of "default":

BSS c0:ff:ee:c0:ff:ee(on wlan0)
        TSF: 848750528860 usec (9d, 19:45:50)
        freq: 2462
        beacon interval: 100 TUs
        capability: ESS Privacy ShortPreamble ShortSlotTime RadioMeasure (0x1431)
        signal: -69.00 dBm
        last seen: 3253 ms ago
        Information elements from Probe Response frame:
        SSID: default
        Supported rates: 1.0* 2.0* 5.5* 11.0* 6.0* 9.0 12.0* 18.0 
        DS Parameter set: channel 11
        Country: US     Environment: Indoor/Outdoor
                Channels [1 - 11] @ 30 dBm

To connect to this open network manually for just this boot:

iw wlan0 connect "default"

If connecting using WEP, also specify a network key:

iw wlan0 connect "default" keys 0:abcde d:1:0011223344

If connecting to a WPA network use wpa_passphrase and wpa_supplicant:

mkdir /etc/wpa_supplicant/
wpa_passphrase "ssid name" "full passphrase" >> /etc/wpa_supplicant/wpa_supplicant-wlan0.conf

After generating the configuration file the wpa_supplicant daemon can be started.

wpa_supplicant -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant-wlan0.conf -B

This will return output similar to:

 Successfully initialized wpa_supplicant
 root@ts-imx6-q:~# dmesg
 ...
 [  306.924691] wlan0: authenticate with c0:ff:ee:c0:ff:ee
 [  306.959415] wlan0: send auth to c0:ff:ee:c0:ff:ee (try 1/3)
 [  306.968137] wlan0: authenticated
 [  306.978477] wlan0: associate with c0:ff:ee:c0:ff:ee (try 1/3)
 [  306.988577] wlan0: RX AssocResp from c0:ff:ee:c0:ff:ee (capab=0x1431 status=0 aid=9)
 [  307.009751] wlan0: associated
 [  307.012768] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
 [  307.047989] wlcore: Association completed.

Use iw wlan0 info and iw wlan0 station dump to verify the connection. This will also report the link quality to the AP.

Wireless may be associated, but this does not get an IP on the network. To connect to the internet or talk to the internal network first configure the interface. See configuring the network, but on many networks only a DHCP client is needed:

udhcpc -i wlan0

Systemd can also be configured to start wpa_supplicant on boot up.

# Assuming the same path for the wpa conf file as shown above
systemctl enable wpa_supplicant@wlan0
systemctl start wpa_supplicant@wlan0

Once this service is started it will bring up the wlan0 link and associate it to the SSID that is noted in the wpa_supplicant.conf file. Configure the IP settings the same way as a wired network.

In /etc/systemd/network/wlan0.network

[Match]
Name=wlan0

[Network]
DHCP=yes

For a static configuration of IP, the following format may be used:

[Match]
Name=wlan0

[Network]
Address=192.168.0.50/24
Gateway=192.168.0.1
DNS=192.168.0.1

For more information on what options are available to configure the network, see the systemd network documentation.

Yocto Application Development

Yocto provides a cross toolchain including the native tools and required ARM libraries. The cross toolchain is only available for 64bit Linux host PCs. Download the toolchain by saving the following link:

In order to install the toolchain, use the following commands to run the installation script:

chmod a+x poky-*.sh
sudo ./poky-*.sh

In order to use the toolchain, the environment for it must be sourced to the current terminal before it can be used to build applications: To build an application first source the environment for the toolchain:

source /opt/poky/3.0.2/environment-setup-cortexa9t2hf-neon-poky-linux-gnueabi

# This command sets up paths for the shell along with a number of other
# environment variable. For example:
$ echo $CC
arm-poky-linux-gnueabi-gcc -march=armv7-a -marm -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=cortex-a9 --sysroot=/opt/poky/3.0.2/sysroots/cortexa9hf-vfp-neon-poky-linux-gnueabi

# Cross compiling a simple hello world program:
$CC hello.c -o hello

It is also possible to develop applications directly on the device via serial console or ssh. Yocto includes development tools such as vim, gcc, g++, gdb, make, autoconf, binutils, etc. See the next sections for using the cross toolchain with IDEs.

Configure Qt Creator IDE

Note: This guide is intended for our stock Yocto image using systemd. On custom images, the same instructions should apply if a cross toolchain is built. This can be built through Yocto with bitbake meta-toolchain-qt5. Be sure to update the paths if using a different distribution.


Install the qtcreator tool on a host Linux PC. Any recent version from a modern Linux distribution should be sufficient and work without issue. On a Debian/Ubuntu desktop, run:

sudo apt-get update && sudo apt-get install qtcreator -y

The SDK which includes the Qt support will also need to be downloaded. The cross toolchain is only available for 64-bit Linux host PCs:

In order to install the toolchain, use the following commands to run the installation script:

chmod a+x poky-*.sh
sudo ./poky-*.sh

These instructions assume the installation path will be the default at /opt/poky/3.0.2/


Note: An environment script has to be sourced before every execution of qtcreator. Without this, builds will fail.
source /opt/poky/3.0.2/environment-setup-cortexa9t2hf-neon-poky-linux-gnueabi
qtcreator


Qt Creator needs to be configured to build using this toolchain. Once Qt Creator is launched, select Tools->Options->Devices Click Add, select Generic Linux Device, and then click Start Wizard

Qt Device Configuration
Qt Device Configuration

On the next page specify the IP address or hostname of the device running Yocto. In this example, the unit has an IP address of 192.168.2.45 obtained via DHCP. The default Yocto image will use the user root with no password to connect. Set the name to TSIMX6

Qt Device Configuration
Qt Device Configuration

It will then verify connectivity. Click close and continue.

Qt Device Test
Qt Device Test
Note: The paths given in the images below may not match the latest toolchain, but are meant to show where these values would go. Follow the text appropriate to the architecture of your host PC for the correct values


In the left column of the Options menu, select Build & Run. On the Qt Versions tab, click Add in the upper right to configure the TS Kit. Qt Creator may see the qmake binary added to your path from the sourced environment script. If this is detected, add in the string TSIMX6 to the title as shown in the photo below. If it is not autodetected, add the full path and ensure the version name is set to TSIMX6 Qt 5.13.2. This will allow it to be recognized when setting the right binary for the kit.

/opt/poky/3.0.2/sysroots/x86_64-pokysdk-linux/usr/bin/qmake
Qt Versions tab
Qt Versions tab


On the Compilers tab click Add, select GCC then C. Set the Name to TSIMX6 GCC. For the Compiler Path use the following:

/opt/poky/3.0.2/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc

Repeat the above steps for the g++ compiler; click Add, select GCC then C++. Set the name to TSIMX6 G++. And for the Compiler Path use the following:

/opt/poky/3.0.2/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++
Qt Compiler tab
Qt Compiler tab

On the Debuggers tab click Add. For name, specify TSIMX6 GDB. For the path, specify the location of gdb with the following:

/opt/poky/3.0.2/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gdb
Qt Debugger tab
Qt Debugger tab

On the Kits tab click Add. For Name, enter TSIMX6. Set device type to Generic Linux Device. Set the device to TSIMX6 (default for Generic Linux). Set Qt mkspec to the following (make sure there is no space at the end):

/opt/poky/3.0.2/sysroots/cortexa9t2hf-neon-poky-linux-gnueabi/usr/lib/mkspecs/linux-oe-g++


Set C Compiler to TSIMX6 GCC and C++ Compiler to TSIMX6 G++. Set Debugger to TSIMX6 GDB. Set the Qt version to TSIMX6 QT 5.13.2. Finally, click Apply.

Qt Kit tab
Qt Kit tab
Note: If there is a red exclamation point over the kits icon, it indicates that the compiler ABI does not match. In this case, you will need to revisit the "Compiler", "Debugger", and "Qt Versions" tabs, and browse the host PC for these files manually rather than copy/pasting the paths from these instructions. This is a bug in Ubuntu 16.04's Qt Creator, and may be in later versions as well.

At this point Qt Creator is set up to begin a hello world project.

Qt Creator Hello World

Open the Qt Creator IDE and click New Project.

Qt New Project
Qt New Project

Qt provides multiple templates for application development. For this example select the default Qt Widgets Application.

Qt Widgets App
Qt Widgets App

Specify the location for your project. Keep in mind that the compile process will create more build paths in the Create In: path.

Qt Location
Qt Location

Next, select the kit. The TSIMX6 is the kit we set up in the last section, but you may have other kits pre-installed on your system. These can be used for testing graphical development on your PC. Keep in mind distribution versions may contain different functionality.

Qt Select Kit
Qt Select Kit

Next select the class and filename information. This example will use the defaults.

Qt Select Classes
Qt Select Classes

Select any version control for the project. The example will use none and finish the wizard. This will generate the new project.

Qt Project Management
Qt Project Management

Click the button under Help on the left column, and select TSIMX6 debug. If there is only one kit selected, this will be default.

Qt Select build
Qt Select build

Now return to edit, and open the Qt project file, qt5-helloworld.pro. Add in these lines anywhere after the target is specified:

linux-* {
    target.path = /home/root
    INSTALLS += target
}
Qt pro file
Qt pro file

Last, the DISPLAY must be selected. This is done by setting a run environment variable that will be set when the application is run on the board.

Qt run environment settings
Qt run environment settings

At this point click the green allow in the bottom left to run the application. This can also be launched from the menu at Build->Run.

Qt Build and Deploy
Qt Build and Deploy

From here, you can begin customizing your application. Refer to the official Qt documentation for more information

Yocto Hide Cursor

The default image includes the xcursor-transparent icon theme. This can hide the mouse pointer. To enable this, run these commands:

mkdir -p ~/.icons/default/

echo "[Icon Theme]" > ~/.icons/default/index.theme
echo "Inherits=xcursor-transparent" >> ~/.icons/default/index.theme

# Now reset x, or reset the unit and the cursor will be invisible.

Yocto Startup Scripts

To have a custom headless application start up at boot a systemd service needs to be created. Create the file /etc/systemd/system/yourapp.service with contents similar to below:

[Unit]
Description=Run an application on the i.MX6

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

[Install]
WantedBy=multi-user.target

If an application depends on networking, the systemd script will want to have After=network.target in the Unit section. Once this file is in place, it can be added to automatic startup with the following:

# Enable the application to be started on boot up
systemctl enable yourapp.service

# Start the application now, but will not affect automatic startup
systemctl start yourapp.service
Note: See the systemd documentation for in depth documentation on services.

To set up a graphical application startup, modify the /usr/bin/mini-x-session file

At the end of the script replace matchbox-terminal with the desired application (absolute path may need to be specified):

matchbox-terminal &
exec matchbox-window-manager

The exec statement must be last in the script in order to take over this script's PID for correct operation.

Custom Build Yocto

If our stock Yocto distribution does not meet all of your needs, it is possible to re-build it with a custom set of features. Including less options for a smaller footprint, or more packages to add more features.

While we may provide guidance, our free support does not include every situation that can cause a build failure in generating custom images.

QNX

QNX is an RTOS that supports the i.MX6 CPU. We provide a BSP for the TS-4900 and TS-7970 quad core or solo based on QNX Neutrino 6.6.0. The supporting files are available here:

We provide support for booting QNX on our platforms, but further support is provided by QNX

Known Working:

  • UARTs 1-5
  • Ethernet
  • I2C 1, I2C 2
  • SD (/dev/hd0)
  • eMMC (/dev/emmc0)
  • USB Host
  • SPI NOR (/dev/fs0)
  • HDMI (TS-7970 only)
  • LCD Interface (TS-TPC-8390 with TS-4900 only)
  • RS485

Known not working:

  • WIFI
  • FPGA based UARTs

Not yet tested:

  • I210 (Second gig eth)

QNX BSP

Before compiling QNX be sure to edit the file: src/hardware/startup/boards/imx6x/ts7970/board.h Set either BOARD_TS7970 or BOARD_TS4900 depending on the target board.

We have also included a port of tshwctl which is used to access the FPGA. This allows you to read/write FPGA registers and to change the crossbar. For example, to set up auto TXEN on the TS-7970 RS-485 port (/dev/ser4):

export MB_TXD=TTYSER4_TXD
export TTYMAX1_RXD=GPIO
export TTYSER4_RXD=MB_RXD_485
export TXD_232_COM=GPIO
export MB_TX_EN_485=TTYSER4_TXEN
tshwctl -b 0x7970 -s

tshwctl -b 0x7970 -c

This will print out the modified state of the crossbar. The relevant pins are now:

  TTYSER4_RXD ( in) (  0) MB_RXD_485  
       MB_TXD ( in) (  0) TTYSER4_TXD
 MB_TX_EN_485 ( in) (  0) TTYSER4_TXEN                                          
  TTYMAX1_RXD ( in) (  0) GPIO                                                  
  TXD_232_COM ( in) (  0) GPIO   

Use tshwctl to specify the baud rate and mode of the uart so the TX enable pin will be automatically toggled.

tshwctl -b 0x7970 -a 4 -x 115200 -i 8n1

/dev/ser4 is now configured for RS485 traffic.

QNX Booting

Write the example image to a disk.

bzip2 -d ts7970-qnx-6.6.0-20150707.dd.bz2

#Replace sdx with your device.  Try lsblk to find your SD card.
sudo dd if=ts7970-qnx-6.6.0-20150707.dd bs=4M of=/dev/sdx
sync

Reinsert or partprobe the disk, and there will be a single partition present. The partition includes the QNX IFS, and a u-boot script. On startup the imx6 is configured to launch the hush script. If present, at /boot/boot.ub on either the SD or eMMC depending on if the SD boot jumper is present. The script loads the FPGA, then copies the QNX ifs into memory and jumps into it to begin execution.

Android

This Android distribution is based off of Freescale's port of AOSP to the i.MX6 platform. This allows users to run existing APKs to use this platform with no modifications, or develop new projects using Android Studio.

Getting Started with Android

Android must be run from the eMMC. This can be written with the USB production tool, or from the SD card. To use the USB drive, follow the instructions here, and download the image and copy it to the USB drive as emmcimage.dd.bz2.

Download the Android image here:

To load from the SD card, boot up to any Linux distribution from the SD card such as the default Yocto. Once booted here, run:

wget -qO- ftp://ftp.embeddedTS.com/ts-arm-sbc/ts-7990-linux\
/distributions/android/android-7.1.1-tsimx6-tiwifi-\
latest.dd.bz2 | bzcat | dd bs=4M of=/dev/mmcblk2 conv=fsync

This will download it, decompress it, and write it to the eMMC drive. Reboot and boot into Android.

Android Networking

On startup android will automatically start dhcpcd on eth0, or WIFI can be configured via the Settings->Wi-Fi menu.

Android Software Development

AOSP development works exactly the same as on an Android phone, except the Google APIs associated with the store are not available. See The android documentation for getting started on development: http://developer.android.com/training/basics/firstapp/index.html

Android Manually Install APK

APKs can be installed just like on any other Android device. On the device go to settings->About Tablet and press the "build number" until the text states "You are now a developer". Go back to Settings and there is now a "Developer Options" menu. Under Debugging enable USB Debugging. You should now be able to run adb commands to install apk files.

adb install </path/to/app.apk>

Backup / Restore

While all of our products ship with images pre-loaded in to any supplied media, there are many situations where new images may need to be written. For example, to restore a device to its factory settings or apply a customized image/filesytem for application deployment. Additionally, specific units may be used for development and that unit's disk images need to be replicated to other units to be deployed in the field.

We offer a number of different ways to accomplish both capturing images to be written to other units, and the actual writing process itself. See the sections below for details on our USB Image Replicator tool to capture and/or write images, as well as details on manual processes to capture and write images on each of this device's media.


Image Replicator

This platform supports our Image Replicator tool. The Image Replicator tool is intended for use by developers as a means to write bootable images or filesystems on to a device's media (SD / eMMC / SATA / etc.) as part of their production or preparation process. In addition to writing media, the Image Replicator tool is capable of capturing images from a device's media and preparing them to be written to other devices.

The Image Replicator tool is a USB disk image that can be booted on a target device to capture or write its media directly without the need for a host workstation. The USB disk image is based on Buildroot and contains a set of scripts which handle the capture and write process. The process and its scripts are flexible and can be used as-is or adapted in to larger production processes to format and load data on to devices. The single USB drive can be used to capture images from a device, and then can be inserted in to other devices to write those same images on to other devices. The capture process is not necessary if it is not needed. Images for the target device can be copied to the USB drive, booted on compatible units, and have the target images written to that unit's media.


Image Capture Process

The image capture process performs the following steps. For more detailed information, see the Image Capture section below.

  1. If no valid images exist on the disk, image capture starts.
  2. For each valid media present on the unit, a bit for bit copy of the source is made.
  3. This image is mounted, sanitized (to remove unneeded files and allow safe copying of the image to other units), and saved as either a disk image or a tarball depending on the partition layout of the source disk.
  4. All images and tarballs are compressed, with both the output files having their MD5 hash saved as well as all of the files contained in the root partition having their MD5 hashes saved to a file for later verification.

The captured images and tarballs are named such that the USB Image Replicator disk can be immediately used to boot another unit and have it perform the Image Write process to write that unit's media with the captured images.

Note: When using this process, the USB drive used for the Image Replicator must be sized large enough to handle multiple compressed images as well as the uncompressed copy of the media image actively being worked with. If the image capture process runs out of space, the process will indicate a failure.


Image Write Process

The image write process performs the following steps. For more details information see the Image Write section below.

  1. For each valid media present on the unit, find the first valid source image file for it.
  2. If a source image exists for a media that is not present on the unit, then the process indicates a failure.
  3. If the source image is a tarball, format the target disk with an appropriate filesystem, and unpack it to the target disk, verifying all files against the MD5 hash file list after they are written.
  4. If the source image is a disk image, write that to the target disk. If an MD5 file for the disk image exists, read back the written disk and compare it to the hash.


Creating a USB Image Replicator Disk

Image Replicator USB disk images can be found below:

Disk image: tsimx6-usb-image-replicator.dd.xz

Tarball: tsimx6-usb-image-replicator-rootfs.tar.xz

Two types of USB Image Replicator images are available for this platform, a tarball and an actual disk image. They both have the same contents and are intended to provide different methods to write the Image Replicator tool to a USB disk.

Disk Image (.dd.xz)
The disk image is easier to write from different workstation OSs, will auto-expand to the full disk length on its first boot, and is intended to be used for image capture (and later image writing) due to its small size and auto-expansion process. We recommend this route for users who may not have access to a Linux workstation or need to capture images from a golden unit first.
Tarball Image (.tar.xz)
The tarball image is easiest to write from a Linux workstation, but requires creating a partition table on the USB disk (if one does not already exist), formatting the filesystem, and unpacking the tarball. It can readily be used for for both image capture and writing, but is the easiest route when image capture is not needed due to the auto-expansion process.


Note: It is recommended to use USB drives with solid-state media for this process. Slower USB drives, especially those with spinning media, may take too long to enumerate and the bootloader will not boot the Image Replicator disk. Additionally, the use of low quality, damaged, and/or worn out USB drives may cause unexpected errors that appear unrelated to the USB drive itself. If there are issues using the Image Replicator, we recommend first trying a new, fresh, high-quality USB drive from a trusted named brand.


Disk Image

This process uses a small disk image that can be written to a USB device. This disk image uses an ext3 filesystem which expands on its first boot to the full length of the disk before beginning the image capture process. This disk is recommended for users who may not have access to a Linux workstation or who need to capture images from a golden unit.

It is possible to use the disk image for just image writing, however, in order to ensure full disk space is available it is recommended to write the disk image to a USB drive, boot it on a unit, let the image capture process complete, insert the USB drive in to a workstation, and then remove the captured image files before copying in the desired image files for the target unit from the workstation.


Writing Disk Image From a Linux Workstation

The disk image can be written via the command line with the dd command (replace /dev/sdX with the correct USB device node):

xzcat <platform>-usb-image-replicator.dd.xz | dd of=/dev/sdX bs=1M conv=fsync

Graphical tools also exist for this purpose, for example balenaEtcher[1] offers this functionality.


Writing Disk Image From a Windows Workstation

A number of tools exist for writing an image to a USB drive, including (but not limited to) balenaEtcher[1] and Win32DiskImager[2]


Writing Disk Image From a MacOS Workstation

We recommend using a tool such as balenaEtcher[1] to write disk images.


  1. 1.0 1.1 1.2 embeddedTS is not affiliated with this tool. balenaEtcher version 1.5.101 tested in Windows 10 on 20220216
  2. embeddedTS is not affiliated with this tool. Win32DiskImager 1.0.0 tested in Windows 10 on 20220216. Cannot handle compressed images, must first decompress disk image.


Tarball

This process is easiest on a Linux workstation, but can be performs on other operating systems as well so long as they can support a compatible filesystem, the xz compression algorithm, as well as the tarball archive format. Note that in many cases, one of our computing platforms running our stock Linux image can be used if a Linux workstation is not available. After writing the tarball to a USB disk, the full length of the USB disk would be available to copy source images to in order to write them to other units.

The image replicator and scripts require a minimum of 50 MB; this plus the size of any target disk images or tarballs to be used dictates the minimum USB disk size required. The USB drive should have only a single partition, which is formatted ext2[1] / 3 / 4[2] or FAT32/vfat[3] Note that other filesystems are not compatible with U-Boot and therefore cannot be used.


Writing Tarball From a Linux Workstation

# This assumes USB drive is /dev/sdc:
sudo mkfs.ext3 /dev/sdc1
sudo mkdir /mnt/usb/
sudo mount /dev/sdc1 /mnt/usb/
sudo tar --numeric-owner -xf /path/to/<platform>-usb-image-replicator-rootfs.tar.xz -C /mnt/usb/
sudo umount /mnt/usb/


Writing Tarball From a Windows Workstation

It is recommended to use a third party tool, as native Windows archive tools have been observed to not work correctly. Tools such as 7-Zip[4] or PeaZip[5] are known working. It may also be possible to use Windows Subsystem for Linux following the Linux Workstation instructions above, but this has not been tested.

Note that some Windows tools may attempt to use the whole disk, rather than create a partition table. A partition table with a single partition is required for U-Boot support.

With a formatted USB disk, the archive can be unpacked to the root folder of the USB disk. Be sure to not unpack the tarball contents in to a new folder on the drive as this will not be bootable.


  1. The ext2 filesystem has a max file size limit as low at 16 GiB. This may cause issues for Image Capture.
  2. Use of ext4 may require additional options. U-Boot on some platforms does not support the 64-bit 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 may need to be used with ext4 for proper compatibility. Older versions of e2fsprogs do not need these options passed, nor are they needed for ext2 / 3.
  3. The FAT32 (supported by vfat in Linux) filesystem has a max file size limit of 4 GiB. This may cause issues for Image Capture.
  4. embeddedTS is not affiliated with this tool. 7-Zip 21.07 tested in Windows 10 on 20220222
  5. embeddedTS is not affiliated with this tool. PeaZip 7.2.0 tested in Windows 10 on 20220222


Running the Image Replicator Tool

On startup if SW1 is depressed before power is applied and held for a few moments after, then TS-7970's U-Boot will attempt to located a file called /tsinit.ub on a USB drive. If found, it will copy this file to memory at ${loadaddr} and then execute source ${loadaddr} to run this U-Boot script. This is the mechanism used to boot either of the two disk images on the TS-7970.

Once a USB drive is formatted with the Image Replicator tool (see Creating a USB Image Replicator Disk for the correct files and process), boot to this USB drive (note that the Image Replicator already sets up the correct U-Boot boot scripts to boot to the USB drive, see the aforementioned section for details on how to make U-Boot call the scripts on the USB drive). This will start either image capture if no disk images/tarballs are present on the USB drive, or image write if there are disk images/tarballs present on the USB drive.

The Image Replicator tool, while in progress, will flash the green LED once per second while the red LED remains solidly lit. Upon completion, the red LED turns off and the green LED will slowly blink to indicate success, while a blinking red LED with the green LED off indicates a failure.

On each boot, startup scripts will check if the single partition of the USB drive can be expanded and do so if possible. If this process fails, then any further operations will not be run and the LEDs will blink to indicate a failure.


Image Capture

If no valid images to write exist on the booted USB Image Replicator drive, the image capture process starts automatically.

Note that while in progress, the USB Image Replicator drive is mounted read-write. It is not advised to remove power or disconnect the USB Image Replicator drive until the whole process has completed.

To help diagnose failures, files in /tmp/logs/ contain output from each capture process.

For each media present on the unit (SD / eMMC / SATA / etc.), the image capture process will do the following:

  1. Copy the entire media image to an appropriately named file on the USB Image Replicator drive, e.g. sdimage.dd. No data is written to the source media and it is never mounted. The source disk can follow the stock partition layout, or implement a customized one.
  2. Perform an fsck on the Linux rootfs partition in the image file. Note that, if deviating from the standard partition layout, it may be necessary to modify the scripts handling the capture process.
  3. Mount the Linux rootfs partition from the image file and sanitize the filesystem. The sanitization process removes temporary files (e.g. /log/ files), unique files (e.g. ssh private key files, machine ID files), adds a file to indicate that it is a custom image with the date as its contents, etc. The full list of operations can be found in this script. It may be necessary to modify this file for unique situations.
  4. If the media's partition layout uses only a single partition, the filesystem is packed in to a tarball on the USB Image Replicator drive which is appropriately named and compressed, e.g. sdimage.tar.xz. The image file is then unmounted and removed from the USB Image Replicator drive.
  5. If the media's partition layout uses multiple partitions, the image file is then unmounted, an md5sum of the image file taken, it is compressed and appropriately named on the USB Image Replicator drive, e.g. emmcimage.dd.xz, and then an md5sum of the compressed image is taken.

Note that when using this process, the USB Image Replicator drive that is used must be sized large enough to handle multiple compressed images as well as the uncompressed copy of the media image actively being worked with. If the image capture process runs out of space, the process will indicate a failure via the LEDs.

The images files captured are saved to the root folder of the USB Image Replicator drive. Upon completion, it is safe to remove power or unplug the USB drive.

For more details on the image capture process, see this script.


Image Write

This process is used to write existing images to media on a target unit. If appropriately named disk images or tarballs (see table below) are present in the root folder of the USB Image Replicator drive when booted, then the startup scripts will start the image writing process. The latest disk images we provide for our platforms can be downloaded from our FTP site, see the backup and restore section for links to these files.

Note that the USB Image Replicator drive remains read-only through the entire process but target devices may be mounted or actively written. It is not advised to remove power or disconnect the USB Image Replicator drive until the whole process has completed.

To help diagnose failures, files in /tmp/logs/ contain output from each writing process.

The Image Replicator script expects disk images or tarballs to have specific names to match the target media. The script will attempt to match tarball and then disk image names (in the order they are listed in the table below) for each target media, using the first file that is found to write to the target media. Note that symlinks can be used on the USB Image Replicator disk if formatted with a filesystem that supports symlinks. This can be used, for example, to write the same tarball to both SD and eMMC from only a single copy of the source tarball.

Upon completion, it is safe to remove power or unplug the USB drive.

For more details on the image write process, see this script.

The following table is the list of valid file names and how they are processed:

Target media Accepted filenames Description
SD Card

/sdimage.tar.xz

/sdimage.tar.bz2

/sdimage.tar.gz

/sdimage.tar

Tar of the filesystem. This will repartition the SD card to a single partition and extract this tarball to the filesystem. If present, a file named /md5sums.txt in the tarball will have its contents checked against the whole filesystem after the tarball is extracted. This md5sums.txt file is optional and can be omitted, but it must not be blank if present. This file is present in our official images and is created during image capture with the Image Replicator tool.

/sdimage.dd.xz

/sdimage.dd.bz2

/sdimage.dd.gz

/sdimage.dd

Disk image of the media. This will be written to the SD card block device directly. If present on the USB Image Replicator drive, a file named /sdimage.dd.md5 will be used to verify the data written to the SD card against this checksum. This file is provided with our official images and is created during image capture with the Image Replicator tool.
eMMC

/emmcimage.tar.xz

/emmcimage.tar.bz2

/emmcimage.tar.gz

/emmcimage.tar

Tar of the filesystem. This will repartition the eMMC to a single partition and extract this tarball to the filesystem. If present, a file named /md5sums.txt in the tarball will have its contents checked against the whole filesystem after the tarball is extracted. This md5sums.txt file is optional and can be omitted, but it must not be blank if present. This file is present in our official images and is created during image capture with the Image Replicator tool.

/emmcimage.dd.xz

/emmcimage.dd.bz2

/emmcimage.dd.gz

/emmcimage.dd

Disk image of the media. This will be written to the eMMC block device directly. If present on the USB Image Replicator drive, a file named /emmcimage.dd.md5 will be used to verify the data written to the SD card against this checksum. This file is provided with our official images and is created during image capture with the Image Replicator tool.
SATA

/sataimage.tar.xz

/sataimage.tar.bz2

/sataimage.tar.gz

/sataimage.tar

Tar of the filesystem. This will repartition the first SATA drive with a single partition and extract this tarball to the filesystem. If present, a file named /md5sums.txt in the tarball will have its contents checked against the whole filesystem after the tarball is extracted. This md5sums.txt file is optional and can be omitted, but it must not be blank if present. This file is present in our official images and is created during image capture with the Image Replicator tool.

/sataimage.dd.xz

/sataimage.dd.bz2

/sataimage.dd.gz

/sataimage.dd

Disk image of the media. This will be written to the first SATA block device directly. If present on the USB Image Replicator drive, a file named /sataimage.dd.md5 will be used to verify the data written to the SD card against this checksum. This file is provided with our official images and is created during image capture with the Image Replicator tool.
U-Boot

/u-boot.imx

U-Boot binary blob. This will be written to the SPI flash. The imx_type variable of the new file and the existing U-Boot installation on SPI flash will be checked to ensure the file being written is compatible with the current CPU. If the file /u-boot.imx.md5 is present on the USB drive, this will be used to verify the data written to SPI flash.
Note: SATA is only present on models with Dual/Quad CPUs


Building the Image Replicator from Source

The Image Replicator tool uses Buildroot to create the bootable USB disk image and tarball. See the project repository on github for information on compatibility and instructions on building: https://github.com/embeddedTS/buildroot-ts

MicroSD Card

Note: Our Image Replicator tool can be used to automate this process.


These instructions assume you have an SD card with one partition. Most SD cards ship this way by default. If the card has had its partition table modified this can be corrected with a tool like 'gparted' or 'fdisk'.

Plug the SD card into a USB reader and connect it to a linux workstation PC. Newer distributions include a utility called 'lsblk' which lists all block devices like a USB SD card reader:

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. Note that on your system, sdX will not be 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.

After plugging in the device after Linux has booted you can use dmesg to print out the kernel log. When the USB drive is added it will append to the end of that file. Try running:

dmesg | tail -n 100
 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)

Make sure the partition table is using the MBR scheme and not GPT.

In this case, sdXc is shown as a 3.97GB card. Note that on your system, sdX will not be 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 following commands will reformat the first partition of the SD card, and unpack the latest filesystem on there:

# Verify nothing else has this mounted
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-4900-linux/distributions/debian/debian-armhf-bullseye-latest.tar.bz2

sudo tar --numeric-owner -xf debian-armhf-bullseye-latest.tar.bz2 -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.

Once written, the files on disk can be verified to ensure they are the same as the source files in the archive. Reinsert the disk to flush the block cache completely, then run the following commands:

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

The md5sum command will report what differences there are, if any, and return if it passed or failed.

eMMC

Note: Our Image Replicator tool can be used to automate this process.


Write the image:

These commands assume the unit is booted from SD and eMMC is set up with a single partition:

# Verify nothing else has this mounted
umount /dev/mmcblk2p1

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/distributions/debian/debian-armhf-bullseye-latest.tar.bz2
tar --numeric-owner -xf debian-armhf-bullseye-latest.tar.bz2 -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.

After the tarball is unpacked, the data on disk can be verified with md5sum:

# Drop any block cache
echo 3 > /proc/sys/vm/drop_caches
mount /dev/mmcblk2p1 /mnt/emmc
cd /mnt/emmc/
sudo md5sum -c md5sums.txt
umount /mnt/emmc
sync

The md5sum command will report what differences there are, if any, and return if it passed or failed.

Backup the image:

First boot the device to any compatible bootable SD card. The SD needs have enough free space for the compressed image of the data on the eMMC. Our default image eMMC image is ~500MB when compressed. A tarball of the eMMC can be created on the SD card with the following commands:

mkdir /mnt/emmc/
mount /dev/mmcblk2p1 /mnt/emmc/
cd /mnt/emmc/
tar --numeric-owner -cjf /root/emmc-backup.tar.bz2 *
cd /
umount /mnt/emmc/

Compile the Kernel

To add additional driver support, reduce the size of our stock kernel kernel, or to write custom kernel drivers the kernel can be compiled from our sources. The following steps walk through the kernel build process; they are compatible with most of our Linux distributions.

This device has multiple kernels released and available in our git repository:

Newer kernels are released on the linux-tsimx repository:

  • embeddedTS/linux-tsimx
  • The "ts-imx_4.9.11_1.0.0_ga" branch is the only one that should be used with our i.MX6 series.

For legacy kernels:

  • embeddedTS/linux-3.10.17-imx6
  • The "master" branch is 3.10.17 and is largely outdated and replaced with later kernels. This is used with the old Yocto Dora builds.
  • The "imx_3.10.53_1.1.0_ga" kernel is a stable branch. Use this with Yocto Dizzy, Fido, or compatible with Debian Jessie.
  • The "imx_3.14.52_1.1.0_ga" branch is compatible with Yocto Jethro, and Debian.
  • The "imx_4.1.15_1.0.0_ga" branch is compatible with Yocto Jethro, Yocto Morty and Debian. Includes recent fixes not in older branches. This is recommended for most users.

The kernel can be rebuilt by cross compiling from an x86 or x86_64 Linux workstation. Our stock kernels are built with the toolchains built by Yocto. The appropriate cross toolchain for your Linux workstation can be downloaded here:

Note: Older kernels will require older toolchains. For older Yocto kernels use a matching Yocto toolchain. For Debian, the latest toolchain and kernel is recommended.
chmod a+x poky*.sh
sudo ./poky*.sh

This will ask for the install directory for the toolchain. A custom location can be chosen, however the following instructions will assume the default installation location.

This process will also require several applications for the install/build process. These can be installed on an Ubuntu/Debian workstation with the following command:

sudo apt-get install git build-essential lzop u-boot-tools libncursesw5-dev fakeroot bc

Once those are installed:

git clone https://github.com/embeddedTS/linux-tsimx.git -b ts-imx_4.9.11_1.0.0_ga linux-tsimx6 --depth 1

# For legacy kernels instead:
# git clone https://github.com/embeddedTS/linux-3.10.17-imx6.git -b imx_4.1.15_1.0.0_ga linux-tsimx6 --depth 1
# If it is already cloned, the "git pull" command will download and merge the latest changes

# For WiFi support, download qcacld-2.0:
# This is only compatible with 4.1.15 or 4.9.11 kernels
git clone https://github.com/embeddedTS/qcacld-2.0.git -b caf-wlan/CNSS.LEA.NRT_3.1

cd linux-tsimx6
# These export commands must be run every time before any make commands
export ARCH=arm
# For 64-bit
export CROSS_COMPILE=/opt/poky/2.2.2/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-
# For 32-bit
#export CROSS_COMPILE=/opt/poky/2.2.2/sysroots/i686-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-
export LOADADDR=0x10008000
export TEMPDIR=$(mktemp -d)

make ts4900_defconfig

## Make any changes in "make menuconfig" or driver modifications, then compile
make -j8 all uImage zImage

mkdir "$TEMPDIR"/boot/
cp arch/arm/boot/uImage  "$TEMPDIR"/boot/uImage
cp arch/arm/boot/zImage  "$TEMPDIR"/boot/zImage
cp arch/arm/boot/dts/imx6*-ts*.dtb "$TEMPDIR"/boot/
INSTALL_MOD_PATH="$TEMPDIR" make modules_install
make headers_install INSTALL_HDR_PATH="$TEMPDIR"

# Compile wifi driver:
cd ../qcacld-2.0/
export KERNEL_SRC="../linux-tsimx6/"
make clean
CONFIG_CLD_HL_SDIO_CORE=y make -j8
INSTALL_MOD_PATH="$TEMPDIR" make modules_install 

fakeroot sh -c "chmod 755 $TEMPDIR;
	chown -R root:root $TEMPDIR;
	tar cjvf kernel.tar.bz2 -C $TEMPDIR .;
	rm -rvf $TEMPDIR"

This will generate "kernel.tar.bz2" which contains the kernel and necessary modules. It can be installed to the device by copying it to a running unit and executing:

# Only run this on a device! Not on a workstation!
tar -xf kernel.tar.bz2 -C /

This can also be extracted over existing images from a workstation, or removable media like SD cards. For example, assuming the SD card on a workstation is "/dev/sdc":

mkdir /mnt/sd/
mount /dev/sdc1 /mnt/sd/
tar -xf kernel.tar.bz2 -C /mnt/sd/
umount /mnt/sd/

Change Kernel Splash Screen

The kernel splashscreen allow for a 224 color image, up to the full screen resolution. For the fastest boot speed, it should be kept as small as possible. The image will be centered around a black background.

To convert an image, for example, "mylogo.png":

convert mylogo.png mylogo.ppm
ppmquant 224 mylogo.ppm > mylogo-224.ppm
pnmnoraw mylogo-224.ppm > logo_user_clut224.ppm
cp logo_user_clut224.ppm <kernel build sources>/drivers/video/logo/

Recompile the kernel following the guide in the previous section to have the splashscreen appear on all future boots.

Add to the kernel cmdline in U-Boot, "logo.nologo" in order to completely disable the splash screen.


Linux 5.10.y

A compatible armhf cross compiler is needed for building the 5.10 kernel. We recommend using the cross compiler available in Debian distributions. 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

If using our instructions for using Docker to handle the cross compiler, then the Docker environment needs to be entered first:

# Create a place to store the kernel:
mkdir -p ~/Projects/tsimx6/kernel/
cd ~/Projects/tsimx6/kernel/
docker run -it --volume $(pwd):/work armhf-bullseye-toolchain bash

# Once in the Docker container shell, run:
cd /work/


If the Docker container is not being used, a number of host tools are required to be installed on the workstation:

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

# Do a shallow clone of the sources
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, the U-Boot kernel address, 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 LOADADDR=0x10008000
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 -b linux4microchip-2021.10-1 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 tsimx6_defconfig

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


Build and Install

Note: If using the Docker container to cross compile, be sure to exit the container after the build script below completes! The tarball will be located in the linux-lts/ folder that was created.

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
find arch/arm/boot/dts -name "*ts*.dtb" -exec cp {} "${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.


Linux 6.6.y

A compatible armhf cross compiler is needed for building the 6.6 kernel. We recommend using the cross compiler available in Debian distributions. 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

If using our instructions for using Docker to handle the cross compiler, then the Docker environment needs to be entered first:

# Create a place to store the kernel:
mkdir -p ~/Projects/tsimx6/kernel/
cd ~/Projects/tsimx6/kernel/
docker run -it --volume $(pwd):/work armhf-bullseye-toolchain bash

# Once in the Docker container shell, run:
cd /work/


If the Docker container is not being used, a number of host tools are required to be installed on the workstation:

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

# Do a shallow clone of the sources
git clone --depth 1 -b linux-6.6.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, the U-Boot kernel address, 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 LOADADDR=0x10008000
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 -b linux4microchip-2024.04 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 tsimx6_defconfig

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


Build and Install

Note: If using the Docker container to cross compile, be sure to exit the container after the build script below completes! The tarball will be located in the linux-lts/ folder that was created.

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
find arch/arm/boot/dts -name "*ts*.dtb" -exec cp {} "${TEMPDIR}/boot" \;

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

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

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

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

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


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

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

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


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

Features

ADC

The TS-7970 includes 3x 10-bit ADC channels designed for 4-20 mA current loop measurements; they are not able be configured for direct voltage measurement. These channels are updated roughly twice per second. These are accessed using the tsmicroctl utility:

root@ts-imx6:# tsmicroctl --info
VDD_ARM_CAP=1216
VDD_HIGH_CAP=2618
VDD_SOC_CAP=1246
VDD_ARM=1456
SILAB_P10=0x39B
SILAB_P11=0x0
SILAB_P12=0x0
VIN=12241
V5_A=5207
V3P1=3276
DDR_1P5V=1571
V1P8=1894
V1P2=1262
RAM_VREF=783
V3P3=3543
SILABREV=1
SILAB_P10_UA=21472
SILAB_P11_UA=0
SILAB_P12_UA=0

The other samples are the various voltages on the board. The current loop values measured by the ADC are "SILAB_P10", "SILAB_P11", and "SILAB_P12". Those are the raw ADC values whereas the channel names with "_UA" appended to them are the converted micro-amp reading of the current loop.

Bluetooth

On the REV F TS-7970s the end of life TIWI-BLE module has been replaced with the Silex SX-SDMAC2832S+.

SILEX Bluetooth

Support for Bluetooth is provided by the BlueZ project. BlueZ has support for many different profiles for HID, A2DP, and many more. Refer to the BlueZ documentation for more information. Please see our BLE Examples page for information on installing the latest BlueZ release, getting started, and using demo applications.

First load the driver in bluez. For 5.10 and later, run:

btattach -P qca -S 115200 -B /dev/ttymxc1 &

For kernel 4.9 and below, run:

echo 27 > /sys/class/gpio/export
echo low > /sys/class/gpio/gpio27/direction
sleep .5
echo high > /sys/class/gpio/gpio27/direction
hciattach /dev/ttymxc1 qca 115200 -t30 flow

Either will create an hci0 interface that can interface with bluez. For example, to scan devices use blutoothctl commands power on and scan on.

root@tsimx6:~# bluetoothctl
Agent registered
[CHG] Controller 84:25:3F:B6:1C:4D Pairable: yes
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
[CHG] Controller 84:25:3F:B6:1C:4D Discovering: yes
[NEW] Device 19:CD:41:6B:AC:09 19-CD-41-6B-AC-09

TI Bluetooth

The Wi-Fi option for the device also includes a Bluetooth 4.0 LE module. Support for Bluetooth is provided by the BlueZ project. BlueZ has support for many different profiles for HID, A2DP, and many more. Refer to the BlueZ documentation for more information. Please see our BLE Examples page for information on installing the latest BlueZ release, getting started, and using demo applications.

To connect this to 'bluez' the Bluetooth device needs to be initialized and set up. The "BT_EN" pin needs to be pulsed, then 'hciattach' is used to connect to the device and set it up as an HCI interface:

# Install bluez if it is not already present
apt-get update
apt-get install bluez bluez-tools

# Loads firmware for the wifi+BT module
ifconfig wlan0 up

tshwctl --addr 16 --poke 0x3 # Turn on BT_CTS
tshwctl --addr 2 --poke 0x3 # Turn on UART2_RTS
echo 237 > /sys/class/gpio/export
echo low > /sys/class/gpio/gpio237/direction
echo high > /sys/class/gpio/gpio237/direction
sleep .1
hciattach /dev/ttymxc1 texas 3000000
hciconfig hci0 up

Once this is loaded, it is possible to scan for nearby devices:

hcitool scan

This will return a list of devices such as:

	14:74:11:A1:1E:C9	BlackBerry 8530

Bluez has support for many different profiles for HID, A2DP, and many more. Refer to the Bluez documentation for more information.

CAN

The TS-7970 CAN ports are located on the COM2 Header and the Terminal Blocks.

The i.MX6 includes 2 CAN controllers which support the SocketCAN interface. Before proceeding with the examples, see the Kernel's CAN documentation here.

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

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

## Dump data & errors:
candump can0 &

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

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

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

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

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

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

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

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

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

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

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

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

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

ip link set can0 type can restart-ms 100

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

CPU

The i.MX6 is an armv7a Cortex-A9 by NXP. The CPU itself is available in 792MHz, 996MHz, and 1.2GHz with a solo, dual, or quad core processor.

Refer to NXP's documentation for in depth documentation on these CPU cores:

eMMC

This board includes a Micron eMMC module with builds that have "4096F" in the part number. Our off the shelf builds are 4GiB, but up to 64GiB are available for larger builds. The eMMC flash appears to Linux as an SD card at /dev/mmcblk2. Our default programming will include one partition programmed with our Yocto image.

The eMMC are like SD cards in that they should not be powered down during a write/erase cycle. This eMMC module includes support for setting a fuse for a "Write Reliability" mode, and a "pseudo-SLC" mode. With both of these enabled then any writes will be atomic to 512B. If a sector is being written during a power loss, a block is guaranteed to have either the old or new data. This scheme is far more resilient to power loss than more traditional flash media. In cases of old 512B data fsck will still be able to recover a mountable filesystem. In cases where the corrupted file is a database it can still need a mechanism for recovery.

When this pSLC mode is turned on it will reduce the available space to under half, and reduce the write speed.

See our post on preventing filesystem corruption.

The mmc-utils package is used to enable these modes. First determine the exact size of the flash you're using:

mmc extcsd read /dev/mmcblk2 | grep MAX_ENH_SIZE_MULT -A 1
Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x0001cd
 i.e. 1888256 KiB

So in this case, 1888256 KiB (1.801 GiB) is the max size of the enhanced partition.

MAX_ENH_SIZE=$(mmc extcsd read /dev/mmcblk2 | grep "\\[MAX_ENH_SIZE_MULT\\]" -A 1 | sed -n '2p' | cut -f 3 -d ' ')
mmc write_reliability set -n 0 /dev/mmcblk2
# If write_reliability fails with "WR_REL_SET is read-only", this can be ignored. Many newer 
# eMMC chipsets ship with write reliability always on

mmc enh_area set -y 0 "$MAX_ENH_SIZE" /dev/mmcblk2
WARNING: Setting either of those modes is permanent. Using the wrong value it is possible to brick eMMC which will not be covered by the warranty. Evaluation units with fuses set will not be accepted through returns.

After this is run, cycle power to the board. On all future boots the eMMC will be detected at the smaller size. Changing the enhanced area will erase the drive. After these mmc commands the disk will need to be rewritten.

This can be applied automatically from our USB production blast.sh with:

#!/bin/bash

mmc extcsd read /dev/mmcblk2 > /tmp/csd
PART_DONE=$(grep PARTITION_SETTING_COMPLETED < /tmp/csd | cut -f 2 -d ':' | tr -d '[:space:]')
if [ "$PART_DONE" = "0x00" ]; then
    WR_REL_SET=$(grep "\\[WR_REL_SET\\]" < /tmp/csd | cut -f 2 -d ':' | tr -d '[:space:]')
    MAX_ENH_SIZE=$(grep "\\[MAX_ENH_SIZE_MULT\\]" < /tmp/csd -A 1 | sed -n '2p' | cut -f 3 -d ' ')

    # Some eMMC devices ship with this enabled already
    if [ "$WR_REL_SET" = "0x00" ]; then
        mmc write_reliability set -n 0 /dev/mmcblk2
    fi
    mmc enh_area set -y 0 "$MAX_ENH_SIZE" /dev/mmcblk2
    # This requires a power cycle on the eMMC for these settings.  
    # This pokes a register in the FPGA to cause a real POR rather 
    # than software reset
    tshwctl --addr 30 --poke 0x2
else
    echo "Partitioning is completed!"
fi

Enclosures

Every enclosure includes a front label which exposes 1 button, and 4 status LEDs.

TS-ENC797

The TS-7970 is available with 3 enclosures matching the various build options:

Enclosure Model Images Supported Boards
TS-ENC797
TS-ENC797 Front
TS-ENC797 Back
  • TS-7970-1G-4GF-S8S-RTC-I
  • TS-7970-2G-4GF-Q10S-RTC-E
TS-ENC797-CP
TS-ENC797-CP Front
TS-ENC797-CP Back
  • TS-7970-1G-4GF-S8S-RTC-CP-WIFI-I
  • TS-7970-2G-4GF-Q10S-RTC-CP-WIFI-E
TS-ENC797-CP-WIFI

This enclosure includes WIFI Antenna and UFL to SMA cable.

TS-ENC797-CP-WIFI Front
TS-ENC797-CP-WIFI Back
  • TS-7970-1G-4GF-S8S-RTC-CP-WIFI-I with WIFI antenna
  • TS-7970-2G-4GF-Q10S-RTC-CP-WIFI-E with WIFI antenna

These 3 enclosures can also be ordered with a DIN clip as TS-ENC797-DIN, TS-ENC797-CP-DIN, and TS-ENC797-CP-WIFI-DIN.

TS-ENC797-DIN

FPGA

The Lattice FPGA provides several features used by default on the TS-7970:

  • Automatic TX enable for RS-485 half duplex
  • DIO expander
  • UART/DIO crossbar
  • Clock generator
Note: The TS-7970 REV H and later include a Lattice MachXO3, where earlier revs use the Lattice MachXO2. The logic used on both is identical and does not require any user code changes.

The FPGA is software reloadable and can be customized for specific purposes. The registers are accessed over I2C using the "tshwctl" utility in the ts4900-utils repository. The DIO can be accessed using the sysfs GPIOs 224 through 288 using the "tsgpio" driver. See the GPIO section for more information on the recommended method to access GPIO.

Usage: tshwctl [OPTIONS] ...
Technologic Systems i.mx6 FPGA Utility
     -m, --addr <address>   Sets up the address for a peek/poke
     -v, --poke <value>     Writes the value to the specified address
     -t, --peek             Reads from the specified address
     -i, --mode <8n1>       Used with -a, sets mode like '8n1', '7e2', etc
     -x, --baud <speed>     Used with -a, sets baud rate for auto485
     -a, --autotxen <uart>  Enables autotxen for supported CPU UARTs
                              Uses baud/mode if set or reads the current
                              configuration of that uart
     -c, --dump             Prints out the crossbar configuration
     -g, --get              Print crossbar for use in eval
     -s, --set              Read environment for crossbar changes
     -q, --showall          Print all possible FPGA inputs and outputs.
     -h, --help             This message
Addr Bits Function
00 7:2 TTYMXC2_RXD Crossbar
1 Reserved
0 TTYMXC2_RXD Output Enable
01 7:2 TTYMXC4_RXD Crossbar
1 Reserved
0 TTYMXC4_RXD Output Enable
02 7:2 TTYMXC2_RTS Crossbar
1 TTYMXC2_RTS Data
0 TTYMXC2_RTS Output Enable
03 7:2 TTYMXC3_RXD Crossbar
1 Reserved
0 TTYMXC3_RXD Output Enable
04 7:2 TTYMXC1_RTS Crossbar
1 Reserved
0 TTYMXC1_RTS Output Enable
05 7:2 TTYMXC2_CTS Crossbar
1 TTYMXC2_CTS Output Data
0 TTYMXC2_CTS Output Enable
06 7:2 MB_TXD Crossbar
1 Reserved
0 MB_TXD Output Enable
07 7:2 MB_TX_EN_485 Crossbar
1 Reserved
0 MB_TX_EN_485 Output Enable
08 7:2 STC_TXD_485 Crossbar
1 Reserved
0 STC_TXD_485 Output Enable
09 7:2 STC_TX_EN_485 Crossbar
1 Reserved
0 STC_TX_EN_485 Output Enable
10 7:2 TXD_232_COM Crossbar
1 Reserved
0 TXD_232_COM Output Enable
11 7:2 RTS_232_COM Crossbar
1 Reserved
0 RTS_232_COM Output Enable
12 7:2 HD1_TXD Crossbar
1 HD1_TXD Data
0 HD1_TXD Output Enable
13 7:2 Reserved
1 BT_EN Data
0 BT_EN Output Enable
14 7:2 Reserved
1 WL_EN Data
0 WL_EN Output Enable
15 7:3 Reserved
2 BT_RTS Input Data
1:0 Reserved
16 7:2 BT_CTS Crossbar
1 BT_CTS Data
0 BT_CTS Output Enable
17 7:2 BT_RXD Crossbar
1:0 Reserved
18 7:2 TTYMXC1_RXD Crossbar
1:0 Reserved
19 7:2 HD1_DIO_1 Crossbar
1 HD1_DIO_1 Data
0 HD1_DIO_1 Output Enable
20 7:2 HD1_DIO_2 Crossbar
1 HD1_DIO_2 Data
0 HD1_DIO_2 Output Enable
21 7:2 HD1_DIO_3 Crossbar
1 HD1_DIO_3 Data
0 HD1_DIO_3 Output Enable
22 7:2 HD1_DIO_4 Crossbar
1 HD1_DIO_4 Data
0 HD1_DIO_4 Output Enable
23 7:2 HD1_DIO_5 Crossbar
1 HD1_DIO_5 Data
0 HD1_DIO_5 Output Enable
24 7:2 HD1_DIO_6 Crossbar
1 HD1_DIO_6 Data
0 HD1_DIO_6 Output Enable
25 7:2 EN_OUT_1 Crossbar
1 EN_OUT_1 Data
0 EN_OUT_1 Output Enable
26 7:2 EN_OUT_2 Crossbar
1 EN_OUT_2 Data
0 EN_OUT_2 Output Enable
27 7:2 FPGA_IRQ_1 Crossbar
1 Input Data
0 Reserved
28 7:2 STC_TXD_232 Crossbar
1:0 Reserved
29 7:2 Reserved
1 push_sw reset [1]
0 Reserved
30 7:2 Reserved
1 Reboot (on 1) [2]
0 Reserved
31 7:3 Reserved
2 Push SW Input Data
1:0 Reserved
32 7:0 RS485_CNT0 [23:16]
33 7:0 RS485_CNT0 [15:8]
34 7:0 RS485_CNT0 [7:0]
35 7:0 RS485_CNT1 [23:16]
36 7:0 RS485_CNT1 [15:8]
37 7:0 RS485_CNT1 [7:0]
38 7:0 RS485_CNT2 [23:16]
39 7:0 RS485_CNT2 [15:8]
40 7:0 RS485_CNT2 [7:0]
41 7:0 RS485_CNT3 [23:16]
42 7:0 RS485_CNT3 [15:8]
43 7:0 RS485_CNT3 [7:0]
44 7:2 TTYMAX0_RXD Crossbar
1 Reserved
0 TTYMAX0_RXD Output Enable
45 7:2 TTYMAX1_RXD Crossbar
1 Reserved
0 TTYMAX1_RXD Output Enable
46 7:2 TTYMAX2_RXD Crossbar
1 Reserved
0 TTYMAX2_RXD Output Enable
51 7:4 FPGA Revision
3 R39 Option Resistor (1 = not present)
2 R34 Option Resistor (1 = not present)
1 R36 Option Resistor (1 = not present)
0 R37 Option Resistor (1 = not present)
53 7:2 TTYMAX0_CTS Crossbar
1 Reserved
0 TTYMAX0_CTS Output Enable
54 7:2 TTYMAX1_CTS Crossbar
1 Reserved
0 TTYMAX1_CTS Output Enable
55 7:2 TTYMAX2_CTS Crossbar
1 Reserved
0 TTYMAX2_CTS Output Enable
56 7:6 DIO1 and DIO2 input data.
5:0 HD1_DIO input data
57 7:2 Reserved
1 LCD_D10
0 CN_99_BOOT_SEL Input Data
58 7:2 HD1_SPI_CLK Crossbar
1 HD1_SPI_CLK Data
0 HD1_SPI_CLK Output Enable
59 7:2 HD1_SPI_MOSI Crossbar
1 HD1_SPI_MOSI Data
0 HD1_SPI_MOSI Output Enable
60 7:2 HD1_SPI_MISO Crossbar
1 HD1_SPI_MISO Data
0 HD1_SPI_MISO Output Enable
61 7:2 Reserved
1 1 = Always pass through SPI rather than on HD1_SPI_CS# assert only
0 Reserved
  1. If this bit is set to 1, depressing SW1 will cause an immediate hardware reboot
  2. When set to 1 will cause a hardware reboot

FPGA Crossbar

The FPGA crossbar allows almost any of the FPGA pins to be rerouted. All the FPGA addresses that have a crossbar mux register can be written with these output values.

Crossbar Value Selected Function
0 Do not change
1 BT_RTS
2 BT_TXD
3 TTYMXC4_TXD
4 TTYMXC2_TXD
5 TTYMXC2_RTS
6 TTYMXC1_RTS
7 TTYMXC2_CTS
8 MB_RXD_485
9 STC_RXD_485_3V
10 RXD_232_COM
11 CTS_232_COM
12 STC_RXD
13 HD1_RXD
14 TTYMXC3_TXD
15 TTYMXC1_TXD
16 TTYMAX0_TXD
17 TTYMAX0_TXEN
18 TTYMAX0_RTS
19 TTYMAX1_TXD
20 TTYMAX1_TXEN
21 TTYMAX1_RTS
22 TTYMAX2_TXD
23 TTYMAX2_TXEN
24 TTYMAX2_RTS
25 TTYMXC1_TXEN
26 TTYMXC3_TXEN
27 CLK_12MHZ
28 CLK_14MHZ
29 FPGA_24MHZ_CLK
30 CLK_28MHZ
31 GPIO
32 HD1_DIO_1
33 HD1_DIO_2
34 HD1_DIO_3
35 HD1_DIO_4
36 HD1_DIO_5
37 HD1_DIO_6
38 DIO_1_IN
39 DIO_2_IN
40 LCD_D10
41 PUSH_SW_CPU
42 HD1_SPI_CLK
43 HD1_SPI_MOSI
44 HD1_SPI_MISO


For example, we can remap three ttyMAX ports to the HD1 GPIO.

Pin Function
HD1_DIO_1 ttyMAX0 txd
HD1_DIO_2 ttyMAX0 rxd
HD1_DIO_3 ttyMAX1 txd
HD1_DIO_4 ttyMAX1 rxd
HD1_DIO_5 ttyMAX2 txd
HD1_DIO_6 ttyMAX2 rxd
tshwctl --dump

This will return the mapping of all of the pins as they are currently set. These are the relevant pins:

     FPGA Pad (DIR) (VAL) FPGA Output
       MB_TXD ( in) (  0) TTYMAX1_TXD
  STC_TXD_485 ( in) (  0) TTYMAX0_TXD
  RTS_232_COM ( in) (  0) TTYMAX2_TXD
    HD1_DIO_1 ( in) (  0) GPIO
    HD1_DIO_2 ( in) (  0) GPIO
    HD1_DIO_3 ( in) (  0) GPIO
    HD1_DIO_4 ( in) (  0) GPIO
    HD1_DIO_5 ( in) (  0) GPIO
    HD1_DIO_6 ( in) (  0) GPIO
  TTYMAX0_RXD ( in) (  0) STC_RXD_485_3V
  TTYMAX1_RXD ( in) (  0) MB_RXD_485
  TTYMAX2_RXD ( in) (  0) CTS_232_COM

...

The tshwctl tool uses the bash environment to set/get pin status. To remap these pins:

eval $(tshwctl --get)
export HD1_DIO_1=TTYMAX0_TXD
export HD1_DIO_3=TTYMAX1_TXD
export HD1_DIO_5=TTYMAX2_TXD
export TTYMAX0_RXD=HD1_DIO_2
export TTYMAX1_RXD=HD1_DIO_4
export TTYMAX2_RXD=HD1_DIO_6

# These last 3 aren't required, but this will disable ttyMAX pins on
# their default locations.  Without this, writes to /dev/ttyMAX0 
# would go to both STC_TXD_485 and to HD1_DIO_1.
export MB_TXD=GPIO
export STC_TXD_485=GPIO
export RTS_232_COM=GPIO

# This will read the environment and look for the PAD names 
# for any changes and apply them.
tshwctl --set

The CPU UARTs can also be used in place of the ttyMAX FPGA UART to provide RS-485. For example, to use the bluetooth uart (ttymxc1) in place of ttyMAX0:

export STC_TX_EN_485=TTYMXC1_TXEN
export TTYMXC1_RXD=STC_RXD_485_3V
export STC_TXD_485=TTYMXC1_TXD
tshwctl --set
# Describe timing for CPU uarts:
stty -F /dev/ttymxc1 115200 cs8 -cstopb
tshwctl --autotxen 1

GPIO

Note: It is possible to use memory mapped CPU registers as documented in the CPU reference manual to control GPIO. When using this, be aware that the kernel may attempt to also access these registers for various reasons. Also note that each register represents a bank of GPIO pins. Use a read-modify-write operation to avoid disturbing other GPIO pins. We strongly recommend using the sysfs interface as described below.

The i.MX6 GPIO are available using the kernel sysfs interface. See the kernel's documentation here for more detail. This interface provides a set of files and directories for interacting with GPIO. This allows GPIO to be accessed from any language that can read and write files. For example, to toggle CN1_89/EIM_A22, the kernel maps this to GPIO 48 (See the table below for the full I/O mapping).

To interact with this pin, first export it to userspace:

echo "48" > /sys/class/gpio/export

If the command returns with a permission denied on a GPIO that means it is claimed by another kernel driver. If it succeeds, the kernel will create the "/sys/class/gpio/gpio48/" directory. The relevant files in this directory are:

 direction - "in", "high", "low", or "out".  Out is equivalent to low
 value - write "1" or "0", or read "1" or "0" if direction is in
 edge - write with "rising", "falling", or "none"
# Set GPIO 48 high
echo "out" > /sys/class/gpio/gpio48/direction
echo "1" > /sys/class/gpio/gpio48/value
# Set GPIO 48 low
echo "0" > /sys/class/gpio/gpio48/value

# Read the value of GPIO 48
echo "in" > /sys/class/gpio/gpio48/direction
cat /sys/class/gpio/gpio48/value

As an output, the "value" file can be written with "0" for low (GND), or "1" for high (3.3V). As an input the GPIO will have a 100k pullup. The GPIO pins from the i.MX6 processor support an absolute maximum voltage range of -0.5 to 3.6V. It is also possible to use any processor GPIO as an interrupt. This is done by writing the "edge" file and using select() or poll() on the "value" file to watch for changes. See the Interrupts section for more details.

The GPIO numbers in the table below are relevant to how the Linux references these numbers. The CPU documentation refers to bank and IO while Linux flattens this out to one number space.

Pins #224 and above are from the perspective of the FPGA rather than the CPU. For example, toggling the IO #224 is ttymxc2_rxd which does not toggle the cpu's uart pin, but the FPGA IO directed at that pin in the CPU. Many of these UART pins are not set as GPIO by default, and the FPGA includes its own crossbar. The UART pins will be mapped to cpu or fpga uarts.

Pad Name [1] GPIO Number Common Functions [2] Location
SD4_DAT3 43 USB HUB Reset# Onboard
DISP0_DAT23 145 SEL_DC_USB# Onboard
EIM_A16 54 EN_USB_5V Onboard
EIM_D27 91 Green LED Onboard
GPIO_2 2 Red LED Onboard
GPIO_9 9 Yellow LED Onboard
DISP0_DAT4 121 Blue LED Onboard
CSI0_DATA_EN 148 FPGA_IRQ_0 (FPGA UART irq) Onboard
GPIO_4 4 FPGA_IRQ_1 (unused) Onboard
DISP0_DAT14 136 JTAG_FPGA_TMS Onboard
DISP0_DAT17 139 JTAG_FPGA_TCK Onboard
DISP0_DAT18 140 JTAG_FPGA_TDO Onboard
DISP0_DAT22 144 JTAG_FPGA_TDI Onboard
DISP0_DAT20 142 Gyro IRQ Onboard
EIM_LBA 59 GPIO HD2 pin 3
EIM_OE 57 Modbus fault Onboard
EIM_RW 58 GPIO HD2 pin 22
EIM_A19 51 EN_MODBUS_24V# Onboard
DISP0_DAT5 122 EN_MODBUS_3V# Onboard
EIM_D23 87 EN_RTC_PWR Onboard
DISP0_DAT0 117 EN_CAN_1# Onboard
EIM_BCLK 191 EN_CAN_2# Onboard
DISP0_DAT7 124 GPIO HD1 pin 7
DISP0_DAT9 126 GPIO HD1 pin 21
DISP0_DAT10 127 GPIO HD1 pin 9
DISP0_DAT11 133 GPIO HD1 pin 14
EIM_CS0 55 GPIO HD2 pin 5
EIM_A24 132 GPIO HD2 pin 12
EIM_WAIT 128 GPIO HD2 pin 11
EIM_EB1 61 GPIO HD2 pin 10
EIM_DA0 64 GPIO HD2 pin 2
EIM_DA1 65 GPIO HD2 pin 4
EIM_DA2 66 GPIO HD2 pin 6
EIM_DA3 67 GPIO HD2 pin 8
EIM_DA4 68 GPIO HD2 pin 7
EIM_DA5 69 GPIO HD2 pin 9
EIM_DA6 70 GPIO HD2 pin 13
EIM_DA7 71 GPIO HD2 pin 15
EIM_DA8 72 GPIO HD2 pin 16
EIM_DA9 73 GPIO HD2 pin 17
EIM_DA10 74 GPIO HD2 pin 14
EIM_DA11 75 GPIO HD2 pin 24
EIM_DA12 76 GPIO HD2 pin 21
EIM_DA13 77 GPIO HD2 pin 19
EIM_DA14 78 GPIO HD2 pin 20
EIM_DA15 79 GPIO HD2 pin 18
SD4_DAT5 45 TTYMXC1_RTS FPGA Crossbar
SD4_DAT6 46 TTYMXC1_CTS FPGA Crossbar
  1. The pad name does not often correspond with the functionality of the IO we use, but can be used to reference the pad in the CPU manual.
  2. This does not contain all of the functions possible for a pin, but the common functions as they are used on our off the shelf basebords. Consult the i.MX6 CPU Reference manual, and FPGA crossbar section for a complete list.

FPGA GPIO

The FPGA is used as a GPIO expander, and a crossbar. In most cases the FPGA IO are usable for low speed IO. The crossbar allows passing through some spare CPU GPIO which are interruptible.

Note: If any IO are used from the kernel, keep in mind these IO cannot be called from an interrupt context. These IO "can sleep". Instead of gpio_set_value use gpio_set_value_cansleep().

Some pins will need to be changed into GPIO before they can be used. For example, to toggle HD1 pin 12 (HD1_TXD):

tshwctl --dump
 root@ts-imx6:~# tshwctl --dump
   FPGA Pad    (DIR) (VAL) FPGA Output
   TTYMXC2_RXD ( in) (  0) HD1_RXD
   TTYMXC4_RXD ( in) (  0) STC_RXD
   TTYMXC2_CTS ( in) (  0) GPIO
   TTYMXC3_RXD ( in) (  0) RXD_232_COM
   TTYMXC1_CTS ( in) (  0) BT_RTS
   TTYMXC2_RTS ( in) (  1) GPIO
        MB_TXD ( in) (  0) TTYMAX1_TXD
  MB_TX_EN_485 ( in) (  0) TTYMAX1_TXEN
   STC_TXD_485 ( in) (  0) TTYMAX0_TXD
 STC_TX_EN_485 ( in) (  0) TTYMAX0_TXEN
   TXD_232_COM ( in) (  0) TTYMXC3_TXD
   RTS_232_COM ( in) (  0) TTYMAX2_TXD
       HD1_TXD ( in) (  0) TTYMXC2_TXD
        BT_CTS ( in) (  1) TTYMXC1_RTS
 ...

In this case HD1_TXD is the signal we want to toggle. The HD1_TXD signal is passing through TTYMXC2_TXD. It is possible to toggle ttymxc2_txd from the CPU as a GPIO, but the CPU IOMUXC would first need to be configured. On the CPU IOMUXC this is a UART, not a GPIO by default. On the FPGA as well this is configured to pass through the CPU pin, but it can be configured to be a GPIO:

export HD1_TXD=GPIO
tshwctl --set

Now running "tshwctl --dump" will show this HD1_TXD signal is now a GPIO. Refer to the below table to see the FPGA pin to toggle. In this case, 236.

echo 236 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio236/direction
echo low > /sys/class/gpio/gpio236/direction
Pad Name [1] GPIO Number Default Function Location
TTYMXC2_RXD 224 ttymxc2 rxd HD1 pin 12
TTYMXC4_RXD 225 ttymxc4 rxd P1-B pin 16
TTYMXC2_RTS 226 NC NC
TTYMXC3_RXD 227 ttymxc3 rxd COM Header pin 2
TTYMXC1_CTS 228 ttymxc1 cts Onboard (Bluetooth RTS)
TTYMXC2_CTS 229 NC NC
MB_TXD 230 ttyMAX1 txd Modbus RJ45 Data pins 4/5 +/-
MB_TX_EN_485 231 ttyMAX1 txen Onboard
STC_TXD_485 232 ttyMAX0 TXD P1-A Terminal Block pin 2, COM2 Header pin 1
STC_TX_EN_485 233 ttyMAX0 TXEN Onboard [2]
TXD_232_COM 234 ttymxc3 TXD COM2 Header pin 3
RTS_232_COM 235 ttyMAX2 TXD COM2 Header pin 7
HD1_TXD 236 ttymxc2 TXD HD1 pin 12
BT_EN 237 GPIO Onboard
WL_EN 238 GPIO Onboard
BT_RTS 239 ttymxc1 CTS Onboard
BT_CTS 240 ttymxc1 RTS Onboard
BT_RXD 241 ttymxc1 TXD Onboard
TTYMXC1_RXD 242 ttymxc1 TXD Onboard
HD1_DIO_1 243 GPIO HD1 pin 8
HD1_DIO_2 244 GPIO HD1 pin 6
HD1_DIO_3 245 GPIO HD1 pin 4
HD1_DIO_4 246 GPIO HD1 pin 2
HD1_DIO_5 247 GPIO HD1 pin 24
HD1_DIO_6 248 GPIO HD1 pin 22
EN_OUT_1 249 GPIO Onboard/Terminal Block P1-B pin 5
EN_OUT_2 250 GPIO Onboard/Terminal Block P1-B pin 6
STC_TXD_232 252 ttymxc4 TXD P1-B Terminal Block pin 7
FPGA Register 253 1 = Reboot on push_sw Register
FPGA Register 254 1 = Reboot Register
TTYMAX0_RXD 268 ttyMAX0 RXD P1-A Terminal Block pin 3, COM2 Header pin 6
TTYMAX1_RXD 269 ttyMAX1 RXD RJ45 2W-Modbus pin 5
TTYMAX2_RXD 270 ttyMAX2 RXD COM2 Header pin 8
HD1_SPI_CLK 282 #SPI, GPIO HD1 pin 17
HD1_SPI_MOSI 283 #SPI, GPIO HD1 pin 20
HD1_SPI_MISO 284 #SPI, GPIO HD1 pin 18
  1. The pad name rarely corresponds with the functionality of the IO we use. This name can be used to reference the pad in the CPU manual.
  2. This pin is set up to automatically toggle with TX data in the FPGA. You do not need to manually toggle this to transmit/receive.

I2C

The i.MX6 supports standard I2C at 100khz, or using fast mode for 400khz operation. The CPU has 2 I2C buses used on the TS-7970

/dev/i2c-0 is internal to the board and connects to the RTC and FPGA. /dev/i2c-1 is external on #HD3 and also shared with HDMI

i2c-0
Address Device
0x10 Supervisory microcontroller
0x28-0x2F FPGA
0x57 NVRAM
0x6B Onboard PCIe Clock Generator
0x6F RTC
i2c-1
Address Device
0x50 HDMI

The second I2C bus (/dev/i2c-1) is brought out on HD3 pin 15 (SCL) and HD3 pin 16 (SDA). This bus has no onboard devices, but does run to the HDMI port. Some video devices may attempt to communicate via this line.

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

The kernel makes the I2C available at /dev/i2c-#. The i2c-tools (i2cdetect, i2cgetm, i2cset) can be used to interact with a device, it is possible to create a custom interface application.

Interrupts

The i.MX6 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 are exposed through the sysfs gpio mechanism. This example will trigger on a falling edge for GPIO 48:

echo "48" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio48/direction
echo "falling" > /sys/class/gpio/gpio48/edge

From here, an application can poll() or select() on the "/sys/class/gpio/gpio48/value" file and will return when the edge setting has been triggered:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>
 
int main(int argc, char **argv)
{
	char gpio_irq[64];
	int ret, irqfd = 0, i = 0;
	fd_set fds;
	FD_ZERO(&fds);
	int buf;
 
	if(argc < 2) {
		printf("Usage: %s <gpio number>\n", argv[0]);
		return 1;
	}
 
	snprintf(gpio_irq, sizeof(gpio_irq), "/sys/class/gpio/gpio%d/value", atoi(argv[1]));
	irqfd = open(gpio_irq, O_RDONLY, S_IREAD);
 
	if(irqfd == -1) {
		printf("Could not open IRQ %s\n", argv[1]);
		printf("Make sure the GPIO is already exported", argv[1]);
		return 1;
	}

	// Read first since there is always an initial status
	ret = read(irqfd, &buf, sizeof(buf));

	while(1) {
		FD_SET(irqfd, &fds);
		// See if the IRQ has any data available to read
		ret = select(irqfd + 1, NULL, NULL, &fds, NULL);
 
		if(FD_ISSET(irqfd, &fds))
		{
			FD_CLR(irqfd, &fds);  //Remove the filedes from set
			printf("IRQ detected %d\n", i);
			fflush(stdout);
			i++;
			
			/* The return value includes the actual GPIO register value */
			read(irqfd, &buf, sizeof(buf));
			lseek(irqfd, 0, SEEK_SET);
		}
 
		//Sleep, or do any other processing here
		usleep(100000);
	}
 
	return 0;
}

This example can be run as "./irqtest 48" which will echo every time the pin changes but not consume any CPU time while waiting for an edge to occur.

Jumpers

The TS-7970 has a set of jumpers located near the edge of the SBC, near the HDMI connector. These jumpers control a number of aspects of the TS-7970's behavior. The jumpers are labeled on the silkscreen rather than numbered:

Label Description
SD Boot When jumper is set, boot kernel and Debian from the SD card. Otherwise boot kernel and Debian from eMMC. This jumper influences U-Boot behavior.
CON EN When jumper is set, it will redirect the USB device port to connect to the on-board supervisory microcontroller which provides a USB serial interface. When removed, this device port is instead connected to the CPU USB OTG interface.
CAN1 When jumper is set, adds a 120 ohm termination resistor across CAN1 (linux can0 interface) H and L pins.
CAN2 When jumper is set, adds a 120 ohm termination resistor across CAN2 (Linux can1 interface) H and L pins.

LEDs

The TS-7970 has 4 user controllable LEDs.

On startup, the red LED turns on while the system is in u-boot. When execution switches to the Linux kernel, the green LED turns on, and red turns off (controlled by the default state in the device tree).

The blue LED is also driven by the supervisory microcontroller. By default this will turn on the LEDs when connected. When the system is in sleep mode it will turn off the led but blink on briefly on occasion to show activity. If USB has power, but VIN has been removed or is below the minimum threshold, the blue led will blink rapidly.

After startup, users can take over the LED behavior by writing to the files in /sys/class/leds/<name>/brightness. These include:

  • (1) blue-led
  • (2) green-led
  • (3) red-led
  • (4) yellow-led

The kernel provides access to control the LEDs using the sysfs:

# 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 for a given LED is in its directory:

echo "heartbeat" > /sys/class/leds/red-led/trigger
Trigger value LED toggles on
none Default, no action
mmc0 MicroSD card activity
mmc1 eMMC activity
mmc2 WIFI SDIO activity
timer 2hz blink
oneshot Blinks after delay. [1]
heartbeat Similar to timer, but varies the period based on system load
backlight Toggles on FB_BLANK
gpio Toggle based on a specified gpio. [2]
cpu0 Blink on CPU core 0 activity
cpu1 Blink on CPU core 1 activity
cpu2 Blink on CPU core 2 activity
cpu3 Blink on CPU core 3 activity
default-on Only turns on by default. Only useful for device tree.
transient Specify on/off with time to turn off. [3]
flash/torch Toggle on Camera activation. Not currently used.
  1. See the Kernel documentation for more details
  2. 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
  3. See the Kernel documentation for more details

LVDS

The TS-7970 includes one LVDS output from the i.MX6 processor. This interface can provide a pixel clock up to 85MHz supporting displays up to 1366x768 at 60hz. The LVDS pairs are available on the #HD3 header.

Linux will require some customization in the device tree to describe the timing for the LCD. These values should be provided by the LCD datasheet. As an example, this is for the 10" Hantronix display used on the TS-TPC-8950:

&ldb {
	status = "okay";

	lvds-channel@0 {
		crtc = "ipu1-di1";
		fsl,data-mapping = "spwg";
		fsl,data-width = <18>;
		status = "okay";
		primary;

		display-timings {
			native-mode = <&timing0>;
			timing0: hantronix-svga1 {
				clock-frequency = <40000000>;
				hactive = <800>;
				vactive = <600>;
				hback-porch = <46>;
				hfront-porch = <210>;
				vback-porch = <23>;
				vfront-porch = <12>;
				hsync-len = <20>;
				vsync-len = <10>;
				de-active = <1>;
				hsync-active = <1>;
				vsync-active = <1>;
				pixelclk-active = <0>;
			};
		};
	};
};

The mxcfb1 node should also be changed from HDMI to LVDS:

	mxcfb1: fb@0 {
		compatible = "fsl,mxc_sdc_fb";
		disp_dev = "ldb";
		interface_pix_fmt = "RGB666";
		default_bpp = <16>;
		int_clk = <0>;
		late_init = <0>;
		status = "okay";
	};

Technologic Systems offers engineering services which can assist in integrating custom displays. Contact us for more information.

MicroSD Card Interface

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

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

See chapter 67 of the i.MX6 reference manual for the specific CPU variant for more information on the mmc controller.

We have performed compatibility testing on the Sandisk MicroSD cards we provide. We do not suggest switching brands/models without your own qualification testing. While SD cards specifications are standardized, in practice cards behave very differently. We do not recommend ATP or Transcend MicroSD cards due to known compatibility issues.

Our testing has shown that on average microSD cards will last between 6-12TB. After this cards can begin to experience corruption, or stop being recognized by the host PC. This may be enough storage for many applications to write for years without problems. For more reliable storage consider using the eMMC. Our endurance testing showed a write lifetime on average of about 123 TiB.

MicroSD cards should not have power removed during a write or they will have disk corruption. Keep the filesystem mounted read only if this is a possibility. It is not always possible for fsck to recover from the types of failures that will be seen with SD power loss. Consider using the eMMC for storage instead which is far more resilient to power loss.

NVRAM

The RTC includes 120 bytes of NVRAM which can be used for custom applications. The utility 'nvramctl' can be used to read/write the NVRAM. The source for this utility is available from our ts4900-utils github.

The utility reads/writes a byte at a time, and returns the value in hex.

nvramctl --addr 10 --set 0x40
nvramctl --addr 10 --get
# Returns "nvram10=0x40".
# This can also be used with eval
eval $(nvramctl --addr 10 --get)
echo $nvram10
# Returns "0x40"

The NVRAM code can be included in your application by using these two files:

Onboard SPI Flash

This board includes 8 MiB of SPI flash using a Micron N25Q064A13ESE40F. The CPU uses this for the initial boot to load u-boot, as well as the u-boot environment. In Linux this is accessed with the /dev/mtdblock devices.

Bytes Size Description
0x000000-0x0003FF 1 KB Unused
0x000400-0x0FFFFF 0.999 MiB U-Boot
0x100000-0x101FFF 8 KiB U-Boot environment #1
0x102000-0x17FFFF 504 KiB Unused
0x180000-0x181FFF 8 KiB U-Boot environment #2
0x182000-0x1FFFFF 504 KiB Unused
0x200000-0x700000 5 MiB Unused

PWM

The CPU exposes one PWM on HD1_IRQ (HD1 pin 21). By default, this pin is a GPIO which is used as an interrupt for daughter cards. To use this as PWM a modification to the device tree will be required. See the #Compile the Kernel section to get a build environment working. The file "arch/arm/boot/dts/imx6qdl-ts7970.dtsi" will need to be modified.

First the pin must be configured to be PWM and not a GPIO. Find the line:

 MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30	0x1b088 /* HD1_IRQ */

and remove it.

Add the "pinctrl_pwm2" block below as a new section in the "imx6-ts7970" section:

iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog>;

	imx6-ts7970 {
		pinctrl_pwm2: pwm2grp {
			fsl,pins = <
				MX6QDL_PAD_DISP0_DAT9__PWM2_OUT		0x1b088
			>;
		};

The "MX6QDL_PAD_DISP0_DAT9__PWM2_OUT" pad name comes from "imx6q-pinfunc.h" or "imx6dl-pinfunc.h" files. The format follows "MX6QDL_PAD_<CPU Pad Name>__<Function of that pad>". This specifies that the pad "DISP0_DAT9" to be used as PWM2's output.

At the end of the file, add the following block which enables the PWM controller and connects the iomuxc pinctrl created above:

&pwm2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm2>;
	status = "okay";
};


After rebuilding and installing this updated device tree, the directory "/sys/class/pwm/pwmchip0/" will be available to control the PWM as outlined below.

# Each PWM controller has "1" pwm which will be pwm channel 0
echo 0 > /sys/class/pwm/pwmchip0/export


This will create a "pwm0/" directory under "pwmchip0/" which has the following files:

period Total period, inactive and active time in the PWM cycle specified in nanoseconds.
duty_cycle Active time of the PWM signal specified in nanoseconds. Must be less than the period.
enable Write 1 to enable, 0 to disable
polarity When the pwm is disabled this can be written as "normal" for default behavior or "inversed" to invert the signal.

As an example, this will set a 50 khz signal with a 50% duty cycle.

# 20us is the period for 50khz
echo 20000 > /sys/class/pwm/pwmchip0/pwm0/period
echo 10000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

A common use of the PWM is for backlight control which is specified in the device tree. Our TS-TPC-8390 baseboard device tree can be used as an example.

In addition to setting up the PWM as demonstrated above, the PWM is connected to the pwm-backlight driver.

	backlight_lcd {
		compatible = "pwm-backlight";
		pwms = <&pwm3 0 5000000>;
		brightness-levels = <0 128 140 160 180 200 220 240 255>;
		default-brightness-level = <8>;
		power-supply = <&reg_3p3v>;
	};

This specifies PWM3 to run with 5000000 ns periods (200hz) with duty cycles specified in brightness-levels up to 255. This example creates 8 levels of brightness for the backlight, but more duty cycles can be added if more levels are needed.

RTC

The TS-7970 includes a built in RTC. Before REV H, this is the Intersil ISL12020. This provides a long RTC battery life, as well as a built in temperature sensor to provide ±5 ppm across -40 to 85 C. The RTC appears at "/dev/rtc0" in our images, and is accessed using the standard hwclock command.

On the REV H and on due to parts availability this is instead provided by the Supervisory Microcontroller. This provides the same I2C register interface to Linux as the original Intersil part, but does not support the temperature compensation. Since this cannot support temperature compensation the RTC on REV H and newer is similar to a more typical RTC+crystal. See the #RTC Calibration section for more details.

The emulated RTC device on REV H and later only shows on the i2c bus if there is a battery with sufficient voltage (> 2V) installed in the board on startup. If the /dev/rtc0 device does not exist on startup, this can be used to detect a failed battery.

The battery attached to this RTC is a CR1632 Lithium battery expected to last approximately 10 years.

The ISL12020 compatible RTC device in the microcontroller uses the same Linux driver. ll of the features Linux uses are implemented, but many of the tuning, temperature compensation, and voltage threshold functions are not implemented. The NVRAM/SRAM is implemented the same way at 0x57.

Emulated ISL12020 Registers
Address Section Notes
0x0-0x6 RTC Implementation matches ISL12020
0x7-0x0f CSR
  • In INT, only WRTC/ARST are implemented
  • PWR_VDD/PWR_VBAT/ITRO/ALPHA/BETA/FATR/FDTR regs are not implemented [1]
  • 0x0f bit 8 hard coded to 1 to identify this emulated core
0x10-0x15 ALARM
  • Implementation matches ISL12020.
  • Supported as a wake source from sleep mode.
0x16-0x1a TVS2B Implementation mostly matches ISL12020 [2]
0x1b-0x1f TVB2V Implementation mostly matches ISL12020 [3]
0x20-0x27 DSTCR This section is not implemented [4]
0x28-0x29 TEMP Implementation matches ISL12020, reads microcontroller die temperature
0x2a-0x2b NPPM This section is not implemented [5]
0x2C XT0 This section is not implemented [6]
0x2D ALPHAH This section is not implemented [6]
0x2E-0x2F GPM Stored in ram, but does not persist on battery
  1. The temperature compensation is not supported by this RTC so these regs are unused.
  2. Does not support clearing the timestamp manually
  3. Does not support clearing the timestamp manually
  4. Linux does not use the daylight savings time auto correction registers, so this is not implemented.
  5. The microcontroller does not support the same PPM corrections
  6. 6.0 6.1 The microcontroller cannot support the temperature table since it cannot execute code while running off only the RTC battery.

RTC Calibration

The TS-7970 Rev. H included a change due to parts availability the where the RTC functionality was moved from the temperature compensated Intersil ISl12022 RTC to the supervisory microcontroller. This provides a register set compatible with Linux's existing RTC driver so software is backwards compatibile, but the newer RTC has a higher drift.

A typical RTC crystal is approximately ±20 ppm accurate which results in drift while the system is offline of approximately ±631 seconds per year. A crystal's accuracy will become worse when run in different temperatures, or as the crystal ages.

The Intersil RTC was previously ±5 ppm which is approximately ±158 seconds per year. This is also temperature compensated so the Intersil RTC checks the temperature every 10 minutes and tunes itself to stay within a low drift.

The new supervisory microcontroller does not support temperature compensation with its RTC, however we have created a process for calibrating the RTC. This can be used to compensate for the typical temperature where the board operates. The RTC on TS-7970's before Rev. H are factory calibrated and temperature compensated and will not benefit from further calibration documented below.

Our circuit, operating temperature, the variance of each crystal as they are manufactured, and aging all contribute to crystal accuracy. In the TS-7970 production process we perform this calibration at room temperature. At the time of use in our factory this will give roughly <5 ppm immediately after calibration. The crystal will offset by ±3 ppm per year, and will vary more significantly based on the temperature.

The ppm offset range can be calculated with:

0.035 * (CalibrationTemp - OperatingTemp)^2

Eg, our calibration is performed at 22 C:

0.035*(22-85)^2=138.915

, or roughly ±139 ppm at 85 C.

To calculate the seconds offset per year:

(60*60*24*365)*(138.915*10^-6)=4380.8
Temperature (C) Estimated PPM range
85 ±139
50 ±27
10 ±5
-40 ±135

These are not exact ppm offsets, but a rough range to use for estimation of drift.

Recalibration will help compensate for the affects of aging on the crystal, and can be used to target a more application specific typical operating temperature. Calibration is performed by removing the offset in the RTC, then using an NTP client to sync up the clock. These instructions are for Debian, but will work under any distribution that can run Chrony and a recent kernel.

First, we must clear the RTC offset.

# This requires an up to date version of 4.9, or any release of 5.10 for the offset file:
echo 0 > /sys/class/rtc/rtc0/offset

After clearing the rtc offset, install chrony.

apt-get install chrony -y

Open /etc/chrony/chrony.conf, and add the line:

 rtcfile /var/lib/chrony/rtcfile

Make sure there is no 'rtcsync' in the file since it cannot sync the hardware clock during this test, and that cannot be set with rtcfile.

Then restart chrony, and force a sync:

service chrony restart
chronyc makestep

At this step we must wait for the system clock to get in sync with the upstream NTP server. From our testing with a good network connection this can take 15-30 minutes until the RTC offset settles. From here we can query chrony for the RTC offset.

root@tsimx6:~# chronyc rtcdata
RTC ref time (UTC) : Fri Nov 18 13:38:36 2022
Number of samples  : 64
Number of runs     : 40
Sample span period : 254m
RTC is fast by     :    -0.198639 seconds
RTC gains time at  :   -21.674 ppm

In this example, the RTC is offset is -21.674 ppm. Linux expects this value to be in parts per billion, and it should be indicated what value will correct the crystal. Multiply the ppm by 1000 * -1 to get a value we can write to the offsets file. For example:

# Parse rtcdata and get the PPM value
# Eg, with the above example this is:
# PPM=-21.674
PPM=$(chronyc rtcdata | grep ppm | awk '{print $6}')
# Convert to parts per billion and invert the value to apply a correction.
# Eg, with the above example this is:
# PPB_CORRECTION=21674
PPB_CORRECTION=$(echo "scale=0; ${PPM}*-1000/1" | bc)

echo $PPB_CORRECTION > /sys/class/rtc/rtc0/offset

After writing the offset, this is stored in flash in the emulated RTC and will persist between reboots. This should not be written constantly as to not wear the flash. If this is being written often, the driver could be modified to remove the flag that specifies this should be saved in flash, and then it will be loaded from ram only.

SATA

The i.MX6 Quad and Dual include integrated SATA II support. This interface has been tested to provide 72 MiB/s write, and 75 MiB/s read through block access. In Linux this is accessed through the "/dev/sda" device node:

[    1.768036] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
[    1.785377] ata1.00: ATA-8: MKNSSDAT30GB-DX, 507ABBF0, max UDMA/133
[    1.791716] ata1.00: 58626288 sectors, multi 16: LBA48 NCQ (depth 31/32)
[    1.805380] ata1.00: configured for UDMA/133
[    1.810320] scsi 0:0:0:0: Direct-Access     ATA      MKNSSDAT30GB-DX  507A PQ: 0 ANSI: 5
[    1.819459] sd 0:0:0:0: [sda] 58626288 512-byte logical blocks: (30.0 GB/27.9 GiB)
[    1.827427] sd 0:0:0:0: [sda] Write Protect is off
[    1.832812] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[    1.843621]  sda: sda1
[    1.847381] sd 0:0:0:0: [sda] Attached SCSI dis

To use the SATA device for booting, press the SW1 button on startup and enter the U-Boot command prompt. Change the default 'bootcmd' to instead load from SATA by running:

env set bootcmd 'run sataboot';
env save;

On startup now the "SD boot" jumper will be ignored and the unit will boot straight to SATA.

Supervisory Microcontroller

The TS-7970 includes a supervisory microcontroller to provide 3 functions:

  • ADC channels
  • Sleep Mode
  • USB Console (/dev/ttymxc0)
  • RTC (REV H and beyond only)

Prior to REV H boards, this was using a Silicon labs microcontroller, and on REV H and later this is using a Renesas Microcontroller. These behave the same, but the REV H uses a different USB driver. REV E and below use the Silicon Labs CP201x driver. This is present on most Linux distributions. On Windows this is available with a WHQL signed driver from Silabs. REV H and beyond use the standard CDC-ACM class device which is also present in both Linux and Windows by default.

The RTC on REV E and earlier is an Intersil ISL12020. On REV H and beyond, the RTC functionality is provided by the Renesas Microcontroller using the same Register set as the intersil. While this is capable of keeping time and providing the same NVRAM functionality as the original part, it does not support the same temperature compensation as the original part. The original intersil RTC part could achieve less than ±5ppm drift across temperature, while the Renesas microcontroller is less than ±20ppm. Contact us if you require the higher accuracy.

The microcontroller exists at address 0x10 on I2C bus 0 using 8-bit address and data. It can be read for up to 32 bytes to get the ADC values, and firmware revision. Our example code 'tsmicroctl -i' includes reading all the ADC channels in millivolts and the firmware revision. For example:

 # tsmicroctl -i
 VDD_ARM_CAP=1026
 VDD_HIGH_CAP=2603
 VDD_SOC_CAP=1239
 VDD_ARM=1451
 SILAB_P10=0x0
 SILAB_P11=0x0
 SILAB_P12=0x0
 VIN=4779
 V5_A=5189
 V3P1=3230
 DDR_1P5V=1559
 V1P8=1904
 V1P2=1259
 RAM_VREF=778
 V3P3=3522
 SILABREV=1

In U-Boot, the 'tsmicroctl' command can be used (with no arguments) to read the same values.

The sleep mode is accessible from U-Boot with 'tsmicroctl <seconds>' and in Linux with 'tsmicroctl -s <seconds>'. This will power off everything on the board except the microcontroller.

The original Silicon Labs would sample all ADC channels in a 10-bit scale of 0-2.5V. On the Renesas microcontroller, this is now a 12-bit scale of 0-3.3V. The Renesas scales these down to the old ranges/values to match the original Silicon Labs ADC output. To scale for real millivolts the code should be written assuming the resistor dividers from REV E, as well as a 0-2.5V VREF and 10-bits. This is already supported in tsmicroctl.c.

The microcontroller samples all ADC channels in a scale of 0-2.5 V. The schematic shows the voltage dividers to bring the higher voltages it samples into this range.

Silabs Read Registers
Register Description
0 VDD_ARM_CAP MSB
1 VDD_ARM_CAP LSB
2 VDD_HIGH_CAP MSB
3 VDD_HIGH_CAP LSB
4 VDD_SOC_CAP MSB
5 VDD_SOC_CAP LSB
6 VDD_ARM MSB
7 VDD_ARM LSB
8 SILAB_P10 MSB
9 SILAB_P10 LSB
10 SILAB_P11 MSB
11 SILAB_P11 LSB
12 SILAB_P12 MSB
13 SILAB_P12 LSB
14 VIN MSB
15 VIN LSB
16 V5_A MSB
17 V5_A LSB
18 V3P1 MSB
19 V3P1 LSB
20 DDR_1P5V MSB
21 DDR_1P5V LSB
22 V1P8 MSB
23 V1P8 LSB
24 V1P2 MSB
25 V1P2 LSB
26 RAM_VREF MSB
27 RAM_VREF LSB
28 V3P3 MSB
29 V3P3 LSB
30 Firmware Revision

Supervisory Microcontroller Sleep Mode

The TS-7970 implements a very low power sleep mode using the onboard supervisory microcontroller. This allows powering off the i.MX6 CPU entirely. While in this mode the entire board will consume about 22 mW.

The board can wake 4 ways:

  • Timer - sleep mode requires specifying an amount of seconds to sleep (up to 16777215).
  • SW1 - Pressing the button on the side of the board.
  • PUSH_SW# goes low on HD1. The SW1 signal is brought to the header so connected cards can wake the TS-7970.
  • RTC Alarm (REV H and newer). Can wake if the RTC alarm triggers.

The sleep mode can be entered by calling 'tshwctl --sleep 60' to sleep for 60 seconds, but this typically should not be called directly. This would be equivalent to disconnecting power while booted which can cause data loss.

The Yocto, Debian, or Ubuntu distributions use systemd to manage shutdown. When systemd shuts down it will call all executables in the "/lib/systemd/system-shutdown/". Create a script with the name of "micro-sleep" in said directory with these contents:

#!/bin/bash

tsmicroctl --sleep 60

And make it executable:

chmod a+x /lib/systemd/system-shutdown/micro-sleep

Now the board will sleep immediately following a shutdown. It is safe during the sleep mode to disconnect power without risking data.

SPI

The CPU has 1 SPI port available on an external interface. This can be manipulated via either specific kernel drivers, or userspace using the "/dev/spidev" interface. On the TS-7970 these are exposed as "/dev/spidev1.1" (FPGA) and "/dev/spidev1.2" (HD1) in userspace.

The "/dev/spidevX.Y" device nodes are created where X is the controller and Y is the chip select used. See the compiling the kernel section for information on setting up a build environment. Any GPIO can be used as another SPI chip select by modifying the device tree. No more than 4 chip selects can be used with the i.MX6 SPI controller. For example in "arch/arm/boot/dts/imx6qdl-ts7970.dtsi":

&ecspi2 {
	fsl,spi-num-chipselects = <3>;
	cs-gpios = <&gpio5 31 0>, <&gpio7 12 0>, <&gpio5 18 0>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_ecspi2>;
	status = "okay";

	serial1: max3100-1@0 {
		compatible = "max3100-ts";
		reg = <0>;
		interrupt-parent = <&gpio1>;
		interrupts = <4 2>;
		spi-max-frequency = <1000000>;
		loopback = <0>;
		crystal = <1>;
		poll-time = <100>;
		fifo-size = <16>;
	};

	spidevfpga: spi@1 {
		compatible = "spidev";
		reg = <1>;
		spi-max-frequency = <1000000>;
	};

	spidevhd1: spi@2 {
		compatible = "spidev";
		reg = <2>;
		spi-max-frequency = <1000000>;
	};
};

This bus is shared with the on-board FPGA UARTs (/dev/ttyMAX*). The "spidevfpga" node is intended for customized FPGA communication. The "spidevhd1" node is for general use on the HD1 external interface.

UARTs

This board uses UARTs from both the CPU and the FPGA. The CPU UART 0 (/dev/ttymxc0) is a dedicated console for Linux and U-Boot and not suggested to be reused. The other CPU UARTs for ttymxc1 through ttymxc4 are usable for end applications. These support up to 5Mb/s UART data with DMA.

The FPGA also emulates a MAX3100 UART interface accessible at /dev/ttyMAX0-2. These UARTs support a total throughput of about 115200[1]. These UARTs include hardware that makes implementing RS-485 half duplex software extremely simple. If higher throughput is needed, the FPGA crossbar can be adjusted to use a CPU UART with TXEN support instead.

Note: Our SPI interface matches the max3100 almost entirely, except optionally a single 8-bit transaction can be sent to act as a chip select between the three uarts supported on our interface. The default FPGA supports 3 UARTs on this interface. This is handled automatically by our driver (max3100-ts).

The RS-485 half duplex direction control is built into the ttyMAX UARTs. By default, they are connected to the RS-485 ports and no code is required for the transmit enable to toggle. The CPU UARTs however do not have transmit enable built in. The FPGA provides support for transmit enable on ttymxc1/ttymxc3, but additional setup steps are required so the FPGA can properly time the transmit enable output. The FPGA needs to know the baud rate, and symbol size (data bits, parity, stop bits) that the UART will be run at

For example:

# Configure ttymxc1 and ttymxc3 as 115200, 8n1

stty -F /dev/ttymxc1 115200 cs8 -cstopb
tshwctl --autotxen 1

stty -F /dev/ttymxc3 115200 cs8 -cstopb
tshwctl --autotxen 3

The 'tshwctl' tool will read the UART settings and set up the FPGA timing for TXEN automatically. The baud rate and mode settings must be set before running the 'tshwctl' command!

When using the FPGA for either the ttyMAX UARTs or the CPU UARTs, the TXEN timing will happen well under a single bit time [2] of any baud rate possible by the hardware.

All of these UARTs are accessed using the standard /dev/ interfaces. See these resources for information on programming with UARTs in Linux.

  1. Idle periods do not count towards the total throughput limitation.
  2. This is a requirement for half duplex MODBUS

The #FPGA includes a crossbar to select where UARTs are routed so these can be changed, but these are the default mappings:

UART Type TX (or +) RX (or -)
ttymxc0 USB USB Device USB Device
ttymxc1 1.8V TTL (onboard only) Onboard Bluetooth RX Onboard Bluetooth TX
ttymxc2 TTL (5V Tolerant) HD1 Header pin 12 HD1 Header pin 10
ttymxc3 RS232 COM2 Header pin 3 COM2 Header pin 2
ttymxc4 RS232 P1-B Terminal Block pin 7 P1-B Terminal Block pin 8
ttyMAX0 RS485 P1-A Terminal Block pin 2, COM2 Header pin 1 P1-A Terminal Block pin 3, COM2 Header pin 6
ttyMAX1 RS485 RJ45 2W-Modbus pin 4 RJ45 2W-Modbus pin 5
ttyMAX2 RS232 COM2 Header pin 7 COM2 Header pin 8

USB

USB OTG

This SBC includes support to act as a USB peripheral to another system. Remove the "CON EN" jumper to disable the on-board USB serial debug port and connect the USB device port to the CPU's OTG port. The CPU port is strapped to only act as a USB device. Several devices are compiled into the default kernel. Other devices can be compiled into the kernel by following the compile the kernel section.

USB Serial

modprobe g_serial use_acm=1

This will create the device "/dev/ttyGS0". See the kernel documentation for more information:

USB Ethernet

modprobe g_ether

This provides a "usb0" network interface. This driver simulates an Ethernet network connection between the host PC and the i.MX6.

USB Host

The i.MX6 provides 1 USB Host with supporting USB 2.0 (480Mbit/s). The TS-7970 includes a USB Hub expanding this to 4 USB host ports.

Typically USB is interfaced with by using standard Linux drivers, but low level USB communication is possible using libusb.

The TS-7970 USB 5V rail can be toggled on/off through a GPIO. This can be used to save power, or to reset USB devices that get stuck in a bad state.

# Power disabled
echo 1 > /sys/class/leds/en-usb-5v/brightness
sleep 2 # let any devices reset
# Enable power
echo 0 > /sys/class/leds/en-usb-5v/brightness
Note: The USB OTG which can act as a host does not always use the same controllable 5V supply. Refer to the schematic's EN_USB_5V/USB_5V for more information on this control.

Watchdog

The CPU's watchdog timer is a hardware component that helps ensure the stability and responsiveness of the system. It does this by resetting the system if it detects that a certain process or application is not functioning as expected. If the watchdog timer is not regularly reset or "fed," it will expire and trigger a system reset.

By default, the watchdog timer has a timeout period of 60 seconds. However, it is powered by a ring oscillator that may not be perfectly accurate, meaning the timer may expire more quickly than expected. To ensure that the watchdog timer does not expire prematurely, it should be reset or "fed" at least 4 times more frequently than its configured timeout period. For example, if the timeout is set to 60 seconds, the watchdog should be reset at least every 15 seconds.

The kernel provides an interface to the watchdog driver at /dev/watchdog. This interface can be used to enable the watchdog timer by feeding it from an application. For more information on using the watchdog timer, refer to the kernel documentation at the following links:

WIFI

The TS-7970 releases prior to F included the LSR TIWI-BLE using the TI wl1271 chipset. When this went end of life the rev E boards were changed to support the Silex SX-SDMAC2832S+ module based on the QCA9377 chipset.

Silex WIFI (Rev F or later)

This board uses the Silex SX-SDMAC2832S+ based on the Qualcomm QCA9377 chipset.

Key Features:

  • FCC/IC/CE/MIC Modular Certification
  • Dual band, 2.4GHz and 5GHz
  • Station, AP, and Monitor mode
  • 802.11 a/b/g/n/ac
  • Bluetooth 4.2 (BD/EDR/LE)
  • -40 to 85C operation

Linux uses the "wireless-tools", "wpa-supplicant", and "hostapd" packages to support most of the functionality in this module. Refer to the distribution support for #Yocto, #Debian, or #Android for more information.

The module can be put in monitor mode where it can capture packets. The driver must be loaded with connection mode 4 to support this:

modprobe -r wlan
modprobe wlan con_mode=4
ifconfig wlan0 up
iwpriv wlan0 setMonChan 36 2
tcpdump -i wlan0 -w test.pcap

This will generate a test.pcap that includes raw wireless frames.

TI WIFI (Rev E or earlier)

This board includes a TiWi-BLE SDIO module that uses the Texas Instruments WL1271L Transceiver. Linux provides support for this using the wl12xx driver. See the LSR site for detailed product information.

Summary Features:

  • IEEE 802.11 b/g/n
  • 2.4GHz
  • Linux drivers include support for client and AP mode
  • Host up to 8 clients on AP
  • Industrial temp, -40 to 85C
  • Certifications
    • FCC Bluetooth® Grant
    • FCC WLAN Grant
    • IC
    • CE
    • SAR Testing
    • SAR Testing EU

Linux uses the "wireless-tools", "wpa-supplicant", and "hostapd" packages to support most of the functionality in this module. Refer to the distribution support for #Yocto, #Debian, or #Android for more information.

External Interfaces

Audio

The TS-7970 includes two 3.5mm jacks. The top port is a mono microphone input, and the bottom port is a headphone port with left and right channels. Use "alsamixer" or "amixer" to adjust the volume.

In Linux select between the HDMI and 3.5mm ports with an alsa variable. By default all audio comes out of the sgtl5000 for the 3.5mm ports.

# list the sound cards
aplay -l

export ALSA_CARD=imxhdmisoc
espeak "this is playing from the HDMI monitor"


## On kernel 4.1:
#export ALSA_CARD=imx6qts7970sgtl
## On kernel 4.9
export ALSA_CARD=Codec
espeak "this is playing from the onboard sgtl5000"

COM2 Header

The COM2 header is a 2x5 0.1" pitch header with RS485, CAN, and RS232.

Pin # Description
1 STC_485+ (/dev/ttyMAX0)
2 RS232 RXD (/dev/ttymxc3)
3 RS232 TXD (/dev/ttymxc3)
4 CAN_1_H (can0 interface)
5 GND
6 STC_485- (/dev/ttyMAX0)
7 RS232 TXD (/dev/ttyMAX2)
8 RS232 RXD (/dev/ttyMAX2)
9 CAN_1_L (can0 interface)
10 NC

Ethernet

The TS-7970 includes two 10/100/1000 Ethernet ports. The port with the larger connector uses the FEC MAC from the CPU with a Marvell PHY. The other smaller optional port is a PCIe Intel I210 chipset.

Under Linux the CPU ethernet is typically eth0, and depending on the distribution the second ethernet is either eth1 or enp1s0.

The CPU and I210 both receive unique sequential mac addresses. These are pulled from the Technologic Systems OUI "00:D0:69". Both chipsets support downshifting if some of the twisted pairs are missing connection.

On both Ethernet ports the right LED indicates speed. It is on for gigabit, and off for 10/100. The left LED will blink on activity.

See the #Debian_Networking for configuring the network on the default distribution.


I210 PTP

The Intel i210 ethernet supports 1588 PTP (V1 & V2).

This is supported in Linux with the linuxptp project. This will synchronize the Linux system clock to within ±1 us.

This requires using an image based on the Linux 4.9+ kernel.

apt-get install linuxptp -y

phc2sys -s /dev/ptp1 -w &
ptp4l -2 -H -i enp0s1 -m -p /dev/ptp1 &

If the clocks are significantly off this may take time for the clocks to converge.

HDMI

The TS-7970 includes an HDMI 1.4 port which supports EDID for automatically configuring the video modes on your monitor, and HDMI audio. In Linux this will be /dev/fb0. The HDMI is capable of outputting up to 1080p60.

Under either distribution the mode will default to the largest and highest refresh rate compatible with both the monitor and the i.MX6. You can override this in yocto with xrandr, or under debian/ubuntu/yocto with a kernel cmdline change. Hold SW1 when power is applied and the board will stop at u-boot. Run these commands to override the EDID settings and use 1024x768M@60.

env set cmdline_append "console=ttymxc0,115200 rootwait ro init=/sbin/init video=mxcfb0:dev=hdmi,1024x768M@60,if=RGB24" 
env save

HDMI to VGA/DVI-A adapters are possible to use with the TS-7970, but the port protection chip strictly follows the HDMI standard. Some adapters are known to violate the standard and try to pull too much power off of the HDMI port. For an adapter to work it should accept a separate power input such as a microUSB port. The TS-7970 can still power the adapter through USB, but the HDMI header should not be used for sourcing current.


Rotate the video output

Under Yocto you can use xrandr to rotate the screen:

export DISPLAY=:0 
xrandr --rotate left
xrandr --rotate right
xrandr --rotate normal
xrandr --rotate inverted

Under Debian or Ubuntu you can rotate the screen in the Xorg.conf. Edit the file /etc/X11/xorg.conf and append this to the end:

Section "Device"
    Identifier      "fbdev display"
    Driver          "fbdev"
    Option "Rotate" "CCW"
EndSection

After the display is rotated you will also need to rotate a touchscreen if this is being used. This example matches the CCW rotation, but swapaxes or the invertx/y options will need to be adjusted for other rotations.

Section "InputClass"
       Identifier "axis inversion"
       MatchIsTouchscreen "true"
       # swap x/y axes on the device. i.e. rotate by 90 degrees
       Option "SwapAxes" "on"
       # Invert the respective axis.
       Option "InvertX" "on"
       Option "InvertY" "off"
EndSection

On newer X11 releases libinput is used instead of the evdev driver. To rotate with Debian 10 and above this will require changing the coordinate transormation matrix. Edit /etc/X11/Xsession.d/10x11-ts-calibration and add the transformation matrix for your rotation to the end of the script. Eg, for clockwise rotations add:

xinput set-prop "ADS7846 Touchscreen" 'Coordinate Transformation Matrix' 0 -1 1 1 0 0 0 0 1

HD1

HD1 is a 2x12 0.10" pitch header including DIO, USB, SPI, an IRQ, 3.3V, and 5V. All GPIO are 3.3V tolerant unless otherwise specified.

The USB port on this header is normally the top USB port near the Ethernet connectors. This can instead by routed to this header by changing the mux:

# Select HD1 USB
echo 1 > /sys/class/leds/sel_dc_usb/brightness
# Select external type A USB port
echo 0 > /sys/class/leds/sel_dc_usb/brightness
Pin # GPIO Number Description
1 N/A PUSH_SW#
2 246 HD1_DIO_4
3 N/A GND
4 245 HD1_DIO_3
5 N/A GND
6 244 HD1_DIO_2
7 124 DISP0_DAT7
8 243 HD1_DIO_1
9 127 DISP0_DAT10
10 224 (input only) ttymxc2 RXD
11 N/A USB host data-
12 236 ttymxc2 TXD
13 N/A USB host data+
14 133 DISP0_DAT11
15 N/A 5V
16 N/A 5V
17 282 SPI_2_CLK
18 284 SPI_2_MISO
19 146 HD1_SPI_CS#
20 283 SPI_2_MOSI
21 126 HD1_IRQ
22 248 HD1_DIO_6
23 N/A 3.3V
24 247 HD1_DIO_5


HD2

HD2 is a 0.10" pitch header.

Pin # Description
1 GND
2 EIM_DA0 (GPIO #64)
3 EIM_LBA (GPIO #59)
4 EIM_DA1 (GPIO #65)
5 EIM_CS0 (GPIO #55)
6 EIM_DA2 (GPIO #66)
7 EIM_DA4 (GPIO #68)
8 EIM_DA3 (GPIO #67)
9 EIM_DA5 (GPIO #69)
10 EIM_EB1 (GPIO #61)
11 EIM_WAIT (GPIO #128)
12 EIM_A24 (GPIO #132)
13 EIM_DA6 (GPIO #70)
14 EIM_DA10 (GPIO #74)
15 EIM_DA7 (GPIO #71)
16 EIM_DA8 (GPIO #72)
17 EIM_DA9 (GPIO #73)
18 EIM_DA15 (GPIO #79)
19 EIM_DA13 (GPIO #77)
20 EIM_DA14 (GPIO #78)
21 EIM_DA12 (GPIO #76)
22 EIM_RW (GPIO #58)
23 3.3V supply
24 EIM_DA11 (GPIO #75)


HD3

HD3 is a 2x8 0.10" pitch header including LVDS, I2C, 3.3V and 5V which can be used to connect up a third party display.

Pin # Description
1 LVDS0_TX1_N
2 LVDS0_TX1_P
3 3.3V supply
4 LVDS0_TX0_N
5 LVDS0_TX0_P
6 5V Supply
7 LVDS0_CLK_N
8 LVDS0_CLK_P
9 GND
10 LVDS0_TX2_N
11 LVDS0_TX2_P
12 GND
13 LVDS0_TX3_N
14 LVDS0_TX3_P
15 I2C 2 CLK
16 I2C 2 DAT


Mini Card Connector

The TS-7970 includes a mini card header which includes USB and power like a mini pcie header. It does not include a PCIe bus. Many peripherals, such as cell modems, do not actually need the PCIe bus and instead use the USB host which is present on this header.

This connector uses a mounting screw M2 x 0.4mm thread, 4mm long. For example, 92005A016.

This port also supports mSATA which can be used for higher capacity drives.

Note: SATA is not available on the i.MX6 solo or duallite processors.

Push Button

The push switch is accessed by reading FPGA registers:

tshwctl --addr 31 --peek

With no press bit 2 will be set so it will return "addr31=0x4". If there is a press it will be cleared, so "addr31=0x0".

This pin is sampled in u-boot to detect if it should stop in u-boot and look for usb updates. If this interferes with your intended usage you can boot to u-boot and disable this by running:

env delete preboot;
env set bootdelay 1;
env save;

After this change u-boot will wait 1 second on every boot for the user to press ctrl+c to break into u-boot on startup.

RJ45 2W-Modbus

The 2W MODBUS port follows a standard pinout:

Note: MODBUS power output cannot be used when powering the TS-7970 from 5 V directly. The 8-28 V input must be used and that input voltage will be made available on the MODBUS jack.

The RS-485 port on pins 4 and 5 is accessed with /dev/ttyMAX1.

The MODBUS_FAULT signal (gpio 57) is used to determine if there is a dead-short on the MODBUS power pins. This enables the developer to detect a line problem before turning potentially damaging power onto the line. The method of checking this is to set EN_MODBUS_3V#, then read MODBUS_FAULT. If MODBUS_FAULT is high, then there is a problem with the cabling or device to be powered and EN_MODBUS_24V# should not be asserted.

# EN_MODBUS_24V# 51
# EN_MODBUS_3V# 122
# MODBUD_FAULT 57
echo 51 > /sys/class/gpio/export
echo 122 > /sys/class/gpio/export
echo 57 > /sys/class/gpio/export

# Test line with 3.3 V to see if the power pins are shorted
echo "low" > /sys/class/gpio/gpio122/direction # EN_MODBUS_3V# is active low.

# Read mb_fault
echo "in" > /sys/class/gpio/gpio57/direction
cat /sys/class/gpio/gpio57/value
# If returns 1, do not continue.

# Switch 3 V off pins 6 and 7:
echo 1 > /sys/class/gpio/gpio122/value

# Switch VIN to pins 6 and 7:
echo high > /sys/class/gpio/gpio51/direction

Terminal Blocks

The TS-7970 includes two removable terminal blocks (OSTTJ0811030) for power, UARTs, CAN, and other general purpose IO.


P1-A
Pin # Description
1 Ground
2 STC_485+ (/dev/ttyMAX0)
3 STC_485- (/dev/ttyMAX0)
4 STC_CAN_2_H (can1 interface)
5 STC_CAN_2_L (can1 interface)
6 Power Input (8-28VDC)
7 Power Input (5VDC)
8 Ground [1]
P1-B
Pin # Description
1 Ground
2 AD_P10 (4-20mA analog input)
3 AD_P11 (4-20mA analog input)
4 AD_P12 (4-20mA analog input)
5 DIO_1 (30 VDC I/O)[2]
6 DIO_2 (30 VDC I/O)[2]
7 RS-232_STC_TXD (/dev/ttymxc4)
8 RS-232_STC_RXD (/dev/ttymxc4)
  1. This ground should be used for the power supply since it includes a ferrite bead to help suppress noise.
  2. 2.0 2.1 See DIO Usage below for operational details of these I/O pins

DIO Usage

The DIO_1 and DIO_2 IO can be outputs, or inputs. As inputs the digital threshold is 1.2V. To guarantee low it must be < 0.5V, or for high > 2.0V. When the IO is low the external device needs to sink up to 3.5mA. When the IO is high the external device needs to source 10 uA max. There is an internal 1.5k pullup to 5V that will bias the input high. As outputs these IO can sink up to 500mA.

EN_DIO_1 and EN_DIO_2 outputs are controlled through FPGA DIO 249 and 250 respectively. See the #GPIO section for more information. If these pins are specified as low or in, then they are readable on FPGA reg 56 bits 7:6.

DIO_1 and DIO_2 are accessed through FPGA registers.

tshwctl --addr 56 --peek

# read "addr56" into bash variable
eval $(tshwctl --addr 56 --peek)

# Read bit 7 for DIO1
echo $(($addr56 >> 7))

# Read bit 6 for DIO2
echo $((($addr56 >> 6) & 0x1))

USB Device

The USB type B device port is connected to the onboard Silabs for USB to serial console, or to the CPU's #USB OTG. The USB functionality is picked from the "CON EN" jumper.

Note: Previous to REV C TS-7970, the USB device port can prevent the CPU from booting up if "CON_EN" is removed, and USB is plugged in before CPU power is connected. As a workaround on earlier revs you can cut the red wire from your USB cable.

USB Hosts

The TS-7970 includes 4x USB 2.0 ports. The top port on the USB Type A connector (J2) near the audio jack is run in parallel with the Mini Card Connector. If the Minicard is used, the top port of J2 should not be connected to an external device.

Specifications

Power Specifications

The TS-7970 supports two methods for power input. There are separate 5 V and 8-28 V inputs. Only one of these may be provided to the at any time; supplying both inputs may cause damage to the TS-7970 or power supplies.

Input Min voltage Max voltage
5 V input 4.75 V 5.25 V
8-28 V Input 8.00 V 28.00 V

Power Consumption

The i.MX6 power consumption can vary a lot depending on the build and activity of the board. Most of the power savings happens automatically when the CPU and GPU are idle. It is also possible to disable the Ethernet PHY for extra savings.

# Put ETH PHY in reset
echo 116 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio116/direction

# Put USB HUB in reset
echo 43 > /sys/class/gpio/export
echo low > /sys/class/gpio/gpio43/direction

Ethernet is not connected unless otherwise specified. Serial is disconnected during the measurement. The CPU test is 5x processes of "openssl speed". The GPU test is Qt5CinematicExperience in the Yocto image.

These tests are performed powering the board through 5V.

TS-7970 solo without WIFI or I210
Test Max Watts Average Watts
CPU 100% + GPU loaded (LCD 100%) + IO + Ethernet + HDMI 4.50 (0.90 A) 3.40 (0.68 A)
CPU 100% 2.80 (0.56 A) 2.35 (0.47 A)
CPU Idle + HDMI 2.75 (0.55 A) 2.05 (0.41 A)
CPU Idle + CPU Ethernet 2.75 (0.55 A) 2.20 (0.44 A)
CPU Idle 2.50 (0.50 A) 1.95 (0.39 A)
CPU Idle USB HUB off 2.75 (0.55 A) 1.95 (0.39 A)
CPU Idle USB HUB off, Ethernet PHY in reset 2.15 (0.43 A) 1.60 (0.32 A)
Using onboard uC to sleep CPU 0.025 (125 mA) 0.022 (4.4 mA)
TS-7970 quad core with WIFI and I210
Test Max Watts Average Watts
CPU 100% + GPU loaded (LCD 100%) + IO + Ethernet + HDMI 10.80 (2.16 A) 7.75 (1.55 A)
CPU 100% 6.15 (1.23 A) 5.40 (1.08 A)
CPU Idle + HDMI 4.55 (0.91 A) 2.90 (0.58 A)
CPU Idle + WIFI on wpa2 running iperf 6.85 (1.37 A) 3.95 (0.79 a)
CPU Idle + CPU Ethernet 5.00 (1.00 A) 3.10 (0.62 A)
CPU Idle + PCIe Ethernet 3.60 (0.72 A) 2.85 (0.57 A)
CPU Idle 4.85 (0.97 A) 2.80 (0.56 A)
CPU Idle USB HUB off 3.50 (0.70 A) 2.75 (0.55 A)
CPU Idle USB HUB off, Ethernet PHY in reset 3.30 (0.66 A) 2.40 (0.48 A)
Using onboard uC to sleep CPU 0.025 (125 mA) 0.022 (4.4 mA)

Temperature Specifications

The i.MX6 CPUs we provide off the shelf are either a solo industrial, or quad core extended temperature. The TS-7970 is designed using industrial components that will support -40C to 85C operation, but the CPU is rated to a max junction temperature rather than an ambient temperature. We expect the solo to work to 80C ambient while idle with a heatsink and open air circulation. To reach higher temperatures with this or other variants of this CPU some custom passive or active cooling may be required.

Model Number Operating Min Cooling Temp [1] Passive Temp [2] Critical/Max Junction Temp [3]
TS-7970-*S8S* -40C 75C 85C 105C
TS-7970-*Q10S* -20C 75C 85C 100C
  1. CPU stops all throttling below this temperature
  2. CPU begins throttling until the cooling temperature
  3. CPU Max temperature. Linux will shut down to cool in u-boot at this temperature.

Our test data can be used to estimate the temperature rise of the CPU over the ambient temperature. These are tested without an enclosure in open air. The temp ranges show the CPU at idle at the low end, to a very high system load at the high end.

Configuration Temp rise over ambient
Solo No Heatsink 21-27C
Solo with HS-50x53x13 18-20C
Quad No Heatsink 16-50C
Quad with HS-50x53x13 10-23C

For custom builds these are also exposed in /sys/:

# Passive
cat /sys/devices/virtual/thermal/thermal_zone0/trip_point_0_temp
# Critical
cat /sys/devices/virtual/thermal/thermal_zone0/trip_point_1_temp

The current CPU die temp can be read with:

cat /sys/devices/virtual/thermal/thermal_zone0/temp

When the CPU heats up past the cooling temp on a first boot, it will take no action. Heating up past the passive temperature the kernel will cool down the CPU by reducing clocks. This will show a kernel message:

[  158.454693] System is too hot. GPU3D will work at 1/64 clock.

If it cools back down below the cooling temperature it will spin back up the clocks.

[  394.082161] Hot alarm is canceled. GPU3D clock will return to 64/64

If it continues heating to the critical temperature it will overheat and reboot. Booting back up u-boot will block the boot until the temperature has been reduced to the Cooling Temp+5C. This will be shown on boot with:

U-Boot 2015.04-07857-g486fa69 (Jun 03 2016 - 12:04:30)

CPU:   Freescale i.MX6SOLO rev1.1 at 792 MHz
CPU Temperature is 105 C, too hot to boot, waiting...
CPU Temperature is 102 C, too hot to boot, waiting...
CPU Temperature is 99 C, too hot to boot, waiting...
CPU Temperature is 90 C, too hot to boot, waiting...
CPU Temperature is 86 C, too hot to boot, waiting...
CPU Temperature is 84 C, too hot to boot, waiting...
CPU Temperature is 80 C, too hot to boot, waiting...
CPU Temperature is 80 C, too hot to boot, waiting...
CPU Temperature is 80 C, too hot to boot, waiting...
CPU:   Temperature 78 C
Reset cause: WDOG
Board: TS-7970

These temperature tests show the TS-7970 with/without both the heatsink and enclosure. The HS-15x15x5 test data is provided as an example of a smaller heatsink, but this heatsink is not recommended for the TS-7970.

Temp Testing without enclosure

Temp Testing with enclosure

IO Specifications

The GPIO external to the board are all nominally 3.3V, but will vary depending on if they are CPU/FPGA pins.

The CPU pins can be adjusted in software and will have initial values in the device tree. This lets you adjust the drive strength, and pull strength of the IO. See the device tree for your kernel for further details on a specific IO.

The FPGA IO cannot be adjusted further in software.

IO Typical Range Absolute Max VIL Max[1] VIH Min[2] Drive strength
External CPU GPIO 0-3.3 V -0.5-3.6 V 0.99 V 2.31 V 27.5 mA
External FPGA GPIO 0-3.3 V -0.5-3.75 V 0.8 V 2.0 V 12 mA
  1. Maximum input voltage that will trigger a logic low
  2. Minimum input voltage that will trigger a logic high

Refer to the MachXO Family Datasheet for more detail on the FPGA IO. Refer to the CPU quad or solo datasheet for further details on the CPU IO.

WARNING: Do not drive any IO from an external supply until 3.3V is up on the board. Doing so can violate the power sequencing of the board causing failures.

Rail Specifications

The TS-7970 generates all rails from either the 8-28VDC input, or the 5V input. This table does not document every rail. This will only cover those that can provide power to an external header for use in an application.

Direct 5V input will bypass our regulator, but the absolute max a supply can provide 5A to the board.

Rail Current Available Location
3.3V 200mA [1] HD1 pin 23, HD2 pin 23, mPCIe, HD3 pin 3
5V Quad core 2A, Solo 3A [2] HD1 pins 15/16, HD3 pin 6, USB, mPCIe
  1. Contact us if you need more on this rail
  2. These limitations are only relevant if 8-28V is supplied into the board.

Revisions and Changes

TS-7970 PCB Revisions

Revision Changes
A
  • Initial Release
B
  • Changed U17 to support the MPU-9250 9 axis accelerometer
  • Changes TVS1 to use 4.7V_A
  • Fix I210 ethernet LED polarity
  • Use 153-ball eMMC to support bigger eMMCs on custom builds
  • Added PU from 5V_A to SW_5V. This prevents a negative leakage on the the SW_5V rail. If the rail has a negative voltage it will otherwise not switch on.
  • CPU pin U4 tied to ground. Used to detect REV B boards.
C
  • Not released
D
  • Changed PHY to Marvell 88E1512 due to published Microchip errata #9-10 which affects link reliability with some link partners.
Note: This change should be transparent in Linux from older kernels, but if link problems are seen from older images make sure the Marvell PHY driver is actually disabled as it does not configure this PHY correctly. The genphy driver will communicate correctly with this PHY. Earlier shipping images had this enabled, but current images keep this driver disabled
  • Changed to a larger Ethernet Magjack with separate centertaps as required by the PHY manufacturer.
  • CPU pin C13 tied to ground. Used to detect REV D boards.
  • Added two lane MIPI connector (CN1)
  • Changed to smaller battery holder
  • Pull USB_5V_DETECT on silabs low when CON_EN jumper is off. This fixes the bug on previous revisions which would cause the board to fail to boot when CON_EN is off and USB is connected on the P2 port before the TS-7970 is powered on.
  • Added PUSH_SW# to HD1 which allows a pin to wake the board out of sleep.
  • Changed pin 28 to Enable 2.5V REF to reduce power in silabs sleep mode
  • Improvements for our internal production
E
  • Minor changes for internal production.
  • H6 biased low to detect new rev
F
  • LSR TIWI-BLE Replaced with Silex SX-SDMAC2832S+
H
  • Due to parts availability, replaced Lattice MachXO2 with Lattice MachXO3.
  • Due to parts availability, replaced microcontroller Silabs 8051 with Renesas RA4M2
    • No software image changes to support any existing microcontroller features
    • For more details
  • Due to parts availability, the Intersil ISL12020 functionality is also provided by the same Renesas RA4M2.

U-Boot Changelog

Jun-17-2015
  • Added TS-7970 support
Jul-27-2015
  • Added fix for PCIe hang in Linux. Some of the GPR1 regs were not being reset after a reboot. U-boot will now reset these before going into Linux. This hang was not present on all CPUs, usually solo, and only if PCIe is enabled in the kernel.
Oct-07-2015
  • TS-7970 now has a POR on every reboot
  • TS-7970 can reload the FPGA from a /boot/ts7970.vme file
  • PUSH_SW is now read through i2c to free up FPGA_IRQ_1
May-09-2016
  • Updated to imx_v2015.04_3.14.52_1.1.0_ga branch
  • Updated DDR config to latest NXP recommendations
  • Includes new thermal driver. If the CPU has overheated and rebooted it will wait in u-boot until the system cools down to the temperature specified in the thermal fuses. These are adjustable one time in software.
  • Disabled NFS umountall
May-27-2016
  • Added tsmicroctl command to read adc values, or start the sleep mode for the board. Requires a silabs from May 27th 2016 or later to include the sleep mode.
  • Added FPGA_RESET# through a signal rather than a FPGA POR. Requires FPGA REV 5 for FPGA reset to work correctly.
WARNING: Do not update past this u-boot without having REV 5 of the FPGA or the FPGA will not be reset on startup.
Jun-03-2016
  • Added suggested fixes for Micrel PHY errata.
  • Added FPGA and Silabs revision to startup output.
Jan-11-2017
  • Added REV D support
  • Added Marvell PHY support
  • Allow solo to boot at 85C instead of 80C, quad is still 80C.
Feb-17-2017
  • Added check for 64bit ext4 filesystem.
Mar-27-2017
  • Changed string to indicate REV D/E for new boards.
  • Added I2C recovery improvements for fixing stuck bus
Mar-23-2018
  • Add support for SST26VF064BA, and IS25LP064A spi flashes
Nov-14-2018
  • Reduced USB block size to 256B to improve compatibility with USB thumbdrives.
Mar-31-2020
  • Added support for the new TS-7970 revisions
Oct-06-2022
  • Added support for detecting REV H PCBs

FPGA Changelog

Check the FPGA rev with:

echo $(($(tshwctl --peek --addr 51)>>4))
Rev Changes
0
  • Initial Release
1
  • Switched max3100 to use FPGA_IRQ_1 to leave FPGA_IRQ_0 to the silabs.
2
  • Corrected CTS/RTS polarity on MAX3100
  • Corrected flipped CPU UART CTS/RTS for bluetooth
  • Corrected HD1 SPI bus
3
  • Disabled pulldown on HD1 SPI CS.
4
  • Fixed the FPGA ttyMAX* uarts
5
  • The signal FPGA_IRQ_0 is now FPGA_RESET which needs to be pulsed on reset by u-boot. This is implemented in the May-27-2016 release.
  • Register 61, bit 1 is now used to force SPI at all times on the HD1 SPI pins rather than just on chip select assert. This should allow any GPIO to be used as chip selects.
6
  • Disables USB HUB 24mhz while in reset
7
  • Includes support for REV D pin changes.
11
  • Fix for CPU UART TXEN behavior. ttyMAX uarts are not affected.
12
  • Migrated to Mach XO3

Using the u-boot from Oct-07-2015 or later you can reload the FPGA during startup for custom FPGAs. During startup you will see u-boot reload this file:

Bytes transferred = 56341 (dc15 hex)
VME file checked: starting downloading to FPGA
Diamond Deployment Tool 3.5
CREATION DATE: Wed Oct 07 11:38:24 2015


Downloading FPGA 53248/56341 completed
FPGA downloaded successfully

Supervisory Microcontroller Changelog

Revision Changes
0
  • Initial Release
1
  • Added Sleep mode
  • Blinks blue LED in low power modes. Sleep mode does this, as well as USB device connected with no power on the main VIN.
2
  • Added support for REV D boards. Earlier boards will continue to use REV 1 only.
3
  • Fixed Silabs not responding on I2C after sleep mode is used.
4
  • This revision prevents USB suspend from putting the silabs into a low power state. In previous versions if a USB cable is connected, but the serial console is not open, then some operating systems will issue a USB suspend. This would prevent communication over the I2C to the silabs.
5
  • Port to Silicon Labs EFM8 series
6
  • Initial migration to Renesas RA4M2 series.
7
  • Support for in the field updates
  • USB Serial number set to board Serial/MAC address
  • Sleep mode bug fixes
8
  • Prevent RTC/SRAM writes as power is dropping to prevent corruption
  • USB CDC ACM fixed issues with dropped characters. REV 8 will not drop any data in TX/RX at 115200 baud.
9
  • RTC write fixes
10
  • Added support for disabling internal RTC if vbatt is < 2V so we can support optional population of the real ISL RTC for custom populations
  • RTC bug fixes
11
  • Fixed RTC bug that can prevent reboot
12
  • Fixed CDC ACM bug that resulted in large amounts of interrupts on the host system
13
  • Added support for configurable RTC offsets to calibrate RTC.
14
  • Fix CDC-ACM to fix support with some USB UART clients on Windows 10 after a Windows Update.
    • Putty, Realterm, and possibly others would refuse to open the port.
    • Teraterm was not affected
    • Windows 11 is not affected so far
    • Linux connectivity is not affected
15
  • Fixed regression with lowest power sleep mode with USB disconnected. This fix is required to wake back up from sleep.
16
  • Fixed issue with SW1 wake from sleep when usb is connected.

The current revision can be checked with:

tsmicroctl -i
# or
tssupervisorupdate -i

Supervisory Microcontroller Updates

The TS-7970 REV H running microcontroller rev 7 and newer can update the microcontroller version in the field with safe atomic updates that can be shipped as part of your software image. This is safe to include on images that will be run with the older Silicon Labs microcontroller where it will skip the update, and only perform the update on boards that need it.

wget https://files.embeddedts.com/ts-arm-sbc/ts-7970-linux/supervisory-firmware/tssupervisorupdate-static-v1.1.0
wget http://files.embeddedts.com/ts-arm-sbc/ts-7970-linux/supervisory-firmware/ts7970-micro-update-latest.bin

chmod a+x tssupervisorupdate-static-v1.1.0
./tssupervisorupdate-static-v1.1.0 -u ts7970-micro-update-latest.bin

The static binary should run in most environments, but the sources are available here if a recompile is necessary.

Software Images

Yocto Changelog

Quad/Dual Image Solo/Duallite Image Changes
ts-x11-image-ts4900-quad-20140905235640.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20140908160116.rootfs.tar.bz2
  • Initial Release
ts-x11-image-ts4900-quad-20141119190447.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20141119204157.rootfs.tar.bz2
  • Systemd default
  • Added /usr/lib/openssh/sftp-server (Fixes QtCreator/Eclipse deploy)
  • Added QtQuick
  • Added Sqlite to QT
  • Added early TS-7970 support.
  • Updated kernel with significant fixes, see github for more information.
ts-x11-image-ts4900-quad-20141224171440.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20141224175107.rootfs.tar.bz2
  • Updated Kernel
    • Fixed ISL RTC errors hardware builds that omit the RTC
    • Fixed I2C bus for 8390 ADC
    • Added small pop fix for sgtl5000 on the 8390
  • Updated ts4900-utils
    • New util 8390adc for reading the low speed MCP ADC
    • Fixed tshwctl to support auto TX-EN RS485 on ttymxc1
ts-x11-image-ts4900-quad-20150331224909.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20150401003538.rootfs.tar.bz2
  • Updated to 3.10.53 kernel
    • Significant fixes to GPU, UARTs, CAN and more.
    • Added TS-TPC-8950 support
    • Fixed 7" twinkling pixels on TS-8390 w/solo
    • Included splash screen
  • Updated to Yocto Dizzy for new freescale GPU support
  • Added Chromium to default image (google-chrome)
  • Updated toolchain to match dizzy image
  • Included gstreamer in the image
  • Updated FPGA with crossbar, max3100 based spi uart, bluetooth fixes (REV C only)
ts-x11-image-ts4900-quad-20150527173205.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20150528210615.rootfs.tar.bz2
  • Fixed networkd
  • Enabled PCIe in default kernel
    • Added I210 support for TS-7970
ts-x11-image-ts4900-quad-20150620060219.rootfs.tar.bz2 ts-x11-image-ts4900-solo-20150622150127.rootfs.tar.bz2
  • Added TS-7970 support
ts-x11-image-tsimx6-20150821190815.rootfs.tar.bz2
  • Updated to Yocto Fido
    • Removed GTK3 packages to reduce image size (GTK2 still available)
    • Removed distcc from default environment
    • Includes QT 5.4.3
    • Included qtmultimedia, xcursor-transparent theme
  • Updated Kernel
    • Includes fix for rare screen flip issues
ts-x11-image-tsimx6-20150821190815.rootfs.tar.bz2
  • Included significantly fixed support for the TS-7970
    • I210 support is fixed, but some prototype boards will need to be RMA'd to get MACs assigned.
    • All UARTs are now working
    • Included tsmicroctl for reading the silabs ADC (p10-12 4-20mA included)
    • Included load_fpga for software reloading fpgas later after boot
  • Updated TS-4900 FPGA to have CTS/RTS fixed for bluetooth, and corrected CTS/RTS polarity on the max3100s
ts-x11-image-tsimx6-20151014183028.rootfs.tar.bz2
  • Corrected defconfig used in kernel
    • Fixed WIFI and other modules
  • If used with the u-boot release from 10-14-2015 this fixes the mac address for the smsc95xx
ts-x11-image-tsimx6-20151221232637.rootfs.tar.bz2
  • Fixed MAC address to use device tree as well as parameter for the latest u-boot support.
  • Fixed tsgpio driver which was causing some incorrect DIO sets.
    • The WIFI driver uses tsgpio for toggling the enable which also corrects the behavior of ifdown/ifup wlan0.
  • Added rsync and lighttpd-cgi support
ts-x11-image-tsimx6-20160512161729.rootfs.tar.bz2
  • Added 100kohm pullups to the onboard/offboard SPI chip selects.
ts-x11-image-tsimx6-20161116215413.rootfs.tar.bz2
  • Updated to Yocto Jethro
  • Updates to QT 5.5
  • Updated to 4.1.15 based on Freescale/NXP's imx_4.1.15_1.0.0_ga.
  • Added improved support for TS-TPC-7990
  • New tshwctl with crossbar support.
ts-x11-image-tsimx6-20170301225516.rootfs.tar.bz2
  • Updated to Yocto Morty 2.2.1 with the same imx_4.1.15_1.0.0_ga kernel
  • Includes QT 5.7.1
  • Included additional alsa utilities
ts-x11-image-tsimx6-20170731205110.rootfs.tar.bz2
  • Updated to Morty 2.2.2
  • Included QT Quick 1.x/2.x support
  • Added support for TS-TPC-7990 REV C in kernel and ts4900-utils
  • Updated kernel
    • Fixed issue with ttyMAX* UARTs losing data or requiring the user to transmit before it continues to receive again
    • Fixed issue with ttyMAX* loopbacks dropping the first character
    • Added wilc3000 support for TS-TPC-7990 REV C WIFI
ts-x11-image-tsimx6-20180502184622.rootfs.tar.bz2
  • Updated to Yocto Morty 2.2.3
  • Add support for SST26VF064BA, and IS25LP064A spi flashes
  • Fixed TS-TPC-7990 REV C WIFI
ts-x11-image-tsimx6-20180608232731.rootfs.tar.bz2
  • Added support for accelerated gstreamer playback
ts-x11-image-tsimx6-20200409220332.rootfs.tar.bz2
  • Updated to Yocto Zeus
  • Added support for Silex WIFI driver
ts-x11-image-tsimx6-20211130163916.rootfs.tar.bz2
  • Added WIFI fix for solo TS-4900 on fallback device tree
  • Fixed TS-7970 FPGA GPIOs > 32.
ts-x11-image-tsimx6-20211206183743.rootfs.tar.bz2
  • Added support for Silex Bluetooth

Debian Changelog

Image date Debian Release Image Changes
20140929 Debian 7 Wheezy debian-armhf-wheezy-20140929.tar.bz2
  • Initial Release
20141125 Debian 7 Wheezy debian-armhf-wheezy-20141125.tar.bz2
  • Updated kernel with significant fixes, see github for more information.
  • Included first TS-7970 FPGA
20160825 Debian 8 Jessie debian-armhf-jessie-20160825.tar.bz2
  • New kernel - 3.10.53 (from freescale's 3.10.53_1.1.0_ga) instead of 3.10.17.
    • Fixed CAN dropped frames (just under 1% of frames were dropped on 3.10.17)
    • Fixed reported UART RX fifo overflows
    • GPU fixes
    • Kernel includes compiled in splash screen for quick graphical response on boot
  • TS-TPC-8950 support added
  • New FPGA (crossbar added, bluetooth fixed, and max3100 implemented)
  • Added bluez, wireless-tools, usbutils, nfs-common, and pciutils into the image.
  • Added Openssh server (generates on first boot)
20150526 Debian 8 Jessie debian-armhf-jessie-20150526.tar.bz2
  • First update to Debian Jessie
20151008 Debian 8 Jessie debian-armhf-jessie-20151008.tar.bz2
  • Included kernel support for TS-7970 REV A
  • Updated to latest TS-4900 FPGA (20150603)
  • Included openssh, generates keys on first boot. Remove /etc/ssh/*key* to regenerate.
  • Included latest ts4900-utils with TS-7970 support.
20160512 Debian 8 Jessie debian-armhf-jessie-20160512.tar.bz2
  • Fixed TS-7970 ttyMAX uarts (requires FPGA update)
  • Fixed resolv.conf symlink to use resolvd
  • Updated to 3.14.52 kernel
  • Corrected TS-TPC-8950 calibration
20160512 Debian 8 Jessie debian-armhf-jessie-20160512.tar.bz2
  • Moved to 4.1.15 kernel
  • Updated Debian to latest Jessie changes
  • Added latest ts4900-utils with improved TS-TPC-7990 support.
20170123 Debian 8 Jessie debian-armhf-jessie-20170123.tar.bz2
  • Added support for TS-7970 REV D hardware
  • Added support for TS-7990 REV B hardware
20170306 Debian 8 Jessie debian-armhf-jessie-20170306.tar.bz2
  • Fixed resolv.conf symlink
  • Added nfs-common
  • Cleaned up old temporary files
20170327 Debian 8 Jessie debian-armhf-jessie-20170327.tar.bz2
  • Fixed regression in TS-TPC-8950 support
  • Adds root.version to list image date
20170419 Debian 8 Jessie debian-armhf-jessie-20170419.tar.bz2
  • Fixed issue of missing U-boot splash screen disabling the backlight on REV B boards.
  • Fixed potential issue with WIFI not being recognized.
  • Added support for #TS-DC799-SILO board.
20170731 Debian 8 Jessie debian-armhf-jessie-20170731.tar.bz2
  • Added support for TS-TPC-7990 REV C in kernel and ts4900-utils
  • Updated kernel
    • Fixed issue with ttyMAX* UARTs losing data or requiring the user to transmit before it continues to receive again
    • Fixed issue with ttyMAX* loopbacks dropping the first character
    • Added wilc3000 support for TS-TPC-7990 REV C WIFI
20180412 Debian 9 Stretch debian-armhf-stretch-20180412.tar.bz2
  • Add support for SST26VF064BA, and IS25LP064A spi flashes
  • Initial port to Debian Stretch
20180501 Debian 9 Stretch debian-armhf-stretch-20180501.tar.bz2
  • Added support for TS-MINI-ADC
20181016 Debian 9 Stretch debian-armhf-stretch-20181016.tar.bz2
  • Updated kernel to support the offboard SPI Chip select on TS-7990 REV C.
20200401 Debian 10 Buster debian-armhf-buster-20200401.tar.bz2
  • Updated to Debian Buster (10)
  • Updated to Linux 4.9.11
  • Added SILEX SDMAC+ support for TS-4900 REV E and TS-7970 REV F
20210210 Debian 10 Buster debian-armhf-buster-20210210.tar.bz2
  • Updated to latest kernel revision with less verbose qcacld messages
20210526 Debian 10 Buster debian-armhf-buster-20210526.tar.bz2
  • Kernel update to fix imx_thermal support when the board is already heat soaked past the passive cooling temp.
20211130 Debian 10 Buster debian-armhf-buster-20211130.tar.bz2
  • Added WIFI fix for solo TS-4900 on fallback device tree
20230808 Debian 10 Buster debian-armhf-buster-20230808.tar.bz2
  • add support for TS-TPC-7990 REV E
20211217 Debian 11 Bullseye debian-armhf-bullseye-20211217.tar.bz2
  • Initial release of Debian Bullseye
20230807 Debian 11 Bullseye debian-armhf-bullseye-20230807.tar.bz2
  • Updated bullseye image to add support for TS-TPC-7990 REV E
20230628 Debian 11 Bullseye debian-armhf-bookworm-x11-20230628.tar.bz2
  • Initial release of Debian Bookworm
  • Bumps to kernel 5.10
20230807 Debian 12 Bookworm debian-armhf-bookworm-x11-20230807.tar.bz2
  • Added missing Silex firmware
  • Fixed issue with Micrel phy on the TS-4900 solo
  • add support for TS-TPC-7990 REV E
20230807 Debian 12 Bookworm debian-armhf-bookworm-x11-20230807.tar.bz2
  • Added missing Silex firmware
  • Fixed issue with Micrel phy on the TS-4900 solo
  • add support for TS-TPC-7990 REV E
20240409 Debian 12 Bookworm x11 headless minimal
  • Added apt locked version of wpa_supplicant to fix ath10k compatibility.
  • Bumped to kernel v5.10.214-ts
20240909 Debian 12 Bookworm x11 headless minimal
  • Bumped to kernel v5.10.224.1-ts
    • Supports updated Accelerometer/Gyro on TS-TPC-7990 REV E

Arch Linux Changelog

Image Changes
arch-armhf-20180502.tar.bz2 Initial Release

Ubuntu Linux Changelog

Image date Ubuntu Edition Links Changes
20160407 16.04 Xenial Xerus ubuntu-armhf-16.04-20160407.tar.bz2
  • Initial Release
20160818 16.04 Xenial Xerus ubuntu-armhf-16.04-20160818.tar.bz2
  • Bumped from 3.14.52 to 4.1.15 kernel. This adds support for the TS-TPC-7990.
  • Added more common packages, mmc, can-utils, etc.
20170306 16.04 Xenial Xerus ubuntu-armhf-16.04-20170306.tar.bz2
  • Updated ts4900-utils for final TS-7970/TS-TPC-7990
  • Added TS-TPC-7990 REV B support
20180221 16.04 Xenial Xerus ubuntu-armhf-16.04-20180221.tar.bz2
  • Fixed TS-TPC-8950 touchscreen
  • Updated to latest packages in apt repository
  • Updated ts4900-utils to latest version, included fix for supercaps.
  • Updated chromium browser's .desktop file to allow starting as root.
20190114 18.04 Bionic Beaver ubuntu-armhf-18.04-20190114.tar.bz2
  • Update to Ubuntu 18.04
  • Updated to kernel 4.9
20190806 18.04 Bionic Beaver ubuntu-armhf-18.04-20190806.tar.bz2
  • Updated to latest 4.9 kernel in git to add missing bluetooth driver
2011130 20.04 Focal Fossa ubuntu-armhf-20.04-2011130.tar.bz2
  • Updated to Ubuntu 20.04 with Silex wifi support
20230807 23.04 Lunar Lobster ubuntu-armhf-23.04-x11-20230807.tar.bz2
  • Initial release with Ubuntu 23.04
  • Updated to kernel 5.10
20240409 23.04 Lunar Lobster x11 headless minimal
  • Added apt locked version of wpa_supplicant to fix ath10k compatibility.
  • Bumped to kernel v5.10.214-ts
20240909 23.04 Lunar Lobster x11 headless minimal
  • Bumped to kernel v5.10.224.1-ts
    • Supports updated Accelerometer/Gyro on TS-TPC-7990 REV E
20240909 24.04 Noble Numbat x11 headless minimal
  • Bumped to kernel v5.10.224.1-ts
    • Supports updated Accelerometer/Gyro on TS-TPC-7990 REV E

Ubuntu Core Linux Changelog

Image Changes
ubuntu-core-16-2016-12-22.img.bz2
  • Initial Release
ubuntu-core-16-2017-04-21.img.bz2
  • Fixed boot scripts to work with core updates
  • Added support for the TS-4900 carrier board specific device trees.
  • Added support for the TS-7970
  • Added support for the TS-TPC-7990
  • Updated Kernel
    • Added ttyMAX* uart support
    • Added fixes from our main Linux kernel to the RTC driver
    • Fixed ethernet timing
ubuntu-core-16-2017-10-05.img.bz2
  • Added WIFI support
ubuntu-core-16-2019-09-12.img.bz2
  • Updated for latest SPI flash
ubuntu-core-16-2019-10-09.img.bz2
  • Bluetooth firmware included in the image

TS-7970 Errata

Issue Status Description
RS232 prevents booting on Rev. A Workarounds available, fixed in Rev. B

Early TS-7970 Rev. A boards may fail to boot if RS232 is connected before the board is powered. A small amount of RS232 idle negative voltage leaks from the transceiver to the FET controlling the switched 5V. The FET will not toggle while the output has a negative voltage, so the 5V rail never comes up. If this is a concern or if the issue is seen, we can rework the board to have a 2.5 ohm resistor from SW_5V to 5V_A on U47 pins 4 and 5. Rev. A boards shipped after 01/13/2016 include this fix.

Boot is prevented if the USB Device port (not host) is plugged in without the console enable jumper. Fixed in Rev. C

If the console jumper is not installed the silabs has USB VBUS, but no data signals. This puts the USB device into a locked up state while it waits to communicate on this bus. Due to this lockup it is unable to monitor voltages and turn on the SW_5V to the reset of the board. The fix is to disconnect VBUS from the silabs which is done on the Rev. C PCB. A cable without VCC can be made to work around the issue, or submit an RMA.

Watchdog behavior Fixed with BOM change on Rev. H

As part of the Rev. H changes, the 32khz that was being supplied by the discrete RTC is no longer available. If the CPU does not receive a 32khz input, it instead switches to an internal ring oscillator in the CPU. This clock in the CPU can be routed to PWM, RTC, or Watchdog, but in our software this is only used for the Watchdog. The early Rev. H units did not short the CPU's 32khz clock input to ground, and may not reliably start the ring oscillator. This can result in the Watchdog either tripping, or not tripping when it should. This can be fixed with a BOM change to connect this signal to ground. For units experiencing this issue, submit an RMA here.

The default software does not feed the watchdog. This will only affect users who are using the /dev/watchdog interface in their application.

Product Change Notices

WIFI Module replacement

Due to an EOL the WIFI module this part is being replaced wit the Silex SX-SDMAC2832S+ starting with PCB revision F. For users who do not use WIFI and write their own image, no action is required to support REV F boards. The board will now attempt to load a new device tree, but it will fall back to the old location so existing images will boot.

To support this new wifi chipset a new u-boot and kernel updates are required. For most WIFI users this will require only an updated kernel to support the new WIFI, and the newer board revisions will ship with the required u-boot to make use of this.

For users with unmodified kernels these can be updated to include the new WIFI support with a tar:

This can be installed directly to the board:

wget https://files.embeddedTS.com/ts-socket-macrocontrollers/ts-4900-linux/kernel/linux-4.9.11-20200701.tar.bz2
tar -xf linux-4.9.11-20200701.tar.bz2 -C /

This can also be used to install over an existing image:

mkdir /tmp/image/
sudo tar --numeric-owner -xf old-image.tar.bz2 -C /tmp/image/
sudo tar -xf linux-4.9.11-20200701.tar.bz2 -C /tmp/image/
sudo tar --numeric-owner -cjf new-image.tar.bz2 -C /tmp/image .

For users with custom kernels these should be updated to our latest commits:

  • 4.9 3544502eff51a659101411ed7879c0596e7c73f5
  • 4.1 04b83989d3930580a2f6ee70ac4483e6728e1fcf

Existing images will also need to be updated to support the firmware required by these new chipsets. If either of the above stock kernels are installed these packages also include the required firmware. This can also be installed in your image with the files here:

cd /tmp/
wget http://files.embeddedts.com/ts-arm-sbc/ts-7970-linux/wifi-firmware/silex-sdmac-plus-firmware-latest.tar.bz2
mkdir /tmp/image/
sudo tar --numeric-owner -xf old-image.tar.bz2 -C /tmp/image/
sudo tar -xf /tmp/silex-sdmac-plus-firmware-latest.tar.bz2 -C /tmp/image/lib/firmware/
sudo tar --numeric-owner -cjf new-image.tar.bz2 -C /tmp/image .

For users versions this requires a u-boot change to support loading the new PCB revision device trees.

U-boot will now search for the device tree looking for imx6<cpu>-ts7970-revf.dtb if the board is a rev f. For example, on a quad core TS-7970 REV F, it will attempt to load these files in this order:

  • imx6q-ts7970-revf.dtb
  • imx6q-ts7970.dtb

Boards before REV F will not attempt to load the revf dtb files.

When using the older images which did not have the pcb rev in the device tree, this will fall back to the older file but the startup output will show this output while it checks for the updated device tree.

Booting from the eMMC ...
** File not found /boot/boot.ub **
** File not found /boot/imx6q-ts7970-revf.dtb **
42451 bytes read in 126 ms (328.1 KiB/s)

SPI Flash Vendor Change

Due to an EOL the SPI flash on this product is changing. The old part is a Micron N25Q064A13ESE40F. Two new parts were qualified to reduce the impact of any potential EOL in the future. The new parts are the Microchip's SST26VF064BA, and ISSI's IS25LP064A.

Most applications will not be affected by this change unless they are manually accessing /dev/mtdblock0 or creating a custom u-boot. In those cases some updates will be required.

Linux Kernel Changes

Rebuilding the latest kernel in our git will include these changes, but the specific commits for our various kernel branches are:

U-Boot Changes

These two patches are required for the new flash:

Images with support

Any of our Linux images after March 7th, 2018 include support for this new SPI flash.

New eMMC chip

Due to an EOL on the older Micron MTFC4GMDEA-4M IT part, the replacement Micron MTFC4GACAJCN-4M IT has been qualified for use on this board. This new eMMC flash includes write reliability enabled by default. This will improve reliability for power loss events without requiring user intervention. These modes are further detailed in the eMMC section.

This may require a change to production processes for those who were manually set write reliability and enhanced area for the previous chip. The enh_area and write_reliability settings are permanent and these partition settings are locked once any of them are set. This led to scripts verifying write reliability was set and assuming both were set. The eMMC section includes an example shell script for enabling atomic writes on both versions of this chip.

New Microcontroller and FPGA

Due to parts availability constraints the TS-7970 has been redesigned to have a few replacement parts.

  • Lattice MachXO2 has been replaced with a Lattice MachXO3.
  • Silabs 8051 microcontroller has been replaced with a Renesas RA4M2
  • Intersil ISL12020MIRZ functionality is now provided by the same Renesas RA4M2

None of these require the user to change their shipping image. The only changes a user should see from these changes is:

  • Higher RTC PPM drift on the new RTC (±5ppm vs ±20ppm)
  • Different USB device
  • There is 120 bytes instead of 128 bytes of NVRAM

The Lattice MachXO3 has been configured with the same logic as the previous MachXO2 so this does not have any user facing changes.

Instead of the Silicon Labs C8051 series microcontroller, this has been replaced with a Renesas RA4M2 series part (R7FA4M2AB3CNE). We have taken great care to ensure there are no code changes required by users to support this new part. This part provides 12-bit ADC instead of 10-bit, and uses a 3.3V VREF instead of a 2.5V VREF, but the firmware we provide on the Renesas scales these to the Silicon Labs part analog values so user code does not need to change. Users should continue to scale these ADC values as if they are 10-bit 2.5V VREF with the REV E resistor dividers on the analog values. The existing tsmicroctl -i command can be used as an example.

The only user facing change with this new part is the driver used to access console over USB. Instead of the Silabs CP2103 driver, the new microcontroller now uses the standard USB CDC-ACM class device driver. This is included by default in all major operating systems. Under windows the user should generally not see any difference except the device name will be: "TS-7970 Console" instead of "Silicon Labs CP210x USB to UART Bridge" as the device name.

The Renesas microcontroller also takes the place of the Intersil RTC and provides a compatible register set over I2C. This also provides the same battery backed SRAM as the Intersil RTC. See the #RTC section for more details on this support.

Under Linux the device will be /dev/ttyACM0 instead of /dev/ttyUSB0 as on the previous devices. Some Linux distributions such as Ubuntu include ModemManager that can mistake this ACM0 device as a cell modem. To prevent this, run this one time on your Linux host:

echo "ATTR{idVendor}==\"35b0\",  ENV{ID_MM_DEVICE_IGNORE}=\"1\"" > /etc/udev/rules.d/75-embeddedts-mm.rules

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.

Trademarks

Arm and Cortex are registered trademarks of Arm Limited (or its subsidiaries) in the US and/or elsewhere.