TS-4300

From embeddedTS Manuals

This product is under engineering sampling, and is still under development.

This product supports applying firmware updates to the FPGA and onboard microcontroller (Wizard) so many features will be provided as updates in the field as they are completed.

Feature Status Notes
Ethernet Working Tested iperf on both ports to validate 1Gb/s. Tested nfs booting, no issues seen with Ethernet traffic. Some features like PTP are currently not tested.
eMMC Working Preliminarily Tested. The bootloader is loaded from mmc0 boot partition 0. Tested booting to Linux and reading/writing.
microSD Working Preliminarily Tested
i.MX93 NPU Working Tested with 6.6.52 kernel. See NPU documentation section for script to install software support.
USB Host Ports Working Tested USB drives enumerate and read/write data.
RTC Working Verified this RTC from the wizard holds and retains time.
FPGA PWM controller Working Preliminarily Tested, final PWM count will change once remaining fpga core are implemented
Bluetooth Working Preliminarily Tested, verified bluetoothctl scanning & discoverable
DIO Working Tested CPU IO and FPGA controllers to be working, and support interrupts on rising/falling/both edges.
WIFI Testing Preliminarily working, but feature improvements for next hardware revision.
Baseboard Overlays TODO Each baseboard will load a device tree overlay to the "imx93-ts4300.dtb", using U-Boot's "Expansion Board" concept.

https://docs.u-boot.org/en/v2025.04/usage/cmd/extension.html Our u-boot will be updated to load: imx93-ts4300-<baseboardid>.dtbo.

Examples will be provided for the TS-8551 and some common customizations.

Serial Ports TODO UARTs are working, not yet tested for carrier board transceivers
CAN TODO
SPI TODO
FPGA XBAR TODO This will be provided as an FPGA update, and Linux driver update. This will allow switching around various FPGA interfaces to differenet FPGA pins.
EXT_RESET# TODO This pin will be supported as both a GPIO, and by default will be an external reset that will instantly reset the board when held low. This will be implemented with the FPGA XBAR.
TS-SILO Supercap Backup TODO The TS-SILO will provide backup power after power has been lost, which provides time to properly shutdown and unmount drives after power has been lost. This has been preliminarily tested in the hardware and will be provided as a future Wizard update, and Linux driver update.
i.MX93 low power sleep TODO This is the low power mode in the cpu where we can suspend to ram. This requires further documentation / testing
Wizard low power sleep TODO This feature will allow powering off the i.MX93, FPGA, and most ICs, but allow waking on RTC alarm, push button, and planned on a future PCB revision is movement from the accelerometer/gyro.
i.MX93 Low drive mode TODO This lower performance / operating mode that allows lower runtime power. This requires further changes in the FPGA/linux to implement.
i.MX93 M33 TODO This is the ARM Cortex-M33 microcontroller built into the i.MX93, allowing users to run some code in an RTOS like Zephyr or FreeRTOS. This is expected to be a u-boot configuration and linux change only
Image Replicator TODO This is the USB tool to rewrite the image on production units. This product support will be added in the future.
Open Source FPGA TODO The FPGA is planned to be open sourced, and will be after some additional features are stabilized.
TS-4300
ts-4300.gif
Product Page
Documentation
Schematic
FTP Path
Processor
NXP i.MX9352
1.7 GHz Arm® Cortex®-A55/M33
i.MX93 Product Page
CPU Documentation

Overview

TS-4300 Overview

Getting Started

TS-4300 Getting Started

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, #Ubuntu, #Yocto, or #Buildroot sections for information on application development.

U-Boot Standard Boot

This platform uses u-boot's "Standard Boot" as the method to search available storage media for a bootable operating system.

By default the board will attempt booting to these devices:

boot_target Description
usb U-boot will probe for any available USB Storage media
mmc1 microSD
mmc0 Onboard eMMC flash
pxe Network boot

The order, and the enabled boot targets can be customized by changing the variable:

# Boot to eMMC only:
setenv boot_targets mmc0

# Boot to USB, then eMMC:
setenv boot_targets usb mmc0

# Default targets
setenv boot_targets usb mmc1 mmc0 pxe

While searching each media, u-boot searches for valid boot methods on each device.

bootmeths Description
script Legacy distro-boot scripts. Looks for /boot/boot.scr, /boot/boot.scr.uimg, and executes those
extlinux Looks for extlinux/extlinux.conf. See the syslinux project for more details.
efi Looks for an EFI boot partition, and executes the EFI payload such as grub, or the Linux kernel.
pxe For PXE boot only, checks for valid DHCP describing boot.

The order, and the enabled boot methods can be customized by changing the variable:

# Only boot extlinux:
setenv bootmeths extlinux

# Try script, then EFI
setenv bootmeths script efi

# Default bootmeths
setenv bootmeths script extlinux efi pxe

On our factory preprogrammed images the typical boot skips USB, mmc1, and boots to a script on eMMC.

U-Boot Baseboard/Extension Support

In the selected boot method u-boot loads a device tree which describes the hardware the kernel runs on. The imx93-ts4300.dtb is always loaded to describe the TS-4300 hardware. Every baseboard is supported using a device tree overlay.

This extends the TS-4300 device tree with the features needed to support the carrier board. In u-boot, this is loaded using u-boot's extension support.

All of our off the shelf baseboards contain a hard-wired 8-input multiplexer to indicate the baseboard model. This is not required to implement in custom baseboards, but it can be useful to identify the board model in software. The u-boot extension will scan the baseboard id, eg, the TS-8551 which is hard wired as 0x16.

TS-8551 baseboard ID resulting in ID 0x16
  • S0 is connected to CN2_006
  • S1 is connected to CN2_008
  • S2 is connected to CN1_098
  • BD_ID_DATA is connected to CN1_083

The 6 least significant input pins (Y0 - Y5) are used to define the baseboard model. The upper two inputs (Y6 and Y7) define board revision.

The baseboard id is specified in hex, so the TS-8551 searches for:

imx93-ts4300-16.dtbo

If it exists, it is applied automatically with "extension apply all" in our standard boot scripts. Custom carrier boards should use the ID "0x2a", which will never be used by our off the shelf boards.

U-Boot Environment

TS-4300 u-boot environment

Booting From NFS

TS-4300 U-Boot NFS boot

U-Boot Development

TS-4300 U-boot development

Debian

Debian 12 - Bookworm

Debian 12 - Getting Started

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

Image Estimated Size Description
tsimx9-debian-12-bookworm-x11-latest.tar.xz 1233 MiB
  • Includes 6.6 kernel with ts9370_defconfig that includes broad driver support
  • Base Debian with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
  • Includes X11 that launches matchbox and xterm on startup
  • Includes touchscreen support
tsimx9-debian-12-bookworm-headless-latest.tar.xz 961 MiB
  • Includes 6.6 kernel with ts9370_defconfig that includes broad driver support
  • Base Debian with common utils
  • Common embedded tools (i2c, can, gpio, iio, serial tools, etc)
  • Includes hardware support
  • Networking tools (ethernet, wifi, bluetooth)
  • Includes Development tools
tsimx9-debian-12-bookworm-minimal-latest.tar.xz 379 MiB
  • Includes 6.6 kernel with ts9370_defconfig that includes broad driver support
  • Includes base Debian rootfs adding only what is required for Ethernet support.

The default login is root with no password.

To write this to an SD card, first partition the SD card to have one large ext4 partition. Once it is formatted, extract this tar with:

# Assuming your SD card is /dev/sdc with one partition
mkfs.ext4 /dev/sdc1
mkdir /mnt/sd/
sudo mount /dev/sdc1 /mnt/sd/
sudo tar --numeric-owner -xJf tsimx9-debian-12-bookworm-x11-latest.tar.xz -C /mnt/sd
sudo umount /mnt/sd
sync

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

mkfs.ext3 /dev/mmcblk2p1
mkdir /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
wget -qO- https://files.embeddedts.com/ts-arm-sbc/ts-9370-linux/distributions/debian/ tsimx9-debian-12-bookworm-x11-latest.tar.xz | tar --numeric-owner -xJ -C /mnt/emmc/
umount /mnt/emmc
sync

Debian 12 - Networking

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

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

Most commonly:

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

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

auto end0
allow-hotplug end0
iface end0 inet dhcp

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

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

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

service networking restart

Debian 12 - WIFI Client

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

Install wpa_supplicant:

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

Run:

wpa_passphrase youressid yourpassword

This command will output information similar to:

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

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

/etc/network/interfaces.d/wlan0

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

To have this take effect immediately:

service networking restart

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

Debian 12 - WIFI Access Point

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

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


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

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

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


To start the access point launch hostapd:

hostapd /etc/hostapd/hostapd.conf &

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

Debian 12 - Installing New Software

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

apt-get update

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

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

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

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

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

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

Debian 12 - Setting up SSH

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

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

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

Debian 12 - Starting Automatically

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 12 - Cross Compiling

Debian provides cross compilers in their matching distribution. For example, if you are running Debian 12 on your workstation or VM:

sudo dpkg --add-architecture arm64
sudo apt-get update

# Cross compiler
sudo apt-get install gcc-aarch64-linux-gnu

# Install any needed libraries/headers from Debian 12 for arm64:
sudo apt-get install libc6-dev:arm64 libgpiod-dev:arm64

A hello world can be built with:

aarch64-linux-gnu-gcc hello.c -o hello

Tools like docker/cqfd can make this simpler to run Debian 12 in a container just for the build. See our cqfd hello world project that demonstrates a simpler way to run these from most Linux systems.

Debian 12 - Compile the aarch64 Kernel

For building kernels targeting the Debian images we recommend using cqfd. This allows building a compatible kernel using identical tools from any build host.

To build a kernel for the embeddedTS i.MX93 based platforms:

# Install cqfd-linux-lts builds scripts
git clone https://github.com/embeddedTS/cqfd-linux-lts
cd cqfd-linux-lts

# Clone the Linux kernel
git clone https://github.com/embeddedTS/prototype-linux-imx93.git -b lf-6.6.y-ts linux

# Build the kernel:
./build_tsimx93_tar.sh

This will set up the container including Debian's cross compilers, and any dependencies needed to build the kernel. This runs once on initial setup, and the only when the Dockerfile is modified. Next, it builds the defconfig, compiles the kernel, and assembles a tar of the build objects for that image. After it completes, it will print out the path to the tar file.


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 linux-*.tar.gz -C /mnt
Note: The tar h argument to tar is necessary on recent distributions that merge /usr/. Not using it will render the system unbootable.

Ubuntu

TS-4300 Ubuntu Sections

Buildroot

TS-4300 Buildroot Sections

Backup / Restore

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

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

Image Replicator

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

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


Image Capture Process

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

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

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

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


Image Write Process

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

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

Creating a USB Image Replicator Disk

Creating USB image replicator i.MX93

Running the Image Replicator Tool

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


Image Replicator Runtime Options

Some of the runtime operations of the Image Replicator can be specified. These are handled by creating empty files in the root folder of the bootable USB drive. When booted, these files are analyzed and actions taken based on them.

Option Description

IR_NO_CAPTURE_SD

IR_NO_CAPTURE_SD1

IR_NO_CAPTURE_EMMC

IR_NO_CAPTURE_SATA

When capturing, skip media matching this name. See the respective platform manual for information on which names correspond to which physical media. Note that the names are generic and match what the media is captured as, regardless of actual device node. The names are uniform between capture and write for a given system.
IR_NO_COMPRESS When capturing, do not compress the data. On slower systems, slower disks, or systems with a large amount of data to capture, the final compression can take a significant amount of time. This option will allow a capture, but will not attempt to compress it.
IR_SHELL_ONLY When booting, skip doing any of the image replication process (Capture or Write) and instead drop to a login prompt. Useful for debugging. Note that, to prevent any confusion the system will indicate a non-critical failure when skipping any of the Image Replication process.


Image Replicator LED Status

The green and red LEDs of the platform are used to indicate status.

Any LED patterns not matching the table below indicate different operational states of the platform itself, e.g. executing the bootloader, the kernel is running but Image Replicator has not yet started, etc.

Green Red State Description
Short Strobe Solid Running The Image Replicator process is running.
0.5 Hz Blink Off Succeeded All operations being performed by the Image Replicator have completed successfully.
Off 0.5 Hz Blink Non-critical Failure One or more operations being performed by the Image Replicator have failed to complete. View logs in /tmp/logs/ as well as the failure reason in /tmp/failed
Off 4 Hz Blink Critical Failure An operation has failed in a way that could leave the device inoperable if power were to be removed. View logs in /tmp/logs as well as the failure reason in /tmp/failed.


Image Capture

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

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

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

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

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

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

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

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


Image Write

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

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

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

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

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

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

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

Target media Accepted filenames Description
SD Card

/sdimage.tar.xz

/sdimage.tar.bz2

/sdimage.tar.gz

/sdimage.tar

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

/sdimage.dd.xz

/sdimage.dd.bz2

/sdimage.dd.gz

/sdimage.dd

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

/emmcimage.tar.xz

/emmcimage.tar.bz2

/emmcimage.tar.gz

/emmcimage.tar

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

/emmcimage.dd.xz

/emmcimage.dd.bz2

/emmcimage.dd.gz

/emmcimage.dd

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

/u-boot-dtb.bin

/SPL

U-Boot binary blob. This will be written to the bootloader area of eMMC. Note that both files are required for U-Boot, if either file is missing then the Image Replicator tool will not write either of them. If the file /SPL.md5 is present on the USB drive, this will be used to verify the data written to disk.

Building the Image Replicator from Source

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

microSD Card

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

TS-4300 MicroSD Backup/restore

Booted from SD

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

TS-4300 eMMC Backup/restore

Features

Battery-backed RTC

TS-4300 RTC

Bluetooth

TS-4300 Bluetooth

CAN

The TS-4300 provides two CAN controllers, one on CN2_97/CN2_99, and the second on CN1_69/CN1_71. These TTL signals require a transceiver such as the NXP TJA1462A.

The i.MX93 includes 2 CAN controllers. These support CAN 2.0B, and CAN FD. Both of these include drivers which support the SocketCAN interface. Before proceeding with the examples, see the Kernel's CAN documentation here.

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

## Dump data & errors:
candump can0 &

## Send the packet with:
#can_id = 0x7df
#data 0 = 0x3
#data 1 = 0x1
#data 2 = 0x0c
cansend can0 7DF#03010C

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

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

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

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

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

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

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

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

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

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

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

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

ip link set can0 type can restart-ms 100

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

CPU

The CPU is a i.MX9352 CPU which is a dual core Arm® Cortex®-A55 at 1.7GHz. This is a 64-bit Arm® v8.2-A architecture core.

  • 32 KB L1 Instruction Cache
  • 32 KB L1 Data Cache
  • 64 KB per-core L2 cache
  • Media Processing Engine (MPE) with Arm® NeonTM technology supporting the

Advanced Single Instruction Multiple Data architecture

  • Floating Point Unit (FPU) with support of the Arm® VFPv4-D16 architecture

eMMC Interface

The onboard eMMC supports the eMMC5.1 specification, and SDR104 speeds with an 8-bit bus. The eMMC performance provides high speed access, typically with larger eMMC providing faster speeds:

  • 32 GB eMMC
    • 118 MB/s Write
    • 311 MB/s Read
  • 16 GB eMMC
    • 107 MB/s Write
    • 175 MB/s Read

The onboard eMMC supports fast sequential access of approximately 250 MiB/s read or 110MiB/s write.

The eMMC provides 4 devices:

Device Description
/dev/mmcblk0 User partition that includes GPT partitions and bootable OS
/dev/mmcblk0boot0 Bootloader partition that includes ATF/OP-TEE/DDR firmware/U-Boot, and u-boot environment
/dev/mmcblk0boot1 Unused bootloader partition
/dev/mmcblk0rpmb Replay protected memory block

Besides including a bootable image, /dev/mmcblk0 does not include any preallocated data at various offset.

The mmcblk0boot0 partition does include data at some specific offsets. This device is not guaranteed to be the same size on all equivalent parts, but will provide at least 4MB.

mmcblk0boot0
Offset Description
0x0-0x1FFFFF Singleboot image including arm-trusted-firmware, LPDDR4 firmware, OP-TEE, imx93 Sentinal firmware, and U-Boot.
0x200000-0x203FFF U-boot environment
0x204000-0x207FFF U-boot environment (Redundant)
0x240000-0x2BFFFF Pending FPGA Update Image

Ethernet Ports

TS-4300 Ethernet Ports

FPGA

FPGA Bus

The TS-4300's FPGA is connected to the CPU over the FlexSPI bus. This provides 32-bit access to the FPGA, mapped at 0x2800_0000.

FPGA Memory Map

Offset Description
0x0000 Model/Rev Info
0x0020 IRQ core
0x0040 FPGA GPIO block #0
0x0080 FPGA GPIO block #1
0x00C0 FPGA GPIO block #2
0x0100 FPGA GPIO block #3
0x0400 FPGA PWM 0
0x2000 FPGA XBAR


FPGA Info Core

The FPGA model/info core is used for testing / identification of the board. In general user should not need to implement access to this core without a custom FPGA, but the register interface is as follows:

# Read the MODEL register
memtool md 0x28000000+4
Address Name Bits Field RO/RW Description
0x0 MODEL [31:16] Reserved RO Reserved bits
[15:0] Model Number RO Model number of the core (e.g., 0x9370, 0x9390, 0x4300)
0x4 VERSION [31] Git Dirty Bit RO Indicates if the working tree is dirty
[30:24] Major Tag Version RO Major version number
[23:16] Minor Tag Version RO Minor version number
[15:8] Patch Tag Version RO Patch version number
[7:0] Commits Since Tag RO Number of commits since the tag
0x8 GIT_INFO [31:0] Git Short Hash RO 31-bit Git short hash
0xC BUILD_TIME [31:0] Build Time RO Build time encoded as epoch ≫ 1
0x10 SCRATCH0 [31:0] Scratch Reg 0 RW General-purpose scratch register 0
0x14 SCRATCH1 [31:0] Scratch Reg 1 RW General-purpose scratch register 1
0x18 UNIQUE_IDENTIFIER [31:0] Unique Identifier RW Custom identifier for user-built FPGA images (0 for stock)

FPGA GPIO Core

The GPIO core supports:

  • set/clr regs for data and oe
  • IRQ level/edge, edge select between rising/falling/both edges
  • 32 IO per bank.

For Linux usage of the GPIO controller, see the GPIO section which shows how to use the GPIO/IRQs from userspace. While we recommend using the existing driver stack, the register documentation the 32-bit registers controlling each block are defined as follows:

Address Name Read/Write Description
0x00 oe Read Output enable state of GPIO pins.
Write Set bits to enable output for corresponding GPIOs.
0x04 oe_clr Read N/A
Write Clear bits to disable output for corresponding GPIOs.
0x08 output_data Read Current state of GPIO output data.
output_data_set Write Set bits to drive high the corresponding GPIO outputs.
0x0C input_data Read Current state of GPIO input data.
output_data_clr Write Set bits to drive low the corresponding GPIO outputs.
0x10 irq_pending Read Shows active and unmasked interrupts. 0 = Inactive/masked, 1 = Active and unmasked.
Write Acknowledge interrupt. 0 = No effect, 1 = Ack interrupt.
0x14 irq_mask Read Shows IRQ Mask. 0 = Unmasked, 1 = Masked.
irq_mask_set Write Masks IRQ for corresponding bits. 0 = No effect, 1 = Mask interrupt.
0x18 irq_mask_clear Read N/A
Write Unmasks IRQ for corresponding bits. 0 = No effect, 1 = Unmask interrupt.
0x1C irq_mask_and_ack Read N/A
Write Acknowledge and mask the corresponding IRQ. 0 = No effect, 1 = Acknowledge and mask.
0x20 irq_edge_level Read/Write 0 = Level-sensitive IRQ, 1 = Edge-triggered IRQ.
0x24 irq_edge_sel Read/Write 0 = Use polarity to select edge, 1 = Either edge
0x28 irq_polarity Read/Write 0 = Active-low/falling edge, 1 = Active-high/rising edge.

FPGA PWM

This system includes PWM that supports 10-bit duty/period, a 66.666666mhz 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) Duty Cycle units (ns) Max Period (ns) Max Period (Hz)
0 66666666 15 15345 65167
1 33333333 30 30690 32583
2 16666666 60 61380 16291
3 8333333 120 122760 8145
4 4166666 240 245520 4072
5 2083333 480 491040 2036
6 1041666 960 982080 1018
7 520833 1920 1964161 509
8 260416 3840 3928330 254
9 130208 7860 7856660 127
10 65104 15360 15713320 63
11 32552 30720 31426640 31

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 0x28000400, each PWM are 0x20 registers apart.

Address Bits Description
0x00 (CONFIG) 31:2 Reserved
1 PWM Inversion (0 = Idle high, duty cycle low), (1 = Idle low, duty cycle high)
0 PWM Enable (1 = Enable PWM output, 0 = Drive default state)
0x04 (PERIOD) 31:10 Reserved
9:0 PWM Period (0–1023 steps)
0x08 (DUTY) 31:10 Reserved
9:0 PWM Duty Cycle (0–1023 steps)
0x0C (SHIFT) 31:12 Reserved
11:0 Shift (Clock frequency = 66666666 / (1 >> shift))

FPGA XBAR

The FPGA XBAR controller allows rerouting some fpga pins between other pins. For example, the FPGA has connections to many of the CPU UARTs, SPI, and has several internal cores. This lets the users control which controllers are connected to certain pins. For example, the daughtercard header is all GPIO by default. The xbar allows routing the CPU's UART away from a RS-485 transceiver, and instead to this daughter card header. This does not make the daughter card header RS-485 levels, but just changes which controller drives these pins.

Under Linux the pin mapping can be controlled 2 ways, either through a device tree modification, or through debugfs in userspace.

For Userspace:


cd "/sys/kernel/debug/pinctrl/28002000.pinctrl-tsxbar-pinctrl/"

# echo a list of every output pin
cat pingroups

# echo a list of every function available:
cat pinmux-functions

# To see functions on a given pin:
cat pinmux-functions | grep MIKRO_TXD
# This returns:
##function 3: GPIO0_IO14, groups = [ MIKRO_TXD ]
##function 4: UART8_TXD, groups = [ MIKRO_TXD ]

# By default, MIKRO_TXD is a uart.  To select the GPIO:
echo "MIKRO_TXD GPIO0_IO14" > pinmux-select
# To select the UART again:
echo "MIKRO_TXD UART8_TXD" > pinmux-select


For the device tree:


In the device tree, find the compatible = "technologic,ts9390-xbar"; node, and add pin mappings underneath that. See pinfunc-ts9390.h in the same path as the device tree for the available options. For example, this is how to define the mikrobus UART pins as GPIO or UART:

		fpga_xbar: pinctrl@28002000 {
			compatible = "technologic,ts4300-xbar";
			reg = <0x2000 0x200>;

			pinctrl_uart_mikrobus: mikrobusuartgrp {
				xbar,pins = <
					TS9390_PAD_MIKRO_TXD__UART8_TXD
					TS9390_PAD_UART8_RXD__MIKRO_RXD
				>;
			};

			pinctrl_gpio_mikrobus: mikrobusgpiogrp {
				xbar,pins = <
					TS9390_PAD_MIKRO_TXD__GPIO0_IO14
					TS9390_PAD_MIKRO_RXD__GPIO0_IO15
				>;
			};
		};

The mikrobus UART is the default, but this is how it would be explicitly mapped in the device tree:

&lpuart8 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart8 &pinctrl_uart_mikrobus>;
	status = "okay";
};

The XBAR controller supports these muxing options:

Alt 0 Alt 1 Alt 2 Alt 3 Alt 4 Alt 5 Alt 6 Alt 7
Pin #00 (GPIO1_IO0), Default DIO_01
GPIO1_IO0 N/A N/A N/A N/A N/A N/A N/A
Pin #01 (GPIO1_IO1), Default DIO_02
GPIO1_IO1 N/A N/A N/A N/A N/A N/A N/A
Pin #02 (GPIO1_IO2), Default DIO_03
GPIO1_IO2 N/A N/A N/A N/A N/A N/A N/A
Pin #03 (GPIO1_IO3), Default DIO_04
GPIO1_IO3 N/A N/A N/A N/A N/A N/A N/A
Pin #04 (GPIO1_IO4), Default DIO_05
GPIO1_IO4 N/A N/A N/A N/A N/A N/A N/A
Pin #05 (GPIO1_IO5), Default DIO_06
GPIO1_IO5 N/A N/A N/A N/A N/A N/A N/A
Pin #06 (GPIO1_IO6), Default DIO_07
GPIO1_IO6 N/A N/A N/A N/A N/A N/A N/A
Pin #07 (GPIO1_IO7), Default DIO_08
GPIO1_IO7 N/A N/A N/A N/A N/A N/A N/A
Pin #08 (GPIO1_IO8), Default DIO_09
GPIO1_IO8 N/A N/A N/A N/A N/A N/A N/A
Pin #09 (GPIO1_IO9), Default DIO_10
GPIO1_IO9 N/A N/A N/A N/A N/A N/A N/A
Pin #10 (GPIO1_IO10), Default DIO_11
GPIO1_IO10 N/A N/A N/A N/A N/A N/A N/A
Pin #11 (GPIO1_IO11), Default DIO_12
GPIO1_IO11 N/A N/A N/A N/A N/A N/A N/A
Pin #12 (GPIO1_IO12), Default DIO_13
GPIO1_IO12 N/A N/A N/A N/A N/A N/A N/A
Pin #13 (GPIO1_IO13), Default DIO_14
GPIO1_IO13 N/A N/A N/A N/A N/A N/A N/A
Pin #14 (GPIO1_IO14), Default DIO_15
GPIO1_IO14 N/A N/A N/A N/A N/A N/A N/A
Pin #15 (GPIO1_IO15), Default DIO_16
GPIO1_IO15 N/A N/A N/A N/A N/A N/A N/A
Pin #16 (GPIO1_IO16), Default DIO_17
GPIO1_IO16 N/A N/A N/A N/A N/A N/A N/A
Pin #17 (GPIO1_IO17), Default DIO_18
GPIO1_IO17 N/A N/A N/A N/A N/A N/A N/A
Pin #18 (GPIO1_IO18), Default DIO_19
GPIO1_IO18 N/A N/A N/A N/A N/A N/A N/A
Pin #19 (GPIO1_IO19), Default DIO_20
GPIO1_IO19 N/A N/A N/A N/A N/A N/A N/A
Pin #20 (GPIO1_IO20), Default DIO_21
GPIO1_IO20 N/A N/A N/A N/A N/A N/A N/A
Pin #21 (GPIO1_IO21), Default DIO_22
GPIO1_IO21 N/A N/A N/A N/A N/A N/A N/A
Pin #22 (GPIO1_IO22), Default DIO_23
GPIO1_IO22 N/A N/A N/A N/A N/A N/A N/A
Pin #23 (GPIO1_IO23), Default DIO_24
GPIO1_IO23 N/A N/A N/A N/A N/A N/A N/A
Pin #24 (GPIO1_IO24), Default DIO_25
GPIO1_IO24 N/A N/A N/A N/A N/A N/A N/A
Pin #25 (GPIO1_IO25), Default DIO_26
GPIO1_IO25 N/A N/A N/A N/A N/A N/A N/A
Pin #26 (GPIO1_IO26), Default DIO_27
GPIO1_IO26 N/A N/A N/A N/A N/A N/A N/A
Pin #27 (GPIO1_IO27), Default DIO_28
GPIO1_IO27 N/A N/A N/A N/A N/A N/A N/A
Pin #28 (GPIO1_IO28), Default DIO_29
GPIO1_IO28 N/A N/A N/A N/A N/A N/A N/A
Pin #29 (GPIO1_IO29), Default DIO_30
GPIO1_IO29 N/A N/A N/A N/A N/A N/A N/A
Pin #30 (GPIO1_IO30), Default DIO_31
GPIO1_IO30 N/A N/A N/A N/A N/A N/A N/A
Pin #31 (GPIO1_IO31), Default DIO_32
GPIO1_IO31 N/A N/A N/A N/A N/A N/A N/A
Pin #32 (GPIO2_IO0), Default DIO_33
GPIO2_IO0 N/A N/A N/A N/A N/A N/A N/A
Pin #33 (GPIO2_IO1), Default DIO_34
GPIO2_IO1 N/A N/A N/A N/A N/A N/A N/A
Pin #34 (GPIO2_IO2), Default DIO_35
GPIO2_IO2 N/A N/A N/A N/A N/A N/A N/A
Pin #35 (GPIO2_IO3), Default DIO_36
GPIO2_IO3 N/A N/A N/A N/A N/A N/A N/A
Pin #36 (GPIO2_IO4), Default DIO_37
GPIO2_IO4 N/A N/A N/A N/A N/A N/A N/A
Pin #37 (GPIO2_IO5), Default DIO_38
GPIO2_IO5 N/A N/A N/A N/A N/A N/A N/A
Pin #38 (GPIO2_IO6), Default DIO_39
GPIO2_IO6 N/A N/A N/A N/A N/A N/A N/A
Pin #39 (GPIO2_IO7), Default DIO_40
GPIO2_IO7 N/A N/A N/A N/A N/A N/A N/A
Pin #40 (GPIO2_IO8), Default DIO_41
GPIO2_IO8 N/A N/A N/A N/A N/A N/A N/A
Pin #41 (GPIO2_IO9), Default DIO_42
GPIO2_IO9 N/A N/A N/A N/A N/A N/A N/A
Pin #42 (GPIO2_IO10), Default DIO_43
GPIO2_IO10 N/A N/A N/A N/A N/A N/A N/A
Pin #43 (GPIO2_IO11), Default DIO_44
GPIO2_IO11 N/A N/A N/A N/A N/A N/A N/A
Pin #44 (GPIO2_IO12), Default DIO_45
GPIO2_IO12 N/A N/A N/A N/A N/A N/A N/A
Pin #45 (GPIO2_IO13), Default DIO_46
GPIO2_IO13 N/A N/A N/A N/A N/A N/A N/A
Pin #46 (GPIO2_IO14), Default DIO_47
GPIO2_IO14 N/A N/A N/A N/A N/A N/A N/A
Pin #47 (GPIO2_IO15), Default DIO_48
GPIO2_IO15 N/A N/A N/A N/A N/A N/A N/A
Pin #48 (GPIO2_IO16), Default DIO_49
GPIO2_IO16 N/A N/A N/A N/A N/A N/A N/A
Pin #49 (GPIO2_IO17), Default DIO_50
GPIO2_IO17 N/A N/A N/A N/A N/A N/A N/A
Pin #50 (GPIO2_IO18), Default DIO_51
GPIO2_IO18 N/A N/A N/A N/A N/A N/A N/A
Pin #51 (GPIO2_IO19), Default DIO_52
GPIO2_IO19 N/A N/A N/A N/A N/A N/A N/A
Pin #52 (GPIO2_IO20), Default DIO_53
GPIO2_IO20 N/A N/A N/A N/A N/A N/A N/A
Pin #53 (GPIO2_IO21), Default DIO_54
GPIO2_IO21 N/A N/A N/A N/A N/A N/A N/A
Pin #54 (GPIO2_IO22), Default DIO_55
GPIO2_IO22 N/A N/A N/A N/A N/A N/A N/A
Pin #55 (GPIO2_IO23), Default DIO_56
GPIO2_IO23 N/A N/A N/A N/A N/A N/A N/A
Pin #56 (GPIO2_IO24), Default DIO_57
GPIO2_IO24 N/A N/A N/A N/A N/A N/A N/A
Pin #57 (GPIO2_IO25), Default DIO_58
GPIO2_IO25 N/A N/A N/A N/A N/A N/A N/A
Pin #58 (GPIO2_IO26), Default DIO_59
GPIO2_IO26 N/A N/A N/A N/A N/A N/A N/A
Pin #59 (GPIO2_IO27), Default DIO_60
GPIO2_IO27 N/A N/A N/A N/A N/A N/A N/A
Pin #60 (GPIO2_IO28), Default DIO_61
GPIO2_IO28 N/A N/A N/A N/A N/A N/A N/A
Pin #61 (GPIO2_IO29), Default DIO_62
GPIO2_IO29 N/A N/A N/A N/A N/A N/A N/A
Pin #62 (GPIO2_IO30), Default DIO_63
GPIO2_IO30 N/A N/A N/A N/A N/A N/A N/A
Pin #63 (GPIO2_IO31), Default DIO_64
GPIO2_IO31 N/A N/A N/A N/A N/A N/A N/A
Pin #64 (GPIO3_IO0), Default DIO_65
GPIO3_IO0 N/A N/A N/A N/A N/A N/A N/A
Pin #65 (GPIO3_IO1), Default DIO_66
GPIO3_IO1 N/A N/A N/A N/A N/A N/A N/A
Pin #66 (GPIO3_IO2), Default DIO_67
GPIO3_IO2 N/A N/A N/A N/A N/A N/A N/A
Pin #67 (GPIO3_IO3), Default DIO_68
GPIO3_IO3 N/A N/A N/A N/A N/A N/A N/A
Pin #68 (GPIO3_IO4), Default DIO_69
GPIO3_IO4 N/A N/A N/A N/A N/A N/A N/A
Pin #69 (GPIO3_IO5), Default DIO_70
GPIO3_IO5 N/A N/A N/A N/A N/A N/A N/A
Pin #70 (GPIO3_IO6), Default DIO_71
GPIO3_IO6 N/A N/A N/A N/A N/A N/A N/A
Pin #71 (GPIO3_IO7), Default DIO_72
GPIO3_IO7 N/A N/A N/A N/A N/A N/A N/A
Pin #72 (GPIO3_IO8), Default DIO_73
GPIO3_IO8 N/A N/A N/A N/A N/A N/A N/A
Pin #73 (GPIO3_IO9), Default DIO_74
GPIO3_IO9 N/A N/A N/A N/A N/A N/A N/A
Pin #74 (GPIO3_IO10), Default DIO_75
GPIO3_IO10 N/A N/A N/A N/A N/A N/A N/A
Pin #75 (GPIO3_IO11), Default DIO_76
GPIO3_IO11 N/A N/A N/A N/A N/A N/A N/A
Pin #76 (GPIO3_IO12), Default DIO_77
GPIO3_IO12 N/A N/A N/A N/A N/A N/A N/A
Pin #77 (GPIO3_IO13), Default DIO_78
GPIO3_IO13 N/A N/A N/A N/A N/A N/A N/A
Pin #78 (GPIO3_IO14), Default DIO_79
GPIO3_IO14 N/A N/A N/A N/A N/A N/A N/A
Pin #79 (GPIO3_IO15), Default DIO_80
GPIO3_IO15 N/A N/A N/A N/A N/A N/A N/A
Pin #80 (GPIO3_IO16), Default DIO_81
GPIO3_IO16 N/A N/A N/A N/A N/A N/A N/A
Pin #81 (GPIO3_IO17), Default DIO_82
GPIO3_IO17 N/A N/A N/A N/A N/A N/A N/A
Pin #82 (GPIO3_IO18), Default DIO_83
GPIO3_IO18 N/A N/A N/A N/A N/A N/A N/A
Pin #83 (GPIO3_IO19), Default DIO_84
GPIO3_IO19 N/A N/A N/A N/A N/A N/A N/A
Pin #84 (GPIO3_IO20), Default DIO_85
GPIO3_IO20 N/A N/A N/A N/A N/A N/A N/A
Pin #85 (GPIO3_IO21), Default DIO_86
GPIO3_IO21 N/A N/A N/A N/A N/A N/A N/A
Pin #86 (GPIO3_IO22), Default DIO_87
GPIO3_IO22 N/A N/A N/A N/A N/A N/A N/A
Pin #87 (GPIO3_IO23), Default DIO_88
GPIO3_IO23 N/A N/A N/A N/A N/A N/A N/A
Pin #88 (GPIO3_IO24), Default DIO_89
GPIO3_IO24 N/A N/A N/A N/A N/A N/A N/A
Pin #89 (GPIO3_IO25), Default DIO_90
GPIO3_IO25 N/A N/A N/A N/A N/A N/A N/A
Pin #90 (HIGHZ), Default SPI_4_CS_1V8#
N/A N/A N/A N/A N/A N/A N/A N/A
Pin #91 (SPI_4_CS_1V8#), Default SPI4_CN2_CS#
GPIO0_IO04 SPI_4_CS_1V8# N/A N/A N/A N/A N/A N/A
Pin #92 (GPIO0_IO05), Default EN_USB_HOST_5V
GPIO0_IO05 N/A N/A N/A N/A N/A N/A N/A
Pin #93 (GPIO0_IO06), Default OFF_BD_RESET
GPIO0_IO06 N/A N/A N/A N/A N/A N/A N/A
Pin #94 (DIO_08), Default PMIC_RESET#
N/A DIO_08 PMIC_RESET_DISABLED N/A N/A N/A N/A N/A

While the existing drivers should be used for any iomux interaction, this is the register documentation for interacting directly with the core.

Address Bits Read/Write Description
0x0 31:24 RW PIN[n+3] FUNC_SEL
23:16 RW PIN[n+2] FUNC_SEL
15:8 RW PIN[n+1] FUNC_SEL
7:0 RW PIN[n+0] FUNC_SEL

This repeats for 0x0+ceil(N_PINS/4).

For each FUNC_SEL register:

Bits Description
3 HIGH_Z_EN, 1 = enable high-z, regardless of lower bits, 0 drive peripheral values
2:0 Value of 0-7 selects a function that drives oe+data

FPGA IRQ

The FPGA has a single IRQ from the CPU, which it expands to its own IRQ capable cores. It is recommended to interact with GPIO underneath the FPGA which are IRQ capable rather than the IRQ core itself.

This core takes the 1 IRQ, and expands it to up to 32 IRQs. On the current design this is connected to:

IRQ Description
0 FPGA GPIO 0
1 FPGA GPIO 1
2 FPGA GPIO 2

Most physical IRQ capable pins are connected underneath the GPIO cores which provide flexibility for IRQ type, polarity, acks, etc to not miss edges.

We recommend to use the existing Linux BSP which implements drivers for this already ("technologic,fpga-irqc"), but this core uses this register map.

Address Name Access Description
0x00 irq_status R Shows active and unmasked interrupts.
0 = Interrupt inactive or masked.
1 = Interrupt active and unmasked.
W *Not applicable*
0x04 irq_mask_set R Returns mask register; 1 = masked, 0 = unmasked.
W **Write 1** to a bit position to enable that interrupt (sets the corresponding bit).
0x08 irq_mask_clr R N/A
W **Write 1** to a bit position to unmask that interrupt.

FPGA Updates

For most Linux users, the FPGA can be updated with:

curl -sSL http://files.embeddedts.com/ts-socket-macrocontrollers/ts-4300-linux/fpga/update-fpga.sh | sh

Then reboot.

This FPGA supports multiple application loads. On startup, it always starts the first image which is a bootloader that is capable of rewriting the FPGA's flash. If there is no update, it sets a register that switches the FPGA to the second image which contains the common functionality like GPIO, IRQs, etc.

U-boot checks checks for a valid 'fit' image in the eMMC boot 1 partition (mmcblk0boot1) at offset 0x280000. If it finds this valid update, then before switching out of the FPGA bootloader it rewrites the second application load. This take approximately 40 seconds. After writing, it then erases the region of mmcblk0boot1 containing the update, and then sets the register in the bootloader that updates the FPGA.

This update process is designed so the typical case of updating the application load is safe even in the case of sudden power loss. The FPGA bootloader is in a separate erase block of the FPGA's internal flash, so if we are interrupted in the middle of erasing/writing flash it only affects the application load. On the next start up, since the update has not been completed and still exists on mmcblk0boot1, it will restart the update and try again until it succeeds.

GPIO

The i.MX93 CPU and FPGA GPIOs 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 read the push switch:

gpioget $(gpiofind PUSH_SW#)

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 $(gpiofind EN_RELAY_1)=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 to GPIOs that generate interrupts.

In the following table, gpiochips 0 through 2 are on the FPGA. gpiochip 3 is on the CPU, but none of the pins are available as GPIOs. Because this numbering is subject to change, it is advisable to use the gpiofind command to look it up by its label, as shown in the usage examples above and elsewhere in this manual.

Schematic Net Name Direction Bank Line Location
EN_GREEN_LED# Out 4 0 Green LED
EN_RED_LED# Out 4 1 Red LED
SPI4_CN2_CS# Bidir 4 4 CN2_065
EN_USB_HOST_5V Bidir 4 5 CN1_004
OFF_BD_RESET# Bidir 4 6 CN1_009
SEL_LVDS Out 4 7 Onboard
SPI_4_CS_1V8# Bidir 4 8 Onboard
DIO_01 Bidir 5 0 CN2_060
DIO_02 Bidir 5 1 CN2_062
DIO_03 Bidir 5 2 CN2_064
DIO_04 Bidir 5 3 CN2_066
DIO_05 Bidir 5 4 CN2_068
DIO_06 Bidir 5 5 CN2_070
DIO_07 Bidir 5 6 CN2_072
DIO_08 Bidir 5 7 CN1_002
DIO_09 Bidir 5 8 CN1_006
DIO_10 Bidir 5 9 CN1_008
DIO_11 Bidir 5 10 CN1_010
DIO_12 Bidir 5 11 CN1_012
DIO_13 Bidir 5 12 CN1_014
DIO_14 Bidir 5 13 CN1_018
DIO_15 Bidir 5 14 CN1_020
DIO_16 Bidir 5 15 CN1_022
DIO_17 Bidir 5 16 CN1_024
DIO_18 Bidir 5 17 CN1_026
DIO_19 Bidir 5 18 CN1_028
DIO_20 Bidir 5 19 CN1_030
DIO_21 Bidir 5 20 CN1_032
DIO_22 Bidir 5 21 CN1_034
DIO_23 Bidir 5 22 CN1_038
DIO_24 Bidir 5 23 CN1_040
DIO_25 Bidir 5 24 CN1_042
DIO_26 Bidir 5 25 CN1_044
DIO_27 Bidir 5 26 CN1_046
DIO_28 Bidir 5 27 CN1_048
DIO_29 Bidir 5 28 CN1_099
DIO_30 Bidir 5 29 CN1_052
DIO_31 Bidir 5 30 CN1_054
DIO_32 Bidir 5 31 CN1_056
DIO_33 Bidir 6 0 CN1_058
DIO_33 Bidir 6 0 CN1_058
DIO_34 Bidir 6 1 CN1_060
DIO_35 Bidir 6 2 CN1_064
DIO_36 Bidir 6 3 CN1_066
DIO_37 Bidir 6 4 CN1_068
DIO_38 Bidir 6 5 CN1_070
DIO_39 Bidir 6 6 CN1_072
DIO_40 Bidir 6 7 CN1_074
DIO_41 Bidir 6 8 CN1_076
DIO_42 Bidir 6 9 CN1_078
DIO_43 Bidir 6 10 CN1_080
DIO_44 Bidir 6 11 CN1_082
DIO_45 Bidir 6 12 CN1_084
DIO_46 Bidir 6 13 CN1_086
DIO_47 Bidir 6 14 CN1_088
DIO_48 Bidir 6 15 CN1_090
DIO_49 Bidir 6 16 CN1_092
DIO_50 Bidir 6 17 CN1_094
DIO_51 Bidir 6 18 CN1_096
DIO_52 Bidir 6 19 CN1_098
DIO_53 Bidir 6 20 CN1_100
DIO_54 Bidir 6 21 CN1_011
DIO_55 Bidir 6 22 CN1_013
DIO_56 Bidir 6 23 CN1_017
DIO_57 Bidir 6 24 CN1_019
DIO_58 Bidir 6 25 CN1_021
DIO_59 Bidir 6 26 CN1_023
DIO_60 Bidir 6 27 CN1_025
DIO_61 Bidir 6 28 CN1_027
DIO_62 Bidir 6 29 CN1_031
DIO_63 Bidir 6 30 CN1_033
DIO_64 Bidir 6 31 CN1_035
DIO_65 Bidir 7 0 CN1_037
DIO_65 Bidir 7 0 CN1_037
DIO_66 Bidir 7 1 CN1_039
DIO_67 Bidir 7 2 CN1_041
DIO_68 Bidir 7 3 CN1_043
DIO_69 Bidir 7 4 CN1_045
DIO_70 Bidir 7 5 CN1_049
DIO_71 Bidir 7 6 CN1_051
DIO_72 Bidir 7 7 CN1_053
DIO_73 Bidir 7 8 CN1_055
DIO_74 Bidir 7 9 CN1_057
DIO_75 Bidir 7 10 CN1_059
DIO_76 Bidir 7 11 CN1_061
DIO_77 Bidir 7 12 CN1_063
DIO_78 Bidir 7 13 CN1_065
DIO_79 Bidir 7 14 CN1_067
DIO_80 Bidir 7 15 CN1_073
DIO_81 Bidir 7 16 CN1_077
DIO_82 Bidir 7 17 CN1_079
DIO_83 Bidir 7 18 CN1_081
DIO_84 Bidir 7 19 CN1_083
DIO_85 Bidir 7 20 CN1_085
DIO_86 Bidir 7 21 CN1_087
DIO_87 Bidir 7 22 CN1_089
DIO_88 Bidir 7 23 CN1_091
DIO_89 Bidir 7 24 CN1_093
DIO_90 Bidir 7 25 CN1_097


I2C

This product uses two CPU I2C busses for on-board ICs, one I3C-capable bus for offboard.

Device Address Description
/dev/i2c-0 Unused This bus is brought out to CN2_28 (SCL) / CN2_30 (SDA)
/dev/i2c-1 0x25 NXP PMIC
/dev/i2c-3
0x2e TPM [1]
0x54 Wizard µC
0x60 #RTC
  1. On Rev P3 and later

I3C

TS-4300 I3C

LCD Interface

The i.MX93 includes an LCD Interface controller with a simple framebuffer, which can then be passed to LVDS or MIPI-DSI.

LCD Output Mux

The TS-4300 includes a high speed mux controlled by SEL_LVDS. This allows the TS-SOCKET to provide both LVDS and MIPI-DSI on the odd pins CN2_41 through CN2_61.

This can be selected in device tree by specifying the mux state in your MIPI or LVDS nodes:

/* Select MIPI-DSI */
mux-states = <&video_mux 1>;

...

/* Select LVDS */
mux-states = <&video_mux 0>;
SEL_LVDS Value Function TS-Socket pin
0 CPU_LVDS_D1_P CN2_41
CPU_LVDS_D1_M CN2_43
CPU_LVDS_D0_P CN2_47
CPU_LVDS_D0_M CN2_49
CPU_LVDS_D2_P CN2_53
CPU_LVDS_D2_M CN2_55
CPU_LVDS_CLK_P CN2_59
CPU_LVDS_CLK_M CN2_61
1 CPU_MIPI_D1_P CN2_41
CPU_MIPI_D1_M CN2_43
CPU_MIPI_D0_P CN2_47
CPU_MIPI_D0_M CN2_49
CPU_MIPI_D3_P CN2_53
CPU_MIPI_D3_M CN2_55
CPU_MIPI_D2_P CN2_59
CPU_MIPI_D2_M CN2_61

LVDS

TS-4300 LVDS

MIPI-DSI

The i.MX93 includes a MIPI-DSI (DPHY) which, using 4 lanes provides support for up to 2048x1080 pixels at 60hz, and 24 bpp. Refer to the CPU Reference manual's chapters on MIPI-DSI / MIPI-DSI DPHY for more details.

LEDs

There are two LEDS on the TS-4300 that may be controlled by the user through the sysfs interface. These are colored red and green.

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

# Example:  Turn on the Red LED...
echo 1 > /sys/class/leds/red:status/brightness

# Turn it off again...
echo 0 > /sys/class/leds/red:status/brightness

# Make the green LED act as a heartbeat
echo heartbeat > /sys/class/leds/green:power/trigger

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

MicroSD Interface

TS-4300 MicroSD Interface

NPU

The i.MX93 includes an ARM Ethos-U65 NPU to support accelerating neural networks for AI applications.

Features:

  • 256 MACs operating up to 1GHz and 2 OPS/MAC
  • Targets 8-bit and 16-bit integer RNN
  • Handles 8-bit weights

The initial kernels for i.MX93-based products are based on NXP's repository, where NPU support only exists via the M33 co-processor. NXP provides separate firmware for operating the M33 as a standalone model-runner or as a Tensorflow "delegate". This section only discusses the latter method of using the NPU. The Tensorflow delegate takes full control of the M33 and enables Linux's use of the NPU as a machine-learning coprocessor. It shows up as /dev/ethosu0 when kernel-level support is present, activated by compile-time configuration parameters and device tree entries. Additional required software components are as follows:

Component/Repository Description
ethos-u-firmware Firmware binary. Source may be downloaded from NXP as part of their MCUExpresso BSP.
ethos-u-driver-stack-imx User-space driver and libraries that go through /dev/ethosu0 on NXP processors
tflite-ethosu-delegate-imx This is how Tensorflow knows how to use Ethos-U on NXP processors
nxp-imx/tensorflow-imx NXP's fork of Tensorflow, including Tensorflow Lite, that is needed on the i.MX93
nxp-imx/ethos-u-vela.git NXP's Vela fork is required in order to translate Tensorflow Lite models for the Ethos-U

Details on these, as well as on how to use NXP's software support via Yocto, can be found in their i.MX Machine Learning User's Guide.

It should be noted that every one of the above repositories has a kernel release-specific branch. Failures, either when building or at runtime, are common when intermixing releases or when not using a branch that is correctly matched to the kernel in use.

Our standard Debian releases currently include kernel support for Ethos-U, but the additional software listed above must be downloaded and built in order to make use of the NPU.

To make this as pain-free as possible, we provide a script that downloads, builds, and installs all of these components and their dependencies atop our headless or X11 distributions. The script must be executed on the i.MX93 system running the distribution, and requires a high-speed Internet connection. Expect it to take up to three hours.

wget http://files.embeddedts.com/ts-socket-macrocontrollers/ts-4300-linux/scripts/install-npu-software.sh
chmod +x install-npu-software.sh
./install-npu-software.sh

When complete, a much shorter script can be used to verify the installation by downloading and executing this demo (similar to one that appears in the ML User's Guide):

wget http://files.embeddedts.com/ts-socket-macrocontrollers/ts-4300-linux/scripts/run-hopper-example.sh
chmod +x run-hopper-example.sh
./run-hopper-example.sh

The script downloads a Tensorflow model, runs Vela to prepare it for Ethos-U, and then performs an inference task using a test image and label choices that come with Tensorflow.

SILO

TS-4300 SILO

Sleep Mode

TS-4300 sleep modes

SPI

This platform brings out the one "LPSPI4" controller from the i.MX93.

This is connected to:

  • Onboard ADC
  • Mikrobus SPI
    • /dev/spidev1.1
  • Daughtercard Header (When selected through #FPGA XBAR)
    • /dev/spidev1.2

See SPI MUX for more information about how this LPSPI4 is mapped to other pins.

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

TS-4300 UARTs

USB

TS-4300 USB

Watchdog

TS-4300 Watchdog

WiFi

TS-4300 WIFI

Specifications

IO specifications

TS-4300 IO Specifications

Power Consumption

TS-4300 Power Consumption

Power Input Specifications

TS-4300 Power Input Specifications

External Interfaces

TS-Socket

USB-C Console Connector

TS-4300 USB Console Connector

Revisions and Changes

PCB Revisions

Revision Changes
P2
  • Initial public release

U-Boot Revisions

Depending on context, you can determine your U-Boot revision in one of several ways:

1. The U-Boot build date can be viewed as the first line of USB console output when the unit is powered on. For example:

U-Boot 2016.03-00408-gd450758c91 (Oct 10 2019 - 11:59:08 -0700)

CPU:   Freescale i.MX6UL rev1.2 at 396 MHz
...

2. U-Boot has a version command that outputs similar version information to what is shown above.

3. At a Linux shell, the following command prints the version strings of any U-Boot and/or SPL image that is present in eMMC:

strings /dev/mmcblk0boot0 | grep '^U-Boot .*(.*)'

The output is the same string(s) that will be printed on the console at board startup. TS-4300 U-Boot Changelog

FPGA Revisions

To determine the version of the FPGA on a TS-4300, see the startup output in U-Boot:

U-Boot 2024.04-00047-gd6a3cd9d75c-dirty (Mar 07 2025 - 21:03:22 +0000)

Reset Status: POR 

CPU:   NXP i.MX93(52) Rev1.1 A55 at 1700 MHz
CPU:   Extended Industrial temperature grade  (-40C to 125C) at 32C

DRAM:  1 GiB
Model: embeddedTS TS-4300
Core:  200 devices, 25 uclasses, devicetree: fit
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial

BuildInfo:
  - ELE firmware version 1.2.0-38f309fe

switch to partitions #0, OK
mmc0(part 0) is current device
FPGA Bootloader: v0.1.2
FPGA TS-4300: v0.2.2
flash target is MMC:0

In this case, the bootloader is v0.1.2, and the FPGA application is v0.2.2.

See the FPGA Updates section for more details on updating to the latest.

Date Version Description
2025-05-21 v0.2.2
  • Initial public release
2025-09-17 v0.2.3
  • Added EXT_RESET support
  • Completed XBAR support
  • Added SPI CS passthrough

Wizard Firmware Revisions

TS-9370 Wizard Changelog

Software Images

Debian Changelog

TS-9390 Debian Changelog

Product Notes

FCC Advisory

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

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

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

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

Limited Warranty

See our Terms and Conditions for more details.


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.

Trademarks

Arm and Cortex are registered trademarks of Arm Limited (or its subsidiaries) in the US and/or elsewhere.