Bus SPI 4 fils, modes 0 à 3, module MSSP et interfaçage de périphériques haute vitesse
Le SPI (Serial Peripheral Interface) est un bus de communication série synchrone et full-duplex développé par Motorola. Contrairement à l'I2C, le SPI utilise 4 fils et n'a pas d'adressage : chaque esclave a sa propre ligne de sélection (CS/SS).
Le SPI est nettement plus rapide que l'I2C (jusqu'à plusieurs MHz), ce qui le rend idéal pour les transferts de données volumineux (cartes SD, écrans TFT, ADC externes rapides).
| Signal | Direction | PIC16F877A | Rôle |
|---|---|---|---|
| SCK | Maître → Esclave | RC3 (Pin 18) | Horloge série |
| SDO (MOSI) | Maître → Esclave | RC5 (Pin 24) | Données sortantes du maître |
| SDI (MISO) | Esclave → Maître | RC4 (Pin 23) | Données entrantes vers le maître |
| CS / SS | Maître → Esclave | N'importe quel GPIO | Chip Select : LOW = esclave sélectionné |
Le SPI a 4 modes définis par deux paramètres : la polarité de l'horloge (CPOL) et la phase des données (CPHA). Le mode doit correspondre entre le maître et l'esclave.
| Mode | CPOL | CPHA | Description | PIC (CKP, CKE) |
|---|---|---|---|---|
| 0 | 0 | 0 | Repos bas, échantillonnage front montant | CKP=0, CKE=1 |
| 1 | 0 | 1 | Repos bas, échantillonnage front descendant | CKP=0, CKE=0 |
| 2 | 1 | 0 | Repos haut, échantillonnage front descendant | CKP=1, CKE=1 |
| 3 | 1 | 1 | Repos haut, échantillonnage front montant | CKP=1, CKE=0 |
Le mode 0 (CPOL=0, CPHA=0) est le plus courant et est utilisé par la majorité des périphériques SPI (cartes SD, MCP3008, écrans TFT).
#include <xc.h>
#define _XTAL_FREQ 4000000
#define CS_PIN PORTAbits.RA5 // Chip Select sur RA5
#define CS_TRIS TRISAbits.TRISA5
/* ---- Initialisation SPI Master, Mode 0, Fosc/4 ---- */
void spi_init(void) {
// Broches SPI
TRISCbits.TRISC3 = 0; // SCK en sortie
TRISCbits.TRISC5 = 0; // SDO (MOSI) en sortie
TRISCbits.TRISC4 = 1; // SDI (MISO) en entrée
CS_TRIS = 0; // CS en sortie
CS_PIN = 1; // CS inactif (HIGH)
// Mode 0 : CKP=0 (repos bas), CKE=1 (donnée sur front montant)
SSPSTAT = 0x40; // SMP=0, CKE=1
SSPCON = 0x20; // SSPEN=1, CKP=0, Fosc/4 (SSPM=0000)
}
/* ---- Envoyer/Recevoir un octet (full-duplex) ---- */
unsigned char spi_transfer(unsigned char data) {
SSPBUF = data; // Écrire dans le buffer = lance le transfert
while (!SSPSTATbits.BF); // Attendre fin de transfert
return SSPBUF; // Lire la donnée reçue en même temps
}
/* ---- Écrire un octet (ignorer la réponse) ---- */
void spi_write(unsigned char data) {
spi_transfer(data);
}
/* ---- Lire un octet (envoyer un dummy 0xFF) ---- */
unsigned char spi_read(void) {
return spi_transfer(0xFF);
}
Le MCP3008 est un convertisseur ADC 10 bits SPI très populaire. Il offre 8 canaux analogiques et coûte moins de 2 €. Idéal pour étendre les capacités ADC du PIC.
uint16_t mcp3008_read(uint8_t channel) {
uint8_t b0, b1, b2;
CS_PIN = 0; // Sélectionner le MCP3008
spi_transfer(0x01); // Start bit
b1 = spi_transfer((0x80 | (channel << 4))); // Single-ended + channel
b2 = spi_transfer(0x00); // Dummy pour lire les bits restants
CS_PIN = 1; // Désélectionner
return ((b1 & 0x03) << 8) | b2; // Résultat 10 bits
}
| Critère | I2C | SPI |
|---|---|---|
| Nombre de fils | 2 (SDA, SCL) | 4 (SCK, MOSI, MISO, CS) |
| Vitesse max | 400 kHz (Fast) | Plusieurs MHz |
| Multi-périphériques | Oui (adresses) | Oui (1 CS par esclave) |
| Full-duplex | Non | Oui |
| Idéal pour | Capteurs lents, EEPROM, RTC | Carte SD, écran TFT, ADC rapide |
| Pull-up nécessaires | Oui (4.7 kΩ) | Non |
En résumé : utilisez I2C quand vous avez beaucoup de périphériques lents et peu de broches disponibles, et SPI quand la vitesse est critique ou que vous transférez beaucoup de données.