Перейти к содержанию
    

LPC2148 UART: Постоянный вызов прерывания CTI

Иногда 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 про это ни слова, на форумах тоже

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странно...

у меня вполне работает

        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))

???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странно...

у меня вполне работает

        case U0IIR_INT_ID_RX_TIMEOUT:   // прерывание по отсутствию данных
        case U0IIR_INT_ID_RDA:          // прерывание по приему

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

 

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

 

А что в начале/конце обработчика прерывания (главный 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;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сначала у меня стояла такая же проверка как у Вас. Потом обнаружилось, что иногда бывает включен бит 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;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И читать при 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).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не помню, откуда я взял пример обработчика изначально, из 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Лучше разделить

  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 Согласен.

У меня любая ошибка - это ошибка и далее соответствующие действия не зависимо от типа ошибки. Правда отдельно тикают счётчики разных ошибок, прерываний, принятых/переданных байт и т.д. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчет разделить код, я так сделал специально, если, например, ошибка четности будет во 2-м байте в FIFO, прерывание будет вызвано при IIR_RDA, а в цикле флаги мы не проверим. Или я неправ?

 

 

 

Убрал в инициализации сброс FIFO, пока "полет нормальный"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...