2 modules SPI en même temps > conflit

Bonjour à tous.

Je suis bloqué! Voila pas mal d'heures (séparé en plusieurs jours) que je passe sur un petit projet. Malheureusement je suis bloqué à un endroit. Le pire c’est que j’avais prévu que je serais peut être bloqué a cet endroit. Mais en ayant compris le concept, je pensais que j’aurais pu m’en sortir seul mais ce n’est pas le cas.

Pour simplifier: une partie de mon projet consiste à recevoir des informations via un module NRF24L01 (piloté par la librarie RF24) et afficher les informations reçu sur un ecran OLED (controleur SSD1306).
Jusqu'a là en théorie, il n'y a rien d'impossible, loin de là.

Le module radio et l'ecran OLED sont pilotés tous les deux en SPI.

Donc voici les pin SPI de l'arduino (Certaines pins sont donc utilisé par les deux modules)

10 (SS),
11 (MOSI),
12 (MISO),
13 (SCK)

Le RF24 utilise:

CE 6

CS 7

MOSI 11
MISO 12
SCK 13

L’ecran OLED:

RESET 8
DC 9

CS 10

MOSI 11
CLK 13

Sur ma plaque d’essais, j’ai donc branché les deux modules comme ci dessus.
J’ai d’abord fait un prototype très très simple qui utilise seulement le RF24 pour m’assurer que le montage etait bon. Ensuite j’ai fais la même chose pour l’ecran OLED.
Conclusion: Les deux modules fonctionnent bien quand ils sont utilisé séparément.

Et comme vous vous en doutez, quand j’essaye de piloter les deux dans le même programme, ca ne fonctionne pas.

J’ai essayé d’enlever le plus de code possible pour comprendre a partie de quel endroit l’ecran cesse de fonctionner. Voici le code:

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>



#define OLED_DC 9
#define OLED_CS 10
#define OLED_CLK 13
#define OLED_MOSI 11
#define OLED_RESET 8

RF24 radio(6,7);
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);






const uint64_t pipe = 0xF0F0F0F0D2LL;


void setup()   {                
		
	Serial.begin(57600);

	// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
	display.begin(SSD1306_SWITCHCAPVCC);
	
	radio.begin();
	radio.setRetries(15,15);	
	radio.openReadingPipe(1,pipe);




}


void loop() {


	oledWrite();
}	

void oledWrite(){
	
		
display.clearDisplay();
		// text display tests
		display.setTextSize(1);
		display.setTextColor(WHITE);
		display.setCursor(0,0);
		display.println("Hello, world!");

		display.display();

}

Comme vous pouvez le voir, j’ai effacer une grosse partie du code. Il n’y a plus rien dans le loop quasiment.

C’est dès que je mets ces 3 commandes là:

radio.begin();
radio.setRetries(15,15);
radio.openReadingPipe(1,pipe);

que l’écran arrête de fonctionner (en fait dès que je fais radio.begin()) en fait.

D’après ma compréhension, théoriquement les pins CS des modules devraient changer d’état à chaque fois qu’une commande est envoyé au module pour indiquer au SPI à qui parler non?

J’ai regarder un peu le code source mais j’avoue être perdu :frowning:

Est ce que quelqu’un aurait un conseil ou une idée pour me débloquer peut être?

merci beaucoup!

La raison est que la lib d'Adafruit n'utilise pas le périphérique interne SPI mais configure les broches en question comme des pins I/O et recrée le protocole SPI "à la main".
Alors que la lib RF24 utilise le controleur SPI intégré.

La bonne nouvelle c'est que cela veut dire que tu peux en fait utiliser l'écran et la lib Adafruit sur des pins complétement décorrélées.
Garde donc les pins dédiées SPI (MOSI=11, MISO=12, SCK=13) pour le RF24 et prend d'autres pins libre pour le "pseudo-SPI" de l'écran (OLED_MOSI=? et OLED_SCK=?)

Ha oui ca me parait logique maintenant que tu me le dis.
Est ce que tu crois que ca serait super compliqué si je tente de revoir la librarie pour enlever tout ce qui concerne I2C et que je convertisse pour utiliser le SPI hardware?

Enlever I2C : ca ne doit pas aller bien loin

Utiliser le SPI hardware : pour l'instant je n'ai aucune idée pourquoi Adafruit utilise un SPI soft plutot que hard.
Donc pourquoi pas mais il y a peut être une raison.

Raisons possibles :

  • Le mode SPI n'est pas supporté en standard par le SPI hardware de l'ATmega
  • Le mode SPI est supporté mais pas courant et il serait différent de celui utilisé par d'autres périphériques comme le RF24

On voit dans la lib RF24 que chaque fois qu'on veut acceder au RF24 en mettant CSN à LOW, il fait :

  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV4);

Ce qui est assure qu'à chaque fois qu'on veut faire un accès à ce composant, le SPI est dans le bon mode.
De nombreuses libs ne le font pas. Elles configure le SPI au moment du begin() et puis suppose après qu'il est toujours dans le bon mode.
Il faudrait donc déterminer la bonne configuration du SPI pour l'écran OLED.
Apparemment le BitOrder est aussi MSBFIRST mais je n'ai pas regardé pour les autres paramètres.

Salut

Oui je me suis rendu compte que beaucoup de lib ne s'occupait pas de remettre CS à low.
C'est ici que je pensais avoir des problèmes tout simplement.

Je vais peut être faire quelques tests. Je ne me rends vraiment pas compte de l'ampleur. On verra bien :slight_smile:

Ha, je viens de trouver ceci:

http://forum.arduino.cc/index.php/topic,108542

Rebonjour.
En regardant sur github dans le repo du driver ssd1306, et plus particulièrement dans les fork, une personne qui avait fait un patch pour ajouter l'option d'utiliser le SPI hardware. Le patch n'a jamais été poussé dans la branche master. Depuis le master a évolué.

J'ai donc juste réapliquer les changements du patch dans la version actuel du driver. Cela fonctionne très bien est c'est vraiment beaucoup plus rapide qu'avec le SPI software.
Cependant, je n'arrive pas plus a utilisé mes deux modules en même temps.

J'initialise mes deux modules, pas de problème. J'affiche un message sur l’écran: pareil, aucun problème. Par contre, dès que j’appelle la fonction openReadingPipe(1,pipe); (du module RF24), cela efface ce qu'il y a l’écran. Pour que mon écran refonctionne, je dois ré-instancier mon écran. Donc je dois à chaque fois le réinitialiser (il inialise le SPI à chaque fois en fait). J'imagine qu'en faisant cela le RF24 ne doit plus fonctionner et je vais surement devoir le re-instancier également à chaque fois.

J'ai regardé à quel ligne justement l'ecran est effacé.
Voici la ligne en question:

write_register(pgm_read_byte(&child_pipe[child]), reinterpret_cast<const uint8_t*>(&address), 5);

Je ne comprend pas du tout ce que cela représente. Pourtant je ne vois pas de lien avec le controleur SSD1306.

Pourtant dans le code du driver SSD1606, il gère bien à chaque fois la pin CS avant chaque transfert SPI
(et dans le module RF24 également)

Selon vous, qu'est ce qui pourrait faire qu'il y a un conflit avec les deux librairies?