Отговори на тема  [ 11 мнения ] 
проблем с прекъсване при LPC2124 
Автор Съобщение
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение проблем с прекъсване при LPC2124
Здравейте, проблемът е следният:
серийня порт работи, но не може да предизвика прекъсване. Ето част от кода:
Код:
void INTERRUPTSinit(void)
{
#ifdef SRAM_VIA_JLINK
  MEMMAP = 2;
#endif

  // Setup interrupt controller.
  VICProtection = 0;

  // Disable ALL interrupts
  VICIntEnClear = 0xffffffff;
  VICDefVectAddr = (U16)&DefDummyInterrupt;
 
  //konfigurirane na prekusvane ot UART0:
  VICIntSelect &= ~VIC_UART0_bit;  // IRQ on UART0.
  VICVectAddr3 = (unsigned int)&UART0Interrupt;
  VICVectCntl3 = 0x20 | VIC_UART0; // Enable vector interrupt for UART0.
  VICIntEnable = VIC_UART0_bit;    // Enable UART 0 interrupt.

 
  VICProtection = 1;
}
//.....

void UART0Init(U16 baud)
{
  U16 divisor = getperipheralClockFreq() / (16 * baud);
  U0LCR_bit.DLAB=1; //Enable DLAB
  U0LCR_bit.WLS=3;  //8 bits
  U0LCR_bit.SBS=1;  //1 stop bit
  U0DLL = LSB(divisor);
  U0DLM = MSB(divisor);
  U0LCR_bit.DLAB=0; //Disable DLAB
  PINSEL0 = PINSEL0 & ~0xF | 0x5;
 
  U0FCR_bit.FCRFE = 0;
  U0IER_bit.RDAIE = 1;//razreshavam prekusvane pri pristignal simvol
}
//.....

__irq __arm void IRQ_Handler(void)
{
  void (*interrupt_function)();
  U16 vector;

  vector = VICVectAddr;                     // GET VECTOR ADDRESS FROM VIC CONTROLLER
  interrupt_function = (void(*)())vector;

  (*interrupt_function)();                  // Call vectored interrupt function.

  VICVectAddr = 0;
  //A_LED1_OFF;                          // Clear interrupt in VIC.
}

//vsushtnost tova ne pravi nishto:
static void UART0Interrupt(void)
{
   // unsigned long int k;
  IO0CLR = 0xFFFFFFFF;

  //for(k = 0; k < 200000; k++);
  //IO0SET = 0xFFFFFFFF;
 
  switch(U1IIR_bit.IID)
  {
    case 0x1: //tx buffer empty handling code
      {
       // ProtocolStateMachine_2();

      break;
      }
    case 0x2: //Receive data available
      {
       // ProtocolStateMachine_1();
       
      break;
      }
  }
}

Използвах примерния код, но не тръгва с порта, иначе с таймера работеше.


Сря Юли 16, 2008 9:05 pm
Профил
Ранг: Новодошъл
Ранг: Новодошъл

Регистриран на: Чет Яну 04, 2007 12:43 am
Мнения: 178
Мнение 
Има две възможности - или прекъсванията не са разрешени глобално, или приеманите символи не съответстват на конфигурацията на LPC-порта - скорост, четност и т.н. При грешка по четност или frame error портът генерира Line Status Interrupt, който както се вижда от кода не е разрешен.
Може да добавиш:
U0IER_bit.RXLSIE = 1;
и да опиташ отново.

И една корекция:
VICDefVectAddr = (U16)&DefDummyInterrupt;
Този оператор преобразува адреса на вектора по подразбиране в 16-битово число. Ако DefDummyInterrupt е извън първите 64К, адресът, зареден във VICDefVectAddr ще е погрешен. Би тябвало да бъде:
VICDefVectAddr = (U32)&DefDummyInterrupt;


Чет Юли 17, 2008 10:03 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
Всъщност възможностите са много:
1. Глобално забранени прекъсвания към ядрото;
2. Некоректен IRQ вектор в таблицата с ексепшъните;
3. Некоректно ремапване на горната таблица;
4. Некоректно конфигуриране на VIC или в последствие някой бърника по него;
5. Некоректно конфигуриране на PINSEL0 или в последствие някой бърника по него;
6. Некоректно конфигуриране на периферния модул. В случая мисля че конфигурирането на UxLCR трябва да става при DLAB=0, а записа в UxDLL и UxDLM при DLAB=1. За нормалната работа на UART-a след конфигурацията трябва да оставиш DLAB=0.Прекъсванията от този UART не работят коректно ако си забранил FIFO!!!
7. Некоректно конфигуриране на указателя на IRQ стека;
8. Некоректно запомняне/незапомняне на контекста от функцията която обработва прекъсването;
9. Некоректно обработване на прекъсването от горната функция. При този UART обработката има доста особености. Няма да минеш само с празна функция.
10. Сгрешена дефиниция на някой от регистрите в хедър файла.
...
Може бъговете да са повече от един. В твоя случай първо провери точка 6 и 9. Но намери начин да провериш дали средата която ползваш е подсигурила всички останали точки по реда по който са подредени. Списъка не претендира за изчерпателност.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Чет Юли 17, 2008 10:27 am
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение 
Мерси, сега ще действам. Празната функция беше така в примера, всъщност даже не знам за какво служи :oops: , сега ще прочета по-внимателно.


Чет Юли 17, 2008 10:48 am
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение 
Модулът е коректно конфигуриран, защото в главната програма приемам символ и след това го изпращам обратно и всико е наред.


Чет Юли 17, 2008 12:02 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
MidNighT_SpiRiT написа:
Модулът е коректно конфигуриран, защото в главната програма приемам символ и след това го изпращам обратно и всико е наред.

Това добре. Но, ако не си разрешил FIFO може да имаш проблем с прекъсванията. Въпреки, че модулът ще работи с полиране. UART при LPC прави проблеми с вдигането на флагове за прекъсвания, когато не е разрешен FIFO. Не е свързано с времена и пропускане на събития от CPU. Просто модула има бъгове/фийчъри.
Аз бих проверил първо две неща. Целия път на сигнала за прекъсване от периферния модул до CPU-то. Дали е конфигуриран правилно в софтуера и дали състоянието на регистрите, при работа на програмката ти, когато чакаш влизане в прекъсване, а то не идва, съответстват на тази конфигурация. И това след като си направил корекциите, които БатеВаньо посочи

_________________
Най-опасният враг на истината и свободата е мнозинството.


Чет Юли 17, 2008 12:44 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение 
Не мога да открия проблема и реших да не използвам прекъсване от серийния модул :D Първоначалната ми идея се оказа сложна за реалзиране и сега реших да опростя нещата, ще проверявам през определено време дали има получен символ или дали е изпратен предишния, така става по-сигурно и просто. Това, което правя е за дипломна работа, обаче не е много просто, особено като се използва ARM.
Мерси все пак за помощтта, сигурно по-нататък ще ми се наложи да се боря сериозно с тази архитектура.


Чет Юли 17, 2008 2:36 pm
Профил
Ранг: Новодошъл
Ранг: Новодошъл

Регистриран на: Чет Яну 04, 2007 12:43 am
Мнения: 178
Мнение 
Прекъсванията на LPC2124 работят и при забранен FIFO. Единственият ефект (бъг/фийчър) е, че VIC не "вижда" прекъсването от THRE веднага след инициализация. За да преодолея това се наложи да изпращам първия символ извън функцията за обработка на прекъсването. След него всичко върви наред.
Не съм проверявал изрично, но навярно това го има и при разрешен FIFO.
А по отношение на U0LCR_bit.DLAB - той трябва да е 0, за да са достъпни U0RBR, U0THR и U0IER. U0LCR е достъпен при всички случаи. Въобще, '550-архитектурата, избрана от NXP, е друга дискусионна тема - ама това имали хората, това сложили :) .
Между другото, добра практика при побитово установяване на регистрите е да се зареждат и тези полета, в които трябва да има 0 (U0LCR_bit.PE, например), а не да се разчита на "стойности по подразбиране".


Чет Юли 17, 2008 2:53 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
БатеВаньо написа:
Прекъсванията на LPC2124 работят и при забранен FIFO.

Честно да ти кажа това ми е в графата смътен спомен. Веднъж за една дребна задачка се бях натъкнал на него. Докато не разреших FIFO увисвах в чакане на данни от UART-a. Това беше с LPC2214 на 60 MHz и без допълнителни задачи, с код който бях използвал и преди. Така че тогава го свързах с няколко съобщения за подобни проблеми в нета. В търсене на проблема бях орязал кода отвсякъде и накрая дори направих тест - със и без FIFO. И в документацията при описанието на UxFCR има нещо което навежда на тази мисъл. Може пък да е било фийчър на някои от първите ревизии чипове.
Като се замисля MidNighT_SpiRiT ти получаваш вероятно единични байтове. При тази ситуация прекъсването, което ще се получи е CTI, а не RDA. В функцията която идентифицира прекъсването трябва да го предвидиш. Но отдруга страна това
Код:
IO0CLR = 0xFFFFFFFF;

ми подсказва, че следиш дали влизаш в прекъсване с някакъв LED. И явно в случая проблема е че въобще не се стига до идентификация на прекъсването.
В void IRQ_Handler(void) също имаш прочитане на VICVectAddr в U16. Трябва да е U32. Това да не са го направили щото с безплатната версия не можеш да компилираш повече от 16К код? :)
Въобще този void IRQ_Handler(void) малко усложнява нещата. Предполагам, че средата която ползваш поставя на IRQ вектора код за извикване на тази функция. Още едно нещо което трябва да провериш.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Чет Юли 17, 2008 5:20 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Нед Сеп 17, 2006 12:00 pm
Мнения: 450
Местоположение: Plovdiv
Мнение 
Ползвам средата на IAR systems, защото само с нея работи jtag-a(през паралелния порт) на olimex. Ако техническият в Пловдив беше нормален университет щяха да са купили нещо по-нормално за програмиране и дебъгване, но да не навлизам в подробности...
Цитат:
Като се замисля MidNighT_SpiRiT ти получаваш вероятно единични байтове. При тази ситуация прекъсването, което ще се получи е CTI, а не RDA

Да, наистина се получава CTI прекъсване, но то не се разрешава отделно, така, че според мен би трябвало да се получава прекъсване. Буфера го разрешавам, но интересно защо ми дава, че последните два бита, с които се определя при колко байта в буфера да се получи прекъсване са 11, т.е за 14 байта. Опитах да ги нулирам в началото, но без ефект.


Чет Юли 17, 2008 7:39 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 2:01 pm
Мнения: 1952
Местоположение: Варна
Мнение 
MidNighT_SpiRiT написа:
Да, наистина се получава CTI прекъсване, но то не се разрешава отделно, така, че според мен би трябвало да се получава прекъсване.
Имах впредвид че в switch-case вътре в UART0Interrupt(), където правиш идентификация на прекъсването нямаш default case, нямаш и case за CTI. При това положение няма да прочиташ байтовете от UxRBR ако имаш прекъсване по CTI. Дори и ако всичко по получаването на прекъсването е наред. Иначе е ясно че няма отделно разрешаване на CTI прекъсването.
MidNighT_SpiRiT написа:
Буфера го разрешавам, но интересно защо ми дава, че последните два бита, с които се определя при колко байта в буфера да се получи прекъсване са 11, т.е за 14 байта. Опитах да ги нулирам в началото, но без ефект.
Ако обърнеш внимание при този UART '550. Някои от регистрите споделят общи адреси например при запис на адрес 0xE000C008 пишеш в регистър U0FCR, но това е write only регистър. При четене от адрес 0xE000C008 всъщност четеш регистър U0IIR най старшите два бита на който показват дали са разрешени Rx/Tx FIFO. Няма как да прочетеш на какво ниво са конфигурирани FIFO. Трябва да си го помниш в променлива ако ти е необходимо.
Ако не си се отказал още да подкараш прекъсванията от UART. Постави в междинната функция IRQ_Handler() код за светване на някой LED по платката и провери дали се извиква тази функция поне веднъж. Ако не светва LED-a провери какво е поставил IAR на адрес 0x00000018 или 0x40000018 според това къде е мапната таблицата с ексепшън векторите. Предполагам е нещо от сорта ldr pc, [pc, #xx], където (0x18 + 8 + #xx) трябва да сочи константа в литерал пуула с адреса на IRQ_Handler().
Ако това не е така не чакай да ти се извика обработчика на прекъсванията.
Ако искаш да шунтираш междинната функция IRQ_Handler(), която от IAR са поставили за твое добро, постави на адрес 0x00000018(0x40000018) ето този ред:
Код:
ldr     pc, [pc, #-0xFF0]

Това ще насочи IRQ вектора директно към адреса подаван от VICVectAddr.
В този случай обаче трябва да не забравиш да сложиш в края на UART0Interrupt() eдин фиктивен запис в VICVectAddr за ъпдейтване на приоритетите на VIC. Щото иначе всичко от приоритета на UART-a включително и надолу ще остане маскирано в VIC след първия интеръпт от UART-a.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Чет Юли 17, 2008 10:39 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 11 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 3 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни