Работа с устройствами
В следующих разделах обсуждаются:
Прерывания
Системы реального времени
должны уметь работать с внешними устройствами. Часто желательно, чтобы
real-time процесс непосредственно обрабатывал прерывания, исходящие от
устройства. Эта возможность, наряду с прямым вводом-выводом и функциями
проецирования памяти, позволяет пользовательскому процессу полностью контролировать
устройство, исключая, таким образом необходимость написания драйвера, работающего
в режиме ядра.
Управление прерываниями
Интерфейсы RTX-функций управления
прерываниями позволяют приложению обслужить прерывания от устройств, соединенных
с компьютером. Как и в случае процедуры-обработчика срабатывания таймера,
Вы можете назначить прерыванию процедуру-обработчик.
Win32 и RTSS процессы могут
назначить такую процедуру-обработчик с помощью функции RtAttachInterruptVector.
Приоритет, присвоенный потоку-обработчику, определяет приоритет исполнения
обработчика прерывания в Win32 и RTSS подсистемах.
Когда обработчик прерывания
присоединяется к прерыванию, создается поток, который будет исполняться
при возникновении прерывания. Процедура-обработчик прерывания в RTX аналогична
Interrupt Service Routine (ISR) в драйвере устройства. Когда возникает
прерывание, его источник маскируется, и, если приоритет поток-обработчик
прерывания выше, чем у потока, исполняющегося в настоящий момент, начинает
выполняться поток-обработчик. После возврата из обработчика источник прерываний
демаскируется и поток-обработчик подвешивается (suspended).
API
Следующие функции служат
для доступа к RTX-службам прерываний:
- RtAttachInterruptVector –
- назначает
поток – обработчик указанному прерыванию
- RtReleaseInterruptVector -
- “отсоединяет”
обработчик от прерывания, освобождая таким образом прерывание
- RtEnableInterrupts -
- разрешает обработку всех прерываний, которые присоединены к процессу
- RtDisableInterrupts -
- запрещает обработку всех прерываний, которые присоединены к процессу
Общие замечания по программированию
- Поток-обработчик может быть
в любой момент вытеснен потоком с большим приоритетом
- Можно запретить обработку некоторых
прерываний, присоединенных к RTX процессу подняв приоритет исполняющегося
в настоящий момент потока.
- Обработчик прерывания, освобождающий
объект, может удовлетворить условиям wait-функции потока с более высоким
приоритетом. В этом случае возобновится выполнение потока с более высоким
приоритетом и завершение обработчика отложится, все это время прерывание
будет маскировано
- Прерывания от таймера никогда
не маскируются прерываниями с более высоким приоритетом, поэтому они являются
по существу, прерываниями с самым высоким приоритетом. Но эти прерывания
маскируются с помощью RtDisableInterrupts.
Замечания по программированию в Win32 подсистеме
- Все процессы RTSS подсистемы
имеют приоритет над всеми процессами Win32 подсистемы, поэтому любая критичная
по времени обработка прерываний должна осуществляться обработчиком, исполняющимся
как RTSS, а не Win32 процесс.
- RTX-потоки прерываний
в Win32 подсистеме ставятся в очередь планировщиком Windows NT. Это может
привести к недетерминистичным задержкам в исполнении обработчика прерываний.
Использование RtAttachInterruptVector
Для присоединения вектора
прерывания к обработчику надо воспользоваться функцией RtAttachInterruptVector.
При вызове надо указать параметры шины. Для шин с автоматической конфигурацией,
таких как PCI, можно получить информацию о параметрах из регистра Windows
NT, в котором находятся присвоенные устройству значения ресурсов шины.
Для ISA или PC internal bus параметры
необходимо указывать вручную.
Использование RtReleaseInterruptVector
В отличие от выгрузки
драйвера, RTX-приложение может завершить работу и оставить работающее устройство,
пытающееся передать прерывания потоку-обработчику. Хотя библиотека RTX
обычно производит очистку за завершившимся приложением, случается, что
завершающееся приложение может завершиться незаметно для библиотеки. Во
избежании таких ситуаций надо использовать функцию RtReleaseInterruptVector,
которая отсоединяет ранее присоединенное прерывание.
Пример демонстрирует работу с прерываниями и портами ввода/вывода.
Порты ввода/вывода
Системы реального времени
должны иметь возможность читать и писать данные в устройства. RTX-интерфейсы
портов ввода/вывода позволяют осуществлять это без необходимости переключения
в режим ядра. Отпадает необходимость написания драйвера для каждого устройства,
к которому необходимо получить доступ. Кроме того, устраняются задержки,
связанные с запросом обслуживания драйвером при каждом обращении к устройству.
Порт ввода/вывода предоставляет
альтернативный метод прямого общения с аппаратурой. В адресном пространстве
ввода/вывода у процессоров Intel каждый адрес представляет собой 8-ми битный
“порт”, который обычно соответствует 8-ми битному управляющему регистру
устройства. Хотя последовательные адреса могут представлять байты в многобайтовом
порту, разработчики обычно используют подход, при котором существует однобайтовый
порт, а многобайтовые величины обычно вводятся, как последовательные однобайтовые
записи в порт.
Перед любым вводом/выводом
из портов необходимо разрешить доступ к портам. Это осуществляется посредством
функции RtEnablePortIo,
параметром которой является диапазон портов ввода/вывода, к которым надо
получить доступ. После этого для передачи данных можно использовать функции
RtWrite* и RtRead*.
API управления портами ввода/вывода
Следующие функции служат для управления портами ввода/вывода:
- RtEnablePortIo -
- разрешает прямой доступ к портам ввода/вывода для указанного диапазона адресов
- RtDisablePortIo -
- запрещает прямой доступ к портам ввода/вывода для указанного диапазона адресов
API передачи данных
Следующие функции служат
для передачи данных из/в портов ввода/вывода:
- RtReadPortUchar,RtReadPortUshort,RtReadPortUlong -
- напрямую читают одно-, двух-, четырехбайтовые данные из указанного порта
- RtWritePortUchar,RtWritePortUshort,RtWritePortUlong -
- напрямую пишут одно-, двух-, четырехбайтовые данные в указанный порт
- RtReadPortBufferUchar,RtReadPortBufferUshort,RtReadPortBufferUlong -
-
копируют одно-, двух-, четырехбайтовые данные из указанного порта ввода/вывода
в буфер
- RtWritePortBufferUchar,RtWritePortBufferUshort,RtWritePortBufferUlong -
- копируют одно-, двух-, четырехбайтовые данные из буфера в указанный порт
ввода/вывода
Общие замечания по программированию
Интерфейсы RTX написаны на
ассемблере и используют вызов _ _stdcall. Это
означает, что подпрограмма ответственна за очистку стека. Вы не должны
использовать другие другие соглашения о вызове (это может вызвать проблемы
с компилятором).
Проецирование физической памяти
Существование адресного пространства
ввода/вывода зависит от архитектуры процессора. Некоторые архитектуры,
поддерживаемые Windows NT, основаны на процессорах, не имеющих отдельного
пространства ввода/вывода. Их порты проецируются в адреса памяти. Эти архитектуры
могут использовать функции проецирования памяти для обеспечения доступа
к физической памяти контроллеров и другой аппаратуры.
Проецирование физической
памяти может также использоваться для предоставления процессам доступа
к физическим участкам памяти в адресном пространстве CPU.
Интерфейс проецирования
физической памяти проецирует участок физической памяти на виртуальное адресное
пространство процесса. Это позволяет приложению получать доступ к участкам
физической памяти непосредственно, как если бы они были буферами в приложении.
Эти интерфейсы полезны в программах, которым нужен доступ к памяти устройств
или регистрам, которые спроецированы на физическре адресное пространство
CPU.
API
Следующие функции служат
для проецирования памяти:
- RtMapMemory –
- проецирует участок адресов физической памяти на виртуальное адресное пространство процесса.
- RtUnmapMemory -
- убирает ранее спроецированнный участок адресов физической памяти из виртуального адресного пространства процесса.
Общие замечания по программированию
Не существует ограничений
или запретов на спроецированный участок памяти. В случае удачного проецирования
обеспечивается указанные базовый адрес и длина области. Не следует проецировать
и изменять адресное пространство Windows NT, т.к. это может привести к
ошибкам в операционной системе.
Замечания по программированию в Win32 подсистеме
Попытка доступа к области,
выходящей за пределы спроецированного адресного пространства, вызовет исключение.
Пример демонстрирует проецирование физической памяти.
Проецирование непрерыного участка памяти
Некоторые устройства, особенно
работающие с DMA, требуют, чтобы их буферы находились в физически непрерывном
участке памяти в адресном пространстве CPU. Кроме того, эти устройства
должны получать доступ к буферам памяти используя настоящий физический
адрес, а не виртуальный адрес, используемый Win32 или RTSS процессом.
Для выделения физически непрерывного
участка памяти и перевода виртуального адреса в физический используются
функции RtAllocateContiguousMemory и RtGetPhysicalAddress соответственно.
API
Следующие функции служат
для работы с физически непрерывным участком памяти:
- RtAllocateContiguousMemory -
- выделяет физически непрерывный участок памяти и проецирует эту память в виртуальное адресное пространство процесса
- RtFreeContiguousMemory -
- высвобождает ранее выделенный физически непрерывный участок памяти
- RtGetPhysicalAddress -
- возвращает
физический адрес по виртуальному адресу ранее выделенного физически непрерывного
участка памяти
Замечания по программированию
- Непрерывный участок памяти всегда
выделяется из non-paged пула памяти Windows NT. Этот пул памяти сравнительно
мал и вскоре после загрузки системы становится фрагментированным в результате
выделения памяти драйверам и другим подсистемам Windows NT. Чтобы избежать
неудач при попытках выделить большой участок памяти, надо делать это сразу
после загрузки и/или вообще минимизировать такие выделения
- В Win32 подсистеме функция RtGetPhysicalAddress
работает только с адресами, полученными в результате вызова RtAllocateContiguousMemory.
Данный пример
демонстрирует выделение непрерывного участка памяти.
Ввод/вывод по шине
Функции RtGetBusDataByOffset,
RtTranslateBusAddress и
RtSetBusDataByOffset облегчают разработку
RTSS-драйверов устройств. Каждая из функций упрощает сбор информации и/или
установку устройства.
RtGetBusDataByOffset
используется преимущественно для поддержки привязывания драйвера к устройству.
Она получает информацию об устройстве (такую как номер шины, interrupt
level, interrupt vector), которая затем используется при вызове RtAttachInterruptVector.
Например, с помощью вызова RtGetBusDataByOffset
можно сканировать PCI шину, находить определенное устройство и затем возвращать
номер шины, на которой находится устройство, interrupt level и interrupt
vector для этой шины.
Установка параметров устройства
осуществляется посредством вызова функции RtSetBusDataByOffset.
Эта функция полезна при очистке или установке статусных регистров, слотов
и т.п. при инициализации устройства.
RtTranslateBusAddress
используется при трансляции диапазона адресов устройства в логическое адресное
пространство драйвера.
Назад | Содержание | Вперед