Partie 1:

Personnalisation du support matériel (I2C)

Il arrive parfois que nous modifions les éléments logiciels de notre matériel pour un client, afin qu’un membre de l’équipe puisse l’utiliser au niveau applicatif. Cette modification implique la personnalisation du noyau, avec l’écriture, la modification et l’intégration des drivers pour un périphérique spécifique, la personnalisation du bootloader et l’optimisation du rootfs pour un démarrage rapide.

Pourquoi personnaliser l’I2C ?

Notre module codec possède plusieurs sorties (Capless HP Out, mono output left, mono output right, stereo output). Pour écouter de la musique sur l’une de ces sorties, nous devons configurer le registre correspondant à celle-ci. Cette configuration se fait via le bus I2C.

Dans notre projet multimédia audio, nous allons personnaliser notre support matériel en modifiant le noyau pour permettre la communication entre les deux cartes suivantes à travers le protocole I2C :

  • La carte d’évaluation du codec EVAL-ADAU1761Z

  • La carte d’évaluation STM32MP257F-EV1

La carte d’évaluation du codec ADAU1761

Cette carte est conçue pour faire de l’audio. Elle comprend à la fois des entrées audio analogiques stéréo asymétriques et différentielles ainsi qu’une interface audio numérique. Des sorties analogiques asymétriques et différentielles sont également fournies, ainsi qu’une sortie casque stéréo sans capuchon. L’USBI fournit l’alimentation et l’interface de communication I2C à la carte d’évaluation.

La carte d’évaluation du stm32mp257f-ev

La carte d’évaluation STM32MP257F-EV1 est conçue comme une plate-forme de démonstration et de développement complète pour le STMicroelectronics STM32MP257FAI3 basé sur Arm® Cortex® A35 et M33.

Dans ce projet,  nous utiliserons yocto comme outil pour personnaliser notre matériel.

Yocto:

Le projet Yocto est un outil open source qui permet de créer une distribution Linux adaptée au matériel. Il est structuré en plusieurs couches (layers) :

  • Couche personnalisée (meta-perso)

  • Couche matérielle (meta-st)

  • Couche Yocto (meta-yocto)

  • OpenEmbedded Core (meta)

Création de notre couche (couche personnalisée)

Nous utilisons Yocto de STMicroelectronics pour créer notre couche. Pour la compilation, Yocto utilise Bitbake, qui provient du projet Poky. Son rôle est de parser tous les scripts Python des différentes recettes (recipes).

Téléchargeons le projet Yocto de STMicroelectronics et affichons toutes les couches disponibles dans ce projet.

Nous créons notre couche personnalisée, que nous nommons meta-nodem.

Pour cela, nous utilisons la commande suivante :

bitbake-layers create-layer ../layers/meta-nodem.

Nous ajoutons la couche nodem que nous avons créée au projet Yocto et vérifions qu’elle a bien été intégrée.

Pour cela, nous utilisons la commande suivante :

bitbake-layers add-layer ../layers/meta-nodem.

Nous pouvons constater que notre couche a bien été ajoutée au projet en utilisant la commande bitbake-layers show-layers.

Examinons maintenant le contenu de cette recette.

Nous allons personnaliser cette recette, puis générer une image basée sur l’image st-image-weston. Voici le résultat obtenu.

ChatGPT said:

Compilons notre nouvelle image nodem-image avec la commande suivante :

bitbake -k nodem-image

La compilation peut prendre jusqu’à 4 heures, en fonction de la puissance de votre ordinateur.

Une fois la compilation terminée, nous obtenons quelques avertissements (warning):

Pour charger l’image sur notre cible, nous utilisons l’outil STM32CUBEProgrammer de STMicroelectronics.

Démarrons la carte

Board support package (BSP)

Personnalisation de notre matériel

Définitions des terminologies :

Device Tree (DTS) :

Dans les systèmes ARM, certains périphériques sont détectés automatiquement lors de leur connexion, comme les périphériques USB, tandis que d’autres, tels que I2C, SPI, UART, etc., ne le sont pas.

Les périphériques non détectables nécessitent un développement logiciel pour que le système d’exploitation (le noyau Linux) puisse connaître leur topologie. Ce développement se fait à partir d’un fichier appelé device tree (DTS).

Le device tree est un fichier structuré qui décrit tous les périphériques (devices) non détectables automatiquement. Il est codé avec l’extension .dts et est compilé à l’aide d’un compilateur dtc (device tree compiler). Après compilation, un fichier binaire dtb est généré, qui est ensuite chargé par le bootloader (u-boot) et transmis au noyau. Ce dernier utilise ce fichier binaire pour connaître la topologie matérielle et assurer le démarrage complet de la carte.

Dans notre projet, ce fichier est nommé stm32mp257f-ev1.dts.


Device Driver :

Un device driver est un code écrit en langage C, destiné à configurer et gérer un périphérique. Il fournit une interface permettant de communiquer avec ce périphérique. Dans notre cas, c’est le driver I2C qui permet à la carte STMicroelectronics de communiquer via l’interface /dev/i2c-0.


Device Tree Source Include (DTSI) :

Le fichier DTSI est un fichier structuré qui sert à modifier le fonctionnement de certains périphériques. Il permet aussi d’ajouter des périphériques non présents dans le fichier DTS original. Ce fichier est inclus dans le fichier DTS. Par exemple, il permet d’activer ou de désactiver certains périphériques (I2C, UART, SPI, etc.).


Bus I2C :

Le bus I2C (Inter-Integrated Circuit) permet l’échange de données entre deux composants électroniques. Il est constitué de trois fils :

  • SDA (Serial Data) : signal de données

  • SCL (Serial Clock) : signal d’horloge

  • GND : masse (Ground)

Après avoir présenté brièvement les différentes terminologies, nous passons maintenant au cœur du sujet.

Ajout de i2c du codec dans le device tree

Localisation de i2c sur carte stm32mp257f-ev

Sur ce microprocesseur stm32mp257f, nous avons 8 bus i2c.

  • i2c1: i2c@40120000
  • i2c2: i2c@40130000
  • i2c3: i2c@40140000
  • i2c4: i2c@40150000

  • i2c5: i2c@40160000
  • i2c6: i2c@40170000
  • i2c7: i2c@40180000
  • i2c8: i2c@46040000

Parmi les 40 broches de sortie de la carte d’évaluation, I2C2 est connecté sur les broches pin 27 (I2C2_SDA) et pin 28(I2C2_SCL). Nous allons utiliser i2c2: i2c@40130000.

Localisation de i2c sur carte du codec EVAL-ADAU1761Z

L’USB fournit à la fois l’alimentation et l’interface de communication I2C pour la carte d’évaluation.

câblage :

STM32MP

(40 GPIO connector)

ADAU1761 

(serial data interface)

Beagle USB 12 Protocol Analyzer
I2C2_SDA (PB4)  SDA (PIN3) SDA (couleur violette)
I2C2_SCL (PB5) SCL(PIN31 SCL (couleur orange)
5 V (PIN 2)  5V (PIN4)
GND (PIN 6) GND (PIN10) GND (couleur rouge)
ChatGPT said:

Dans un premier temps, nous allons modifier le device tree de Linux pour ajouter l’adresse I2C du codec. Pour ce faire, nous avons deux méthodes possibles :

Méthode automatique avec devtool
Devtool est un outil qui permet de modifier, compiler et tester les modifications d’une recette avant de l’intégrer au projet. Il surcharge automatiquement la recette.

Méthode manuelle

  • Télécharger le kernel

  • Effectuer les modifications nécessaires

  • Créer des patches

  • Insérer les patches à l’aide de la commande :
    git format-patch -(nombre de commits) -o /chemin/ou/va/se/stocker/les/patches/

  • Créer une recette de surcharge .bbappend

  • Ajouter le chemin des fichiers dans cette recette de surcharge

Nous allons utiliser la méthode automatique :

Nous appelons devtool pour récupérer la recette du kernel et la placer dans le workspace :

devtool modify virtual/kernel. Nous pouvons également utiliser "devtool modify linux-stm32mp" puisque la recette du kernel est linux-stm32mp.

nous allons ajouter dans le device tree, l’adresse i2c du codec. Nous avons deux méthodes pour modifier le device tree:

  1. Le modifier directement le device tree du kernel et on fait un patch pour appliquer les modifications
  2. Créer un fichier device tree source include (dtsi) dans lequel nous mettrons au fur et à mesure toutes les modifications  des périphériques de la carte puis nous allons ajouter ce fichier au fichier dts principale (stm32mp257f-ev1.dts) puis faire un patch pour appliquer les modifications.

La deuxième méthode est celle avec laquelle  nous allons travailler .

créons un fichier nodem-stm32mp257.dtsi dans lequel nous allons coder

Explications:

  pinctrl-names = « default », « sleep »;

définit l’état de la PIN lorsqu’il est en cours d’utilisation (default) et lorsque le PIN n’est pas actif on le met à l’état de repos (sleep)

               pinctrl-0 = <&i2c2_pins_a>; // PIN à l’état d’utilisation

               pinctrl-1 = <&i2c2_sleep_pins_a>; // PIN à l’état de repos

               i2c-scl-rising-time-ns = <100>; // temps en nano secondes pour que le signal passe à l’état haut

              i2c-scl-falling-time-ns = <13>; // temps en nano secondes pour que le signal passe à l’état bas

             clock-frequency = <400000>; // fréquence en hertz du clock

              status = « okay »; //activation de bus i2c

                /* spare dmas for other usage */ // désactivation du DMA

              /delete-property/dmas; désactivation du DMA

               /delete-property/dma-names;  //désactivation du DMA

               adau1761: adau1761@38 { // déclaration de composant codec ada1761 avec son adresse

                       compatible = « adi,adau1761 »; // ajout de sa compatibilité qui est liée à son driver

                       reg = <0x38>; // déclaration de son adresse

                       status = « okay »; // activation de l’i2c du codec audio

}

Incluons ce fichier dans le dts original (stm32mp257f-ev1.dts) afin qu’il soit pris en compte lors de la compilation.

Utilisons git pour effectuer les commits des fichiers.

git add .

git commit -s -m « nodem dtsi with i2c added in dts »

Nous mettons à jour notre recette avec la commande suivante :

devtool update-recipe linux-stm32mp -a ../layers/meta-nodem

devtool va automatiquement créer un dossier « recipes-kernel » contenant la recette de surcharge pour notre kernel :

linux-stm32mp_6_6.bbappend.

Examinons le contenu de cette recette :

Dans notre dossier « linux-stm32mp », nous avons un fichier patch contenant les modifications à appliquer à la recette du noyau.

Nous avons également la recette de surcharge « linux-stm32mp_6_6.bbappend », qui inclut le chemin du fichier patch à utiliser lors de la compilation du noyau.

Le champ SRC_URI contient la liste des fichiers patches qui seront pris en compte durant la compilation du noyau. Pour l’instant, nous avons un seul fichier : « 0001-nodem-dtsi-with-i2c-added-in-dts.patch ».

Nous procédons à un nettoyage avec la commande « cleanall » :

arduino
bitbake -c cleanall virtual/kernel

Nous pouvons également utiliser :

bitbake -c cleanall linux-stm32mp

Nous compilons le noyau pour vérifier s’il y a des erreurs :

bitbake virtual/kernel

Nous pouvons aussi utiliser :

bitbake linux-stm32mp

Sur la carte d’évaluation, vérifions que l’adresse du codec n’est pas active.

Nous compilons notre image en utilisant la commande suivante :

bitbake -k nodem-image

Test:

Nous re flashons le logiciel à l’aide de l’outil STM32CUBEProgrammer.

Beagle I2C/SPI Protocol Analyzer

L’analyseur de protocole I2C/SPI Beagle polyvalent est l’outil basé sur I2C ou SPI. L’analyseur I2C/SPI Beagle fournit une solution de surveillance de bus haute performance pour l’analyse des trames I2C ou SPI dans un petit boîtier portable, parfait pour le terrain et le laboratoire.

Il sert à analyser les trames spi et i2c. Pour ce projet, nous l’utiliserons pour analyser les trames i2c. Pour faire les tests, nous utiliserons les fonctionnalités de i2c (i2c-tools) qui sont les suivantes:

  • i2cdetect :
    • permet de detecter l’adresse du périphérique qui est connectée sur la carte
      • Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
      • i2cdetect -F I2CBUS
      • i2cdetect -l
      • I2CBUS is an integer or an I2C bus name
  • i2cget:
    • permet de lire un byte contenu dans le registre
      • Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE [LENGTH]]]
      • I2CBUS is an integer or an I2C bus name
      • ADDRESS is an integer (0x08 – 0x77, or 0x00 – 0x7f if -a is given)
      • MODE is one of:
      • b (read byte data, default)
      • w (read word data)
      • c (write byte/read byte)
      • s (read SMBus block data)
      • i (read I2C block data)
  • i2cset:
    • permet d’ecrire un byte dans le registre
      • Usage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] … [MODE]
      •   I2CBUS is an integer or an I2C bus name
      •   ADDRESS is an integer (0x08 – 0x77, or 0x00 – 0x7f if -a is given)
      •   MODE is one of:
      •     c (byte, no value)
      •     b (byte data, default)
      •     w (word data)
      •     i (I2C block data)
      •     s (SMBus block data)
  • i2ctransfer:
    • permet d’ecrire ou de lire un ou plusieurs byte dans le registre
      • Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]
      • I2CBUS is an integer or an I2C bus name
      • DESC describes the transfer in the form: {r|w}LENGTH[@address]
      • 1) read/write-flag 2) LENGTH (range 0-65535, or ‘?’)
      • 3) I2C address (use last one if omitted)

