ivstech 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Иногда 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 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Странно... у меня вполне работает 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 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Странно... у меня вполне работает 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; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex03 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Сначала у меня стояла такая же проверка как у Вас. Потом обнаружилось, что иногда бывает включен бит 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 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба И читать при 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 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Не помню, откуда я взял пример обработчика изначально, из 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 0 2 сентября, 2008 Опубликовано 2 сентября, 2008 · Жалоба Лучше разделить 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 Согласен. У меня любая ошибка - это ошибка и далее соответствующие действия не зависимо от типа ошибки. Правда отдельно тикают счётчики разных ошибок, прерываний, принятых/переданных байт и т.д. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ivstech 0 3 сентября, 2008 Опубликовано 3 сентября, 2008 · Жалоба Насчет разделить код, я так сделал специально, если, например, ошибка четности будет во 2-м байте в FIFO, прерывание будет вызвано при IIR_RDA, а в цикле флаги мы не проверим. Или я неправ? Убрал в инициализации сброс FIFO, пока "полет нормальный" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться