Qt on iMX6ULL Part 1: Hello, LED On/Off
Charles Dias, M.Sc.
Embedded Software Engineer | M.Sc in Electrical Engineering | C, Modern C++ | IoT | RTOS | Embedded Linux | Yocto Project
In the previous article, Qt on i.MX6ULL Part 0: Installation and Initial Setup, we covered the process of setting up a development environment. In this new one, we will learn how to identify available pins on the i.MX6ULL, locate them on the Aster board, and understand how to control a GPIO pin from the Linux user space using the libgpiod. Additionally, we will create a Qt Widget program that allows you to turn a relay module connected to a GPIO pin on and off.
Visit the project's GitHub repository, and feel free to leave suggestions.
Legend
Throughout this text, console commands starting with a "$"?signify a command prompt on your PC. Commands beginning with a "#"?signify a prompt on the embedded system. For example:
This is a command on Linux PC.
$ cd device-tree
This is a command on Linux embedded.
# ifconfig
Hardware requirements
The hardware configuration for this tutorial will consist of the following components:
Electronic circuit and GPIO on iMX6ULL
You have two options for this tutorial: use the onboard LED or the relay module. I'll demonstrate how to control both using libgpiod via the command line. However, we will be using the relay module for the Qt application.
Onboard LED
According to Aster V1.1B Schematics document, there is an LED4 GREEN connected to the SODIMM_104 pin, as shown in the image below. Note that the other LEDs are not assembled on the board.
In the Colibri iMX6ULL Datasheet document, on page 28, we can see that the pin supports multiple functions, including the GPIO function. The ALT5 function is the default configuration after reset, i.e., the gpio2.IO[7] function is selected.
Now, let's move on to the relay module connection.
Connecting the relay module
Firstly, it's crucial to note that our relay module is designed to operate with a 5V supply and control signal. Luckily, the Aster board has the FXMA108 chip, a dual voltage power converter configurable for bidirectional voltage translation between two logic levels.
To properly use the 5V supply on the Arduino connector and provide the appropriate power to our relay module, we must adjust the J2 and J3 jumpers, positioning them on pins 2-3. Moreover, we need to connect the VCC, GND, and IN signals to the Aster board.
We will control the relay module using the pin SODIMM_55. Consequently, the IN pin of the relay module needs to be connected to pin 8 of connector X17, named UNO_GPIO6, as illustrated below.
Look at the Colibri iMX6ULL Datasheet document on page 25 and check that the ALT5 function is the default configuration for the SODIMM_55 pin after reset.
Ensure you changed the J2 and J3 jumpers, and connect the wires according to the image.
It's time to run some tests using the libgpiod library.
Utilizing the Libgpiod library via the command line
Libgpiod is a C library and a set of tools for interacting with the Linux GPIO (General Purpose Input/Output) subsystem. It provides a simplified interface for programming GPIOs on Linux platforms and can be used from the user space.
Before libgpiod, the primary way to interact with GPIOs in Linux was through the sysfs interface, which exposed GPIOs to user space as files in the /sys filesystem. While this sysfs interface is still supported by Toradex BSPs, its use is no longer recommended. To learn more about libgpiod, you can visit libgpiod and GPIO (Linux) by Toradex.
The libgpiod library offers various command-line functionalities. We'll begin by using the gpioinfo command to check information about the GPIOs. The partial expected output is shown below.
# gpioinfo
gpiochip0 - 32 lines:
line 0: "SODIMM_8" unused input active-high
line 1: "SODIMM_6" unused input active-high
line 2: "SODIMM_129" "regulator-usbh-vbus" output active-low [used]
.
.
.
line 30: unnamed "scl" output active-high [used open-drain]
line 31: unnamed "sda" input active-high [used open-drain]
gpiochip1 - 32 lines:
line 0: "SODIMM_55" unused input active-high
line 1: "SODIMM_63" unused input active-high
line 2: "SODIMM_178" unused input active-high
.
.
.
line 30: unnamed unused input active-high
line 31: unnamed unused input active-high
gpiochip2 - 32 lines:
line 0: "SODIMM_56" unused input active-high
line 1: "SODIMM_44" unused input active-high
line 2: "SODIMM_68" unused input active-high
.
.
.
line 30: unnamed unused input active-high
line 31: unnamed unused input active-high
gpiochip3 - 32 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
.
.
. line 30: unnamed unused input active-high
line 31: unnamed unused input active-high
gpiochip4 - 32 lines:
line 0: "SODIMM_43" "cd" input active-low [used]
line 1: "SODIMM_45" unused input active-high
line 2: "SODIMM_137" unused input active-high
.
.
. line 30: unnamed unused input active-high
line 31: unnamed unused input active-high
This command reveals five GPIO banks, gpiochip0 to gpiochip4, with 32 GPIO lines each. However, some lines are marked as unnamed, indicating that these lines are unavailable for use on the SODIMM connector.
You can refine your gpioinfo query by combining it with the grep command. This approach filters the console output to show only the GPIO pins available on the SODIMM connector.
# gpioinfo | grep -e "SODIMM"
As discussed earlier, our interest lies in controlling the SODIMM_104 and SODIMM_55 pins, respectively, the onboard LED4 GREEN and the IN signal from the relay module. We must confirm that these pins are available and not currently used by any other peripheral. This information can be obtained by observing whether both pins are marked as unused in the gpioinfo console output.
# gpioinfo | grep -e "SODIMM_104" -e "SODIMM_55
line 0: "SODIMM_55" unused input active-high
line 7: "SODIMM_104" unused input active-high "
Next, we need to know which GPIO bank and line the pins belongs to. You can identify this using the command gpiofind which will display the GPIO bank and line for each pin you select.
# gpiofind SODIMM_10
gpiochip1 7
# gpiofind SODIMM_55
gpiochip1 04
It's important to note that LED4 GREEN (SODIMM_104) is located on gpiochip1 line 7, and the IN signal (SODIMM_55) is on gpiochip1 line 0.
To verify that we can control these GPIO pins and that we've selected the right ones, libgpiod provides the gpioset command line. This allows us to set the logic level of a GPIO to high or low.
Applying high level to LED4 GREEN (SODIMM_104) and notice that the LED4 GREEN will be activated.
# gpioset 1 7=1
To turn it off, apply the low level.
# gpioset 1 7=0
Run the command gpioinfo | grep -e "SODIMM_104" -e "SODIMM_55" again. Did you notice any difference?
Repeat the gpioset commands using the GPIO bank and line related to SODIMM_55. Depending on your relay module, it could be active-high or active-low. In my case, the relay module is active-low. Thus, the module is activated when we send the command gpioset 1 0=0 and deactivated by gpioset 1 0=1 command.
Libgpiod offers many other command-line, such as gpiodetect, gpioget, and gpiomon. Access the links libgpiod and GPIO (Linux) by Toradex to see more.
Now, it's time to proceed with the Qt project.
Qt Widget project
Let's create a Qt Widget project to allow us to control the relay module or the onboard LED4 GREEN. It's up to you!
Open the Qt Creator program and select Create Project. On the New Project -- Qt Creator screen, choose the Qt widgets Application option and click Choose...
领英推荐
Provide a name for your project and select the location where it will be created on your machine. I used the Part1-HelloLed as my project name.
Next, select qmake as the build system.
Maintain the default settings in the Details screen and also in the Translation section. This latter screen is not shown here.
Select the iMX6ULL kit created in the previous article Qt on i.MX6ULL Part 0: Installation and Initial Setup.
In the Summary section, keep Git as the version control system.
Finally, click Finish. A window similar to the image below should appear.
Create the GUI
On the left, navigate to the Forms folder and double-clink on mainwindow.ui file to open it. The Design create screen should now be visible.
Let's look at some common areas in Qt Creator to help our communication in this and future articles.
We'll begin by adjusting the geometry size of the MainWindow object. Select it in the Property Editor and change the Width to 800 and the Height to 480, which are the dimensions of our display.
In the Widget Box, find the Buttons section and drag a Push Button into the MainWindow. Double-click on this Push Button and change the text to OK. In the Object Inspector, double-click the Push Button object and rename it btnOn. Add another Push Button and change its text to OFF in the Property Editor and name in the Object Inspector to btnOff.
You can explore the Property Editor to adjust button and text sizes. Try creating a GUI similar to mine or even fancier - I'm not a UI/UX designer! ;-)
On the Icon Bar, click the Hammer icon to build the project and then the Green Arrow icon to deploy and run the project on our target device. Ensure the device's IP address matches the one used in previous articles.
Attention: Do not click on the Green Arrow + Bug icon. We'll learn how to use Debug mode in the next article.
After a few seconds, our attractive GUI should appear on the display. Hopefully, you achieved the same result.
What happened when you pressed the buttons on the screen? Did it work?
When you press a button, you should see an effect or animation that indicates the button has been pressed. This confirms that our system responds to the button press. However, the relay module does not change. What's going on?
Signals and Slots
When a button is pressed, we need it to perform an action. This is the role of signals and slots - facilitating communication between objects. To learn more, visit Signals and Slots.
Let's add the signal and slot mechanism to the ON and OFF buttons. Right-click the ON button, and select Go to slot... Then, on the Go to slot - Qt Creator screen, select the signal clicked(). A new empty method, void MainWindow::on_btnOn_clicked(), is added to the mainWindows.cpp file.
Double-click on mainwindows.ui to return to the Design creator screen. Add a signal and slot also to the OFF button as well. An empty method void MainWindow::on_btnOff_clicked() will be created this time.
Open the mainwindows.h file and add the gpiod.h header, the private method getGpioLine, and the private data member m_outputLine. The getGpioLine is used to get the data structure related to the GPIO line, and m_outputLin stores this information for use throughout the program execution.
Next, open the mainwindows.cpp file and implement the function MainWindow::getGpioLine. Modify the MainWindow::MainWindow method to initialize the m_outputLine data member and configure the GPIO line as output. Finally, implement the actions inside the MainWindow::on_btnOn_clicked and MainWindow::on_btnOff_clicked methods. Refer to the image below.
On the Icon Bar, press the Hammer icon to build the project. If you've followed all the steps so far, you may encounter some issues at this point. Look at the lower area of the Qt Creator screen to see numerous red exclamations.
The Qt compiler flags us because the functions related to libgpiod are undefined. This happens because the link phase failed to link with the libgpiod library. To fix this, open the Part1-HelloLed.pro file and add the LIBS += -lgpiod instruction. This informs Qt to include the library during the build process. Build the project again, and everything should compile without errors.
Press the Green Arrow icon on the Icon Bar to run the project. Once the GUI appears on the display, press the ON button, and voilà! The relay module will be activated. Press the OFF button to deactivate it.
Visit the project's GitHub repository to find the final project.
Conclusion
Wait, have you noticed the toolbar at the top of the display?
That might not be something you want in a final Qt application.
In the next article, we'll discuss how to hide the toolbar and set up the environment to run the application in debug.
See you there!