Projet spi-tools

Publié par cpb
Août 12 2014

Je viens de publier sur GitHub un petit projet nommé Spi-tools, regroupant deux utilitaires pour communiquer sous Linux en utilisant le protocole SPI. Ce projet a été écrit pour illustrer le fonctionnement d’un lien SPI entre un microprocesseur sous Linux (Raspberry Pi en l’occurrence) et un microcontrôleur (T.I. MSP430), mais il doit pouvoir s’appliquer à la plupart des besoins de configuration et communication en SPI sous Linux.

Interface Spidev

Ces deux outils fonctionnent en utilisant l’interface Spidev du noyau Linux. Pour la charger il est donc nécessaire de charger dans le kernel le module spidev.ko, généralement précédé du module permettant de piloter le contrôleur SPI du système.

Par exemple, sur un Raspberry Pi, on fera:

$ sudo modprobe spi-bcm2708
$ sudo modprobe spidev

À partir de ce moment, des fichiers spéciaux apparaissent dans /dev pour représenter les interfaces SPI disponibles. Voici le résultat sur un Raspberry Pi.

$ ls -l /dev/spi*
crw-rw---T 1 root spi 153, 0 Aug 11 20:26 /dev/spidev0.0
crw-rw---T 1 root spi 153, 1 Aug 11 20:26 /dev/spidev0.1
$

Compilation du projet

La compilation de ces petits outils ne nécessite aucune bibliothèque ou utilitaire particuliers.

$ git clone https://github.com/cpb-/spi-tools.git
Cloning into 'spi-tools'...
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (29/29), done.
remote: Total 43 (delta 20), reused 34 (delta 13)
Unpacking objects: 100% (43/43), done.
$ cd ../spi-tools/
$ make 
cc -Wall -DVERSION=\"0.1-3-g0408c9d\"    spi-config.c   -o spi-config
cc -Wall -DVERSION=\"0.1-3-g0408c9d\"    spi-pipe.c   -o spi-pipe
$

Configuration

Le premier outil permet de configurer en ligne de commande les paramètres d’une liaison SPI. Si nous l’invoquons sans argument, il nous indique comment obtenir de l’aide.

$ ./spi-config 
./spi-config: no device specified (use option -h for help).
$ ./spi-config -h
usage: ./spi-config options...
  options:
    -d --device=  use the given spi-dev character device.
    -q --query         print the current configuration.
    -m --mode=[0-3]    use the selected spi mode.
             0: low iddle level, sample on leading edge
             1: low iddle level, sample on trailing edge
             2: high iddle level, sample on leading edge
             3: high iddle level, sample on trailing edge
    -l --lsb={0,1}     LSB first (1) or MSB first (0)
    -b --bits=[7...]   bits per word
    -s --speed=   set the speed in Hz
    -h --help          this screen
    -v --version       display the version number
$

On utilisera donc l’option -d pour préciser l’interface SPI concernée. L’option -q nous permet de voir la configuration courante.

$ ./spi-config -d /dev/spidev0.0 -q
/dev/spidev0.0: mode=0, lsb=0, bits=8, speed=500000
$

Nous pourrons donc fixer le mode SPI pour s’adapter à un composant externe, le sens et la taille des mots échangés, ainsi que la vitesse de communication en Hz.

$ ./spi-config -d /dev/spidev0.0 -s 10000000
$ ./spi-config -d /dev/spidev0.0 -q
/dev/spidev0.0: mode=0, lsb=0, bits=8, speed=10000000
$

Communication

Un avantage du SPI est la possibilité de dialoguer en mode full-duplex, le maître recevant dans un registre de réception les données émises par l’esclave alors que lui-même transmet son message. Ce système est donc très rapide. Associé au débit élevé (habituellement plusieurs MHz) que l’on peut employer, il permet des communications très efficaces.

Il est néanmoins difficile à utiliser depuis l’espace utilisateur en employant les appels système read() et write() classiques. Le noyau met donc à notre disposition une commande ioctl() à laquelle on fournit deux buffers, l’un contenant les données à envoyer, l’autre destiné à la réception.

Le programme spi-pipe offre une interface pour cet appel système ioctl() en prenant en charge la gestion des buffers. Comme son nom l’indique, on l’emploie depuis la ligne de commande en lui fournissant les données à envoyer sur son entrée standard et en récupérant simultanément sur sa sortie standard les données reçues.

Comme le programme précédent, il présente une aide en ligne sur les quelques options proposées.

$ ./spi-pipe
./spi-pipe: no device specified (use option -h for help).
$ ./spi-pipe -h
usage: ./spi-pipe options...
  options:
    -d --device=    use the given spi-dev character device.
    -b --blocksize= transfer blocks size in byte
    -h --help            this screen
    -v --version         display the version number
$

Si on veut simplement envoyer octet par octet des données produites par la commande-1 vers un esclave SPI, on pourra utiliser une syntaxe comme

$ commande-1 | ./spi-dev -d /dev/spidev0.0 > /dev/null

