Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LPC2148 UART: Постоянный вызов прерывания CTI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ivstech
Иногда UART переходит в такое состояние, что вызывается прерывание CTI (U1IIR=0b11001100). Если в обработчике прочитать U1LSR, то там хранится значение 0x60, т.е. младший бит (RDR)=0, якобы в FIFO данных нет. Если не прочитать U1RBR, прерывание вызовется снова. Получется, фрагмент обработчика должен быть такого вида:

Код
   case IIR_CTI:
     for(;;)
     {
       temp = rU1LSR;

       data=rU1RBR; // изначально чтение U1RBR было ниже

       // Если данных нет (RDR=0), выходим
       if ((temp&0x11)==0)
         break;

       //data=rU1RBR; // <- здесь

       // Если ошибка, продолжаем цикл без обработки принятых данных
       if (temp&(7<<2)) // PE,FE,BI
         continue;
       tn_my_queue_isend_polling(&queue,data);
     }


Странно, что в ERRATA про это ни слова, на форумах тоже
Alex03
Странно...
у меня вполне работает
Код
        case U0IIR_INT_ID_RX_TIMEOUT:   // прерывание по отсутствию данных
        case U0IIR_INT_ID_RDA:          // прерывание по приему

            while(U0LSR & U0LSR_RDR)
            {
                uchar uc = U0RBR;
                ...
            }
            break;

А что в начале/конце обработчика прерывания (главный switch как выглядит)?
И не пользуетесь ли отладчиком для просмотра регистров проца в(от) которых сбрасываются флаги по чтению (тот же UхRBR)?

О! кстати!
Видимо вместо
Код
if ((temp&0x11)==0)
надо
Код
if (!(temp&0x03))
а то и
Код
if (!(temp&0x01))
???
ivstech
Цитата(Alex03 @ Sep 2 2008, 14:46) *
Странно...
у меня вполне работает
Код
        case U0IIR_INT_ID_RX_TIMEOUT:   // прерывание по отсутствию данных
        case U0IIR_INT_ID_RDA:          // прерывание по приему

            while(U0LSR & U0LSR_RDR)
            {
                uchar uc = U0RBR;
                ...
            }
            break;


Сначала у меня стояла такая же проверка как у Вас. Потом обнаружилось, что иногда бывает включен бит Break interrupt, а RDR - нет. И нужно считать U1RBR, иначе обработчик постоянно вызывается.

Цитата(Alex03 @ Sep 2 2008, 14:46) *
А что в начале/конце обработчика прерывания (главный switch как выглядит)?
И не пользуетесь ли отладчиком для просмотра регистров проца в(от) которых сбрасываются флаги по чтению (тот же UхRBR)?


Код
void tn_uart1_int_func(void)
{
   volatile char temp;
   char data;
   int i;
   int rc;
   temp=rU1IIR;
   switch((temp>>1)&0x7) //-- and clear int source
   {

       ....

   }

   VICVectAddr = 0xFF;
}

В отладчике окно с регистрами закрыто. Обычно такой глюк происходит при отладке при перезапуске программы. Помогает только выключение питания. Код инициализации (со сбросом FIFO). Может, проблема именно в сбросе FIFO при старте? Попробую это отключить

Код
//---- pinout -----
  rPINSEL0.....

  ...

  //-- enable access to divisor latch regs
  rU1LCR = LCR_ENABLE_LATCH_ACCESS;
  //-- set divisor for desired baud
  rU1DLM = 0;
  rU1DLL = 32; // 32;    // (60'000'000)/(16*115200)  = 32

  //-- disable access to divisor latch regs (enable access to xmit/rcv fifos
  //-- and int enable regs)
  rU1LCR = LCR_DISABLE_LATCH_ACCESS;

  //-- Enable UART1 rx interrupts
  rU1IER = 0x0F;  //-- Enable int
  //-- setup line control reg - disable break transmittion, even parity,
  //-- 1 stop bit, 8 bit chars
  rU1LCR = 0x03; // нет четности
  rU1FCR = (0x03<<6) | 7;  //-- Int Trigger - 14 bytes, Enable FIFO,Reset Tx FIFO & Rx FIFO

  // DTR не используется
  // AutoCTS=1, AutoRTS=1
  rU1MCR = (3<<6)|3;
Alex03
Цитата(ivstech @ Sep 2 2008, 15:21) *
Сначала у меня стояла такая же проверка как у Вас. Потом обнаружилось, что иногда бывает включен бит Break interrupt, а RDR - нет. И нужно считать U1RBR, иначе обработчик постоянно вызывается.


