Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Модемы и факс-модемы. Программирование для MS-DOS и Windows.

© Александр Фролов, Григорий Фролов
Том 16, М.: Диалог-МИФИ, 1993.

[Назад] [Содеожание] [Дальше]

5.4. Современные микросхемы UART

Микросхема UART 8250 в ее исходном виде использовалась только в старых моделях компьютеров IBM PC и IBM XT. Современные микросхемы - UART 16450, 16550 и 16550A, изготовленные по новой технологии, позволяют достичь более высокой скорости обмена данными, а также обладают новыми аппаратными возможностями. В этой главе мы рассмотрим основные различия между 8250 и новыми микросхемами, а также приведем дополнительную информацию по программированию UART 16550A.

Опишем основные возможности различных микросхем UART:

  • 8250 (иногда называют 8250-B): Использовалась на первых моделях компьютеров IBM PC и IBM XT
  • 16450 (иногда обозначают как 8250-A): Эта микросхема используется в основном для IBM PC/AT, так как имеет большую производительность. Фактически это микросхема UART 8250, но изготовленная с использованием новой технологии. Микросхема UART 16450 дополнена регистром расширения (scratch register), имеющим адрес 3FFh (base_adr + 7). В ней также устранены ошибки в регистре разрешения прерываний и добавлена возможность перевода линии OUT2 во время проведения тестов в высокоимпедансное состояние
  • 16550: Практически полностью соответствует UART 16450. Добавлена возможность внутренней буферизации передаваемых и принимаемых данных. Буферы выполнены по схеме FIFO (First In First Out - первый вошел, первым вышел) или, другими словами, в виде очереди. При использовании буферизации можно заметно уменьшить число прерываний, вырабатываемых асинхронным портом. Однако из-за ошибки в микросхеме эту возможность лучше не использовать - можно потерять отдельные символы. В общем случае микросхема 16550 более быстрая, чем 16450. Дополнительно 16550 дает возможность использовать несколько каналов прямого доступа (DMA channels)
  • 16550A (иногда обозначают как 16550AN) Соответствует 16550, но в ней исправлены ошибки реализации буфера FIFO. Эта микросхема дает возможность использования нескольких каналов прямого доступа. 16550A, как правило, используется в компьютерах с процессорами 80386/486 и в компьютерах с RISC-архитектурой. Заметим, что, если вы хотите работать на скоростях больших, чем 9600 бит/с, вам желательно использовать именно эту микросхему.

    5.4.1. Как определить тип микросхемы UART

    Как же определить, какая из этих микросхем UART установлена на вашем асинхронном адаптере? Кроме возможности заглянуть в документацию, существует еще один способ. Фактически этот способ основан на различиях в особенностях микросхем UART. Ниже приведены особенности микросхем UART различных типов:

  • UART 8250 не имеет регистра расширения
  • UART 16450 не имеет внутренних буферов FIFO
  • UART 16550 имеет внутренние буфера FIFO, но с ошибками. Бит D7 регистра управления прерываниями (регистр IIR) равен единице, а бит D6 - нулю
  • UART 16550A не содержит ошибок при реализации FIFO. Биты D7 и D6 регистра управления прерываниями (регистр IIR) равны единице.

    Согласно этим особенностям микросхем UART возможен следующий алгоритм определения их типа:

  • Читаем и сохраняем значение регистра расширения. Адрес регистра расширения определяем как базовый адрес плюс семь (base_adr + 7)
  • Записываем в регистр расширения какое-либо число, например, 0A5h
  • Снова считываем значение регистра расширения и сравниваем его с числом 0A5h, записанным в него ранее. Если эти значения не равнозначны, значит регистр расширения отсутствует и, следовательно, тип проверяемой микросхемы UART - 8250
  • Запоминаем в регистре расширения другое число, например, 5Ah
  • Снова считываем значение регистра расширения и сравниваем его с ранее записанным числом. Если эти значения не одинаковы, значит регистр расширения отсутствует и, следовательно, тестируемая микросхема UART 8250
  • Восстанавливаем величину, изначально хранившуюся в регистре расширения
  • Считываем и сохраняем значение регистра управления прерываниями
  • Записываем единицу в регистр управления режимом буферизации (регистр FCR, подробно описан ниже)
  • Считываем значение регистра управления прерываниями. Если бит D7 сохраненного регистра управления прерываниями содержит нулевое значение, запоминаем единицу в регистре FCR
  • Если бит D6 регистра управления прерываниями содержит единицу, тип микросхемы UART - 16550A
  • Если бит D7 регистра управления прерываниями содержит единицу, тестируемая микросхема - UART 16550
  • В противном случае мы имеем микросхему UART 16450.

    5.4.2. Программа для определения типа микросхемы UART

    Теперь приведем программу TST_UART, реализующую изложенный алгоритм. В данной программе используются созданные нами функции is_UART_8250() и is_UART_FIFO(). Первая позволяет определить по отсутствию регистра расширения микросхему UART 8250, а вторая по особенностям реализации внутреннего буфера данных различает остальные типы микросхем.

    Исходный текст программы TST_UART представлен в листинге 5.1.

    Листинг 5.1. Файл 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-1994.   "
    		   "Программа определения типа 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
    *
    *.Descr        Функция определяет тип микросхемы,
    *              используемый данным последовательным асинхронным
    *              адаптером (UART).
    *
    *.Proto        int is_UART_8250( int port );
    *
    *.Params       int port - номер асинхронного адаптера:
    *                 0 - COM1, 1 - COM2
    *
    *.Return       Для UART 8250 - возвращает константу UART_8250,
    *              в остальных случаях возвращает 0
    **/
    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
    *
    *.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
    **/
    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 );
    }
    

    5.4.3. Изменения в регистрах 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. Но в отличие от регистра идентификации прерываний, доступного только для чтения, этот регистр доступен только для записи.

    Итак, регистр управления режимом буферизации имеет следующий формат:

    D0 Установка этого бита в единицу разрешает использование буферизации для принимаемых и передаваемых данных. Этот бит должен содержать единицу, если какой-либо из других битов содержит единицу

    D1 Сброс приемного буфера. При установке этого бита в единицу буфер приемника очищается. Затем бит автоматически сбрасывается в ноль

    D2 Сброс буфера передатчика. При установке этого бита в единицу буфер передатчика очищается. Затем бит автоматически сбрасывается в ноль

    D3 Выбор режима прямого доступа. Бит не используется на большинстве последовательных асинхронных адаптеров

    D4-D5 Не используются

    D7, D6 Управление прерываниями от приемника. Если буферизация отсутствует, то прерывание происходит всякий раз при приеме нового символа. С разрешенной буферизацией UART может генерировать прерывание при получении заданного количества символов:

    Биты D7 D6

    Количество символов, байт

    00

    1

    01

    4

    10

    8

    11

    14

    5.4.4. Как использовать буферизацию?

    Обычно без использования буферизации UART генерирует прерывание всякий раз, когда передается или принимается очередной символ. В результате при скорости 2400 бит/с прерывания происходят с частотой 240 прерываний за одну секунду. Это не очень много, но при увеличении скорости до максимально возможной - 115200 бит/с за секунду - происходит уже 11520 прерываний. 11520 прерываний за одну секунду - это уже много. Использование буферизации позволяет при той же скорости резко сократить количество прерываний. Так, при генерации прерываний каждые 14 символов (бит регистра управления буферизацией D7 = 1, D6 = 1) за секунду произойдет около 823 прерываний.

    При приеме данных наблюдается аналогичная картина, за исключением того, что можно изменить число символов, которое необходимо получить для генерации прерывания. Когда принимается необходимое число символов, генерируется прерывание, но все остальные символы, поступающие в приемник, также размещаются в буфере. При этом прерывание при получении данных не очищается до тех пор, пока в буфере не станет меньше символов, чем определено битами D7 и D6.

    При программировании UART 16550A для использования режима буферизации необходимо выполнить следующие действия:

  • Когда для определения причины прерывания считывается регистр идентификации прерывания, надо использовать только три младших бита. Для этого можно замаскировать полученное значение числом 07h
  • После обычной инициализации UART надо разрешить использование буферизации, записав в регистр управления буферизацией число 0C7h. При этом будет разрешено использование буферизации, выполнена очистка буферов приемника и передатчика, а также вызвана генерация прерываний при записи в буфер приемника больше 14 символов. После этого следует прочитать содержимое регистра идентификации прерывания (по тому же адресу). Если бит D6 этого регистра не установлен, то ваша микросхема UART не является 16550A. И вам следует запретить использование буферизации, записав ноль в регистр управления буферизацией.

    Операционная система Windows 3.1 поддерживает новые возможности асинхронных последовательных адаптеров, созданных на основе микросхемы UART 16550A. Поэтому, когда вы пишете приложение для Windows, нет необходимости самостоятельно определять тип микросхемы UART.

    [Назад] [Содеожание] [Дальше]

  •