USB HID - Human Interface Device Class: Exemplo com a placa FRDM-KL25Z

A classe de dispositivos USB HID foi inicialmente criada para que dispositivos de entrada de dados pudessem ser adicionados facilmente em um computador. Alguns exemplos são: teclados, mouse, joystick, entre outros. Essa classe será tomada como exemplo por ser a mais simples.

 

O artigo apresenta algumas definições gerais do protocolo USB. No final, um exemplo de aplicação executado no PC para controlar um LED da placa Freedom Board KL25Z é demonstrado. Em cada tópico algumas referências serão citadas para consulta.

 

 

Introdução ao protocolo USB

 

Quando conectamos um dispositivo USB no computador, o SO se encarrega de exportar as informações sobre o dispositivo. Essas informações são obtidas a partir dos descritores USB.

 

Propriedades de um dispositivo USB.
Figura 1: Propriedades de um dispositivo USB.

 

Essas informações são obtidas com o dispositivo conectado, utilizando requisições do tipo GetDescriptor definidas no protocolo USB. Essa requisição é estruturada por uma operação de controle chamada de Setup que é enviada para o dispositivo USB. Os elementos que compõe essa operação são ilustrados abaixo.

 

 

Esses campos especificam uma operação de controle. Por exemplo, os campos bmRequestType e bRequest indicam a operação GetDescriptor quando os respectivos valores são: 0x80 e 0x06. Outras operações são apresentadas neste link: Setup Packet.

 

0bmRequestType1Bit-MapD7 Data Phase Transfer Direction
0 = Host to Device
1 = Device to Host
D6..5 Type
0 = Standard
1 = Class
2 = Vendor
3 = Reserved
D4..0 Recipient
0 = Device
1 = Interface
2 = Endpoint
3 = Other
4..31 = Reserved
1bRequest1Value

Request

2wValue2Value

Value

4wIndex2Index or Offset

Index

6wLength2Count

Number of bytes to transfer if there is a data phase

 

Alguns campos dos descritores podem especificar uma referência para outro descritor. Por exemplo, algumas configurações são apenas mensagens (strings), como o nome do dispositivo que foi conectado. Para tal, existem descritores de string.

 

O tipo do descritor é indicado pelo campo wValue. Já o campo wIndex é utilizado conforme o descritor solicitado. Uma requisição desse tipo com wValue e wIndex iguais a 0x03 e 0x01, respectivamente, indica uma operação de leitura do descritor de string 1.

 

 

Transferência de dados

 

No tópico anterior foi apresentada a operação de controle chamada Setup. A partir da operação de Setup, o host consegue enviar e receber informações do dispositivo USB. A informação apresentada é apenas uma parte do protocolo USB. Na verdade, os campos apresentados formam um pacote de dados, denominado Setup Packet.

 

Um pacote é um conjunto de bytes.

 

Em geral, a transferência de dados entre os dois elementos ocorre em pacotes - seguindo o formato especificado no protocolo de comunicação -, sendo que cada pacote tem uma função específica. De modo geral, são definidos três tipos de transferências, com o seguinte formato: TOKEN + DATA + HANDSHAKE.

 

O Setup é uma exemplo da informação enviada em DATA.

 

Idependente do pacote, o primeiro byte enviado é um número de identificação PID (Packet Identifier) que tem apenas um byte (somente os primeiros quatro bits são utilizados para definir o tipo do pacote, o restante dos bits são espelhados). Na tabela abaixo são destacados os tipos de pacote e as respectivas funções. Os dois primeiros bits determinam o tipo e o restante é utilizado para definir a função/operação.

 

PID TypePID NamePID<3:0>
TokenOUT0001
IN1001
SOF0101
SETUP1101
DataDATA00011
DATA11011
DATA20111
MDATA1111
HandshakeACK0010
NAK1010
STALL1110
NYET0110
SpecialPRE1100
ERR1100
SPLIT1000
PING0100
Reserved0000

 

 

Operações de Controle

 

Toda transferência é iniciada enviando um pacote TOKEN. Para operação de Setup, o PID do pacote deve ser 1101. A estrutura desse pacote é ilustrada abaixo (Sync e EOP indicam o início e o fim da transferência de um pacote).

 

Sync
PID
ADDR
ENDP
CRC5
EOP
 
8 bits
7 bits
4 bits
5 bits
 

 

Essa operação de controle deve ser realizada em um dispositivo específico, sendo determinado pelo campo ADDR. Toda comunicação está relacionada a um local em que os dados são armazenados, denominado endpoint (ENDP). Um dispositivo USB pode apresentar até 16 endpoints para função de entrada (IN), e outros 16 para saída (OUT) de dados. A direção indica:

  • IN: do dispositivo para o host;
  • OUT: do host para o dispositivo.

 

Cabe ressaltar que somente o endpoint 0 é utilizado para as operações de controle.

 

Na sequência, as informações da operação de Setup são enviadas dentro do pacote DATA. 

 

Sync
PID
DATA
CRC16
EOP
 
8 bits
(0-1024)
x 8 bits
16 bits
 

 

Por fim, a conexão é finalizada com um pacote HANDSHAKE. Note que o campo PID define a operação: ACK, NAK, STALL ou NYET.

 

Sync
PID
EOP
 
8 bits
 

 

 

Fluxo de comunicação e descritores

 

A primeira comunicação servirá para descobrir o tamanho máximo do pacote que o dispositivo está configurado para operar. Os pacotes de configuração (SETUP) sempre serão enviados ao endpoint 0. Como destacado, o Setup possui 8 bytes para especificar a operação de controle. A estrutura que representa esse bloco de dados é mostrada abaixo.

 

 

Os descritores USB também podem ser implementados como estruturas. A definição de cada campo pode ser vista neste link.

 

 

 

Reports

 

Os dados que o dispositivos USB-HID exporta são transferidos por estruturas chamadas de reports. A estrutura do relatório é transformada em uma tabela de valores e armazenada em um descritor. Esse descritor é utilizado para informar o host sobre a estrutura do report.

 

Nesse exemplo, o dispositivo será utilizado somente para controlar um LED. Para construir a estrutura de um report foi utilizada a ferramenta HID Descriptor. Mais detalhes dos campos do report podem ser obtidos no mesmo link.

 

Ferramenta HID Descriptor para listar dispositivos USB HID.
Figura 2: Ferramenta HID Descriptor.

 

 

Configurando USB- HID no microcontrolador KL25Z

 

O código apresentado é uma modificação deste projeto: Minimal USB HID example for Kinetis L.

 

A configuração do controlador USB é realizada a partir de registradores e estruturas de dados armazenados em memória. O periférico controla toda recepção de pacotes e notifica a aplicação usando interrupções, facilitando o desenvolvimento da aplicação.

 

Recepção de pacotes e notificação.
Figura 3: Recepção de pacotes e notificação.

 

Quando um dispositivo é conectado no barramento USB, ocorre a condição de RESET. Nesse momento, o dispositivo deve habilitar o endpoint 0 e configurar o endereço com o valor 0. Isso é necessário, pos o host iniciará uma comunicação com o dispositivo de endereço 0 no endpoint 0. 

 

Como dito, a comunicação ocorre entre o host e um endpoint. Para facilitar tal operação, o periférico USB da KL25Z conta com uma estrutura chamada Buffer Descriptor Table (BDT) que é armazenada na memória. Nessa tabela são armazenados os descritores (BD) de cada endpoint.

 

 

Buffer Descriptor

 

O Buffer Descriptor (BD) é utilizado para controlar as operações em um endpoint. Cada endpoint possui uma configuração de 8 bytes. Considerando que cada endpoint possui um canal de entrada e outro saída, são necessários 16 bytes.

 

Para possibilitar que um endpoint possa operar enquanto os dados são processados, existe um mecanismo de double buffer. Considerando isso, o BD é utilizado para:

  • Indicar quem tem acesso ao buffer do endpoint na memória (bit OWN);
  • Determinar qual buffer está sendo utilizado (bit DATA0/1);
  • Apontar para o endereço base do endpoint na memória (32 bits);
  • Definir quantos bytes serão transferidos (campo BC de 10 bits).

 

O formato do BD é ilustrado na figura abaixo. Para mais informações, consulte o documento do microcontrolador, na página 617.

 

Estrutura do Buffer Descriptor.
Figura 4: Estrutura do Buffer Descriptor. Fonte: KL25 Sub-Family Reference Manual.

 

Para representar o BD, a seguinte estrutura foi criada.

 

 

 

Buffer Descriptor Table

 

Tal estrutura é organizada em 512 bytes na memória, sendo referenciada a partir de um conjunto de registradores chamados de BDT Page Registers.

 

A USB possui um controlador DMA dedicado que é usado para acessar o BDT. Esse mecanismo é utilizado para acessar tal região de memória quando um token é recebido. Os dados indicados no BDT serão utilizados para acessar o buffer referente ao endpoint utilizado na comunicação.

 

O endereço acessado na tabela é formado pelos elementos ilustrados na Figura abaixo.

 

Composição do endereço para acessar um BD.
Figura 5: Composição do endereço para acessar um BD. Fonte: KL25 Sub-Family Reference Manual.

 

Abaixo é mostrado a definição do BDT com um vetor de estruturas do tipo BD. Como dito, para cada endpoint existem dois buffer duplicados para entrada e saída. Logo, são quatro buffers por enpoint.

 

 

 

Endpoint

 

Para representar o endpoint, foi criada a seguinte estrutura:

 

 

O handler é utilizado para definir a rotina de tratamento da transação conforme o PID recebido. Já o membro data foi utilizado para apontar para o buffer utilizado (BD que está sendo usado no momento).

 

Configuração inicial do periférico

 

Para operar no modo FullSpeed é necessário que a USB opere em 48 MHz. Tal configuração é realizada na função de inicialização do sistema. Abaixo são mostrados os procedimentos de configuração da USB.

 

 

No início somente a interrupção por Reset é ativada. A rotina de tratamento é mostrada a seguir:

  • Reset: Habilita o endpoint 0, determina o endereço do dispositivo igual a zero e habilita outras interrupções;
  • Token: Ocorre sempre que uma transação é finalizada. Obtém o endpoint, a operação e os dados envolvidos na transação.

 

 

Operações de controle

 

As operações realizadas no endpoint 0 são para obter informações do dispositivo e também configurá-lo. Nessa aplicação, somente os comandos SetAddress, SetConfiguration, GetDescriptor e GetInterface foram implementados. A seguir é mostrado um exemplo de operação do Setup. A partir dos dados é determinado qual requisição será processada.

 

 

Descritores

 

Dispositivos HID utilizam apenas transferências de controle e de interrupção. Nessas transferências, um pacote de dados pode conter até 64 bytes. Interrupção significa que o endpoint é utilizado para transferir poucos dados rapidamente. Nesse caso, o dispositivo USB deve ser reativo. Para tal, o endpoint é usado somente em uma direção.

 

Essas configurações são realizadas com o preenchimento das estruturas de dados mostradas a seguir.

 

 

Note que no descritor HID existe uma referência para estrutura do report.

 

 

Exemplo

 

A seguir é mostrado um exemplo de operação no endpoint 1, controlando o estado do LED RGB conectado no pino PB19. A aplicação verifica dois bytes recebidos para definir qual operação será realizada. O primeiro byte é utilizado para definir o LED e o segundo para determinar o estado.

 

 

 

Enviando informações para um dispositivo

 

Para enviar dados ao dispositivo foi criada uma aplicação em C#, utilizando a biblioteca HIDInterface.

 

Aplicação para enviar comandos de controle do LED.
Figura 6: Aplicação para enviar comandos de controle do LED.

 

O dispositivo é localizado utilizando as informações do PID e VID.

 

 

Por fim, os dados são enviados para o dispositivo conforme a operação solicitada.

 

 

 

Para saber mais

 

Algumas partes do projeto não foram apresentadas no artigo. O projeto completo pode ser acessado no github.

 

Para conhecer mais sobre o protocolo USB acesse os materiais:

 

Para descrição dos reports:

 

Para descrição do periférico, acesse o datasheet no microcontrolador:

 

Outros artigos do Embarcados:

Raspberry Pi Zero W - Utilizando placa de som USB

Usando FreeRTOS para aplicações com a Freescale FRDM KL25z

Conheça a FRDM KL25Z da NXP

 

Vale conferir o livro Tecnologia ARM escrito pelo Fábio Pereira. Esse livro possui uma seção com muita informação sobre o protocolo USB.

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Fernando Deluno Garcia
Fascinado por computação, especialmente na interface entre hardware e software, me engajei na área de sistemas embarcados. Atuo com desenvolvimento de sistemas embarcados e sou docente da Faculdade de Engenharia de Sorocaba.Para mais informações: https://about.me/fdelunogarcia

1
Deixe um comentário

avatar
 
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Leonardo Miguel Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Leonardo Miguel
Visitante
Miguel

Olá Fernando, seu artigo realmente foi um show de conhecimento sobre o protocolo USB.
Tenho uma duvida, eu consigo enviar comando "bytes" para um dispositivo USB HID Keybord, para fazer determinadas alterações?