Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

проблем с прекъсване при LPC2124
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=5950
Страница 1 от 1

Автор:  MidNighT_SpiRiT [ Сря Юли 16, 2008 9:05 pm ]
Заглавие:  проблем с прекъсване при 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;
      }
  }
}

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

Автор:  БатеВаньо [ Чет Юли 17, 2008 10:03 am ]
Заглавие: 

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

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

Автор:  Zdrav [ Чет Юли 17, 2008 10:27 am ]
Заглавие: 

Всъщност възможностите са много:
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. Но намери начин да провериш дали средата която ползваш е подсигурила всички останали точки по реда по който са подредени. Списъка не претендира за изчерпателност.

Автор:  MidNighT_SpiRiT [ Чет Юли 17, 2008 10:48 am ]
Заглавие: 

Мерси, сега ще действам. Празната функция беше така в примера, всъщност даже не знам за какво служи :oops: , сега ще прочета по-внимателно.

Автор:  MidNighT_SpiRiT [ Чет Юли 17, 2008 12:02 pm ]
Заглавие: 

Модулът е коректно конфигуриран, защото в главната програма приемам символ и след това го изпращам обратно и всико е наред.

Автор:  Zdrav [ Чет Юли 17, 2008 12:44 pm ]
Заглавие: 

MidNighT_SpiRiT написа:
Модулът е коректно конфигуриран, защото в главната програма приемам символ и след това го изпращам обратно и всико е наред.

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

Автор:  MidNighT_SpiRiT [ Чет Юли 17, 2008 2:36 pm ]
Заглавие: 

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

Автор:  БатеВаньо [ Чет Юли 17, 2008 2:53 pm ]
Заглавие: 

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

Автор:  Zdrav [ Чет Юли 17, 2008 5:20 pm ]
Заглавие: 

БатеВаньо написа:
Прекъсванията на 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 вектора код за извикване на тази функция. Още едно нещо което трябва да провериш.

Автор:  MidNighT_SpiRiT [ Чет Юли 17, 2008 7:39 pm ]
Заглавие: 

Ползвам средата на IAR systems, защото само с нея работи jtag-a(през паралелния порт) на olimex. Ако техническият в Пловдив беше нормален университет щяха да са купили нещо по-нормално за програмиране и дебъгване, но да не навлизам в подробности...
Цитат:
Като се замисля MidNighT_SpiRiT ти получаваш вероятно единични байтове. При тази ситуация прекъсването, което ще се получи е CTI, а не RDA

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

Автор:  Zdrav [ Чет Юли 17, 2008 10:39 pm ]
Заглавие: 

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.

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/