Accessing GPIO from Qt5

Qt5 is has many useful classes for handling the filesystem, but I didn’t find anything for handling the GPIOs in an embedded system. You need to handle the GPIO configuration by opening a standard file descriptor and reading/writing from/to with the standard QFile methods.

This is just a snippet that shows briefly how to change the direction of a GPIO. In my case I have for buttons that must be configured as inputs:

#define GPIO_INPUT_UP 83
#define GPIO_INPUT_DOWN 84
#define GPIO_INPUT_LEFT 6
#define GPIO_INPUT_RIGHT 1

static bool setup_gpio_input()
{
    QString     gpio_file,
                gpio_num;
    QFile       exportFile,
                directionFile;
    QByteArray  ba; 

    for (int i = 0; i < 4; i++) {
        if (i == 0)
            gpio_num.setNum(GPIO_INPUT_UP);
        else if (i == 1)
            gpio_num.setNum(GPIO_INPUT_DOWN);
        else if (i == 2)
            gpio_num.setNum(GPIO_INPUT_LEFT);
        else if (i == 3)
            gpio_num.setNum(GPIO_INPUT_RIGHT);

        // Export GPIO
        gpio_file = "/sys/class/gpio/export";
        exportFile.setFileName(gpio_file);
        exportFile.open(QIODevice::WriteOnly);
        ba = gpio_num.toLatin1();
        exportFile.write(ba); 
        exportFile.close();

        // Set GPIO direction
        gpio_file = "/sys/class/gpio/gpio" + gpio_num + "/direction";
        directionFile.setFileName(gpio_file);
        directionFile.open(QIODevice::WriteOnly);
        directionFile.write("in");
        directionFile.close(); 
    }   

    return true;
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    if (!setup_gpio_input())
        qDebug() << "Fail to set GPIOs input";
}

Skipping incompatible /lib/libpthread.so.0 when searching for /lib/libpthread.so.0

This normally happens when compiling for an arch, say ARM, and try to execute the binary in an x86_64 arch.
But in this case, it was not this problem, I was sure that I was compiling and executing for the right places for the right archs.

The error was the following:

/opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.3/../../../../arm-linux-gnueabihf/bin/ld: skipping incompatible /lib/libpthread.so.0 when searching for /lib/libpthread.so.0
/opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.3/../../../../arm-linux-gnueabihf/bin/ld: cannot find /lib/libpthread.so.0

Then I discovered that the same issue appears with libc.so.6.
For some reason this happened after a Fedora upgrade, something got missing during the upgrade.

In order to fix it, change to the directory where your sysroot resides, in my case is /opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/sysroot

Edit the file usr/lib/libpthread.so.
Change the GROUP line that is where the linker searches for libpthread:

/*GROUP ( /lib/libpthread.so.0 /usr/lib/libpthread_nonshared.a )*/
GROUP ( libpthread.so.0 libpthread_nonshared.a )

Edit also the file usr/lib/libc.so:

/*GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux-armhf.so.3 ) )*/
GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-armhf.so.3 ) )

After this, I was able again to execute the binaries as before.

Adding a splashscreen in U-Boot in an Atmel based custom board

Normally, when you start an embedded Linux project you have an evaluation kit that comes with an LCD with a splashscreen in U-Boot. Then, when you have your custom board based on that evaluation board and if you’re lucky enough to use an LCD with the same characteristics, changing the splashscreen is an easy task. But if the LCD is quite different, you have to make some changes that are not difficult, but can take some time if you don’t know where to search.

Recently, I had to do just that with an Atmel SAMA5D3 board that was derived from the SAMA5D3 evaluation kit, but instead of mounting the default 800×400 LCD it mounts a 480×272 LCD with different characteristics such as clock frequency, horizontal/vertical syncs, and so on.

The default U-Boot configuration from Atmel (U-Boot 2015.01) does not support a splashscreen, only a raw image (logo) embedded in the code, so the first step is remove the support for the logo, enable the Atmel HLCD driver, enable the splashscreen and enable the bmp command that is needed to display the .bmp image.

These changes take place in the board header file that contains its configuration, in my case, it was the include/configs/sama5d3xek.h file.
This is a code snippet with the changes:

/* LCD */
#define CONFIG_LCD

/* Do not use LCD_COLOR32 or you'll get a BUG() and a bricked board */
#define LCD_BPP                     LCD_COLOR16

/* My board is an 24bit RGB */
#define LCD_OUTPUT_BPP              24

/* Comment these lines that enable the raw image logo */
/*#define CONFIG_LCD_LOGO*/
/*#define CONFIG_LCD_INFO*/
/*#define CONFIG_LCD_INFO_BELOW_LOGO*/
/*#define CONFIG_SYS_WHITE_ON_BLACK*/

/* Enable Atmel HLCD driver */
#define CONFIG_ATMEL_HLCD

/* For an Atmel based board is quite safe to use it, even though the LCD is a 24bit RGB */
#define CONFIG_ATMEL_LCD_RGB565
#define CONFIG_SYS_CONSOLE_IS_IN_ENV

/* Enable splashscreen */
#define CONFIG_SPLASH_SCREEN

/* Enable the bmp command */
#define CONFIG_CMD_BMP

/* Enable support for 16bit BMP */
#define CONFIG_BMP_16BPP

Some of these parameters could change for your LCD, such as LCD_OUTPUT_BPP. Adjust them according to the LCD datasheet.

Now you’ll probably have to change a couple of things: how the LCD is initialized by your board and how it is physically connected. In my case this is in board/atmel/sama5d3xek/sama5d3xek.c.

Set the parameters used to initialize the LCD. You may need to check its datasheet.

vidinfo_t panel_info = {
    .vl_col = 480,
    .vl_row = 272,
    .vl_clk = 9000000,
    .vl_bpix = LCD_BPP,
    .vl_bpox = LCD_OUTPUT_BPP,
    .vl_tft = 1,
    .vl_hsync_len = 45,
    .vl_left_margin = 10,
    .vl_right_margin = 10,
    .vl_vsync_len = 8,
    .vl_upper_margin = 10,
    .vl_lower_margin = 10,
    .mmio = ATMEL_BASE_LCDC,
};

Now check how the LCD is connected to the board. Mine has the higher 8 bit connected to peripheral A, while the evaluation kit’s higher 8 bit are connected to the peripheral C. You may need your board schematics to check to which peripheral is connected and change it accordingly:

at91_set_a_periph(AT91_PIO_PORTA, 16, 0);   /* LCDD16 */
at91_set_a_periph(AT91_PIO_PORTA, 17, 0);   /* LCDD17 */
at91_set_a_periph(AT91_PIO_PORTA, 18, 0);   /* LCDD18 */
at91_set_a_periph(AT91_PIO_PORTA, 19, 0);   /* LCDD19 */
at91_set_a_periph(AT91_PIO_PORTA, 20, 0);   /* LCDD20 */
at91_set_a_periph(AT91_PIO_PORTA, 21, 0);   /* LCDD21 */
at91_set_a_periph(AT91_PIO_PORTA, 22, 0);   /* LCDD22 */
at91_set_a_periph(AT91_PIO_PORTA, 23, 0);   /* LCDD23 */

At this point you should be able to have a nice boot splashscreen that you can change from userspace if you write to the right address.
A new post will describe how to do this.

References:
Official splashscreen U-Boot page.