Recherchons l’I2CBUS de notre codec avec la commande suivante :

cat /sys/firmware/devicetree/base/soc@0/bus@42080000/i2c@40130000

Vérifions si notre codec est bien pris en compte. En effet, il se trouve à l’adresse 0038 et est connecté à l’adresse 40130000 sur le bus i2c-0.

Utilisez la commande suivante :

ls -l /sys/bus/i2c/devices/

Vérifions avec la commande suivante :

i2cdetect -y 0

Nous allons effectuer des opérations de lecture et d’écriture sur le registre (0x4002) de notre codec.

Écriture dans le registre 0x4002 :

i2ctransfer -f -y 0 w8@0x38 0x40 0x02 0x00 0x00 0x00 0x00 0x20 0x03

Utilisons l’outil Total Phase pour analyser les trames envoyées et effectuer le débogage de l’écriture.

Nous constatons que les trames ont été correctement envoyées par le microprocesseur ST.

Essayons maintenant de lire :

i2ctransfer -f -y 0 w8@0x38 0x40 0x02 r6

Débogage de la lecture :

Nous constatons également que le registre 0x4003 contient correctement les valeurs qui ont été écrites.

Dans cet article, nous avons abordé les points suivants :

  • La création de votre propre recette à partir de la recette originale.

  • La modification du fichier dts pour ajouter le périphérique i2c.

  • La lecture et l’écriture sur le bus i2c.

  • Le débogage des trames i2c à l’aide de l’outil Total Analyzer.

Dans la deuxième partie, nous aborderons la génération du signal d’horloge qui sera utilisé par notre codec.

Dans la seconde partie, nous parlerons de génération du signal d’horloge qui sera utilisé par notre codec.

N’hésitez pas à nous faire part de vos remarques ou à poser vos questions à l’adresse suivante.

Nous vous accompagnons en toute transparence dans la réalisation des activités suivantes :

  • Développement du BSP (Board Support Package )
    • Mise en place du Bootloader, personnalisation du noyau Linux et développement de pilotes de périphériques adaptés à votre matériel, assurant ainsi le bon fonctionnement de votre système.
  • Intégration logicielle avec yocto ou buildroot.
    • Création de distributions Linux embarquées personnalisées basées sur Yocto ou Buildroot, avec un focus sur l’intégration, la qualité et le déploiement.
  • Développement Bare Metal, avec ou sans RTOS .
    • Optimisation des performances et de l’efficacité des systèmes basés sur des microcontrôleurs.
    • Développement temps réel avec FreeRTOS. La gestion de la planification des tâches, la communication entre les tâches et la gestion de la mémoire pour répondre à vos besoins de performances en temps réel.
    • Intégration de périphériques et optimisation du code, assurant une utilisation minimale des ressources.
0 réponses

Laisser un commentaire

Rejoindre la discussion?
N’hésitez pas à contribuer !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *