Перейти к содержанию
    

Драйвера в Linux для периферии Microblaze

Доброго времени суток!

В данный момент времени приходится разбираться с программированием драйверов для периферии Microblaze (до этого имел небольшой опыт в программировании драйверов для ARM9 семейства AT91).

Суть данной темы (как мне кажется :rolleyes: ) на этом форуме в том, чтобы любой желающий кому нужна и/или интересна подобная тематика (примеры, общие вопросы и рекомендации программирования драйверов с учетом аппаратных особенностей IP-COREs Microblaze) смог задать вопрос, найти готовый рабочий кусок кода и т.д. К сожалению просидев неделю в гугле, ничего подобного и полезного в таком же духе не нашел :(

 

Как водится, начал я с мигания светодиодом. Вот пример кода драйвера который засвечивает третий светодиод в линейке:

 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>

static int __init kruger_driver_init(void)
{
  struct device_node *root_dn;
  struct device_node *kruger_gpio;
  struct gpio_chip *kruger_gc;
  int ret;

  printk(KERN_ALERT "Kruger driver init...\n");
  root_dn = of_find_node_by_path("/");
  kruger_gpio = of_find_node_by_name(root_dn, "ledss");
  if (!kruger_gpio)
  {
    printk(KERN_ALERT "LEDs not found in DTF\n");
    return -ENODEV;
  }
  printk(KERN_ALERT "LEDs find\n");
  kruger_gc = of_node_to_gpiochip(kruger_gpio);
  printk(KERN_ALERT "%s: gpio controller %s \n", root_dn->full_name, kruger_gpio->full_name);
  if(!kruger_gc)
  {
    printk(KERN_ALERT "gc not register\n");
    ret = -ENODEV;
  }
  ret = kruger_gc->direction_output(kruger_gc, 2, 1);
  if (ret < 0)
  {
    printk(KERN_ALERT "LEDs output error\n");
    return -ENODEV;
  }
  kruger_gc->set(kruger_gc, 2, 1);
  return 0;    
}

static void __exit kruger_driver_exit(void)
{
  printk(KERN_ALERT "Kruger driver exit\n");
}

module_init(kruger_driver_init);
module_exit(kruger_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kruger");
MODULE_DESCRIPTION("Gpio example driver");

 

Кусок dts-файла, соответствующий светодиодной линейке:

 

LEDs_8Bit: ledss@81420000 {
            compatible = "xlnx,xps-gpio-2.00.a", "xlnx,xps-gpio-1.00.a";
            reg = < 0x81420000 0x10000 >;
            xlnx,all-inputs = <0x0>;
            xlnx,all-inputs-2 = <0x0>;
            xlnx,dout-default = <0x0>;
            xlnx,dout-default-2 = <0x0>;
            xlnx,family = "spartan3adsp";
            xlnx,gpio-width = <0x8>;
            xlnx,gpio2-width = <0x20>;
            xlnx,interrupt-present = <0x0>;
            xlnx,is-dual = <0x0>;
            xlnx,tri-default = <0xffffffff>;
            xlnx,tri-default-2 = <0xffffffff>;
        };

Для работы с gpio я использовал структуру gpio_chip.

Все подробности о ней можно узнать из комментариев в файле include/asm-generic/gpio.h

 

Очень многое я почерпнул из исходников самого ядра, в частности, из "фирмовых" драйверов Xilinx.

 

Так что, если есть желающие поделится примерами - прошу выкладывать ;)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток, продолжая тему о драйверах для IP-CORE Microblaze, столкнулся со следующей проблемой:

 

Решил написать драйвер который обрабатывает внешние прерывание по нажатию на кнопку. Драйвер в системе регистрируется нормально, но обработчик прерывания никак не реагирует.

Код драйвера:

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/irq.h>

static int irq;

static irqreturn_t test_irq_handler(int irq, void *dev_id)
{
  printk(KERN_ALERT "all ok!\n");
  return IRQ_HANDLED;
}

static int __init kruger_driver_init(void)
{
  struct device_node *root_dn;
  struct device_node *kruger_gpio;
  struct resource resource;
  int result;
  unsigned int start_addr;
  unsigned long  *virt_addr;

  printk(KERN_ALERT "Kruger driver init\n");
  root_dn = of_find_node_by_path("/");
  kruger_gpio = of_find_node_by_name(root_dn, "gpiob");
  if (!kruger_gpio)
  {
    printk(KERN_ALERT "GPIO buttons not found in DTF\n");
    return -ENODEV;
  }
  result = of_address_to_resource(kruger_gpio, 0, &resource);
  if (result < 0)
  {
    printk(KERN_ALERT "GPIO buttons: error address to resource");
    return -ENODEV;
  }
  printk(KERN_ALERT "GPIO buttons: reg. size=%d Bytes\n", (u32)resource.end-(u32)resource.start);
  start_addr = (unsigned int)resource.start;

  irq = of_irq_to_resource(kruger_gpio, 0, &resource);
  if (irq == NO_IRQ)
  {
    printk(KERN_ALERT "GPIO buttons: of_irq_to_resource() failed\n");
    of_node_put(kruger_gpio);
    return -ENODEV;
  }

  printk(KERN_ALERT "GPIO buttons: irq=%d\n", irq);
  virt_addr = of_iomap(kruger_gpio, 0);
  printk(KERN_ALERT "GPIO buttons: at 0x%08X mapped to 0x%08X\n", start_addr, (u32)virt_addr);
  result = request_irq(irq, &test_irq_handler, IRQF_TRIGGER_MASK, "Gpio Buttons", NULL);
  if (result < 0)
  {
      printk(KERN_ALERT "GPIO buttons: error to request IRQ%d : %d\n", irq, result);
      of_node_put(kruger_gpio);
      return -ENODEV;
  }
  printk(KERN_ALERT "GPIO buttons module inserted successfully\n");
  return 0;
}

static void __exit kruger_driver_exit(void)
{
  printk(KERN_ALERT "Kruger driver exit\n");
}

module_init(kruger_driver_init);
module_exit(kruger_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kruger");
MODULE_DESCRIPTION("Gpio example driver");

 

Часть DTF-файла отвечающая за кнопки:

Push_Buttons: gpiob@81400000 {
            compatible = "xlnx,xps-gpio-2.00.a", "xlnx,xps-gpio-1.00.a";
            interrupt-parent = <&xps_intc_0>;
            interrupts = < 1 2 >;
            reg = < 0x81400000 0x10000 >;
            xlnx,all-inputs = <0x1>;
            xlnx,all-inputs-2 = <0x0>;
            xlnx,dout-default = <0x0>;
            xlnx,dout-default-2 = <0x0>;
            xlnx,family = "spartan3adsp";
            xlnx,gpio-width = <0x4>;
            xlnx,gpio2-width = <0x20>;
            xlnx,interrupt-present = <0x1>;
            xlnx,is-dual = <0x0>;
            xlnx,tri-default = <0xffffffff>;
            xlnx,tri-default-2 = <0xffffffff>;
        };

 

Часть лога при инициализации драйвера:

 

[    7.635430] Kruger driver init
[    7.637493] GPIO buttons: reg. size=65535 Bytes
[    7.642095] GPIO buttons: irq=1
[    7.645278] GPIO buttons: at 0x81400000 mapped to 0xC80A0000
[    7.651114] GPIO buttons module inserted successfully

 

Вывод файла /proc/interrupt

CPU0       
  1:          0     level Xilinx INTC  Gpio Buttons
  2:     546096      edge Xilinx INTC  timer
  4:       1193      edge Xilinx INTC  uartlite

 

Кто-то пробовал "запускать" внешние прерывания по линухом? В чем может быть проблема?

 

ЗЫ: Задавал этот же вопрос на офф. сайте Xilinx в разделе Embedded Linux - молчат как партизаны :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну тогда нам ничего не остается, и мы будем молчать в тряпочку :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...