Программирование модемов© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 236 стр. 2.10. Современные микросхемы UARTФактически микросхема UART 8250 в ее исходном виде использовалась только в старых моделях компьютеров IBM PC. Современные микросхемы - UART 16450, 16550 и 16550A, изготовленные по новой технологии, позволяют достичь более высокой скорости обмена данными, а также обладают новыми аппаратными возможностями. В этой главе мы рассмотрим основные различия между 8250 и новыми микросхемами, а также приведем дополнительную информацию по программированию UART 16550A. Опишем основные возможности различных микросхем UART:
Как определить тип микросхемы UARTКак же определить, какая из этих микросхем установлена на вашем асинхронном адаптере? Кроме возможности заглянуть в документацию существует еще один способ (для программы этот способ единственный, ведь она не может ознакомиться с документацией). Фактически этот способ основан на различиях в особенностях микросхем UART. Ниже приведены особенности микросхем UART различных типов:
Согласно этим особенностям микросхем UART возможен следующий алгоритм определения их типа:
Теперь приведем программу, реализующую изложенный алгоритм. В данной программе используются созданные нами функции is_UART_8250() и is_UART_FIFO(). Первая позволяет определить по отсутствию регистра расширения микросхему UART 8250, а вторая по особенностям реализации внутреннего буфера данных различает остальные типы микросхем. // TST_UART.C // Программа определения типа микросхемы UART асинхронного адаптера #define UART_8250 1 #define UART_16450 2 #define UART_16550 3 #define UART_16550A 4 void main(void) { // номер асинхронного порта может быть 0 для COM1 // или 1 для COM2 int port = 0; int test; printf("\n(c) Frolov G.V. 1992. " "Программа определения типа UART\n\n"); printf("\Введите номер асинхронного порта (COM1 - 0, COM2 - 1):"); scanf( "%d", &port ); if(( port != 0 ) && ( port != 1 )){ printf( "асинхронный порт COM%d не поддерживается\n", port ); exit( -1 ); } // проверяем, является ли микросхема UART - UART 8250 if( is_UART_8250(port) == UART_8250 ) { printf("Обнаружена микросхема UART 8250\n"); exit(0); } // проверяем другие типы микросхем UART if(( test = is_UART_FIFO(port) ) == UART_16550A ) { printf("Обнаружена микросхема UART 16550A\n"); exit(0); } else if(test == UART_16550) { printf("Обнаружена микросхема UART 16550\n"); exit(0); } printf("Обнаружена микросхема UART 16450\n"); } /** *.Name is_UART_8250 *.Title Определяет тип UART. * *.Descr Эта функция определяет тип микросхемы, * используемый данным последовательным асинхронным * адаптером (UART). * *.Proto int is_UART_8250( int port ); * *.Params int port - номер асинхронного адаптера: * 0 - COM1, 1 - COM2 * *.Return Для UART 8250 - возвращает константу UART_8250, * в остальных случаях возвращает 0 * *.Sample tst_uart.c **/ int is_UART_8250( int port ) { int save_scr, in_scr; // сохраняем значения регистра расширения save_scr = inp( 0x3ff - 0x100 * port ); // записываем в регистр расширения число 0x5A outp( 0x3ff - 0x100 * port, 0x5A ); // считываем регистр расширения in_scr = inp( 0x3ff - 0x100 * port ); // сохранилось ли записанное число? if( in_scr != 0x5A ) { // если нет, значит, регистр расширения отсутствует и, // следовательно, тип микросхемы - UART 8250 // восстанавливаем значение регистра расширения outp( 0x3ff - 0x100 * port, save_scr ); return( UART_8250 ); } // записываем в регистр расширения другое число - 0xA5 outp( 0x3ff - 0x100 * port, 0xA5 ); // считываем регистр расширения in_scr = inp( 0x3ff - 0x100 * port ); // восстанавливаем значение регистра расширения outp( 0x3ff - 0x100 * port, save_scr ); // сохранилось ли записанное число? if( in_scr != 0xA5 ) // если нет, регистр расширения отсутствует и, // следовательно, тип микросхемы - UART 8250 return( UART_8250 ); // в противном случае регистр расширения есть и надо выполнить // дальнейшее тестирование для определения типа UART return( 0 ); } /** *.Name is_UART_FIFO *.Title Определяет тип UART. * *.Descr Эта функция определяет тип микросхемы, * используемой данным последовательным асинхронным * адаптером (UART). * *.Proto int is_UART_FIFO( int port ); * *.Params int port - номер асинхронного адаптера: * 0 - COM1, 1 - COM2 * *.Return для UART 164550 - возвращает константу UART_16450, * для UART 16550 - возвращает константу UART_16550, * для UART 16550A - возвращает константу UART_16550A * *.Sample tst_uart.c **/ int is_UART_FIFO( int port ) { int save_iir, in_iir; // сохраняем значение регистра определения прерывания save_iir = inp( 0x3fa - 0x100 * port ); // разрешаем использование FIFO outp( 0x3fa - 0x100 * port, 0x1 ); // читаем значение регистра определения прерывания in_iir = inp( 0x3fa - 0x100 * port ); // восстанавливаем значение регистра определения прерывания outp( 0x3fa - 0x100 * port, 0x0 ); // если бит D6 содержит единицу, значит, мы имеем UART 16550A if(( in_iir & 0x40 ) == 1 ) return( UART_16550A ); // если бит D7 содержит единицу, значит, мы имеем UART 16550 if(( in_iir & 0x80 ) == 1 ) return( UART_16550 ); // если биты D7 и D6 содержат нули, значит, мы имеем UART 16450 // (буфер FIFO отсутствует) return( UART_16450 ); } Изменения в регистрах UART 16550AВ этой главе мы рассмотрим изменения в форматах регистров UART 16550A по сравнению с UART 8250. Начнем с регистра идентификации прерывания. Этот регистр доступен только для чтения. По сравнению с UART 8250 в нем добавлены два бита - D6 и D7, которые показывают статус буфера FIFO. Если биты D7 и D6 оба равны единице, то разрешено использование буферизации (FIFO). Если же только бит D7 содержит единицу, это означает, что вы имеете дело с микросхемой UART 16550. В ней режим буферизации реализован с ошибками, и использовать его не надо. Бит D3 используется для сигнализации таймаута. Он устанавливается в том случае, если буфер FIFO содержит данные, которые необходимо прочитать. Это случается после небольшого промежутка времени, если в буфер не поступают новые символы. Если бит D3 содержит единицу, то бит D2 также содержит единицу. Это означает, что буфер приемника содержит данные. Для микросхем UART 8250 и 16450 биты D3, D6 и D7 всегда содержат нули. Биты D4 и D5 не используются во всех рассматриваемых микросхемах. Для управления режимом буферизации UART 16550A имеет дополнительный регистр - регистр управления буферизацией FIFO. Этот регистр разделяет общий адрес с регистром идентификации прерываний - base_adr + 2. Но в отличие от регистра идентификации прерываний, доступного только для чтения, этот регистр доступен только для записи. Итак, регистр управления режимом буферизации имеет следующий формат: 7 6 5 4 3 2 1 0 --T-T-T-T-T-T-T-¬ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ LT+T+T+T+T+T+T+T- ¦ ¦ LT- ¦ ¦ ¦ L= Разрешение буферизации. При D0, равном ¦ ¦ ¦ ¦ ¦ ¦ единице, буферизация разрешена ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ L=== Сброс приемного буфера ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ L===== Сброс буфера передатчика ¦ ¦ ¦ ¦ ¦ ¦ ¦ L======= Выбор режима прямого доступа ¦ ¦ ¦ ¦ ¦ L========== Не используются ¦ ¦ ¦ L============= Триггер приемника (LSB) ¦ L=============== Триггер приемника (MSB)
Как использовать буферизацию?Обычно без использования буферизации UART генерирует прерывание всякий раз, когда передается или принимается очередной символ. В результате при скорости 2400 бод прерывания происходят с частотой 240 прерываний за одну секунду. Это не очень много, но при увеличении скорости до максимально возможной - 115200 бод за секунду - происходит уже 11520 прерываний. 11520 прерываний за одну секунду - это уже много. При использовании буферизации при той же скорости количество прерываний можно резко сократить. Так, при генерации прерываний каждые 14 символов (бит регистра управления буферизацией D7 = 1, D6 = 1) за секунду произойдет только 822,86 прерываний. При приеме данных наблюдается аналогичная картина, за исключением того, что можно изменить число символов, которое необходимо получить для генерации прерывания. Когда принимается необходимое число символов генерируется прерывание, но все остальные символы, поступающие в приемник, также размещаются в буфере. При этом прерывание при получении данных не очищается до тех пор, пока в буфере не станет меньше символов, чем определено битами D7, D6. При программировании UART 16550A для использования режима буферизации необходимо выполнить следующие действия: ¦ Когда для определения причины прерывания считывается регистр идентификации прерывания, надо использовать только три младших бита. Для этого можно замаскировать полученное значение числом 07h ¦ После обычной инициализации UART надо
разрешить использование буферизации, записав в
регистр управления буферизацией число 0C7h. При
этом будет разрешено использование буферизации,
произведена очистка буферов приемника и
передатчика, а также вызвана генерация
прерываний при записи в буфер приемника больше 14
символов. После этого следует прочитать
содержимое регистра идентификации прерываня (по
тому же адресу). Если бит D6 этого регистра не
установлен, то ваша микросхема UART не является
16550A. И вам следует запретить использование
буферизации, записав ноль в регистр управления
буферизацией. |