Cet article explique comment utiliser le port SPI présent sur le Atmega328p du Arduino UNO.

Dans cet article, nous utiliserons une boucle pour l’écriture. Cette méthode est simple mais elle limite les performances du microcontrôleur. Je ferai un autre article qui expliquera comment faire cette opération en interruption, ce qui est recommandé afin de libérer le programme principal.

Étape 1 : Initialisation du port SPI

Le port SPI utilise 3 liens pour transmettre et recevoir les données en plus d’un signal pour sélectionner l’esclave visé.

Signal Broche (port) Description
SCLK 13 (PB5) Horloge
MISO 12 (PB4) Données de l’esclave vers le maître
MOSI 11 (PB3) Données du maître vers l’esclave
CS 10 (PB2) Sélection de l’esclave

Les signaux SCLK, MOSI, CS sont donc des sorties pour l’Arduino et le signal MISO est une entrée. La ligne suivante configure les broches requises en sorties.

DDRB |= (1<<2) | (1<<3) | (1<<5) ;

La configuration par défaut correspond à la majorité des situations.  L’horloge principale est divisée par 4 (ce qui donne 4Mhz pour le Arduino UNO), le signal SCLK est à 0 lorsque le SPI est inactif, les données débutent par le MSB. Le registre de contrôle est le SPCR.

La ligne suivante active le SPI et place le SPI en mode maître :

SPCR = (1<<SPE) | (1<<MSTR);

Étape 2 : Utilisation du port SPI 

Après son initialisation, le port SPI est prêt pour envoyer des données. Avant toute communication, il faut sélectionner l’esclave en abaissant le signal CS correspondant. Il suffit ensuite d’écrire dans le registre SPDR l’octet à transmettre. Après chaque écriture, il faut lire le bit d’état SPIF du registre d’état SPSR. Ce dernier devient 1 lorsque la transmission est terminée. Voici une fonction d’écriture qui regroupe ces lignes :

uint8_t spiWrite(uint8_t data)
{
  SPDR = data;
  while(!(SPSR & (1<<SPIF)));
  return SPDR;
}

La fonction retourne le contenu de SPDR, qui contient alors l’octet reçu via le lien MISO simultanément à l’écriture sur MOSI.

Voici un exemple de code qui initialise le port SPI puis envoie 0x40 suivi de 0x05 vers un esclave.

// Dans cet exemple, CS est sur le bit 2 du port B
// Initialisation du SPI
DDRB |= (1<<2) | (1<<3) | (1<<5) ; 
SPCR = (1<<SPE) | (1<<MSTR);
// Transmission vers un esclave
PORTB &= ~(1<<2);   // mise à zéro de CS
spiWrite(0x40);
spiWrite(0x05);
PORTB |= (1<<2);   // mise à un de CS