GPIO в модуле ядра Linux на Raspberry Pi

В данном модуле речь пойдет о том, как моргать светодиодом из модуля ядра Linux. Для своих экспериментов я использую Raspberry Pi B+, но тоже можно повторить на любой другой платформе.
Я предполагаю, что вы уже умеете передавать параметры в модуль ядра через командную строку, если нет воспользуйтесь статьями из раздела Ядро Linux. Также нам понадобятся таймеры.
Моргать будем постоянно с заданным периодом таймера.

Для работы с GPIO в модуле ядра Linux необходимо подключить файл linux/gpio.h
Так выглядят заголовки и основные переменные.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/gpio.h>

#include "blablamod.h"

static struct timer_list my_timer;
static int gpio_pin = 21;
static int gpio_value = 1;
static int timer_period = 1000;
module_param(gpio_pin, int, 0755);
module_param(timer_period, int, 0755);

static struct gpio led;

Обработчик переполнения таймера:

static void my_timer_callback(unsigned long data)
{
    printk(KERN_NOTICE "timer_callback called (%ld): %lu.\n", jiffies, data);
    gpio_value = (gpio_value) ? 0 : 1;
    gpio_set_value(gpio_pin, gpio_value);
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(timer_period));
}

Прежде чем использовать GPIO нужно его настроить. Это мы сделаем в функции инициализации модуля.

static int __init blablamod_init( void ) {
    int ret;
    printk(KERN_NOTICE "Blablatogle module loaded!\n" );
    led.gpio = gpio_pin;
    led.flags = GPIOF_OUT_INIT_LOW;
    led.label = "LED";
    if (!gpio_is_valid(gpio_pin))
    {
        printk(KERN_ALERT " GPIO number %d not valid.\n", gpio_pin);
        return 1;
    }
    ret = gpio_request(gpio_pin,"LED");
    if (ret)
    {
        printk(KERN_ALERT "Gpio request failed.\n");
        return -2;
    }
    //value 0
    gpio_direction_output(gpio_pin, 0);
    gpio_set_value(gpio_pin, gpio_value);
    setup_timer( &my_timer, my_timer_callback, 10 );
    ret = mod_timer(&my_timer, jiffies + msecs_to_jiffies(timer_period));
    if (ret)
        printk(KERN_ALERT "Error in mod_timer\n");
    return 0;
}

Для работы с Gpio нам предлагают структуру gpio. Она содержит номер ножки, тип (вход, выход) и символьное имя.
Для проверки номера ножки на валидность можно воспользоваться функцией gpio_is_valid, которая вернет true если такая ножка существует.
После проверки нужно запросить у системы выбранную ножку при помощи функции gpio_request. Затем установить ножку на выход при помощи gpio_direction_output, указав также состояние по умолчанию (0 или 1).
Теперь можно изменять значение на выходе при помощи функции gpio_set_value, которая принимает в качестве аргументов номер ножки и необходимый уровень.
Далее заводится таймер. Подробности описывать не буду.

Как вы уже наверное поняли, после окончания работы ножку нужно вернуть системе. Иначе повторно захватить её уже не удастся до перезагрузки.

static void __exit blablamod_exit( void ) {
    int ret;
    printk(KERN_NOTICE "Blablatogle module unloaded!\n" );

    gpio_free(led.gpio);
    ret = del_timer( &my_timer );
    if (ret)
        printk(KERN_ALERT "The timer is still in use...\n");
}

Тут мы отдаем ножку системе и удаляем таймер.
При периоде в 100мс выглядит вот так:

Период можно менять регулируя параметр при загрузке модуля или же через sysfs.

Код можно найти на GitHub.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий