Diagnostic et Correction de l'Erreur Code 10 des Périphériques HID sur I²C avec STM32

Il est courant pour les développeurs embarqués de rencontrer un scénario frustrant : un périphérique est physiquement connecté, l'alimentation est stable, et pourtant, le Gestionnaire de périphériques de Windows affiche une croix rouge accompagnée du message "Ce périphérique ne peut pas démarrer (Code 10)". Souvent, le périphérique en question est désigné comme un "Périphérique HID I²C", et l'on sait que la communication I²C avec la puce tactile, par exemple, semble active sur un oscilloscope.

Cette situation n'indique pas nécessairement un matériel défectueux ou un pilote incorrect. Il s'agit d'un problème typique dans le développement embarqué, particulièrement lors de l'implémentation de la fonctionnalité HID sur I²C avec des microcontrôleurs STM32, où un détail manquant peut entraîner cet échec de démarrage.

Cet article se propose de décortiquer en profondeur l'énigme du "périphérique HID I²C Code 10", en explorant les temporisations de bas niveau, les spécifications protocolaires, la configuraton des registres et la logique du firmware. L'objectif est de vous guider pas à pas vers une solution permettant un montage stable et une fonctionnalité "plug-and-play" effective.

Comprendre le "Code 10" pour les Périphériques HID I²C

Le "Code 10" n'implique pas l'absence physique du périphérique, mais plutôt un échec d'initialisation de la part de l'hôte. Le système d'exploitation, via l'ACPI, détecte bien la présence de votre périphérique HID. Cependant, il ne parvient pas à obtenir les informations cruciales lors des phases ultérieures de la communictaion I²C, telles que le descripteur de rapport, ou le périphérique ne répond tout simplement pas correctement aux requêtes de lecture.

En d'autres termes, Windows perçoit le périphérique mais échoue à établir un dialogue significatif. Ce problème est rarement causé par une seule défaillance, mais plutôt par une accumulation de facteurs :

  • Instabilité de la couche physique du bus I²C.
  • Adresse esclave mal configurée ou non alignée.
  • Format du descripteur non conforme aux spécifications.
  • Gestion incorrecte des broches d'interruption.
  • Firmware ne répondant pas en temps voulu aux interrogations de l'hôte.

La résolution de ce problème nécessite une approche méthodique, diagnostiquant chaque couche pour appliquer le correctif précis.

La Synergie entre I²C et HID : Le Concept "HID over I²C"

Si l'USB HID est le protocole standard pour les claviers et souris, saviez-vous que, depuis Windows 8, Microsoft supporte également l'exécution du protocole HID sur un bus I²C ? C'est ce que l'on appelle le HID over I²C.

Le principe est simple : en évitant l'utilisation d'un PHY USB et d'une pile de protocole USB complexe, un microcontrôleur compatible I²C (comme un STM32), associé à une puce tactile ou un capteur conforme aux spécifications, peut "se faire passer" pour un périphérique d'entrée HID standard auprès d'un PC.

La chaîne de communication est la suivante :

[PC] ←(ACPI via Contrôleur I²C du chipset)→ [STM32] ←I²C→ [Capteur Tactile/Périphérique]

Le PC accède directement au périphérique via le contrôleur I²C de la carte mère. Pour que cela fonctionne, toute la communication doit strictement adhérer à la HID over I²C Specification. Le moindre écart, même un seul bit mal interprété, peut entraîner l'abandon de la connexion par l'hôte.

Configuration Optimale de l'I²C sur STM32

Une erreur courante est de croire que l'appel à la fonction HAL HAL_I2C_Init() suffit. En réalité, de nombreux problèmes de "Code 10" prennent racine dans les détails de l'initialisation du périphérique I²C.

Voici un exemple de configuration I²C pour un périphérique STM32, mettant l'accent sur les paramètres essentiels au-delà d'une initialisation minimale :


/**
  * @brief  Configure le périphérique I2C1 pour la communication HID.
  *         Cette fonction initialise les paramètres I2C critiques.
  * @param  None
  * @retval None
  */
static void configure_i2c_peripheral(void)
{
    // Déclaration du handle I2C
    I2C_HandleTypeDef i2c_device_handle;

    // Association du handle à l'instance matérielle I2C1
    i2c_device_handle.Instance = I2C1;

    // Configuration des paramètres de communication I2C
    i2c_device_handle.Init.ClockSpeed      = 100000;          // Vitesse d'horloge standard : 100 kHz
    i2c_device_handle.Init.DutyCycle       = I2C_DUTYCYCLE_2; // Rapport cyclique pour le mode standard (100 kHz ou 400 kHz)
    i2c_device_handle.Init.OwnAddress1     = 0;               // Adresse du périphérique (esclave), 0 si non utilisée comme esclave principal
    i2c_device_handle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT; // Mode d'adressage 7 bits, courant pour les périphériques HID
    i2c_device_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // Désactivation de l'adressage secondaire
    i2c_device_handle.Init.OwnAddress2     = 0;               // Adresse secondaire non utilisée
    i2c_device_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // Désactivation de la reconnaissance de l'appel général
    i2c_device_handle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;   // Autorisation du "clock stretching" par l'esclave

    // Exécution de l'initialisation du périphérique I2C
    if (HAL_I2C_Init(&i2c_device_handle) != HAL_OK)
    {
        // Gestion de l'erreur d'initialisation.
        // Par exemple, appel à une fonction d'erreur custom.
        // Error_Handler();
    }
}

Étiquettes: STM32 I2C HID-over-I2C Code10 Dépannage Embarqué

Publié le 10 septembre à 15h53