md
Module horloge et mémoire EEPROM I2C pour Raspberry Pi
Mise à jour : 2020-02-23, première version : 2020-02-18
<-Various Hardware with Raspbian Buster Lite - Real-Time Clock --

Pour remplacer une horloge matérielle dont la pile fixe était morte, j'ai choisi un autre modèle basé sur la même puce, DS3231, mais avec une pile remplaçable. Ce nouveau dispositif n'est pas conçu pour être branché directement sur le connecteur entrée/sortie (E/S) d'un Raspberry Pi. Il est beaucoup plus grand pour accueillir la pile ce qui permet l'ajout de la petite puce de 8 broches qui est une mémoire Flash de 32K bits (4K d'octets de 8 bits) de type AT24C32.

Voici comment brancher l'horloge sur le bus I2C matériel du Raspberry Pi dans Raspbian Buster et comment accéder à la mémoire Flash. Le billet montre aussi comment brancher le module sur d'autres broches d'entrée sorties que les broches 2 et 3 du bus I2C matériel. C'est possible en utilisant un bus I2C virtuel. Enfin, on peut lire la température du capteur de chaleur de la puce DS3231. .

Table des matières

  1. I2C sur le Raspberry Pi
  2. Logiciels utiles
  3. Utilisation de l'horloge sur le bus I2C matériel
  4. Utilisation de la mémoire Flash sur le bus I2C matériel
  5. Utilisation de l'horloge sur le bus I2C émulé
  6. Utilisation de la mémoire Flash sur le bus I2C émulé
  7. Multiples bus I2C
  8. Le second bus I2C matériel
  9. Lecture de la température avec le DS3231
  10. Choix d'une pile

I2C sur le Raspberry Pi toc

I2C (Inter-Integrated Circuit ou encore TWI - Two Wire Interface) est un protocole de communication série fréquemment utilisé pour relier de nombreux dispositifs tels horloges, afficheurs, mémoires EEPROM, et sondes à un microcontrôleur. La communication, qui n'est pas très rapide, se fait à l'aide de deux signaux et une connexion vers la masse.

Tous les modèles Raspberry Pi ont un bus I2C matériel sur les broches 3 (SDA) et 5 (SCL) du connecteur d'entrée/sortie de 26 ou 40 broches selon le modèle. Cependant, le bus n'est pas activé par défaut et tant qu'il n'est pas activé les broches 3 et 5 sont des E/S générales. Des bus I2C virtuels peuvent être crées en ajoutant un module.

Alors que plusieurs dispositifs peuvent être connectés simultanément au bus I2C, seuls deux dispositifs peuvent échanger des données à un moment donné. Le dispositif qui initie la connexion est le maître, le destinateur est l'esclave. Le bus peut comprendre plus d'un maître, mais l'échange de données entre maîtres est impossible, de même qu'entre esclaves. De plus un esclave ne peut initier la communication avec un maître. Voir Understanding the I2C Bus, Texas Instruments Application Report SLVA704, p. 3. de Jonathan Valdez et Jared Becker (juin 2015).

En principe, un dispositif peut être maître ou esclave; jamais les deux simultanément. En pratique, la plupart des dispositifs plus simples ne sont que des esclaves et seuls les microcontrôleurs ont la possibilité d'être esclave en plus d'être maître, mais ce n'est pas toujours le cas. D'ailleurs, il semble que le Raspberry Pi n'est pas en mesure de mettre son bus I2C en mode esclave.

On s'en doute, un bus I2C est représenté par un fichier dans le répertoire des périphériques /dev dans Linux. À titre d'exemple, il y a trois bus I2C activés sur un Orange Pi PC 2.

opipc@orangepipc2:~$ ls -l /dev/i2* crw-rw---- 1 root i2c 89, 0 Feb 16 04:02 /dev/i2c-0 crw-rw---- 1 root i2c 89, 1 Feb 16 04:02 /dev/i2c-1 crw-rw---- 1 root i2c 89, 2 Feb 16 04:02 /dev/i2c-2

Et voici la liste des périphériques I2C sur un Raspberry Pi 3 B dont le bus I2C matériel a été activé.

woopi@goldserver:~ $ ls -l /dev/i2c* crw-rw---- 1 root i2c 89, 1 Feb 10 22:17 /dev/i2c-1

Comme on peut voir le périphérique i2c-0 qui serait lié au bus I2C utilisé pour reconnaître les cartes d'extension n'est pas créé.

Logiciels utiles toc

Trois logiciels sont utilisés ci-dessous. Il y a i2cdetect et ic2get qui sont contenus dans le paquet i2c-tools. Le premier affiche l'adresse des dispositifs branchés sur un bus I2C. Le second peut lire les registres d'un esclave I2C. L'installation du paquet i2c-tools est très simple.

woopi@goldserver:~ $ sudo apt install -y i2c-tools

L'installation du programme eeprog qui peut écrire et lire sur la mémoire EEPROM est un peu plus complexe. Il faut obtenir le code source et compiler l'utilitaire. De plus, plusieurs versions de eeprog sont disponibles sur le Web. Les seules qui fonctionnent sont la version « tear» du logiciel eeprog élaboré par Kris Rusocki ou des dérivées de celle-ci dont celle de Ján Sáreník sur GitHub.

woopi@goldserver:~ $ wget https://github.com/jsarenik/eeprog/archive/master.zip --2020-01-29 19:10:06-- https://github.com/jsarenik/eeprog/archive/master.zip ... 2020-01-29 19:10:07 (268 KB/s) - ‘master.zip’ saved [19445] woopi@goldserver:~ $ unzip 0.7.7_master.zip ... woopi@goldserver:~ $ mv eeprog-master eeprog woopi@goldserver:~ $ cd eeprog woopi@goldserver:~/eeprog $ make ...

Le problème avec les versions originales de eeprog est qu'en écriture elles utilisent une fréquence trop élevé. Il faut ralentir la cadence. La fréquence I2C de l'EEPROM AT24C32 dépend de l'alimentation. Il se peut que l'on puisse enregistrer des données avec la version originale de eeprog sur l'EEPROM AT24C32 si l'alimentation de ce dernier est à 5 volts. Avec un tel potentiel, le signal de synchronisation de l'EEPROM peut atteindre 400 KHz. Toutefois, le module doit fonctionner à 3,3 volts parce qu'il est branché à un Raspberry Pi. Or la fréquence d'opération I2C de l'EEPROM diminue rapidement lorsque la tension est réduite. Je ne sais pas la valeur exacte de cette fréquence à 3,3 volts, mais à 2,7 volts la fréquence maximale est réduite à 100 KHz.

Ni i2c-tools, ni eeprog ne sont nécessaire au fonctionnement de l'horloge et de la mémoire Flash. On pourra donc tout éliminer plus tard si désiré. Voici comment faire.

woopi@goldserver:~/some_dir/or_other $ cd ~ woopi@goldserver:~ $ rm eeprog-0.7.7_master.zip woopi@goldserver:~ $ rm -r eeprog woopi@goldserver:~ $ sudo apt purge i2c-tools -y

Utilisation de l'horloge sur le bus I2C matériel toc

Le branchement du module est très facile puisque les connexions sont très bien indiquées sur la plaquette. Au minimum, il faut relier quatre broches de cette dernière aux broches correspondantes du connecteur E/Sdu Raspberry Pi: l'alimentation et la masse (VCC et GND) et les signaux de données et de synchronisation (SDA et SCL) du bus I2C. Pour des raisons exposées plus loin, je n'ai pas installé de pile initialement.

Initialement, on peut installer temporairement le module I2C et le pilote de l'horloge. Une seule commande suffit pour réaliser ces deux tâches. Après on peut vite confirmer l'action.

woopi@goldserver:~ $ sudo dtoverlay i2c-rtc ds3231 woopi@goldserver:~ $ ls -l /dev/i2c* /dev/rt* crw-rw---- 1 root i2c 89, 1 Jan 29 02:57 /dev/i2c-1 lrwxrwxrwx 1 root root 4 Jan 29 02:57 /dev/rtc -> rtc0 crw------- 1 root root 253, 0 Jan 29 02:57 /dev/rtc0

Le périphérique i2c-1 (on dit aussi contrôleur) a été crée, ainsi que le périphérique rtc0 qui communique avec l'horloge par l'entremise du contrôleur i2c-1. La commande i2cdetect affiche les adresses des dispositifs branchés sur le bus I2C matériel.

woopi@goldserver:~ $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --

Deux dispositifs ont été trouvés. Le premier est la mémoire Flash (eeprom) à l'adresse 0x57 et le second est l'horloge à l'adresse 0x68. Le UU est une indication qu'un pilote a pris en charge le dispositif.

woopi@goldserver:~ $ sudo hwclock -v hwclock from util-linux 2.33.1 System Time: 1580275162.357510 Trying to open: /dev/rtc0 Using the rtc interface to the clock. Last drift adjustment done at 1580060171 seconds after 1969 Last calibration done at 1580060171 seconds after 1969 Hardware clock is on UTC time Assuming hardware clock is kept in UTC time. Waiting for clock tick... ioctl(3, RTC_UIE_ON, 0): Invalid argument Waiting in loop for time from /dev/rtc0 to change ...got clock tick Time read from Hardware Clock: 2020/01/29 05:19:23 Hw clock time : 2020/01/29 05:19:23 = 1580275163 seconds since 1969 Time since last adjustment is 214992 seconds Calculated Hardware Clock drift is 0.000000 seconds 2020-01-29 01:19:22.840443-04:00

Clairement l'horloge matérielle est en fonction. On peut être surpris de voir que l'heure est juste en l'absence d'une pile. L'explication est simple. Le système d'exploitation, ou plus précisément le composant systemd-timesync, obtient l'heure actuelle d'un serveur de référence SNTP lors du démarrage du Raspberry Pi. Dès que pilote i2c-rtc est installé, le système ajuste l'horloge matérielle.

Puisque tout fonctionne, on peut installer i2c-rtc de façon permanente en ajoutant la commande donnée ci-dessus dans le fichier de configuration du système d'exploitation.

woopi@goldserver:~ $ sudo nano /boot/config.txt

... # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # For access to I2C RTC and other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3) span style="font-weight: bold; color: red">dtoverlay=i2c-rtc,ds3231 ...

Il n'est pas nécessaire d'activer le protocole I2C avec l'utilitaire raspi-config. Auparavant, je disais qu'il fallait aussi modifier le script qui ajuste l'heure de l'horloge matérielle quand le module i2c-rtc est embarqué. Voici comment faire.

woopi@goldserver:~ $ sudo nano /lib/udev/hwclock-set

Normalement le script ne fait rien, car son exécution est arrêtée dès le test initial, du moins dans les distributions utilisant systemd dont Raspbian. Il faut enlever ce test ou l'escamoter avec des « # » au début des lignes ce qui les transforment en commentaires.

#!/bin/sh # Reset the System Clock to UTC if the hardware clock from which it # was copied by the kernel was in localtime. dev=$1 #if [ -e /run/systemd/system ] ; then # exit 0 #fi ...

Ceci n'est probablement pas une bonne idée. À la prochaine mise à jour, le script /lib/udev/hwclock-set sera écrasé, remplacé par la version originale. Voir Debian Bug report logs - #855203 hwclock-set: Synchronize from hwclock despite systemd presence

Utilisation de la mémoire Flash sur le bus I2C matériel toc

Si l'on a installé l'horloge comme indiqué à la section précédente, on peut immédiatement vérifier qu'il est possible d'écrire et de lire le EEPROM AT24C32. Autrement, le bus I2C n'est pas encore en service.

woopi@goldserver:~ $ sudo i2cdetect -l woopi@goldserver:~ $ ls /dev/i2* ls: cannot access '/dev/i2*': No such file or directory

L'installation temporaire du module i2c1 qui met en œuvre le bus I2C matériel broches E/S 2 et 3 est très simple.

woopi@goldserver:~ $ sudo dtoverlay i2c1 woopi@goldserver:~ $ ls -l /dev/i2c* /dev/rt* crw-rw---- 1 root i2c 89, 1 Jan 29 02:57 /dev/i2c-1

Si on affiche les adresses des dispositifs I2C branchés sur le bus 1 quand le module de prise en charge du bus est i2c1 on en observe deux au minimum.

woopi@goldserver:~ $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

L'adresse 0x57 est celle du EEPROM AT24C32 (en realité c'est l'adresse par défaut qu'on peut modifier avec quelques soudure). L'adresse 0x68 est celle de l'horloge matériel. Parce que seul le bus I2C est activé et qu'aucun pilote pour l'horloge n'a été chargé, i2detect montre l'adresse 0x68 et non le UU comme à la section précédente.

Si le module i2c-rtc a été installé plutôt que i2c1, alors i2cdetect affiche les adresses des dispositifs en indiquant que le pilote de l'horloge est en place.

woopi@goldserver:~ $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

Puisque le bus I2C est activé et que l'adresse du EEPROM est connue, on peut écrire un message dans la mémoire et puis lire celle-ci pour s'assurer que l'accès est possible.

woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:29 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit Operation: read 29 bytes from offset 0, Output file: <stdout> Reading 29 bytes from 0x0 Lorem ipsum dolor si... woopi@goldserver:~ $ echo "This is working!" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-1 0x57 eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit Operation: write at offset 0, Input file: <stdin> Write cycle time: 2 milliseconds Writing <stdin> starting at address 0x0 ................. woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:18 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit Operation: read 18 bytes from offset 0, Output file: <stdout> Reading 18 bytes from 0x0 This is working!

Utilisation de l'horloge sur le bus I2C émulé toc

Le Rapsberry Pi ne possède qu'un seul bus I2C matériel utilisable. Si la broche E/S 2 ou 3 sert à d'autres fin, on peut créer un bus I2C virtuel avec le module i2c-rtc-gpio.

woopi@goldserver:~ $ sudo dtoverlay -h i2c-rtc-gpio Name: i2c-rtc-gpio Info: Adds support for a number of I2C Real Time Clock devices using the software i2c controller Usage: dtoverlay=i2c-rtc-gpio,<param>=<val> Params: abx80x Select one of the ABx80x family: AB0801, AB0803, AB0804, AB0805, AB1801, AB1803, AB1804, AB1805 ds1307 Select the DS1307 device ds1339 Select the DS1339 device ds3231 Select the DS3231 device m41t62 Select the M41T62 device mcp7940x Select the MCP7940x device mcp7941x Select the MCP7941x device pcf2127 Select the PCF2127 device pcf2129 Select the PCF2129 device pcf8523 Select the PCF8523 device pcf8563 Select the PCF8563 device rv3028 Select the Micro Crystal RV3028 device addr Sets the address for the RTC. Note that the device must be configured to use the specified address. trickle-diode-type Diode type for trickle charge - "standard" or "schottky" (ABx80x only) trickle-resistor-ohms Resistor value for trickle charge (DS1339, ABx80x, RV3028) wakeup-source Specify that the RTC can be used as a wakeup source backup-switchover-mode Backup power supply switch mode. Must be 0 for off or 1 for Vdd < VBackup (RV3028 only) i2c_gpio_sda GPIO used for I2C data (default "23") i2c_gpio_scl GPIO used for I2C clock (default "24") i2c_gpio_delay_us Clock delay in microseconds (default "2" = ~100kHz)

Comme on peut voir les E/S GPIO23 et GPIO24 seront utilisées pour les signaux SDA et SCL respectivement. Si le module i2c-rtc a été ajouté au fichier de configuration /boot/config.txt, il doit être enlevé et le Pi doit être redémarrer. Si le module était chargé temporairement, on peut le retirer avec l'utilitaire dtoverlay. Dès qu'on sait qu'il n'y a plus de périphérique pour l'horloge, on peut installer i2c-rtc-gpio.

woopi@goldserver:~ $ sudo dtoverlay -l Overlays (in load order): 0: i2c-rtc ds3231=true woopi@goldserver:~ $ sudo dtoverlay -r 0 woopi@goldserver:~ $ ls /dev/rtc ls: cannot access '/dev/rtc': No such file or directory woopi@goldserver:~ $ sudo dtoverlay i2c-rtc-gpio ds3231 Message from syslogd@goldserver at Jan 30 14:18:16 ... kernel:[45446.974763] Internal error: Oops - BUG: 0 [#1] SMP ARM Message from syslogd@goldserver at Jan 30 14:18:16 ... kernel:[45447.002358] Process dtoverlay (pid: 3690, stack limit = 0xb07f204f) ... Message from syslogd@goldserver at Jan 30 14:18:16 ... kernel:[45447.108343] Code: 1a000003 e5932004 e3120001 1a000000 (e7f001f2) Segmentation fault

Clairement cela ne fonctionne pas. J'ai donc modifié le fichier de configuration.

woopi@goldserver:~ $ sudo nano /boot/config.txt

# Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on ... # for access to I2C RTC and other I2C devices on software I2C bus (SDA on GPIO23, SCL on GPIO24 by default) dtoverlay=i2c-rtc-gpio,ds3231 ...

Après un redémarrage, le bus I2C virtuel et le périphérique de l'horloge sont installés correctement.

woopi@goldserver:~ $ sudo i2cdetect -l i2c-3 i2c i2c-gpio-rtc@0 I2C adapter woopi@goldserver:~ $ sudo i2cdetect -y 3 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- woopi@goldserver:~ $ sudo hwclock -v hwclock from util-linux 2.33.1 System Time: 1580409344.320549 Trying to open: /dev/rtc0 Using the rtc interface to the clock. Last drift adjustment done at 1580060171 seconds after 1969 Last calibration done at 1580060171 seconds after 1969 Hardware clock is on UTC time Assuming hardware clock is kept in UTC time. Waiting for clock tick... ioctl(3, RTC_UIE_ON, 0): Invalid argument Waiting in loop for time from /dev/rtc0 to change ...got clock tick Time read from Hardware Clock: 2020/01/30 18:35:45 Hw clock time : 2020/01/30 18:35:45 = 1580409345 seconds since 1969 Time since last adjustment is 349174 seconds Calculated Hardware Clock drift is 0.000000 seconds 2020-01-30 14:35:44.845273-04:00

Utilisation de la mémoire Flash sur le bus I2C émulé toc

Si le module i2c-rtc-gpio a été installé comme expliqué à la section précédente, alors on peut communiquer avec la mémoire Flash à l'adresse 0x57 sur le périphérique i2c-3. S'il n'y a pas d'horloge avec la mémoire Flash alors on ajoute le module i2c-gpio.

woopi@goldserver:~ $ dtoverlay -h i2c-gpio Name: i2c-gpio Info: Adds support for software i2c controller on gpio pins Usage: dtoverlay=i2c-gpio,<param>=<val> Params: i2c_gpio_sda GPIO used for I2C data (default "23") i2c_gpio_scl GPIO used for I2C clock (default "24") i2c_gpio_delay_us Clock delay in microseconds (default "2" = ~100kHz) bus Set to a unique, non-zero value if wanting multiple i2c-gpio busses. If set, will be used as the preferred bus number (/dev/i2c-<n>). If not set, the default value is 0, but the bus number will be dynamically assigned - probably 3.

On peut procéder à l'installation directe du module dans ce cas. Évidemment, le i2c-rtc-gpio ne doit pas être activé.

woopi@goldserver:~ $ sudo dtoverlay i2c-gpio woopi@goldserver:~ $ sudo i2cdetect -l i2c-3 i2c ffffffff.i2c I2C adapter woopi@goldserver:~ $ sudo i2cdetect -y 3 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

On ne verra pas l'adresse 0x68 s'il n'y a pas d'horloge I2C. On peut tester l'accès à la mémoire comme auparavant en ajustant le bus qui est maintenant /dev/i2c-3.

woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:29 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit Operation: read 29 bytes from offset 0, Output file: <stdout> Reading 29 bytes from 0x0 Lorem ipsum dolor si... woopi@goldserver:~ $ echo "* A new EEPROM *" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-3 0x57 eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit Operation: write at offset 0, Input file: <stdin> Write cycle time: 2 milliseconds Writing <stdin> starting at address 0x0 ................. woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:18 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit Operation: read 18 bytes from offset 0, Output file: <stdout> Reading 18 bytes from 0x0 * A new EEPROM *

Multiples bus I2C toc

Il est possible d'avoir plus d'un bus I2C. Voici la partie pertinente du fichier /boot/config.txt qui crée le bus matériel et un bus émulé.

... # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3) dtoverlay=i2c-rtc,ds3231 # For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by default) dtoverlay=i2c-gpio ...


woopi@goldserver:~ $ ls /dev/i2c* /dev/i2c-1 /dev/i2c-3 woopi@goldserver:~ $ sudo i2cdetect -l i2c-3 i2c ffffffff.i2c I2C adapter i2c-1 i2c bcm2835 I2C adapter I2C adapter woopi@goldserver:~ $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- woopi@goldserver:~ $ sudo i2cdetect -y 3 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- woopi@goldserver:~ $ sudo hwclock -v hwclock from util-linux 2.33.1 System Time: 1580420342.707524 Trying to open: /dev/rtc0 Using the rtc interface to the clock. Last drift adjustment done at 1580060171 seconds after 1969 Last calibration done at 1580060171 seconds after 1969 Hardware clock is on UTC time Assuming hardware clock is kept in UTC time. Waiting for clock tick... ioctl(3, RTC_UIE_ON, 0): Invalid argument Waiting in loop for time from /dev/rtc0 to change ...got clock tick Time read from Hardware Clock: 2020/01/30 21:39:04 Hw clock time : 2020/01/30 21:39:04 = 1580420344 seconds since 1969 Time since last adjustment is 360173 seconds Calculated Hardware Clock drift is 0.000000 seconds 2020-01-30 17:39:03.151299-04:00 woopi@goldserver:~ $ echo "Hardware I2C bus" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-1 0x57 eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit Operation: write at offset 0, Input file: <stdin> Write cycle time: 2 milliseconds Writing <stdin> starting at address 0x0 ................. woopi@goldserver:~ $ echo "Software I2C bus" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-3 0x57 eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit Operation: write at offset 0, Input file: <stdin> Write cycle time: 2 milliseconds Writing <stdin> starting at address 0x0 ................. woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:18 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit Operation: read 18 bytes from offset 0, Output file: <stdout> Reading 18 bytes from 0x0 Hardware I2C bus 4woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:18 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit Operation: read 18 bytes from offset 0, Output file: <stdout> Reading 18 bytes from 0x0 Software I2C bus

Contrairement à des commentaires lus sur les forums, il ne semble pas y avoir de contraintes sur le numéro de bus I2C ni sur la séquence de création des bus.

... # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on dtoverlay=i2c-gpio,bus=6,i2c_gpio_sda=27,i2c_gpio_scl=22 # For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3) dtoverlay=i2c-rtc,ds3231 # For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by defa$ dtoverlay=i2c-gpio ...

woopi@goldserver:~ $ sudo i2cdetect -l i2c-3 i2c ffffffff.i2c I2C adapter i2c-1 i2c bcm2835 I2C adapter I2C adapter i2c-6 i2c 6.i2c I2C adapter

... # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by default) dtoverlay=i2c-gpio # For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3) dtoverlay=i2c-rtc,ds3231 dtoverlay=i2c-gpio,bus=9,i2c_gpio_sda=27,i2c_gpio_scl=22

woopi@goldserver:~ $ sudo i2cdetect -l i2c-3 i2c ffffffff.i2c I2C adapter i2c-1 i2c bcm2835 I2C adapter I2C adapter i2c-9 i2c 9.i2c I2C adapter

La seule contrainte est que le numéro du bus ne peut pas être 0 ou 2.

Le second bus I2C matériel toc

Si le connecteur E/S du Raspberry Pi possède 40 broches, il y a un deuxième bus I2C matériel qui est affecté à l'identification des cartes d'extensions (les HAT) en utilisant les broches 27 (ID_SD) et 28 (ID_SC). En principe on ne devrait pas se servir de ce bus. Les avertissements sont nombreux à ce sujet. La Fondation Raspberry le dit deux fois plutôt qu'une dans ses instructions sur la conception des cartes d'extensions. Dans les alinéas GPIO Requirements et ID EEPROM il y a le même passage:

Within the set of pins available on the GPIO header, ID_SC and ID_SD (GPIO0/SCL and GPIO1/SDA) are reserved for board detection / identification. The only allowed connections to the ID_ pins are an ID EEPROM plus 3.9K pull up resistors. Do not connect anything else to these pins!

On retrouve sensiblement le même avertissement sur les schématiques des divers modèles. Dans son tutoriel sur le protocole I2C, Sparkfun ajoute « It's only there to talk to EEPROMs at addresses 0x50 during boot time. User access at runtime is problematic. If you want a general purpose I2C bus on the B+, you'll need to use I2C-1, on pins 3 and 5 of the 40-pin connector ». Cependant, le tutoriel enchaîne avec la marche à suivre pour utiliser le bus. Il s'agit d'utiliser le module i2c_vc qu'on peut charger avec l'utilitaire dtparam. Avant de l'installer voyons l'imformation que l'utilitaire affiche à propos de ce module.

woopi@goldserver:~ $ sudo dtparam -h i2c_vc i2c_vc Set to "on" to enable the i2c interface usually reserved for the VideoCore processor (default "off") woopi@goldserver:~ $ sudo dtparam i2c_vc=on woopi@goldserver:~ $ ls /dev/i2* /dev/i2c-0

Puisque le périphérique est en place, j'ai pris la chance de brancher le module d'horloge avec mémoire flash aux broches 27 (SDA) et 28 (SCL) du second bus I2C (et aussi la masse et VCC à 3,3 volts bien sur) en prenant soin de couper l'alimentation avant de procéder. Après il a été facile de vérifier qu'il était possible de se servir de la mémoire flash.

woopi@goldserver:~ $ sudo i2cdetect -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-0 0x57 -r 0:29 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit Operation: read 29 bytes from offset 0, Output file: <stdout> Reading 29 bytes from 0x0 Lorem ipsum dolor si... woopi@goldserver:~ $ echo "eeprom on i2c-0 " | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-0 0x57 eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit Operation: write at offset 0, Input file: <stdin> Write cycle time: 2 milliseconds Writing <stdin> starting at address 0x0 ................. woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-0 0x57 -r 0:18 -f eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved. Copyright (c) 2011 by Kris Rusocki - All rights reserved. Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit Operation: read 18 bytes from offset 0, Output file: <stdout> Reading 18 bytes from 0x0 eeprom on i2c-0

Il ne semble pas y avoir de module qui prenne en charge l'horloge avec ce bus I2C. J'ai pu toutefois vérifier qu'il était possible d'accéder à la puce DS3231 avec un script Python qui est décrit en plus de détails dans un autre billet.

woopi@goldserver:~ $ ve rtcpy (rtcpy) woopi@goldserver:~ $ ./rtc -i 0 -bash: ./rtc: No such file or directory (rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0 Sat Feb 22 20:53:42 2020 (rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0 -u -s "2138-12-09 12:13:14" (rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0 Tue Dec 9 12:13:27 2138

Pour installer ce bus I2C matériel de façon permanente, on ajoute une ligne dans le fichier de configuration.

woopi@goldserver:~ $ sudo nano /boot/config.txt

# Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on dtparam=i2c_vc=on

Je n'ai pas testé l'utilisation de ce bus avec l'autre bus I2C matériel ou d'autres bus virtuels, mais j'estime que cela devrait fonctionné. Ceci étant dit, il n'est certe pas recommandé et peut-être même pas possible d'utiliser le controleur i2c0. Comme l'indique la fin de la commande d'aide générale de l'utilitaire dtparam, il pourrait y avoir un conflit avec la caméra Pi.

woopi@goldserver:~ $ sudo dtparam -h ... N.B. It is recommended to only enable those interfaces that are needed. Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc interfering with Pi Camera, I2S and SPI hogging GPIO pins, etc.)

De même, il est fort probable qu'il y aurait un conflit avec tout dispositif I2C branché sur ce bus qui utiliserait l'adresse 0x50.

Lecture de la température avec le DS3231 toc

Pour assurer la précision, la puce DS3231 pare aux variations provoquées par les changements de température. Donc, elle incorpore une sonde de température dont il est possible d'obtenir la valeur. La température de la puce se trouve dans les registres 0x11 et 0x12 qu'on peut lire avec l'utilitaire i2cget.

woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x11 Error: Could not open file `/dev/i2c-1' or `/dev/i2c/1': No such file or directory woopi@goldserver:~ $ i2cget -y 1 0x68 0x11 Error: Could not set address to 0x68: Device or resource busy

Le problème est que le périphérique à l'adresse 0x68 est l'horloge qui est pris en charge par le pilote rtc_ds1307.

woopi@goldserver:~ $ lsmod | grep rtc rtc_ds1307 24576 0 hwmon 16384 2 rtc_ds1307,raspberrypi_hwmon

Si l'on retire le module, on aura accès au DS3231.

woopi@goldserver:~ $ sudo rmmod rtc_ds1307 woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x11 0x14 woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x12 0x40

Le registre 0x11 contient la partie entière de la température en degré Celsius, alors que les deux bits les plus significatifs du registre 0x12 contiennent la partie fractionnaire de la température en quart de degré Celsius. Or 0x40 = 01000000 dont les deux bits les plus significatifs sont 01. Donc la température est 20 + 1* (1/4) = 20,25 °C ce qui était raisonnable.

On peut réinstaller le module rtc_ds1307 et l'horloge fonctionnera de nouveau.

woopi@goldserver:~ $ sudo modprobe rtc_ds1307 woopi@goldserver:~ $ sudo hwclock -v hwclock from util-linux 2.33.1 System Time: 1580085041.982210 Trying to open: /dev/rtc0 Using the rtc interface to the clock. Last drift adjustment done at 1580060171 seconds after 1969 Last calibration done at 1580060171 seconds after 1969 Hardware clock is on UTC time Assuming hardware clock is kept in UTC time. Waiting for clock tick... ioctl(3, RTC_UIE_ON, 0): Invalid argument Waiting in loop for time from /dev/rtc0 to change ...got clock tick Time read from Hardware Clock: 2020/01/27 00:30:43 Hw clock time : 2020/01/27 00:30:43 = 1580085043 seconds since 1969 Time since last adjustment is 24872 seconds Calculated Hardware Clock drift is 0.000000 seconds 2020-01-26 20:30:42.444318-04:00

Choix d'une pile toc

Le module comprend un support pour une pile bouton dont la fonction est de maintenir l'horloge en marche lorsque l'alimentation est coupée. Il y a un circuit assez sommaire pour charger un accumulateur de façon constante lorsque le module est alimenté. D'ailleurs un accumulateur (LIR2032) était fournie avec ces modules initialement. Sans surprise, les modules que j'ai obtenus de deux fournisseurs dernièrement n'avaient pas de piles incluses. Les nouveaux règlements à propos du transport de pile de type lithium-ion étant beaucoup plus sévères, les vendeurs évitent d'en expédier.

On retrouve sur le forum Arduino une discussion au sujet du module qui commence en novembre 2014 et qui demeure active. Je me permet de résumer ce long débat.

Pour ces raisons, au moins un revendeur enlève la résistance de 200 ohms pour désactiver le circuit et recommande l'utilisation d'une pile lithium CR2032 non rechargeable. Puisqu'il est difficile de trouver le LIR2032 localement à un prix raisonnable et puisque je doute fort de l'efficacité du circuit pour charger la pile quand le module est alimenté à 3,3 volts, j'imite ce revendeur avec les modules en ma possession.

<-Various Hardware with Raspbian Buster Lite - Real-Time Clock --