Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En Windows 10 y versiones posteriores, se proporciona API con acceso directo desde el modo de usuario a la entrada y salida de uso general (GPIO), Inter-Integrated Circuit (I2C), Interfaz de Periféricos Serial (SPI) y receptor-transmisor asíncrono universal (UART). Los paneles de desarrollo, como Raspberry Pi 2, exponen un subconjunto de estas conexiones, lo que le permite ampliar un módulo de proceso base con circuitos personalizados para abordar una aplicación determinada. Estos buses de bajo nivel suelen compartirse con otras funciones críticas a bordo, con solo un subconjunto de pines y buses GPIO expuestos en conectores. Para conservar la estabilidad del sistema, es necesario especificar qué patillas y buses son seguros para la modificación por parte de las aplicaciones en modo de usuario.
En este documento se describe cómo especificar esta configuración en Advanced Configuration and Power Interface (ACPI) y se proporcionan herramientas para validar que la configuración se especificó correctamente.
Importante
La audiencia de este documento es Unified Extensible Firmware Interface (UEFI) y los desarrolladores ACPI. Se asume cierta familiaridad con ACPI, la autoría del Lenguaje de Fuente de ACPI (ASL) y SpbCx/GpioClx.
El acceso en modo de usuario a los buses de bajo nivel en Windows se configura a través de los entornos GpioClx y SpbCx existentes. Un nuevo controlador llamado RhProxy, disponible en Windows IoT Core y Windows Enterprise, expone GpioClx y SpbCx recursos al modo de usuario. Para habilitar las API, se debe declarar un nodo de dispositivo para rhproxy en las tablas ACPI con cada uno de los recursos GPIO y SPB que se deben exponer al modo de usuario. Este documento le guía en la creación y verificación del ASL.
ASL por ejemplo
Veamos la declaración de nodo del dispositivo rhproxy en Raspberry Pi 2. En primer lugar, cree la declaración del dispositivo ACPI en el ámbito \_SB.
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
- _HID: id. de hardware. Establézcalo en un identificador de hardware específico del proveedor.
- _CID: id. compatible. Debe ser "MSFT8000".
- _UID: identificador único. Establézcalo en 1.
A continuación, declaramos cada uno de los recursos GPIO y SPB que se deben exponer al modo de usuario. El orden en el que se declaran los recursos es importante porque los índices de recursos se usan para asociar propiedades a los recursos. Si hay varios buses I2C o SPI expuestos, el primer bus declarado se considera el bus "predeterminado" para ese tipo y será la instancia devuelta por los GetDefaultAsync() métodos de Windows.Devices.I2c.I2cController y Windows.Devices.Spi.SpiController.
SPI
Raspberry Pi tiene dos buses SPI expuestos. SPI0 tiene dos líneas de selección de chip de hardware y SPI1 tiene una línea de selección de chip de hardware. Se requiere una declaración de recursos SPISerialBus() para cada línea de selección de chip para cada bus. Las dos declaraciones de recursos SPISerialBus siguientes son para las dos líneas de selección de chip en SPI0. El campo DeviceSelection contiene un valor único que el controlador interpreta como un identificador de línea de selección de chip de hardware. El valor exacto que ha colocado en el campo DeviceSelection depende de cómo el controlador interprete este campo del descriptor de conexión ACPI.
Nota:
Este artículo contiene referencias al término esclavo, un término que Microsoft no condona y ha dejado de usar en nuevos productos y documentación. Cuando el término se quite del software, lo quitaremos de este artículo.
// 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
¿Cómo sabe el software que estos dos recursos deben asociarse con el mismo bus? La asignación entre el nombre descriptivo del bus y el índice de recursos se especifica en el DSD.
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},
Esto crea un bus denominado "SPI0" con dos líneas de selección de chip: índices de recursos 0 y 1. Se requieren varias propiedades más para declarar las funcionalidades del bus SPI.
Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },
Las propiedades MinClockInHz y MaxClockInHz especifican las velocidades de reloj mínimas y máximas compatibles con el controlador. La API impedirá que los usuarios especifiquen valores fuera de este intervalo. La velocidad del reloj se pasa al controlador SPB en el campo _SPE del descriptor de conexión (sección ACPI 6.4.3.8.2.2).
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},
La propiedad SupportedDataBitLengths muestra las longitudes de bits de datos admitidas por el controlador. Se pueden especificar varios valores en una lista separada por comas. La API impedirá que los usuarios especifiquen valores fuera de esta lista. La longitud del bit de datos se pasa al controlador SPB en el campo _LEN del descriptor de conexión (sección ACPI 6.4.3.8.2.2).
Puede considerar estas declaraciones de recursos como "plantillas". Algunos de los campos se fijan en el arranque del sistema, mientras que otros se especifican dinámicamente en tiempo de ejecución. Se han corregido los siguientes campos del descriptor SPISerialBus:
- Selección de Dispositivo
- Polaridad de Selección de Dispositivo
- WireMode
- Modo Esclavo
- Fuente de Recursos
Los campos siguientes son marcadores de posición para los valores especificados por el usuario en tiempo de ejecución:
- Longitud de bits de datos
- VelocidadDeConexión
- PolaridadDelReloj
- ClockPhase
Puesto que SPI1 solo contiene una sola línea de selección de chip, se declara un único SPISerialBus() recurso:
// 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
La declaración de nombre amigable que acompaña, la cual es necesaria, se especifica en el DSD y hace referencia al índice de la declaración de este recurso.
Package(2) { "bus-SPI-SPI1", Package() { 2 }},
Esto crea un bus denominado "SPI1" y lo asocia al índice de recursos 2.
Requisitos del controlador SPI
- Debe usar
SpbCxo ser compatible con SpbCx - Debe haber superado las pruebas MITT SPI de
- Debe admitir la velocidad del reloj de 4Mhz.
- Debe admitir la longitud de datos de 8 bits
- Debe admitir todos los modos SPI: 0, 1, 2, 3
I2C
A continuación, declaramos los recursos de I2C. Raspberry Pi ofrece un solo bus I2C en los pines 3 y 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
La declaración del nombre amigable, que es necesaria, se especifica en el DSD.
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
Esto declara un bus I2C con el nombre descriptivo "I2C1" que hace referencia al índice de recursos 3, que es el índice del recurso I2CSerialBus() que declaramos anteriormente.
Se han corregido los siguientes campos del descriptor I2CSerialBus():
- Modo Esclavo
- Fuente de Recursos
Los siguientes campos son marcadores de posición para los valores especificados por el usuario en tiempo de ejecución.
- Dirección del Esclavo
- VelocidadDeConexión
- Modo de Direccionamiento
Requisitos del controlador I2C
- Debe usar SpbCx o ser compatible con SpbCx
- Debe haber superado las pruebas MITT I2C
- Debe admitir el direccionamiento de 7 bits
- Debe admitir la velocidad del reloj de 100 kHz.
- Debe admitir la velocidad del reloj de 400kHz.
GPIO
A continuación, declaramos todos los pines GPIO que se habilitan para el modo de usuario. Ofrecemos la siguiente orientación para decidir qué pines exponer:
- Declare todos los pines en las cabeceras expuestas.
- Declara los pines que están conectados a funciones integradas útiles como botones y LEDs.
- No declares pines que estén reservados para funciones del sistema o que no estén conectados a nada.
El siguiente bloque de ASL declara dos pines: GPIO4 y GPIO5. Las otras patillas no se muestran aquí por razones de brevedad. El apéndice C contiene un script de PowerShell de ejemplo que se puede usar para generar los recursos 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 }
Se deben observar los siguientes requisitos al declarar pines GPIO:
- Solo se admiten controladores GPIO asignados a memoria. No se admiten controladores GPIO interfazados a través de I2C/SPI. El controlador de controlador es un controlador asignado a memoria si establece la marca MemoryMappedController en la estructura CLIENT_CONTROLLER_BASIC_INFORMATION en respuesta a la devolución de llamada CLIENT_QueryControllerBasicInformation.
- Cada pin requiere tanto un recurso GpioIO como un recurso GpioInt. El recurso GpioInt debe seguir inmediatamente al recurso GpioIO y debe hacer referencia al mismo número de pin.
- Los recursos GPIO deben ordenarse en orden ascendente de número de pines.
- Cada recurso GpioIO y GpioInt debe contener exactamente un número de patilla en la lista de patillas.
- El campo ShareType de ambos descriptores debe ser Compartido
- El campo EdgeLevel del descriptor GpioInt debe ser Edge.
- El campo ActiveLevel del descriptor GpioInt debe ser ActiveBoth.
- Campo PinConfig
- Debe ser el mismo en los descriptores GpioIO y GpioInt.
- Debe ser uno de PullUp, PullDown o PullNone. No puede ser PullDefault.
- La configuración de pull debe coincidir con el estado de encendido del pin. La colocación del pin en el modo de extracción especificado del estado de encendido no debe cambiar el estado de la patilla. Por ejemplo, si la hoja de datos especifica que el pin aparece con una extracción, especifique PinConfig como PullUp.
El código de inicialización de firmware, UEFI y controladores no debe cambiar el estado de un pin desde su estado de encendido durante el arranque. Solo el usuario sabe lo que está asociado a un pin y, por tanto, qué transiciones de estado son seguras. El estado de activación de cada pin debe documentarse para que los usuarios puedan diseñar hardware que interactúe correctamente con un pin. Una patilla no debe cambiar de estado inesperadamente durante el arranque.
Modos de conducción admitidos
Si el controlador GPIO admite resistencias de pull-up y pull-down integradas, además de entrada de alta impedancia y salida CMOS, debe especificar esto mediante la propiedad opcional SupportedDriveModes.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
La propiedad SupportedDriveModes indica qué modos de operación son compatibles con el controlador GPIO. En el ejemplo anterior, se admiten todos los siguientes modos de conducción. La propiedad es una máscara de bits de los siguientes valores:
| Valor de marca | Modo de conducción | Descripción |
|---|---|---|
| 0x1 | Entrada de Alta Impedancia | El pin admite una entrada de impedancia alta, que corresponde al valor "PullNone" en ACPI. |
| 0x2 | InputPullUp | El pin admite una resistencia de extracción integrada, que corresponde al valor "PullUp" en ACPI. |
| 0x4 | InputPullDown | El pin admite una resistencia de extracción integrada, que corresponde al valor "PullDown" en ACPI. |
| 0x8 | SalidaCMOS | El pin admite la generación de altos fuertes y bajos fuertes (a diferencia de drenaje abierto). |
InputHighImpedance y OutputCmos son compatibles con casi todos los controladores GPIO. Si no se especifica la propiedad SupportedDriveModes, este es el valor predeterminado.
Si una señal GPIO pasa por un convertidor de nivel antes de llegar a un encabezado expuesto, declare los modos de conducción admitidos por el SOC, incluso si el modo de conducción no sería observable en el encabezado externo. Por ejemplo, si un pin pasa por un transductor de nivel bidireccional que hace que un pin aparezca como drenaje abierto con resistencia de pull-up, nunca observará un estado de alta impedancia en el conector expuesto incluso si el pin está configurado como una entrada de alta impedancia. Todavía debe declarar que el pin admite una entrada de impedancia alta.
Numeración de pines
Windows admite dos esquemas de numeración de pines.
- Numeración secuencial de patillas: los usuarios ven números como 0, 1, 2... hasta el número de patillas expuestas. 0 es el primer recurso gpioIo declarado en ASL, 1 es el segundo recurso gpioIo declarado en ASL, etc.
- Numeración de patillas nativas: los usuarios ven los números de pin especificados en descriptores GpioIo, por ejemplo, 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
La propiedad UseDescriptorPinNumbers indica a Windows que use la numeración nativa de pines en lugar de la numeración secuencial de pines. Si no se especifica la propiedad UseDescriptorPinNumbers o su valor es cero, Windows tendrá como valor predeterminado numeración de patillas secuenciales.
Si se utiliza la numeración de patillas nativas, también debe especificar la propiedad PinCount.
Package (2) { “GPIO-PinCount”, 54 },
La propiedad PinCount debe coincidir con el valor devuelto a través de la propiedad TotalPins en la devolución de llamada CLIENT_QueryControllerBasicInformation del controlador GpioClx.
Elija el esquema de numeración más compatible con la documentación publicada existente para el tablero. Por ejemplo, Raspberry Pi usa la numeración de pines nativa porque muchos diagramas de pinout existentes usan los números de pin BCM2835. MinnowBoardMax usa la numeración de patillas secuenciales porque hay pocos diagramas de anclaje existentes y la numeración de patillas secuenciales simplifica la experiencia del desarrollador porque solo se exponen 10 patillas de más de 200 patillas. La decisión de usar la numeración de pines secuenciales o nativas debe tener como objetivo reducir la confusión de los desarrolladores.
Requisitos del controlador GPIO
- Debe usar
GpioClx - Debe estar la memoria asignada en el SoC.
- Debe usar el control de interrupciones de ActiveBoth emulado.
Receptor-Transmisor Asíncrono Universal (UART)
Si el controlador UART usa SerCx o SerCx2, puede usar rhproxy para exponer el controlador al modo de usuario. Los controladores UART que crean una interfaz de dispositivo de tipo GUID_DEVINTERFACE_COMPORT no necesitan usar rhproxy. El controlador interno Serial.sys es uno de estos casos.
Para exponer un UART de estilo SerCx en modo usuario, declare un recurso UARTSerialBus como se indica a continuación.
// 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
,
,
,
)
Solo se fija el campo ResourceSource mientras que todos los demás campos son marcadores de posición para los valores especificados en tiempo de ejecución por el usuario.
La declaración de nombre amigable que acompaña es:
Package(2) { "bus-UART-UART2", Package() { 2 }},
Esto asigna el nombre descriptivo "UART2" al controlador, que es el identificador que los usuarios usarán para acceder al bus desde el modo de usuario.
Multiplexación de pines en tiempo de ejecución
La multiplexación de pines es la capacidad de utilizar el mismo pin físico para diferentes funciones. Varios periféricos en chip diferentes, como un controlador I2C, un controlador SPI y un controlador GPIO, pueden enrutarse al mismo pin físico en un SOC. El bloque mux controla qué función está activa en el pin en cualquier momento dado. Tradicionalmente, el firmware es responsable de establecer asignaciones de funciones en el arranque y esta asignación permanece estática a través de la sesión de arranque. La multiplexación de pines en tiempo de ejecución agrega la capacidad de volver a configurar las asignaciones de funciones de pines durante la ejecución. Permitir que los usuarios elijan la función de un pin en tiempo de ejecución acelera el desarrollo, ya que les permite reconfigurar rápidamente las patillas de una placa, y además permite que el hardware soporte una gama más amplia de aplicaciones, algo que no sería posible con una configuración estática.
Los usuarios consumen compatibilidad de multiplexación con GPIO, I2C, SPI y UART sin escribir código adicional. Cuando un usuario abre un GPIO o bus mediante OpenPin() o FromIdAsync(), los pines físicos subyacentes se multiplexan automáticamente a la función solicitada. Si los pines ya están en uso por otra función, se producirá un error en la llamada a OpenPin() o FromIdAsync(). Cuando el usuario cierra el dispositivo mediante la eliminación del objeto GpioPin, I2cDevice, SpiDeviceo SerialDevice, se liberan los pines, lo que los permite abrirse posteriormente para una función diferente.
Windows contiene soporte integrado para la multiplexación de pines en los marcos de GpioClx, SpbCxy SerCx. Estos frameworks trabajan juntos para cambiar automáticamente un pin a la función correcta cuando se accede a un pin o bus GPIO. El acceso a los pines se arbitra para evitar conflictos entre varios clientes. Además de este soporte integrado, las interfaces y los protocolos para la multiplexación de patillas son de propósito general y se pueden ampliar para admitir dispositivos y escenarios adicionales.
En este documento se describen primero las interfaces y protocolos subyacentes implicados en la multiplexación de patillas y, a continuación, se describe cómo agregar compatibilidad con la multiplexación de patillas a los controladores de controlador GpioClx, SpbCx y SerCx.
Arquitectura de mux de pines
En esta sección se describen las interfaces y protocolos involucrados en la multiplexación de pines. El conocimiento de los protocolos subyacentes no es necesariamente requerido para admitir la multiplexación de pines con controladores GpioClx/SpbCx/SerCx. Para obtener más información sobre cómo admitir la multiplexación de patillas con controladores GpioClx/SpbCx/SerCx, consulte Implementación del soporte de multiplexación de patillas en controladores cliente de GpioClx y Consumo de soporte de multiplexación en controladores SpbCx y SerCx.
La multiplexación de pines se realiza mediante la cooperación de varios componentes.
- Servidores de multiplexación de pines: estos controladores controlan el bloque de control de multiplexación de pines. Los servidores de multiplexación de patillas reciben solicitudes de los clientes para reservar recursos de multiplexación (a través de IRP_MJ_CREATE) y para cambiar la función de una patilla (a través de solicitudes IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS). El servidor de multiplexación de pines suele ser el controlador GPIO, ya que el bloque de multiplexación a veces forma parte del bloque GPIO. Incluso si el bloque de multiplexación es un periférico independiente, el controlador GPIO es un lugar lógico para colocar la funcionalidad de multiplexación.
- Clientes de multiplexación de patillas: estos son controladores que consumen la multiplexación de patillas. Los clientes de multiplexación de pines reciben recursos de multiplexación de pines del firmware ACPI. Los recursos de multiplexación de pines son un tipo de recurso de conexión y los gestiona el centro de recursos. Los clientes de multiplexación de pines reservan recursos de multiplexación de pines creando un manejador para el recurso. Para realizar un cambio de hardware, los clientes deben confirmar la configuración mediante el envío de una solicitud de IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS. Los clientes liberan recursos de multiplexación de patillas cerrando el identificador, momento en el cual la configuración de multiplexación se revierte a su estado predeterminado.
- Firmware ACPI: especifica la configuración de multiplexación con recursos de
MsftFunctionConfig(). Los recursos MsftFunctionConfig indican qué pines, en qué configuración de multiplexación, son necesarios para un cliente. Los recursos MsftFunctionConfig contienen el número de función, la configuración de pull y la lista de números de patillas. Los recursos MsftFunctionConfig se suministran a clientes de multiplexación de pines como recursos de hardware, que los controladores reciben en su devolución de llamada PrepareHardware, de manera similar a los recursos de conexión GPIO y SPB. Los clientes reciben un identificador del centro de recursos que se puede usar para abrir un identificador para el recurso.
Debe pasar el modificador de línea de comandos
/MsftInternalaasl.exepara compilar archivos ASL que contengan descriptoresMsftFunctionConfig(), ya que estos descriptores están actualmente bajo revisión por parte del comité de trabajo ACPI. Por ejemplo:asl.exe /MsftInternal dsdt.asl
A continuación se muestra la secuencia de operaciones implicadas en la multiplexación de pines.
de interacción cliente-servidor de multiplexación de pines
- El cliente recibe recursos MsftFunctionConfig del firmware ACPI en su EvtDevicePrepareHardware() callback.
- El cliente usa la función auxiliar del centro de recursos
RESOURCE_HUB_CREATE_PATH_FROM_ID()para crear una ruta de acceso desde el identificador de recurso y, a continuación, abre un identificador a la ruta de acceso (mediante ZwCreateFile(), IoGetDeviceObjectPointer(), o WdfIoTargetOpen()). - El servidor extrae el identificador del centro de recursos de la ruta de acceso del archivo mediante las funciones
RESOURCE_HUB_ID_FROM_FILE_NAME()auxiliares del centro de recursos y, a continuación, consulta el centro de recursos para obtener el descriptor de recursos. - El servidor realiza la gestión del uso compartido para cada conector del descriptor y completa la solicitud IRP_MJ_CREATE.
- El cliente emite una solicitud IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS en el identificador recibido.
- En respuesta a IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, el servidor realiza la operación de multiplexación de hardware por hacer que la función especificada se active en cada pin.
- El cliente continúa con las operaciones que dependen de la configuración de multiplexación de patillas solicitada.
- Cuando el cliente ya no requiere que se multiplexen los pines, cierra el manejador.
- En respuesta al identificador que se ha cerrado, el servidor revierte los pines a su estado inicial.
Descripción del protocolo para los clientes de multiplexación de pines
En esta sección se describe cómo un cliente utiliza la funcionalidad de multiplexación de pines. Esto no se aplica a los drivers de los controladores SerCx y SpbCx, ya que las estructuras implementan este protocolo por cuenta de los controladores.
Análisis de recursos
Un controlador WDF recibe recursos MsftFunctionConfig() en su rutina evtDevicePrepareHardware(). Los recursos msftFunctionConfig se pueden identificar mediante los campos siguientes:
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
Una EvtDevicePrepareHardware() rutina puede extraer recursos msftFunctionConfig de la siguiente manera:
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;
}
Reservar y confirmar recursos
Cuando un cliente quiere multiplexar pins, reserva y confirma el recurso de configuración MsftFunctionConfig. En el ejemplo siguiente se muestra cómo un cliente podría reservar y confirmar recursos 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;
}
El controlador debe almacenar el WDFIOTARGET en una de sus áreas de contexto para que se pueda cerrar más adelante. Cuando el controlador esté listo para liberar la configuración de multiplexación, debe cerrar el identificador de recursos llamando a WdfObjectDelete(), o WdfIoTargetClose() si piensa reutilizar WDFIOTARGET.
WdfObjectDelete(resourceHandle);
Cuando el cliente cierra su identificador de recursos, los pines se revierten a su estado inicial y ahora pueden ser adquiridos por otro cliente.
Descripción del protocolo para los servidores de multiplexión de pines
En esta sección se describe cómo un servidor de multiplexación de pines expone su funcionalidad a los clientes. Esto no se aplica a los controladores miniport GpioClx, ya que el framework implementa este protocolo por los controladores cliente. Para obtener más información sobre cómo admitir la multiplexación de patillas en los controladores del cliente de GpioClx, consulte Implementación de compatibilidad con la multiplexación en controladores de cliente GpioClx.
Manejo de solicitudes de IRP_MJ_CREATE
Los clientes abren un identificador de un recurso cuando desean reservar un recurso de multiplexación de pines. Un servidor de multiplexación de pines recibe IRP_MJ_CREATE solicitudes mediante una operación de reanálisis desde el hub de recursos. El componente de ruta de acceso final de la solicitud de IRP_MJ_CREATE contiene el identificador del centro de recursos, que es un entero de 64 bits en formato hexadecimal. El servidor debe extraer el identificador del centro de recursos del nombre de archivo mediante RESOURCE_HUB_ID_FROM_FILE_NAME() reshub.h y enviar IOCTL_RH_QUERY_CONNECTION_PROPERTIES al centro de recursos para obtener el MsftFunctionConfig() descriptor.
El servidor debe validar el descriptor y extraer el modo de uso compartido y la lista de pines del descriptor. A continuación, debe realizar el arbitraje de uso compartido para las patillas y, si se realiza correctamente, marcar las patillas como reservadas antes de completar la solicitud.
El arbitraje de uso compartido tiene éxito en general si se realiza correctamente para cada pin de la lista de pines. Cada pin debe ser arbitrado de la siguiente manera:
- Si el pin aún no está reservado, el arbitraje de uso compartido se realiza correctamente.
- Si el pin ya está reservado como exclusivo, se produce un error en el arbitraje de uso compartido.
- Si el pin ya está reservado como compartido,
- y se comparte la solicitud entrante, el arbitraje del uso compartido se realiza con éxito.
- y la solicitud entrante es exclusiva y se produce un error en el arbitraje de uso compartido.
Si falla el arbitraje compartido, la solicitud debe completarse con STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE. Si el arbitraje de uso compartido tiene éxito, la solicitud debe estar completada con STATUS_SUCCESS.
Tenga en cuenta que el modo de uso compartido de la solicitud entrante debe tomarse del descriptor MsftFunctionConfig, no irpSp-Parameters.Create.ShareAccess>.
Gestión de solicitudes de IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS
Después de que el cliente haya reservado correctamente un recurso MsftFunctionConfig abriendo un identificador, puede enviar IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS para solicitar al servidor que realice la operación de multiplexación de hardware real. Cuando el servidor recibe IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, para cada patilla de la lista de patillas debe
- Establezca el modo de extracción especificado en el miembro PinConfiguration de la estructura PNP_FUNCTION_CONFIG_DESCRIPTOR en el hardware.
- Asigna el pin con la función que se especifica a través del miembro FunctionNumber de la estructura PNP_FUNCTION_CONFIG_DESCRIPTOR.
A continuación, el servidor debe completar la solicitud con STATUS_SUCCESS.
El significado de FunctionNumber se define mediante el servidor y se entiende que el descriptor MsftFunctionConfig se creó con conocimiento de cómo interpreta el servidor este campo.
Recuerde que cuando se cierra el identificador, el servidor tendrá que revertir los pines a la configuración en la que se encontraban cuando se recibió IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, por lo que es posible que el servidor tenga que guardar el estado de los pines antes de modificarlos.
Gestión de solicitudes IRP_MJ_CLOSE
Cuando un cliente ya no requiere un recurso de multiplexación, cierra su identificador. Cuando un servidor recibe una solicitud de IRP_MJ_CLOSE, debe revertir los pines al estado en que se encontraban cuando se recibió IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS. Si el cliente nunca envió un IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, no es necesaria ninguna acción. A continuación, el servidor debe marcar los pines como disponibles en relación con el arbitraje de recursos compartidos y completar la solicitud con STATUS_SUCCESS. Asegúrese de sincronizar correctamente el manejo de IRP_MJ_CLOSE con el manejo de IRP_MJ_CREATE.
Directrices de elaboración para tablas ACPI
En esta sección se describe cómo proporcionar recursos de multiplexación a los controladores cliente. Tenga en cuenta que necesitará el compilador ASL de Microsoft, versión 14327 o posterior, para compilar tablas que contengan recursos de MsftFunctionConfig().
MsftFunctionConfig() recursos se proporcionan a los clientes de multiplexación de pines como recursos de hardware.
MsftFunctionConfig() los recursos deben proporcionarse a los controladores que requieren cambios de multiplexación de patillas, que normalmente son los controladores de SPB y de controladores de serie, pero no deben proporcionarse a los controladores periféricos serie y SPB, ya que el controlador maneja la configuración de multiplexación.
La MsftFunctionConfig() macro ACPI se define de la siguiente manera:
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
- Compartido/Exclusivo: si es exclusivo, este pin se puede adquirir mediante un solo cliente a la vez. Si se comparte, varios clientes compartidos pueden adquirir el recurso. Establézcalo siempre en exclusivo, ya que permitir que varios clientes no coordinados accedan a un recurso mutable pueden provocar carreras de datos y, por tanto, resultados imprevisibles.
- PinPullConfig es uno de
- PullDefault: usar la configuración predeterminada de activación definida por el SOC.
- PullUp: habilitar resistencia de extracción
- PullDown: habilitar resistencia de extracción
- PullNone: deshabilitar todas las resistencias de extracción
- FunctionNumber: el número de función que se va a programar en el multiplexor.
- ResourceSource: la ruta de acceso del espacio de nombres ACPI del servidor de multiplexación de pines
- ResourceSourceIndex: establézcalo en 0.
- ResourceConsumer/ResourceProducer: establézcalo en ResourceConsumer.
- VendorData: datos binarios opcionales cuyo significado es definido por el servidor de multiplexación de pines. Esto normalmente debe dejarse en blanco
- Lista de pines: una lista separada por comas de números de pines a los que se aplica la configuración. Cuando el servidor de multiplexación de pines es un controlador GpioClx, estos son números de pines GPIO y tienen el mismo significado que los números de pin en un descriptor GpioIo.
En el ejemplo siguiente se muestra cómo se puede proporcionar un recurso MsftFunctionConfig() a un controlador de 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)
}
}
Además de los recursos de memoria e interrupción que normalmente requiere un controlador de dispositivo, también se especifica un recurso de MsftFunctionConfig(). Este recurso permite al controlador I2C configurar los pines 2 y 3, administrados por el nodo del dispositivo en \_SB.GPIO0, en la función 4 con la resistencia pull-up habilitada.
Compatibilidad con el soporte de multiplexación en controladores de cliente GpioClx
GpioClx tiene compatibilidad integrada para la multiplexación de patillas. Los controladores de miniport de GpioClx (también conocidos como "controladores cliente de GpioClx") gestionan el hardware del controlador GPIO. A partir de la compilación 14327 de Windows 10, los controladores de miniport de GpioClx pueden agregar compatibilidad con la multiplexación de pines mediante la implementación de dos nuevos DDIs.
- CLIENT_ConnectFunctionConfigPins: llamado por
GpioClxpara ordenar al controlador miniport que aplique la configuración de multiplexación especificada. - CLIENT_DisconnectFunctionConfigPins: se llama por
GpioClxpara ordenar al controlador del miniport para restaurar la configuración original de multiplexación.
Consulte Funciones de Devolución de Llamada de Eventos GpioClx para obtener una descripción de estas rutinas.
Además de estos dos nuevos DDIs, se deben auditar los DDIs existentes para verificar su compatibilidad con la multiplexación de pines.
- CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt: GpioClx llama a CLIENT_ConnectIoPins para que el controlador miniport configure un conjunto de pines para la entrada o salida de GPIO. GPIO es mutuamente excluyente con MsftFunctionConfig, lo que significa que un pin nunca se conectará para GPIO y MsftFunctionConfig al mismo tiempo. Dado que no es necesario que la función predeterminada de un pin sea GPIO, es posible que un pin no se muxe necesariamente a GPIO cuando se llame a ConnectIoPins. ConnectIoPins es necesario para realizar todas las operaciones necesarias para que el pin esté listo para la E/S de GPIO, incluidas las operaciones de multiplexación. CLIENT_ConnectInterrupt debe comportarse de forma similar, ya que las interrupciones se pueden considerar como un caso especial de entrada GPIO.
- CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – estas rutinas deben devolver los pines al estado en el que estaban cuando se llamó a CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt, a menos que se especifique la marca PreserveConfiguration. Además de revertir la dirección de las patillas a su estado predeterminado, el miniporte también debe revertir el estado de multiplexación de cada patilla al estado en el que se encontraba cuando se llamó a la rutina _Connect.
Por ejemplo, supongamos que la configuración predeterminada de multiplexación de un pin es UART y que el pin también se puede usar como GPIO. Cuando se llama a CLIENT_ConnectIoPins para conectar el pin para GPIO, debe multiplexar el pin a GPIO y, en CLIENT_DisconnectIoPins, debe multiplexar el pin de nuevo a UART. En general, las rutinas Desconexión deben deshacer las operaciones realizadas por las rutinas Connect.
Soporte para la multiplexación en controladores SpbCx y SerCx
A partir de la compilación 14327 de Windows 10, los entornos de SpbCx y SerCx contienen soporte incorporado para la multiplexión de pines, lo que permite que los controladores SpbCx y SerCx actúen como clientes de multiplexión de pines sin necesidad de modificar el código de los controladores. Por extensión, cualquier controlador periférico SpbCx/SerCx que se conecte a un controlador de un controlador SpbCx/SerCx con soporte para multiplexión desencadenará la actividad de multiplexión de pines.
En el diagrama siguiente se muestran las dependencias entre cada uno de estos componentes. Como puede ver, la multiplexación de patillas introduce una dependencia de los controladores SerCx y SpbCx al controlador GPIO, que normalmente es responsable de la multiplexación.
En el momento de la inicialización del dispositivo, los frameworks SpbCx y SerCx analizan todos los recursos MsftFunctionConfig() proporcionados como recursos de hardware para el dispositivo. A continuación, spbCx/SerCx adquiere y libera los recursos de multiplexación de patillas a petición.
SpbCx aplica la configuración de multiplexación de patillas en su controlador de IRP_MJ_CREATE, justo antes de llamar al callback EvtSpbTargetConnect() del controlador cliente. Si no se pudo aplicar la configuración de multiplexación, no se llamará al callback EvtSpbTargetConnect() del controlador del driver. Por lo tanto, un controlador de SPB puede suponer que las patillas se multiplexan a la función SPB para el momento en que se invoque EvtSpbTargetConnect().
SpbCx revierte la configuración de multiplexación de patillas en su controlador de IRP_MJ_CLOSE, justo después de invocar la devolución de llamada del controlador EvtSpbTargetDisconnect(). El resultado es que las patillas se conmutan a la función SPB cada vez que un controlador periférico abre un identificador al controlador del SPB, y se desconectan cuando el controlador periférico cierra su identificador.
SerCx se comporta de forma similar.
SerCx adquiere todos los recursos MsftFunctionConfig() en su controlador de IRP_MJ_CREATE justo antes de invocar el controlador EvtSerCx2FileOpen() devolución de llamada y libera todos los recursos en su controlador de IRP_MJ_CLOSE, justo después de invocar el controlador del controlador EvtSerCx2FileClose devolución de llamada.
La implicación de la multiplexación dinámica de pines para los controladores SerCx y SpbCx es que deben ser capaces de tolerar que los pines se multiplexen de la función SPB/UART en determinados momentos. Los controladores de dispositivos deben asumir que las patillas no se multiplexarán hasta que se llame a EvtSpbTargetConnect() o EvtSerCx2FileOpen(). Los pines no necesitan ser multiplexados para la función SPB/UART durante las siguientes llamadas de retorno. A continuación no es una lista completa, pero representa las rutinas PNP más comunes implementadas por controladores de dispositivos.
- DriverEntry
- EvtDriverDeviceAdd
- EvtPrepararHardwareDispositivo/EvtLiberarHardwareDispositivo
- EvtDeviceD0Entry/EvtDeviceD0Exit
Comprobación
Cuando esté listo para probar rhproxy, resulta útil usar el siguiente procedimiento paso a paso.
- Compruebe que cada controlador
SpbCx,GpioClxySerCxse esté cargando y funcionando correctamente. - Compruebe que
rhproxyestá presente en el sistema. Algunas ediciones y compilaciones de Windows no lo tienen. - Compilación y carga del nodo rhproxy mediante
ACPITABL.dat - Comprobación de que el nodo del
rhproxydispositivo existe - Compruebe que
rhproxyestá cargando e iniciando - Comprobar que los dispositivos esperados se exponen al modo de usuario
- Compruebe que puede interactuar con cada dispositivo desde la línea de comandos.
- Comprobar que puedes interactuar con cada dispositivo desde una aplicación para UWP
- Ejecución de pruebas de HLK
Verificación de controladores del controlador
Dado que rhproxy expone otros dispositivos en el sistema al modo de usuario, solo funciona si esos dispositivos ya funcionan. El primer paso es comprobar que esos dispositivos (los controladores I2C, SPI, GPIO que desea exponer) ya funcionan.
En el símbolo del sistema, ejecute
devcon status *
Examine la salida y compruebe que se inician todos los dispositivos de interés. Si un dispositivo tiene un código de problema, debe solucionar el motivo por el que ese dispositivo no se está cargando. Todos los dispositivos deben haberse habilitado durante la incorporación inicial de la plataforma. La solución de problemas de los controladores SpbCx, GpioClxo SerCx está fuera del ámbito de este documento.
Compruebe que rhproxy está presente en el sistema
Compruebe que el rhproxy servicio está presente en el sistema.
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
Si la clave reg no está presente, rhproxy no existe en el sistema. Rhproxy está presente en todas las compilaciones de IoT Core y Windows Enterprise compilación 15063 y posteriores.
Compilación y carga de ASL con ACPITABL.dat
Ahora que ha creado un nodo rhproxy ASL, es el momento de compilarlo y cargarlo. Puede compilar el nodo rhproxy en un archivo AML independiente que se pueda anexar a las tablas ACPI del sistema. Como alternativa, si tiene acceso a los orígenes ACPI del sistema, puede insertar el nodo rhproxy directamente en las tablas ACPI de la plataforma. Sin embargo, durante la configuración inicial, puede ser más fácil usar ACPITABL.dat.
Cree un archivo denominado yourboard.asl y coloque el nodo del dispositivo RHPX dentro de definitionBlock:
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1) { Scope (\_SB) { Device(RHPX) { ... } } }Descargue el WDK y busque
asl.exeenC:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerifyEjecute el siguiente comando para generar ACPITABL.dat:
asl.exe yourboard.aslCopie el archivo ACPITABL.dat resultante en c:\windows\system32 en el sistema en prueba.
Habilite el modo testsigning en su sistema en prueba:
bcdedit /set testsigning onReinicie el sistema en prueba. El sistema anexará las tablas ACPI definidas en ACPITABL.dat a las tablas de firmware del sistema.
Compruebe que el nodo del dispositivo rhproxy existe
Ejecute el siguiente comando para enumerar el nodo del dispositivo rhproxy.
devcon status *msft8000
La salida de devcon debe indicar que el dispositivo está presente. Si el nodo del dispositivo no está presente, las tablas ACPI no se agregaron correctamente al sistema.
Compruebe que rhproxy está cargando e iniciando
Compruebe el estado de rhproxy:
devcon status *msft8000
Si la salida indica que se inicia rhproxy, rhproxy se ha cargado y iniciado correctamente. Si ve un código de problema, debe investigar. Algunos códigos de problema comunes son:
- Problema 51:
CM_PROB_WAITING_ON_DEPENDENCYel sistema no está iniciando rhproxy porque una de sus dependencias no se pudo cargar. Esto significa que los recursos pasados a rhproxy apuntan a nodos ACPI no válidos, o los dispositivos de destino no están iniciando. En primer lugar, compruebe que todos los dispositivos funcionan correctamente (consulte "Verificar los controladores del controlador" arriba). A continuación, compruebe su ASL y asegúrese de que todas las rutas de acceso de recursos (por ejemplo,\_SB.I2C1) son correctas y apuntan a nodos válidos en DSDT. - Problema 10:
CM_PROB_FAILED_STARTRhproxy no se pudo iniciar, lo más probable es que se deba a un problema de análisis de recursos. Revise su ASL y compruebe los índices de recursos en el DSD, asegurándose de que los recursos GPIO estén especificados en orden creciente de número de pines.
Comprobar que los dispositivos esperados se exponen al modo de usuario
Ahora que rhproxy se está ejecutando, debe haber creado interfaces de dispositivos a las que puede acceder el modo de usuario. Usaremos varias herramientas de línea de comandos para enumerar dispositivos y ver que están presentes.
Clona el repositorio https://github.com/ms-iot/samples y compila los ejemplos GpioTestTool, I2cTestTool, SpiTestTool y Mincomm. Copie las herramientas en el dispositivo en prueba y use los siguientes comandos para enumerar los dispositivos.
I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list
Deberías ver tus dispositivos y nombres amigables listados. Si no ve los dispositivos correctos y los nombres amigables, revise su ASL.
Comprobación de cada dispositivo en la línea de comandos
El siguiente paso es usar las herramientas de línea de comandos para abrir e interactuar con los dispositivos.
Ejemplo de I2CTestTool:
I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3
Ejemplo de SpiTestTool:
SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3
Ejemplo de GpioTestTool:
GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off
Ejemplo de MinComm (serial). Conecte Rx a Tx antes de ejecutar:
MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)
Comprobar cada dispositivo desde una aplicación para UWP
Use los ejemplos siguientes para validar que los dispositivos funcionan desde UWP.
- IoT-GPIO
- IoT-I2C
- IoT-SPI
- customSerialDeviceAccess
Ejecución de las pruebas de HLK
Descargue el Hardware Lab Kit (HLK). Las siguientes pruebas están disponibles:
- Pruebas funcionales y de estrés de GPIO WinRT
- Pruebas de escritura de I2C en WinRT (se requiere EEPROM)
- Pruebas de lectura de WinRT de I2C (se requiere EEPROM)
- Pruebas de direcciones de esclavos I2C WinRT inexistentes
- Pruebas Funcionales Avanzadas de WinRT de I2C (mbed LPC1768 Requerido)
- pruebas de comprobación de frecuencia de reloj de WinRT SPI (mbed LPC1768 obligatorio)
- Pruebas de Transferencia de E/S de WinRT (se requiere mbed LPC1768)
- Pruebas de verificación de pasos de SPI WinRT
- Pruebas de detección de huecos de transferencia de SPI WinRT (se requiere mbed LPC1768)
Al seleccionar el nodo del dispositivo rhproxy en el administrador de HLK, las pruebas aplicables se seleccionarán automáticamente.
En el administrador de HLK, seleccione "Dispositivo proxy del centro de recursos":
A continuación, haga clic en la pestaña Pruebas y seleccione Pruebas I2C WinRT, Gpio WinRT y Spi WinRT.
Haga clic en Ejecutar seleccionado. Para obtener más documentación sobre cada prueba, haga clic con el botón derecho en la prueba y haga clic en "Descripción de la prueba".
Recursos
- especificación ACPI 5.0
- Asl.exe (compilador de ASL de Microsoft)
- Windows.Devices.Gpio
- Windows.Devices.I2c
- Windows.Devices.Spi
- Windows.Devices.SerialCommunication
- marco de creación y ejecución de pruebas (TAEF)
- SpbCx
- GpioClx
- serCx
- Pruebas de I2C de MITT
- GpioTestTool
- I2cTestTool
- SpiTestTool
- MinComm (serie)
- Kit de Laboratorio de Hardware (HLK)
Apéndice
Apéndice A: Lista de ASL de Raspberry Pi
Consulte también Asignaciones de pines de Raspberry Pi 2 y 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
}
})
}
}
}
Apéndice B: Lista de ASL de MinnowBoardMax
Consulte también Asignaciones de pines del 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 }},
}
})
}
}
}
Apéndice C: script de PowerShell de ejemplo para generar recursos GPIO
El siguiente script se puede usar para generar las declaraciones de recursos GPIO para 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;
}