Страниц: 1 2 [3]
  Печать  
Автор Тема: Проблемы с in32 () или out32()  (Прочитано 14179 раз)
@nger
Гость
« Ответ #30 : Декабря 12, 2013, 11:42:32 am »

В обработчике прерывания я выставляю флаги превышения порога в нужном канале, затем через poll проверяю их.

Источник очищаете? Если работа идет по уровню, как раз и подвесите систему.
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #31 : Декабря 12, 2013, 07:37:28 pm »

Плата на РС шине, поэтому прерывания по уровню. Без опций.

Посмотрите внимательно что линуксовый драйвер делает в обработчике прерывания. Вы похоже не сбрасываете запрос прерывания с платы.
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #32 : Декабря 12, 2013, 11:20:55 pm »

Код:
static irqreturn_t mm080_interrupt(int irq, void *sysdev, struct pt_regs *regs)
{
int i, do_wake = 0;
struct mm080_sysdev *dev = sysdev;
u32 channel = 0;
irqreturn_t ret = IRQ_NONE;

spin_lock(&dev->lock);
channel =  hw_interrupt_ready_flags(dev);
if (channel) {
// Выставляем флаг POLLIN для всех каналов устройства и флаг POLLPRI для
// того канала, в котором произошло превышение. Флаг POLLIN сообщает о
// том, что данные готовы для вычитывания, т.к. по превышению порога
// хотя бы в одном канале, данные сливаются со всех каналов и анализи-
// руются.
for (i = 0; i < NUM_CHANNELS; i++) {
dev->adc_poll_flags[i] |= POLLIN;
if (channel & (1 << i))
dev->adc_poll_flags[i] |= POLLPRI;
}
// dev->adc_poll_flags[0] |= POLLPRI;
hw_interrupt_acknowledge(dev);
do_wake = 1;
ret = IRQ_HANDLED;
// hw_compare_disable(dev);
// interrupt_disable(dev);
}
spin_unlock(&dev->lock);
if (do_wake)
for (i = 0; i < NUM_CHANNELS; i++)
wake_up_interruptible(&dev->adc_waitq[i]);

return ret;
}
да вроде тут нет никакого сброса прерывания...
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #33 : Декабря 12, 2013, 11:54:03 pm »

what is hw_interrupt_acknowledge(dev)?
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #34 : Декабря 13, 2013, 08:49:35 am »

Установка 30 бита в 1

Код:
// 30 - подтверждение прерывания по событию превы-
// шения установленного порога(готовность
// данных). Для подтверждения надо записать '1'.
в своём драйвере я так же дергаю эту функцию.

Единственно что в в обработчик прерывания я попадаю только 1 раз при вызове InterruptAttach...
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #35 : Декабря 13, 2013, 10:00:39 am »

При вызове InterruptAttach() вы устанавливаете свой обработчик. Попадать в него вы должны по выставлению сигнала прерывания от платы. Честно, я не очень представляю что вы делаете. В документации qnx есть целая глава посвященная написанию обработчиков прерываний и как это работает. Я надеюсь вы ее читали.
Записан
ed1k
QOR.Moderator
*****
Offline Offline

Сообщений: 739


Просмотр профиля WWW
« Ответ #36 : Декабря 13, 2013, 10:04:17 am »

Вы вызываете InterruptAttach() _до_ _того_, как ставите биты в регистре управления разрешающие работу и прерывания, верно?
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #37 : Декабря 13, 2013, 10:21:39 pm »

Верно, InterruptAttach я делаю до того как разрешаю прерывания. Аттач делается в инициализации драйвера после инициализации ресурменеджера. Я понимаю, что привязываю прерывания платы к своей функции-обработчику.
Прерывания я разрешаю уже из своей программы, командой драйверу "включить прерывания"

А вообще у меня есть подозрения, что зависание системы не связано на прямую с прерываниями, так как в предыдущей версии драйвера, ещё без обработки прерываний, плата уже вешала систему...
« Последнее редактирование: Декабря 13, 2013, 10:24:51 pm от denmor86 » Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #38 : Января 21, 2014, 06:59:20 pm »

Итак я снова добрался до платы, точнее всего устройства в сборе.

Посмотрел его работу на Debian 5 убедился что драйвер для linux работает корректно и плата прошита.

Лог pci -vvv
Код:
Class          = Communication (Other)
Vendor ID      = 3755h, Unknown
Device ID      = 47h, Unknown Unknown
PCI index      = 0h
Class Codes    = 078000h
Revision ID    = 1h
Bus number     = 3
Device number  = 10
Function num   = 0
Status Reg     = 200h
Command Reg    = bh
I/O space access enabled
Memory space access enabled
Bus Master disabled
Special Cycle operations monitor
Memory Write and Invalidate disabled
Palette Snooping disabled
Parity Error Response disabled
Data/Address stepping disabled
SERR# driver disabled
Fast back-to-back transactions to different agents disabled
PCI INTx enabled
Header type    = 0h Single-function
BIST           = 0h Build-in-self-test not supported
Latency Timer  = 0h
Cache Line Size= 0h
BAR - 0 [Mem]  = f0000000h 32bit length 134217728 enabled
Subsystem Vendor ID = 3755h
Subsystem ID        = 4h
Max Lat        = 0ns
Min Gnt        = 0ns
PCI Int Pin    = INT A
Interrupt line = 11
CPU Interrupt  = bh
Device Dependent Registers:
0x040:  0000 0000 0b00 0002   0000 0000 0000 0000
0x050:  0000 00f0 0000 0000   0000 0000 0000 0000
0x060:  0000 0000 0000 0000   0000 0000 0000 0000
0x070:  0000 0000 0000 0000   0000 0000 0b00 0000
0x080:  0000 0000 0b00 0002   0000 0000 0000 0000
0x090:  0000 00f0 0000 0000   0000 0000 0000 0000
0x0a0:  0000 0000 0000 0000   0000 0000 0000 0000
0x0b0:  0000 0000 0000 0000   0000 0000 0b00 0000
0x0c0:  0000 0000 0b00 0002   0000 0000 0000 0000
0x0d0:  0000 00f0 0000 0000   0000 0000 0000 0000
0x0e0:  0000 0000 0000 0000   0000 0000 0000 0000
0x0f0:  0000 0000 0000 0000   0000 0000 0b00 0000


Проблема моя сохранилась, после установке разрешения плате делать сравнение с порогом, плата вешает всю систему.
Функции коннекта к плате.
Код:
/**
 @fn int Pci080Open( mm080_sysdev *dev)
 @brief Инициализация устройства

 Инициализация и поиск устройства на шине
 @param dev    - Дескриптор устройства
 @return 0 - успех, -1 - ошибка
 */
int Pci080Open(struct mm080_sysdev *dev) {
pthread_attr_t attr;
int ret = 0;

if (g_pDevice)
return (-1);

if (Pci080Connect(PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_PCI080, dev) == -1)
return (-1);

if (dev->attached != 1)
return (-1);

pthread_attr_init(&attr);

dev->iid = InterruptAttach( (int)dev->irq, IrqHandler, (const void *)dev, sizeof( struct mm080_sysdev * ), _NTO_INTR_FLAGS_END );
if ( dev->iid < 0 )
  return (-1);
else
  printf("[DRV_080_EMI] Interrupt %d is atteched in %d IRQ.\n",dev->iid,dev->irq);

g_pDevice = dev;
ret = ResmgrInit(dev);
if (ret != 0)
return (ret);
pthread_create(&dev->resmgr_thread, &attr, &ResmgrProcess, (void *) dev);

printf("[DRV_080_EMI] Driver is open.\n");

return (0);
}
int Pci080Connect(uint16_t vid, uint16_t did, struct mm080_sysdev *dev) {
struct pci_dev_info info;
void *pDevice = NULL;
void *p = NULL;
int i = 0;

if ((g_pciServer = pci_attach(0)) == -1)
return (-1);

/* Enable I/O-ports access */
ThreadCtl(_NTO_TCTL_IO, 0);

memset(&info, 0, sizeof(info));
memset(dev, 0, sizeof(struct mm080_sysdev));

info.VendorId = vid;
info.DeviceId = did;
  pDevice = pci_attach_device(NULL, PCI_SEARCH_VENDEV, 0, &info);
if (!pDevice) {
printf("[DRV_080_EMI] Error pci attach device. Exit. \n");
pci_detach(g_pciServer);
g_pciServer = 0;
return (-1);
}

p = mmap_device_memory(0, info.BaseAddressSize[0],
PROT_READ | PROT_WRITE | PROT_NOCACHE, 0, PCI_MEM_ADDR(info.PciBaseAddress[0]));
if( !p ) {
printf("[DRV_080_EMI] Error mmap device memory. Exit. \n");
pci_detach(g_pciServer);
g_pciServer = 0;
return(-1);

}
dev->device = pDevice;
dev->vid = vid;
dev->did = did;
dev->irq = info.Irq;
dev->cregs = (struct mm080_cregs *)p;
dev->ver = readl(&dev->cregs->version);

dev->mapped_bar0 = p;
dev->bar0_area_len = info.BaseAddressSize[0];

// Задаём доступ прошивки к ZBT.
hwctl_set_zbt_access_sw(dev, FW_ZBT_ACCESS);
// Настраиваем PLL.
// 0x99 - 100MHz; 0x19 - 200MHz; 0x1f - 248MHz.
hw_pll_setup(0x19, &dev->cregs->pll_1_ctrl, dev);
// Запрещаем прерывания. Прерывания будут разрешаться программой.
interrupt_disable(dev);

for (i = 0; i < NUM_CHANNELS; i++)
dev->adc_poll_flags[i] = 0;

strcpy(dev->name, PCI_DEVICE_NAME_PCI080 );
dev->attached = 1;


#ifdef _DEBUG_
printf("[DRV_080_EMI] Device found:\n");
printf("[DRV_080_EMI] did:vid: %04x:%04x\n", dev->vid, dev->did);
printf("[DRV_080_EMI] name: %s\n", dev->name);
printf("[DRV_080_EMI] version: %#x\n", dev->ver);
printf("[DRV_080_EMI] control reg = %#x\n", mmio32_read(&dev->cregs->control));
#endif
return (0);
}

Функция обработчик прерывания:
Код:
const struct sigevent * IrqHandler(void *area, int id) {
int i;
struct mm080_sysdev *dev = (struct mm080_sysdev *) area;
uint32_t channel = 0;

pthread_spin_lock(&dev->lock);
channel = hw_interrupt_ready_flags(dev);

if (channel) {
// Выставляем флаг POLLIN для всех каналов устройства и флаг POLLPRI для
// того канала, в котором произошло превышение. Флаг POLLIN сообщает о
// том, что данные готовы для вычитывания, т.к. по превышению порога
// хотя бы в одном канале, данные сливаются со всех каналов и анализи-
// руются.
#ifdef _DEBUG_
printf("Interrupt in %d channel \n", channel);
#endif
for (i = 0; i < NUM_CHANNELS; i++) {
dev->adc_poll_flags[i] |= POLLIN;
if (channel & (1 << i))
dev->adc_poll_flags[i] |= POLLPRI;
}
hw_interrupt_acknowledge(dev);
}
pthread_spin_unlock(&dev->lock);
return 0;
}

Я в тупике, написал программку тест, последовательно ввожу команды типа, разрешить прерывания, загрузить пороги, разрешить сравнение с порогом. После последней команды ребутаю СПишку(( Cry
« Последнее редактирование: Января 21, 2014, 07:02:55 pm от denmor86 » Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #39 : Января 22, 2014, 10:29:54 am »

Ларчик открывался просто, нельзя использовать printf(...) в функции обработчике прерывания...

Разбираюсь с поллингом...

Забавно всё делать в первый раз, столько всего узнаёшь  Smiley
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #40 : Января 22, 2014, 12:51:14 pm »

Возник вопрос, как правильно и легче организовать приём статуса от платы?
Плата по прерыванию понимает в каком из 4 каналов произошло превышение порога, клиент это должен понять и прочитать информацию с платы.
Нашёл 3 функции похожие друг на друга:
poll(...)
select(...)
ionotify(...)

Какую правильно использовать и как правильно реализовать установку флагов превышения в функции обработчике прерывания в драйвере?
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #41 : Января 22, 2014, 06:50:45 pm »

Итак с select я разобрался, почти... не понял как получить разные ответы... ну думаю разберусь...

Теперь обнаружились другие проблемы, прерывания срабатывают независимо от входного сигнала, т.е прошивка не правильно сравнивает сигнал с пороговыми значениями. Соответственно походу пороги я не правильно записываю на плату.

Существует ли способ узнать правильно ли я маплю память устройства?

я маплю так:
Код:
p = mmap_device_memory(0, info.BaseAddressSize[0],
PROT_READ | PROT_WRITE | PROT_NOCACHE, 0, PCI_MEM_ADDR(info.PciBaseAddress[0]));

далее использую конструкции типа:
Код:
void *addres = pDev->mapped_bar0 + mem_areas[inode].offset + mem_areas[inode].shift;
где
Код:
dev->mapped_bar0 = p;

в linux-драйвере память мапится

Код:
p = ioremap_nocache(pci_resource_start(pdev, 0),
    pci_resource_len(pdev, 0));
Записан
denmor86
Участник
*
Offline Offline

Сообщений: 35


Просмотр профиля
« Ответ #42 : Января 30, 2014, 09:36:17 pm »

Всем спасибо за ответы, тему можно закрыть. Разобрался сам.
Записан
Страниц: 1 2 [3]
  Печать  
 
Перейти в: