Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Zynq, Petalinux, прерывания и заголовочные файлы
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Balabes
Здравствуйте!
Хочу обработать прерывания от AXI Timer в линуксе. На сайте xilinx нарыл пример.
CODE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

#define DEVICE_NAME "xilaxitimer"

#define IRQ_NUM 91

#define XIL_AXI_TIMER_BASEADDR 0x41C00000
#define XIL_AXI_TIMER_HIGHADDR 0x41C0FFFF

#define XIL_AXI_TIMER_TCSR_OFFSET 0x0
#define XIL_AXI_TIMER_TLR_OFFSET 0x4
#define XIL_AXI_TIMER_TCR_OFFSET 0x8
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK 0x00000100

#define XIL_AXI_TIMER_CSR_CASC_MASK 0x00000800
#define XIL_AXI_TIMER_CSR_ENABLE_ALL_MASK 0x00000400
#define XIL_AXI_TIMER_CSR_ENABLE_PWM_MASK 0x00000200
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK 0x00000100
#define XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK 0x00000080
#define XIL_AXI_TIMER_CSR_ENABLE_INT_MASK 0x00000040
#define XIL_AXI_TIMER_CSR_LOAD_MASK 0x00000020
#define XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK 0x00000010
#define XIL_AXI_TIMER_CSR_EXT_CAPTURE_MASK 0x00000008
#define XIL_AXI_TIMER_CSR_EXT_GENERATE_MASK 0x00000004
#define XIL_AXI_TIMER_CSR_DOWN_COUNT_MASK 0x00000002
#define XIL_AXI_TIMER_CSR_CAPTURE_MODE_MASK 0x00000001

#define TIMER_CNT 0xF8000000

static struct platform_device *pdev;
void *dev_virtaddr;
static int int_cnt;

static irqreturn_t xilaxitimer_isr(int irq,void*dev_id)
{
unsigned int data;

/*
* Check Timer Counter Value
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCR_OFFSET);
printk("xilaxitimer_isr: Interrupt Occurred ! Timer Count = 0x%08X\n",data);

/*
* Clear Interrupt
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data | XIL_AXI_TIMER_CSR_INT_OCCURED_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

/*
* Disable Timer after 100 Interrupts
*/
int_cnt++;

if (int_cnt>=100)
{
printk("xilaxitimer_isr: 100 interrupts have been occurred. Disabling timer");
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data & ~(XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK),
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
}

return IRQ_HANDLED;
}