Приведите тогда код всего обработчика прерываний...
Break interrupt, а также OE/PE/FE - это другой тип прерывания, и проверять их надо не в CTI а в RLS.
И читать при Break interrupt надо не U1RBR а U1LSR
У меня обработчик начинается так:
Код
    uint register nIIR;
    while( ((nIIR = U0IIR) & U0IIR_INT_PENDING) == 0 )
    {
        switch(nIIR & U0IIR_INT_ID_MASK)
        {
        case U0IIR_INT_ID_RLS: // прерывание по ошибке
            U0LSR;
            ...
            break;
meister
Цитата(Alex03 @ Sep 2 2008, 15:07) *
И читать при Break interrupt надо не U1RBR а U1LSR


Мануал:
Note: A parity error is associated with the character at the top of the UART1 RBR FIFO.

То есть, при возникновении RLS, читать LSR, чтобы определить, какая ошибка и RBR - что принялось с ошибкой. В случае OE - RBR читать не надо (доставать нормальные байты, имхо, следует только в RDA и CIT).
ivstech
Не помню, откуда я взял пример обработчика изначально, из IARa или tn_kernel. Затем ввел переменную temp, чтобы можно было посмотреть содержимое U1IIR. Бит PENDING я не проверяю, т.к. прерывание вызвалось.

Код
void tn_uart1_int_func(void)
{
   volatile char temp;
   char data;
   int i;
   int rc;
   temp=rU1IIR;
   switch((temp>>1)&0x7) //-- and clear int source
   {
   case IIR_THRE:  // continue sending data
     for (i=0; i<16; i++)
     {
       rc = tn_my_queue_ireceive(&queueTX,&data);
       if(rc != TERR_NO_ERR)
       {
         if (i==0) // нет данных на передачу
           tn_sem_isignal(&semTx1UDRE);

         // ^^^ передача 1-го байта после остановки осуществляется из основной программы

         // (т.к. прерывание THRE вызывается однократно)
         break;
       }
       rU1THR=data;

     }
     break;
   case IIR_RLS: // error manage
   case IIR_RDA: // receive data
   case IIR_CTI: // time out
     for(;;)
     {
       temp = rU1LSR;
       // Если данных нет (RDR=0), выходим
       if ((temp&0x01)==0)
         break;

       // Читаем с вершины FIFO
       data=rU1RBR;
       // Если ошибка, продолжаем цикл без обработки принятых данных
       if (temp&(7<<2)) // PE,FE,BI
         continue;
       tn_my_queue_isend_polling(&queueRX,data);
     }
     break;
   case IIR_MODEM_STATUS:
     // Прерывание CTS or DSR or RI or DCD
     // CTS автоматический
     // DSR не используется
     temp=rU1MSR;
     // Проверяем только RI и DCD (заглушки)
     if (temp&(1<<6)); // Звонок
     if (temp&(1<<7)); // Связи нет

   }

   VICVectAddr = 0xFF;
}




Основное подозрение у меня сейчас на инициализацию со сбросом FIFO. Т.к. значение U1LSR привязано к значению на вершине RX FIFO, похоже, при очистке FIFO U1LSR не сбрасывается как при чтении U1RBR
Alex03
Лучше разделить
Код
  case IIR_RLS: // error manage
      temp = rU1LSR;
      if (temp&(7<<2)) // PE,FE,BI
      {
         data=rU1RBR;
         ...
      }
      ...
     break;
   case IIR_RDA: // receive data
   case IIR_CTI: // time out
     for(;;)
     {
       temp = rU1LSR;
       // Если данных нет (RDR=0), выходим
       if ((temp&0x01)==0)
         break;

       // Читаем с вершины FIFO
       data=rU1RBR;
       tn_my_queue_isend_polling(&queueRX,data);
     }
     break;


meister Согласен.
У меня любая ошибка - это ошибка и далее соответствующие действия не зависимо от типа ошибки. Правда отдельно тикают счётчики разных ошибок, прерываний, принятых/переданных байт и т.д. smile.gif
ivstech
Насчет разделить код, я так сделал специально, если, например, ошибка четности будет во 2-м байте в FIFO, прерывание будет вызвано при IIR_RDA, а в цикле флаги мы не проверим. Или я неправ?



Убрал в инициализации сброс FIFO, пока "полет нормальный"
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.