TS-7100 FPGA
FPGA Registers
The TS-7100 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
| Offset | Description |
|---|---|
| 0x0000 | UART 16550 #0 |
| 0x0100 | Opencore SPI controller #0 |
| 0x0120 | Opencore SPI controller #1 |
| 0x0180 | FPGA PWM 0 |
| 0x0190 | FPGA PWM 1 |
| 0x01a0 | FPGA PWM 2 |
| 0x01b0 | FPGA PWM 3 |
| 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. These are used for the FRAM memory, accessing the flash used for the LCD splash screen image, and the LCD touch screen itself. All of these operations are handled via the Linux kernel. It is not recommended to interact directly with these registers
FPGA PWM
The TS-7100 includes a PWM core that supports 10-bit duty/period, a 4.95 MHz input clock, and 12 values of input clock shift.
Each PWM shows as its own controller with a single channel each.
| PWM | Location |
|---|---|
| pwmchip0 | Terminal Block pin 14 DIO_1_STC |
| pwmchip1 | Terminal Block pin 16 DIO_2_STC |
| pwmchip2 | Terminal Block pin 27 EN_HS_SW |
| pwmchip3 | Terminal Block pin 18 EN_LS_OUT_3 |
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 | 49500000 | 20667 | 48387 |
| 1 | 24750000 | 41333 | 24194 |
| 2 | 12375000 | 82667 | 12097 |
| 3 | 6187500 | 165333 | 6048 |
| 4 | 3093750 | 330667 | 3024 |
| 5 | 1546875 | 661333 | 1512 |
| 6 | 773437 | 1322668 | 756 |
| 7 | 386718 | 2645338 | 378 |
| 8 | 193359 | 5290677 | 189 |
| 9 | 96679 | 10581409 | 95 |
| 10 | 48339 | 21163036 | 47 |
| 11 | 24169 | 42326948 | 24 |
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, this is the register map for the PWM core.
| 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)) |
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.
- ↑ Note that this is also used for UART clock generation.
FPGA IRQs
| Bit | Description |
|---|---|
| 31:17 | Reserved |
| 16 | Touch Screen IRQ |
| 15:13 | Reserved |
| 12 | DIO Fault Breaker IRQ |
| 11 | Reserved |
| 10 | Opencore SPI Controller #1 IRQ |
| 9 | Opencore SPI Controller #0 IRQ |
| 8:1 | Reserved |
| 0 | UART #0 IRQ |