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 proporcionan API para el acceso directo desde el modo de usuario a la entrada/salida de propósito general (GPIO), el circuito interintegrado (I2C), la interfaz periférica serie (SPI) y el 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 integradas, y solo una parte de los pines GPIO y de los buses se expone en los 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 da por sentada cierta familiaridad con ACPI, con la creación en ACPI Source Language (ASL) y con SpbCx/GpioClx.
El acceso en modo de usuario a buses de bajo nivel en Windows se canaliza a través de los frameworks existentes GpioClx y SpbCx. 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 explica la redacció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 métodos GetDefaultAsync() 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.
Note
Este artículo contiene referencias al término esclavo, un término que Microsoft no se condona y ha dejado de usar en nuevos productos y documentación. Cuando se elimine el término del software, también lo eliminaremos 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 correspondencia entre el nombre descriptivo del bus y el índice de recursos se especifica en la 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 a su 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 del dispositivo
- WireMode
- SlaveMode
- ResourceSource
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
- Velocidad de conexión
- Polaridad del reloj
- 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 descriptivo que acompaña , que es necesaria, se especifica en el DSD y hace referencia al índice de esta declaración de recursos.
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 SPI de MITT
- 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 único 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 de nombre descriptivo correspondiente, que es obligatoria, 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():
- SlaveMode
- ResourceSource
Los siguientes campos son marcadores de posición para los valores especificados por el usuario en tiempo de ejecución.
- SlaveAddress
- Velocidad de conexión
- AddressingMode
Requisitos del controlador I2C
- Debe usar SpbCx o ser compatible con SpbCx
- Debe haber superado las pruebas de 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 están expuestos al modo de usuario. Ofrecemos la siguiente orientación para decidir qué pines deben exponerse:
- Declare todos los pines de los conectores expuestos.
- Declara pines que están conectados a funciones útiles integradas en la placa, como botones y LED.
- No declare pines 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 motivos 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 }
Deben observarse 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 del dispositivo controlador es un controlador mapeado en memoria si establece el indicador MemoryMappedController en la estructura CLIENT_CONTROLLER_BASIC_INFORMATION en respuesta a la rutina de 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 según el número de pin.
- Los recursos GpioIO y GpioInt deben contener exactamente un número de pin en la lista de pines.
- 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 extracción debe coincidir con el estado de encendido de la patilla. Configurar el pin en el modo de pull especificado partiendo del estado de encendido no debe cambiar el estado del pin. 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 del firmware, la UEFI y los controladores no debe cambiar el estado de un pin con respecto a su estado al encenderse 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 cada pin al encenderse debe documentarse para que los usuarios puedan diseñar hardware que se conecte correctamente a un pin. Una patilla no debe cambiar de estado de forma inesperada durante el arranque.
Modos de conducción admitidos
Si el controlador GPIO admite resistencias integradas de pull-up y pull-down, además de entrada de alta impedancia y salida CMOS, debe especificarlo mediante la propiedad opcional SupportedDriveModes.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
La propiedad SupportedDriveModes indica qué modos de accionamiento son compatibles con el controlador GPIO. En el ejemplo anterior, se admiten todos los siguientes modos de accionamiento. La propiedad es una máscara de bits de los siguientes valores:
| Valor del indicador | Modo de conducción | Descripción |
|---|---|---|
| 0x1 | Alta impedancia de entrada | 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 | OutputCmos | El pin puede generar tanto niveles altos como niveles bajos fuertes (a diferencia de una salida 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 adaptador de nivel antes de llegar a un conector de pines accesible, indique los modos de salida admitidos por el SoC, incluso si el modo de salida no pudiera observarse en el conector externo. Por ejemplo, si un pin pasa por un adaptador de nivel bidireccional que hace que el pin se comporte como un drenador abierto con pull-up resistivo, nunca se observará un estado de alta impedancia en la cabecera expuesta, aunque el pin esté configurado como una entrada de alta impedancia. Aun así, debe indicar que el pin admite una entrada de alta impedancia.
Numeración de pines
Windows admite dos esquemas de numeración de patillas:
- 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 nativa de pines – Los usuarios ven los números de pin indicados en los 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 patillas en lugar de la numeración secuencial de patillas. 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 nativa de pines, 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 función de devolución de llamada CLIENT_QueryControllerBasicInformation del controlador GpioClx.
Elija el esquema de numeración más compatible con la documentación ya publicada para su placa. Por ejemplo, Raspberry Pi usa la numeración nativa de pines porque muchos diagramas de distribución de pines existentes usan la numeración de pines 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 utilizar una numeración secuencial o nativa de las patillas debe buscar reducir la confusión entre los desarrolladores.
Requisitos del controlador GPIO
- Debe usar
GpioClx - Debe estar mapeada en memoria en el SoC.
- Debe usar el control de interrupciones de ActiveBoth emulado.
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 de bandeja de entrada Serial.sys es uno de estos casos.
Para exponer al modo de usuario un UART de estilo SerCx, 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 descriptivo 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 patillas es la capacidad de usar la misma patilla física 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 multiplexor controla qué función está activa en el pin en cada momento. 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 permite volver a configurar las asignaciones de funciones de los pines en tiempo de 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 los pines de una placa y hace que el hardware sea compatible con una gama más amplia de aplicaciones que las que permitiría 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 un bus mediante OpenPin() o FromIdAsync(), los pines físicos subyacentes se multiplexan automáticamente para la función solicitada. Si los pines ya están en uso por otra función, la llamada a OpenPin() o FromIdAsync() fallará. Cuando el usuario cierra el dispositivo mediante la eliminación del objeto GpioPin, I2cDevice, SpiDevice o SerialDevice , se liberan las patillas, lo que permite que se abran posteriormente para una función diferente.
Windows contiene soporte integrado para la multiplexación de pines en los marcos de trabajo GpioClx, SpbCx y SerCx. Estos marcos de trabajo funcionan conjuntamente para asignar automáticamente un pin a la función correcta cuando se accede a un pin GPIO o a un bus. El acceso a los pines se gestiona para evitar conflictos entre múltiples clientes. Además de este soporte integrado, las interfaces y los protocolos para la multiplexación de pines 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 multiplexación de pines
En esta sección se describen las interfaces y los protocolos subyacentes que intervienen en la multiplexación de pines. No es necesario conocer los protocolos subyacentes para ofrecer compatibilidad con la multiplexación de pines mediante los controladores GpioClx/SpbCx/SerCx. Para obtener más información sobre cómo admitir la multiplexación de pines con controladores GpioCls/SpbCx/SerCx, consulte Implementación de la compatibilidad con la multiplexación de pines en controladores cliente GpioClx y Uso de la compatibilidad con la multiplexación en controladores SpbCx y SerCx.
La multiplexación de pines se lleva a cabo gracias a la interacción de varios componentes.
- Controladores de multiplexación de pines: son controladores que gestionan el bloque de control de la multiplexación de pines. Los servidores de multiplexación de pines reciben solicitudes de multiplexación de pines de los clientes mediante solicitudes para reservar recursos de multiplexación (a través de IRP_MJ_CREATE) y solicitudes para cambiar la función de un pin (mediante solicitudes *IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS-). El gestor de multiplexación de pines suele ser el controlador GPIO, ya que el bloque de multiplexación a veces está integrado en el 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 pines: son controladores que utilizan la multiplexación de pines. 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 administra el concentrador de recursos. Los clientes de multiplexación de pines reservan recursos de multiplexación de pines abriendo un descriptor de acceso al recurso. Para efectuar un cambio en el hardware, los clientes deben aplicar la configuración enviando una solicitud IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS. Los clientes liberan los recursos de multiplexación de pines al cerrar el descriptor, momento en el que la configuración de multiplexación vuelve a su estado predeterminado.
- firmware ACPI – especifica la configuración de multiplexación con los recursos
MsftFunctionConfig(). Los recursos MsftFunctionConfig expresan qué pines, en qué configuración de multiplexación, son necesarios por un cliente. Los recursos MsftFunctionConfig contienen el número de función, la configuración pull y la lista de números de pines. Los recursos MsftFunctionConfig se proporcionan a los clientes de multiplexación de pines como recursos de hardware, y los controladores los reciben en su rutina de devolución de llamada PrepareHardware, de forma 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 la opción de la línea de comandos
/MsftInternalaasl.exepara compilar archivos ASL que contengan descriptoresMsftFunctionConfig(), ya que estos descriptores están siendo revisados actualmente por el grupo de trabajo de ACPI. Por ejemplo:asl.exe /MsftInternal dsdt.asl
A continuación se muestra la secuencia de operaciones necesarias para la multiplexación de pines.
- El cliente recibe recursos MsftFunctionConfig del firmware ACPI en su función de devolución de llamada EvtDevicePrepareHardware().
- El cliente usa la función
RESOURCE_HUB_CREATE_PATH_FROM_ID()auxiliar del centro de recursos 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 el arbitraje del acceso compartido para cada pin del descriptor y completa la solicitud de IRP_MJ_CREATE.
- El cliente envía una solicitud IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS sobre el identificador recibido.
- En respuesta a IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, el servidor realiza la operación de multiplexación de hardware activando la función especificada en cada pin.
- El cliente procede con las operaciones que dependen de la configuración de multiplexación de pines solicitada.
- Cuando el cliente ya no requiere que se muxen las patillas, cierra el identificador.
- Cuando se cierra el descriptor, el servidor restablece 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 controladores de controladora SerCx y SpbCx, ya que los frameworks implementan este protocolo en su nombre.
Análisis de recursos
Un controlador WDF recibe MsftFunctionConfig() recursos 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 pines, reserva y confirma el recurso 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 mediante una llamada a WdfObjectDelete() o WdfIoTargetClose() si piensa reutilizar WDFIOTARGET.
WdfObjectDelete(resourceHandle);
Cuando el cliente cierra su descriptor del recurso, los pines se reconfiguran a su estado inicial y ahora pueden ser adquiridos por otro cliente.
Descripción del protocolo para los servidores de multiplexación de pines
En esta sección se describe cómo un servidor de multiplexación de pines pone su funcionalidad a disposición de los clientes. Esto no se aplica a los GpioClx controladores miniport, ya que la infraestructura implementa este protocolo en nombre de los controladores de cliente. Para obtener más información sobre cómo implementar la compatibilidad con la multiplexación de pines en los controladores cliente GpioClx, consulte Implementación de la compatibilidad con la multiplexación en los controladores cliente GpioClx.
Procesamiento de solicitudes IRP_MJ_CREATE
Los clientes abren un descriptor de un recurso cuando quieren reservar un recurso de multiplexación de pines. Un servidor de multiplexación de pines recibe solicitudes IRP_MJ_CREATE a través de una operación de nueva resolución procedentes del concentrador de recursos. El último componente de la ruta de acceso de la solicitud IRP_MJ_CREATE contiene el identificador del concentrador 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 del descriptor el modo de uso compartido y la lista de pines. A continuación, debe realizar el arbitraje del uso compartido de las patillas y, si tiene éxito, marcar las patillas como reservadas antes de completar la solicitud.
El arbitraje de compartición se completa correctamente si se completa correctamente para cada pin de la lista de pines. Cada pin debe gestionarse 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 de forma exclusiva, el arbitraje de compartición falla.
- Si el pin ya está reservado como compartido,
- y la solicitud entrante se comparte, el arbitraje de uso compartido se realiza correctamente.
- y la solicitud entrante es exclusiva, falla el arbitraje compartido.
Si se produce un error en el arbitraje de uso compartido, la solicitud debe completarse con STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE. Si el arbitraje compartido se realiza correctamente, la solicitud debe completarse 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>.
Control 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 controlador 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 hardware.
- Configure el pin para la función especificada por el 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 cierre el descriptor, el servidor tendrá que restablecer los pines a la configuración que tenían 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.
Control de solicitudes de IRP_MJ_CLOSE
Cuando un cliente ya no requiere un recurso de multiplexación, cierra su identificador. Cuando un servidor recibe una solicitud IRP_MJ_CLOSE, debe revertir las patillas al estado en el que estaban cuando se recibió IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS. Si el cliente nunca envió un IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, no es necesario realizar ninguna acción. Entonces, el servidor debe marcar los pines como disponibles para 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 para la redacción de las tablas ACPI
En esta sección se describe cómo proporcionar recursos de multiplexación a los controladores cliente. Tenga en cuenta que necesitará la compilación 14327 del compilador ASL de Microsoft o una posterior para compilar tablas que contengan recursos MsftFunctionConfig().
MsftFunctionConfig() los recursos se suministran a los clientes de multiplexación de pines como recursos de hardware.
MsftFunctionConfig() Los recursos deben proporcionarse a los controladores que requieren cambios en la multiplexación de pines, que normalmente son los controladores SPB y de serie, pero no deben proporcionarse a los controladores de periféricos SPB y de periféricos serie, ya que el controlador se encarga de la configuración de la 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: uno de
- PullDefault – usar la configuración pull predeterminada al encender 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 – número de función que se va a programar en el multiplexor.
- ResourceSource – la ruta del espacio de nombres ACPI del servidor de multiplexado de pines
- ResourceSourceIndex: establézcalo en 0.
- ResourceConsumer/ResourceProducer: establézcalo en ResourceConsumer.
- VendorData – datos binarios opcionales cuyo significado está definido por el servidor de multiplexación de pines. Esto normalmente debe dejarse en blanco
- Lista de pines – una lista de números de pin separados por comas a los que se aplica esta configuración. Cuando el controlador de multiplexación de pines es un controlador GpioClx, se trata de números de pin GPIO y tienen el mismo significado que los números de pin en un descriptor GpioIo.
El ejemplo siguiente muestra cómo se podría proporcionar un recurso MsftFunctionConfig() al controlador 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 la memoria y los recursos de interrupción que normalmente requiere un controlador del controlador, también se especifica un recurso MsftFunctionConfig(). Este recurso permite al controlador I2C configurar los pines 2 y 3, gestionados por el nodo de dispositivo en \_SB.GPIO0, con la función 4 y la resistencia pull-up habilitada.
Compatibilidad con la multiplexación en controladores cliente GpioClx
GpioClx admite de forma nativa la multiplexación de pines. Los controladores miniport de GpioClx (también denominados “controladores cliente de GpioClx”) controlan el hardware del controlador GPIO. A partir de la compilación 14327 de Windows 10, los controladores miniport de GpioClx pueden admitir la multiplexación de pines mediante la implementación de dos nuevas DDI:
- CLIENT_ConnectFunctionConfigPins: llamado por
GpioClxpara indicar al controlador miniport que aplique la configuración de multiplexación especificada. - CLIENT_DisconnectFunctionConfigPins –
GpioClxla llama para ordenar al controlador miniport que revierta la configuración de multiplexación.
Consulte Funciones de devolución de llamada de eventos de GpioClx para obtener una descripción de estas rutinas.
Además de estos dos nuevos DDI, deben auditarse los DDI existentes para comprobar su compatibilidad con la multiplexación de pines:
- CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt – GpioClx invoca a CLIENT_ConnectIoPins para indicar al controlador miniport que configure un conjunto de pines como entrada o salida 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 que se encontraban cuando se llamó a CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt, a menos que se especifique el indicador PreserveConfiguration. Además de restablecer la dirección de los pines a su estado predeterminado, el minipuerto también debe restablecer la configuración de multiplexación de cada pin al estado en que se encontraba cuando se llamó a la rutina _Connect.
Por ejemplo, supongamos que la configuración de multiplexación predeterminada de un pin es UART y que el pin también puede utilizarse como GPIO. Cuando se llama a CLIENT_ConnectIoPins para conectar el pin como GPIO, se debe configurar el pin para GPIO y, en CLIENT_DisconnectIoPins, se debe volver a configurar el pin como UART. En general, las rutinas Desconexión deben deshacer las operaciones realizadas por las rutinas Connect.
Compatibilidad de la multiplexación en los controladores SpbCx y SerCx
A partir de la compilación 14327 de Windows 10, los marcos SpbCx y SerCx contienen compatibilidad integrada con la multiplexación de pines, lo que permite que los controladores SpbCx y SerCx actúen como clientes de multiplexación de pines sin necesidad de realizar cambios de código en los propios controladores. Por extensión, cualquier controlador periférico SpbCx/SerCx que se conecte a un controlador SpbCx/SerCx con capacidad de multiplexación activará la multiplexación de pines.
En el diagrama siguiente se muestran las dependencias entre cada uno de estos componentes. Como se puede ver, la multiplexación de pines introduce una dependencia de los controladores SerCx y SpbCx con respecto al controlador GPIO, que normalmente es el responsable de la multiplexación.
Durante la inicialización del dispositivo, los frameworks SpbCx y SerCx analizan todos los recursos MsftFunctionConfig() suministrados al dispositivo como recursos de hardware. SpbCx/SerCx adquieren y liberan después los recursos de multiplexación de pines según sea necesario.
SpbCx aplica la configuración de multiplexación de pines en su rutina de tratamiento de IRP_MJ_CREATE, justo antes de llamar a la función de devolución de llamada EvtSpbTargetConnect() del controlador cliente. Si no se pudo aplicar la configuración de multiplexación, no se llamará a la función de retorno EvtSpbTargetConnect() del controlador del controlador. Por lo tanto, un controlador de SPB puede suponer que las patillas están multiplexadas para la función SPB cuando se llama a EvtSpbTargetConnect().
SpbCx revierte la configuración de multiplexación de pines en su rutina de tratamiento de IRP_MJ_CLOSE, justo después de invocar la callback EvtSpbTargetDisconnect() del controlador. El resultado es que los pines se asignan a la función SPB siempre que un controlador de periférico abre un identificador del controlador SPB, y dejan de estar asignados a esa función cuando el controlador de periférico cierra dicho identificador.
SerCx se comporta de forma similar.
SerCx adquiere todos los MsftFunctionConfig() recursos en su controlador IRP_MJ_CREATE justo antes de invocar la función de devolución de llamada EvtSerCx2FileOpen() del controlador, y libera todos los recursos en su controlador de IRP_MJ_CLOSE justo después de invocar la función de devolución de llamada EvtSerCx2FileClose del controlador.
La implicación de la multiplexación dinámica de pines para los controladores de SerCx y SpbCx es que deben ser capaces de tolerar que, en determinados momentos, los pines se reasignen y dejen de estar asignados a la función SPB/UART. Los controladores del controlador deben asumir que las patillas no se multiplexen hasta que se llame a EvtSpbTargetConnect() o a EvtSerCx2FileOpen(). No es necesario que los pines estén multiplexados a la función SPB/UART durante las siguientes rutinas de devolución de llamada. Lo siguiente no es una lista completa, sino que representa las rutinas de PNP más comunes implementadas por los controladores del controlador.
- DriverEntry
- EvtDriverDeviceAdd
- EvtDevicePrepareHardware/EvtDeviceReleaseHardware
- EvtDeviceD0Entry/EvtDeviceD0Exit
Comprobación
Cuando esté listo para probar rhproxy, resulta útil usar el siguiente procedimiento paso a paso.
- Compruebe que los controladores
SpbCx,GpioClxySerCxse cargan y funcionan 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
Verificar los controladores del dispositivo
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 resolución de problemas de los controladores SpbCx, GpioClx o 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 puesta en marcha 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.
Active la firma de prueba en el sistema sometido a 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 o bien los recursos pasados a rhproxy apuntan a nodos ACPI no válidos, o bien los dispositivos de destino no se inician. En primer lugar, vuelva a comprobar que todos los dispositivos funcionan correctamente (consulte «Verificar los controladores del mando», más 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, vuelva a comprobar los índices de recursos en el DSD y verifique que los recursos GPIO estén especificados en orden ascendente por número de pin.
Comprobar que los dispositivos esperados se exponen al modo de usuario
Ahora que rhproxy está en ejecución, debería haber creado interfaces de dispositivo a las que se puede acceder desde el modo de usuario. Usaremos varias herramientas de línea de comandos para enumerar dispositivos y ver que están presentes.
Clone el repositorio https://github.com/ms-iot/samples y compile 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 sus nombres reconocibles en la lista. Si no ve los dispositivos correctos y los nombres reconocibles, vuelva a comprobar 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 (serie). 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.
Ejecución de las pruebas de HLK
Descargue el Kit de laboratorio de hardware (HLK). Están disponibles las siguientes pruebas:
- Pruebas funcionales y de esfuerzo de GPIO WinRT
- Pruebas de escritura de I2C WinRT (se requiere EEPROM)
- Pruebas de lectura de I2C WinRT (se requiere EEPROM)
- Pruebas de direcciones de esclavos inexistentes de WinRT de I2C
- Pruebas funcionales avanzadas de I2C para WinRT (requiere mbed LPC1768)
- Pruebas de verificación de la frecuencia de reloj de SPI WinRT (se requiere mbed LPC1768)
- Pruebas de transferencia de E/S de WinRT (requiere una mbed LPC1768)
- Pruebas de verificación del stride de SPI WinRT
- Pruebas de detección de intervalos entre transferencias de SPI WinRT (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 MITT I2C
- GpioTestTool
- I2cTestTool
- SpiTestTool
- MinComm (Serial)
- 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 Asignación de pines de 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;
}