Pour lire des données envoyées par un esclave et les traiter avec la commande-2:

$ ./spi-dev -d /dev/spidev0.0 </dev/zero  | commande-2

Enfin, on peut intercaler la commande dans un pipeline ainsi :

$ commande-1 | ./spi-pipe -d /dev/spidev0.0 | commande-2

Conclusion

Ce petit projet simple me sert à mettre au point et vérifier le comportement d’une bibliothèque de communication plus évoluée dont je reparlerai ici. Tous les retours (bugs, suggestions, etc.) sont les bienvenus.

 

Suivant :

Précédent :

12 Réponses

  1. fabrice dit :

    Salut Christophe,

    Superbes outils, ils m’auraient été d’un grand secours lors d’un précédent développement!

    Question à 3 francs 6 sous, est-ce que cela pourrait également être utilisable avec uClinux?

    a+

    Fabrice

    • cpb dit :

      Bonjour Fabrice,

      Je n’ai pas essayé de compiler ces utilitaires avec la uClibC, mais à mon avis ça ne devrait pas poser de problème, la seule dépendance au système étant des appels open() et ioctl() simples. J’ai juste un doute sur l’utilisation de getopt_long() qui est peut-être « Gnu specific » mais qu’on peut remplacer facilement par getopt() avec des options d’une seule lettre.

      A+

  2. sinseman44 dit :

    plus qu’à l’inclure dans buildroot maintenant …
    Super boulot en tous cas. 🙂

  3. Mustapha dit :

    Bonjour,

    Je veux tester ces outils pour programmer le potentiomètre digital MCP4132, pouvez vous me donner une idée.

    Merci

  4. leTux dit :

    Bonjour Christophe,

    Toujours pas d’article prévu pour le projet lxMCU ?

    J’attend cette article avec impatience 😉

    Merci d’avance

  5. Emmanuel dit :

    Bonjour,

    À ceux qui ne connaisse pas, xxd est un petit utilitaire bien pratique pour convertir du texte en binaire (et l’inverse) dans un pipe. Par exemple, pour lire l’identifiant d’une flash n25q256a, ça donne:

    echo « 9e00000000 » | xxd -r -p | spi-pipe -d /dev/spidev0.0 | xxd

    00000000: 0020 ba19 10

    Je viens d’utiliser ces outils pour comprendre le fonctionnement d’une mémoire flash sur une électronique que nous développons. Ils nous ont été d’un grand secours.

    Merci !

    • jgrossholtz dit :

      Merci pour cet article et surtout pour cet outil bien pratique. Je viens de valider le fonctionnement d’un proto grâce à vous !

      Pour envoyer du binaire hexadécimal, par exemple des commandes pour le slave sur le bus, on ne dispose parfois pas de xdd. Mais on peut y arriver simplement avec echo. Par exemple:
      echo -ne ‘\xAE’ | spi-pipe -d /dev/spidev0.1 > output

  6. Frank Norris dit :

    Dear Mr Blaess
    My apologies for writing in English my grasp of French is not up to conveying technical data.
    I currently using your spi-toolset on a raspberry pi, with the intention to access an ADC chip TLC549.
    I have successfully down loaded your spi-toolset and have managed to prove to myself that the TLC549 chipset with attached photo transistor is sensing light changes (is working), however the output is completely uncontrolled.
    I am unsure of what to use as command_1 and command_2. everything tried so far has been unsuccessful (clearly my grasp of linux commands is inadequate).
    It seems that command_1 shoulld turn the cs line from high to low to start the TLC549 chip operating, hold it for around 17 micro secs and then return it to high.
    The chip should take a sample reading convert it and send the output to MISO.
    I need to grap the result as a number for use in controlling an infrared camera’s exposure and lighting.
    Please, are you able to offer a clue as to how I should compose the commands to achieve this.
    Many thanks
    Sincerely Frank Norris Amateur wildlife photographer

  7. Steve Rice dit :

    This is like I2C tools. Very good job. But i am confused as to the command_1, is this a file with the spi commands in it ? I am a hardware developer and programming is not my thing but i can use command line tools to test my hardware. Thank you for any assistance.

    • cpb dit :

      No, command_1 is an executable file or a system command that you can run. Using the pipe symbol ‘|‘, everything the program write on its output is redirected to the choosen spi device.

      You can use for example echo "Hello" to send the « Hello » string.

      The command_2 program in the second example will receive as input what the SPI device sent. For example the command « wc » will count the received characters, words and lines.

  8. TGo1 dit :

    Bonjour Christophe,
    Super job, cependant je ne comprend pas tout …
    j’ai la version 1.0.2, et sur un spi-config, la réponse me sort un spiready=0
    Je présume que ceci veut dire que mon pigpio(spi) est OFF ?
    Alors que dans un programme, spi-open(…) me répond bien OK !!!!

    Autre soucis, est ce que piscope est assez rapide pour lire sur un bus SPI, car il me semble qu’il manque des clocks ou autres datas.
    Merci
    Thierry

URL de trackback pour cette page