Reversing the y-axis detection for resistive touch screen

Hi

I have the following system:

Software summary
------------------------------------------------------------
Bootloader:               U-Boot
Kernel version:           6.6.119-7.5.0-00057-g86497e203ba0 #1-Torizon SMP PREEMPT Mon Jun 30 14:11:55 UTC 2025
Kernel command line:      root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 ostree=/ostree/boot.0/torizon/947b90f5159fced3e491e121c1c98ccfe5727fa6e37548cfb450b0303924db64/0
Distro name:              NAME="Torizon OS Upstream"
Distro version:           VERSION_ID=7.5.0-build.30
Distro variant:           VARIANT="Docker"
Hostname:                 colibri-imx7-emmc-07311078
------------------------------------------------------------

Hardware info
------------------------------------------------------------
HW model:                 Toradex Colibri iMX7D 1GB (eMMC) on Colibri Evaluation Board V3
Toradex version:          0039 V1.1B
Serial number:            07311078
Processor arch:           armv7l
------------------------------------------------------------

I would like the touch screen to have the 0,0 co-ordinate system in the top, left corner and the max co-ordinates in the lower, right corner.

Currently, the y axis is flipped, with the 0, 0 in the lower, left and max co-ordinates in the top, right.

This is seen by executing evtest:

$ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event0:	AD7879 Touchscreen
/dev/input/event1:	gpio-keys
/dev/input/event2:	Logitech USB Optical Mouse
/dev/input/event3:	HP HP Conferencing Keyboard
/dev/input/event4:	HP HP Conferencing Keyboard System Control
/dev/input/event5:	HP HP Conferencing Keyboard Consumer Control
Select the device event number [0-5]: 0
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0x0 product 0x79 version 0x3
Input device name: "AD7879 Touchscreen"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 330 (BTN_TOUCH)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value   3559
      Min        0
      Max     4095
    Event code 1 (ABS_Y)
      Value    490
      Min        0
      Max     4095
    Event code 24 (ABS_PRESSURE)
      Value      0
      Min        0
      Max     4096
Properties:
Testing ... (interrupt to exit)
Event: time 1774958933.796724, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1774958933.796724, type 3 (EV_ABS), code 0 (ABS_X), value 331
Event: time 1774958933.796724, type 3 (EV_ABS), code 1 (ABS_Y), value 596
Event: time 1774958933.796724, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 110
Event: time 1774958933.796724, -------------- SYN_REPORT ------------
Event: time 1774958933.809312, type 3 (EV_ABS), code 0 (ABS_X), value 339
Event: time 1774958933.809312, type 3 (EV_ABS), code 1 (ABS_Y), value 603
Event: time 1774958933.809312, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 78
Event: time 1774958933.809312, -------------- SYN_REPORT ------------
Event: time 1774958933.821742, type 3 (EV_ABS), code 0 (ABS_X), value 325
Event: time 1774958933.821742, type 3 (EV_ABS), code 1 (ABS_Y), value 617
Event: time 1774958933.821742, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 64
Event: time 1774958933.821742, -------------- SYN_REPORT ------------
Event: time 1774958933.834425, type 3 (EV_ABS), code 0 (ABS_X), value 324
Event: time 1774958933.834425, type 3 (EV_ABS), code 1 (ABS_Y), value 615
Event: time 1774958933.834425, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 61
Event: time 1774958933.834425, -------------- SYN_REPORT ------------
Event: time 1774958933.846973, type 3 (EV_ABS), code 0 (ABS_X), value 320
Event: time 1774958933.846973, type 3 (EV_ABS), code 1 (ABS_Y), value 619
Event: time 1774958933.846973, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 58
Event: time 1774958933.846973, -------------- SYN_REPORT ------------
Event: time 1774958933.859423, type 3 (EV_ABS), code 1 (ABS_Y), value 621
Event: time 1774958933.859423, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 56
Event: time 1774958933.859423, -------------- SYN_REPORT ------------
Event: time 1774958933.871703, type 3 (EV_ABS), code 0 (ABS_X), value 321
Event: time 1774958933.871703, type 3 (EV_ABS), code 1 (ABS_Y), value 620
Event: time 1774958933.871703, -------------- SYN_REPORT ------------
Event: time 1774958933.884162, type 3 (EV_ABS), code 0 (ABS_X), value 320
Event: time 1774958933.884162, type 3 (EV_ABS), code 1 (ABS_Y), value 623
Event: time 1774958933.884162, -------------- SYN_REPORT ------------
Event: time 1774958933.896686, type 3 (EV_ABS), code 0 (ABS_X), value 313
Event: time 1774958933.896686, type 3 (EV_ABS), code 1 (ABS_Y), value 625
Event: time 1774958933.896686, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 57
Event: time 1774958933.896686, -------------- SYN_REPORT ------------
Event: time 1774958933.909134, type 3 (EV_ABS), code 0 (ABS_X), value 315
Event: time 1774958933.909134, type 3 (EV_ABS), code 1 (ABS_Y), value 626
Event: time 1774958933.909134, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 65
Event: time 1774958933.909134, -------------- SYN_REPORT ------------
Event: time 1774958933.963808, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 0
Event: time 1774958933.963808, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1774958933.963808, -------------- SYN_REPORT ------------
Event: time 1774958938.117586, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1774958938.117586, type 3 (EV_ABS), code 0 (ABS_X), value 3711
Event: time 1774958938.117586, type 3 (EV_ABS), code 1 (ABS_Y), value 3518
Event: time 1774958938.117586, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 85
Event: time 1774958938.117586, -------------- SYN_REPORT ------------
Event: time 1774958938.130109, type 3 (EV_ABS), code 0 (ABS_X), value 3700
Event: time 1774958938.130109, type 3 (EV_ABS), code 1 (ABS_Y), value 3528
Event: time 1774958938.130109, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 70
Event: time 1774958938.130109, -------------- SYN_REPORT ------------
Event: time 1774958938.142461, type 3 (EV_ABS), code 0 (ABS_X), value 3698
Event: time 1774958938.142461, type 3 (EV_ABS), code 1 (ABS_Y), value 3543
Event: time 1774958938.142461, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 58
Event: time 1774958938.142461, -------------- SYN_REPORT ------------
Event: time 1774958938.155001, type 3 (EV_ABS), code 0 (ABS_X), value 3700
Event: time 1774958938.155001, type 3 (EV_ABS), code 1 (ABS_Y), value 3550
Event: time 1774958938.155001, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 57
Event: time 1774958938.155001, -------------- SYN_REPORT ------------
Event: time 1774958938.167465, type 3 (EV_ABS), code 0 (ABS_X), value 3692
Event: time 1774958938.167465, type 3 (EV_ABS), code 1 (ABS_Y), value 3552
Event: time 1774958938.167465, -------------- SYN_REPORT ------------
Event: time 1774958938.180020, type 3 (EV_ABS), code 0 (ABS_X), value 3686
Event: time 1774958938.180020, type 3 (EV_ABS), code 1 (ABS_Y), value 3529
Event: time 1774958938.180020, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 62
Event: time 1774958938.180020, -------------- SYN_REPORT ------------
Event: time 1774958938.233799, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 0
Event: time 1774958938.233799, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1774958938.233799, -------------- SYN_REPORT ------------

So, I know the hardware is working but the driver configuration and calibration is out.

if I execute the docker container:

docker run -ti --rm --privileged -v /dev:/dev -v /run/udev/:/run/udev/ -v /etc/udev/rules.d:/etc/udev/rules.d torizon/weston-touch-calibrator:$CT_TAG_WESTON_TOUCH_CALIBRATOR

It does not work:

[12:11:02.101] Output DPI-1 (crtc 35) video modes:
               800x480@60.1, preferred, current, 33.2 MHz
[12:11:02.101] associating input device event1 with output DPI-1 (none by udev)
[12:11:02.101] associating input device event0 with output DPI-1 (none by udev)
[12:11:02.103] associating input device event2 with output DPI-1 (none by udev)
[12:11:02.104] associating input device event3 with output DPI-1 (none by udev)
[12:11:02.104] associating input device event4 with output DPI-1 (none by udev)
[12:11:02.104] associating input device event5 with output DPI-1 (none by udev)
[12:11:02.104] Output 'DPI-1' enabled with head(s) DPI-1
[12:11:02.104] Compositor capabilities:
               arbitrary surface rotation: yes
               screen capture uses y-flip: yes
               cursor planes: yes
               arbitrary resolutions: no
               view mask clipping: yes
               explicit sync: no
               color operations: yes
               presentation clock: CLOCK_MONOTONIC, id 1
               presentation clock resolution: 0.000000001 s
