[Tutorial] Le Nrf24L01, l’Arduino et le MSP 430.

Publié: 27 mars 2013 dans Tutoriaux
Tags:, , ,

Bonjour à tous !

Alors aujourd’hui je vous propose de faire communiquer un MSP430 et une Arduino par une liaison sans-fil à base de NRF24l01+.

Nrf24L01, késako ?

Ces modules de communication sont très intéressants pour plusieurs raisons :

* Le prix : à moins de 3€ sur ebay par module, on peut imaginer créer tout un réseau pour presque rien.
* Ce sont des transceivers : à la fois émetteur et récepteur.
* 2,4 ghz : ça élimine beaucoup d’interférences.
* 128 canaux et plusieurs canaux de réception par module : ça permet d’avoir plusieurs émetteurs pour un seul récepteur sans risquer de collision.
* Plusieurs fonctions directement implémentées : ré-émission automatique, CRC (checksum) …
* Portée : 100m en champs libre, 20 m en intérieur (après ça dépend des murs et du débit). Pour 12€ il existe des modules avec amplificateur de puissance, pas testé mais la portée est annoncée à 1000 mètres.
* La consommation (le point qui m’intéresse, vous après verrez pourquoi 😉 ) : à fond ils bouffent 12mA et à la plus faible puissance on tombe à 8 mA. Mais ce n’est pas tout, il utilise la technologie Shockburst qui consiste lors d’une émission à émettre toutes les trames d’un coup. Autrement dit, si on communique à 10 kbits par seconde avec le module alors il va « accumuler » les données, et une fois qu’on lui demande de transmettre il envoi tout d’un coup, ce qui réduit au maximum la consommation. Enfin on peut les mettre en veille, la consommation tombe alors à moins de 1µA (mais le SPI est toujours actif !). Le réveil est assez rapide (<130µs).

Bref ils ont de quoi convaincre ! Datasheet : http://www.nordicsemi.com/kor/Products/2.4GHz-RF/nRF24L01P

Un doc en anglais, une sorte de synthèse commentée de la datasheet qui m’a pas mal aidé (attention cependant elle traite des modules pas « + ») : http://www.diyembedded.com/tutorials/nrf24l01_0/nrf24l01_tutorial_0.pdf

Comparé à la version « + » il n’y a surtout que quelque registres qui changent.

Si vous voulez plus d’infos et/ou vous limiter au cas de l’arduino, je vous recommande les articles de M. Skywodd : http://skyduino.wordpress.com/2012/01/20/tutoriel-arduino-mirf-v2-nrf24l01/ http://skyduino.wordpress.com/2012/02/01/arduino-transmission-valeur-analogique-par-nrf24l01/

Alors pourquoi interfacer un MSP430 et un Nrf ?

Et bien comme vous l’avez vu, la consommation est particulièrement optimisée, et c’est également la spécialité des MSP430 (et en plus les deux utilisent du 3,3V). Prenons un exemple simple : une sonde de température ambiante. On n’a pas besoin de prendre la température toutes les secondes, seulement une mesure toute les 10 secondes, voire une toute les minutes. Et voilà le principe de fonctionnement :

1) Réveil du MSP430 et du NRF24L01+.

2) Acquisition de la température.

3) Emission radio vers la base.

4) On rendort tout le monde pendant 10 sec.

Les étapes 1) 2) et 3) prennent environ 200 µs. Donc pendant la très grande majorité du temps, la consommation est inférieure à 2µA, et pendant 200µs elle reste très modérée : 400µA du NRF + 400µA pour un MSP430 à 1mhz. L’émission consomme 12 mA mais pendant 10-20 µs.

J’ai fait un essai avec une émission toutes les 2 secondes, alimenté par un condensateur goldcap 5F. Ca a tenu 2 jours, ce qui me donnait une consommation de ~10µA. Avec un pile bouton 200 mAh, ce montage pourrait tenir : 200 000 / 10 / 24 / 365 = 2,3 an ! Et à 0,5 hz de fréquence ! Imaginez si vous greffez un panneau solaire ou si on passe à une émission par minute … Les applications sont quasi infinies !

Allez, assez de théorie place à la pratique !

Alors sachez que je me suis pas mal débattu avec ce trio … Car il y a quelques paramètres qui diffèrent entre les deux librairies, et le problème c’est qu’on bosse en aveugle : tant que tous les paramètres ne sont pas bons, il n’y a pas de communication et le debug est pour ainsi dire quasi-impossible … Bref voici le code côté MSP430 (lib = https://github.com/spirilis/msprf24) :

#include <msp430.h>
#include "msprf24.h"
#include "nrf_userconfig.h"

char addrTX[]={'t','e','s','t','2'};

char buf[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; // trame exemple

int main(void) {

WDTCTL = WDTPW + WDTHOLD;
BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0;

if (CALBC1_1MHZ != 0xFF) {
DCOCTL = 0x00;
BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */
DCOCTL = CALDCO_1MHZ;
}

BCSCTL1 |= XT2OFF + DIVA_3;
BCSCTL3 = XT2S_0 + LFXT1S_0 + XCAP_0;
TA0CCTL0 = CM_0 + CCIS_0 + OUTMOD_0 + CCIE; // configuration du timer à 1 s
TA0CCR0 = 4095;
TA0CTL = TASSEL_1 + ID_0 + MC_1;

UCB0CTL1 |= UCSWRST; // configuration du SPI
UCB0CTL0 = UCMSB + UCMST + UCMODE_0 + UCSYNC;
UCB0CTL1 = UCSSEL_2 + UCSWRST;
UCB0BR0 = 64;
UCB0BR1 = 6;
UCB0CTL1 = ~UCSWRST;

P1DIR|=BIT0;

rf_crc=RF24_EN_CRC|RF24_CRCO; // CRC active, 16-bit
rf_addr_width=5; // On utilise une adresse de 5 bytes
rf_speed_power=RF24_SPEED_2MBPS|RF24_POWER_0DBM; // vitesse 1MBPS et puissance max
rf_channel=1;

msprf24_init();

msprf24_set_pipe_packetsize(0,16); // payload de 16 byte sur le pipe 0
msprf24_open_pipe(0,1); // ouverture du pipe avec Auto-Acknowledgement

w_tx_addr(addrTX); // configuration adresse émission
w_rx_addr(0,addrTX); // configuration adresse réception idem à celle de transmission
                      // pour permettre la réception de l'ACK

msprf24_standby(); // module en veille (pas endormi)

while(1){

if(msprf24_is_alive()) { // fait clignoter la LED rouge sur launchpad si
	P1OUT^=BIT0; // le nrf est bien connecté
}else{
	P1OUT&=!BIT0;
}

LPM3; // on endort

w_tx_payload(16,buf); // on charge le FIFO avec le tableau buf
msprf24_activate_tx(); // émission
msprf24_get_irq_reason(); // récupère les alertes du NRF
while(!(rf_irq && RF24_IRQ_TX)) msprf24_get_irq_reason(); // tant que la transmission n’est pas finie, on boucle
msprf24_irq_clear(RF24_IRQ_TX); // on efface les flags d’alerte

}

}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR_HOOK(void) {
LPM3_EXIT;
}

+

Modification du nrf_userconfig.h : en haut il y des constantes suivant la fréquence de fonctionnement, il suffit de décommenter la partie qui vous correspond et de commenter les autres et en bas la partie hardware pour définir où sont brancher les pins CE, CSN et IRQ si vous l’utilisez. J’avoue j’ai pas approfondi le code plus que ça, et il n’est pas optimisé. Il y a surement des lignes que je pourrai virer, mais ils m’avaient tellement fait galérer ces modules que j’en avez marre xD

Comme je vais reprendre ce principe bientôt, je publierai une mise à jour 😉

Côté Arduino :

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

void setup(){
  Serial.begin(9600);
  ConfigMirf();

  Serial.println("Listening...");
}

void loop(){

  if( Mirf.dataReady()){

    byte data[Mirf.payload];
    Mirf.getData(data);

    for (int i=0;i<16;i++){
      Serial.print(data[i]);
      Serial.print(" ");
    }
Serial.println(" ");

  }

}

void ConfigMirf(){

  Mirf.spi = &MirfHardwareSpi;
  Mirf.cePin=8;
  Mirf.csnPin=7;

  Mirf.init();

  Mirf.setRADDR((byte *)"2tset");
  Mirf.setTADDR((byte *)"1tset");
  Mirf.payload = 16;
  Mirf.config();

}

+

Modification du fichier Mirf.h : en effet chose étonnante les créateur de cette lib n’ont pas créé de fonction directe pour modifier la gestion de la CRC … Il faut modifier cette ligne en haut :


#define mirf_CONFIG ((1<<EN_CRC) | (1<<CRCO) ) // CRC active 2 bytes, correspond ici avec le code du MSP 430

#define mirf_CONFIG ((1<<EN_CRC) | (0<<CRCO) ) // CRC active 1 byte

#define mirf_CONFIG ((0<<EN_CRC) | (0<<CRCO) ) // CRC désactivée

Alors vous aurez peut-être noter les petites différences :

* Les adresses ne sont pas dans le même ordre.

* Les canaux sont décalé de 1 (MSP = de 1 à 128, Arduino = de 0 à 127)

Alors après bien sur vous pouvez remplir buf avec ce que vous voulez. A noter également qu’ici je n’ai pas géré la mise en sommeil du Nrf, seulement celle du MSP, mais c’est très facile, il suffit de faire :


msprf24_powerdown(); // endort

msprf24_standby(); // réveil, nécessite 130µs d’après la datasheet

Pour recevoir côté MSP430, en gardant les paramètres du précédent code :


msprf24_get_irq_reason();

if(rf_irq && RF24_IRQ_RX) {

msprf24_irq_clear(RF24_IRQ_RX);

r_rx_payload(16,buf);

}

Bon la du coup ça reste assez simpliste au niveau des fonctionnalités, mais débroussaillé tout ça m’a pris un temps fou vu ces quelques différences foireuses dures à débusquer … Mais ça fait déjà le principal : envoyer et recevoir des données. Je n’ai pas été très explicite dans le code, si vous comprenez pas n’hésitez pas je compléterais 😉

Enjoy !

EDIT 12/06/13 : suite à des problèmes d’un lecteur j’ai repris mon code et trouvé quelques erreurs. En fait il y a quelque chose qui m’échappe avec le registre EN_AA qui permet l’activation de l’auto-acknowledgment. Il s’agit d’une fonction qui permet à l’émetteur de confirmer que son message a bien été reçu. Je ferai un peu plus de test demain mais je pense avoir trouvé. En tout cas j’ai édité les codes de l’articles qui fonctionnent avec un launchpad équipé d’un G2553 et une Arduino nano (ou Uno et compagnie c’est pareil, testé sur Mega également, il suffit d’adapter les n° de pins).

Une remarque également : la librairie Arduino utilise le pipe 1 pour recevoir car apparemment c’est le pipe 0 qui reçoit les ACK, ce qui permet de le garder libre. C’est pourquoi sur le MSP430 il faut configurer le pipe 0 avec la même adresse que celle utilisée pour l’envoi, une façon de reconnaître la provenance de l’ACK et d’éviter tout conflit.

 

EDIT n°2 13/06/13 : deux points : j’ai approfondi le coup de l’auto-acknowledgment. Il faut également que ce paramètre soit synchronisé sur les deux parties ! Par défaut le nrf l’a d’activé, donc si on ne précise pas côté Arduino, il faut utiliser sur le MSP430 :

msprf24_open_pipe(0,1);

+

Il faut mettre d’adresse du destinataire en réception sur le pipe 0.

Si on ne veut pas d’ACK, dans ce cas on désactive côté arduino avec :

Mirf.configRegister(EN_AA,0); // ACK disabled

+

Côté MSP :

msprf24_open_pipe(0,0);

Second point le câblage. Bon côté Arduino y’a pas de mystère je pense. Côté MSP :

MISO P1.6
MOSI P1.7
SCK P1.5
CE P2.4
CSN P2.3

Attention, CE et CSN sont dépendants de ce que vous avez mis dans nrf_userconfig.h. Pour avoir cette config j’ai :


/* CSN SPI chip-select */
#define nrfCSNport 2
#define nrfCSNportout P2OUT
#define nrfCSNpin BIT3

/* CE Chip-Enable (used to put RF transceiver on-air for RX or TX) */
#define nrfCEport 2
#define nrfCEportout P2OUT
#define nrfCEpin BIT4
Publicités
commentaires
  1. tiji dit :

    Bonjour battomicro, je viens vers toi car je suis en galère avec le NRF l’arduino et le MSP. en fait je suis tombé sur ton tuto mais j’arrive pas à compilé coté arduino j’ai pas mal d’erreur. j’aimerais donc savoir s’il y’a moyen que tu m’aides.
    Merci

  2. battooo dit :

    Salut,

    J’ai corrigé le code, j’avais eu un problème avec les balises code de wordpress et ça m’avait fait plein de bug et j’avais effacé quelques trucs importants … Réessaye le code de mon article, ça devrait compiler cette fois 😉

  3. tiji dit :

    merci pour ton aide. ouais ça compile nikel mais je reçois tjrs pas de trame je sais pas si c mon msp430 qui envoie rien ou c’est moi qui ai mal configurer mes 2 modules (arduino UNO, et MSP430 F). en tt cas merci de ton aide. je continue de fouiner. le canal 0 coté arduino correspond au 1 coté msp c bien ça?

  4. battooo dit :

    Oui effectivement. Si j’ai le temps demain je retesterai mes deux codes histoire de voir si j’ai pas une autre erreur qui s’est glissée …

  5. tiji dit :

    slt batt. je galere tjrs avec le code du coup j’ai pris un msp430G2553 j’aimerais savoir si c le meme que tu utilise? et toi ta l arduino uno Rev3 ou non? et tes données tu les reçois bien via l hyperterminal de l’arduino (car moi j’ ai rien juste les printf que je fais)? du coup je sais po si c le canal ou le debit qui est pas bon.
    merci pour ton aide.

  6. tiji dit :

    et un dernier truc pourquoi ton adress emission et reception est en l envers lol ??

  7. battooo dit :

    oui normal : la logique « intrinsèque » du nrf24l01 commence par le byte de fin. La lib MSP respecte ça, alors que ce n’est pas le cas sur Arduino ce qui n’est pas grave entre Arduino : si tout le monde est à l’envers, alors tout le monde est à l’endroit 😉

    J’ai pas eu le temps mais je pense que demain je l’aurai pour tester mes codes vite fait, autant tu te prends la tête pour rien 😉

  8. tiji dit :

    slt batt . j’ai besoin de ton aide. pourrais tu me filler t truc coté arduino et coté msp des que ta tout testé? ta mon mail normalement non ?
    Merci d’avance je suis vraiment coincé si sa se trouve ya les trame qui passe et c moi qui sait pas comment les observer. (oublie pas de mettre cmt les pin sont connectées stp !) je suis désespéré lol

  9. battooo dit :

    Oué c’est bon j’ai trouvé le lièvre ^^ bon il y a deux trois erreurs de syntaxe comme je l’avais prévu suite au bug de balises code, mais il y a un problème avec le registre EN_AA, il faut le forcer à 0 côté arduino. Par contre si on le mets à 1 de chaque côté, ça ne marche plus … Bref je mets à jour tout ça ce soir en attendant d’y voir plus clair

    mirf.configRegister(EN_AA, 0)

  10. tiji dit :

    merci batt mon espoir de faire marché ce bordel repose sur toi ! fait moi signe des que ta corrigé tout ça parce que je sais plus ou chercher lol . j ai jamais galéré autant a faire marché un truc sur l’arduino par contre le msp c vrai q je découvre lol !!! merci pour ton aide

  11. battooo dit :

    C’est corrigé depuis 4h 😉

  12. tiji dit :

    ouais je suis entrain de le tester la! c’est vraiment le bordel lol. je vois passé des truc bizarre sur l’hyper terminal impossible de savoir s’il sagit de la trame ou des printf du programme en tt cas il faut changer la vitesse pour que ça se mette a jour et des fois ça affiche  » attente données  » et je sais pas à quoi cela correspond! c’est vraiment le vrai bordel ce truc lol… en tout cas gros merci pour ton aide. toi tu recoit bien ta trame 1234…15 dans l’hyperT à le vitesse de 9600 bds ?

  13. battooo dit :

    Nan je passe simplement par le Serial Monitor arduino

  14. tiji dit :

    Ok merci battooo . peut tu juste me cmt sont connecté tes pin (MI, MO, CLK, CE, CSN, IRQ) sur le mspG2553 et l’ardiuno uno car mon ma boucle nrf_is_alive allume kedal ! stp.

  15. battooo dit :

    updated 😉

    Au passage l’IRQ n’est pas géré ici donc inutile de le brancher

  16. tiji dit :

    ok merci. je me remets dessus en espérant avoir ma  » fameur trame qui passe « 

  17. tiji dit :

    putain ça marche se foutu truc ! merci batt … par contre les trame arrivent quand elles veulent des fois durant 30 min y a rien et d’un coups y en à 2. En tout cas merci pr ton aide. au fait ta bien fait de préciser les Pins. c’est important. encore Merci b@tt.

    • battooo dit :

      si tu as des problèmes de transmission, essaye ne virant la CRC. Moi sans l’ACK et avec la CRC 16 bits, à moins d’un mètre j’avais des paquets ratés !