How to run peripheral example GPIO C Example?

Hello All,

I am using iMX8MP and on windows laptop run ubuntu virtual Linux. I referred this link for GPIO Example and GitHub C Code: LINK

All required setup I did and successfully ran hello example. But when i tried to build this GPIO C example getting below error:

Please help me how build successfully for arm64 architecture?

Thank you in Advanced.
Vishal

Hi, I’m the Toradex AI Assistant.

I might make mistakes. Our support team will step in if needed. If I answered your question, please tick the “Solution” checkbox. For follow-up questions to me, please use @ToradexAI in your post.

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


Hello Vishal,

Thank you for providing detailed information about your setup and the issue. The error you’re facing while building the GPIO C example is likely due to missing GPIO development dependencies—specifically, the libgpiod development headers and libraries.

Here’s how you can resolve the error and build the GPIO C example for your i.MX8MP (arm64) module:


1. Update torizonPackages.json

Add the required GPIO development libraries to your torizonPackages.json as below:

{
    "deps": [
       "libgpiod2"
    ],
    "devDeps": [
       "libgpiod-dev"
    ]
}

This ensures libgpiod and its development files are available in your container.
Learn more: C GPIO application sample, Toradex Docs


2. Update the Makefile

Ensure your Makefile links against the gpiod library:

- LDFLAGS :=
+ LDFLAGS := -lgpiod

This step allows proper linkage for GPIO functions used in your application.


3. Rebuild the Development Container

Once you’ve updated torizonPackages.json, rebuild the development container.

  • In VS Code: Open the Command Palette and run Torizon: Rebuild Container.
  • Alternatively, run the check-deps task.

This ensures the new dependencies are installed in your build environment.
See details: Community Reference


4. Confirm Device Access

Make sure your docker-compose.yml gives the container access to the required GPIO device:

devices:   
  - "/dev/gpiochip0"

Sample Reference


Summary

  • Add libgpiod2 and libgpiod-dev to torizonPackages.json
  • Link the binary with -lgpiod in the Makefile.
  • Rebuild the container for dependencies to take effect.
  • Confirm /dev/gpiochip0 access in your docker-compose.yml.

These steps should resolve the “gpiod.h: No such file” and allow you to build and run the GPIO C example on your i.MX8MP.

Let me know if you need further clarification or run into any other issues!

Best regards,
Toradex AI Assistant.

Hey @vishalborle92,

Can you run the task runner commands try-update-template-accepting-all and check-deps download all the is required, and then run the build command again? Also can you post the full logs rather than a screenshot.

Thanks

-Eric

Hello Eric.tx,
Thanks for prompt response.

I verified all things that Toradex AI said looks correct to me. then tried to run try-update-template-accepting-all but getting errors attached full log for your reference..

Container Runtime: docker
Run Arguments: --rm --privileged torizon/binfmt
Container Name: binfmt
Error response from daemon: No such container: binfmt
Container does not exist. Starting ...
*  Terminal will be reused by tasks, press any key to close it. 

You are about to accept all incoming changes from the updated template
If the project is not versioned there is no way back
Accept all changes? [y/n]: y
Copy-Item: /home/vishal/gpio/C/gpioC/.conf/projectUpdater.ps1:105:1
Line |
105 |  Copy-Item `
    |  ~~~~~~~~~~~
    | Cannot find path '/home/vishal/.apollox/cConsole/.conf/update.json' because it does not exist.

*  The terminal process "pwsh '-nop', '/home/vishal/gpio/C/gpioC/.conf/projectUpdater.ps1', '/home/vishal/gpio/C/gpioC', 'gpioC', '1'" terminated with exit code: 1. 
*  Terminal will be reused by tasks, press any key to close it. 

*  Executing task: DOCKER_HOST= docker build --pull -f /home/vishal/gpio/C/gpioC/Dockerfile.sdk /home/vishal/gpio/C/gpioC -t cross-toolchain-arm64-gpioc --build-arg IMAGE_ARCH=arm64 --build-arg GPU= --build-arg APP_ROOT=/home/torizon/app 

[+] Building 2.2s (8/8) FINISHED                                                                                                              docker:default
=> [internal] load build definition from Dockerfile.sdk                                                                                                0.0s
=> => transferring dockerfile: 1.07kB                                                                                                                  0.0s
=> WARN: InvalidDefaultArgInFrom: Default value for ARG torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG} results in empty or invali  0.0s
=> [internal] load metadata for docker.io/torizon/debian-cross-toolchain-arm64:3.3.0-bookworm                                                          2.1s
=> [internal] load .dockerignore                                                                                                                       0.0s
=> => transferring context: 56B                                                                                                                        0.0s
=> [1/4] FROM docker.io/torizon/debian-cross-toolchain-arm64:3.3.0-bookworm@sha256:46b730261b75685dd8bd454f295114bc1dfcd85f6e8f077b97bb57d719f033fd    0.0s
=> CACHED [2/4] RUN apt-get -q -y update &&     apt-get -q -y install     &&     apt-get clean && apt-get autoremove &&     rm -rf /var/lib/apt/lists  0.0s
=> CACHED [3/4] RUN apt-get -q -y update &&     apt-get -q -y install  libgpiod-dev:     &&     apt-get clean && apt-get autoremove &&     rm -rf /va  0.0s
=> CACHED [4/4] WORKDIR /home/torizon/app                                                                                                              0.0s
=> exporting to image                                                                                                                                  0.0s
=> => exporting layers                                                                                                                                 0.0s
=> => writing image sha256:892c7a076563ebb070fe0c7087e138031c6cd4d0ffaf09ca3495d92b76cfb6ea                                                            0.0s
=> => naming to docker.io/library/cross-toolchain-arm64-gpioc                                                                                          0.0s

1 warning found (use docker --debug to expand):
- InvalidDefaultArgInFrom: Default value for ARG torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG} results in empty or invalid base image name (line 16)
*  Terminal will be reused by tasks, press any key to close it. 

*  Executing task: make ARCH=arm64 makedir 

*  Terminal will be reused by tasks, press any key to close it. 

*  Executing task: DOCKER_HOST= docker run --rm -v /home/vishal/gpio/C/gpioC:/home/torizon/app cross-toolchain-arm64-gpioc make ARCH=arm64 CC=aarch64-linux-gnu-gcc debug 

aarch64-linux-gnu-gcc -Iincludes/ -g build-arm64/debug/main.o -o build-arm64/debug/gpioC -lgpiod
/usr/lib/gcc-cross/aarch64-linux-gnu/12/../../../../aarch64-linux-gnu/bin/ld: cannot find -lgpiod: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [Makefile:47: build-arm64/debug/gpioC] Error 1

*  The terminal process "/usr/bin/bash '-c', 'DOCKER_HOST= docker run --rm -v /home/vishal/gpio/C/gpioC:/home/torizon/app cross-toolchain-arm64-gpioc make ARCH=arm64 CC=aarch64-linux-gnu-gcc debug'" terminated with exit code: 2. 
*  Terminal will be reused by tasks, press any key to close it. 

Thanks,
Vishal

Hey @vishalborle92,

And can you run the check-deps task runner and post the logs?

Thanks

Hi @eric.tx

I just ran check-deps task below log:

Checking dependencies ...
👍 openssh-client debian package dependency installed
👍 sshpass debian package dependency installed
👍 build-essential debian package dependency installed
👍 make debian package dependency installed
👍 gdb debian package dependency installed
👍 gcc debian package dependency installed
✅ All packages already installed and installation scripts executed before for this project
 *  Terminal will be reused by tasks, press any key to close it. 

All dependency looks good but still getting this gpiod lib not found for arm64.

Hey @vishalborle92,

Have you added the Debian packages to the torizonpackages.json file? We have a guide here for this here: Add Packages, Libraries, Tools and Files | Toradex Developer Center

-Eric

Hi @eric.tx

I was able to build my GPIO example the problem was in VS code settings.json not configured properly. But now when trying to run this example getting below ERROR:


Full log:

Container Runtime: docker
Run Arguments: -d -p 5002:5000 --restart=always registry:2
Container Name: registry
Container Exists
Container is running
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: pwsh -nop .conf/validateDepsRunning.ps1 


⚠️ VALIDATING ENVIRONMENT


✅ Environment is valid!

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: bash -c [[ ! -z "192.168.209.40" ]] && true || false 

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: bash -c [[ "aarch64" == "aarch64" ]] && true || false 

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: sleep 1 

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: sshpass -p raj54321 scp -P 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no /home/vishal/Toradex_Peripheral_Test/gpioC/docker-compose.yml torizon@192.168.209.40:~/ 

Warning: Permanently added '192.168.209.40' (ED25519) to the list of known hosts.
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: DOCKER_HOST=192.168.209.40:2375 docker image prune -f --filter=dangling=true 

Total reclaimed space: 0B
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: if [ false == false ]; then DOCKER_HOST=192.168.209.40:2375 docker compose -p torizon down --remove-orphans ; fi 

WARN[0000] Warning: No resource found to remove for project "torizon". 
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: DOCKER_HOST= docker build --pull -f /home/vishal/Toradex_Peripheral_Test/gpioC/Dockerfile.sdk /home/vishal/Toradex_Peripheral_Test/gpioC -t cross-toolchain-arm64-gpioc --build-arg IMAGE_ARCH=arm64 --build-arg GPU=-imx8 --build-arg APP_ROOT=/home/torizon/app 

[+] Building 3.2s (9/9) FINISHED                                                                                                                          docker:default
 => [internal] load build definition from Dockerfile.sdk                                                                                                            0.0s
 => => transferring dockerfile: 1.08kB                                                                                                                              0.0s
 => WARN: InvalidDefaultArgInFrom: Default value for ARG torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG} results in empty or invalid base image  0.0s
 => [internal] load metadata for docker.io/torizon/debian-cross-toolchain-arm64:3.3.0-bookworm                                                                      3.1s
 => [auth] torizon/debian-cross-toolchain-arm64:pull token for registry-1.docker.io                                                                                 0.0s
 => [internal] load .dockerignore                                                                                                                                   0.0s
 => => transferring context: 56B                                                                                                                                    0.0s
 => [1/4] FROM docker.io/torizon/debian-cross-toolchain-arm64:3.3.0-bookworm@sha256:46b730261b75685dd8bd454f295114bc1dfcd85f6e8f077b97bb57d719f033fd                0.0s
 => CACHED [2/4] RUN apt-get -q -y update &&     apt-get -q -y install     &&     apt-get clean && apt-get autoremove &&     rm -rf /var/lib/apt/lists/*            0.0s
 => CACHED [3/4] RUN apt-get -q -y update &&     apt-get -q -y install  libgpiod-dev:arm64     &&     apt-get clean && apt-get autoremove &&     rm -rf /var/lib/a  0.0s
 => CACHED [4/4] WORKDIR /home/torizon/app                                                                                                                          0.0s
 => exporting to image                                                                                                                                              0.0s
 => => exporting layers                                                                                                                                             0.0s
 => => writing image sha256:b8bfb7d61709dd80328fbaeb3512bdf8d08c52855c3924bab836ee7aeda213b1                                                                        0.0s
 => => naming to docker.io/library/cross-toolchain-arm64-gpioc                                                                                                      0.0s

 1 warning found (use docker --debug to expand):
 - InvalidDefaultArgInFrom: Default value for ARG torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG} results in empty or invalid base image name (line 16)
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: make ARCH=arm64 makedir 

 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: DOCKER_HOST= docker run --rm -v /home/vishal/Toradex_Peripheral_Test/gpioC:/home/torizon/app cross-toolchain-arm64-gpioc make ARCH=arm64 CC=aarch64-linux-gnu-gcc debug 

make: Nothing to be done for 'debug'.
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: DOCKER_HOST= docker compose build --pull --build-arg SSHUSERNAME=torizon --build-arg APP_ROOT=/home/torizon/app --build-arg IMAGE_ARCH=arm64 --build-arg SSH_DEBUG_PORT=2230 --build-arg GPU=-imx8 gpioc-debug 

WARN[0000] The "DOCKER_LOGIN" variable is not set. Defaulting to a blank string. 
WARN[0000] /home/vishal/Toradex_Peripheral_Test/gpioC/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion 
[+] Building 3.2s (15/15) FINISHED                                                                                                                                       
 => [internal] load local bake definitions                                                                                                                          0.0s
 => => reading from stdin 629B                                                                                                                                      0.0s
 => [internal] load build definition from Dockerfile.debug                                                                                                          0.0s
 => => transferring dockerfile: 2.69kB                                                                                                                              0.0s
 => WARN: StageNameCasing: Stage name 'Debug' should be lowercase (line 34)                                                                                         0.0s
 => [internal] load metadata for docker.io/torizon/debian:3.3.0-bookworm                                                                                            3.0s
 => [auth] torizon/debian:pull token for registry-1.docker.io                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                   0.0s
 => => transferring context: 56B                                                                                                                                    0.0s
 => [1/7] FROM docker.io/torizon/debian:3.3.0-bookworm@sha256:0ce675b0a48960560e2add9299f60b025271caba22a371e05c1f28029b1f6b28                                      0.0s
 => [internal] load build context                                                                                                                                   0.0s
 => => transferring context: 219B                                                                                                                                   0.0s
 => CACHED [2/7] RUN apt-get -q -y update &&     apt-get -q -y install     openssl     openssh-server     rsync     file     curl     gdb &&     apt-get clean &&   0.0s
 => CACHED [3/7] RUN apt-get -q -y update &&     apt-get -q -y install  libgpiod-dev:arm64     &&     apt-get clean && apt-get autoremove &&     rm -rf /var/lib/a  0.0s
 => CACHED [4/7] COPY .conf/id_rsa.pub /id_rsa.pub                                                                                                                  0.0s
 => CACHED [5/7] RUN mkdir /var/run/sshd &&     sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g'         -i /etc/pam.d/sshd &&       0.0s
 => CACHED [6/7] RUN rm -r /etc/ssh/ssh*key &&     dpkg-reconfigure openssh-server                                                                                  0.0s
 => CACHED [7/7] COPY --chown=torizon:torizon ./build-arm64/debug /home/torizon/app                                                                                 0.0s
 => exporting to image                                                                                                                                              0.0s
 => => exporting layers                                                                                                                                             0.0s
 => => writing image sha256:0641a77627bc616bd845b4b9666f9636bc12973a6cb149602055ee0373584d8e                                                                        0.0s
 => => naming to localhost:5002/gpioc-debug:arm64                                                                                                                   0.0s
 => resolving provenance for metadata file                                                                                                                          0.0s
[+] Building 1/1
 ✔ gpioc-debug  Built                                                                                                                                               0.0s 
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: DOCKER_HOST= docker compose push gpioc-debug 

WARN[0000] The "DOCKER_LOGIN" variable is not set. Defaulting to a blank string. 
WARN[0000] /home/vishal/Toradex_Peripheral_Test/gpioC/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion 
[+] Pushing 17/17
 ✔ Pushing localhost:5002/gpioc-debug:arm64: ca8564d2dc49 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 741b7819b2cb Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: cb173e3ee503 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 3dd5ff32f84e Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: b937ad84fd14 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: a2e660bade7b Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: b83567f86ab3 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 011c6a76c6f1 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 9a2f818ab1d2 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 1534a4ee32df Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 6c6a5ec41a1a Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: da5e0894d918 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 1fbc9c24ec18 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 451a08d8b887 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 2bc4ea22b6d4 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 08ee52a25812 Layer already exists                                                                                      0.0s 
 ✔ Pushing localhost:5002/gpioc-debug:arm64: 644fed2a3898 Layer already exists                                                                                      0.0s 
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: sshpass -p raj54321 ssh -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no torizon@192.168.209.40 LOCAL_REGISTRY=192.168.66.128 TAG=arm64 docker compose pull gpioc-debug 

Warning: Permanently added '192.168.209.40' (ED25519) to the list of known hosts.
time="2025-08-12T04:50:44Z" level=warning msg="The \"DOCKER_LOGIN\" variable is not set. Defaulting to a blank string."
time="2025-08-12T04:50:44Z" level=warning msg="/var/rootdirs/home/torizon/docker-compose.yml: `version` is obsolete"
 gpioc-debug Pulling 
 gpioc-debug Warning 
WARNING: Some service image(s) must be built from source by running:
    docker compose build gpioc-debug
1 error occurred:
        * Error response from daemon: Get "http://192.168.66.128:5002/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)



 *  The terminal process "sshpass '-p', 'raj54321', 'ssh', '-p', '22', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no', 'torizon@192.168.209.40', 'LOCAL_REGISTRY=192.168.66.128 TAG=arm64 docker compose pull gpioc-debug'" terminated with exit code: 18. 
 *  Terminal will be reused by tasks, press any key to close it. 

Could please help me out to solve this error to run simple GPIO example?

Thanks.

Hello @vishalborle92

@eric.tx is taking a well-deserved vacation and I’ve been asked to step in here. The way the IDE works is that your application is built as a container and stored in a docker registry running on your build system. This registry needs to be available from the device to be able to download the container images. If your device is unable to route to the laptop or you have a firewall blocking inbound connections, that will cause failures like this.

I’ve also seen some issues where a more complicated network setup on your build system would cause issues. More than 1 interface, for instance, or higher-end enterprise wifi protocols. Do you have anything like that?

From your Toradex module, can you ping the ip address of your build system? It seems that it is expected to be at 192.168.66.128.

Drew

Hello @drew.tx

I checked ping 192.168.66.128 and getting response as below:

More than 1 interface, for instance, or higher-end enterprise wifi protocols. Do you have anything like that? - More than 1 interface we connected only one carrier board.

Thanks,
Vishal

Hi Vishal,

Apologies for not being more clear. My question about enterprise wifi, multiple interfaces, etc was related to your desktop setup. We have seen many instances where IT setups would interfere with the connectivity between the IDE extension and the target hardware. In some cases users need to setup an isolated lab network without their IT additions to be able to get full functionality.

I can’t say with certainty that is your issue here but the net result is that your board is trying to contact the container registry running on your desktop and is failing. I know we are implementing some changes to remove the need for that container registry; I don’t believe that feature is available yet but I think it will help in this case.

First step though, can you switch to the prerelease version of the Torizon Marketplace extension? In the VSCode Extension Marketplace tab, if you search for “Torizon” and display the page for our extension, there should be a button to switch to prerelease. Screenshot attached.

Please let me know how the prelease goes and any more details about your IT environment that may be relevant.

Thanks,
Drew

Hi Vishal,

I just heard back from the devs that the new feature I mentioned is actually in the prerelease version, so it may well solve your connection issue. Please let me know how it goes.

Drew

Hello @drew.tx,

Sorry for delay response here was holidays last 3 days, Now today i tried as you suggested:
First Switched IDE extension to pre-released version but still same problem not able to connect:

I connected device and host windows using my mobile hotspot to avoid unnecessary some port blocked.

Can you please help for how i checked if my IT blocked 5002 port?

Thanks,
Vishal.

Hi Vishal,

I am checking with the dev team to confirm if this feature is actually working in the prerelease.

In the meantime, I’m not sure using mobile hotspot will help. Sometimes those setups block clients from talking to each other. As for checking if IT has blocked anything, you would have to check with them. The only thing we can confirm is that the system is not responding on that port but there is no way for us to tell why.

Hi @vishalborle92 and @drew.tx

I went thru this the other day a few times. Not exactly sure when/why mine started working, but my steps did include closing the project file, shutting down VSC, then starting back up again. Not sure if the linkage between WSL and the host OS was getting confused or something?

You also must be patient when opening to allow all of the tasks to run. If you jump in and try to do things before the startup tasks complete, you might get mixed results.

It was also nice to try and query the local docker registry from another host on the local intranet (http://192.168.209.40/v2/_catalog) to make sure your image is in there and accessible.

I also went away from debug mode for a bit and just tried to compose from the tcb command line and push (eliminating the ssh variable from the equation). Not sure if this helped me, but sure gained more knowledge about the build/deploy process :wink:

Hi @DaveM

Thanks for the input. The point about letting all the tasks run is a good one. I regularly get too quick on my mouse finger only to have nothing happen.

@vishalborle92 did you create a new project after switching to the prerelease? There may be settings in the old project that are not updated to match. There is a try-update-template task in the “TASK RUNNER” that is supposed to migrate your code to the newer version of the template but for this test specifically, I would recommend creating an whole new project to make sure. And to make doubly sure, our devs suggested that you change the templates branch so that you will be using the current prerelease version of those as well. Details for that are here.

Give those steps a try and let me know how it goes.

Hello @drew.tx and @DaveM ,

Thanks a lot for your suggestion after created new project then it started working and able to set breakpoint and successfully debug my hello example. I am trying to run simple UART example using IVY Carrier board and iMX8MP SOM but able to send and received simple data.

The below simple example i written in c program:

// File: main.c
//
// This program demonstrates basic UART communication on a Toradex i.MX8M Plus module
// running Torizon OS. It opens a specified serial port, configures it using termios,
// sends a message, and attempts to read a response.
//
// To compile and run this application within a Docker container managed by the
// Torizon IDE Extension in VS Code, ensure your project's Dockerfile and
// docker-compose.yml are correctly configured as described below.

#include <stdio.h>    // Standard input/output definitions
#include <string.h>   // String function definitions
#include <unistd.h>   // UNIX standard function definitions (for read, write, close)
#include <fcntl.h>    // File control definitions (for open)
#include <errno.h>    // Error number definitions
#include <termios.h>  // POSIX terminal control definitions (for termios API)

// Define the path to the UART device.
// For Toradex Verdin modules, /dev/verdin-uart1 is a common general-purpose UART.
// You can verify available UARTs on your module by running 'ls -l /dev/verdin-uart*'
// in the module's terminal.
#define UART_DEVICE "/dev/verdin-uart1"

int main() {
    int uart_fd; // File descriptor for the UART device
    struct termios tty; // Structure to hold the terminal attributes

    printf("UART Example Started.\n");
    // ------------------- 1. OPEN THE UART DEVICE -------------------
    // O_RDWR   : Open for reading and writing
    // O_NOCTTY : This port is not a controlling terminal for the process
    // O_NDELAY : Non-blocking open. If the port is not ready, open() returns an error.
    //            This flag can be removed if you want a blocking open.
    uart_fd = open(UART_DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
    if (uart_fd < 0) {
        perror("Error opening UART device");
        return -1;
    }

    printf("UART device %s opened successfully.\n", UART_DEVICE);

    // ------------------- 2. CONFIGURE THE UART -------------------
    // Get the current attributes of the terminal
    if (tcgetattr(uart_fd, &tty)!= 0) {
        perror("Error from tcgetattr");
        close(uart_fd);
        return -1;
    }

    // Clear all flags and set to default values (important for clean configuration)
    memset(&tty, 0, sizeof(tty));

    // Control Modes (c_cflag):
    // CREAD      : Enable the receiver (essential for receiving data)
    // CLOCAL     : Ignore modem control lines (e.g., DCD, DTR) - crucial for direct serial comms
    tty.c_cflag |= CREAD | CLOCAL;

    // Set the baud rate for both input and output. B115200 is 115200 bits per second.
    cfsetispeed(&tty, B115200);
    cfsetospeed(&tty, B115200);

    // Set the character size to 8 bits.
    // Use `CS8` for 8-bit characters. Other options: CS5, CS6, CS7.
    tty.c_cflag &= ~CSIZE; // Clear current size bits
    tty.c_cflag |= CS8;    // Set 8 data bits

    // Disable parity (odd/even)
    tty.c_cflag &= ~PARENB;  // Disable parity generation and checking
    tty.c_cflag &= ~PARODD;  // Ensure odd parity is also disabled if PARENB was set

    // Disable hardware flow control (RTS/CTS)
    tty.c_cflag &= ~CRTSCTS;

    // Set 1 stop bit. CSTOPB sets two stop bits; clearing it sets one.
    tty.c_cflag &= ~CSTOPB;

    // Local Modes (c_lflag):
    // Raw mode: Disable canonical processing (ICANON), input echoing (ECHO, ECHOE),
    // and signal generation (ISIG). This is typically desired for machine-to-machine
    // communication to prevent the kernel from interpreting special characters.
    tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // Input Modes (c_iflag):
    // No software flow control (IXON/IXOFF)
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    // Disable any special handling of newline characters or break conditions
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);

    // Output Modes (c_oflag):
    // No output processing (OPOST) - ensures raw data is sent without modification
    tty.c_oflag &= ~OPOST;

    // Set the timeouts for read() operations:
    // VMIN = 0, VTIME = 5: A read() will return after 500ms (5 * 0.1s) if no data
    // is available, or as soon as at least one character is received.
    tty.c_cc[VMIN]  = 0;   // Minimum number of characters for non-canonical read
    tty.c_cc[VTIME] = 5;   // Timeout in 0.1s increments (5 = 0.5 seconds)

    // Apply the settings immediately (TCSANOW)
    if (tcsetattr(uart_fd, TCSANOW, &tty)!= 0) {
        perror("Error from tcsetattr");
        close(uart_fd);
        return -1;
    }

    printf("UART configured successfully: 115200, 8N1, No Flow Control.\n");

    // ------------------- 3. SEND DATA -------------------
    char tx_buffer[] = "Hello from Toradex i.MX8M Plus UART!\n";
    int tx_bytes = strlen(tx_buffer);

    printf("Sending %d bytes: '%s'\n", tx_bytes, tx_buffer);
    if (write(uart_fd, tx_buffer, tx_bytes) < 0) {
        perror("Error writing to UART");
    }

    // tcdrain() waits until all output written to the object referred to by fd has been transmitted.
    // This is important to ensure data is physically sent before proceeding, especially before reading.
    if (tcdrain(uart_fd)!= 0) {
        perror("Error from tcdrain");
    }

    // Small delay to allow external device to process and respond
    usleep(100000); // 100ms delay

    // ------------------- 4. RECEIVE DATA -------------------
    char rx_buffer[256]; // Corrected: Declared as an array to hold received data
    int rx_bytes = 0;

    printf("Waiting for response...\n");
    rx_bytes = read(uart_fd, rx_buffer, sizeof(rx_buffer) - 1); // Read up to buffer size - 1 for null terminator

    if (rx_bytes < 0) {
        perror("Error reading from UART");
    } else if (rx_bytes == 0) {
        printf("No data received within timeout.\n");
    } else {
        // Null-terminate the received data to treat it as a C string
        rx_buffer[rx_bytes] = '\0';
        printf("Received %d bytes: '%s'\n", rx_bytes, rx_buffer);
    }

    // ------------------- 5. CLOSE THE UART DEVICE -------------------
    close(uart_fd);
    printf("UART device closed.\n");

    return 0;
}

And when I run this example I saw not getting any ERROR for opening the UART port and saw below message on debug console:

=thread-group-added,id="i1"
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
Warning: Debuggee TargetArchitecture not detected, assuming x86_64.
=cmd-param-changed,param="pagination",value="off"
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at src/main.c:28
Loaded '/lib/ld-linux-aarch64.so.1'. Symbols loaded.
Loaded '/lib/aarch64-linux-gnu/libc.so.6'. Symbols loaded.
UART Example Started.
[Inferior 1 (process 40) exited with code 0377]
The program '/home/torizon/app/UARTTest' has exited with code 377 (0x00000179).

Just to check I added simple log using printf(“UART Example Started.\n”);

could you please help me out to run simple UART example? Is there any configuration that required to access UART port? As i know I already added devices in “docker-compose.yml” as like be

)

I really appreciate your help to run out my simple example? Can you please also share me where to connect USB to TTL converter PIN mapping for IVY Carrier board?

Thanks Again..!!
Vishal

Hi Vishal,

Which UART are you expecting the output to appear on? Your code is accessing UART1 which is available on the J6 pin header. You can see the pin assignments on p13 table 8 of the Ivy datasheet.

As for your question on the USB adapter, which UART is this for? If it’s for the Linux console, that is on UART 3 and is available with a 1.8v adapter on J17 or a 3.3v adapter on J1.

Hello @drew.tx ,

First I tried to run UART1 using J6 connector but it not work getting garbage value, so then I tested my code on UART1 and it working

We want to work on UART1 and the datasheet said RS232_TX and RS232_RX, Can you please let me know what the voltage level for RS232? I checked using DMM and shows 5V?

But on debug console not able to see printf messages:

=thread-group-added,id="i1"
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
Warning: Debuggee TargetArchitecture not detected, assuming x86_64.
=cmd-param-changed,param="pagination",value="off"
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at src/main.c:81
Loaded '/lib/ld-linux-aarch64.so.1'. Symbols loaded.
Loaded '/lib/aarch64-linux-gnu/libc.so.6'. Symbols loaded.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000007fa4b399e4 in read () from /lib/aarch64-linux-gnu/libc.so.6

But in code I used printf for logging message to see where the code running.

Thanks,
Vishal

Hi @vishalborle92

I’m not following completely but I think what you are asking is why when you write data to UART1 it only shows on the actual serial port and not inside the GDB window correct? In that case writing directly to the hardware bypasses the mechanism GDB uses to redirect the output to the GDB console. Using printf should allow the output in the console. If you need it in both places, it’s probably easiest just to call both printf and the UART write function.

Regarding the RS232 voltages, they have already been run through an RS232 level shifter and the output spec is 13.2V. Note these are not FTDI level but straight-up RS232.

Drew