Very High Speed Integrated Circuit Hardware Description Language/Interfaces RS232 et USB
Ce chapitre risque de rester en construction un certain temps. En effet, à ce jour nous n'avons pas beaucoup d'expérience dans ces domaines. Nous avons un projet avec des étudiants sur l'USB avec un ATMEL ATMEGA8 qui, nous l'espèrons, va nous faire progresser dans le domaine de l'USB. À terme, puisque ce cours comprendra un processeur softcore compatible ATMEGA8, nous espèrons porter ce projet dans un FPGA. Le lecteur impatient peut se retrousser les manches et compléter ce chapitre à sa guise.
Comme d'habitude le préfixe "(en)" devant un hyperlien sera une référence wikipédia en anglais.
L'interface RS232
[modifier | modifier le wikicode]Le circuit spécialisé qui gère la liaison série (ou RS232) s’appelle une UART.
On rappelle que ce type de liaison série permet d'envoyer des informations sans horloge de référence. Elle est à un logique au repos. Une trame est composée des 8 bits à transmettre, précédé d'un bit de start ("0" logique), et suivi par au moins un bit de stop ("1" logique). Le bit de stop peut être doublé et éventuellement précédé par un bit de parité. Pour une parité paire, le bit de parité est mis à "0" quand le nombre de "1" est pair tandis qu'une parité impaire met à "0" pour un nombre impair de "1".
La vue de l'image ci-contre semble indiquer le contraire de ce que je suis en train d'expliquer. Mais n'oubliez pas que du point de vue électrique, un niveau logique "0" est représenté par une tension de +3 V à +25 V et un niveau logique "1" par une tension de −3 V à −25 V (codage NRZ). Ordinairement, des niveaux de +12 V et −12 V sont utilisés.
Utiliser les logicores Xilinx
[modifier | modifier le wikicode]Dans sa documentation Xilinx n'appelle pas ces programmes VHDL fournis des logicores (cœurs gratuits) mais des macros. La notion de logicore existe cependant chez Xilinx. Par abus de langage j'appellerai ces programmes dans la suite de ce chapitre des logicores !
Si l’on utilise des FPGA Xilinx, il est possible d’utiliser des cœurs fournis par ce fabricant. C'est pratique, mais si vous utilisez un FPGA Altera ou Actel, cela ne fonctionne plus !
Ces logicores sont disponibles chez Xilinx : faites une recherche du fichier KCPSM3.zip qui contient le PicoBlaze et les logicores en question.
Generateur de Baud
[modifier | modifier le wikicode]Dans les deux figures ci-dessous, on voit apparaître un signal "en_16_x_baud". Il nous faut maintenant en discuter.
Tout utilisateur des logicores devra fournir un signal de 16 fois la vitesse de transmission et synchronisé avec l'horloge générale.
Un exemple de programme réalisant cela sera inséré dans la partie exercice un peu plus tard.
Transmettre
[modifier | modifier le wikicode]Nous allons nous intéresser à la transmission de données vers l'extérieur. Pour cela, il faut utiliser le composant décrit par bbfifo_16x8.vhd avec le composant décrit par kcuart_tx.vhd et les assembler pour faire le composant décrit par uart_tx.vhd. Nous ne donnons pas le code de ces composants car ce code est illisible. Un schéma de principe sera bien plus utile.
Prenez le temps de repérer les composants décrits dans le texte.
La version moderne utilise des composants pour lesquels on a rajouté un 9 (par rapport aux anciennes versions) : bbfifo9, kcuart9_tx, kcuart9_rx, uart9_tx et uart9_rx. Ces composants permettent de recevoir et d'émettre un bit de parité.
Un exemple de programme utilisant ces logicores peut être trouvé dans le livre VHDL et conception, particulièrement à partir de la section En aura-t-on fini un jour avec ce compteur de passages ?
Recevoir
[modifier | modifier le wikicode]Nous allons nous intéresser à la réception de données provenant de l'extérieur. Pour cela, il faut utiliser le composant décrit par bbfifo_16x9.vhd avec le composant décrit par kcuart9_rx.vhd et les assembler pour faire le composant décrit par uart9_rx.vhd. Ces fichiers se trouvent dans le répertoire VHDL du fichier KCPSM3.zip qui est téléchargeable chez Xilinx. Ne sachant pas si j’ai le droit d’en donner le contenu ici, je ne préfère pas les publier.
Encore une fois, un schéma de principe sera bien plus utile.
Un exemple de programme utilisant ces logicores peut être trouvé dans le livre VHDL et conception, particulièrement à partir de la section Et un petit dernier séquenceur pour la route...
Utiliser un cœur indépendant du fondeur
[modifier | modifier le wikicode]Il n’est pas très difficile de trouver sur Internet (chez Opencores) des cœurs RS232 libres. Il y en a même dans certains projets. Nous donnons par exemple ici ceux que l’on trouve dans le projet ATMega8 présenté dans le chapitre Embarquer un Atmel ATMega8.
Composant global
[modifier | modifier le wikicode]Voici le code source qui sera commenté plus tard.
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
--
-- This code is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this code (see the file named COPYING).
-- If not, see http://www.gnu.org/licenses/.
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- Module Name: uart_baudgen - Behavioral
-- Create Date: 14:34:27 11/07/2009
-- Description: a UART and a fixed baud rate generator.
--
-------------------------------------------------------------------------------
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity uart is
generic(CLOCK_FREQ : std_logic_vector(31 downto 0);
BAUD_RATE : std_logic_vector(27 downto 0));
port( I_CLK : in std_logic;
I_CLR : in std_logic;
I_RD : in std_logic;
I_WE : in std_logic;
I_TX_DATA : in std_logic_vector(7 downto 0);
I_RX : in std_logic;
Q_TX : out std_logic;
Q_RX_DATA : out std_logic_vector(7 downto 0);
Q_RX_READY : out std_logic;
Q_TX_BUSY : out std_logic);
end uart;
architecture Behavioral of uart is
component baudgen
generic(CLOCK_FREQ : std_logic_vector(31 downto 0);
BAUD_RATE : std_logic_vector(27 downto 0));
port( I_CLK : in std_logic;
I_CLR : in std_logic;
Q_CE_1 : out std_logic;
Q_CE_16 : out std_logic);
end component;
signal B_CE_1 : std_logic;
signal B_CE_16 : std_logic;
component uart_rx
port( I_CLK : in std_logic;
I_CLR : in std_logic;
I_CE_16 : in std_logic;
I_RX : in std_logic;
Q_DATA : out std_logic_vector(7 downto 0);
Q_FLAG : out std_logic);
end component;
signal R_RX_FLAG : std_logic;
component uart_tx
port( I_CLK : in std_logic;
I_CLR : in std_logic;
I_CE_1 : in std_logic;
I_DATA : in std_logic_vector(7 downto 0);
I_FLAG : in std_logic;
Q_TX : out std_logic;
Q_FLAG : out std_logic);
end component;
signal L_RX_OLD_FLAG : std_logic;
signal L_TX_FLAG : std_logic;
signal L_TX_FLAGQ : std_logic;
signal L_TX_DATA : std_logic_vector(7 downto 0);
signal L_RX_READY : std_logic;
begin
Q_RX_READY <= L_RX_READY;
Q_TX_BUSY <= L_TX_FLAG xor L_TX_FLAGQ;
baud: baudgen
generic map(CLOCK_FREQ => CLOCK_FREQ,
BAUD_RATE => BAUD_RATE)
port map( I_CLK => I_CLK,
I_CLR => I_CLR,
Q_CE_1 => B_CE_1,
Q_CE_16 => B_CE_16);
rx: uart_rx
port map( I_CLK => I_CLK,
I_CLR => I_CLR,
I_CE_16 => B_CE_16,
I_RX => I_RX,
Q_DATA => Q_RX_DATA,
Q_FLAG => R_RX_FLAG);
tx: uart_tx
port map( I_CLK => I_CLK,
I_CLR => I_CLR,
I_CE_1 => B_CE_1,
I_DATA => L_TX_DATA,
I_FLAG => L_TX_FLAG,
Q_TX => Q_TX,
Q_FLAG => L_TX_FLAGQ);
process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_TX_FLAG <= '0';
L_TX_DATA <= X"33";
else
if (I_RD = '1') then -- read Rx data
L_RX_READY <= '0';
end if;
if (I_WE = '1') then -- write Tx data
L_TX_FLAG <= not L_TX_FLAG;
L_TX_DATA <= I_TX_DATA;
end if;
if (R_RX_FLAG /= L_RX_OLD_FLAG) then
L_RX_READY <= '1';
end if;
L_RX_OLD_FLAG <= R_RX_FLAG;
end if;
end if;
end process;
end Behavioral;
Genérateur de bauds
[modifier | modifier le wikicode]Voici le code source qui sera commenté plus tard.
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
--
-- This code is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this code (see the file named COPYING).
-- If not, see http://www.gnu.org/licenses/.
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- Module Name: baudgen - Behavioral
-- Create Date: 13:51:24 11/07/2009
-- Description: fixed baud rate generator
--
-------------------------------------------------------------------------------
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity baudgen is
generic(clock_freq : std_logic_vector(31 downto 0);
baud_rate : std_logic_vector(27 downto 0));
port( I_CLK : in std_logic;
I_CLR : in std_logic;
Q_CE_1 : out std_logic; -- baud x 1 clock enable
Q_CE_16 : out std_logic); -- baud x 16 clock enable
end baudgen;
architecture Behavioral of baudgen is
constant BAUD_16 : std_logic_vector(31 downto 0) := baud_rate & "0000";
constant LIMIT : std_logic_vector(31 downto 0) := clock_freq - BAUD_16;
signal L_CE_16 : std_logic;
signal L_CNT_16 : std_logic_vector( 3 downto 0);
signal L_COUNTER : std_logic_vector(31 downto 0);
begin
baud16: process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_COUNTER <= X"00000000";
elsif (L_COUNTER >= LIMIT) then
L_COUNTER <= L_COUNTER - LIMIT;
else
L_COUNTER <= L_COUNTER + BAUD_16;
end if;
end if;
end process;
baud1: process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_CNT_16 <= "0000";
elsif (L_CE_16 = '1') then
L_CNT_16 <= L_CNT_16 + "0001";
end if;
end if;
end process;
L_CE_16 <= '1' when (L_COUNTER >= LIMIT) else '0';
Q_CE_16 <= L_CE_16;
Q_CE_1 <= L_CE_16 when L_CNT_16 = "1111" else '0';
end behavioral;
Reception
[modifier | modifier le wikicode]Voici le code source qui sera commenté plus tard.
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
--
-- This code is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this code (see the file named COPYING).
-- If not, see http://www.gnu.org/licenses/.
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- Create Date: 14:22:28 11/07/2009
-- Design Name:
-- Module Name: uart_rx - Behavioral
-- Description: a UART receiver.
--
-------------------------------------------------------------------------------
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity uart_rx is
PORT( I_CLK : in std_logic;
I_CLR : in std_logic;
I_CE_16 : in std_logic; -- 16 times baud rate
I_RX : in std_logic; -- Serial input line
Q_DATA : out std_logic_vector(7 downto 0);
Q_FLAG : out std_logic); -- toggle on every byte received
end uart_rx;
architecture Behavioral of uart_rx is
signal L_POSITION : std_logic_vector(7 downto 0); -- sample position
signal L_BUF : std_logic_vector(9 downto 0);
signal L_FLAG : std_logic;
signal L_SERIN : std_logic; -- double clock the input
signal L_SER_HOT : std_logic; -- double clock the input
begin
-- double clock the input data...
--
process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_SERIN <= '1';
L_SER_HOT <= '1';
else
L_SERIN <= I_RX;
L_SER_HOT <= L_SERIN;
end if;
end if;
end process;
process(I_CLK, L_POSITION)
variable START_BIT : boolean;
variable STOP_BIT : boolean;
variable STOP_POS : boolean;
begin
START_BIT := L_POSITION(7 downto 4) = X"0";
STOP_BIT := L_POSITION(7 downto 4) = X"9";
STOP_POS := STOP_BIT and L_POSITION(3 downto 2) = "11"; -- 3/4 of stop bit
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
L_FLAG <= '0';
L_POSITION <= X"00"; -- idle
L_BUF <= "1111111111";
Q_DATA <= "00000000";
elsif (I_CE_16 = '1') then
if (L_POSITION = X"00") then -- uart idle
L_BUF <= "1111111111";
if (L_SER_HOT = '0') then -- start bit received
L_POSITION <= X"01";
end if;
else
L_POSITION <= L_POSITION + X"01";
if (L_POSITION(3 downto 0) = "0111") then -- 1/2 bit
L_BUF <= L_SER_HOT & L_BUF(9 downto 1); -- sample data
--
-- validate start bit
--
if (START_BIT and L_SER_HOT = '1') then -- 1/2 start bit
L_POSITION <= X"00";
end if;
if (STOP_BIT) then -- 1/2 stop bit
Q_DATA <= L_BUF(9 downto 2);
end if;
elsif (STOP_POS) then -- 3/4 stop bit
L_FLAG <= L_FLAG xor (L_BUF(9) and not L_BUF(0));
L_POSITION <= X"00";
end if;
end if;
end if;
end if;
end process;
Q_FLAG <= L_FLAG;
end Behavioral;
Émission
[modifier | modifier le wikicode]Voici le code source qui sera commenté plus tard.
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009, 2010 Dr. Juergen Sauermann
--
-- This code is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This code is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this code (see the file named COPYING).
-- If not, see http://www.gnu.org/licenses/.
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- Module Name: uart_tx - Behavioral
-- Create Date: 14:21:59 11/07/2009
-- Description: a UART receiver.
--
-------------------------------------------------------------------------------
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity uart_tx is
port( I_CLK : in std_logic;
I_CLR : in std_logic; -- RESET
I_CE_1 : in std_logic; -- BAUD rate clock enable
I_DATA : in std_logic_vector(7 downto 0); -- DATA to be sent
I_FLAG : in std_logic; -- toggle to send data
Q_TX : out std_logic; -- Serial output line
Q_FLAG : out std_logic); -- Transmitting Flag
end uart_tx;
architecture Behavioral of uart_tx is
signal L_BUF : std_logic_vector(7 downto 0);
signal L_TODO : std_logic_vector(3 downto 0); -- bits to send
signal L_FLAG : std_logic;
begin
process(I_CLK)
begin
if (rising_edge(I_CLK)) then
if (I_CLR = '1') then
Q_TX <= '1';
L_BUF <= "11111111";
L_TODO <= "0000";
L_FLAG <= I_FLAG; -- idle
elsif (I_CE_1 = '1') then
if (L_TODO /= "0000") then -- transmitting
Q_TX <= L_BUF(0); -- next bit
L_BUF <= '1' & L_BUF(7 downto 1);
if (L_TODO = "0001") then
L_FLAG <= I_FLAG;
end if;
L_TODO <= L_TODO - "0001";
elsif (L_FLAG /= I_FLAG) then -- new byte
Q_TX <= '0'; -- start bit
L_BUF <= I_DATA; -- data bits
L_TODO <= "1001";
end if;
end if;
end if;
end process;
Q_FLAG <= L_FLAG;
end Behavioral;
Bibliographie supplémentaire
[modifier | modifier le wikicode]Pour l'instant nous nous contenterons de dire que vous pouvez trouver de la documentation en anglais dans des livres. Personnellement nous adorons "FPGA Prototyping By VHDL Examples" de Pong P. Chu et nous aimons un peu moins "Design Recipes for FPGA" de Peter Wilson.
L'interface USB
[modifier | modifier le wikicode]L'interface USB est simple électriquement (quatre fils seulement) mais complexe du point de vue protocole : on y trouve des concepts réseaux qui ne sont pas forcément maîtrisés par tous les électroniciens. Il faudrait probablement un ouvrage entier pour décrire l'USB : pour rester concis nous allons essentiellement nous intéresser à la classe (en) HID.
Introduction
[modifier | modifier le wikicode]Il est inévitable de commencer par quelques définitions.
- On parle d'attachement lorsqu'un périphérique est connecté à un bus USB d'ordinateur. L'ordinateur s'appellera hôte dans ce cas.
- Le protocole qui suit l'attachement s’appelle l'énumération.
- La norme USB définit des types de périphériques appelés classes.
L'énumération se fait en trois étapes :
- attribution d'une adresse au périphérique, comprise entre 1 et 127, par l'hôte (le PC)
- envoi des descripteurs par le périphérique à l'hôte
- configuration du périphérique par l'hôte
Un périphérique quelconque a obligation de s'enregistrer comme appartenant à une certaine classe. Autrement dit, avant de concevoir votre périphérique il vous faut décider à quelle classe il appartient : mémoire de masse, caméra, clavier, souris...
Une classe spécifie, entre autres :
- le taux maximal de transfert
- des commandes spécifiques appelées requêtes de classe
- le nombre de terminaisons (Endpoints en anglais) et pour chacune des terminaisons son nombre de divisions en sections IN et OUT.
Ce qui peut surprendre à ce stade, c’est la notion de terminaison. Elle est liée au fait qu'une adresse de périphérique est insuffisante pour résoudre tous les problèmes de dialogues, et donc on ajoute une division supplémentaire.
Donnons un exemple pour se fixer les idées sur les classes.
La classe HID (Human Interface Device) est la classe des périphériques type claviers et souris. Elle est caractérisée par le fait que l'hôte doit savoir utiliser un tel périphérique sans système d'exploitation. Cette classe impose, entre autres :
- un taux de transfert maximal seulement 6 fois plus rapide que la liaison RS232
- un endpoint portant le numéro 1 en IN
- un transfert de données par appel pour l'endpoint 1 (interrupt transfer)
- le périphérique doit présenter ses données sous forme de rapport (rapport HID input)
Il y a tellement de données dans cette sections qu’il est possible qu'un débutant s'y perde un peu. Prenez éventuellement le temps de lire et relire, mais de toute façon, il est normal qu’à ce point, vous ne compreniez pas tout.
Les transferts
[modifier | modifier le wikicode]Les transfert de données représentent les échanges de données sur le bus USB.
Les trames
[modifier | modifier le wikicode]Toutes les millisecondes un paquet nommé SOF (Start of Frame) est envoyé par l'hôte sur le bus. Cette division en entités élémentaires de 1 ms est appelée trame.
Une trame permet l'échange de plusieurs transactions.
Transactions
[modifier | modifier le wikicode]Les transfert de données sont divisés en transactions pour éviter de monopoliser l'hôte.
Une transaction comporte trois phases distinctes :
- la phase TOKEN qui est toujours initiée par l'hôte. Cette phase spécifie l'adresse du périphérique de destination, le numéro de la terminaison (endpoint) et enfin le sens de l'échange IN ou OUT
- la phase DATA qui correspond à l'envoi de données dont l'expéditeur est soit l'hôte (section OUT), soit le périphérique (section IN)
- la phase HANDSHAKE informe de la réussite ou non de l'échange
Une transaction correspond physiquement à un groupe d'octets que l’on appelle paquet. Tous les paquets ont toujours la même architecture que nous présentons maintenant sans entrer dans les détails.
- paquet TOKEN
Sync PID ADDR ENDP CRC EOP 8 bits 7 bits 4 bits 5 bits
Parmi les champs de ce paquet, vous voyez le champ PID. On aura l’occasion de donner des valeurs à ce champ lorsqu'on s'intéressera aux transferts (un peu plus loin).
- paquet DATA
Sync PID Data CRC EOP 8 bits 0-1 024 octets 2 octets
Vous voyez dans ce paquet que la taille des données est limitée. Elle est très largement suffisante pour les périphériques HID classiques : claviers et souris.
- paquet HANDSHAKE
Sync PID EOP 8 bits
C'est la valeur de ce PID qui définira si l'échange s'est correctement passé.
Si les choses se passent mal, une transaction peut être interrompue mais seulement par le périphérique.
Il existe plusieurs sortes d'appels, nous allons commencer par décrire le transfert par appel.
Transfert par appel
[modifier | modifier le wikicode]On appelle transfert par appel (en anglais interrupt transfer), un transfert qui se fait régulièrement à l'initiative de l'hôte.
Chaque appel est une transaction IN qui informe le périphérique que s'il a des données à transmettre, c’est le moment.
- Exemple de transfert IN par appel
Sync PID ADDR ENDP CRC EOP Sync PID Data CRC EOP Sync PID EOP IN 7 bits 4 bits 5 bits → Data0 0-1 024 octets 2 octets → ACK Hôte vers périphérique Réponse périphérique vers hôte de l'hôte
Je dois avouer que cette façon de représenter les transactions (tableau pour représenter les paquets) n’est pas très conventionnelle. Les flèches dénotent un envoi de trames et le temps s'écoule de la gauche vers la droite. Vous avez donc trois paquets échangés dans l'exemple ci-dessus. Le PID du premier pacquet est IN, celui de la réponse est data0 et et pour terminer l'hôte envoie un ACK au périphérique. Examinons un autre type de transfert par appel :
- Exemple de transfert OUT par appel
Sync PID ADDR ENDP CRC EOP Sync PID Data CRC EOP Sync PID EOP OUT 7 bits 4 bits 5 bits → Data0 0-1 024 octets 2 octets → ACK Hôte vers périphérique Hôte vers périphérique du périphérique
La classe HID déjà mentionnée attribue à l'endpoint 1 un transfert par appel. Cela veut dire qu'un périphérique HID doit attendre la demande de l'hôte pour envoyer ses données.
Les descripteurs
[modifier | modifier le wikicode]Voir aussi
[modifier | modifier le wikicode]- D'autres périphériques sont évoqués dans la partie travaux pratiques de ce livre
- La RS232
- (fr) USB : Universal Serial Bus
- Description en français de l'USB
- (en) USB