Предоставление доступа в пользовательском режиме к GPIO, I2C и SPI
В Windows 10 и более поздних версиях API предоставляются с прямым доступом из пользовательского режима к входным и выходным данным общего назначения (GPIO), Межинконференционным каналом (I2C), последовательным периферийным интерфейсом (SPI) и универсальным асинхронным приемником-приемником (UART). Доски разработки, такие как Raspberry Pi 2, предоставляют подмножество этих подключений, что позволяет расширить базовый вычислительный модуль с пользовательским каналом для решения конкретного приложения. Эти низкоуровневые автобусы обычно совместно используются с другими критически важными функциями подключения, с только подмножеством пин-кодов GPIO и автобусов, предоставляемых на заголовках. Чтобы сохранить стабильность системы, необходимо указать, какие закрепления и автобусы безопасны для изменения приложениями в пользовательском режиме.
В этом документе описывается, как указать эту конфигурацию в advanced Configuration and Power Interface (ACPI) и предоставить средства для проверки правильности указания конфигурации.
Внимание
Аудитория этого документа — это единый расширяемый интерфейс встроенного ПО (UEFI) и разработчики ACPI. Предполагается, что некоторые знания об использовании ACPI, исходном языке ACPI (ASL) и spbCx/GpioClx.
Доступ в режиме пользователя к автобусам низкого уровня в Windows работает через существующие GpioClx
и SpbCx
платформы. Новый драйвер с именем RhProxy, доступный в Windows IoT Core и Windows Enterprise, предоставляет GpioClx
и SpbCx
ресурсы в пользовательском режиме. Чтобы включить API, узел устройства для rhproxy должен быть объявлен в таблицах ACPI с каждым из ресурсов GPIO и SPB, которые должны предоставляться в пользовательском режиме. В этом документе рассматривается создание и проверка ASL.
ASL по примеру
Давайте рассмотрим объявление узла устройства rhproxy в Raspberry Pi 2. Сначала создайте объявление устройства ACPI в области \_SB.
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
- _HID — идентификатор оборудования. Задайте для этого идентификатор оборудования для конкретного поставщика.
- _CID — совместимый идентификатор. Должен быть "MSFT8000".
- _UID — уникальный идентификатор. Задайте значение 1.
Затем мы объявляем каждый из ресурсов GPIO и SPB, которые должны предоставляться в пользовательском режиме. Порядок объявления ресурсов важен, так как индексы ресурсов используются для связывания свойств с ресурсами. Если доступно несколько шин I2C или SPI, первый объявленный автобус считается шиной по умолчанию для этого типа и будет экземпляром, возвращаемым методами Windows.Devices.I2c.I2cController и Windows.Devices.SpiController.GetDefaultAsync()
SPI
Raspberry Pi имеет два открытых автобуса SPI. SPI0 имеет две аппаратные линии выбора микросхем, и SPI1 имеет одну аппаратную линию выбора микросхемы. Для каждой линии выбора микросхемы для каждой шины требуется одно объявление ресурса SPISerialBus(). Следующие два объявления ресурсов SPISerialBus предназначены для двух линий выбора микросхем в SPI0. Поле DeviceSelection содержит уникальное значение, которое драйвер интерпретирует как идентификатор линии аппаратного чипа. Точное значение, которое вы помещаете в поле DeviceSelection, зависит от того, как драйвер интерпретирует это поле дескриптора подключения ACPI.
Примечание.
В этой статье содержатся ссылки на термин "раб" — термин, который корпорация Майкрософт не поддерживает и перестала использовать в новых продуктах и документации. Когда этот термин будет удален из программного обеспечения, мы удалим его из статьи.
// Index 0
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE0 - GPIO 8 - Pin 24
0, // Device selection (CE0)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 1
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE1 - GPIO 7 - Pin 26
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
Как программное обеспечение знает, что эти два ресурса должны быть связаны с одной шиной? Сопоставление понятного имени шины и индекса ресурсов указывается в DSD:
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},
При этом создается шина с именем SPI0 с двумя линиями выбора микросхем — индексами ресурсов 0 и 1. Для объявления возможностей шины SPI требуется несколько дополнительных свойств.
Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },
Свойства MinClockInHz и MaxClockInHz указывают минимальные и максимальные скорости часов, поддерживаемые контроллером. API не позволит пользователям указывать значения за пределами этого диапазона. Скорость часов передается драйверу SPB в поле _SPE дескриптора подключения (раздел ACPI 6.4.3.8.2.2).
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},
Свойство SupportedDataBitLengths содержит длину бита данных, поддерживаемую контроллером. Несколько значений можно указать в разделенном запятыми списке. API не позволит пользователям указывать значения за пределами этого списка. Длина бита данных передается драйверу SPB в поле _LEN дескриптора подключения (раздел ACPI 6.4.3.8.2.2).
Эти объявления ресурсов можно рассматривать как "шаблоны". Некоторые поля фиксируются при загрузке системы, а другие динамически задаются во время выполнения. Исправлены следующие поля дескриптора SPISerialBus:
- DeviceSelection
- DeviceSelectionPolarity
- WireMode
- SlaveMode
- ResourceSource
Следующие поля являются заполнителями для значений, указанных пользователем во время выполнения:
- DataBitLength
- ConnectionSpeed
- ClockPolarity
- ClockPhase
Так как SPI1 содержит только одну линию выбора микросхемы, объявляется один SPISerialBus()
ресурс:
// Index 2
SPISerialBus( // SCKL - GPIO 21 - Pin 40
// MOSI - GPIO 20 - Pin 38
// MISO - GPIO 19 - Pin 35
// CE1 - GPIO 17 - Pin 11
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
Соответствующее объявление понятного имени , которое является обязательным, указывается в DSD и ссылается на индекс этого объявления ресурса.
Package(2) { "bus-SPI-SPI1", Package() { 2 }},
При этом создается шина с именем SPI1 и связывает ее с индексом ресурсов 2.
Требования к драйверу SPI
- Должен использоваться
SpbCx
или быть совместимым с SpbCx - Должны пройти тесты MITT SPI
- Должна поддерживать скорость 4 МГц
- Должна поддерживать 8-разрядную длину данных
- Должен поддерживать все режимы SPI: 0, 1, 2, 3
I2C
Затем мы объявляем ресурсы I2C. Raspberry Pi предоставляет одну шину I2C на закреплении 3 и 5.
// Index 3
I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
0xFFFF, // SlaveAddress: placeholder
, // SlaveMode: default to ControllerInitiated
0, // ConnectionSpeed: placeholder
, // Addressing Mode: placeholder
"\\_SB.I2C1", // ResourceSource: I2C bus controller name
,
,
) // VendorData
Соответствующее объявление понятного имени , которое является обязательным, указывается в DSD:
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
Это объявляет шину I2C с понятным именем I2C1, который относится к индексу ресурсов 3, который является индексом ресурса I2CSerialBus(), объявленного выше.
Исправлены следующие поля дескриптора I2CSerialBus():
- SlaveMode
- ResourceSource
Следующие поля являются заполнителями для значений, указанных пользователем во время выполнения.
- SlaveAddress
- ConnectionSpeed
- АдресацияMode
Требования к драйверу I2C
- Должен использовать SpbCx или быть совместимым с SpbCx
- Должны пройти тесты MITT I2C
- Должна поддерживать 7-разрядную адресацию
- Должна поддерживать скорость 1000 Гц
- Должна поддерживать скорость 400kГц
GPIO
Затем мы объявляем все пин-коды GPIO, которые предоставляются в пользовательском режиме. Мы предлагаем следующие рекомендации по выбору того, какие закрепления следует предоставить:
- Объявите все закрепления на предоставленных заголовках.
- Объявите пин-коды, подключенные к полезным функциям подключения, таким как кнопки и индикаторы.
- Не объявляйте пин-коды, зарезервированные для системных функций или не подключенные к чему-либо.
Следующий блок ASL объявляет два закрепления — GPIO4 и GPIO5. Другие закрепления здесь не отображаются для краткости. Приложение C содержит пример скрипта PowerShell, который можно использовать для создания ресурсов GPIO.
// Index 4 – GPIO 4
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 4 }
// Index 6 – GPIO 5
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 5 }
При объявлении закреплений GPIO необходимо соблюдать следующие требования:
- Поддерживаются только контроллеры GPIO, сопоставленные с памятью. Контроллеры GPIO, интерфейсированные через I2C/SPI, не поддерживаются. Драйвер контроллера — это контроллер, сопоставленный с памятью, если он задает флаг MemoryMappedController в структуре CLIENT_CONTROLLER_BASIC_INFORMATION в ответ на обратный вызов CLIENT_QueryControllerBasicInformation .
- Для каждого пин-кода требуется как ресурс GpioIOIO, так и ресурс GpioInt. Ресурс GpioInt должен немедленно следовать ресурсу GpioIOIO и должен ссылаться на тот же номер пин-кода.
- Ресурсы GPIO должны быть упорядочены путем увеличения числа пин-кода.
- Каждый ресурс GpioIO и GpioInt должен содержать ровно один номер пин-кода в списке контактов.
- Поле ShareType обоих дескрипторов должно быть общим
- Поле EdgeLevel дескриптора GpioInt должно быть edge
- Поле ActiveLevel дескриптора GpioInt должно иметь значение ActiveBoth
- Поле PinConfig
- Должен быть одинаковым в дескрипторах GpioIO и GpioInt
- Должен быть одним из pullUp, PullDown или PullNone. Это не может быть PullDefault.
- Конфигурация извлечения должна соответствовать состоянию пин-кода питания. Вставка пин-кода в указанный режим извлечения из состояния питания не должна изменять состояние пин-кода. Например, если таблица указывает, что пин-код поставляется с вытягиванием, укажите PinConfig как PullUp.
Код инициализации встроенного ПО, UEFI и драйвера не должен изменять состояние пин-кода из состояния питания во время загрузки. Только пользователь знает, что подключено к закреплению и поэтому какие переходы состояния безопасны. Состояние питания каждого закрепления должно быть задокументировано, чтобы пользователи могли разрабатывать оборудование, которое правильно взаимодействует с закреплением. Пин-код не должен неожиданно изменять состояние во время загрузки.
Поддерживаемые режимы дисков
Если контроллер GPIO поддерживает встроенные оттягивание и вытягивание резисторов в дополнение к входным данным с высоким импандером и выходным данным CMOS, необходимо указать это с необязательным свойством SupportedDriveModes.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
Свойство SupportedDriveModes указывает, какие режимы дисков поддерживаются контроллером GPIO. В приведенном выше примере поддерживаются все следующие режимы дисков. Свойство представляет собой битовую маску следующих значений:
Значение флага | Режим диска | Description |
---|---|---|
0x1 | InputHighImpedance | Пин-код поддерживает входные данные с высоким импедансом, соответствующий значению PullNone в ACPI. |
0x2 | InputPullUp | Пин-код поддерживает встроенный резистор подтягивания, соответствующий значению PullUp в ACPI. |
0x4 | InputPullDown | Пин-код поддерживает встроенный резистор вниз, соответствующий значению PullDown в ACPI. |
0x8 | OutputCmos | Закрепление поддерживает создание сильных максимумов и сильных минимумов (в отличие от открытого слива). |
InputHighImpedance и OutputCmos поддерживаются почти всеми контроллерами GPIO. Если свойство SupportedDriveModes не указано, это значение по умолчанию.
Если сигнал GPIO проходит через смену уровня перед достижением открытого заголовка, объявите режимы диска, поддерживаемые SOC, даже если режим диска не будет наблюдаться во внешнем заголовке. Например, если пин-код проходит через двунаправленный сдвиг уровня, который делает пин-код открытым сливом с сопротивлением вытягиванием, вы никогда не будете наблюдать состояние высокого импедданса на открытом заголовке, даже если пин-код настроен как вход с высоким импеддансом. Вы по-прежнему должны объявить, что пин-код поддерживает входные данные с высокими импеансами.
Закрепление нумерирования
Windows поддерживает две схемы нумерирования контактов:
- Последовательное нумерирование пин-кода — пользователи видят такие числа, как 0, 1, 2... до количества предоставленных закреплений. 0 является первым ресурсом GpioIo, объявленным в ASL, 1 является вторым ресурсом GpioIo, объявленным в ASL, и т. д.
- Нумерирование собственного пин-кода — пользователи видят номера пин-кода, указанные в дескрипторах GpioIo, например 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
Свойство UseDescriptorPinNumbers сообщает Windows использовать собственное нумерирование пин-кода вместо последовательного нумерирования пин-кода. Если свойство UseDescriptorPinNumbers не указано или его значение равно нулю, Windows по умолчанию будет использовать последовательное нумерирование пин-кодов.
Если используется нумерирование собственного пин-кода, необходимо также указать свойство PinCount .
Package (2) { “GPIO-PinCount”, 54 },
Свойство PinCount должно соответствовать значению, возвращаемого через свойство TotalPins в CLIENT_QueryControllerBasicInformation обратном вызове GpioClx
драйвера.
Выберите схему нумерирования, которая наиболее совместима с существующей опубликованной документацией для вашей платы. Например, Raspberry Pi использует собственное нумерирование пин-кода, так как многие существующие схемы закреплений используют номера BCM2835 закреплений. MinnowBoardMax использует последовательное нумерирование пин-кода, так как существует несколько существующих схем закреплений, а последовательное нумерирование пин-кода упрощает работу разработчика, так как только 10 контактов предоставляются из более чем 200 контактов. Решение об использовании последовательного или собственного нумерирования закреплений должно стремиться к снижению путаницы разработчика.
Требования к драйверу GPIO
- Необходимо использовать
GpioClx
- Должен быть сопоставлен с памятью on-SOC
- Должен использовать эмулированную обработку прерываний ActiveBoth
UART
Если драйвер UART использует SerCx
или SerCx2
, можно использовать rhproxy для предоставления драйвера пользовательскому режиму. Драйверы UART, создающие интерфейс устройства типа GUID_DEVINTERFACE_COMPORT
, не нужно использовать rhproxy. Драйвер папки "Входящие Serial.sys
" является одним из этих случаев.
Чтобы предоставить UART в пользовательском режиме стиль SerCx
, объявите UARTSerialBus
ресурс следующим образом.
// Index 2
UARTSerialBus( // Pin 17, 19 of JP1, for SIO_UART2
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT2", // ResourceSource: UART bus controller name
,
,
,
)
Только поле ResourceSource исправлено, а все остальные поля являются заполнителями для значений, указанных во время выполнения пользователем.
Сопровождающее объявление понятного имени:
Package(2) { "bus-UART-UART2", Package() { 2 }},
Это присваивает понятное имя UART2 контроллеру, которое является идентификатором пользователей, которые будут использовать для доступа к шине из пользовательского режима.
Мультиплексирование пин-кода среды выполнения
Мультиплексирование контактов — это возможность использовать один и тот же физический пин-код для разных функций. Несколько различных периферийных устройств на микросхеме, таких как контроллер I2C, контроллер SPI и контроллер GPIO, могут быть перенаправлены на один и тот же физический пин-код на SOC. Блок мультиплекса определяет, какая функция активна на закреплении в любое время. Традиционно встроенное ПО отвечает за установку назначений функций при загрузке, и это назначение остается статическим через сеанс загрузки. Мультиплексирование пин-кода среды выполнения добавляет возможность перенастройки назначений пин-функций во время выполнения. Чтобы пользователи могли выбирать функцию пин-кода во время выполнения, ускоряя разработку, позволяя пользователям быстро перенастроить пин-коды доски и позволяет оборудованию поддерживать более широкий спектр приложений, чем статическую конфигурацию.
Пользователи используют поддержку gpIO, I2C, SPI и UART без написания дополнительного кода. Когда пользователь открывает GPIO или шину с помощью OpenPin() или FromIdAsync(), базовые физические пин-коды автоматически сопоставляются с запрошенной функцией. Если пин-коды уже используются другой функцией, вызов OpenPin() или FromIdAsync() завершится сбоем. Когда пользователь закрывает устройство путем удаления объекта GpioPin, I2cDevice, SpiDevice или SerialDevice, выдается пин-код, что позволяет им позже открываться для другой функции.
Windows содержит встроенную поддержку мультиплексирования контактов в платформах GpioClx, SpbCx и SerCx. Эти платформы работают вместе, чтобы автоматически переключать пин-код на правильную функцию при доступе к пин-коду или шине GPIO. Доступ к пин-кодам является арбитражем, чтобы предотвратить конфликты между несколькими клиентами. Помимо этой встроенной поддержки интерфейсы и протоколы для мультиплексирования контактов являются общими целями и могут быть расширены для поддержки дополнительных устройств и сценариев.
В этом документе сначала описываются базовые интерфейсы и протоколы, связанные с мультиплексированием пин-адресов, а затем описывается, как добавить поддержку мультиплексирования пин-адресов в драйверы контроллеров GpioClx, SpbCx и SerCx.
Архитектура мультиплексирования закреплений
В этом разделе описываются базовые интерфейсы и протоколы, связанные с мультиплексированием пин-кода. Знание базовых протоколов не обязательно требуется для поддержки мультиплексирования контактов с драйверами GpioClx/SpbCx/SerCx. Дополнительные сведения о поддержке мультиплексирования пин-адресов с помощью драйверов GpioCls/SpbCx/SerCx см. в статье "Реализация поддержки мультиплексирования пин-адресов в драйверах клиентов GpioClx и использовании мультиплексирования" в драйверах контроллеров SpbCx и SerCx.
Мультиплексирование пин-адресов осуществляется сотрудничеством нескольких компонентов.
- Закрепление серверов мультиплексирования — это драйверы, управляющие блоком управления мультиплексированием пин-кода. Серверы мультиплексирования пин-кода получают запросы на мультиплексирование контактов от клиентов через запросы на резервирование ресурсов мультиплексирования (через IRP_MJ_CREATE) и запросы на переключение функции пин-кода (через *IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS-запросы). Сервер мультиплексирования пин-кода обычно является драйвером GPIO, так как блок мультиплексирования иногда является частью блока GPIO. Даже если блок мьюксирования является отдельным периферийным устройством, драйвер GPIO является логическим местом для размещения функций мьюзинга.
- Клиенты мультиплексирования пин-кода — это драйверы, использующие мультиплексирование пин-кода. Клиенты мультиплексирования пин-кода получают ресурсы мультиплексирования пин-кода из встроенного ПО ACPI. Ресурсы мультиплексирования закреплений — это тип ресурса подключения и управляются центром ресурсов. Закрепление мультиплексирования клиентов резервировать ресурсы с помощью маркера для ресурса. Чтобы изменить оборудование, клиенты должны зафиксировать конфигурацию, отправив запрос IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS . Клиенты выпускают ресурсы с мультиплексированием пин-кода, закрывая дескриптор, в котором конфигурация мультиплексирования возвращается в состояние по умолчанию.
- Встроенное ПО ACPI — задает конфигурацию мьюксирования с
MsftFunctionConfig()
ресурсами. Ресурсы MsftFunctionConfig выражают, какие контакты, в которых конфигурация мультиплексирования требуется клиенту. Ресурсы MsftFunctionConfig содержат номер функции, конфигурацию извлечения и список чисел пин-кода. Ресурсы MsftFunctionConfig предоставляются клиентам с закреплением мультиплексирования в качестве аппаратных ресурсов, которые получают драйверы в обратном вызове PrepareHardware аналогично ресурсам подключения GPIO и SPB. Клиенты получают идентификатор концентратора ресурсов, который можно использовать для открытия дескриптора к ресурсу.
Необходимо передать переключатель командной
/MsftInternal
строки дляasl.exe
компиляции файлов ASL,MsftFunctionConfig()
содержащих дескрипторы, так как эти дескрипторы в настоящее время рассматриваются рабочим комитетом ACPI. Например:asl.exe /MsftInternal dsdt.asl
Ниже показана последовательность операций, связанных с мультиплексированием контактов.
- Клиент получает ресурсы MsftFunctionConfig из встроенного ПО ACPI в обратном вызове EvtDevicePrepareHardware().
- Клиент использует вспомогательные функции центра ресурсов для создания пути из идентификатора ресурса, а затем открывает дескриптор
RESOURCE_HUB_CREATE_PATH_FROM_ID()
пути (с помощью ZwCreateFile(), IoGetDeviceObjectPointer()или WdfIoTargetOpen()). - Сервер извлекает идентификатор концентратора ресурсов из пути к файлу с помощью вспомогательных функций
RESOURCE_HUB_ID_FROM_FILE_NAME()
концентратора ресурсов, а затем запрашивает концентратор ресурсов, чтобы получить дескриптор ресурса. - Сервер выполняет обмен арбитражем для каждого пин-кода в дескрипторе и завершает запрос IRP_MJ_CREATE.
- Клиент выдает запрос IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS на полученный дескриптор.
- В ответ на IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS сервер выполняет операцию аппаратного мультиплексирования, делая указанную функцию активной на каждом закреплении.
- Клиент выполняет операции, зависящие от запрошенной конфигурации мультиплексирования пин-кода.
- Если клиенту больше не требуется мультиплексирование контактов, он закрывает дескриптор.
- В ответ на закрываемый дескриптор сервер возвращает пин-код обратно в исходное состояние.
Описание протокола для клиентов с мультиплексированием пин-кода
В этом разделе описывается, как клиент использует функции мультиплексирования контактов. Это не относится к SerCx
драйверам контроллера, SpbCx
так как платформы реализуют этот протокол от имени драйверов контроллера.
Анализ ресурсов
Драйвер WDF получает MsftFunctionConfig()
ресурсы в подпрограмме EvtDevicePrepareHardware(). Ресурсы MsftFunctionConfig можно определить следующими полями:
CM_PARTIAL_RESOURCE_DESCRIPTOR::Type = CmResourceTypeConnection
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Class = CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Type = CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG
Подпрограмма EvtDevicePrepareHardware()
может извлечь ресурсы MsftFunctionConfig следующим образом:
EVT_WDF_DEVICE_PREPARE_HARDWARE evtDevicePrepareHardware;
_Use_decl_annotations_
NTSTATUS
evtDevicePrepareHardware (
WDFDEVICE WdfDevice,
WDFCMRESLIST ResourcesTranslated
)
{
PAGED_CODE();
LARGE_INTEGER connectionId;
ULONG functionConfigCount = 0;
const ULONG resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
for (ULONG index = 0; index < resourceCount; ++index) {
const CM_PARTIAL_RESOURCE_DESCRIPTOR* resDescPtr =
WdfCmResourceListGetDescriptor(ResourcesTranslated, index);
switch (resDescPtr->Type) {
case CmResourceTypeConnection:
switch (resDescPtr->u.Connection.Class) {
case CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG:
switch (resDescPtr->u.Connection.Type) {
case CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG:
switch (functionConfigCount) {
case 0:
// save the connection ID
connectionId.LowPart = resDescPtr->u.Connection.IdLowPart;
connectionId.HighPart = resDescPtr->u.Connection.IdHighPart;
break;
} // switch (functionConfigCount)
++functionConfigCount;
break; // CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG
} // switch (resDescPtr->u.Connection.Type)
break; // CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
} // switch (resDescPtr->u.Connection.Class)
break;
} // switch
} // for (resource list)
if (functionConfigCount < 1) {
return STATUS_INVALID_DEVICE_CONFIGURATION;
}
// TODO: save connectionId in the device context for later use
return STATUS_SUCCESS;
}
Резервирование и фиксация ресурсов
Когда клиент хочет использовать закрепление, он резервирует и фиксирует ресурс MsftFunctionConfig. В следующем примере показано, как клиент может зарезервировать и зафиксировать ресурсы MsftFunctionConfig.
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS AcquireFunctionConfigResource (
WDFDEVICE WdfDevice,
LARGE_INTEGER ConnectionId,
_Out_ WDFIOTARGET* ResourceHandlePtr
)
{
PAGED_CODE();
//
// Form the resource path from the connection ID
//
DECLARE_UNICODE_STRING_SIZE(resourcePath, RESOURCE_HUB_PATH_CHARS);
NTSTATUS status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
&resourcePath,
ConnectionId.LowPart,
ConnectionId.HighPart);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Create a WDFIOTARGET
//
WDFIOTARGET resourceHandle;
status = WdfIoTargetCreate(WdfDevice, WDF_NO_ATTRIBUTES, &resourceHandle);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Reserve the resource by opening a WDFIOTARGET to the resource
//
WDF_IO_TARGET_OPEN_PARAMS openParams;
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(
&openParams,
&resourcePath,
FILE_GENERIC_READ | FILE_GENERIC_WRITE);
status = WdfIoTargetOpen(resourceHandle, &openParams);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Commit the resource
//
status = WdfIoTargetSendIoctlSynchronously(
resourceHandle,
WDF_NO_HANDLE, // WdfRequest
IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS,
nullptr, // InputBuffer
nullptr, // OutputBuffer
nullptr, // RequestOptions
nullptr); // BytesReturned
if (!NT_SUCCESS(status)) {
WdfIoTargetClose(resourceHandle);
return status;
}
//
// Pins were successfully muxed, return the handle to the caller
//
*ResourceHandlePtr = resourceHandle;
return STATUS_SUCCESS;
}
Драйвер должен хранить WDFIOTARGET в одной из его областей контекста, чтобы его можно было закрыть позже. Когда драйвер готов к выпуску конфигурации mxing, он должен закрыть дескриптор ресурсов, вызвав WdfObjectDelete()или WdfIoTargetClose(), если планируется повторно использовать WDFIOTARGET.
WdfObjectDelete(resourceHandle);
Когда клиент закрывает дескриптор ресурса, пин-коды будут обмязаться обратно в исходное состояние и теперь могут быть приобретены другим клиентом.
Описание протокола для серверов мультиплексирования пин-кодов
В этом разделе описывается, как сервер мультиплексирования пин-кода предоставляет свои функциональные возможности клиентам. Это не относится к GpioClx
мини-драйверам, так как платформа реализует этот протокол от имени клиентских драйверов. Дополнительные сведения о поддержке мультиплексирования контактов в драйверах клиентов см. в статье "Реализация поддержки мультиплексирования в GpioClx
драйверах клиентов GpioClx".
Обработка запросов IRP_MJ_CREATE
Клиенты открывают дескриптор для ресурса, когда они хотят зарезервировать ресурс мультиплексирования контактов. Сервер мультиплексирования пин-кода получает IRP_MJ_CREATE запросы путем операции повторного анализа из концентратора ресурсов. Конечный компонент пути запроса IRP_MJ_CREATE содержит идентификатор концентратора ресурсов, который является 64-разрядным целым числом в шестнадцатеричном формате. Сервер должен извлечь идентификатор концентратора ресурсов из имени файла, используя RESOURCE_HUB_ID_FROM_FILE_NAME()
reshub.h, и отправить IOCTL_RH_QUERY_CONNECTION_PROPERTIES в концентратор ресурсов, чтобы получить дескриптор MsftFunctionConfig()
.
Сервер должен проверить дескриптор и извлечь режим общего доступа и список закреплений из дескриптора. Затем он должен выполнять обмен арбитражем для пин-кодов, и в случае успеха помечайте пин-коды как зарезервированные перед завершением запроса.
Общий доступ к арбитражу успешно завершается, если обмен данными успешно выполнен для каждого пин-кода в списке пин-кодов. Каждый пин-код должен быть арбитражирован следующим образом:
- Если пин-код еще не зарезервирован, обмен арбитражом успешно выполнен.
- Если пин-код уже зарезервирован как эксклюзивный, обмен арбитража завершается ошибкой.
- Если пин-код уже зарезервирован как общий,
- и входящие запросы являются общими, обмен арбитража успешно выполнен.
- и входящий запрос является эксклюзивным, обмен арбитражом завершается сбоем.
Если сбой арбитража общего доступа, запрос должен быть завершен с STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE. Если арбитраж совместного использования выполнен успешно, запрос должен завершиться STATUS_SUCCESS.
Обратите внимание, что режим общего доступа для входящего запроса должен быть взят из дескриптора MsftFunctionConfig, а не IrpSp-Parameters.Create.ShareAccess>.
Обработка запросов IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS
После успешного зарезервированного ресурса MsftFunctionConfig, открыв дескриптор, он может отправить IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS , чтобы запросить сервер для выполнения фактической операции многомерного взаимодействия оборудования. Когда сервер получает IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, для каждого пин-кода в списке пин-кода он должен
- Задайте режим извлечения, указанный в элементе PinConfiguration PNP_FUNCTION_CONFIG_DESCRIPTOR структуры в оборудование.
- Мультиплексирование пин-кода функции, указанной членом FunctionNumber структуры PNP_FUNCTION_CONFIG_DESCRIPTOR.
Затем сервер должен завершить запрос с помощью STATUS_SUCCESS.
Значение FunctionNumber определяется сервером, и понятно, что дескриптор MsftFunctionConfig был создан с знанием того, как сервер интерпретирует это поле.
Помните, что при закрытии дескриптора сервер должен будет вернуть пин-коды в конфигурацию, в которую они находились при получении IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, поэтому серверу может потребоваться сохранить состояние пин-кода перед их изменением.
Обработка запросов IRP_MJ_CLOSE
Если клиент больше не требует многомерного ресурса, он закрывает его дескриптор. Когда сервер получает запрос IRP_MJ_CLOSE , он должен вернуть пин-коды в состояние, в которое они находились при получении IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS . Если клиент никогда не отправлял IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, никаких действий не требуется. Затем сервер должен пометить пин-коды как доступные для обмена арбитражем и завершить запрос с помощью STATUS_SUCCESS. Не забудьте правильно синхронизировать обработку IRP_MJ_CLOSE с обработкой IRP_MJ_CREATE.
Рекомендации по разработке таблиц ACPI
В этом разделе описывается, как предоставлять ресурсы для мьюксирования клиентским драйверам. Обратите внимание, что для компиляции таблиц, содержащих MsftFunctionConfig()
ресурсы, потребуется сборка компилятора Microsoft ASL 14327 или более поздней версии. MsftFunctionConfig()
ресурсы предоставляются клиентам с закреплением мультиплексирования в качестве аппаратных ресурсов. MsftFunctionConfig()
Ресурсы должны предоставляться драйверам, для которых требуются изменения мультиплексирования пин-адресов, которые обычно являются драйверами SPB и последовательным контроллером, но не должны предоставляться драйверам SPB и последовательным периферийным драйверам, так как драйвер контроллера обрабатывает конфигурацию мультиплексирования.
Макрос MsftFunctionConfig()
ACPI определяется следующим образом:
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
- Общий или эксклюзивный — если это монопольное, этот пин-код может быть приобретен одним клиентом одновременно. При совместном доступе несколько общих клиентов могут получить ресурс. Всегда устанавливайте это на монопольное значение, так как позволяет нескольким несогласованным клиентам получать доступ к изменяемому ресурсу, что может привести к гонкам данных и таким образом непредсказуемым результатам.
- PinPullConfig — один из
- PullDefault — используйте конфигурацию вытягивания по умолчанию, определяемую SOC
- PullUp — включение резистора подтягивания
- PullDown — включение резистора вниз
- PullNone — отключение всех резисторов по запросу
- FunctionNumber — номер функции для программирования в мьюкс.
- ResourceSource — путь к пространству имен ACPI сервера мультиплексирования пин-кода
- ResourceSourceIndex — задайте для этого значение 0
- ResourceConsumer/ResourceProducer — задайте для этого значение ResourceConsumer
- VendorData — необязательные двоичные данные, значение которого определяется сервером мультиплексирования пин-кода. Обычно это должно оставаться пустым
- Список контактов — разделенный запятыми список чисел пин-кода, к которым применяется конфигурация. Если сервер мультиплексирования пин-кода является драйвером GpioClx, это номера пин-кода GPIO и имеют то же значение, что и цифры пин-кода в дескрипторе GpioIo.
В следующем примере показано, как можно предоставить ресурс MsftFunctionConfig() драйверу контроллера I2C.
Device(I2C1)
{
Name(_HID, "BCM2841")
Name(_CID, "BCMI2C")
Name(_UID, 0x1)
Method(_STA)
{
Return(0xf)
}
Method(_CRS, 0x0, NotSerialized)
{
Name(RBUF, ResourceTemplate()
{
Memory32Fixed(ReadWrite, 0x3F804000, 0x20)
Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x55 }
MsftFunctionConfig(Exclusive, PullUp, 4, "\\_SB.GPI0", 0, ResourceConsumer, ) { 2, 3 }
})
Return(RBUF)
}
}
Помимо ресурсов памяти и прерываний, которые обычно требуются драйвером контроллера, MsftFunctionConfig()
также указывается ресурс. Этот ресурс позволяет драйверу контроллера I2C помещать пин-коды 2 и 3, управляемые узлом устройства в \_SB. GPIO0 — в функции 4 с включенным резистором подтягивания.
Поддержка поддержки многомерного масштабирования в драйверах клиентов GpioClx
GpioClx
имеет встроенную поддержку мультиплексирования контактов. Драйверы минипорта GpioClx (также называемые драйверами клиентов GpioClx), оборудование контроллера GPIO. В windows 10 сборки 14327 драйверы минипорта GpioClx могут добавить поддержку мультиплексирования контактов, реализуя два новых DDIs:
- CLIENT_ConnectFunctionConfigPins — вызывается для
GpioClx
выполнения команды мини-драйвера минипорта для применения указанной конфигурации многомерной настройки. - CLIENT_DisconnectFunctionConfigPins — вызывается командой
GpioClx
мини-драйвера минипорта для возврата конфигурации мьюксирования.
Дополнительные сведения об этих подпрограммах см . в функциях обратного вызова событий GpioClx.
Помимо этих двух новых DDIs существующие DDIs должны быть проверены для обеспечения совместимости мультиплексирования пин-кодов:
- CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt — CLIENT_ConnectIoPins вызывается GpioClx, чтобы командовать мини-драйверу для настройки наборов контактов для входных или выходных данных GPIO. GPIO является взаимоисключающим с MsftFunctionConfig, то есть пин-код никогда не будет подключен для GPIO и MsftFunctionConfig одновременно. Так как функция пин-кода по умолчанию не требуется для GPIO, пин-код может не обязательно быть объединен в GPIO при вызове ConnectIoPins. ConnectIoPins требуется для выполнения всех операций, необходимых для подготовки пин-кода для операций ввода-вывода GPIO, включая операции мультиплексирования. CLIENT_ConnectInterrupt должно вести себя аналогично, так как прерывания можно рассматривать как особый случай ввода GPIO.
- CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt. Эти подпрограммы должны возвращать пин-коды в состояние, в которое они находились при вызове CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt, если не указан флаг PreserveConfiguration. Помимо возврата направления закреплений в состояние по умолчанию, минипорт должен также вернуть состояние мультиплексирования каждого пин-кода в состояние, в которое он был вызван при вызове подпрограммы _Connect.
Например, предположим, что конфигурация мультиплексирования по умолчанию пин-кода — UART, а пин-код также можно использовать в качестве GPIO. При вызове CLIENT_ConnectIoPins для подключения пин-кода для GPIO он должен объединять пин-код в GPIO и в CLIENT_DisconnectIoPins, он должен объединять пин-код обратно в UART. Как правило, подпрограммы отключения должны отменять операции, выполняемые подпрограммами Connect.
Поддержка многомерного масштабирования в драйверах контроллера SpbCx и SerCx
По состоянию на сборку Windows 10 14327 и SerCx
платформы содержат встроенную поддержку мультиплексирования контактов, SpbCx
которая позволяет SpbCx
SerCx
и драйверам контроллера быть закреплением клиентов с мультиплексированием без каких-либо изменений кода драйверов контроллера. По расширению любой периферийный драйвер SpbCx/SerCx, который подключается к драйверу контроллера SpbCx/SerCx, активирует действие мультиплексирования пин-адресов.
На следующей схеме показаны зависимости между каждым из этих компонентов. Как видно, мультиплексирование пин-адресов представляет зависимость от драйверов контроллера SerCx и SpbCx к драйверу GPIO, который обычно отвечает за мультиплексирование.
Во время инициализации устройства и SerCx
платформы анализируют все MsftFunctionConfig()
ресурсы, SpbCx
предоставляемые как аппаратные ресурсы для устройства. SpbCx/SerCx затем приобретает и освобождает ресурсы мультиплексирования пин-кода по требованию.
SpbCx
Применяет конфигурацию мультиплексирования пин-кода в обработчике IRP_MJ_CREATE перед вызовом обратного вызова evtSpbTargetConnect() драйвера клиента. Если не удалось применить конфигурацию многомерного масштабирования, обратный вызов драйвера EvtSpbTargetConnect()
контроллера не будет вызван. Таким образом, драйвер контроллера SPB может предположить, что к тому времени EvtSpbTargetConnect()
вызывается закрепление в функцию SPB.
SpbCx
отменяет конфигурацию мультиплексирования контактов в обработчике IRP_MJ_CLOSE сразу после вызова обратного вызова драйвера контроллера EvtSpbTargetDisconnect(). Результатом является то, что закрепление выполняется с помощью функции SPB всякий раз, когда периферийный драйвер открывает дескриптор драйвера контроллера SPB и удаляется, когда периферийный драйвер закрывает их дескриптор.
SerCx
ведет себя аналогично. SerCx
получает все MsftFunctionConfig()
ресурсы в обработчике IRP_MJ_CREATE непосредственно перед вызовом обратного вызова драйвера контроллера EvtSerCerCx2FileOpen() и освобождает все ресурсы в обработчике IRP_MJ_CLOSE, сразу после вызова обратного вызова драйвера контроллера EvtSerCx2FileClose .
Последствия динамического мультиплексирования пин-контактов для SerCx
SpbCx
драйверов контроллера заключается в том, что они должны иметь возможность терпеть стирать пин-коды от функции SPB/UART в определенное время. Драйверы контроллера должны предположить, что пин-коды не будут обдумываться до тех пор или EvtSerCx2FileOpen()
не EvtSpbTargetConnect()
вызывается. Пин-коды не необходимы для функции SPB/UART во время следующих обратных вызовов. Ниже приведен не полный список, но представляет наиболее распространенные подпрограммы PNP, реализованные драйверами контроллеров.
- DriverEntry
- EvtDriverDeviceAdd
- EvtDevicePrepareHardware/EvtDeviceReleaseHardware
- EvtDeviceD0Entry/EvtDeviceD0Exit
Проверка
Когда вы будете готовы протестировать rhproxy, полезно использовать следующую пошаговую процедуру.
- Убедитесь, что каждый
SpbCx
драйвер контроллераGpioClx
SerCx
загружается и работает правильно. - Убедитесь, что
rhproxy
в системе присутствует. Некоторые выпуски и сборки Windows не имеют его. - Компиляция и загрузка узла rhproxy с помощью
ACPITABL.dat
- Убедитесь, что
rhproxy
узел устройства существует rhproxy
Проверка загрузки и запуска- Убедитесь, что ожидаемые устройства предоставляются в пользовательском режиме
- Убедитесь, что вы можете взаимодействовать с каждым устройством из командной строки.
- Убедитесь, что вы можете взаимодействовать с каждым устройством из приложения UWP
- Выполнение тестов HLK
Проверка драйверов контроллера
Так как rhproxy предоставляет другие устройства в системе в пользовательском режиме, он работает только в том случае, если эти устройства уже работают. Первым шагом является проверка того, что эти устройства — контроллеры I2C, SPI, GPIO, которые вы хотите предоставить, уже работают.
В командной строке выполните команду
devcon status *
Просмотрите выходные данные и убедитесь, что запущены все интересующие устройства. Если у устройства есть код проблемы, необходимо устранить неполадки, почему это устройство не загружается. Все устройства должны были быть включены во время начальной приведения платформы. SpbCx
Устранение неполадок с GpioClx
драйверами контроллера или SerCx
драйверами контроллеров выходит за рамки этого документа.
Убедитесь, что rhproxy присутствует в системе
Убедитесь, что rhproxy
служба присутствует в системе.
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
Если ключ reg отсутствует, rhproxy не существует в вашей системе. Rhproxy присутствует во всех сборках IoT Core и Windows Enterprise сборки 15063 и более поздних версий.
Компиляция и загрузка ASL с помощью ACPITABL.dat
Теперь, когда вы создали узел ASL rhproxy, пришло время скомпилировать и загрузить его. Узел rhproxy можно скомпилировать в автономный AML-файл, который можно добавить в системные таблицы ACPI. Кроме того, если у вас есть доступ к источникам ACPI системы, можно вставить узел rhproxy непосредственно в таблицы ACPI платформы. Однако во время начальной приведения может быть проще использовать ACPITABL.dat
.
Создайте файл с именем yourboard.asl и поместите узел устройства RHPX в DefinitionBlock:
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1) { Scope (\_SB) { Device(RHPX) { ... } } }
Скачайте WDK и найдите
asl.exe
по адресуC:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify
Выполните следующую команду, чтобы создать ACPITABL.dat:
asl.exe yourboard.asl
Скопируйте полученный файл ACPITABL.dat в файл c:\windows\system32 в системе под тестом.
Включите функцию testsigning в системе под тестом:
bcdedit /set testsigning on
Перезагрузите систему под тестом. Система добавит таблицы ACPI, определенные в ACPITABL.dat в системные таблицы встроенного ПО.
Убедитесь, что узел устройства rhproxy существует
Выполните следующую команду, чтобы перечислить узел устройства rhproxy.
devcon status *msft8000
Выходные данные devcon должны указывать на наличие устройства. Если узел устройства отсутствует, таблицы ACPI не были успешно добавлены в систему.
Убедитесь, что rhproxy загружает и запускается
Проверьте состояние rhproxy:
devcon status *msft8000
Если выходные данные указывают на запуск rhproxy, rhproxy загружен и успешно запущен. Если вы видите код проблемы, необходимо изучить. Ниже приведены некоторые распространенные коды проблем:
- Проблема 51 .
CM_PROB_WAITING_ON_DEPENDENCY
Система не запускает rhproxy, так как одна из зависимостей не была загружена. Это означает, что ресурсы, переданные в rhproxy, указывают на недопустимые узлы ACPI или целевые устройства не запускаются. Сначала дважды проверьте успешность работы всех устройств (см. раздел "Проверка драйверов контроллера" выше). Затем дважды проверьте ASL и убедитесь, что все пути к ресурсам (например,\_SB.I2C1
) являются правильными и указывают на допустимые узлы в DSDT. - Проблема 10 -
CM_PROB_FAILED_START
Rhproxy не удалось запустить, скорее всего, из-за проблемы синтаксического анализа ресурсов. Перейдите по индексам ресурсов ASL и дважды проверьте индексы ресурсов в DSD и убедитесь, что ресурсы GPIO указаны в увеличении порядка чисел пин-кода.
Убедитесь, что ожидаемые устройства предоставляются в пользовательском режиме
Теперь, когда выполняется rhproxy, он должен создать интерфейсы устройств, к которым можно получить доступ в пользовательском режиме. Мы будем использовать несколько средств командной строки для перечисления устройств и их наличие.
Клонируйте репозиторий https://github.com/ms-iot/samples и создайте примеры, SpiTestTool
а также Mincomm
выполните сборку и I2cTestTool
сборкуGpioTestTool
. Скопируйте средства на тестируемое устройство и используйте следующие команды для перечисления устройств.
I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list
Вы должны увидеть ваши устройства и понятные имена. Если вы не видите нужные устройства и понятные имена, дважды проверьте ASL.
Проверка каждого устройства в командной строке
Следующим шагом является использование средств командной строки для открытия и взаимодействия с устройствами.
Пример I2CTestTool:
I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3
Пример SpiTestTool:
SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3
Пример GpioTestTool:
GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off
Пример MinComm (serial). Подключите Rx к Tx перед выполнением:
MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)
Проверка каждого устройства из приложения UWP
Используйте следующие примеры, чтобы проверить, работают ли устройства из UWP.
Запуск тестов HLK
Скачайте комплект оборудования (HLK). Доступны следующие тесты:
- Функциональные и стрессовые тесты GPIO WinRT
- Тесты записи WinRT I2C (обязательный EEPROM)
- Тесты чтения I2C WinRT (обязательный EEPROM)
- I2C WinRT Несуществующие тесты ведомого адреса
- Расширенные функциональные тесты I2C WinRT (требуется LPC1768 mbed)
- Тесты проверки частоты часов SPI WinRT (требуется LPC1768 mbed)
- Тесты передачи операций ввода-вывода SPI WinRT (требуется LPC1768 mbed)
- Тесты проверки шага SPI WinRT
- Тесты обнаружения разрывов передачи SPI WinRT (требуется LPC1768 mbed)
При выборе узла устройства rhproxy в диспетчере HLK будут автоматически выбраны применимые тесты.
В диспетчере HLK выберите "Устройство прокси-сервера Концентратора ресурсов":
Затем откройте вкладку "Тесты" и выберите тесты I2C WinRT, Gpio WinRT и Spi WinRT.
Нажмите кнопку "Выполнить выбранный". Дополнительная документация по каждому тесту доступна правой кнопкой мыши, щелкнув тест и щелкнув "Описание теста".
Ресурсы
- Спецификация ACPI 5.0
- Asl.exe (компилятор Microsoft ASL)
- Windows.Devices.Gpio
- Windows.Devices.I2c
- Windows.Devices.Spi
- Windows.Devices.SerialCommunication
- Тестовая платформа разработки и выполнения (TAEF)
- SpbCx
- GpioClx
- SerCx
- Тесты MITT I2C
- GpioTestTool
- I2cTestTool
- SpiTestTool
- MinComm (serial)
- Комплект аппаратных лабораторий (HLK)
Приложение
Приложение A . Список Raspberry Pi ASL
См. также сопоставления контактов Raspberry Pi 2 и 3
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
//
// RHProxy Device Node to enable WinRT API
//
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
// Index 0
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE0 - GPIO 8 - Pin 24
0, // Device selection (CE0)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 1
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE1 - GPIO 7 - Pin 26
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 2
SPISerialBus( // SCKL - GPIO 21 - Pin 40
// MOSI - GPIO 20 - Pin 38
// MISO - GPIO 19 - Pin 35
// CE1 - GPIO 17 - Pin 11
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 3
I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
0xFFFF, // SlaveAddress: placeholder
, // SlaveMode: default to ControllerInitiated
0, // ConnectionSpeed: placeholder
, // Addressing Mode: placeholder
"\\_SB.I2C1", // ResourceSource: I2C bus controller name
,
,
) // VendorData
// Index 4 - GPIO 4 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
// Index 6 - GPIO 5 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
// Index 8 - GPIO 6 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 6 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
// Index 10 - GPIO 12 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 12 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
// Index 12 - GPIO 13 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 13 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
// Index 14 - GPIO 16 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 16 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
// Index 16 - GPIO 18 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 18 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
// Index 18 - GPIO 22 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 22 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
// Index 20 - GPIO 23 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 23 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
// Index 22 - GPIO 24 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 24 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
// Index 24 - GPIO 25 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 25 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
// Index 26 - GPIO 26 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 26 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
// Index 28 - GPIO 27 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 27 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
// Index 30 - GPIO 35 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 35 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 35 }
// Index 32 - GPIO 47 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 47 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 47 }
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
// Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
// SPI 0
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }}, // Index 0 & 1
Package(2) { "SPI0-MinClockInHz", 7629 }, // 7629 Hz
Package(2) { "SPI0-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// SPI 1
Package(2) { "bus-SPI-SPI1", Package() { 2 }}, // Index 2
Package(2) { "SPI1-MinClockInHz", 30518 }, // 30518 Hz
Package(2) { "SPI1-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// I2C1
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
// GPIO Pin Count and supported drive modes
Package (2) { "GPIO-PinCount", 54 },
Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
Package (2) { "GPIO-SupportedDriveModes", 0xf }, // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
}
})
}
}
}
Приложение B. Перечисление ASL MinnowBoardMax
См. также сопоставления контактов MinnowBoard Max
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
// Index 0
SPISerialBus( // Pin 5, 7, 9 , 11 of JP1 for SIO_SPI
1, // Device selection
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
8, // databit len
ControllerInitiated, // slave mode
8000000, // Connection speed
ClockPolarityLow, // Clock polarity
ClockPhaseSecond, // clock phase
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
ResourceConsumer, // Resource usage
JSPI, // DescriptorName: creates name for offset of resource descriptor
) // Vendor Data
// Index 1
I2CSerialBus( // Pin 13, 15 of JP1, for SIO_I2C5 (signal)
0xFF, // SlaveAddress: bus address
, // SlaveMode: default to ControllerInitiated
400000, // ConnectionSpeed: in Hz
, // Addressing Mode: default to 7 bit
"\\_SB.I2C6", // ResourceSource: I2C bus controller name (For MinnowBoard Max, hardware I2C5(0-based) is reported as ACPI I2C6(1-based))
,
,
JI2C, // Descriptor Name: creates name for offset of resource descriptor
) // VendorData
// Index 2
UARTSerialBus( // Pin 17, 19 of JP1, for SIO_UART2
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT2", // ResourceSource: UART bus controller name
,
,
UAR2, // DescriptorName: creates name for offset of resource descriptor
)
// Index 3
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {0} // Pin 21 of JP1 (GPIO_S5[00])
// Index 4
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {0}
// Index 5
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {1} // Pin 23 of JP1 (GPIO_S5[01])
// Index 6
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {1}
// Index 7
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {2} // Pin 25 of JP1 (GPIO_S5[02])
// Index 8
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {2}
// Index 9
UARTSerialBus( // Pin 6, 8, 10, 12 of JP1, for SIO_UART1
115200, // InitialBaudRate: in bits ber second
, // BitsPerByte: default to 8 bits
, // StopBits: Defaults to one bit
0xfc, // LinesInUse: 8 1-bit flags to declare line enabled
, // IsBigEndian: default to LittleEndian
, // Parity: Defaults to no parity
FlowControlHardware, // FlowControl: Defaults to no flow control
32, // ReceiveBufferSize
32, // TransmitBufferSize
"\\_SB.URT1", // ResourceSource: UART bus controller name
,
,
UAR1, // DescriptorName: creates name for offset of resource descriptor
)
// Index 10
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {62} // Pin 14 of JP1 (GPIO_SC[62])
// Index 11
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {62}
// Index 12
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {63} // Pin 16 of JP1 (GPIO_SC[63])
// Index 13
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {63}
// Index 14
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {65} // Pin 18 of JP1 (GPIO_SC[65])
// Index 15
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {65}
// Index 16
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {64} // Pin 20 of JP1 (GPIO_SC[64])
// Index 17
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {64}
// Index 18
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {94} // Pin 22 of JP1 (GPIO_SC[94])
// Index 19
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {94}
// Index 20
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {95} // Pin 24 of JP1 (GPIO_SC[95])
// Index 21
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {95}
// Index 22
GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {54} // Pin 26 of JP1 (GPIO_SC[54])
// Index 23
GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {54}
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
// SPI Mapping
Package(2) { "bus-SPI-SPI0", Package() { 0 }},
Package(2) { "SPI0-MinClockInHz", 100000 },
Package(2) { "SPI0-MaxClockInHz", 15000000 },
// SupportedDataBitLengths takes a list of support data bit length
// Example : Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8, 7, 16 }},
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }},
// I2C Mapping
Package(2) { "bus-I2C-I2C5", Package() { 1 }},
// UART Mapping
Package(2) { "bus-UART-UART2", Package() { 2 }},
Package(2) { "bus-UART-UART1", Package() { 9 }},
}
})
}
}
}
Приложение C. Пример скрипта PowerShell для создания ресурсов GPIO
Следующий скрипт можно использовать для создания объявлений ресурсов GPIO для Raspberry Pi:
$pins = @(
@{PinNumber=4;PullConfig='PullUp'},
@{PinNumber=5;PullConfig='PullUp'},
@{PinNumber=6;PullConfig='PullUp'},
@{PinNumber=12;PullConfig='PullDown'},
@{PinNumber=13;PullConfig='PullDown'},
@{PinNumber=16;PullConfig='PullDown'},
@{PinNumber=18;PullConfig='PullDown'},
@{PinNumber=22;PullConfig='PullDown'},
@{PinNumber=23;PullConfig='PullDown'},
@{PinNumber=24;PullConfig='PullDown'},
@{PinNumber=25;PullConfig='PullDown'},
@{PinNumber=26;PullConfig='PullDown'},
@{PinNumber=27;PullConfig='PullDown'},
@{PinNumber=35;PullConfig='PullUp'},
@{PinNumber=47;PullConfig='PullUp'})
# generate the resources
$FIRST_RESOURCE_INDEX = 4
$resourceIndex = $FIRST_RESOURCE_INDEX
$pins | % {
$a = @"
// Index $resourceIndex - GPIO $($_.PinNumber) - $($_.Name)
GpioIO(Shared, $($_.PullConfig), , , , "\\_SB.GPI0", , , , ) { $($_.PinNumber) }
GpioInt(Edge, ActiveBoth, Shared, $($_.PullConfig), 0, "\\_SB.GPI0",) { $($_.PinNumber) }
"@
Write-Host $a
$resourceIndex += 2;
}