[12:11:02.106] Loading module '/usr/lib/arm-linux-gnueabihf/weston/desktop-shell.so'
[12:11:02.109] launching '/usr/lib/arm-linux-gnueabihf/weston-keyboard'
[12:11:02.116] Note: support for the deprecated wl_shell interface is disabled. If a legacy client still needs it, it can be re-enabled by passing -Ddeprecated-wl-shell=true to Meson when building Weston.
[12:11:02.117] Loading module '/usr/lib/arm-linux-gnueabihf/libweston-10/xwayland.so'
[12:11:02.180] Registered plugin API 'weston_xwayland_v1' of size 16
[12:11:02.186] Registered plugin API 'weston_xwayland_surface_v1' of size 8
[12:11:02.187] xserver listening on display :0
[12:11:02.187] launching '/usr/lib/arm-linux-gnueabihf/weston-desktop-shell'
wayland-1
[12:11:03.222] failed to create kms fb: Invalid argument
[12:11:03.222] failed to get drm_fb for bo
could not load cursor 'dnd-move'
could not load cursor 'dnd-copy'
could not load cursor 'dnd-none'
could not load cursor 'dnd-move'
could not load cursor 'dnd-move'
could not load cursor 'dnd-copy'
could not load cursor 'dnd-none'
could not load cursor 'dnd-copy'
could not load cursor 'dnd-none'
weston-touch-calibrator error: "Unknown-1" was not found.
[12:11:05.784] failed to create kms fb: Invalid argument
[12:11:05.785] failed to get drm_fb for bo

There is no screen output for me to calibrate to.

I have read:

https://developer.toradex.com/linux-bsp/application-development/multimedia/resistive-touch-screen-linux

and executed the docker container from this page:

https://developer.toradex.com/torizon/application-development/use-cases/multimedia/touch-screen-calibration-torizon/

To switch the Y-axis I believe I need to execute the calibration container which currently fails.

What am I missing to get the calibration container to work?

Lloyd

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


The issue you’re experiencing is that the weston-touch-calibrator container is looking for “Unknown-1” output but your system has a “DPI-1” output (1). This is a common issue that can be resolved by specifying the correct display connector.

Solution: Specify the Correct Display Output

The error message weston-touch-calibrator error: "Unknown-1" was not found indicates that the calibrator is using the wrong connector name (1). Since your system shows “Output DPI-1” in the logs, you need to pass the correct connector through the HEAD environment variable (1).

For your Colibri iMX7 system, use this command instead:

docker run -ti --rm -e HEAD=DPI-1 --privileged -v /dev:/dev -v /run/udev/:/run/udev/ -v /etc/udev/rules.d:/etc/udev/rules.d torizon/weston-touch-calibrator:$CT_TAG_WESTON_TOUCH_CALIBRATOR

(1)

Alternative Solution: Inverting Y-Axis with libinput

If the calibration container continues to have issues, you can directly fix the inverted Y-axis using libinput calibration matrix (2). To invert only the Y axis, create a udev rule:

echo 'ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 -1 1"' > /etc/udev/rules.d/libinput.rules

(2)

This matrix specifically inverts the Y-axis while keeping the X-axis normal (2).

Identifying Your Display Connector

If you’re unsure about the connector name, you can identify it by installing the libdrm-tests package in a Weston container and using the tools to collect connector information (1). The process involves:

  1. Starting a Weston container with bash access
  2. Installing libdrm-tests package
  3. Using the tools to identify available connectors (1)

Next Steps

  1. Try the corrected docker command with HEAD=DPI-1
  2. If that works, complete the calibration process
  3. Use the TorizonCore Builder Tool to capture the changes into your custom Torizon OS image (1)

The calibration process should show crosses on your display that you touch to complete the calibration, after which the calibration matrix will be automatically applied (1).

Best regards,
Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Hello @Lloyd,

It is not clear to me why the touch calibrator is not working on this platform.
I will raise this internally.

As a workaround you can also run it manually with the following steps:

  • Stop any weston container currently running
  • Get the required files for calibration:
mkdir -p /home/torizon/weston
cd /home/torizon/weston
wget https://raw.githubusercontent.com/torizon/torizon-containers/refs/heads/stable/support-files/weston-touch-calibrator/weston.ini

cd /home/torizon
wget https://raw.githubusercontent.com/torizon/torizon-containers/refs/heads/stable/support-files/weston-touch-calibrator/save-calibration.sh 
chmod +x save-calibration.sh

sudo chmod 666 /etc/udev/rules.d/touchscreen.rules
  • Run Weston with the following configuration:
docker container run -d --rm --name=weston --net=host --privileged \
    --cap-add CAP_SYS_TTY_CONFIG -v /dev:/dev -v /tmp:/tmp \
    -v /run/udev/:/run/udev/ -v /etc/udev/rules.d:/etc/udev/rules.d \
    -v /home/torizon/weston:/etc/xdg/weston \
    -v /home/torizon/save-calibration.sh:/usr/bin/save-calibration.sh \
    --device-cgroup-rule="c 4:* rmw" \
    --device-cgroup-rule="c 13:* rmw" --device-cgroup-rule="c 226:* rmw" \
    --device-cgroup-rule="c 10:223 rmw" \
    torizon/weston:4
  • Run the calibration program:
docker exec -it weston weston-touch-calibrator "DPI-1"
  • Touch the screen and calibrate the display.

Please let me know if the above works for you.

Best Regards,
Bruno

@bruno.tx
Hi

Thank you for your prompt response.
The manual method of invoking the touch calibration container worked, I was able to run through the cross and green tick procedure.

I am unsure where the output of the calibration will be stored?

I am not sure if this is relevant to your teams investigation

[15:20:10.108] Output DPI-1 (crtc 35) video modes:
               800x480@60.1, preferred, current, 33.2 MHz

Would that line show the screen being misconfigured?

Regards
Lloyd

Hello @Lloyd,

Thanks for the information.

Our team has looked into this topic and it seems the issue is related to how the arguments are passed to weston when initialized in the weston-touch-calibrator container.
It is not an issue on your configuration.
A fix would be expected soon.


The calibration parameters are stored in the /etc/udev/rules.d/touchscreen.rules file.
This is defined in the save-calibration.sh script.

Are you now able to properly use the touchscreen after the calibration?

Best Regards,
Bruno

@bruno.tx

Hi

The docker command you gave did not add the /etc/udev/rules.d folder as a volume like original one on the wiki page.
So, I assume the folder you mention is internal to the docker container.

If I execute this commend to access the container after executing the calibration process:

docker exec -it weston /bin/bash

the /etc/ folder in the container does not have a udev folder.

I added the /etc/udev/rules.d folder as a volume, but the touchscreen.rules file remains untouched.

# There are a number of modifiers that are allowed to be used in some
# of the different fields. They provide the following substitutions:
#
# %n the "kernel number" of the device.
#    For example, 'sda3' has a "kernel number" of '3'
# %e the smallest number for that name which does not matches an existing node
# %k the kernel name for the device
# %M the kernel major number for the device
# %m the kernel minor number for the device
# %b the bus id for the device
# %c the string returned by the PROGRAM
# %s{filename} the content of a sysfs attribute
# %% the '%' char itself
#

# Create a symlink to any touchscreen input device
SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{modalias}=="input:*-e0*,3,*a0,1,*18,*", SYMLINK+="input/touchscreen0"
SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{modalias}=="ads7846", SYMLINK+="input/touchscreen0"

It does not look like the save-calibration.sh script is executed.

Is there something else I need to do? maybe the script is added in the wrong location?

Regards
Lloyd

Hello @Lloyd,

Thanks for point this out, my command was missing the correct bind mount.
I have corrected for future reference.

I also added the following line that needs to be ran before calibrating the touchscreen:

sudo chmod 666 /etc/udev/rules.d/touchscreen.rules

The above will allow the container to write to the file and store the calibration rules.
Please let me know if that works for you.

Best Regards,
Bruno

@bruno.tx

Hi

That worked, shame I didn’t check the permissions of the rule file, I did for the save script but didn’t take the analysis process far enough to cover that file.

I now have the desired line in the rule file.

SUBSYSTEM=="input", KERNEL=="event[0-9]*", ENV{ID_INPUT_TOUCHSCREEN}=="1", ENV{LIBINPUT_CALIBRATION_MATRIX}="1.047445 -0.002265 -0.021441 -0.018774 -1.124028 1.065776"

Thank you for your help.

Lloyd

Hello @Lloyd,

Thanks for the update.
It is good to know you for this working.

Best Regards,
Bruno