Есть самописная программа-драйвер. По прерыванию от таймера читает ПЛИС и складывает его данные в свой внутренний буфер.
В 2.6.33.20 все работает нормально. Но после перехода на 3.6.3
облом.
Основа для обработчика с сайта
http://dmilvdv.narod.ru/AT91SAM9260/index.html?linux.html
Обработчик не вещается на таймер. Кусок кода для инициализации прерывания:
// Initialize ADC. The following two lines set the appropriate PMC bit
// for the ADC. Easier than mapping PMC registers and then setting the bit.
at91adc_clk = clk_get(NULL, // Device pointer - not required.
"adc_clk"); // Clock name.
clk_enable(at91adc_clk);
// Initialize Timer Counter module 0. The following two lines set the appropriate
// PMC bit for TC0. Easier than mapping PMC registers and then setting the bit.
at91tc0_clk = clk_get(NULL, // Device pointer - not required.
"tc0_clk"); // Clock name.
clk_enable(at91tc0_clk);
// Map registers to the current address space.
mapped_base_pio_a = ioremap_nocache(AT91_PIOA, 0x200);
PIO_A_SODR = (int*) (mapped_base_pio_a + PIO_SODR);
PIO_A_CODR = (int*) (mapped_base_pio_a + PIO_CODR);
mapped_base_pio_b = ioremap_nocache(AT91_PIOB, 0x200);
PIO_B_SODR = (int*) (mapped_base_pio_b + PIO_SODR);
PIO_B_CODR = (int*) (mapped_base_pio_b + PIO_CODR);
PIO_B_PDSR = (int*) (mapped_base_pio_b + PIO_PDSR);
*(int*) (mapped_base_pio_b + PIO_PER) = out_mask;
*(int*) (mapped_base_pio_b + PIO_IDR) = out_mask;
*(int*) (mapped_base_pio_b + PIO_MDDR) = out_mask;
*(int*) (mapped_base_pio_b + PIO_PUDR) = out_mask;
*(int*) (mapped_base_pio_b + PIO_OWDR) = out_mask;
*(int*) (mapped_base_pio_b + PIO_OER) = out_mask;
*(int*) (mapped_base_pio_b + PIO_PER) = in_mask;
*(int*) (mapped_base_pio_b + PIO_IDR) = in_mask;
*(int*) (mapped_base_pio_b + PIO_MDDR) = in_mask;
*(int*) (mapped_base_pio_b + PIO_PUER) = in_mask;
*(int*) (mapped_base_pio_b + PIO_ODR) = in_mask;
mapped_fpga_sram = ioremap_nocache(FPGA_MEM_BASE_ADDR, FPGA_MEM_SIZE);
if (mapped_fpga_sram == NULL)
{
printk(KERN_INFO "%s %d Memory mapping error.\n",__FILE__,__LINE__);
ret = -EACCES;
goto exit_5;
}
set_param_word((unsigned short int*) (((unsigned char*)mapped_fpga_sram)+BUFSIZE_ADDR), QUAN_KADR_ALL_PLIS);
//printk(KERN_INFO "***** bufsize = %u\n", *((unsigned short int*) (((unsigned char*)mapped_fpga_sram)+BUFSIZE_ADDR)));
at91mcuconf_base = ioremap_nocache(AT91_MCU_CONF, 0x100);
if (at91mcuconf_base == NULL){
printk(KERN_INFO "%s %d MCU memory mapping failed\n",__FILE__,__LINE__);
ret = -EACCES;
}
iowrite32(0, at91mcuconf_base+0x00);
iowrite32(0x07060101, at91mcuconf_base+0x04);
iowrite32(0x00070003, at91mcuconf_base+0x08);
iowrite32(0x00000021, at91mcuconf_base+0x0C);
iounmap(at91mcuconf_base);
at91tc0_base = ioremap_nocache(AT91SAM9260_BASE_TC0, // Physical address
64); // Number of bytes to be mapped.
if (at91tc0_base == NULL){
printk(KERN_INFO "%s %d TC0 memory mapping failed\n",__FILE__,__LINE__);
ret = -EACCES;
goto exit_5;
}
// iIrq = 0;
// Configure TC0 in waveform mode, TIMER_CLK1 and to generate interrupt on RC compare.
// Load 50000 to RC so that with TIMER_CLK1 = MCK/2 = 50MHz, the interrupt will be
// generated every 1/50MHz * 50000 = 20nS * 50000 = 1 milli second.
// NOTE: Even though AT91_TC_RC is a 32-bit register, only 16-bits are programmble.
// 1250 = 40kHz = 25us
iowrite32(50000, (at91tc0_base + AT91_TC_RC));
iowrite32((AT91_TC_WAVE | AT91_TC_WAVESEL_UP_AUTO), (at91tc0_base + AT91_TC_CMR));
iowrite32(AT91_TC_CPCS, (at91tc0_base + AT91_TC_IER));
iowrite32((AT91_TC_SWTRG | AT91_TC_CLKEN), (at91tc0_base + AT91_TC_CCR));
// Install interrupt for TC0.
ret = request_irq(AT91SAM9260_ID_TC0, // Interrupt number
at91tc0_isr, // Pointer to the interrupt sub-routine
0, // Flags - fast, shared or contributing to entropy pool
"ext_adc", // Device name to show as owner in /proc/interrupts
NULL); // Private data for shared interrupts
if (ret != 0){
printk(KERN_INFO "%s %d Timer interrupt request failed\n",__FILE__,__LINE__);
ret = -EBUSY;
goto exit_6;
}
После request_irq ошибка. На консоле в это время
genirq: Flags mismatch irq 17. 00000000 (ext_adc) vs. 000152a0 (at91_tick).
Догадываясь что возможно флаши разные ставил
IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL
эту строчку взял из файла at91sam926x_time.c
После этого происходит полное зависание системы
Прошу вашей помощи - я совсем запутался. Сейчас у меня варианты:
- неправильная инициализация параметров для прерывания
- что-то надо еще добавить в код обработки прерывания
- у кого то есть что то похожее и по аналогии я подпилю свой под новое ядро
Полностью сам драйвер привести не могу.
Обработчик прерывание начинается
static irqreturn_t at91tc0_isr(int irq, void *dev_id) {
ioread32(at91tc0_base + AT91_TC_SR);// Read TC0 status register to reset RC compare status
*PIO_B_SODR = PIN_DEBUG_MASK;
// текс обработчика
*PIO_B_CODR = PIN_DEBUG_MASK;
return IRQ_HANDLED;.