static int __init xilaxitimer_init(void)
{
unsigned int data;

int_cnt = 0;

printk(KERN_INFO "xilaxitimer_init: Initialize Module \"%s\"\n", DEVICE_NAME);

/*
* Register ISR
*/
if (request_irq(IRQ_NUM, xilaxitimer_isr, 0, DEVICE_NAME, NULL)) {
printk(KERN_ERR "xilaxitimer_init: Cannot register IRQ %d\n", IRQ_NUM);
return -EIO;
}
else {
printk(KERN_INFO "xilaxitimer_init: Registered IRQ %d\n", IRQ_NUM);
}

/*
* Map Physical address to Virtual address
*/
dev_virtaddr = ioremap_nocache(XIL_AXI_TIMER_BASEADDR,
XIL_AXI_TIMER_HIGHADDR - XIL_AXI_TIMER_BASEADDR + 1);

/*
* Set Timer Counter
*/
iowrite32(TIMER_CNT,
dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
printk("xilaxitimer_init: Set timer count 0x%08X\n",data);

/*
* Set Timer mode and enable interrupt
*/
iowrite32(XIL_AXI_TIMER_CSR_LOAD_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(XIL_AXI_TIMER_CSR_ENABLE_INT_MASK | XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

/*
* Register Device Module
*/
pdev = platform_device_register_simple(DEVICE_NAME, 0, NULL, 0);
if (pdev == NULL) {
printk(KERN_WARNING "xilaxitimer_init: Adding platform device \"%s\" failed\n", DEVICE_NAME);
kfree(pdev);
return -ENODEV;
}

/*
* Start Timer
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data | XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

return 0;
}

static void __exit xilaxitimer_edit(void)
{
/*
* Exit Device Module
*/
iounmap(dev_virtaddr);
free_irq(IRQ_NUM, NULL);
platform_device_unregister(pdev);
printk(KERN_INFO "xilaxitimer_edit: Exit Device Module \"%s\".\n", DEVICE_NAME);
}

module_init(xilaxitimer_init);
module_exit(xilaxitimer_edit);

MODULE_AUTHOR ("Xilinx");
MODULE_DESCRIPTION("Test Driver for Zynq PL AXI Timer.");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("custom:xilaxitimer");


собираю образ и файловую систему. загружается. все отлично. но в /usr/include/linux нет <linux/interrupt.h> и других. понимаю что нужно в конфиге ядра или файловой системе что-то сделать.
Кто опытен в линуксах на цинке подскажите как быть. т.к. опыта особого ни в цинке ни в линуксе не имею.
faa
Цитата(Balabes @ Apr 11 2018, 15:47) *
Здравствуйте!
Хочу обработать прерывания от AXI Timer в линуксе. На сайте xilinx нарыл пример.
Код
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

#define DEVICE_NAME "xilaxitimer"
......
module_init(xilaxitimer_init);
module_exit(xilaxitimer_edit);

MODULE_AUTHOR ("Xilinx");
MODULE_DESCRIPTION("Test Driver for Zynq PL AXI Timer.");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("custom:xilaxitimer");


собираю образ и файловую систему. загружается. все отлично. но в /usr/include/linux нет <linux/interrupt.h> и других. понимаю что нужно в конфиге ядра или файловой системе что-то сделать.
Кто опытен в линуксах на цинке подскажите как быть. т.к. опыта особого ни в цинке ни в линуксе не имею.


Копать документацию в сторону ядра, модулей, кросс-компиляции и т.д. - но, похоже, тут ликбез нужен. И, видимо, с 0.

ЗЫ: для длинных исходных текстов на этом форуме есть отдельный "codebox"
Balabes
За тег спасибо, на панельке его почему то нет.

Вы хотите сказать что в конфигураторе ядра который с петалинуксом идет, нельзя настроить эту функцию?
faa
Цитата(Balabes @ Apr 11 2018, 19:51) *
Вы хотите сказать что в конфигураторе ядра который с петалинуксом идет, нельзя настроить эту функцию?


Конфигуратор ядра идет с ядром.
А какое ядро в петалинухе и есть ли там этот драйвер - хз.
Мы не пользуемся петалинухом, поэтому что там и как - только в общих чертах.

А официальное ядро от Xilinx тут.
sheynmanyu
Balabes, Вы каким петалинуксом пользуетесь?
Кому-нибудь здесь удавалось настроить Petalinux (любой версии), чтобы он ядро и u-boot грузил с официального git из ветки master? Или он только умеет из соответствующей своей ветки грузить обновления? Подскажите, плиз?
Balabes
sheynmanyu использую последний петалинукс, долго искал указание на то из какой ветки исходники, вот лучшее что нашел
Код
[core]
    repositoryformatversion = 0
    filemode = true
    bare = true
[remote "origin"]
    url = https://github.com/Xilinx/linux-xlnx.git
    fetch = +refs/*:refs/*
    mirror = true


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

faa, если я все правильно понял, мне нужно добавить модуль в ядро, содержащий обработчик прерывания. А можно прерывания обрабатывать в коде из SDK? знаю что вопрос нубский, но да, я нуб(
sheynmanyu
Цитата(Balabes @ Apr 12 2018, 13:37) *
А можно прерывания обрабатывать в коде из SDK?

Скорее, подключить соответствующий драйвер (для работы с Вашим блоком). И работать через обращения к этому драйверу. Файлы с описаниями ядра линукса тут
Не могу найти ничего подходящего, что работало бы с axi-устройствами. Может, устройства amba (ttyAM#)?

А для общего понимания можно заглянуть в книжку Jonathan Corbet "Драйверы Устройств Linux" (например, здесь ), в самом начале.
...Я вот тоже сейчас с петалинуксом бодаюсь. Но у меня он даже запускаться не хочет sad.gif((
Balabes
Вы скорее всего встречали этот гайд, но вдруг нет. Файловую систему можно взять и ту что петалинукс сделает, но в убунте и gcc есть и даже apt ссыль
Balabes
Снова здравствуйте!
Модуль собрал, через insmod запускаю, таймер настраивается, тикает, судя по регистру состояния прерывание срабатывает (8 бит равен 1), но вот обработчик не вызывается. Есть у знающих идеи что я делаю не так?

CODE
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

#define DEVICE_NAME "xilaxitimer"

#define IRQ_NUM 61

#define XIL_AXI_TIMER_BASEADDR 0x42800000
#define XIL_AXI_TIMER_HIGHADDR 0x4280FFFF

#define XIL_AXI_TIMER_TCSR_OFFSET 0x0
#define XIL_AXI_TIMER_TLR_OFFSET 0x4
#define XIL_AXI_TIMER_TCR_OFFSET 0x8
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK 0x00000100

#define XIL_AXI_TIMER_CSR_CASC_MASK 0x00000800
#define XIL_AXI_TIMER_CSR_ENABLE_ALL_MASK 0x00000400
#define XIL_AXI_TIMER_CSR_ENABLE_PWM_MASK 0x00000200
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK 0x00000100
#define XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK 0x00000080
#define XIL_AXI_TIMER_CSR_ENABLE_INT_MASK 0x00000040
#define XIL_AXI_TIMER_CSR_LOAD_MASK 0x00000020
#define XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK 0x00000010
#define XIL_AXI_TIMER_CSR_EXT_CAPTURE_MASK 0x00000008
#define XIL_AXI_TIMER_CSR_EXT_GENERATE_MASK 0x00000004
#define XIL_AXI_TIMER_CSR_DOWN_COUNT_MASK 0x00000002
#define XIL_AXI_TIMER_CSR_CAPTURE_MODE_MASK 0x00000001

#define TIMER_CNT 0x0000FFFF

static struct platform_device *pdev;
void *dev_virtaddr;
static int int_cnt;

static irqreturn_t xilaxitimer_isr(int irq,void*dev_id)
{
unsigned int data;

/*
* Check Timer Counter Value
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCR_OFFSET);
printk("xilaxitimer_isr: Interrupt Occurred ! Timer Count = 0x%08X\n",data);

/*
* Clear Interrupt
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data | XIL_AXI_TIMER_CSR_INT_OCCURED_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

/*
* Disable Timer after 100 Interrupts
*/
int_cnt++;

if (int_cnt>=100)
{
printk("xilaxitimer_isr: 100 interrupts have been occurred. Disabling timer");
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data & ~(XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK),
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
}

return IRQ_HANDLED;
}

static int __init xilaxitimer_init(void)
{
unsigned int data;

int_cnt = 0;

printk(KERN_INFO "xilaxitimer_init: Initialize Module \"%s\"\n", DEVICE_NAME);

/*
* Register ISR
*/
if (request_irq(IRQ_NUM, xilaxitimer_isr, 0, DEVICE_NAME, NULL)) {
printk(KERN_ERR "xilaxitimer_init: Cannot register IRQ %d\n", IRQ_NUM);
return -EIO;
}
else {
printk(KERN_INFO "xilaxitimer_init: Registered IRQ %d\n", IRQ_NUM);
}

/*
* Map Physical address to Virtual address
*/
dev_virtaddr = ioremap_nocache(XIL_AXI_TIMER_BASEADDR,
XIL_AXI_TIMER_HIGHADDR - XIL_AXI_TIMER_BASEADDR + 1);

/*
* Set Timer Counter
*/
iowrite32(TIMER_CNT,
dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
printk("xilaxitimer_init: TLR 0x%08X\n",data);

/*
* Set Timer mode and enable interrupt
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data | XIL_AXI_TIMER_CSR_INT_OCCURED_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
printk("xilaxitimer_init: empty TCSR 0x%08X\n",data);


iowrite32(XIL_AXI_TIMER_CSR_LOAD_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

iowrite32(XIL_AXI_TIMER_CSR_ENABLE_INT_MASK | XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

iowrite32(XIL_AXI_TIMER_CSR_DOWN_COUNT_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
printk("xilaxitimer_init: full TCSR 0x%08X\n",data);


/*
* Register Device Module
*/
pdev = platform_device_register_simple(DEVICE_NAME, 0, NULL, 0);
if (pdev == NULL) {
printk(KERN_WARNING "xilaxitimer_init: Adding platform device \"%s\" failed\n", DEVICE_NAME);
kfree(pdev);
return -ENODEV;
}

/*
* Start Timer
*/
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
iowrite32(data | XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK,
dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
printk("xilaxitimer_init: TCSR 0x%08X\n",data);


printk("xilaxitimer_init: timer started\n");

/*int i = 0;
for (i; i < 50; i++)
{
data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCR_OFFSET);
printk("xilaxitimer_init: XIL_AXI_TIMER_TCR_OFFSET 0x%08X\n",data);

data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
printk("xilaxitimer_init: XIL_AXI_TIMER_TCSR_OFFSET 0x%08X\n",data);
}*/

return 0;
}

static void __exit xilaxitimer_edit(void)
{
/*
* Exit Device Module
*/
iounmap(dev_virtaddr);
free_irq(IRQ_NUM, NULL);
platform_device_unregister(pdev);
printk(KERN_INFO "xilaxitimer_edit: Exit Device Module \"%s\".\n", DEVICE_NAME);
}

module_init(xilaxitimer_init);
module_exit(xilaxitimer_edit);

MODULE_AUTHOR ("Xilinx");
MODULE_DESCRIPTION("Test Driver for Zynq PL AXI Timer.");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("custom:xilaxitimer");

Balabes
здравствуйте.
Проблему локализовал, требуется помощь в устранении.
как видно на скрине сверху что мой таймер зарегистрирован как прерывание номер 61, но мне нужно прерывание №61 в GIC а не в системе.
Как я понял до какой-то версии ядра, это было одно и тоже. Теперь нет. Как найти нужный номер прерывания, я не могу понять. Люди писали что через
res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
или
platform_get_irq(pdev, 0);

но у меня почему то не получилось. Подскажите, кто что сможет
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.