Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
No Windows 10 e posterior, as APIs são fornecidas com acesso direto do modo de usuário ao GPIO (entrada/saída de uso geral), I2C (Circuito de Inter-Integrated), SPI (Interface Periférica Serial) e UART (receptor-transmissor assíncrono universal). Placas de desenvolvimento como o Raspberry Pi 2 expõem um subconjunto dessas conexões, que permitem estender um módulo de computação base com circuitos personalizados para abordar um aplicativo específico. Esses barramentos de baixo nível geralmente são compartilhados com outras funções críticas integradas, com apenas um subconjunto de pinos GPIO e barramentos expostos em cabeçalhos. Para preservar a estabilidade do sistema, é necessário especificar quais pinos e barramentos são seguros para modificação por aplicativos em modo de usuário.
Este documento descreve como especificar essa configuração no ACPI (Advanced Configuration and Power Interface) e fornece ferramentas para validar se a configuração foi especificada corretamente.
Importante
O público-alvo deste documento é a UEFI (Unified Extensible Firmware Interface) e os desenvolvedores de ACPI. Alguma familiaridade com ACPI, criação de ASL (ACPI Source Language) e SpbCx/GpioClx é assumida.
O acesso do modo de usuário a barramentos de nível baixo no Windows é inserido nas estruturas de GpioClx
e SpbCx
existentes. Um novo driver chamado RhProxy, disponível no Windows IoT Core e no Windows Enterprise, expõe recursos de GpioClx
e SpbCx
ao modo de usuário. Para habilitar as APIs, um nó de dispositivo para rhproxy deve ser declarado em suas tabelas ACPI com cada um dos recursos GPIO e SPB que devem ser expostos ao modo de usuário. Este documento explica a criação e a verificação do ASL.
ASL por exemplo
Vamos percorrer a declaração do nó do dispositivo rhproxy no Raspberry Pi 2. Primeiro, crie a declaração do dispositivo ACPI no escopo \_SB.
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
}
- _HID – ID de hardware. Defina-a como uma ID de hardware específica do fornecedor.
- _CID – ID compatível. Deve ser "MSFT8000".
- _UID – ID única. Defina para 1.
Em seguida, declaramos cada um dos recursos GPIO e SPB que devem ser expostos ao modo de usuário. A ordem na qual os recursos são declarados é importante porque os índices de recursos são usados para associar propriedades aos recursos. Se houver vários barramentos I2C ou SPI expostos, o primeiro barramento declarado será considerado o barramento "padrão" para esse tipo e será a instância retornada pelos métodos GetDefaultAsync()
de Windows.Devices.I2c.I2cController e Windows.Devices.Spi.SpiController.
SPI
Raspberry Pi tem dois barramentos SPI expostos. SPI0 tem duas linhas de seleção de chip de hardware e SPI1 tem uma linha de seleção de chip de hardware. Uma declaração de recurso SPISerialBus() é necessária para cada linha de seleção de chips para cada barramento. As duas declarações de recurso SPISerialBus a seguir são para as duas linhas de seleção de chip no SPI0. O campo DeviceSelection contém um valor exclusivo que o driver interpreta como um identificador de linha de seleção de chip de hardware. O valor exato que você coloca no campo DeviceSelection depende de como o driver interpreta esse campo do descritor de conexão ACPI.
Observação
Este artigo contém referências ao termo escravo — um termo que a Microsoft não tolera e parou de usar em novos produtos e documentação. Quando o termo for removido do software, o removeremos deste artigo.
// 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
Como o software sabe que esses dois recursos devem ser associados ao mesmo barramento? O mapeamento entre o nome amigável do barramento e o índice de recursos é especificado no DSD:
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},
Isso cria um barramento chamado "SPI0" com duas linhas de seleção de chip – índices de recursos 0 e 1. Várias outras propriedades são necessárias para declarar as capacidades do barramento SPI.
Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },
As propriedades MinClockInHz e MaxClockInHz especificam as velocidades mínimas e máximas do relógio compatíveis com o controlador. A API impedirá que os usuários especifiquem valores fora desse intervalo. A velocidade do relógio é passada para o driver SPB no campo _SPE do descritor de conexão (seção ACPI 6.4.3.8.2.2).
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},
A propriedade SupportedDataBitLengths lista os comprimentos de bits de dados suportados pelo controlador. Vários valores podem ser especificados em uma lista separada por vírgulas. A API impedirá que os usuários especifiquem valores fora dessa lista. O comprimento do bit de dados é passado para o driver SPB no campo _LEN do descritor de conexão (seção ACPI 6.4.3.8.2.2).
Você pode pensar nessas declarações de recurso como "modelos". Alguns dos campos são corrigidos na inicialização do sistema, enquanto outros são especificados dinamicamente em runtime. Os seguintes campos do descritor SPISerialBus são corrigidos:
- Seleção de Dispositivos
- Polaridade de Seleção de Dispositivo
- WireMode
- Modo Escravo
- Fonte de Recursos
Os campos a seguir são espaços reservados para valores especificados pelo usuário em runtime:
- DataBitLength
- Velocidade de Conexão
- Polaridade do Clock
- ClockPhase
Como o SPI1 contém apenas uma única linha de seleção de chip, um único recurso de SPISerialBus()
é declarado:
// 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
A declaração de nome amigável que acompanha – que é necessária – é especificada no DSD e refere-se ao índice dessa declaração de recurso.
Package(2) { "bus-SPI-SPI1", Package() { 2 }},
Isso cria um barramento chamado "SPI1" e o associa ao índice de recursos 2.
Requisitos do Controlador SPI
- Deve usar
SpbCx
ou ser compatível com SpbCx - Deve ter sido aprovado nos testes de SPI do MITT
- Deve dar suporte à velocidade do relógio de 4Mhz
- Deve dar suporte ao comprimento dos dados de 8 bits
- Deve dar suporte a todos os modos spi: 0, 1, 2, 3
I2C
Em seguida, declaramos os recursos de I2C. Raspberry Pi expõe um único barramento I2C nos pinos 3 e 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
A declaração de nome amigável que acompanha – que é necessária – é especificada no DSD:
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
Isso declara um barramento I2C com o nome amigável "I2C1" que se refere ao índice de recursos 3, que é o índice do recurso I2CSerialBus() que declaramos acima.
Os seguintes campos do descritor I2CSerialBus() são fixos:
- Modo Escravo
- Fonte de Recursos
Os campos a seguir são espaços reservados para valores especificados pelo usuário em runtime.
- Endereço do Escravo
- Velocidade de Conexão
- Modo de Endereçamento
Requisitos do controlador I2C
- Deve usar spbCx ou ser compatível com SpbCx
- Deve ter passado nos testes do MITT I2C
- Deve dar suporte ao endereçamento de 7 bits
- Deve dar suporte à velocidade do relógio de 100kHz
- Deve dar suporte à velocidade do relógio de 400kHz
GPIO
Em seguida, declaramos todos os pinos GPIO expostos ao modo de usuário. Oferecemos as seguintes diretrizes para decidir quais pinos expor:
- Declare todos os pinos em cabeçalhos expostos.
- Declare os pinos que estão conectados a funções úteis integradas, como botões e LEDs.
- Não declare pinos reservados para funções do sistema ou que não estejam conectados a nada.
O bloco a seguir de ASL declara dois pinos – GPIO4 e GPIO5. Os outros pinos não são mostrados aqui para simplificar. O apêndice C contém um script de exemplo do PowerShell que pode ser usado para gerar os recursos de 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 }
Os seguintes requisitos devem ser observados ao declarar pinos GPIO:
- Há suporte apenas para controladores GPIO mapeados por memória. Não há suporte para controladores GPIO interfaciados por I2C/SPI. O driver do controlador é um controlador mapeado de memória se ele definir o sinalizador MemoryMappedController na estrutura CLIENT_CONTROLLER_BASIC_INFORMATION em resposta ao retorno de chamada CLIENT_QueryControllerBasicInformation.
- Cada pin requer um gpioIO e um recurso GpioInt. O recurso GpioInt deve seguir imediatamente o recurso GpioIO e se referir ao mesmo número de pino.
- Os recursos de GPIO devem ser ordenados aumentando o número de pinos.
- Cada recurso GpioIO e GpioInt deve conter exatamente um número de pino na lista de pinos.
- O campo ShareType de ambos os descritores deve ser Compartilhado
- O campo EdgeLevel do descritor GpioInt deve ser Edge
- O campo ActiveLevel do descritor GpioInt deve ser ActiveBoth
- O campo PinConfig
- Deve ser o mesmo nos descritores GpioIO e GpioInt
- Deve ser um de PullUp, PullDown ou PullNone. Não pode ser PullDefault.
- A configuração de pull deve corresponder ao estado de ativação do pino. Ao configurar o pino no modo de resistência configurado a partir do estado inicial, o estado do pino não deve ser alterado. Por exemplo, se a folha de dados especificar que o pino aparece com um pull up, especifique PinConfig como PullUp.
O código de inicialização de firmware, UEFI e driver não deve alterar o estado de um pino de seu estado de ativação durante a inicialização. Somente o usuário sabe o que está anexado a um pino e, portanto, quais transições de estado são seguras. O estado de ativação de cada pino deve ser documentado para que os usuários possam projetar hardware que interfaces corretamente com um pino. Um pino não deve mudar de estado inesperadamente durante a inicialização.
Modos de unidade de disco com suporte
Se o controlador GPIO oferecer suporte a resistores internos de pull-up e pull-down, além de entrada de alta impedância e saída CMOS, você deve especificar isso com a propriedade opcional SupportedDriveModes.
Package (2) { “GPIO-SupportedDriveModes”, 0xf },
A propriedade SupportedDriveModes indica quais modos de acionamento têm suporte do controlador GPIO. No exemplo acima, todos os modos de condução a seguir têm suporte. A propriedade é uma máscara de bits dos seguintes valores:
Valor do sinalizador | Modo de Condução | Descrição |
---|---|---|
0x1 | Entrada de Alta Impedância | O pino suporta entrada de alta impedância, que corresponde ao valor "PullNone" no ACPI. |
0x2 | EntradaPullUp | O pino dá suporte a um resistor de pull-up interno, que corresponde ao valor "PullUp" no ACPI. |
0x4 | InputPullDown | O pino dá suporte a um resistor de pull-down interno, que corresponde ao valor "PullDown" no ACPI. |
0x8 | OutputCmos | O pino dá suporte à geração de altas fortes e baixos fortes (em vez de ralo aberto). |
InputHighImpedance e OutputCmos são compatíveis com quase todos os controladores GPIO. Se a propriedade SupportedDriveModes não for especificada, esse será o padrão.
Se um sinal GPIO passar por um level shifter antes de chegar a um cabeçalho exposto, declare os modos de operação compatíveis com o SoC, mesmo que o drive mode não seja observável no cabeçalho externo. Por exemplo, se um pino passar por um shifter de nível bidirecional que faz com que um pino apareça como um dreno aberto com pull resistivo para cima, você nunca observará um estado de alta impedância no cabeçalho exposto mesmo se o pino estiver configurado como uma entrada de alta impedância. Você ainda deve declarar que o pin dá suporte à entrada de alta impedância.
Numeração de Pinos
O Windows dá suporte a dois esquemas de numeração de pinos:
- Numeração sequencial de pinos – os usuários veem números como 0, 1, 2... até o número de pinos expostos. 0 é o primeiro recurso GpioIo declarado em ASL, 1 é o segundo recurso GpioIo declarado em ASL e assim por diante.
- Numeração de Pino Nativo – Os usuários veem os números de pino especificados nos descritores GpioIo, por exemplo, 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },
A propriedade UseDescriptorPinNumbers informa ao Windows a usar a numeração de pinos nativa em vez de numeração de pinos sequencial. Se a propriedade UseDescriptorPinNumbers não for especificada ou seu valor for zero, o Windows usará como padrão a numeração de pino sequencial.
Se a numeração nativa de pino for usada, você também deverá especificar a propriedade PinCount.
Package (2) { “GPIO-PinCount”, 54 },
A propriedade PinCount deve corresponder ao valor retornado por meio da propriedade TotalPins na callback CLIENT_QueryControllerBasicInformation do driver GpioClx
.
Escolha o esquema de numeração mais compatível com a documentação publicada existente para sua placa. Por exemplo, Raspberry Pi usa numeração de pinos nativa porque muitos diagramas de disposição de pinos existentes usam números de pino de BCM2835. MinnowBoardMax utiliza numeração sequencial de pinos porque há poucos diagramas de pinagem existentes, e essa numeração facilita a experiência do desenvolvedor, já que apenas 10 pinos são expostos de um total de mais de 200 pinos. A decisão de usar a numeração de pino sequencial ou nativa deve ter como objetivo reduzir a confusão do desenvolvedor.
Requisitos do Driver GPIO
- Deve usar
GpioClx
- Deve estar mapeado em memória no SOC
- Deve usar tratamento de interrupção emulado do ActiveBoth
UART (Receptor-Transmissor Assíncrono Universal)
Se o driver UART usar SerCx
ou SerCx2
, você poderá usar rhproxy para expor o driver ao modo de usuário. Os drivers UART que criam uma interface de dispositivo do tipo GUID_DEVINTERFACE_COMPORT
não precisam usar rhproxy. O driver da caixa de entrada Serial.sys
é um desses casos.
Para expor um UART de estilo SerCx
ao modo de usuário, declare um recurso de UARTSerialBus
da seguinte maneira.
// 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
,
,
,
)
Somente o campo ResourceSource é corrigido enquanto todos os outros campos são espaços reservados para valores especificados em runtime pelo usuário.
A declaração de nome amigável que acompanha é:
Package(2) { "bus-UART-UART2", Package() { 2 }},
Isso atribui o nome amigável "UART2" ao controlador, que é o identificador que os usuários usarão para acessar o barramento em modo de usuário.
Configuração de Pinos em Tempo de Execução
O pin muxing é a capacidade de usar o mesmo pin físico para funções diferentes. Vários periféricos diferentes no chip, como um controlador I2C, um controlador SPI e um controlador GPIO, podem ser roteados para o mesmo pino físico em um SOC. O bloco mux controla qual função está ativa no pino em um determinado momento. Tradicionalmente, o firmware é responsável por estabelecer atribuições de função na inicialização e essa atribuição permanece estática durante a sessão de inicialização. O pin muxing em tempo de execução possibilita reconfigurar as atribuições de função dos pinos durante o tempo de execução. Permitir que os usuários escolham a função de um pin em runtime acelera o desenvolvimento, permitindo que os usuários reconfigurem rapidamente os pinos de uma placa e permite que o hardware dê suporte a uma gama mais ampla de aplicativos do que uma configuração estática.
Os usuários consomem suporte de muxing para GPIO, I2C, SPI e UART sem escrever nenhum código adicional. Quando um usuário abre um GPIO ou um barramento usando OpenPin() ou FromIdAsync(), os pinos físicos subjacentes são automaticamente multiplexados para a função solicitada. Se os pinos já estiverem em uso por uma função diferente, a chamada OpenPin() ou FromIdAsync() falhará. Quando o usuário fecha o dispositivo descartando o GpioPin, I2cDevice, SpiDevice ou objeto serialDevice, os pinos são liberados, permitindo que eles sejam abertos posteriormente para uma função diferente.
O Windows contém suporte interno para pin muxing nas estruturas GpioClx, estruturas SpbCxe estruturas SerCx. Esses frameworks funcionam em conjunto para alternar automaticamente um pino para sua função correta quando um pino GPIO ou barramento é acessado. O acesso aos pinos é arbitrado para evitar conflitos entre vários clientes. Além desse suporte interno, as interfaces e os protocolos para o pin muxing são de uso geral e podem ser estendidos para dar suporte a dispositivos e cenários adicionais.
Este documento descreve primeiro as interfaces e protocolos subjacentes envolvidos no pin muxing e, em seguida, descreve como adicionar suporte para o pin muxing para drivers de controlador GpioClx, SpbCx e SerCx.
Arquitetura do Pin Muxing
Esta seção descreve as interfaces subjacentes e os protocolos envolvidos no pin muxing. O conhecimento dos protocolos subjacentes não é necessariamente necessário para dar suporte ao pin muxing com drivers GpioClx/SpbCx/SerCx. Para obter detalhes sobre como dar suporte ao pin muxing com drivers GpioCls/SpbCx/SerCx, consulte Implementando o suporte a pin muxing em drivers de cliente GpioClx e Consumindo suporte a muxing em drivers de controlador SpbCx e SerCx.
A multiplexação de pinos é feita através da cooperação de vários componentes.
- Pinagem de servidores de multiplexação – esses são drivers que controlam o bloco de controle de multiplexação de pinos. Os servidores pin muxing recebem solicitações de pin muxing de clientes por meio de solicitações para reservar recursos de muxing (por meio de IRP_MJ_CREATE) solicitações e solicitações para alternar a função de um pin (por meio de solicitações *IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS). O servidor de multiplexação de pinos geralmente é o driver GPIO, já que o bloco de multiplexação às vezes faz parte do bloco GPIO. Mesmo que o bloco de muxing seja um periférico separado, o driver GPIO é um local lógico para colocar a funcionalidade de muxing.
- Clientes de multiplexação de pinos – estes são drivers que consomem multiplexação de pinos. Os clientes de multiplexação de pinos recebem recursos de multiplexação de pinos do firmware ACPI. Os recursos de multiplexação de pinos são um tipo de recurso de interligação e são gerenciados pelo hub de recursos. Os clientes reservam recursos de muxing de pinos ao abrir um identificador para o recurso. Para realizar uma alteração de hardware, os clientes devem confirmar a configuração enviando uma solicitação IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS. Os clientes liberam recursos de multiplexação de pinos ao fechar o identificador, momento em que a configuração de multiplexação retorna ao seu estado padrão.
- Firmware ACPI – especifica configuração de multiplexagem com recursos de
MsftFunctionConfig()
. Os recursos MsftFunctionConfig definem quais pinos, na configuração de muxing em que são exigidos pelo cliente. Os recursos MsftFunctionConfig contêm número de função, configuração de pull e lista de números de pinos. Os recursos MsftFunctionConfig são fornecidos como recursos de hardware para clientes de muxing, sendo recebidos por drivers em seu callback PrepareHardware, de forma semelhante aos recursos de conexão GPIO e SPB. Os clientes recebem uma ID de hub de recurso que pode ser usada para abrir um acesso ao recurso.
Você deve passar a opção de linha de comando
/MsftInternal
paraasl.exe
para compilar arquivos ASL que contêm descritoresMsftFunctionConfig()
, já que esses descritores estão atualmente sob análise pelo comitê de trabalho do ACPI. Por exemplo:asl.exe /MsftInternal dsdt.asl
A sequência de operações envolvidas no pin muxing é mostrada abaixo.
- O cliente recebe recursos MsftFunctionConfig do firmware ACPI em seu EvtDevicePrepareHardware() retorno de chamada.
- O cliente usa a função auxiliar do hub de recursos
RESOURCE_HUB_CREATE_PATH_FROM_ID()
para criar um caminho a partir da ID do recurso e, em seguida, abre um identificador para o caminho (usando ZwCreateFile(), IoGetDeviceObjectPointer()ou WdfIoTargetOpen()). - O servidor extrai a ID do hub de recursos do caminho do arquivo usando funções auxiliares do hub de recursos
RESOURCE_HUB_ID_FROM_FILE_NAME()
e consulta o hub de recursos para obter o descritor de recursos. - O servidor executa a arbitragem de compartilhamento para cada pin no descritor e conclui a solicitação de IRP_MJ_CREATE.
- O cliente emite uma solicitação IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS no identificador recebido.
- Em resposta a IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, o servidor executa a operação de muxing de hardware, tornando a função especificada ativa em cada pin.
- O cliente prossegue com operações que dependem da configuração solicitada de multiplexação de pinos.
- Quando o cliente não exige mais que os pinos sejam multiplexados, ele fecha o manipulador.
- Em resposta ao identificador que é fechado, o servidor reverte os pinos ao seu estado inicial.
Descrição do protocolo para clientes de pin muxing
Esta seção descreve como um cliente consome a funcionalidade de pin muxing. Isso não se aplica a drivers de controlador SerCx
e SpbCx
, uma vez que as estruturas implementam esse protocolo em nome dos drivers do controlador.
Analisando recursos
Um driver WDF recebe recursos MsftFunctionConfig()
na rotina EvtDevicePrepareHardware(). Os recursos msftFunctionConfig podem ser identificados pelos seguintes campos:
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
Uma rotina de EvtDevicePrepareHardware()
pode extrair recursos MsftFunctionConfig da seguinte maneira:
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;
}
Reservando e confirmando recursos
Quando um cliente deseja fazer multiplexação de pinos, ele reserva e confirma o recurso MsftFunctionConfig. O exemplo a seguir mostra como um cliente pode reservar e 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;
}
O driver deve armazenar o WDFIOTARGET em uma de suas áreas de contexto para que ele possa ser fechado posteriormente. Quando o driver estiver pronto para liberar a configuração de muxing, deverá fechar o identificador de recurso chamando WdfObjectDelete()ou WdfIoTargetClose() se pretende-se reutilizar o WDFIOTARGET.
WdfObjectDelete(resourceHandle);
Quando o cliente fecha seu identificador de recurso, os pinos são restaurados ao estado inicial, e agora podem ser adquiridos por um cliente diferente.
Descrição do protocolo para servidores de multiplexação de pinos
Esta seção descreve como um servidor de pin muxing expõe sua funcionalidade aos clientes. Isso não se aplica aos miniport drivers GpioClx
, pois a framework implementa esse protocolo em nome dos drivers cliente. Para obter detalhes sobre como suportar a multiplexação de pinos em drivers de cliente GpioClx
, consulte Implementando o suporte a multiplexação em drivers de cliente GpioClx.
Tratamento de solicitações IRP_MJ_CREATE
Os clientes abrem um identificador para um recurso quando desejam reservar um recurso de pin muxing. Um servidor de configuração de pinos (pin muxing) recebe IRP_MJ_CREATE solicitações por meio de uma operação de reinterpretação do hub de recursos. O componente de caminho final da solicitação IRP_MJ_CREATE contém a ID do hub de recursos, que é um inteiro de 64 bits no formato hexadecimal. O servidor deve extrair o ID do hub de recursos do nome do arquivo usando RESOURCE_HUB_ID_FROM_FILE_NAME()
do reshub.h e enviar IOCTL_RH_QUERY_CONNECTION_PROPERTIES ao hub de recursos para obter o descritor MsftFunctionConfig()
.
O servidor deve validar o descritor e extrair o modo de compartilhamento e a lista de pinos do descritor. Em seguida, ele deve executar a arbitragem de compartilhamento para os pinos e, caso seja bem-sucedido, marcar os pinos como reservados antes de concluir a solicitação.
A arbitragem de compartilhamento terá êxito geral se a arbitragem de compartilhamento for bem-sucedida para cada pino na lista de pinos. Cada pino deve ser arbitrado da seguinte maneira:
- Se o pino ainda não estiver reservado, a arbitragem de compartilhamento terá êxito.
- Se o pino já estiver reservado como exclusivo, a arbitragem de compartilhamento falhará.
- Se o pino já estiver reservado como compartilhado,
- e a solicitação de entrada é compartilhada, a arbitragem de compartilhamento é bem-sucedida.
- e a solicitação de entrada é exclusiva, a arbitragem de compartilhamento falha.
Se a arbitragem de compartilhamento falhar, a solicitação deverá ser concluída com STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE. Se a arbitragem de compartilhamento tiver sucesso, a solicitação deve ser concluída com STATUS_SUCCESS.
Observe que o modo de compartilhamento da solicitação de entrada deve ser obtido do descritor MsftFunctionConfig, e não de IrpSp->Parameters.Create.ShareAccess.
Manipulando solicitações de IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS
Depois que o cliente tiver reservado com êxito um recurso MsftFunctionConfig abrindo um identificador, ele poderá enviar IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS para solicitar que o servidor execute a operação de muxing de hardware real. Quando o servidor recebe IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, para cada pino na lista de pinos, ele deve
- Defina o modo de pull especificado no membro PinConfiguration da estrutura PNP_FUNCTION_CONFIG_DESCRIPTOR em hardware.
- Multiplexe o pino na função especificada pelo membro FunctionNumber da estrutura PNP_FUNCTION_CONFIG_DESCRIPTOR.
Em seguida, o servidor deve concluir a solicitação com STATUS_SUCCESS.
O significado de FunctionNumber é definido pelo servidor e entende-se que o descritor MsftFunctionConfig foi criado com conhecimento de como o servidor interpreta esse campo.
Lembre-se de que, quando a alça for fechada, o servidor terá que restaurar a configuração dos pinos para como estavam quando IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS foi recebido, de modo que o servidor talvez precise salvar o estado dos pinos antes de modificá-los.
Tratamento de solicitações IRP_MJ_CLOSE
Quando um cliente não precisa mais de um recurso de muxing, ele fecha o identificador. Quando um servidor recebe uma solicitação IRP_MJ_CLOSE, ele deve reverter os pinos para o estado em que estavam quando IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS foi recebido. Se o cliente nunca enviou um IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, nenhuma ação será necessária. Em seguida, o servidor deve marcar os pinos como disponíveis em relação à arbitragem de compartilhamento e concluir a solicitação com STATUS_SUCCESS. Certifique-se de sincronizar corretamente o tratamento de IRP_MJ_CLOSE com o de IRP_MJ_CREATE.
Diretrizes de criação para tabelas ACPI
Esta seção descreve como fornecer recursos de muxing para drivers cliente. Observe que você precisará do compilador do Microsoft ASL build 14327 ou posterior para compilar tabelas que contêm recursos MsftFunctionConfig()
.
MsftFunctionConfig()
recursos são fornecidos aos clientes de muxing como recursos de hardware. Os recursos MsftFunctionConfig()
devem ser fornecidos a drivers que exigem alterações de multiplexação de pinos, que normalmente são drivers de controlador SPB e serial. No entanto, não devem ser fornecidos a drivers de periféricos SPB e serial, já que o driver do controlador gerencia a configuração de multiplexação.
A macro ACPI MsftFunctionConfig()
é definida da seguinte maneira:
MsftFunctionConfig(Shared/Exclusive
PinPullConfig,
FunctionNumber,
ResourceSource,
ResourceSourceIndex,
ResourceConsumer/ResourceProducer,
VendorData) { Pin List }
- Compartilhado/Exclusivo – se exclusivo, esse pin pode ser adquirido por um único cliente de cada vez. Se compartilhado, vários clientes compartilhados poderão adquirir o recurso. Sempre defina isso como exclusivo, pois permitir que vários clientes não codificados acessem um recurso mutável pode levar a corridas de dados e, portanto, resultados imprevisíveis.
- PinPullConfig – um dos
- PullDefault – use a configuração de pull padrão do power-on definida pelo SOC
- PullUp – habilitar o resistor de pull-up
- PullDown – habilitar o resistor de pull-down
- PullNone – desabilitar todos os resistores de pull
- FunctionNumber – o número da função a ser programada no mux.
- ResourceSource – O caminho do namespace ACPI do servidor de multiplexação de pino
- ResourceSourceIndex – defina-o como 0
- ResourceConsumer/ResourceProducer – defina-o como ResourceConsumer
- VendorData – dados binários opcionais cujo significado é definido pelo servidor de pin muxing. Isso geralmente deve ser deixado em branco
- Lista de pinos – uma lista separada por vírgulas de números de pino aos quais a configuração se aplica. Quando o servidor de pin muxing é um driver GpioClx, estes são números de pinos GPIO e têm o mesmo significado que os números de pinos em um descritor GpioIo.
O exemplo a seguir mostra como é possível fornecer um recurso MsftFunctionConfig() a um driver de 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)
}
}
Além dos recursos de memória e interrupção normalmente exigidos por um driver de controlador, um recurso de MsftFunctionConfig()
também é especificado. Esse recurso permite que o driver do controlador I2C coloque os pinos 2 e 3 – gerenciados pelo nó do dispositivo em \_SB. GPIO0 – na função 4 com o resistor de pull-up habilitado.
Suporte a muxing em drivers de cliente GpioClx
GpioClx
tem suporte interno para a multiplexação de pinos. Os drivers de miniporto GpioClx (também conhecidos como "drivers cliente GpioClx") operam o hardware do controlador GPIO. A partir do Windows 10 build 14327, os drivers de miniporto GpioClx podem adicionar suporte para o pin muxing implementando dois novos DDIs:
- CLIENT_ConnectFunctionConfigPins – chamado por
GpioClx
para comandar o driver de miniporto para aplicar a configuração de muxing especificada. - CLIENT_DisconnectFunctionConfigPins – chamado por
GpioClx
para instruir o miniport driver a reverter a configuração de muxing.
Consulte as funções de retorno de chamada de evento GpioClx para obter uma descrição dessas rotinas.
Além desses dois novos DDIs, os DDIs existentes devem ser auditados para compatibilidade com pin muxing.
- CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt – CLIENT_ConnectIoPins é chamado pelo GpioClx para comandar o driver de miniporto a configurar um conjunto de pinos para entrada ou saída GPIO. GPIO e MsftFunctionConfig são mutuamente exclusivos, o que significa que um pino nunca será conectado para GPIO e MsftFunctionConfig ao mesmo tempo. Como a função padrão de um pino pode não ser GPIO, um pino pode não estar necessariamente configurado como GPIO quando ConnectIoPins é chamado. ConnectIoPins é necessário para realizar todas as operações necessárias para preparar o pino para entrada/saída do GPIO, incluindo operações de multiplexação. CLIENT_ConnectInterrupt deve se comportar de maneira similar, pois as interrupções podem ser consideradas como um caso especial de entrada GPIO.
- CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – essa rotina deve retornar pinos ao estado em que estavam quando CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt foi chamado, a menos que o sinalizador PreserveConfiguration seja especificado. Além de reverter a direção dos pinos para seu estado padrão, o miniporto também deve reverter o estado de multiplexação de cada pino para o estado em que estava quando a rotina _Connect foi chamada.
Por exemplo, suponha que a configuração de muxing padrão de um pino seja UART e que o pino também possa ser usado como GPIO. Quando CLIENT_ConnectIoPins é chamado para conectar o pino para GPIO, ele deve mux o pino para GPIO e, em CLIENT_DisconnectIoPins, ele deve mux o pino de volta para UART. Em geral, as rotinas de desconexão devem desfazer as operações feitas pelas rotinas do Connect.
Dar suporte ao muxing em drivers de controlador SpbCx e SerCx
A partir do Windows 10 build 14327, as estruturas SpbCx
e SerCx
contêm suporte interno para multiplexação de pinos, o que permite que drivers de controlador SpbCx
e SerCx
sejam clientes de multiplexação de pinos sem alterações de código nos drivers de controlador. Por extensão, qualquer driver periférico SpbCx/SerCx que se conecta a um driver de controlador SpbCx/SerCx compatível com multiplexação de pinos iniciará a ativação de multiplexação de pinos.
O diagrama a seguir mostra as dependências entre cada um desses componentes. Como você pode ver, o pin muxing introduz uma dependência dos drivers de controlador SerCx e SpbCx em relação ao driver GPIO, que geralmente é responsável pelo muxing.
No momento da inicialização do dispositivo, as estruturas SpbCx
e SerCx
analisam todos os recursos MsftFunctionConfig()
fornecidos como recursos de hardware para o dispositivo. Em seguida, o SpbCx/SerCx adquire e solta os recursos de multiplexação de pinos sob demanda.
SpbCx
aplica a configuração de pin muxing em seu manipulador de IRP_MJ_CREATE, pouco antes de chamar a função de callback EvtSpbTargetConnect() do driver cliente . Se a configuração de muxing não puder ser aplicada, a função de retorno EvtSpbTargetConnect()
do driver do controlador não será chamada. Portanto, um driver do controlador SPB pode assumir que os pinos estão multiplexados para a função SPB no momento em que o EvtSpbTargetConnect()
é chamado.
SpbCx
reverte a configuração de pin muxing em seu manipulador de IRP_MJ_CLOSE, logo após invocar o EvtSpbTargetDisconnect() do driver do controlador retorno de chamada. O resultado é que os pinos são multiplexados para a função SPB sempre que um driver periférico abre um identificador para o driver do controlador SPB e são desconectados quando o driver periférico fecha o identificador.
SerCx
se comporta da mesma forma.
SerCx
adquire todos os recursos MsftFunctionConfig()
em seu manipulador de IRP_MJ_CREATE pouco antes de invocar o do driver do controlador EvtSerCx2FileOpen() retorno de chamada e libera todos os recursos em seu manipulador de IRP_MJ_CLOSE, logo após invocar o driver do controlador EvtSerCx2FileClose retorno de chamada.
A implicação da multiplexação dinâmica de pinos para os drivers dos controladores SerCx
e SpbCx
é que eles devem ser capazes de tolerar que os pinos sejam desviados da função SPB/UART em determinados momentos. Os drivers do controlador precisam assumir que os pinos não serão multiplexados até que EvtSpbTargetConnect()
ou EvtSerCx2FileOpen()
sejam chamados. Os pinos não precisam ser multiplexados para a função SPB/UART durante as seguintes chamadas de retorno. A seguir não é uma lista completa, mas representa as rotinas PNP mais comuns implementadas por drivers de controlador.
- DriverEntry
- EvtDriverDeviceAdd
- EvtDevicePrepareHardware/EvtDeviceReleaseHardware (prepara/libera hardware do dispositivo)
- EvtDeviceD0Entry/EvtDeviceD0Exit
Verificação
Quando você estiver pronto para testar o rhproxy, é útil usar o procedimento passo a passo a seguir.
- Verifique se o driver de controlador de cada
SpbCx
,GpioClx
eSerCx
está carregando e operando corretamente. - Verifique se
rhproxy
está presente no sistema. Algumas edições e builds do Windows não o têm. - Compile e carregue seu nó rhproxy usando
ACPITABL.dat
- Verifique se o nó do dispositivo
rhproxy
existe - Verifique se
rhproxy
está carregando e iniciando - Verifique se os dispositivos esperados estão expostos ao modo de usuário
- Verifique se você pode interagir com cada dispositivo na linha de comando
- Verifique se você pode interagir com cada dispositivo de um aplicativo UWP
- Executar testes HLK
Verificar drivers do controlador
Como o rhproxy expõe outros dispositivos no sistema ao modo de usuário, ele só funciona se esses dispositivos já estiverem funcionando. A primeira etapa é verificar se esses dispositivos - os controladores I2C, SPI, GPIO que você deseja expor - já estão funcionando.
No prompt de comando, execute
devcon status *
Examine a saída e verifique se todos os dispositivos de interesse foram iniciados. Se um dispositivo tiver um código de problema, você precisará solucionar por que esse dispositivo não está sendo carregado. Todos os dispositivos devem ter sido habilitados durante a inicialização da plataforma. A solução de problemas de drivers de controlador SpbCx
, GpioClx
ou SerCx
está além do escopo deste documento.
Verifique se a rhproxy está presente no sistema
Verifique se o serviço rhproxy
está presente no sistema.
reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy
Se a chave reg não estiver presente, a rhproxy não existirá em seu sistema. O Rhproxy está presente em todos os builds do IoT Core e do Windows Enterprise build 15063 e posteriores.
Compilar e carregar ASL com ACPITABL.dat
Agora que você criou um nó ASL rhproxy, é hora de compilá-lo e carregá-lo. Você pode compilar o nó rhproxy em um arquivo AML autônomo que pode ser acrescentado às tabelas ACPI do sistema. Como alternativa, se você tiver acesso às origens ACPI do sistema, poderá inserir o nó rhproxy diretamente nas tabelas ACPI da sua plataforma. No entanto, durante a configuração inicial, pode ser mais fácil usar ACPITABL.dat
.
Crie um arquivo chamado yourboard.asl e coloque o nó do dispositivo RHPX dentro de um DefinitionBlock:
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1) { Scope (\_SB) { Device(RHPX) { ... } } }
Baixe o do WDK
e localize em Execute o seguinte comando para gerar ACPITABL.dat:
asl.exe yourboard.asl
Copie o arquivo de ACPITABL.dat resultante para c:\windows\system32 em seu sistema em teste.
Ative o modo de assinatura de teste no sistema em teste:
bcdedit /set testsigning on
Reinicialize o sistema em teste. O sistema anexará as tabelas ACPI definidas em ACPITABL.dat às tabelas de firmware do sistema.
Verifique se o nó do dispositivo rhproxy existe
Execute o seguinte comando para enumerar o nó do dispositivo rhproxy.
devcon status *msft8000
A saída do devcon deve indicar que o dispositivo está presente. Se o nó do dispositivo não estiver presente, as tabelas ACPI não foram adicionadas com sucesso ao sistema.
Verificar se a rhproxy está carregando e iniciando
Verifique o status da rhproxy:
devcon status *msft8000
Se a saída indicar que o rhproxy foi iniciado, o rhproxy foi carregado e iniciado com êxito. Caso veja um código de problema, você precisará investigar. Alguns códigos de problema comuns são:
- Problema 51 –
CM_PROB_WAITING_ON_DEPENDENCY
O sistema não está iniciando a rhproxy porque uma de suas dependências falhou ao carregar. Isso significa que os recursos passados para o rhproxy apontam para nós ACPI inválidos, ou os dispositivos de destino não estão iniciando. Primeiro, verifique se todos os dispositivos estão sendo executados com êxito (consulte 'Verificar drivers de controlador' acima). Em seguida, verifique duas vezes seu ASL e certifique-se de que todos os seus caminhos de recurso (por exemplo,\_SB.I2C1
) estão corretos e apontem para nós válidos em seu DSDT. - Problema 10 –
CM_PROB_FAILED_START
– O Rhproxy não foi iniciado, provavelmente devido a um problema de análise de recursos. Revise seu ASL e verifique novamente os índices de recursos no DSD, e assegure-se de que os recursos GPIO estão especificados em ordem crescente de número de pinos.
Verifique se os dispositivos esperados estão expostos ao modo de usuário
Agora que o rhproxy está em execução, ele deve ter criado interfaces de dispositivos que podem ser acessadas pelo modo de usuário. Usaremos várias ferramentas de linha de comando para enumerar dispositivos e ver que eles estão presentes.
Clone o repositório https://github.com/ms-iot/samples e crie os exemplos GpioTestTool
, I2cTestTool
, SpiTestTool
e Mincomm
. Copie as ferramentas para seu dispositivo em teste e use os comandos a seguir para enumerar dispositivos.
I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list
Você deve ver seus dispositivos e nomes amigáveis listados. Se você não vir os dispositivos corretos e os nomes amigáveis, verifique novamente sua ASL.
Verificar cada dispositivo na linha de comando
A próxima etapa é usar as ferramentas de linha de comando para abrir e interagir com os dispositivos.
Exemplo de I2CTestTool:
I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3
Exemplo de SpiTestTool:
SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3
Exemplo de GpioTestTool:
GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off
Exemplo de MinComm (serial). Conecte o Rx ao Tx antes de executar:
MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)
Verificar cada dispositivo de um aplicativo UWP
Use os exemplos a seguir para validar que os dispositivos funcionam da UWP.
Executar os testes do HLK
Baixe odo
- Testes Funcionais e de Estresse do GPIO WinRT
- testes de gravação do WinRT I2C (necessários para EEPROM)
- Testes de Leitura de I2C WinRT (Requer EEPROM)
- Testes de Endereço Inexistente de Dispositivo I2C WinRT
- Testes Funcionais Avançados de I2C WinRT (Requer mbed LPC1768)
- Teste de Verificação de Frequência de Relógio do SPI WinRT (mbed LPC1768 obrigatório)
- Testes de Transferência de IO do SPI WinRT (LPC1768 mbed necessário)
- Testes de Verificação de Passos do SPI WinRT
- testes de detecção de lacuna de transferência do SPI WinRT (mbed LPC1768 obrigatório)
Quando você seleciona o nó do dispositivo rhproxy no gerenciador do HLK, os testes aplicáveis serão selecionados automaticamente.
No gerenciador do HLK, selecione "Dispositivo proxy do Hub de Recursos":
Em seguida, clique na guia Testes e selecione os testes I2C WinRT, Gpio WinRT e Spi WinRT.
Clique em Executar o Selecionado. A documentação adicional sobre cada teste está disponível clicando com o botão direito do mouse no teste e clicando em "Descrição do Teste".
Recursos
- especificação ACPI 5.0
- Asl.exe (Compilador do Microsoft ASL)
- Windows.Devices.Gpio
- Windows.Devices.I2c
- Windows.Devices.Spi
- Windows.Devices.SerialCommunication
- Estrutura de Criação e Execução de Teste (TAEF)
- SpbCx
- GpioClx
- serCx
- Testes de MITT I2C
- GpioTestTool
- I2cTestTool
- SpiTestTool
- MinComm (Serial)
- Kit de Laboratório de Hardware (HLK)
Apêndice
Apêndice A – Listagem asl do Raspberry Pi
Consulte também mapeamentos de pinos Raspberry Pi 2 &3
DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
Scope (\_SB)
{
//
// RHProxy Device Node to enable WinRT API
//
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
// Index 0
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE0 - GPIO 8 - Pin 24
0, // Device selection (CE0)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 1
SPISerialBus( // SCKL - GPIO 11 - Pin 23
// MOSI - GPIO 10 - Pin 19
// MISO - GPIO 9 - Pin 21
// CE1 - GPIO 7 - Pin 26
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI0", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 2
SPISerialBus( // SCKL - GPIO 21 - Pin 40
// MOSI - GPIO 20 - Pin 38
// MISO - GPIO 19 - Pin 35
// CE1 - GPIO 17 - Pin 11
1, // Device selection (CE1)
PolarityLow, // Device selection polarity
FourWireMode, // wiremode
0, // databit len: placeholder
ControllerInitiated, // slave mode
0, // connection speed: placeholder
ClockPolarityLow, // clock polarity: placeholder
ClockPhaseFirst, // clock phase: placeholder
"\\_SB.SPI1", // ResourceSource: SPI bus controller name
0, // ResourceSourceIndex
// Resource usage
) // Vendor Data
// Index 3
I2CSerialBus( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
0xFFFF, // SlaveAddress: placeholder
, // SlaveMode: default to ControllerInitiated
0, // ConnectionSpeed: placeholder
, // Addressing Mode: placeholder
"\\_SB.I2C1", // ResourceSource: I2C bus controller name
,
,
) // VendorData
// Index 4 - GPIO 4 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
// Index 6 - GPIO 5 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
// Index 8 - GPIO 6 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 6 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
// Index 10 - GPIO 12 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 12 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
// Index 12 - GPIO 13 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 13 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
// Index 14 - GPIO 16 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 16 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
// Index 16 - GPIO 18 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 18 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
// Index 18 - GPIO 22 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 22 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
// Index 20 - GPIO 23 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 23 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
// Index 22 - GPIO 24 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 24 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
// Index 24 - GPIO 25 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 25 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
// Index 26 - GPIO 26 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 26 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
// Index 28 - GPIO 27 -
GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 27 }
GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
// Index 30 - GPIO 35 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 35 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 35 }
// Index 32 - GPIO 47 -
GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 47 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 47 }
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
// Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
// SPI 0
Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }}, // Index 0 & 1
Package(2) { "SPI0-MinClockInHz", 7629 }, // 7629 Hz
Package(2) { "SPI0-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// SPI 1
Package(2) { "bus-SPI-SPI1", Package() { 2 }}, // Index 2
Package(2) { "SPI1-MinClockInHz", 30518 }, // 30518 Hz
Package(2) { "SPI1-MaxClockInHz", 125000000 }, // 125 MHz
Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }}, // Data Bit Length
// I2C1
Package(2) { "bus-I2C-I2C1", Package() { 3 }},
// GPIO Pin Count and supported drive modes
Package (2) { "GPIO-PinCount", 54 },
Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
Package (2) { "GPIO-SupportedDriveModes", 0xf }, // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
}
})
}
}
}
Apêndice B – Listagem ASL MinnowBoardMax
Consulte também Mapeamentos de Pinos do 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 – Exemplo de script do Powershell para gerar recursos de GPIO
O script a seguir pode ser usado para gerar as declarações de recurso 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;
}