TS-7250-V3
Note: | This manual is incomplete at this time and is subject to change without warning while the TS-7250-V3 is in Engineering Sampling phase. |
Product Page | |
Documentation | |
---|---|
Schematic | |
FTP Path | |
Processor | |
NXP i.MX6UL | |
696MHz | |
i.MX6UL Product Page | |
CPU Documentation |
Overview
The TS-7250-V3 is a PC104 form factor SBC with a PC104 bus, mikroBus, Digi XBEE header, soldered down eMMC flash, dual Ethernet, microSD, and wifi. This board also provides a migration path from the TS-7250-V2 and TS-7250 series systems.
Getting Started
A Linux PC is recommended for development. For developers who use Windows, virtualized Linux using VMWare or similar are recommended in order to make the full power of Linux available. The developer will need to be comfortable with Linux anyway in order to work with embedded Linux on the target platform. The main reasons that Linux is useful are:
- Linux filesystems on the microSD card can be accessed on the PC.
- More ARM cross-compilers are available.
- If recovery is needed, a bootable medium can be written.
- A network filesystem can be served.
- Builds such as Linux kernel, buildroot, yocto, distro-seed will not work from WSL1/2 on a case insensitive filesystem.
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 board. |
Connect USB Console
The board includes a USB Micro header connected to the onboard preprogrammed microcontroller. This acts as a USB serial device using the CP210x Virtual COM port. Most operating systems have built-in support for this device, however drivers are available here.
Console from Linux
There are many serial terminal applications for Linux, three common used applications are picocom
, screen
, and minicom
. These examples demonstrate all three applications and assume that the serial device is "/dev/ttyUSB0" which is common for USB adapters. Be sure to replace the serial device string with that of the device on your workstation.
picocom
is a very small and simple client.
sudo picocom -b 115200 /dev/ttyUSB0
screen
is a terminal multiplexer which happens to have serial support.
sudo screen /dev/ttyUSB0 115200
Or a very commonly used client is minicom
which is quite powerful but requires some setup:
sudo minicom -s
- Navigate to 'serial port setup'
- Type "a" and change location of serial device to "/dev/ttyUSB0" then hit "enter"
- If needed, modify the settings to match this and hit "esc" when done:
E - Bps/Par/Bits : 115200 8N1 F - Hardware Flow Control : No G - Software Flow Control : No
- Navigate to 'Save setup as dfl', hit "enter", and then "esc"
Console from Windows
Putty is a small simple client available for download here. Open up Device Manager to determine your console port. See the putty configuration image for more details.
Powering up
The TS-7250-V3 receives power through either the 5VDC 2pin terminal block connector near the DB9, or the 2 pin 8-28VDC terminal block near the mikrobus connector.
If a power supply is ordered with the TS-7250-V2 it will include the correct terminal block connected to the power supply. Otherwise the terminal block will ship with the unit.
Note: | The polarity is marked underneath the removable terminal blocks. |
Once power is applied the device will output information via the built in USB console.
The first output is from U-Boot:
Trying to boot from MMC1 U-Boot 2020.01-00009-g99e2080fad (Mar 12 2020 - 08:43:22 -0700) CPU: Freescale i.MX6UL rev1.2 696 MHz (running at 396 MHz) CPU: Automotive temperature grade (-40C to 125C) at 44C Reset cause: POR Model: Technologic Systems i.MX6UL TS-7250-V3 Board: TS-7250-V3 DRAM: 512 MiB MMC: FSL_SDHC: 0 Loading Environment from MMC... *** Warning - bad CRC, using default environment In: serial Out: serial Err: serial Net: Warning: ethernet@20b4000 using MAC address from ROM eth1: ethernet@20b4000 Warning: ethernet@2188000 using MAC address from ROM , eth0: ethernet@2188000 Press ESC twice to abort autoboot in 1 second(s)
Note: | The message "*** Warning - bad CRC, using default environment" can be safely ignored. This indicates that u-boot scripts are not being customized. Typing "env save" will hide these messages, but this is not needed. |
Note: | The message "using MAC address from ROM" is indicating that the board is using the preprogrammed MAC address as intended. All boards are assigned 2 unique MAC addresses. |
This u-boot and its environment is loaded from the SPI flash (/dev/mmcblk0boot0). This a hardware partition that is independent of the main flash on the emmc (/dev/mmcblk0). From here, u-boot will follow u-boots standard Distro boot command. This will check for boot files on the first USB mass storage, and will by default find a bootable image on eMMC. From here the board will boot to our default #Debian image.
First Linux Boot
When booting with the default settings, a shipped board will boot to the eMMC. The eMMC by default are pre-programmed with our default Debian 10 Buster image. After Linux boots it will ask the user to log in with a username and password. This uses "root" as the username with no password. This can be changed after logging in with the command "passwd" to set an account password.
From the Linux prompt you can now begin testing out hardware, or beginning your application development.
Booting from USB
This board supports booting to an OS image written to a USB drive for development. For the most reliable boot we recommend eMMC boot.
Note: | This can be run from the board while booted to eMMC, but this should not rewrite the same USB stick that the system has used to boot. Rewriting an image while it is used as the boot media will result in a corrupt image. |
This requires a Linux system to write the USB image.
Check lsblk
or dmesg
to find your USB drive, but the following examples will assume /dev/sdc.
wget http://files.embeddedTS.com/ts-arm-sbc/ts-7250-v3-linux/distributions/debian/tsimx6ul-debian-bullseye-latest.tar.xz
sudo sgdisk --zap-all /dev/sdc
sudo sgdisk -n 0:0:0 -t 0:8300 /dev/sdc
sudo mkfs.ext4 /dev/sdc1
sudo mkdir /mnt/usb/
sudo mount /dev/sdc1 /mnt/usb/
sudo tar --numeric-owner -xf tsimx6ul-debian-bullseye-latest.tar.xz -C /mnt/usb/
sudo umount /mnt/usb/
If this USB is plugged into USB on startup, it will be chosen instead of the onboard eMMC. For example:
U-Boot 2020.01-00009-g99e2080fad (Mar 12 2020 - 08:43:22 -0700) CPU: Freescale i.MX6UL rev1.2 696 MHz (running at 396 MHz) CPU: Automotive temperature grade (-40C to 125C) at 34C Reset cause: POR Model: Technologic Systems i.MX6UL TS-7250-V3 Board: TS-7250-V3 DRAM: 512 MiB MMC: FSL_SDHC: 0 Loading Environment from MMC... *** Warning - bad CRC, using default environment In: serial Out: serial Err: serial Net: Warning: ethernet@20b4000 using MAC address from ROM eth1: ethernet@20b4000 Warning: ethernet@2188000 using MAC address from ROM , eth0: ethernet@2188000 Press ESC twice to abort autoboot in 1 second(s) starting USB... Bus usb@2184000: USB EHCI 1.00 Bus usb@2184200: USB EHCI 1.00 scanning bus usb@2184000 for devices... 1 USB Device(s) found scanning bus usb@2184200 for devices... 2 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found Device 0: Vendor: SanDisk Rev: 0001 Prod: Extreme Type: Removable Hard Disk Capacity: 59836.1 MB = 58.4 GB (122544516 x 512) ... is now current device Scanning usb 0:1... Found U-Boot script /boot/boot.scr 675 bytes read in 8 ms (82 KiB/s) root ## Executing script at 82000000 5348808 bytes read in 145 ms (35.2 MiB/s) 33863 bytes read in 8 ms (4 MiB/s) Booting Debian from usb 0:1... root ## Flattened Device Tree blob at 83000000 Booting using the fdt blob at 0x83000000 Loading Device Tree to 9ef68000, end 9ef73446 ... OK Starting kernel ... [ 6.242409] cgroup: cgroup2: unknown option "nsdelegate,memory_recursiveprot" [ 6.251458] cgroup: cgroup2: unknown option "nsdelegate" Welcome to Debian GNU/Linux 11 (bullseye)
U-Boot
U-Boot is a bootloader and comes preinstalled on this board. The U-Boot bootloader is loaded in the eMMC hardware boot partitions in /dev/mmcblk0boot0. U-Boot sets up the hardware and then loads the OS from the available storage devices. U-Boot allows booting images from the microSD, eMMC, NFS, or USB. Most users will not need to customize u-boot further, and can proceed to the #Debian sections for information on application development.
U-boot Distro Boot
U-boot by default uses u-boots distro bootcmd to determine how to boot. As shipped the board will boot to the preprogrammed eMMC with our #Debian image.
By default this will look at:
Order | U-boot device name | Description |
---|---|---|
1 | usb0 | First detected USB mass storage device |
2 | mmc1 | MicroSD card |
3 | mmc0 | Onboard eMMC storage |
4 | dhcp | DHCP Option [1] |
5 | pxe | PXE File [2] |
The default boot order can be left for most users, but boot can be optimized for one boot device by stopping at u-boot and running:
# Boot straight to eMMC:
env set boot_targets 'mmc0';
env save
# Boot to usb, then mmc only
env set boot_targets 'usb0 mmc0';
env save
# Set back to default boot order
env set boot_targets 'usb0 mmc1 mmc0 dhcp pxe'
env save
U-boot will search the boot media on either the 1st partition, or if the disk is partitioned with GPT instead of MBR it will search the "bootable" partition. It will then search for these files:
Order | Search for | Paths | Description |
---|---|---|---|
1 | extlinux | /extlinux/extlinux.conf, /boot/extlinux/extlinux.conf | Menu conf file of kernels |
2 | U-boot script | /boot.scr.uimg, /boot.scr, /boot/boot.scr.uimg, /boot/boot.scr | u-boot script with instructions to load the OS |
3 | EFI Binary | efi/boot/bootarm.efi | EFI binary (such as grub) |
Our Debian images use a u-boot script in /boot/boot.scr.uimg.
U-Boot Environment
The U-Boot environment is stored in the on-board eMMC flash in the /dev/mmcblk0boot0 partition.
# 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 0 off; echo Hello world; led 1 on;'
# Execute commands saved in a variable
env run hellocmd
# Commit env changes to the spi flash
# Otherwise changes are lost
env save
# Restore env to default
env default -a
# Remove a variable
env delete hellocmd
U-Boot Development
Note: | This section is incomplete at this time and is subject to change without warning while the TS-7250-V3 is in Engineering Sampling phase. |
We do provide our U-Boot sources, but we do not recommend rebuilding a custom U-Boot binary as it can leave the system in an unbootable state.
If proceeding with building a custom U-Boot, use the "v2020.01-ts" branch from our github repo: https://github.com/embeddedTS/u-boot-imx this can be executed with the following command:
git clone https://github.com/embeddedTS/u-boot-imx.git -b v2020.01-ts u-boot-ts7250v3
When compiling, we recommend using ONLY this cross-compiler, the use of any other compiler may cause issues or may leave the system in an unbootable state! Specifically, we have experienced RAM problems when using a more recent cross compiler to build this version of U-Boot. The tarball can be extracted with the following:
mkdir /opt/toolchains/ts7250v3/
tar -xf tsimx6ul-glibc-gnueabihf-4.9.4.tar.xz -C /opt/toolchains/ts7250v3/
Once the tarball has been properly extracted set up the following variables and run the build script:
export ARCH=arm
export CROSS_COMPILE=/path/to/folder/bin/arm-linux-gnueabihf-
After the environment variables have been set up as shown above the build is now ready to be executed:
cd /path/to/u-boot-imx
./build-imx6ul.sh ts7250v3
Debian 11
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. The installation is specific to our board, but most Debian documentation applies:
Debian 11 - Getting Started and writing an Image
Once installed, the default user is "root" with no password.
This image can be written to a USB drive, or to the eMMC. For development, a USB thumbdrive will be simplest. If a bootable USB drive is connected this will take priority over other boot media. Plug in a USB drive and check the last output from "dmesg" to get the USB disk. For example, this may be /dev/sdc.
# Erase all older partitions
sudo sgdisk --zap-all /dev/sdc
# Create one GPT Linux partition
sudo sgdisk -n 0:0:0 -t 0:8300 /dev/sdc
# Create a filesystem and mount
sudo mkfs.ext4 /dev/sdc1
sudo mkdir /mnt/usb/
sudo mount /dev/sdc1 /mnt/usb/
# Extract downloaded image:
sudo tar --numeric-owner -xf tsimx6ul-debian-bullseye-latest.tar.xz -C /mnt/usb/
sudo chmod 755 /mnt/usb/
sudo umount /mnt/usb/
These commands will also work while booted from a USB drive to rewrite the eMMC. Instead of /dev/sdc you would use /dev/mmcblk0, and instead of /dev/sdc1 you would use /dev/mmcblk0p1.
Debian 11 - Configuring Network
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 11 - Backup the image
To create backups / restore images, it is recommended to first boot to USB. A disk should not be backed up or written while it is used to boot.
If your image is a single partition it can be backed up as a tar file. This allows the media to easily expand to any disk size.
Create a backup tar
mkdir /mnt/emmc
mount /dev/mmcblk0p1 /mnt/emmc/
tar -cJf /root/backup-of-image.tar.xz -C /mnt/emmc/
umount /mnt/emmc/
Write a tar image to the eMMC
sgdisk --zap-all /dev/mmcblk0
sgdisk -n 0:0:0 -t 0:8300 /dev/mmcblk0
mkfs.ext4 /dev/mmcblk0p1
mkdir /mnt/emmc
mount /dev/mmcblk0p1 /mnt/emmc/
tar -xf /root/backup-of-image.tar.xz -C /mnt/emmc/
umount /mnt/emmc/
Debian 11 - Compile the Kernel
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/tsimx6ul/kernel/
cd ~/Projects/tsimx6ul/kernel/
docker-debian-bookworm
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, and to set up building the kernel modules for the WILC3000 Wi-Fi/BLE module:
export CROSS_COMPILE=arm-linux-gnueabihf- # This may be different if using a different compiler!
export ARCH=arm
export WILC=y
The WILC3000 Wi-Fi/BLE drivers are maintained and built externally out of the kernel tree. Clone this tree inside of the linux-lts/
directory (this is built later):
git clone https://github.com/embeddedTS/wilc3000-external-module/
Next, set the default configuration for this platform. Note that a minimal defconfig and a full-feature defconfig are available. The minimal defconfig contains options for supporting the device and a few common peripherals and technologies. While the full defconfig includes much more support for things like USB devices, a more broad range of netfilter/iptables filter module support, etc.
make tsimx6ul_defconfig
# The minimal defconfig can alternately be used with:
# make tsimx6ul_minimal_defconfig
Build and Install
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
cp arch/arm/boot/dts/*ts*.dtb "${TEMPDIR}"/boot/
# Install kernel modules to the target
INSTALL_MOD_PATH="${TEMPDIR}" make modules_install
# Install kernel headers to the target, this is optional in most cases and can be removed to save space on the target
make headers_install INSTALL_HDR_PATH="${TEMPDIR}"
# If WILC is set to "y", then build the external module for the WILC300 Wi-Fi/BLE device.
# Note that this expects the source to be available as a subfolder in the kernel. See the above sections
# for details on getting the driver source if it is used on this specific platform.
if [ "${WILC}" == "y" ]; then
CONFIG_WILC_SPI=m INSTALL_MOD_PATH="${TEMPDIR}" make M=./wilc3000-external-module modules modules_install
fi
# Use fakeroot to properly set permissions on the target folder as well as create a tarball from this.
fakeroot sh -c "chmod 755 ${TEMPDIR};
chown -R root:root ${TEMPDIR};
tar czf ${TEMPFILE}.tar.gz -C ${TEMPDIR} .";
# Create a final output tarball and cleanup all of the temporary files and folder.
cp ${TEMPFILE}.tar.gz embeddedTS-linux-lts-"$(date +"%Y%m%d")"-"$(git describe --abbrev=8 --dirty --always)".tar.gz
rm -rf "${TEMPDIR}" "${TEMPFILE}"
At this point, the tarball can be unpacked to a bootable media for the device. This can be done from a booted device, or by mounting removable media from a host Linux workstation. For example, if the root folder of the target filesystem to be updated is mounted to /mnt/
, the following can be used to unpack the above tarball:
# Ensure the target filesystem is mounted to /mnt first!
# Extract kernel tarball to target filesystem,
tar xhf embeddedTS-linux-lts-*.tar.gz -C /mnt
Note: | The h argument to tar is necessary on recent distributions that use paths with symlinks. Not using it can potentially render the whole filesystem no longer bootable.
|
This will correctly unpack the kernel, modules, and headers to the target filesystem which can then be booted as normal.
Debian 10
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. The installation is specific to our board, but most Debian documentation applies:
Debian 10 - Getting Started and writing an Image
Once installed, the default user is "root" with no password.
This image can be written to a USB drive, or to the eMMC. For development, a USB thumbdrive will be simplest. If a bootable USB drive is connected this will take priority over other boot media. Plug in a USB drive and check the last output from "dmesg" to get the USB disk. For example, this may be /dev/sdc.
# Erase all older partitions
sudo sgdisk --zap-all /dev/sdc
# Create one GPT Linux partition
sudo sgdisk -n 0:0:0 -t 0:8300 /dev/sdc
# Create a filesystem and mount
sudo mkfs.ext4 /dev/sdc1
sudo mkdir /mnt/usb/
sudo mount /dev/sdc1 /mnt/usb/
# Extract downloaded image:
sudo tar --numeric-owner -xf tsimx6ul-debian-buster-latest.tar.xz -C /mnt/usb/
sudo chmod 755 /mnt/usb/
sudo umount /mnt/usb/
These commands will also work while booted from a USB drive to rewrite the eMMC. Instead of /dev/sdc you would use /dev/mmcblk0, and instead of /dev/sdc1 you would use /dev/mmcblk0p1.
Debian 10 - Configuring Network
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 10 - Backup the image
To create backups / restore images, it is recommended to first boot to USB. A disk should not be backed up or written while it is used to boot.
If your image is a single partition it can be backed up as a tar file. This allows the media to easily expand to any disk size.
Create a backup tar
mkdir /mnt/emmc
mount /dev/mmcblk0p1 /mnt/emmc/
tar -cJf /root/backup-of-image.tar.xz -C /mnt/emmc/
umount /mnt/emmc/
Write a tar image to the eMMC
sgdisk --zap-all /dev/mmcblk0
sgdisk -n 0:0:0 -t 0:8300 /dev/mmcblk0
mkfs.ext4 /dev/mmcblk0p1
mkdir /mnt/emmc
mount /dev/mmcblk0p1 /mnt/emmc/
tar -xf /root/backup-of-image.tar.xz -C /mnt/emmc/
umount /mnt/emmc/
Debian 10 - Compile the Kernel
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/tsimx6ul/kernel/
cd ~/Projects/tsimx6ul/kernel/
docker-debian-bookworm
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, and to set up building the kernel modules for the WILC3000 Wi-Fi/BLE module:
export CROSS_COMPILE=arm-linux-gnueabihf- # This may be different if using a different compiler!
export ARCH=arm
export WILC=y
The WILC3000 Wi-Fi/BLE drivers are maintained and built externally out of the kernel tree. Clone this tree inside of the linux-lts/
directory (this is built later):
git clone https://github.com/embeddedTS/wilc3000-external-module/
Next, set the default configuration for this platform. Note that a minimal defconfig and a full-feature defconfig are available. The minimal defconfig contains options for supporting the device and a few common peripherals and technologies. While the full defconfig includes much more support for things like USB devices, a more broad range of netfilter/iptables filter module support, etc.
make tsimx6ul_defconfig
# The minimal defconfig can alternately be used with:
# make tsimx6ul_minimal_defconfig
Build and Install
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
cp arch/arm/boot/dts/*ts*.dtb "${TEMPDIR}"/boot/
# Install kernel modules to the target
INSTALL_MOD_PATH="${TEMPDIR}" make modules_install
# Install kernel headers to the target, this is optional in most cases and can be removed to save space on the target
make headers_install INSTALL_HDR_PATH="${TEMPDIR}"
# If WILC is set to "y", then build the external module for the WILC300 Wi-Fi/BLE device.
# Note that this expects the source to be available as a subfolder in the kernel. See the above sections
# for details on getting the driver source if it is used on this specific platform.
if [ "${WILC}" == "y" ]; then
CONFIG_WILC_SPI=m INSTALL_MOD_PATH="${TEMPDIR}" make M=./wilc3000-external-module modules modules_install
fi
# Use fakeroot to properly set permissions on the target folder as well as create a tarball from this.
fakeroot sh -c "chmod 755 ${TEMPDIR};
chown -R root:root ${TEMPDIR};
tar czf ${TEMPFILE}.tar.gz -C ${TEMPDIR} .";
# Create a final output tarball and cleanup all of the temporary files and folder.
cp ${TEMPFILE}.tar.gz embeddedTS-linux-lts-"$(date +"%Y%m%d")"-"$(git describe --abbrev=8 --dirty --always)".tar.gz
rm -rf "${TEMPDIR}" "${TEMPFILE}"
At this point, the tarball can be unpacked to a bootable media for the device. This can be done from a booted device, or by mounting removable media from a host Linux workstation. For example, if the root folder of the target filesystem to be updated is mounted to /mnt/
, the following can be used to unpack the above tarball:
# Ensure the target filesystem is mounted to /mnt first!
# Extract kernel tarball to target filesystem,
tar xhf embeddedTS-linux-lts-*.tar.gz -C /mnt
Note: | The h argument to tar is necessary on recent distributions that use paths with symlinks. Not using it can potentially render the whole filesystem no longer bootable.
|
This will correctly unpack the kernel, modules, and headers to the target filesystem which can then be booted as normal.
Buildroot
The full-featured stock 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. To assist customers heading down this path we have a created a git tree that uses BR_EXTERNAL to add support for our boards with an unmodified copy of the buildroot git. The buildroot must be compiled from sources to generate an image.
Buildroot - Compiling an Image
The default image for the TS-7250-V3 generates a minimalistic OS of around 30MiB. This includes the kernel, device tree, boot scripts and the bare minimum linux os to run busybox. Any other libraries besides uclibc would need to be added.
git clone https://github.com/embeddedarm/buildroot-ts.git
cd buildroot-ts
git submodule update --init
make ts7250v3_defconfig
make
USB Production Method
The TS-7250-V3 supports using a USB thumbdrive to rewrite the onboard media. If the USB media is present on startup it will be chosen instead of eMMC. The startup script will:
- Turn on the RED LED
- Rewrite emmc/sd/u-boot as requested
- Blink green to indicate a pass
* Blinking red indicates a failure. See the console output for more details.
The blast image and scripts require a minimum of 50 MB; this plus any disk images or tarballs used dictate the minimum disk size required. The USB drive must have at least 1 partition, with the first partition being formatted ext2/3 or fat32/vfat.
wget http://ftp.embeddedTS.com/ftp/ts-arm-sbc/ts-7250-v3-linux/usb-blaster/ts7250v3-usb-production-rootfs-latest.tar.bz2
# 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/ts7250v3-usb-production-rootfs-latest.tar.bz2 -C /mnt/usb/
# Copy image files to /mnt/usb/
sudo umount /mnt/usb/
At this point disk images or tarballs would be copied to the /mnt/usb/ folder and named as noted below. The latest disk images we provide can be downloaded from our FTP site, see the backup and restore section for links to these files. Note that the script expects images and tarballs to have specific names. When using an ext* filesystem, symlinks can be used.
The formatted USB drive boots into a small buildroot initramfs environment with filesystem and partitioning tools installed. This can be used to format SD, eMMC, or other disks. The buildroot starts up and calls /blast.sh on the USB device. By default this script is set up to look for a number of of specific files on the USB disk and write to media on the host device. Upon completion of the script the green or red LEDs will blink to visually indicate a pass or fail of the script. This script can be used without modification to write images from USB with these filenames:
eMMC | emmcimage.tar.bz2 | Tar of the filesystem. This will repartition the eMMC to 1 ext4 partition and extract this tar to the filesystem. If present, a /md5sums.txt will be checked and every file can be verified on the filesystem. This md5sums file is optional and can be omitted, but it must not be blank if present. |
---|---|---|
emmcimage.dd.bz2 | Disk image of the card. This will be written to mmcblk1 directly. If present a emmcimage.dd.md5 will cause the written data on the eMMC to be read back and verified against this checksum. |
Most users should be able to use the above script without modification. Our buildroot sources are available from our github repo with instructions to rebuild this "ts7250v3_usbprod_defconfig" target.
Features
ADC
This board supports 5 channels of 12-bit ADC using an integrated ADC in the i.MX6UL CPU. All channels can sample 0-30VDC, but channels 1-3 can optionally sample 0-20mA as a current loop. To minimize noise, the ADC pins use a dedicated analog ground available on the even pins of the header. See the #ADC Header section for more details.
These ADCs are accessed through the IIO layer in Linux. This provides ADC samples up to 6ksps between all channels. The simplest API for slow speed acquisition is through iio_attr:
iio_attr -c 2198000.adc voltage0
iio_attr -c 2198000.adc voltage1
iio_attr -c 2198000.adc voltage5
iio_attr -c 2198000.adc voltage8
iio_attr -c 2198000.adc voltage9
ADC Header Pin | Schematic Name | IIO device | IIO name | Voltage | Current loop |
---|---|---|---|---|---|
1 | AN_CH1 | 2198000.adc | voltage0 | 0-30VDC | 0-20mA |
3 | AN_CH2 | 2198000.adc | voltage1 | 0-30VDC | 0-20mA |
5 | AN_CH3 | 2198000.adc | voltage5 | 0-30VDC | 0-20mA |
7 | AN_CH4 | 2198000.adc | voltage8 | 0-30VDC | N/A |
8 | AN_CH5 | 2198000.adc | voltage9 | 0-30VDC | N/A |
The current loops are enabled/disabled with GPIO:
gpioset 20ac000.gpio 7=0 # AN_CH1 voltage
gpioset 20ac000.gpio 8=0 # AN_CH2 voltage
gpioset 20ac000.gpio 9=0 # AN_CH3 voltage
gpioset 20ac000.gpio 7=1 # AN_CH1 current
gpioset 20ac000.gpio 8=1 # AN_CH2 current
gpioset 20ac000.gpio 9=1 # AN_CH3 current
The libiio library provides simple access to the IO. The fastest API is in C which will get about 6ksps.
/* Build with gcc adc-test.c -o adc-test -liio
* Gets ~6ksps
* At the time of writing this does not support the buffer interface */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <iio.h>
uint32_t scale_mv(uint32_t raw)
{
/* fractions $((330+22)) 22 2500 4095 */
uint32_t val = raw * 9;
val += (raw * 629) / 819;
return val;
}
int main(int argc, char **argv)
{
static struct iio_context *ctx;
static struct iio_device *dev;
static struct iio_channel *chn[5];
int i, ret;
long long sample;
ctx = iio_create_default_context();
assert(ctx);
dev = iio_context_find_device(ctx, "2198000.adc");
assert(dev);
chn[0] = iio_device_find_channel(dev, "voltage0", false);
chn[1] = iio_device_find_channel(dev, "voltage1", false);
chn[2] = iio_device_find_channel(dev, "voltage5", false);
chn[3] = iio_device_find_channel(dev, "voltage8", false);
chn[4] = iio_device_find_channel(dev, "voltage9", false);
for (i = 0; i < 5; i++) {
ret = iio_channel_attr_read_longlong(chn[i], "raw", &sample);
assert(!ret);
printf("AN_CH%d_mv=%d\n", i, scale_mv((uint32_t)sample));
}
return 0;
}
The python bindings currently achieve about 2ksps with similar code.
#!/usr/bin/env python3
import iio
ctx = iio.Context('local:')
dev = ctx.find_device('2198000.adc')
scan_channels = ["voltage0", "voltage1", "voltage5", "voltage8", "voltage9"]
i = int(0)
for chan_name in scan_channels:
chn = dev.find_channel(chan_name)
raw = int(chn.attrs['raw'].value)
# Scale 0-4095 to 0-2500(mV)
scaled = raw * (2.5/4095)
# Scale voltage divider on the pin
r1 = 330
r2 = 22
v = scaled / (r2 / (r1 + r2))
i += 1
print('AN_CH{}_V={:.3f}'.format(i, v))
Battery Backed RTC
This board includes the STMicro "M41T00S" Battery Backed RTC using an external battery. This RTC is connected to the CPU via I2C and is handled by the kernel and is presented as a standard RTC device in Linux. TS-7250-V3 board provides battery backed power to the RTC via a replaceable CR1632 coin cell.
Bluetooth
Note: | The latest image for this platform as of April 28th, 2022 has known issues with the Wi-Fi driver and BLE coexistence due to incompatibility with cfg80211 powersave modes.
If using both Wi-Fi and BLE, it is strongly recommended to bring up the Wi-Fi interface, and then run This issue will be addressed in future images and has already been addressed in our kernel sources. We will continue to provide updates as we receive them from the Wi-Fi module manufacturer. |
The Wi-Fi option for this platform also includes a Bluetooth 5.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.
Both Wi-Fi and Bluetooth can be active at the same time on this platform. Note however, that either the Wi-Fi interface needs to be not brought up if Wi-Fi is unused, or it needs to actively connect to an access point or act as an access point. The Bluetooth module can be activated with the following commands:
For Bluez versions found on Debian Stretch and below:
# Enable Bluetooth, and load the firmware
echo BT_POWER_UP > /dev/wilc_bt
sleep 1
echo BT_DOWNLOAD_FW > /dev/wilc_bt
sleep 1
# Attach the BLE device to the system, increase the baud, and enable flow control
hciattach /dev/ttymxc2 any 115200 noflow
sleep 1
hcitool cmd 0x3F 0x0053 00 10 0E 00 01
stty -F /dev/ttymxc2 921600 crtscts
# Note that no other HCI commands should be used! In older versions of BlueZ, HCI commands exist alongside bluetoothd, however HCI commands can interfere with the bluetoothd stack.
For newer versions of BlueZ found on Debian Buster or newer, or newer versions of BlueZ built from source:
echo BT_POWER_UP > /dev/wilc_bt
sleep 1
echo BT_DOWNLOAD_FW > /dev/wilc_bt
sleep 1
btattach -N -B /dev/ttymxc2 -S 115200 &
sleep 1
bluetoothctl power on
sleep 1
hcitool cmd 0x3F 0x0053 00 10 0E 00 01
kill %1 # This terminates the above btattach command
sleep 1
btattach -B /dev/ttymxc2 -S 921600 &
At this point, the device is running at 921600 baud with flow control, and is fully set up ready to be controlled by various components of BlueZ tools. For example, to do a scan of nearby devices:
bluetoothctl
power on
scan on
This will return a list of devices such as:
root@ts-imx6ul:~# bluetoothctl Agent registered [CHG] Controller F8:F0:05:XX:XX:XX Pairable: yes [bluetooth]# power on Changing power on succeeded [CHG] Controller F8:F0:05:XX:XX:XX Powered: yes [bluetooth]# scan on Discovery started [CHG] Controller F8:F0:05:XX:XX:XX Discovering: yes [NEW] Device 51:DD:C0:XX:XX:XX Device_Name [NEW] Device 2A:20:E2:XX:XX:XX Device_Name [CHG] Device 51:DD:C0:XX:XX:XX RSSI: -93 [CHG] Device 51:DD:C0:XX:XX:XX RSSI: -82 [NEW] Device E2:08:B5:XX:XX:XX Device_Name [CHG] Device 51:DD:C0:XX:XX:XX RSSI: -93 [CHG] Device 2A:20:E2:XX:XX:XX RSSI: -94 [NEW] Device 68:62:92:XX:XX:XX Device_Name [NEW] Device 68:79:12:XX:XX:XX Device_Name [bluetooth]# quit
Please note that the Bluetooth module requires the modem control lines CTS and RTS as flow control when running at higher baud rates. It is possible to run the module at the initial 115200 baud if the flow control lines are unwanted.
The module supports some other commands as well:
# Allow the BT chip to enter sleep mode
echo BT_FW_CHIP_ALLOW_SLEEP > /dev/wilc_bt
# Power down the BT radio when not in use
echo BT_POWER_DOWN > /dev/wilc_bt
CAN
The TS-7250-V3 CPU has two FlexCAN ports that use the Linux SocketCAN implementation. These are available on the #COM3 Header
These interfaces can be brought up with:
ip link set can0 up type can bitrate 1000000
ip link set can1 up type can bitrate 1000000
At this point, the port can be used with standard SocketCAN libraries. In Debian, we provide the utilities 'cansend' and 'candump' to test the ports or as a simple packet send/receive tool. In order to test the port, tie CAN_H to the CAN_H pin of the bus, doing the same for the CAN_L pin. Then use the following commands:
candump can0
# This command will echo all data received on the bus to the terminal
cansend can0 7Df#03010c
#This command will send out the above CAN packet to the bus
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
This device uses the i.MX6UL CPU, running at 696 MHz, based upon a Cortex-A7 core and targeting low power consumption.
Refer to NXP's documentation for more detailed information on the i.MX6UL.
GPIO
The i.MX6UL CPU and FPGA GPIO are exposed using a kernel character device. This interface provides a set of files and directories for interacting with GPIO which can be used from any language that interact with special files in linux using ioctl() or similar. For our platforms, we pre-install the "libgpiod" library and binaries. Documentation on these tools can be found here. This section only covers using these userspace tools and does not provide guidance on using the libgpiod library in end applications. Please see the libgpiod documentation for this purpose.
A user with suitable permissions to read and write /dev/gpiochip* files can immediately interact with GPIO pins. For example, to see if input power has failed:
gpioget 4 0
Multiple pins in the same chip can be read simultaneously by passing multiple pin numbers separated by spaces.
To write to a pin, the 'gpioset' command is used. For example, to set Relay 1:
gpioset 4 4=1
Multiple pins in the same chip can be set simultaneously by passing multiple pin=value pairs separated by spaces.
If a call with 'gpioset' or 'gpioget' fails with "Device or resource busy," that means that specific GPIO is claimed by another device. The command 'cat /sys/kernel/debug/gpio' can be used to get a list of all of the system GPIO and what has claimed them.
The 'gpiomon' tool can be used to monitor pins for changes.
Schematic Net Name | Chip | Line | Location |
---|---|---|---|
AN_CH1 | 0 | 0 | ADC Pin 1 |
AN_CH2 | 0 | 1 | ADC Pin 3 |
I2C_1_CLK | 0 | 2 | Onboard I2C |
I2C_1_DAT | 0 | 3 | Onboard I2C |
EN_SD_CARD_3.3V [1] | 0 | 4 | Onboard |
AN_CH3 | 0 | 5 | ADC Pin 5 |
ETH_MDIO | 0 | 6 | Onboard |
ETH_MDC | 0 | 7 | Onboard |
AN_CH4 | 0 | 8 | ADC Pin 7 |
AN_CH5 | 0 | 9 | ADC Pin 9 |
SEL_XBEE_USB [2] | 0 | 11 | Onboard USB MUX |
FPGA_RESET [3] | 0 | 13 | Onboard |
MAGNET_IRQ | 0 | 14 | Onboard |
CONSOLE_TXD | 0 | 16 | Onboard |
CONSOLE_RXD | 0 | 17 | Onboard |
EN_RED_LED# [4] | 0 | 18 | Onboard LED5 |
EN_GRN_LED# [4] | 0 | 19 | Onboard LED2 |
EN_XBEE_USB [1] | 0 | 21 | Onboard |
UART3_TXD | 0 | 24 | Bluetooth UART |
UART3_RXD | 0 | 25 | Bluetooth UART |
UART3_CTS# | 0 | 26 | Bluetooth UART |
UART3_RTS# | 0 | 27 | Bluetooth UART |
UART4_TXD | 0 | 28 | Modem UART |
UART4_RXD | 0 | 29 | Modem UART |
EN_DIO_FET | 0 | 30 | DIO Header pin 4 |
NIM_PWR_ON | 0 | 31 | Onboard |
ENET1_RX_DATA0 | 1 | 0 | Onboard |
ENET1_RX_DATA1 | 1 | 1 | Onboard |
ENET1_RX_EN | 1 | 2 | Onboard |
ENET1_TX_DATA0 | 1 | 3 | Onboard |
ENET1_TX_DATA1 | 1 | 4 | Onboard |
ENET1_TX_EN | 1 | 5 | Onboard |
ENET1_TX_CLK | 1 | 6 | Onboard |
ENET1_RX_ER | 1 | 7 | Onboard |
ENET2_RX_DATA0 | 1 | 8 | Onboard |
ENET2_RX_DATA1 | 1 | 9 | Onboard |
ENET2_RX_EN | 1 | 10 | Onboard |
ENET2_TX_DATA0 | 1 | 11 | Onboard |
ENET2_TX_DATA1 | 1 | 12 | Onboard |
ENET2_TX_EN | 1 | 13 | Onboard |
ENET2_TX_CLK | 1 | 14 | Onboard |
ENET2_RX_ER | 1 | 15 | Onboard |
EMMC_CMD | 1 | 16 | Onboard eMMC |
EMMC_CLK | 1 | 17 | Onboard eMMC |
EMMC_D0 | 1 | 18 | Onboard eMMC |
EMMC_D1 | 1 | 19 | Onboard eMMC |
EMMC_D2 | 1 | 20 | Onboard eMMC |
EMMC_D3 | 1 | 21 | Onboard eMMC |
EN_USB_5V [5] | 2 | 0 | Onboard |
WIFI_IRQ | 2 | 1 | Onboard |
UART4_CTS# | 2 | 3 | Modem UART |
WDOG# | 2 | 4 | Onboard |
I2C_3_DAT | 2 | 5 | I2C data |
I2C_3_CLK | 2 | 6 | I2C clock |
ISA_RESET | 2 | 7 | PC104 B2 |
ISA_IOCHK | 2 | 8 | PC104 A1 |
LCD_PIN7 | 2 | 9 | LCD Header pin 7 |
LCD_PIN8 | 2 | 10 | LCD Header pin 8 |
LCD_PIN9 | 2 | 11 | LCD Header pin 9 |
LCD_PIN10 | 2 | 12 | LCD Header pin 10 |
CAN_1_TXD | 2 | 13 | Onboard CAN |
CAN1_RXD_3V | 2 | 14 | Onboard CAN |
LCD_PIN11 | 2 | 15 | LCD Header pin 11 |
LCD_PIN12 | 2 | 16 | LCD Header pin 12 |
LCD_PIN13 | 2 | 17 | LCD Header pin 13 |
LCD_PIN14 | 2 | 18 | LCD Header pin 14 |
LCD_WR# | 2 | 19 | LCD Header pin 6 |
LCD_EN | 2 | 20 | LCD Header pin 5 |
LCD_RS | 2 | 21 | LCD Header pin 3 |
SYS_RESET# [6] | 2 | 22 | Onboard |
SD_CMD | 2 | 23 | Onboard MicroSD |
SD_CLK | 2 | 24 | Onboard MicroSD |
SD_D0 | 2 | 25 | Onboard MicroSD |
SD_D1 | 2 | 26 | Onboard MicroSD |
SD_D2 | 2 | 27 | Onboard MicroSD |
SD_D3 | 2 | 28 | Onboard MicroSD |
FPGA_FLASH_SELECT [1] | 3 | 0 | Onboard |
DETECT_94-120 [1] | 3 | 1 | Onboard |
EIM_AD_08 | 3 | 2 | EIM Interface to FPGA |
EIM_AD_09 | 3 | 3 | EIM Interface to FPGA |
EIM_AD_10 | 3 | 4 | EIM Interface to FPGA |
EIM_AD_11 | 3 | 5 | EIM Interface to FPGA |
EIM_AD_12 | 3 | 6 | EIM Interface to FPGA |
EIM_AD_13 | 3 | 7 | EIM Interface to FPGA |
EIM_AD_14 | 3 | 8 | EIM Interface to FPGA |
EIM_AD_15 | 3 | 9 | EIM Interface to FPGA |
EIM_IRQ | 3 | 10 | EIM Interface to FPGA |
EIM_BLK | 3 | 11 | EIM Interface to FPGA |
SPI_3_CS# | 3 | 12 | WIFI SPI bus |
SPI_3_CLK | 3 | 13 | WIFI SPI bus |
SPI_3_MOSI | 3 | 14 | WIFI SPI bus |
SPI_3_MISO | 3 | 15 | WIFI SPI bus |
EIM_WAIT# | 3 | 16 | EIM Interface to FPGA |
EIM_CS0# | 3 | 17 | EIM Interface to FPGA |
EIM_OE# | 3 | 18 | EIM Interface to FPGA |
EIM_WE# | 3 | 19 | EIM Interface to FPGA |
EIM_LBA# | 3 | 20 | EIM Interface to FPGA |
EIM_AD_00 | 3 | 21 | EIM Interface to FPGA |
EIM_AD_01 | 3 | 22 | EIM Interface to FPGA |
EIM_AD_02 | 3 | 23 | EIM Interface to FPGA |
EIM_AD_03 | 3 | 24 | EIM Interface to FPGA |
EIM_AD_04 | 3 | 25 | EIM Interface to FPGA |
EIM_AD_05 | 3 | 26 | EIM Interface to FPGA |
EIM_AD_06 | 3 | 27 | EIM Interface to FPGA |
EIM_AD_07 | 3 | 28 | EIM Interface to FPGA |
GYRO_INT | 4 | 0 | Accelerometer/gyro interrupt |
FPGA_IRQ | 4 | 1 | EIM Interface to FPGA |
EN_EMMC_3.3V [1] | 4 | 2 | Onboard eMMC |
GPIO_DVFS [7] | 4 | 3 | Onboard |
WIFI_RESET# | 4 | 5 | Onboard WIFI |
EN_WIFI_PWR | 4 | 6 | Onboard WIFI |
EN_CL_1 | 4 | 7 | ADC Current loop enable |
EN_CL_2 | 4 | 8 | ADC Current loop enable |
EN_CL_3 | 4 | 9 | ADC Current loop enable |
DIO_PIN1 | 5 | 1 | DIO Header pin 1 |
DIO_PIN3 | 5 | 2 | DIO Header pin 3 |
DIO_PIN5 | 5 | 3 | DIO Header pin 5 |
DIO_PIN7 | 5 | 4 | DIO Header pin 7 |
DIO_PIN8 | 5 | 5 | DIO Header pin 8 |
DIO_PIN9 | 5 | 6 | DIO Header pin 9 |
DIO_PIN11 | 5 | 7 | DIO Header pin 11 |
DIO_PIN13 | 5 | 8 | DIO Header pin 13 |
DIO_PIN15 | 5 | 9 | DIO Header pin 15 |
DIO_SPI_MISO | 5 | 10 | SPI MISO |
DIO_SPI_CS#[8] | 5 | 11 | DIO Header pin 6 |
SILAB_CLK [1] | 5 | 12 | Onboard |
SILAB_DAT [1] | 5 | 13 | Onboard |
MIKRO_RESET# | 6 | 0 | Mikrobus header pin 2 |
ISA_BALE | 6 | 1 | PC104 Header pin B28 |
ISA_TC | 6 | 2 | PC104 Header pin B27 |
ISA_ENDX | 6 | 3 | PC104 Header pin B08 |
EN_NIMBEL_3V3 | 6 | 4 | Nimbel VIN voltage |
ISA_IORDY | 6 | 5 | PC104 Header pin A10 |
ISA_REFRESH | 6 | 6 | PC104 Header pin B19 |
ISA_DRQ1 | 6 | 7 | PC104 Header pin B18 |
ISA_DACK1 | 6 | 8 | PC104 Header pin B17 |
ISA_DRQ2 | 6 | 9 | PC104 Header pin B06 |
ISA_DACK2 | 6 | 10 | PC104 Header pin B26 |
EN_NIMBEL_4V | 6 | 11 | Nimbel VIN voltage |
ISA_DRQ3 | 6 | 12 | PC104 Header pin B16 |
ISA_DACK3 | 6 | 13 | PC104 Header pin B15 |
ISA_CN_D03 | 7 | 0 | PC104 Header pin D03 |
ISA_CN_D04 | 7 | 1 | PC104 Header pin D04 |
ISA_CN_D05 | 7 | 2 | PC104 Header pin D05 |
ISA_CN_D06 | 7 | 3 | PC104 Header pin D06 |
ISA_CN_D07 | 7 | 4 | PC104 Header pin D07 |
ISA_CN_D08 | 7 | 5 | PC104 Header pin D08 |
ISA_CN_D09 | 7 | 6 | PC104 Header pin D09 |
ISA_CN_D10 | 7 | 7 | PC104 Header pin D10 |
ISA_CN_D11 | 7 | 8 | PC104 Header pin D11 |
ISA_CN_D12 | 7 | 9 | PC104 Header pin D12 |
ISA_CN_D13 | 7 | 10 | PC104 Header pin D13 |
ISA_CN_D14 | 7 | 11 | PC104 Header pin D14 |
ISA_CN_D15 | 7 | 12 | PC104 Header pin D15 |
- ↑ 1.0 1.1 1.2 1.3 1.4 1.5 1.6 This is controlled automatically on startup to give the SD card a clean reset, but otherwise thsi should not be toggled manually.
- ↑ default is input with pulldown (0). If driven high, this muxes the bottom port of the dual high USB port to the XBEE header. If low or input, no USB is present on this header. This USB is needed for cell modules, but interferes with older serial modules where these usb pins are reserved. See your XBEE/Nimbelink device's datasheet to verify if USB is needed.
- ↑ This is handled automatically on startup
- ↑ 4.0 4.1 See /sys/class/leds/ for interacting with these LEDs rather than toggling the GPIO directly.
- ↑ High by default. This allows power cycling USB perihperals in the field.
- ↑ Ethernet PHY and USB hub reset. This is automatically controlled during startup and should not be toggled.
- ↑ This is under control of the kernel and should never be manually adjusted
- ↑ This pin is an output only
eMMC Interface
The i.MX6UL SD card controller supports the MMC specification, the TS-7250-V3 includes a soldered down eMMC IC to provide on-board flash media.
Our default software image contains 2 partitions:
Device | Contents |
---|---|
/dev/mmcblk0 | eMMC block device |
/dev/mmcblk0boot0 | eMMC boot partition |
/dev/mmcblk0boot1 | eMMC boot partition |
/dev/mmcblk0p1 | Full Debian Linux partition |
This platform includes an eMMC device, a soldered down MMC flash device. Our off the shelf builds are 4 GB, but up to 64 GB are available for customized builds. The eMMC flash appears to Linux as an SD card at /dev/mmcblk0. The eMMC includes additional boot partitions that are used by U-Boot and are not affected by the eMMC partition table.
The eMMC module has a similar concern by default to SD cards in that they should not be powered down during a write/erase cycle. However, this eMMC module includes support for setting a fuse for a "Write Reliability" mode, and a "psuedo SLC (pSLC)" mode. With both of these enabled all writes will be atomic to 512 B and each NAND cell will be treated as a single layer rather than a multi-layer cell. If a sector is being written during a power loss, a block is guaranteed to have either the old or new data. Even in cases where the wrong data is present on the next boot, fsck is often able to deal with the older data being present in a 512 B block. The downsides to setting these modes are that it will reduce the overall write speed and halve the available space on the eMMC to roughly 1.759 GiB. Please note that even with these settings, Technologic Systems strongly recommends designing the end application to eliminate any situations where a power-loss event can occur while any disk is mounted as read/write.
The 'mmc-utils' package is used to enable these modes. The command is pre-installed on the latest image. Additionally we have created a script to safely enable the write reliability and pSLC modes. Since the U-Boot binary and environment reside on the eMMC, care must be taken to save the current state of the boot partitions, enable the modes, restore the boot partitions, and re-enable proper booting options. This script can be used in combination with the production mechanism scripting to complete these steps as part of an end application production process.
WARNING: | Enabling these modes causes all data on the disk to become invalid and must be rewritten. Do not attempt to run the 'mmc' commands from the script individually, all steps in the script must occur as they are or the unit may be unable to boot. If there are any failures of the script, care must be taken to resolve any issues while the unit is still booted or it may fail to boot in the future. |
Note: | Enabling these modes is a one-way operation, it is not possible to undo them once they are made. Because of this, setting these eMMC modes will invalidate Technologic Systems' return/replacement warranty on the unit. See the warranty section for more information on this. |
The 'emmc_reliability' script can be found in the TS-7100 utilities github repository.
WARNING: | Do not run this on the p1 revision boards |
The script must be run when boot from any media other than eMMC, such as NFS, or USB. No partition of the eMMC disk can be mounted when these commands are run. Doing so may result in corruption or inability for the unit to boot. Once the pSLC mode is enabled, all data on the disk will become invalid. This means the partition table will need to be re-created, the filesystems formatted, and all filesystem contents re-written to disk. This is why we recommend using this script in conjunction with the production mechanism scripting. The 'emmc_reliability' script can be run first, then the rest of the production script can create and format the partitions as well as write data to disk.
The script requires a single argument, the device node of the eMMC disk, and will output verbosely to stderr. Any specific errors will also be printed out on stderr.
Example usage:
./emmc_reliability /dev/mmcblk0
Upon successful run, the script will return 0. Any errors will return a positive code. See the script for detailed error code information.
Ethernet Ports
The NXP processor implements two 10/100 ethernet controllers with support built into the Linux kernel. Standard Linux utilities such as ifconfig/ip can be used to control this interface. See the Configuring the Network section for more details. For the specifics of this interface see the CPU manual.
FPGA
FPGA Registers
The TS-7250-V3 FPGA is connected to the CPU over the WEIM bus. This provides 8-bit, 16-bit, or 32-bit access to the FPGA mapped at 0x5000_0000.
For example, to read the FPGA information at the first register of the syscon:
root@ts-imx6ul:~# memtool md -l 0x50004000+4
50004000: 00000006
FPGA Top Level Decode
Offset | Description |
---|---|
0x0000 | UART 16550 #0 |
0x0100 | Opencore SPI controller #0 |
0x0120 | Opencore SPI controller #1 |
0x0180 | FPGA ADC 0 |
0x0188 | Opencore I2C Controller #0 |
0x1a8 | FPGA PWM 0 |
0x4000 | FPGA Syscon |
FPGA 16550
This FPGA includes a 16550 UART peripheral that can be used as a standard Linux serial port. It is not recommended to interact directly with these registers.
FPGA SPI
This FPGA includes a pair of SPI master devices based on the opencore SPI controller supporting up to 19.8MHz speeds. This supports onboard peripherals with the DIO header, and the mikrobus header.
Bus | CS | Description |
---|---|---|
0 | 0 | DIO Header /dev/spidev4.0 |
1 | #FRAM | |
2 | FPGA SPI Flash [1] | |
1 | 0 | Mikrobus /dev/spidev5.0 |
- ↑ It is not recommended to access this (/dev/mtdblock0) flash unless suggested by support.
The /dev/spidev* devices can be accessed from Linux's userspace. See the kernel spidev documentation for more information on interfacing with the SPI peripherals from C.
Other languages also have bindings to interface with spidev:
This controller is based on the opencore, but includes modifications to ignore "RX_NEGEDGE/TX_NEGEDGE" bits (CTRL 9/10), and instead add CPOL and CPHA (CTRL 14/15) to support all SPI 4 modes.
FPGA Syscon
The FPGA syscon is the main system control block of the FPGA. Contained in this region is the FPGA GPIO, PWM, and IRQ control. It is not recommended to interact directly with these registers unless directed to do so by other manual sections.
Some registers are dual purpose, having separate read and write functionality; while others may only have write functionality. Registers that do not read and write the same are indicated with "(RD)" and "(WR)" notation. All other registers read and write the same data set. Any unlisted register addresses are Reserved / Undefined.
Offset | Bits | Description |
---|---|---|
0x00 (RD) | 31:0 | Revision and Info Register. |
0x08 | 31:9 | Reserved |
8 | isa_gpio_en (RW) (reset 0). If set all ISA pins are GPIO. | |
7 | mikro_uart_gpio_en (RW) (reset 0). If set, mikrobus txd/rxd are GPIO | |
6 | mikro_pwm_gpio_en (RW) (reset 0). If set, mikrobus PWM is GPIO | |
5 | mikro_i2c_gpio_en (RW) (reset 0). If set, mikrobus I2C pins are GPIO | |
4 | mikro_spi_gpio_en (RW) (reset 0). If set, mikrobus SPI pins are GPIO | |
3:0 | Board Strap value | |
0x10 (RD) | 15:0 | DIO bank 0 Pin State |
0x10 (WR) | 15:0 | DIO bank 0 Data Set |
0x12 (WR) | 15:0 | DIO bank 0 Output Enable Set |
0x14 (RD) | 15:0 | DIO bank 0 Data |
0x14 (WR) | 15:0 | DIO bank 0 Data Clear |
0x16 (RD) | 15:0 | DIO bank 0 Output Enable |
0x16 (WR) | 15:0 | DIO bank 0 Output Enable Clear |
0x1C (WR) | 15:4 | Reserved |
3:0 | Duty cycle of LCD_BIAS | |
0x20 (WR) | 31:0 | Fractional clock generator [1] |
0x24 (RD) | 31:0 | IRQ Status |
0x24 (WR) | 31:0 | Fractional PWM generator |
0x40 (RD) | 15:0 | DIO bank 1 Pin State |
0x40 (WR) | 15:0 | DIO bank 1 Data Set |
0x42 (WR) | 15:0 | DIO bank 1 Output Enable Set |
0x44 (RD) | 15:0 | DIO bank 1 Data |
0x44 (WR) | 15:0 | DIO bank 1 Data Clear |
0x46 (RD) | 15:0 | DIO bank 1 Output Enable |
0x46 (WR) | 15:0 | DIO bank 1 Output Enable Clear |
0x48 | 31:0 | IRQ mask |
0x50 | 31:0 | ISA memory window |
0x54 (RD) | 15:0 | DIO bank 2 Pin State |
0x54 (WR) | 15:0 | DIO bank 2 Data Set |
0x56 (WR) | 15:0 | DIO bank 2 Output Enable Set |
0x58 (RD) | 15:0 | DIO bank 2 Data |
0x58 (WR) | 15:0 | DIO bank 2 Data Clear |
0x5a (RD) | 15:0 | DIO bank 2 Output Enable |
0x5a (WR) | 15:0 | DIO bank 2 Output Enable Clear |
0x5c (RD) | 15:0 | DIO bank 3 Pin State |
0x5c (WR) | 15:0 | DIO bank 3 Data Set |
0x5e (WR) | 15:0 | DIO bank 3 Output Enable Set |
0x60 (RD) | 15:0 | DIO bank 3 Data |
0x60 (WR) | 15:0 | DIO bank 3 Data Clear |
0x5a (RD) | 15:0 | DIO bank 3 Output Enable |
0x62 (WR) | 15:0 | DIO bank 3 Output Enable Clear |
0x64 (RD) | 15:0 | DIO bank 4 Pin State |
0x64 (WR) | 15:0 | DIO bank 4 Data Set |
0x66 (WR) | 15:0 | DIO bank 4 Output Enable Set |
0x68 (RD) | 15:0 | DIO bank 4 Data |
0x68 (WR) | 15:0 | DIO bank 4 Data Clear |
0x6a (RD) | 15:0 | DIO bank 4 Output Enable |
0x6a (WR) | 15:0 | DIO bank 4 Output Enable Clear |
0x6c (RD) | 15:0 | DIO bank 5 Pin State |
0x6c (WR) | 15:0 | DIO bank 5 Data Set |
0x6e (WR) | 15:0 | DIO bank 5 Output Enable Set |
0x70 (RD) | 15:0 | DIO bank 5 Data |
0x70 (WR) | 15:0 | DIO bank 5 Data Clear |
0x72 (RD) | 15:0 | DIO bank 5 Output Enable |
0x72 (WR) | 15:0 | DIO bank 5 Output Enable Clear |
- ↑ Note that this is also used for UART clock generation.
FPGA IRQs
Bit | Description |
---|---|
31:21 | Reserved |
20 | I2C IRQ |
19 | ADC sample ready |
18 | mikro_int |
17 | PC104 IRQ9 |
16 | PC104 IRQ7 |
15 | PC104 IRQ6 |
14 | PC104 IRQ5 |
13 | PC104 IRQ3 |
12:11 | Reserved |
10 | SPI core #1 IRQ |
9 | SPI core #0 IRQ |
8:0 | UART 8:0 IRQs |
FPGA ADC
The TS-7250-V3 includes a simple low speed ADC to support the analog input on mikrobus modules.
- 304hz sample rate
- 8-bits resolution
- 10kohm input impedance
- 0-6V input range
- 3% absolute accuracy
This ADC is accessed using the IIO subsystem. One time samples can be read from /sys/:
root@tsimx6:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw 127 root@tsimx6:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_scale 25.781250000
The raw value is 0-255, and the scale value converts this to real world values. For example, 127*25.78125=3274.21875mV.
Faster samples, up to 304hz, are available using the buffer interface.
root@tsimx6:~# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage0_en root@tsimx6:~# iio_readdev iio:device0 | hexdump -C WARNING: High-speed mode not enabled 00000000 80 00 00 00 00 00 00 00 4c a8 d9 e8 b7 33 83 15 |........L....3..| 00000010 7f 00 00 00 00 00 00 00 df 8f 22 e9 b7 33 83 15 |.........."..3..| 00000020 7f 00 00 00 00 00 00 00 b7 aa 55 e9 b7 33 83 15 |..........U..3..| 00000030 80 00 00 00 00 00 00 00 e9 d7 86 e9 b7 33 83 15 |.............3..|
In this case, column 1 that starts with 80 is the ADC value. Columns 2-8 are 0 padding. Columns 9-16 are the 64-bit ns timestamp. This is accurate to approximately 10us.
The ADC buffers can also be filled using libiio directly:
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <assert.h>
#include <inttypes.h>
#include <iio.h>
static bool stop;
static void handle_sig(int sig)
{
stop = true;
}
int main (int argc, char **argv)
{
const struct iio_data_format *fmt;
static struct iio_context *ctx;
static struct iio_buffer *rxbuf;
struct iio_channel *chn;
struct iio_device *dev;
/* Catch ctrl+c */
signal(SIGINT, handle_sig);
ctx = iio_create_default_context();
assert(ctx);
iio_context_set_timeout(ctx, 10000);
assert(iio_context_get_devices_count(ctx) > 0);
dev = iio_context_find_device(ctx, "50000180.mikro_adc");
assert(dev);
chn = iio_device_get_channel(dev, 0); /* voltage0 */
assert(chn);
iio_channel_enable(chn);
fmt = iio_channel_get_data_format(chn);
assert(fmt);
rxbuf = iio_device_create_buffer(dev, 256, false);
assert(rxbuf);
printf("%s\n", iio_channel_get_id(chn));
while (!stop) {
ssize_t nbytes;
uint8_t *dat;
nbytes = iio_buffer_refill(rxbuf);
if (nbytes < 0) {
printf("Error refilling buf %d\n",(int) nbytes);
break;
}
for (dat = iio_buffer_first(rxbuf, chn);
dat < (uint8_t *)iio_buffer_end(rxbuf);
dat += iio_buffer_step(rxbuf)) {
printf("%d\n", dat[0]);
//printf("%.0f,\n", (float)dat[0] * fmt->scale);
}
}
iio_buffer_destroy(rxbuf);
iio_channel_disable(chn);
iio_context_destroy(ctx);
return 0;
}
For most users we recommend using the existing linux drivers, but the hardware core can be found at 0x50000180. It is a single 32-bit register:
Bits | Reset value | Description |
---|---|---|
31:24 | 0x55 | Reserved |
23:16 | 0x0 | sample |
15:3 | 0x0 | Reserved |
2 | 0 | sample_missed [1] |
1 | 0 | sample_ready [2] |
0 | 1 | standby_en |
FPGA I2C
The TS-7250-V3 supports the opencore I2C controller which is used for Mikrobus I2C.
The Mikrobus i2c port is /dev/i2c-4. Scan for devices with:
i2cdetect 4
This will show what addresses ack on the bus. Linux i2c-tools (i2cdetect, i2cget, i2cset) can be used to interface with devices, or custom clients can be written.
FPGA PWM
The TS-7250-V3 includes a PWM core that supports 10-bit duty/period, a 79.2mhz input clock, and 12 values of input clock shift.
Linux supports this API through the /sys/ interface using file I/O. First export the pwm channel to enable it:
# Export PWM channel 0
echo 0 > /sys/class/pwm/pwmchip0/export
File | Description |
---|---|
/sys/class/pwm/pwmchip0/pwm0/period | Period in nanoseconds. Must be bigger than the duty cycle or writes will fail. Can only change when the pwm is disabled. |
/sys/class/pwm/pwmchip0/pwm0/duty_cycle | Duty cycle in nanoseconds. Can change at any time, must be less than period. |
/sys/class/pwm/pwmchip0/pwm0/enable | When 1, pwm is outputting. When 0, outputs idle state of the PWM. |
/sys/class/pwm/pwmchip0/pwm0/polarity | When "normal", idle high and duty cycle low. When "inversed", idle low and duty cycle high. A valid period must be set before this can be changed. |
For example, for a 50hz signal with 25% duty cycle:
# Set Period to 20ms
echo 20000000 > /sys/class/pwm/pwmchip0/pwm0/period
# Set duty cycle to 5ms
echo 5000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
# Enable PWM and output 50hz signal
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
# Duty cycle can be changed while it is enabled
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
The Linux PWM API will attempt to arrive at the exact period at the cost of the duty cycle resolution. For the most possible duty cycle resolution use one of the max period ns values from the table below.
Shift | PWM Input Frequency (hz) | Max Period (ns) | Max Period (hz) |
---|---|---|---|
0 | 79200000 | 12917 | 77419 |
1 | 39600000 | 25833 | 38710 |
2 | 19800000 | 51667 | 19355 |
3 | 9900000 | 103333 | 9677 |
4 | 4950000 | 206667 | 4839 |
5 | 2475000 | 413333 | 2419 |
6 | 1237500 | 826667 | 1210 |
7 | 618750 | 1653333 | 605 |
8 | 309375 | 3306667 | 302 |
9 | 154687 | 6613333 | 151 |
10 | 77343 | 13226795 | 76 |
11 | 38671 | 26453932 | 38 |
If period is set to one of these values, the full 10 bits of duty cycle is available. Past that, the Linux API will use the closest available value. Debug output can be enabled with:
echo "file pwm-ts.c +p" > /sys/kernel/debug/dynamic_debug/control
If this is enabled, the kernel can output additional information after setting a frequency:
echo 0 > /sys/class/pwm/pwmchip0/export
# 10ms period:
echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/period
# 5ms duty cycle:
echo 5000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
dmesg | tail
This will output:
[ 75.758146] ts-pwm 500001a8.mikro_pwm: cycle=1293661 shift=10 cnt=773 [ 75.758184] ts-pwm 500001a8.mikro_pwm: shift=10 cnt=773 duty_cnt=387
The last value in cnt indicates how much resolution is available for the duty cycle at this given period. In the best case there are 10 bits (0-2047) to specify duty cycle, but this above example is 0-773 to arrive at this particular period. You can determine the duty cycle increments with period / cnt. From the above example:
10000000 / 773 = 12936.61
The duty cycle can then be configured in increments of 12936ns. Smaller values will round to the closest value.
This PWM will allow a max speed of 79.2MHz / 3 = 26.4MHz, but this will sacrifice all of the available duty cycle except an on/50%/off. The slowest speed is highest divisor at 38hz.
While the Linux driver is recommended for most users, the PWM core is located at 0x500001a8.
Offset | Bits | Description |
---|---|---|
0x0 | 15:2 | Reserved |
1 | Inversed (0 = idle high, duty cycle low), (1 = idle low, duty cycle high) | |
0 | Enabled | |
0x2 | 15:10 | Reserved |
9:0 | Period | |
0x4 | 15:10 | Reserved |
9:0 | Duty Cycle | |
0x6 | 15:4 | Reserved |
3:0 | shift (Clock frequency = 79200000 / (1 >> shift)) |
PC104 Bus
The TS-7250-V3 includes an ISA bus for compatibility with PC104 peripherals. Arm itself has not traditionally had an ISA bus as part of its architecture, so this behaves differently than an x86 where ISA is typically used.
To access the PC104 bus in userspace, open, read, and write the files here:
/sys/bus/platform/devices/50004050.fpgaisa/
File | Description |
---|---|
io8 | 8-bit strobes on IOR/IOW |
io16 | 16-bit strobes on IOR/IOW |
ioalt16 | 16-bit strobes on IOR/IOW with an alternate pinout |
mem8 | 8-bit strobes on MEMR/MEMW |
mem16 | 16-bit strobes on MEMR/MEMW |
memalt16 | 16-bit strobes on MEMR/MEMW with an alternate pinout |
Any programming language can interface with these using standard file IO. Open a file descriptor to one or more of these files, and seek to the offset of the address you are accessing. Use read/write calls to access data on these busses.
For 16-bit accesses the address must always be aligned to an even byte, and reads/writes must always access multiple of 2 bytes at a time.
For C, or languages with a foreign function interface, we provide a library / header which can be used to handle these accesses.
For python, a simple pc104.py can access the bus:
#!/usr/bin/env python3
import os
class PC104:
ISA_PATH = "/sys/bus/platform/devices/50004050.fpgaisa/"
def __init__(self):
self.io8fd = os.open(self.ISA_PATH + "io8", os.O_RDWR | os.O_SYNC)
self.io16fd = os.open(self.ISA_PATH + "io16", os.O_RDWR | os.O_SYNC)
self.io16altfd = os.open(self.ISA_PATH + "ioalt16", os.O_RDWR | os.O_SYNC)
self.mem8fd = os.open(self.ISA_PATH + "mem8", os.O_RDWR | os.O_SYNC)
self.mem16fd = os.open(self.ISA_PATH + "mem16", os.O_RDWR | os.O_SYNC)
self.mem16altfd = os.open(self.ISA_PATH + "memalt16", os.O_RDWR | os.O_SYNC)
def _read(self, fd, addr, size):
os.lseek(fd, addr, os.SEEK_SET)
return os.read(fd, size)
def _write(self, fd, addr, data):
os.lseek(fd, addr, os.SEEK_SET)
os.write(fd, data)
# IO 8-bit methods
def io_8_read(self, addr):
return int.from_bytes(self._read(self.io8fd, addr, 1))
def io_8_write(self, addr, val):
self._write(self.io8fd, addr, val.to_bytes(1))
# IO 16-bit methods
def io_16_read(self, addr):
return int.from_bytes(self._read(self.io16fd, addr, 2))
def io_16_write(self, addr, val):
self._write(self.io16fd, addr, val.to_bytes(2))
# IO 16-bit alternate methods
def io_16_alt_read(self, addr):
return int.from_bytes(self._read(self.io16altfd, addr, 2))
def io_16_alt_write(self, addr, val):
self._write(self.io16altfd, addr, val.to_bytes(2))
# Memory 8-bit methods
def mem_8_read(self, addr):
return int.from_bytes(self._read(self.mem8fd, addr, 1))
def mem_8_write(self, addr, val):
self._write(self.mem8fd, addr, val.to_bytes(1))
# Memory 16-bit methods
def mem_16_read(self, addr):
return int.from_bytes(self._read(self.mem16fd, addr, 2))
def mem_16_write(self, addr, val):
self._write(self.mem16fd, addr, val.to_bytes(2))
# Memory 16-bit alternate methods
def mem_16_alt_read(self, addr):
return int.from_bytes(self._read(self.mem16altfd, addr, 2))
def mem_16_alt_write(self, addr, val):
self._write(self.mem16altfd, addr, val.to_bytes(2))
def close(self):
os.close(self.io8fd)
os.close(self.io16fd)
os.close(self.io16altfd)
os.close(self.mem8fd)
os.close(self.mem16fd)
os.close(self.mem16altfd)
if __name__ == "__main__":
pc104 = PC104()
print(f'PC/104 io8 0x161 = {hex(pc104.io_8_read(0x161))}')
There is also a command line utility to access the pc104 bus:
root@tsimx6:~# pc104_peekpoke Usage pc104_peekpoke <io/mem> <8/16/alt16> <address> [value] Eg: pc104_peekpoke io 8 0x140
For kernel access to the PC104 bus see the header here. Using the existing kernel driver will handle locking between userspace and any kernel drivers such as PC104 based UARTs.
On PC104 peripherals these typically have IRQs such as IRQ5/IRQ6/IRQ7. On ARM these are mapped to other IRQ numbers. Using the fpga_intc driver, interrupts on 14/15/16 correspond with the pins on the PC104 header labelled IRQ 5, 6, and 7.
We strongly recommend using the methods described above for accessing the PC104 bus. For users needing to understand the implementation, the registers are described below.
The FPGA presents a 32-bit memory window at 0x50004050 which follows this format:
Bits | Description |
---|---|
31 | Busy/Go [1] |
30 | 1 = IO, 0 = MEM [2] |
29 | 1 = 8-bit, 0 = 16-bit |
28 | 1 = read cycle, 0 = write cycle |
27 | 0 = standard pinout, 1 = TS Pinout [3] |
26:0 | Address or Data [4] |
- ↑ On read, a 1 indicates the existing transaction is already busy. A 0 indicates it is available. If written to 0 then bits 26:0 specify address. If written to 1 this starts the bus cycle.
- ↑ Cycle type indicates if we use IOW/IOR pins, or MEMR/MEMW.
- ↑ The TS pinout is used on some platforms to remove the need for the 40-pin connnector while still supporting 16-bit peripherals. This does not affect 8-bit accesses. When enabled this uses these pins for the upper 16-bit.
PC104 pin Data bit B4 8 B17 9 B18 10 B25 11 B20 12 B26 13 B27 14 B28 15 - ↑ Accepts a written addr when BUSY/GO = 0. This is data on a write when Busy/GO=1, or on a read after BUSY/GO reads 0 after being written to 1.
PC104 Bus Timing
The TS-7250-V3 PC104 cycles are approximately 1us per access in total, on either 8 or 16-bit. The timing is not user configurable, but is known to work with most typical ISA compatible devices such as a 16550, SJA1000, and more.
PC104 Bus MMAP
On some previous PC104 implementations the PC104 bus was able to be directly memory mapped. While it is not possible on this hardware to access the bus the same way, we do have a compatibility layer that is able to expose the PC104 bus as if it were memory mapped.
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include "pc104.h"
volatile uint8_t *bus;
int main(int argc, char **argv)
{
uint8_t i = 0;
bus = pc104_mmap_init();
assert(bus != NULL);
if(bus[0x140] != 0x9b) {
fprintf(stderr, "TS-RELAY8 not found\n");
}
while(1) {
bus[0x142] = i++;
usleep(10 * 1000);
}
}
Accesses below 0x100000 cause IO accesses. Accesses from 0x100000 to 0x200000 cause MEM accesses. This code turns these mmap accesses into pc104_io/mem_8/16 calls.
This example must be compiled with:
gcc -marm test.c pc104.c -o test
PC104 Peripherals
The TS-7250-V3 is compatible with most of our PC104 devices. We do not test third party PC104 devices.
WARNING: | Do not use third party PC104 power supplies. The -12 and -5V rails are incompatible with our PC104 implementation. |
This list is of our current PC104 peripherals. While none are electrically incompatible, some may require additional driver work in order to function on this platform.
Product | Compatibility | Notes |
---|---|---|
TS-ADC16 | yes | |
TS-ADC24 | No | |
TS-BAT3 | No | |
TS-BAT10 | yes | Current example code does not support IRQs. |
TS-DIO24 | yes | Current example code does not support IRQs. |
TS-DIO64 | yes | Current example code does not support IRQs. |
TS-ISO485 | yes | |
TS-MULTI104 | yes | |
TS-RELAY8 | yes | Relays will flicker on power on for several ms. |
TS-SER1 | yes | |
TS-SER2 | yes | |
TS-SER4 | yes | |
TS-12W | yes | prevents board sleep modes |
TS-13W | yes | prevents board sleep modes |
TS-5620 | TBD | |
TS-9422 | yes | |
TS-9500 | No | |
TS-9600 | TBD | |
TS-9700 | yes | |
TS-IRIDIUM | TBD | |
TS-ETH2 | TBD | |
TS-ETH10 | TBD | |
TS-ETH100 | TBD | |
TS-RF2-AERO | TBD | |
TS-RF2-CF | TBD | |
TS-7KV | No | |
TS-RF2-ZIGBEE | TBD | |
TS-CAN1 | TBD | |
TS-NVRAM | TBD | |
TS-NVRAM2 | TBD | |
TS-MODEM2 | TBD |
TS-ADC16
Product Page | |
alt 16-bit IO |
---|
The TS-ADC16 provides 16 channels of 16-bit analog to digital conversion at 4 channels of 12-bit digital to analog conversion, 4 digital inputs, 4 16-bit edge counters, and 1 digital output. On the TS-7250-V3 this will support a max sample rate of 16khz with 2 channels enabled.
Refer to the TS-ADC16 manual for register / hardware documentation.
This example assumes only JP3 is installed on the TS-ADC16
# Verify the TS-ADC16 is detected. This should return 0x3E in the lower byte
pc104_peekpoke io alt16 0x100
The TS-ADC16 can FIFO up to 512 samples before it overruns and stops the state machine. For continuous samples the max speed is limited by how fast Linux is able to access this FIFO. If the CPU load is too great that this cannot empty the FIFO fast enough, the ADCDLY should be increased for consistent sampling.
To make Linux more deterministic the governor should be changed to performance:
echo "performance" > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
The default "ondemand" scheduler is beneficial for power savings, but when the system detects a load and it changes clock speed this can stop Linux from scheduling other processes too long that the FIFO can overflow.
The below sample c code will pull data from the FIFO as fast as possible and output it to stdout in binary form.
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include "pc104.h"
#define TSADC16_BASE 0x100
#define SAMPLE_SIZE 1024
/*
* The TS-7250-V3
* 1/32000000=31.35ns increments
2000 * 31.35ns = 62.7us. 1/0.0000627 = 15949hz sample rate
*/
#define ADCDLY 2000
/*
* We always sample from the lowest channel to the max channel
* https://docs.embeddedTS.com/TS-ADC16#ADC_pins
*/
#define MAX_CHAN_PAIR 0
int main(int argc, char **argv)
{
uint16_t reg;
int i, fifocnt, ret;
if(isatty(fileno(stdout))) {
fprintf(stderr, "Pipe to a file for raw ADC data\n");
return 1;
}
pc104_init();
if((pc104_io_16_alt_read(TSADC16_BASE) & 0xff) != 0x3E) {
fprintf(stderr, "TS-ADC16 not detected");
return 1;
}
assert(MAX_CHAN_PAIR < 8);
/* Set ADCDLY */
pc104_io_16_alt_write(TSADC16_BASE + 0x4, ((uint32_t)ADCDLY) >> 16);
pc104_io_16_alt_write(TSADC16_BASE + 0x6, ((uint32_t)ADCDLY) & 0xffff);
/* Set ADCCFG
* Trigger with SYSCOM bit
* Single ended
* 0v to 5V */
reg = 0x160 | (MAX_CHAN_PAIR << 1);
pc104_io_16_alt_write(TSADC16_BASE + 0x2, reg);
pc104_io_16_alt_write(TSADC16_BASE + 0x2, reg | 0x1);
do {
reg = pc104_io_16_alt_read(TSADC16_BASE + 0x8);
fifocnt = reg >> 6;
if(!fifocnt) {
reg = pc104_io_16_alt_read(TSADC16_BASE + 0x2);
if(reg & 0x1)
continue;
fprintf(stderr, "Increase ADCDLY, can't keep up\n");
return 1;
}
for (i = 0; i < fifocnt; i++) {
uint16_t buffer = pc104_io_16_alt_read(TSADC16_BASE + 0xa);
ret = write(1, &buffer, sizeof(uint16_t));
assert(ret == sizeof(uint16_t));
}
} while(1);
return 0;
}
This will continuously output raw binary data from the lowest to highest enabled ADC channel.
TS-BAT10
Product Page | |
8-bit IO |
---|
The TS-BAT10 is a 2000mAH 5V battery backup.
Refer to the TS-BAT10 manual for hardware documentation.
This example will charge the battery when it is low and has power, or shutdown when it does not have power and 3.3V is low.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <unistd.h>
#include "pc104.h"
#define TSBAT10_BASE 0x110
typedef enum
{
SW1_OPEN = 1 << 7,
OVER33V = 1 << 6,
VIN_OK = 1 << 5,
BATTERY_EN = 1 << 4,
BAT1CHARGING = 1 << 3,
BAT1CHARGED = 1 << 2,
BAT2CHARGING = 1 << 1,
BAT2CHARGED = 1 << 0
} StatusFlags;
typedef enum
{
RESERVED = 1 << 7,
BAT2SLOWCHARGE = 1 << 6,
BAT1SLOWCHARGE = 1 << 5,
BAT2CHARGEEN = 1 << 4,
BAT1CHARGEEN = 1 << 3,
BAT2TIMERDISABLE = 1 << 2,
BAT1TIMERDISABLE = 1 << 1,
SOFTDISABLE = 1 << 0
} ConfigurationFlags;
int main(int argc, char **argv)
{
uint8_t conf;
pc104_init();
if(argc > 1) { /* Poweroff only */
pc104_io_8_write(TSBAT10_BASE, SOFTDISABLE);
return 0;
}
conf = BAT1CHARGEEN | BAT2CHARGEEN;
while(1) {
uint8_t status;
status = pc104_io_8_read(TSBAT10_BASE);
if(status & BATTERY_EN) {
printf("Battery disabled by JP4\n");
goto SLEEP;
}
if(!(status & VIN_OK)) {
/* If we dont have 5v, and 3.3V is low, shut down*/
if(!(status & OVER33V)) {
printf("TS-BAT10 is low & has no VIN. Shutting down!\n");
system("shutdown -h now");
} else {
printf("VIN not ok, but 3.3V not low yet\n");
}
} else {
if(!(status & OVER33V)) {
/* If battery is not > 3.3V, charge */
printf("Battery is low, VIN present. Charging.\n");
pc104_io_8_write(TSBAT10_BASE, conf);
} else {
printf("VIN OK, but battery is charged\n");
}
}
SLEEP:
sleep(5);
}
return 0;
}
Compile and install this with:
gcc tsbat10.c pc104.c -o tsbat10
cp tsbat10 /usr/local/bin/
Under systemd create a service file at /etc/systemd/system/tsbat10.service
[Unit]
Description=TS-BAT10 daemon
[Service]
Type=simple
ExecStart=/usr/local/bin/tsbat10
[Install]
WantedBy=multi-user.target
Enable and start this service with:
systemctl enable --now tsbat10.service
TS-DIO24
Product Page | |
8-bit IO |
---|
The TS-DIO24 provides 24 0-5V digital I/O. The I/O connector is an Opto-22 compatible interface that provides 16 I/O points configurable as input or output (24 mA as outputs) as well as 4 dedicated outputs capable of driving 48 mA and 4 dedicated outputs capable of sinking 1 Amp
Refer to the TS-DIO24 manual for register / hardware documentation:
The TS-DIO24 currently does not have a kernel driver which would be needed to use the interrupts. The Digital inputs/outputs however can be used from userspace without a driver.
This example assumes no jumpers are installed on the TS-DIO24.
# Verify the TS-DIO24 is detected. This should return 0x54
pc104_peekpoke io 8 0x100
# Set A0 to 5V and turn off the rest of A
pc104_peekpoke io 8 0x105 0x1
# Set PORT B to to high outputs, and set PORT C to an input
pc104_peekpoke io 8 0x106 0xff # PORT B Data
pc104_peekpoke io 8 0x104 0x2 # B output, C input
# Read PORT C
pc104_peekpoke io 8 0x107
TS-DIO64
Product Page | |
8-bit IO |
---|
The TS-DIO64 provides 64 digital I/O points (32 inputs plus 32 open drain outputs) through two 34-pin locking connectors that are compatible with ribbon cables. The outputs are capable of sinking 200mA for pins 1-22, or 23-32 can sink up to 400mA. These sinking outputs support up to 40V.
Refer to the TS-DIO64 manual for register / hardware documentation:
The Digital inputs/outputs can be used from userspace without a driver.
This example assumes no jumpers are installed on the TS-DIO64.
# Verify the board is present. Should return 0xA4
pc104_peekpoke io 8 0x100
# Enable the sink on pin 1, and all other outputs off
pc104_peekpoke io 8 0x104 0x1 # Pins 1-7
pc104_peekpoke io 8 0x105 0x0 # Pins 9-16
pc104_peekpoke io 8 0x106 0x0 # Pins 17-24
pc104_peekpoke io 8 0x107 0x0 # Pins 25-32
# Read IO
pc104_peekpoke io 8 0x108 # Pins 1-7
pc104_peekpoke io 8 0x109 # Pins 9-16
pc104_peekpoke io 8 0x10a # Pins 17-24
pc104_peekpoke io 8 0x10b # Pins 25-32
TS-ISO485
Product Page | |
8-bit IO |
---|
The TS-ISO485 provides two isolated half duplex RS-485 ports, or two isolated RS-422 ports. Refer to the TS-ISO485 manual for more information about the hardware UART usage.
This peripheral implements 16550A based UARTs which require a kernel driver. Under Linux this requires a device tree change. See the Kernel compile section for more details about getting set up the compile the kernel.
In general for 16550 UARTs we recommend these kernel config options:
CONFIG_HZ_PERIODIC=y
CONFIG_HZ_1000=y
CONFIG_SERIAL_8250_TS=y
The default kernel is ideal for low power, but has some tradeoffs with latency. A 16550 only has a 16 byte FIFO and needs to be serviced with relatively low latency, so a the above options make the latency far more deterministic. These changes are necessary to run at 115200 and not drop any data.
This below example will set up the serial devices for a TS-ISO485 with the IRQ2 and IRQ4 jumpers installed. Open the device tree at arch/arm/boot/dts/imx6ul-ts7250v3.dtsi. Add the highlighted section to the device tree and recompile.
pc104bus: fpgaisa@50 {
...
#address-cells = <0x1>;
#size-cells = <0x1>;
/* TS-ISO485 COMA */
ts16550@3e8 {
compatible = "technologic,ts16550";
reg = <0x3e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>; // PC/104 IRQ 6
};
/* TS-ISO485 COMB */
ts16550@2e8 {
compatible = "technologic,ts16550";
reg = <0x2e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; // PC/104 IRQ 7
};
};
On the next boot check the "dmesg" output to verify it loaded:
root@tsimx6:~# dmesg | grep ts16550 ... [ 2.259413] ts16550 50004050.fpgaisa:ts16550@3e8: Adding 16550 UART ttyS0 [ 2.268166] ts16550 50004050.fpgaisa:ts16550@2e8: Adding 16550 UART ttyS1 ...
Now that these are loaded:
Device | Description |
---|---|
/dev/ttyS0 | COMA |
/dev/ttyS1 | COMB |
In this mode COMA/COMB are full duplex RS-485 (RS-422). See the TS-ISO485 manual for mroe details on the HD jumpers to use half duplex.
TS-MULTI104
Product Page | |
8-bit IO |
---|
The TS-MULTI-104 supports serial based Multitech Socketmodems for cellular support.
This peripheral implements 16550A based UARTs which require a kernel driver. Under Linux this requires a device tree change. See the Kernel compile section for more details about getting set up the compile the kernel.
In general for 16550 UARTs we recommend these kernel config options:
CONFIG_HZ_PERIODIC=y
CONFIG_HZ_1000=y
CONFIG_SERIAL_8250_TS=y
The default kernel is ideal for low power, but has some tradeoffs with latency. A 16550 only has a 16 byte FIFO and needs to be serviced with relatively low latency, so a the above options make the latency far more deterministic. These changes are necessary to run at 115200 and not drop any data.
This below example will set up the serial devices for a TS-MULT-104 with the IRQ6, COM1, and 1.8MHz jumpers installed. Open the device tree at arch/arm/boot/dts/imx6ul-ts7250v3.dtsi. Add the highlighted section to the device tree and recompile.
pc104bus: fpgaisa@50 {
...
#address-cells = <0x1>;
#size-cells = <0x1>;
/* TS-MULTI-104 */
ts16550@3f8 {
compatible = "technologic,ts16550";
reg = <0x3f8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>; // IRQ 6
};
};
On the next boot check the "dmesg" output to verify it loaded:
root@tsimx6:~# dmesg | grep ts16550 [ 2.259413] ts16550 50004050.fpgaisa:ts16550@3f8: Adding 16550 UART ttyS0
The device node /dev/ttyS0 can be used to access this UART. As a simple test: picocom -b 115200 /dev/ttyS0
Type in "ATI" and press enter. This should return the cell radio name, and "OK".
For cell modems requiring the 921600 baud rate, remove the 1.8MHz jumper and in the device tree add uartclk = <14745600>;
after specifying the interrupts. This will allow Linux to request the baud rate 921600.
The TS-MULTI-104 manual has a second on setting up pppd with tmobile, but refer to your specific modem's documentation for more information on setting up a connection specific to your modem/carrier.
The power to this modem is also under user control. By default, the modem will be powered.
# Turn off Cell modem power
pc104_peekpoke io 8 0x140 0x1
# Turn modem back on:
pc104_peekpoke io 8 0x140 0x0
TS-RELAY8
Product Page | |
8-bit IO |
---|
The TS-RELAY8 includes 8 SPDT relays. These are capable of switching up to 5A at 30VDC or 30VAC.
See sections of the TS-RELAY8 guide for register / jumper documentation:
WARNING: | The TS-RELAY8 will energize relays immediately on poweron due to a hardware bug with this specific combination of hardware. Make sure your usage can tolerate this small flicker on poweron of several ms. |
This example assumes no jumpers are installed on the TS-RELAY8.
# Verify the TS-RELAY8 is detected. This should return 0x9b
pc104_peekpoke io 8 0x140
# Turn on just RLY1
pc104_peekpoke io 8 0x142 0x1
#Turn on RLY1 and RLY4
pc104_peekpoke io 8 0x142 0x9
# Turn on all relays.
pc104_peekpoke io 8 0x142 0xFF
# Turn off all relays (default state)
pc104_peekpoke io 8 0x142 0x0
TS-SER1
Product Page | |
8-bit IO |
---|
The TS-SER1 provides a single RS-232 port.
This peripheral implements 16550A based UARTs which require a kernel driver. Under Linux this requires a device tree change. See the Kernel compile section for more details about getting set up the compile the kernel.
In general for 16550 UARTs we recommend these kernel config options:
CONFIG_HZ_PERIODIC=y
CONFIG_HZ_1000=y
CONFIG_SERIAL_8250_TS=y
The default kernel is ideal for low power, but has some tradeoffs with latency. A 16550 only has a 16 byte FIFO and needs to be serviced with relatively low latency, so a the above options make the latency far more deterministic. These changes are necessary to run at 115200 and not drop any data.
This below example will set up the serial devices for a TS-SER1 with the IRQ6 and COM3 jumpers installed. Open the device tree at arch/arm/boot/dts/imx6ul-ts7250v3.dtsi. Add the highlighted section to the device tree and recompile.
pc104bus: fpgaisa@50 {
...
#address-cells = <0x1>;
#size-cells = <0x1>;
/* TS-SER1 */
ts16550@3e8 {
compatible = "technologic,ts16550";
reg = <0x3e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
};
};
On the next boot check the "dmesg" output to verify it loaded:
root@tsimx6:~# dmesg | grep ts16550 [ 2.259413] ts16550 50004050.fpgaisa:ts16550@3e8: Adding 16550 UART ttyS0
The device node /dev/ttyS0 can be used to access this UART.
TS-SER2
Product Page | |
8-bit IO |
---|
The TS-SER2 provides two RS-232, RS-485 half duplex or full duplex (RS-422) ports and a parallel port. Refer to the TS-SER2 manual for hardware documentation. The parallel port is currently not supported on this platform.
This peripheral implements 16550A based UARTs which require a kernel driver. Under Linux this requires a device tree change. See the Kernel compile section for more details about getting set up the compile the kernel.
In general for 16550 UARTs we recommend these kernel config options:
CONFIG_HZ_PERIODIC=y
CONFIG_HZ_1000=y
CONFIG_SERIAL_8250_TS=y
The default kernel is ideal for low power, but has some tradeoffs with latency. A 16550 only has a 16 byte FIFO and needs to be serviced with relatively low latency, so a the above options make the latency far more deterministic. These changes are necessary to run at 115200 and not drop any data.
This below example will set up the serial devices for a TS-SER2 with JP 14 through JP18, COMB 6, and COMA 5 jumpers installed. Open the device tree at arch/arm/boot/dts/imx6ul-ts7250v3.dtsi. Add the highlighted section to the device tree and recompile.
pc104bus: fpgaisa@50 {
compatible = "technologic,pc104-bus";
reg = <0x50 0x4>;
ranges = <0 0 0x1000>;
reset-gpio = <&gpio3 7 0>;
#address-cells = <0x1>;
#size-cells = <0x1>;
/* TS-SER2 COMA */
ts16550@2e8 {
compatible = "technologic,ts16550";
reg = <0x2e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <14>;
};
/* TS-SER2 COMB */
ts16550@3e8 {
compatible = "technologic,ts16550";
reg = <0x3e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15>;
};
};
On the next boot check the "dmesg" output to verify it loaded:
root@tsimx6:~# dmesg | grep ts16550 [ 2.259413] ts16550 50004050.fpgaisa:ts16550@2e8: Adding 16550 UART ttyS0 [ 2.268166] ts16550 50004050.fpgaisa:ts16550@3e8: Adding 16550 UART ttyS1
Now that these are loaded:
Device | Description |
---|---|
/dev/ttyS0 | COMA |
/dev/ttyS1 | COMB |
In this mode COMA/COMB are full duplex RS-485 (RS-422). See the TS-ISO485 manual for mroe details on the HD jumpers to use half duplex.
TS-SER4
Product Page | |
8-bit IO |
---|
The TS-SER4 supports 4 UARTs as RS-232, RS-485, or RS-422. Refer to the TS-SER4 manual for hardware documentation.
This peripheral implements 16550A based UARTs which require a kernel driver. Under Linux this requires a device tree change. See the Kernel compile section for more details about getting set up the compile the kernel.
In general for 16550 UARTs we recommend these kernel config options:
CONFIG_HZ_PERIODIC=y
CONFIG_HZ_1000=y
CONFIG_SERIAL_8250_TS=y
The default kernel is ideal for low power, but has some tradeoffs with latency. A 16550 only has a 16 byte FIFO and needs to be serviced with relatively low latency, so a the above options make the latency far more deterministic. These changes are necessary to run at 115200 and not drop any data.
This below example will set up the serial devices for a TS-SER4 with the IRQ2, IRQ4 (selects IRQ6), and COM1 jumpers installed. Open the device tree at arch/arm/boot/dts/imx6ul-ts7250v3.dtsi. Add the highlighted section to the device tree and recompile.
pc104bus: fpgaisa@50 {
...
#address-cells = <0x1>;
#size-cells = <0x1>;
/* COMA */
ts16550@3f8 {
compatible = "technologic,ts16550";
reg = <0x3f8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
};
/* COMB */
ts16550@2f8 {
compatible = "technologic,ts16550";
reg = <0x2f8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
};
/* COMC */
ts16550@3e8 {
compatible = "technologic,ts16550";
reg = <0x3e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
};
/* COMD */
ts16550@2e8 {
compatible = "technologic,ts16550";
reg = <0x2e8 8>;
interrupt-parent = <&fpga_intc>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
};
};
On the next boot check the "dmesg" output to verify it loaded:
root@tsimx6:~# dmesg | grep ts16550 [ 2.259413] ts16550 50004050.fpgaisa:ts16550@3f8: Adding 16550 UART ttyS0 [ 2.268166] ts16550 50004050.fpgaisa:ts16550@2f8: Adding 16550 UART ttyS1 [ 2.278539] ts16550 50004050.fpgaisa:ts16550@3e8: Adding 16550 UART ttyS2 [ 2.287455] ts16550 50004050.fpgaisa:ts16550@2e8: Adding 16550 UART ttyS3
Now that these are loaded:
Device | Description |
---|---|
/dev/ttyS0 | COMA |
/dev/ttyS1 | COMB |
/dev/ttyS3 | COMC |
/dev/ttyS4 | COMD |
TS-12W
Released Mar. 2004 | |
Product Page |
The TS-12W provides 2.4 A on PC/104 5V pin and supports a VIN of 10-30 VDC. The TS-7250-V3 has a built in regulator supporting 8-48 VDC which is recommended instead, but for legacy products with existing mechanical requirements the TS-12W will continue to work. Powering the system from PC/104 does prevent the device's low power sleep mode from functioning.
Refer to the TS-12W manual for more information on hardware features.
TS-13W
Released June 2009 | |
Product Page |
The TS-13W provides 2.6 A on PC/104 5V pin and supports a VIN of 8-30 VDC. The TS-7250-V3 has a built in regulator supporting 8-48 VDC which is recommended instead, but for legacy products with existing mechanical requirements the TS-13W will continue to work. Powering the system from PC/104 does prevent the device's low power sleep mode from functioning.
Refer to the TS-13W manual for more information on hardware features.
TS-9422
Product Page | |
8-bit IO |
---|
The TS-9422 is a POST code output board designed for x86 systems. ARM does not use POST to indicate its boot status, but this board does work to display two hexadecimal values written to 0x80 on the ISA bus.
WARNING: | Make sure the board mounting holes line up on PC104. Unlike most PC104 boards this faces away from the main CPU in order to remain visible while in a stack. |
# Shows 55 on the PC104 bus
pc104_peekpoke io 8 0x80 0x55
TS-9700
Product Page | |
8-bit IO |
---|
The TS-9700 provides 8 channels of 12-bit ADC which support 0-2.5V, 0-10V, or 0-20mA. Optionally this board can include 4x 0-5V DAC channels.
Refer to the TS-9700 manual for register / hardware documentation.
This example assumes addr 0x160 selected by having JP1/2/3 removed.
The TS-9700 identifies as 0x97:
pc104_peekpoke io 8 0x161
The TS-9700 is accessed in userspace with this sample C code.
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <unistd.h>
#include "pc104.h"
#define TS9700_BASE 0x160
void ts9700_set_dac(uint8_t channel, uint16_t val)
{
assert(channel <= 3);
assert(val <= 0xFFF);
pc104_io_8_write(TS9700_BASE + 0x4, val & 0xff);
pc104_io_8_write(TS9700_BASE + 0x5, (channel << 6) | (val >> 8));
while((~pc104_io_8_read(TS9700_BASE + 0x6)) & (1 << 7)){
usleep(10); /* Wait until the DAC is ready */
}
}
uint16_t ts9700_single_sample(uint8_t channel)
{
uint16_t sample;
assert (channel < 8);
pc104_io_8_write(TS9700_BASE, channel | (1 << 4));
while((~pc104_io_8_read(TS9700_BASE)) & (1 << 7)){
usleep(9); /* Wait until the sample is ready */
}
sample = pc104_io_8_read(TS9700_BASE + 0x2);
sample |= ((uint16_t)pc104_io_8_read(TS9700_BASE + 0x3) << 8);
return sample;
}
int main(int argc, char **argv)
{
int i;
pc104_init();
/* Verify the TS-9700 is detected */
if(pc104_io_8_read(TS9700_BASE + 0x1) != 0x97) {
fprintf(stderr, "TS-9700 not detected");
return 1;
}
for (i = 0; i < 8; i++)
printf("chan%d=0x%X\n", i, ts9700_single_sample(i));
ts9700_set_dac(0, 0); // Set channel 0 to 0V
ts9700_set_dac(1, 4095); // Set to 5V (max)
ts9700_set_dac(2, 2048); // Set to 2.5V
ts9700_set_dac(3, 819); // Set to ~1V
return 0;
}
Compile this on the unit with:
gcc ts9700.c tspc104.c -o ts9700
FRAM
This device supports an optional non-volatile Ferroelectric RAM (FRAM) device. The Fujitsu MB85RS16N is a 2 KiB device, in a configuration not unlike an SPI EEPROM. However, the nature of FRAM means it is non-volatile, incredibly fast to write, and is specified with 1 trillion read/write cycles per each byte and a 200 year data retention. The device is connected to Linux and presents itself as a flat file that can be read and written like any standard Linux file.
The EEPROM file can be found at /sys/bus/spi/devices/spi4.1/eeprom.
Note: | FRAM is not present on the TS-7250-V3-SMN1I configuration. |
I2C
The i.MX6UL supports I2C at 100 kHz, or using fast mode for 400 kHz operation. This board uses two CPU I2C busses for onboard ICs.
Device | Address | Description |
---|---|---|
/dev/i2c-0 | 0x1e | #Magnetometer |
0x54 | #Silabs | |
0x68 | #RTC | |
0x6a | #IMU | |
/dev/i2c-1 | 0x20 | NXP pca9555 GPIO expander (bank 11) |
0x64 | ATSHA204 [1] |
- ↑ Not populated by default
IMU
This board features an ST ISM330DLC. This includes both a 3 axis accelerometer and gyroscope. The accelerometer has an acceleration range of ±2/±4/±8/±16 g. The gyroscope has a selectable angular range of ±125/±250/±500/±1000/±2000 Linux provides access to this chipset as part of the IIO subsystem. This is accessed using iio-tools and libiio as ism330dlc_accel, and ism330dlc_gyro.
ST ISM330 Accelerometer
The accelerometer is accessed through IIO as ism330dlc_accel with channels:
- accel_x
- accel_y
- accel_z
- timestamp
For example:
root@tsimx6ul:~# iio_attr -c ism330dlc_accel accel_x dev 'ism330dlc_accel', channel 'accel_x' (input), attr 'injection_raw', ERROR: Permission denied (-13) dev 'ism330dlc_accel', channel 'accel_x' (input), attr 'raw', value '-183' dev 'ism330dlc_accel', channel 'accel_x' (input), attr 'scale', value '0.000598' dev 'ism330dlc_accel', channel 'accel_x' (input), attr 'scale_available', value '0.000598 0.001196 0.002392 0.004785' root@tsimx6ul:~# iio_attr -c ism330dlc_accel accel_y dev 'ism330dlc_accel', channel 'accel_y' (input), attr 'injection_raw', ERROR: Permission denied (-13) dev 'ism330dlc_accel', channel 'accel_y' (input), attr 'raw', value '-292' dev 'ism330dlc_accel', channel 'accel_y' (input), attr 'scale', value '0.000598' dev 'ism330dlc_accel', channel 'accel_y' (input), attr 'scale_available', value '0.000598 0.001196 0.002392 0.004785' root@tsimx6ul:~# iio_attr -c ism330dlc_accel accel_z dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'injection_raw', ERROR: Permission denied (-13) dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'raw', value '16491' dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'scale', value '0.000598' dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'scale_available', value '0.000598 0.001196 0.002392 0.004785'
This shows a snapshot of the x, y, z values. To get the real world value, multiply the scale * the raw value. In this case:
- X: -0.109434 g
- Y: -0.174616 g
- Z: 9.861618 g
The default scale is ±2, but ±2/±4/±8/±16 can be selected by setting the scale:
dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'scale', value '0.000598' dev 'ism330dlc_accel', channel 'accel_z' (input), attr 'scale_available', value '0.000598 0.001196 0.002392 0.004785'
To set ±4, you would write the second available scale:
iio_attr -c ism330dlc_accel accel_x scale 0.001196
The scale values are not independent on this device, and setting x/y/z will set the scale for all 3.
This driver also supports pulling continuous samples using the buffer interface. These can be accessed using iio_readdev:
iio_readdev ism330dlc_accel -T 0 -s 128 > samples.bin
The format of this file is specified with iio_attr:
root@tsimx6ul:~# iio_attr -c ism330dlc_accel dev 'ism330dlc_accel', channel 'accel_x' (input, index: 0, format: le:S16/16>>0), found 4 channel-specific attributes dev 'ism330dlc_accel', channel 'accel_y' (input, index: 1, format: le:S16/16>>0), found 4 channel-specific attributes dev 'ism330dlc_accel', channel 'accel_z' (input, index: 2, format: le:S16/16>>0), found 4 channel-specific attributes dev 'ism330dlc_accel', channel 'timestamp' (input, index: 3, format: le:S64/64>>0), found 0 channel-specific attributes
The samples are padded to the nearest 8-bytes, so this means the binary format is:
Bits | Description |
---|---|
15:0 | accel_x, little endian, signed |
15:0 | accel_y, little endian, signed |
15:0 | accel_z, little endian, signed |
63:0 | timestamp, little endian, signed |
15:0 | Padding |
The unix utility hexdump supports formatting options which can parse these fields:
root@tsimx6ul:~# hexdump samples.bin --format '1/2 "X:%d " 1/2 "Y:%d " 1/2 "Z:%d " 1/8 "TS:%d" 1/2 "" "\n"' | head -n 4 X:-95 Y:-163 Z:8221 TS:200185381271666439 X:-107 Y:-147 Z:8248 TS:200190332264480519 X:-100 Y:-155 Z:8263 TS:200195283888013063 X:-95 Y:-159 Z:8253 TS:200200232540667655
This gives the raw values which can then be multiplied by the scale to get the real world value.
ST ISM330 Gyroscope
The gyroscope is accessed through IIO as ism330dlc_accel with channels:
- anglvel_x
- anglvel_y
- anglvel_z
- timestamp
For example:
root@tsimx6ul:~# iio_attr -c ism330dlc_gyro anglvel_x dev 'ism330dlc_gyro', channel 'anglvel_x' (input), attr 'raw', value '2359' dev 'ism330dlc_gyro', channel 'anglvel_x' (input), attr 'scale', value '0.000153' dev 'ism330dlc_gyro', channel 'anglvel_x' (input), attr 'scale_available', value '0.000153 0.000305 0.000611 0.001222' root@tsimx6ul:~# iio_attr -c ism330dlc_gyro anglvel_y dev 'ism330dlc_gyro', channel 'anglvel_y' (input), attr 'raw', value '-1667' dev 'ism330dlc_gyro', channel 'anglvel_y' (input), attr 'scale', value '0.000153' dev 'ism330dlc_gyro', channel 'anglvel_y' (input), attr 'scale_available', value '0.000153 0.000305 0.000611 0.001222' root@tsimx6ul:~# iio_attr -c ism330dlc_gyro anglvel_z dev 'ism330dlc_gyro', channel 'anglvel_z' (input), attr 'raw', value '2761' dev 'ism330dlc_gyro', channel 'anglvel_z' (input), attr 'scale', value '0.000153' dev 'ism330dlc_gyro', channel 'anglvel_z' (input), attr 'scale_available', value '0.000153 0.000305 0.000611 0.001222'
This shows a snapshot of the x, y, z values. To get the real world value, multiply the scale * the raw value. In this case:
- X: 0.360927 dps
- Y: -0.255051 dps
- Z: 0.422433 dps
The default scale is ±250, but ±250/±500/±1000/±2000 can be selected by setting the scale:
dev 'ism330dlc_gyro', channel 'anglvel_z' (input), attr 'scale', value '0.000153' dev 'ism330dlc_gyro', channel 'anglvel_z' (input), attr 'scale_available', value '0.000153 0.000305 0.000611 0.001222'
To set ±1000, you would write the third available scale:
iio_attr -c ism330dlc_gyro anglvel_z scale 0.000611
The scale values are not independent on this device, and setting x/y/z will set the scale for all 3.
This driver also supports pulling continuous samples using the buffer interface. These can be accessed using iio_readdev:
iio_readdev ism330dlc_gyro -T 0 -s 128 > samples.bin
The format of this file is specified with iio_attr:
root@tsimx6ul:~# iio_attr -c ism330dlc_accel dev 'ism330dlc_gyro', channel 'anglvel_x' (input, index: 0, format: le:S16/16>>0), found 3 channel-specific attributes dev 'ism330dlc_gyro', channel 'anglvel_y' (input, index: 1, format: le:S16/16>>0), found 3 channel-specific attributes dev 'ism330dlc_gyro', channel 'anglvel_z' (input, index: 2, format: le:S16/16>>0), found 3 channel-specific attributes dev 'ism330dlc_gyro', channel 'timestamp' (input, index: 3, format: le:S64/64>>0), found 0 channel-specific attributes
The samples are padded to the nearest 8-bytes, so this means the binary format is:
Bits | Description |
---|---|
15:0 | anglvel_x, little endian, signed |
15:0 | anglvel_y, little endian, signed |
15:0 | anglvel_z, little endian, signed |
63:0 | timestamp, little endian, signed |
15:0 | Padding |
The unix utility hexdump supports formatting options which can parse these fields into their raw values:
root@tsimx6ul:~# hexdump samples.bin --format '1/2 "X:%d " 1/2 "Y:%d " 1/2 "Z:%d " 1/8 "TS:%d" 1/2 "" "\n"' | head -n 40 X:-58 Y:-199 Z:24 TS:419695978925948679 X:-67 Y:-196 Z:29 TS:419701023781322503 X:-64 Y:-197 Z:28 TS:419705968690298631 X:-58 Y:-203 Z:29 TS:419711008204553991
Interrupts
Note: | This section is incomplete at this time. |
LEDs
The red and green LEDs can be controlled from userspace after bootup using the sysfs LED interface. For example, to turn on the red LED:
echo 1 > /sys/class/leds/red-led/brightness
The following LEDs are available on this system:
- red-led
- green-led
A number of triggers are also available, including timers, disk activity, and heartbeat. These allow the LEDs to represent various system activities as they occur. See the kernel LED documentation for more information on triggers and general use of LED class devices.
Magnetometer
The magnetometer is accessed through Linux's industrial I/O (IIO) subsystem as lis2mdl_magn
with channels:
- magn_x
- magn_y
- magn_z
- timestamp
For example:
root@tsimx6ul:~# iio_attr -c lis2mdl_magn -c magn_x dev 'lis2mdl_magn', channel 'magn_x' (input), attr 'raw', value '630' dev 'lis2mdl_magn', channel 'magn_x' (input), attr 'scale', value '0.001500' root@tsimx6ul:~# iio_attr -c lis2mdl_magn -c magn_y dev 'lis2mdl_magn', channel 'magn_y' (input), attr 'raw', value '-165' dev 'lis2mdl_magn', channel 'magn_y' (input), attr 'scale', value '0.001500' root@tsimx6ul:~# iio_attr -c lis2mdl_magn -c magn_z dev 'lis2mdl_magn', channel 'magn_z' (input), attr 'raw', value '9' dev 'lis2mdl_magn', channel 'magn_z' (input), attr 'scale', value '0.001500'
This shows a snapshot of the x, y, z values. To get the measured field strength along each axis, multiply the scale by the raw value to get the actual reading in milligauss. In the above example:
- X: 0.945 mG (milligauss)
- Y: -0.2475 mG
- Z: 0.0135 mG
MicroSD Interface
The i.MX6ul SDHCI driver supports MicroSD (0-2GB), MicroSDHC (4-32GB), and MicroSDXC(64GB-2TB). The linux driver provides access to this socket at /dev/mmcblk1 as a standard Linux block device.
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.
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.
Sleep
SPI
The TS-7250-V3 FPGA includes the 2 opencore SPI controllers. Under Linux these are spi4 and spi5.
Controller | Chip select | Device |
---|---|---|
spi4 | 0 | /dev/spidev4.0 DIO Header SPI bus |
1 | #FRAM | |
2 | FPGA Flash (/dev/mtdblock0) [1] | |
spi5 | 0 | /dev/spidev5.0 #Mikrobus SPI |
The /dev/spidev* devices can be accessed from Linux. See the kernel spidev documentation for more information on interfacing with the SPI peripherals from C.
Other languages also have bindings to interface with spidev:
UARTs
The TS-7250-V3 includes UARTs on the CPU, as well as 16550A compatible registers on the FPGA interface.
UART Dev. | Type | TX / + Loc. | RX / - Loc. | CTS | RTS | DCD | DTR |
---|---|---|---|---|---|---|---|
ttymxc0 | USB Console | P2 MicroUSB | P2 MicroUSB | N/A | N/A | N/A | N/A |
ttymxc2 | Bluetooth | Onboard | Onboard | N/A | N/A | N/A | N/A |
ttymxc3 | 3.3V TTL | XBEE pin 3 | XBEE pin 2 | XBEE pin 12 | N/A | N/A | N/A |
ttyS8 | RS-232 | DB9 pin 3 | DB9 pin 2 | DB9 pin 8 | DB9 pin 7 | DB9 pin 1 | DB9 pin 4 |
ttyS9 | RS-232 | COM2 pin 3 | COM2 pin 2 | COM2 pin 8 | COM2 pin 7 | N/A | N/A |
ttyS10 | RS-232 | COM3 pin 3 | COM3 pin 2 | COM3 pin 8 | COM3 pin 7 | N/A | N/A |
ttyS11 | RS-485 | COM2 pin 1 | COM2 pin 6 | N/A | N/A | N/A | N/A |
ttyS12 | RS-485 | COM2 pin 4 | COM2 pin 9 | N/A | N/A | N/A | N/A |
ttyS13 | TTL | microBUS pin 13 | microBUS pin 14 | N/A | N/A | N/A | N/A |
RS-485
RS-485 is implemented via a UART interface inside of the FPGA. This device handles automatic TXEN assertion and de-assertion for half-duplex RS-485 communication without any required settings or API calls. See the UARTs section for the location of the RS-485 port.
RS-422
While both ttyS11 and ttyS12 support RS-485 half duplex these uarts can also be used as a single full duplex RS-422. Either of these UARTs are electrically compatible with RS-485/RS-422 and support TX or RX. To implement RS-422 in software open either UART and use it for transmit, and open the other UART and only use it for receive.
USB
The TS-7250-V3 offers two USB 2.0 host ports. Power to the host ports can be controlled with the LED subsystem under the LED device "/sys/class/leds/en-usb-5v/". By writing a value greater than 0 to the "brightness" file in that folder, it will enable USB power. While setting it to 0 will turn it off. See the DIO section of the manual for more information on this. The USB A host port stack can provide 1 A total power output shared between the two ports.
Watchdog
The TS-7100 implements a WDT inside the supervisory microcontroller. A standard kernel WDT driver is in place that manages the WDT via the I2C bus. The WDT requires a userspace feeding system as the kernel has no provisions for self-feeding. Our stock distribution uses the 'watchdog' utility to check system health, set feed length, and perform feeds. Any arbitrary timeout value between 10 ms through 42949672.95 seconds is possible, with a resolution of 10 ms. Setting a timeout of 0 and issuing a feed will disable the WDT in hardware.
At power-on, the WDT in the microcontroller is live and running. This means that any failures in the boot process will cause a reboot and another attempt. From there, feeds must be manually done in U-Boot or the system booted to Linux within the default 60 second timeout. Once the kernel initializes the WDT driver, it will change the timeout and issue a single feed (default 5 minutes). Userspace must be fully booted and able to take over feeding within this time frame.
The default Linux timeout of 5 minutes was designed to accommodate very slow external I/O. For example, performing an 'fsck' on an external HDD of large sizes via USB mass storage interface, may take a number of minutes worst case. This timeout can be adjusted via the FDT file for the TS-7100. Setting this timeout to 0 will cause the WDT to be disabled in hardware as soon as the kernel is started.
The kernel driver supports the "Magic Close" feature of the WDT. This means that a 'V' character must be fed in to the watchdog file before the file is closed in order to disable the WDT. If this does not happen then the WDT is not stopped and it will continue it's countdown. This is the default behavior of our stock kernel.
Additionally, if the kernel is compiled with CONFIG_WATCHDOG_NOWAYOUT then the WDT can never be stopped once it is started at boot. This is not enabled by default in our stock kernel
See the Linux WDT API documentation for more information.
WiFi
This board uses an ATWILC3000-MR110CA IEEE 802.11 b/g/n Link Controller Module With Integrated Bluetooth® 4.0. Linux provides support for this module using the wilc3000 driver.
Summary features:
- IEEE 802.11 b/g/n RF/PHY/MAC SOC
- IEEE 802.11 b/g/n (1x1) for up to 72 Mbps PHY rate
- Single spatial stream in 2.4GHz ISM band
- Integrated PA and T/R Switch Integrated Chip Antenna
- Superior Sensitivity and Range via advanced PHY signal processing
- Advanced Equalization and Channel Estimation
- Advanced Carrier and Timing Synchronization
- Wi-Fi Direct and Soft-AP support
- Supports IEEE 802.11 WEP, WPA, and WPA2 Security
- Supports China WAPI security
- Operating temperature range of -40°C to +85°C
Specifications
Power Input Specifications
The TS-7250-V3 supports 2 input ranges. The +5V input on CN2, and the 8-28V input on CN12. The 8-28V input can also come from the PC104 connector's +12V signal.
Input | Min range | Max Range |
---|---|---|
5 VDC | 4.7 VDC [1] | 5.2 VDC |
8-28 VDC | 8 VDC | 28 VDC |
- ↑ This requires requires at least 4.7V to start up, and the onboard supervisory microcontroller will trigger a brownout reset if this dips below 4V. While the TS-7250-V3 will continue to operate at this low of a voltage, any connected devices using the 5V rail directly such as USB may not function as intended this low.
Power Consumption
The TS-7250-V3's i.MX6UL CPU is very flexible with power. It can change the running frequency as needed to consume less power or to allow for more processing power.
The Ethernet can be put into a lower power state by bringing them up, and back down on startup. This is not done by default, and helps power savings regardless of if Ethernet is connected.
ifconfig eth0 up
ifconfig eth1 up
ifconfig eth0 down
ifconfig eth1 down
ifconfig wlan0 up # only needed if WIFI is present
These tests were run with 5V input. Unless otherwise specified these tests are run with no external connections except power, booted over eMMC at an idle prompt. The above ifconfig commands are included in our tests.
Test | Avg. (W) | Peak (W) |
---|---|---|
Idle | 0.77 | 1.29 |
CPU fully loaded [1] | 1.03 | 1.45 |
CPU idle, single Ethernet port up and active [2] | 1.17 | 1.75 |
CPU fully loaded [1], single Ethernet port up and active [2] | 1.40 | 2.03 |
Supervisory Microcontroller sleep mode (ARM CPU off) | 0.055 | 0.063 |
Board Rails
External Interfaces
ADC Header
The ADC header supports 5 channels of 0-30VDC ADC. Of these 5, 3 channels support sampling 0-20mA current loops. These channels are sampled from:
iio_attr -c 2198000.adc voltage0
iio_attr -c 2198000.adc voltage1
iio_attr -c 2198000.adc voltage5
iio_attr -c 2198000.adc voltage8
iio_attr -c 2198000.adc voltage9
See the ADC section for more details on sampling these pins.
Signals | Pin Layout | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Battery Connector
The #RTC uses removable lithium cr1632 batteries.
COM2 Header
The COM2 header is a 0.1" pitch 2x5 header supporting RS-485, RS-422 and RS-232.
Signals | Pin Layout | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
COM3 Header
The COM3 header is a 0.1" pitch 2x5 header supporting CAN and RS-232.
Signals | Pin Layout | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
DB9 Connector
The DB9 (DE-9) connector provides an RS-232 port with full handshakes.
Signals | Pin Layout | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
DIO Header
The DIO header is a 0.1" pitch 2x8 header including SPI and GPIO. All pins on this header are 5V tolerant except SPI output pins. The SPI input pins are 5V tolerant and can be connected to a 5V SPI device. All of these DIO include pullups.
To use the SPI pins on this header as GPIO instead, disable SPI by changing the FPGA Syscon 0x08 bit 10:
tshwctl -a 0x8 --poke32 0x400
The DIO header is designed to provide compatibility with the KPAD accessory. This is a 4x4 numerical keypad. This is supported in userspace with the keypad.c source code, or the "keypad" utility which is included in the shiping image.
This debounces presses to 50ms, and does not repeat when numbers are held. This will output a string containing the key that is pressed. Eg:
root@tsimx6:~# keypad 1 UP DOWN 2ND ENTER
Ethernet connectors
The TS-7250-V3 supports two independent 10/100 Ethernet ports. See the Configuring the Network section of the manual for more information on configuration.
LCD Header
The LCD header is a 0.1" pitch 2x7 header including GPIO. This is designed around compatibility with the HD44780 LCD controller which includes our LCD-LED. The LCD Data pins (7-14) are 5V tolerant. These will output up to 3.3V, and the remaining control IO and PWM are 3.3V tolerant. The TS-7250-V3 Debian images include a command lcdmesg. This can be used to write to our LCD-LED display.
For example, this would write to the display:
lcdmesg "line 1" "line 2"
# Messages can also be piped to lcdmesg:
echo -e "line 1\nline 2\n" | lcdmesg
For example, running:
lcdmesg Technologic Systems
will display:
Pin 4, the LCD_BIAS pin, is used to set the contrast on the LCD.
tshwctl --address 0x1c --poke16 0x0 # Writes minimum
tshwctl --address 0x1c --poke16 0xf # Writes maximum
Signals | Pin Layout | |||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
- ↑ PWM duty cycle controlled by FPGA Syscon reg 0x1c. This may need to be tuned depending on the environment or altitude where the display is used.
mikroBUS Header
The Mikrobus header is a 0.1" pitch 2x8 header which supports the Mikroe Click board ecosystem. This header features 3.3 V, 5 V, SPI, GPIO, ADC, PWM, a UART, and PWM. All I/O on this header are FPGA 3.3-V LVTTL.
The Click boards™ standard (where Click boards™ are a modular prototyping add-on board) is openly documented, allowing for custom boards to be designed.
By default all of these headers default to their non-gpio functions. These can be changed in the FPGA syscon register 0x08. For example:
# Make all mikrobus header pins GPIO:
peekpoke 32 0x50004008 0xF0
# Set only SPI to GPIO:
peekpoke 32 0x50004008 0x10
Signals | Pin Layout | |||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
MicroSD Connector
The MicroSD socket is located near the DB9 on top of the board. See the #MicroSD Interface section for more details on the CPU controller.
MicroUSB Connector
The TS-7250-V3 features an onboard supervisory microcontroller that converts the onboard 3.3V TTL console UART (ttymxc0) into a CP2103 USB serial device.
PC104 Header
The PC/104 connector consists of four rows of pins labelled A-D. This header implements the #PC104 Bus, and optionally most pins can be GPIO.
Refer to the IO specifications for details on the IO voltages of these pins. Not all pins on the PC/104 bus are designed to be 5V tolerant, but will be in places where it is needed for compatibility with the bus.
Pins | IO Specification |
---|---|
D3-D15 [1] | PCA9555 |
A1 | CPU 3.3V |
A10, A11, A12-A31, B6, B8, B11-B20, B25-B28, B30, D1-D2 | FPGA 3.3-V LVTTL |
A2-A9, B4, B21-B23, C11-C18 | FPGA 3.3-V LVTTL+QS3861 |
B2 | Open drain with pull to 5V |
- ↑ These are only present on the models with the optional I2C port expander
Pin | Description | Pin | Description | Pin | Description | Pin | Description | ||||
---|---|---|---|---|---|---|---|---|---|---|---|
B32 | GND | A32 | GND | ||||||||
B31 | GND | A31 | ISA_ADD_00/Chip 50004064.fpga_gpio IO 0 | ||||||||
B30 | ISA_14_3_MHZ [1] | A30 | ISA_ADD_01/Chip 50004064.fpga_gpio IO 1 | ||||||||
B29 | +5V [2] | A29 | ISA_ADD_02/Chip 50004064.fpga_gpio IO 2 | ||||||||
B28 | Chip 50004040.fpga_gpio IO 1/TS mode DAT15 | A28 | ISA_ADD_03/Chip 50004064.fpga_gpio IO 3 | C19 | GND | D19 | GND | ||||
B27 | Chip 50004040.fpga_gpio IO 2/TS mode DAT14 | A27 | ISA_ADD_04/Chip 50004064.fpga_gpio IO 4 | C18 | ISA_DAT_15/Chip 5000405c.fpga_gpio IO 15 | D18 | GND | ||||
B26 | Chip 50004040.fpga_gpio IO 10/TS mode DAT13 | A26 | ISA_ADD_05/Chip 50004064.fpga_gpio IO 5 | C17 | ISA_DAT_14/Chip 5000405c.fpga_gpio IO 14 | D17 | Unused | ||||
B25 | FPGA IRQ 13/TS mode DAT11 | A25 | ISA_ADD_06/Chip 50004064.fpga_gpio IO 6 | C16 | ISA_DAT_13/Chip 5000405c.fpga_gpio IO 13 | D16 | +5V [2] | ||||
B24 | GND | A24 | ISA_ADD_07/Chip 50004064.fpga_gpio IO 7 | C15 | ISA_DAT_12/Chip 5000405c.fpga_gpio IO 12 | D15 | Chip 50004054.fpga_gpio IO 12 | ||||
B23 | FPGA IRQ 14 | A23 | ISA_ADD_08/Chip 50004064.fpga_gpio IO 8 | C14 | ISA_DAT_11/Chip 5000405c.fpga_gpio IO 11 | D14 | Chip 50004054.fpga_gpio IO 11 | ||||
B22 | FPGA IRQ 15 | A22 | ISA_ADD_09/Chip 50004064.fpga_gpio IO 9 | C13 | ISA_DAT_10/Chip 5000405c.fpga_gpio IO 10 | D13 | Chip 50004054.fpga_gpio IO 10 | ||||
B21 | FPGA IRQ 16 | A21 | ISA_ADD_10/Chip 50004064.fpga_gpio IO 10 | C12 | ISA_DAT_09/Chip 5000405c.fpga_gpio IO 9 | D12 | Chip 50004054.fpga_gpio IO 9 | ||||
B20 | TS mode DAT12 | A20 | ISA_ADD_11/Chip 50004064.fpga_gpio IO 11 | C11 | ISA_DAT_08/Chip 5000405c.fpga_gpio IO 8 | D11 | Chip 50004054.fpga_gpio IO 8 | ||||
B19 | Chip 50004040.fpga_gpio IO 6 | A19 | ISA_ADD_12/Chip 50004064.fpga_gpio IO 12 | C10 | Unused | D10 | Chip 50004054.fpga_gpio IO 7 | ||||
B18 | Chip 50004040.fpga_gpio IO 7/TS mode DAT10 | A18 | ISA_ADD_13/Chip 50004064.fpga_gpio IO 13 | C09 | Unused | D09 | Chip 50004054.fpga_gpio IO 6 | ||||
B17 | Chip 50004040.fpga_gpio IO 8/TS mode DAT9 | A17 | ISA_ADD_14/Chip 50004064.fpga_gpio IO 14 | C08 | Unused | D08 | Chip 50004054.fpga_gpio IO 5 | ||||
B16 | Chip 50004040.fpga_gpio IO 12 | A16 | ISA_ADD_15/Chip 50004064.fpga_gpio IO 15 | C07 | Unused | D07 | Chip 50004054.fpga_gpio IO 4 | ||||
B15 | Chip 50004040.fpga_gpio IO 13 | A15 | ISA_ADD_16/Chip 5000406c.fpga_gpio IO 0 | C06 | Unused | D06 | Chip 50004054.fpga_gpio IO 3 | ||||
B14 | ISA_IOR/Chip 5000406c.fpga_gpio IO 4 | A14 | ISA_ADD_17/Chip 5000406c.fpga_gpio IO 1 | C05 | Unused | D05 | Chip 50004054.fpga_gpio IO 2 | ||||
B13 | ISA_IOW/Chip 5000406c.fpga_gpio IO 5 | A13 | ISA_ADD_18/Chip 5000406c.fpga_gpio IO 2 | C04 | Unused | D04 | Chip 50004054.fpga_gpio IO 1 | ||||
B12 | ISA_MEMR/Chip 5000406c.fpga_gpio IO 6 | A12 | ISA_ADD_19/Chip 5000406c.fpga_gpio IO 3 | C03 | Unused | D03 | Chip 50004054.fpga_gpio IO 0 | ||||
B11 | ISA_MEMW/Chip 5000406c.fpga_gpio IO 7 | A11 | ISA_AEN/Chip 50004040.fpga_gpio IO 0 | C02 | Unused | D02 | Chip 5000406c.fpga_gpio IO 9 | ||||
B10 | GND | A10 | Chip 50004040.fpga_gpio IO 5 | C01 | Unused | D01 | Chip 5000406c.fpga_gpio IO 8 | ||||
B09 | 8V_48V [3] | A09 | ISA_DAT_00/Chip 5000405c.fpga_gpio IO 0 | C00 | GND | D00 | GND | ||||
B08 | Chip 50004040.fpga_gpio IO 3 | A08 | ISA_DAT_01/Chip 5000405c.fpga_gpio IO 1 | ||||||||
B07 | Unused | A07 | ISA_DAT_03/Chip 5000405c.fpga_gpio IO 3 | ||||||||
B06 | Chip 50004040.fpga_gpio IO 9 | A06 | ISA_DAT_04/Chip 5000405c.fpga_gpio IO 4 | ||||||||
B05 | N/A | A05 | ISA_DAT_05/Chip 5000405c.fpga_gpio IO 5 | ||||||||
B04 | FPGA IRQ 17/TS mode DAT8 | A04 | ISA_DAT_02/Chip 5000405c.fpga_gpio IO 2 | ||||||||
B03 | +5V [2] | A03 | ISA_DAT_06/Chip 5000405c.fpga_gpio IO 6 | ||||||||
B02 | Chip 20a4000.gpio IO 7 [4] | A02 | ISA_DAT_07/Chip 5000405c.fpga_gpio IO 7 | ||||||||
B01 | GND | A01 | Chip 20a4000.gpio IO 8 |
- ↑ Outputs a continuous 14.318180 MHz clock
- ↑ 2.0 2.1 2.2 Powering the system from PC104 5V prevents the Board's low power sleep mode from functioning.
- ↑ This pin can be used to supply power to the board through the switching regulator.
- ↑ This is automatically pulsed on startup by the ts-pc104 driver as ISA_RESET
Power Connectors
Note: | While the photos below, and shipped PCBs, may show a silkscreen of "8-28V" on the high-voltage input block, all PCB revisions from Rev. A forward support 8-48 VDC input as noted below. |
The TS-7250-V3 provides two power inputs on 2 pin removable terminal blocks. One terminal block supports 5 VDC, and one supports 8-48 VDC. Only one power input may be connected at a time. A typical power supply for this platform should provide 10 W. Refer to the specifications section for more information on power requirements.
Under the removable terminal block the PCB is labelled with the power supply polarity.
USB Ports
The TS-7250-V3 has 2 USB type A host ports. The bottom USB host port can optionally be routed to the #XBEE Header for USB cell modems.
# Route USB to XBEE
gpioset 209c000.gpio 11=1
# Route USB to bottom of J2 (default)
gpioset 209c000.gpio 11=0
Power can also be controlled to save power or reboot peripherals in the field.
gpioset 20a4000.gpio 0=0 # Turn off USB Power
gpioset 20a4000.gpio 0=1 # Turn on USB power
XBEE Header
The CN20 header is a 2mm pitch 2x10 header which supports XBEE form factor modules. These include Nimbelink and Digi cell modems, Zigbee, Digi mesh, and other third party radios.
For Cell radios that use USB this must be enabled. This turns off USB to the bottom port on the dual high type A connector. Only enable if this is compatible with your module:
# Turn on the USB
gpioset 209c000.gpio 11=1
This header can provide 3.3V or 4V as some cell radios require higher voltage. Only enable one power supply to match your radio:
## For 3.3V modules:
#gpioset 50004040.fpga_gpio 4=1
## For 4V modules:
#gpioset 50004040.fpga_gpio 11=1
# Reset to the modem is controlled with:
gpioset
# If your modem supports USB, this must be enabled,
# disabling the lower external USB port and enabling
# the modem's.
gpioset 209c000.gpio 11=1
# Some modems require NIM_PWR_ON to be "pressed" before they
# turn on. WARNING: If the modem is already on, this same
# sequence may turn it off.
#gpioset 209c000.gpio 31=1
#sleep 1
#gpioset 209c000.gpio 31=0
For example, this initialization is known to work for these modules:
- NL_SW_LTE_S7588-T-C
- NL_SW_LTE_SVZM20-B
gpioset 209c000.gpio 11=1 # Route USB to nimbelink
gpioset 6 11=1 # Turn on 4V
gpioset 209c000.gpio 31=1 # assert NIM_PWR_ON
sleep 1
gpioset 209c000.gpio 31=0 # deassert NIM_PWR_ON
For serial modules refer to these related links:
- Technologic Systems: A friendly introduction to XBEE
- Digi's C library for XBEE API mode
- Digi's Python XBEE library
- Digi's C# Library
- Digi's Java Library
- libxbee3 (community XBEE library)
This sample code can be used to verify connectivity to the serial based modules:
wget http://ftp.embeddedTS.com/ftp/ts-arm-sbc/ts-7840-linux/samples/xbeetest.c
gcc xbeetest.c -o xbeetest
gpioset 6 4=1 # Turn on only 3.3V
./xbeetest /dev/ttymxc3
This will print out the module information such as:
XBee3 Zigbee TH RELE: 100A Build: Apr 16 2020 19:00:33 HV: 424E Bootloader: 181 Compiler: 8030001 Stack: 6710 OK
Signals | Pin Layout | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Revisions and Changes
FPGA Changelog
See the current FPGA revision from the u-boot output:
Model: Technologic Systems i.MX6UL TS-7250-V3 Board: TS-7250-V3 REV A FPGA: Rev 24 (47555b21) DRAM: 1 GiB
Or from Linux:
root@tsimx6:~# tshwctl -i MODEL=7250 FPGA_REV=24 FPGA_HASH="47555b21" OPTS=0x0 RAM_MB=1024 PCBREV=A
Revision | Changes |
---|---|
24 | Initial release |
45 |
|
As long as the unit is at least REV A, the unit can be updated on the board itself. The u-boot release must also be updated at the same time since some fpga updates require matching clock changes.
wget -q -O - http://files.embeddedarm.com/ts-arm-sbc/ts-7250-v3-linux/u-boot/update-uboot | bash
wget /u/home/ftp/ts-arm-sbc/ts-7250-v3-linux/fpga/update-fpga-rev45
chmod a+x update-fpga-rev45
./update-fpga-rev45
shutdown -h now
The board must now get a full power cycle for the FPGA to take effect. If the FPGA update fails then this must come back on an RMA to be recovered.
Microcontroller Changelog
Revision | Description |
---|---|
1 |
|
PCB Revisions
Revision | Description |
---|---|
A |
|
Software Images
Debian Changelog
Image | Changes |
---|---|
tsimx6ul-debian-buster-20210513.tar.bz2 | Initial release |
tsimx6ul-debian-buster-20211015.tar.bz2 |
|
tsimx6ul-debian-bullseye-20211014.tar.bz2 |
|
U-Boot Changelog
Unless you are experiencing issues it is not recommended to change u-boot. If the board is written with an invalid u-boot this will require an RMA to recover.
The latest u-boot can be installed on the board with:
wget -q -O - http://files.embeddedarm.com/ts-arm-sbc/ts-7250-v3-linux/u-boot/update-uboot | bash
U-boot Links | Changes |
---|---|
SPL u-boot-dtb.img | Initial release |
SPL u-boot-dtb.img |
|
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.
WARNING: | Setting any of the eMMC's write-once registers (e.g. enabling enhanced area and/or write reliability) will immediately void ALL of our return policies and replacement warranties. This includes but is not limited to: the 45-day full money back evaluation period; any returns outside of the 45-day evaluation period; warranty returns within the 1 year warranty period that would require SBC replacement. Our 1 year limited warranty still applies, however it is at our discretion to decide if the SBC can be repaired, no warranty replacements will be provided if the OTP registers have been written. |