Разработка программ-драйверов и тестирующих программ.

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

При выборе языка программирования необходимо обеспечить:

• программный доступ к устройствам ввода/вывода и к памяти,

• обработку прерываний,

• битовые логические операции.

• управление системным таймером.

Для этих целей наиболее удобен язык Си.

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

Разработанное программное обеспечение для контроллера параллельного обмена опирается на следующие правила:

• устройство сопряжения выполняет определенные функции, каждая из которых реализуется в виде отдельного драйвера; на более низком уровне (управление отдельными разрядами отдельных регистров) разделения на программные модули не производится;

• устройство имеет регистр управления или состояния, в котором каждый бит или группа битов соответствуют определенным режимам работы устройства; маски этих битов (позиции в байте или слове) определяются перед запуском драйвера и используются в битовых операциях для установки или проверки;

• в качестве глобальной переменной определяется первый ("базовый") адрес устройства в адресном пространстве, а его остальные адреса вычисляются добавлением к базовому адресу величины смещения, оцениваемой номером порта.

Контроллер параллельного обмена (КПО) содержит 7 программно-доступных байтовых двунаправленных портов и регистр управляющего слова. Таким образом, на нижнем уровне программирования КПО необходимо реализовать три функции: запись управляющего слова, запись данных в любой порт и чтение данных из любого порта.

На языке Си они выглядят так:

// *** Функция записи управляющего слова

// CW_ADDR — адрес регистра управляющего слова

// cw — байт управляющего слова

outportb (CW_ADDR, cw);

// *** Функция записи данных в порт

// BASE_ADDR — базовый адрес КПО (адрес порта 0)

// port — номер порта (0...6)

// data — байт данных

outportb (BASE_ADDR + port, data):

// *** Функция чтения данных из порта

// BASE_ADDR — базовый адрес КПО (адрес порта 0)

// port — номер порта (0...6)

// data — байт данных

data = inportb (BASE_ADDR + port):

Программа тестирования записи данных КПО.

Последовательно записывается во все порты код 55Н и контролируется правильность записи. При этом все порты, кроме тестируемого, переводятся в режим чтения.

// *** Программа тестирования КПО ***

#include <STDIO.H>

#include <DOS.H>

#define NPORT 7 // Число портов КПО

// Глобальные переменные

unsigned BASE_ADDR; // Базовый адрес КПО

unsigned CW_ADDR; // Адрес регистра управляющего слова

void main (void)

{

unsigned i;

unsigned char data = 0х55;

for (i=0; i<NPORT; i++)

{

outportb (CW_ADDR, 1 « i); // Установка конфигурации:

// i—ый порт на вывод остальные на ввод

outportb (BASE_ADDR + i, data); // Запись данных

if (inportb (BASE_ADDR + i) != data)

printf ("\n\tПорт %d неисправен", i);

else

printf ("\n\tПорт %d исправен", i);

}

}

//*** Конец программы

Каждому порту КПО соответствует один бит управляющего слова. Единица в этом бите устанавливает порт в режим передачи данных, а ноль — в режим приема. Естественно, что когда порт находится в режиме передачи, ничто нe мешает прочитать его содержимое, контролируя таким образом правильность вывода. Именно это свойство КПО использовано в программе его тестирования.

В программе тестирования для последовательной установки портов в режим вывода использовалась операция сдвига единицы на число разрядов, равное номеру порта. Очевидно, что при этом данный порт устанавливается на вывод, а все остальные — на ввод.

Для организации протоколов обмена с "быстрым" устройством — модулем ОЗУ емкостью 16 КБайт с байтовой организацией разработана программа-драйвер обмена батом данных по произвольному адресу.

Модуль ОЗУ подключен к портам КПО следующим образом:

Р0.0 ... Р0.7 — младший байт шины адреса: А0 ... А7,

Р1.0 ... Р1.5 — старшие линии шины адреса: А8 ... А13,

Р1.6 — сигнал разрешения записи -WE,

Р1.7 — сигнал разрешения выхода -ОЕ,

Р2.0 ... Р2.7 — шина данных: D0 ... D7.

Перед вызовом драйверов должно быть предварительно установлено управляющее слово КПО — 03Н (порты 0 и 1 — на вывод, порт 2 — на ввод).

// *** Драйвер модуля ОЗУ ***

#define WE 0х40 // Маска бита WE (бит 6 порта 1)

#define ОЕ 0х80 //Маска бита ОЕ (бит 7 порта 1)

#define АН 0x3F // Маска линий А8...А13 шины адреса (биты 0...5 порта 1)

// Глобальные переменные

unsigned BASE_ADDR: // Базовый адрес КПО

unsigned CW_ADDR; // Адрес регистра управляющего слова

// Прототипы функций

void Write_RAM (unsigned addr, unsigned char data);

unsigned char Read_RAM (unsigned addr);

// Функция записи байта данных

void Write_RAM (unsigned addr, unsigned char data)

{

outportb (CW_ADDR, 7); // Порты 0...2 — на вывод

outportb (BASE_ADDR, addr); // Младший байт адреса

outportb (BASE_ADDR+1, (addr » 8) & AH | OE & (~WE));

// Старшие линии адреса, OE=1, WE=0

outportb (BASE_ADDR+2, data); // Установка данных

outportb (BASE_ADDR+1, (addr » 8) & AH | OE | WE);

// WE=1

outportb (CW_ADDR, 3); // Порты 0,1 — на вывод, порт 2 — на ввод

}

// Функция чтения байта данных

unsigned char Read_RAM (unsigned addr)

{

unsigned char data;

outportb (BASE_ADDR, addr); // Младший байт адреса

outportb (BASE_ADDR+1, (addr » 8) & AH & (~OE) | WE);

// Старшие линии адреса, OE=0, WE=1

data = inportb (BASE_ADDR+2); // Чтение данных

outportb (BASE_ADDR+1, (addr » 8) & AH | OE | WE);

// OE=1

return (data);

}

//*** Конец драйвера

Важно обратить внимание на управление отдельными битами порта 1. Для этого использованы логические операции с прямыми и инверсными масками соответствующих битов. Кроме того, следует отметить, что подключение к порту 2 двунаправленной шины данных требует изменения направления передачи по этому порту, то есть перепрограммирования управляющего слова (в отличие от случаев подключения однонаправленных линий, когда управляющее слово устанавливается в начале программы и больше не модифицируется).

Наши рекомендации