RFM70 Funkmodul

Projekt: RFM70 Funkmodul

Bei dem RFM70 Funkmodul handelt es sich um ein sehr kompaktes und sehr einfach ansteuerbares Modul, das im 2.4 Ghz Frequenzbereich arbeitet. Das Modul kann sowohl senden auch als empfangen, sehr interessant ist dabei die Möglichkeit, dass bis zu sechs Data Pipes genutzt werden können, so kann man ein Modul mit bis zu sechs Adressen ansteuern. Die Adressen können bis zu 5 Byte lang sein was einen riesigen Adressraum ermöglicht.

Einsatzgebiete

Derzeit arbeite ich an einer Haussteuerung, die mittels dieser Module vernetzt werden soll. Für das Modul spricht der große Adressraum, so dass man sehr viele Module miteinander vernetzen kann. Natürlich sind aber auch noch andere Einsatzgebiete denkbar, mit der Übertragungsgeschwindigkeit von bis zu 2Mbps ließen sich sogar Audioübertragungen realisieren.

AVR Library

Die Ansteuerung des Moduls ist sehr einfach, leider fand ich nirgendwo konkrete Beispiele für die Ansteuerung mittels AVR Mega32. Daher habe ich auf Basis der Arduino RFM70 Library eine eigene kleine Library für den AVR Mega32 geschrieben. Sicher kann man diese Library auch auch anderen AVR Controllern verwenden.

Benutzen der Libarary

Das Einbinden der Library ist recht simpel, da sie nur aus zwei Dateien besteht, der Datei rfm70.h und rfm70.c. Zunächst einmal müssen die verwendeten SPI Pins in die Datei rfm70.h eingetragen werden. Dafür sollten folgende #defines genutzt werden:

// PIN SETUP

#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define CE   PB3
#define CSN  PB4
#define SCK  PB7
#define MISO PB6
#define MOSI PB5
#define IRQ  PD2

Wenn Sie in Ihrem Projekt keine Uart ausgabe verwenden, dann sollten Sie den Verweis auf jedenfall entfernen, außerdem müssen Sie dann den Quellcode durchgehen und die entsprechenden Funktionen des Uarts auskommentieren. Damit Sie direkt starten können habe ich eine Uart Lib von Peter Fleury angehangen, diese habe ich beim Testen auch verwendet.

In der main.c wird es nun spannend, hier müssen wir zwischen Sender und Empfänger unterscheiden. Beginnen wir zunächst mit dem Empfänger.

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "uart.h"
#include "rfm70.h"

#define UART_BAUD_RATE 9600

int main()
{
	uint8_t buffer[32];

	sei();
	uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

	DDRA |= (1<<PA4);
	_delay_ms(1000);
	uart_puts("System Ready\n");
	Begin();

	setMode(1);
	setChannel(8);

	while (1)
	{
		if (receivePayload(buffer))
		{
			uart_puts((char*)buffer);
			uart_puts("\n");
		}
	}
}

Ich denke, der Code sollte selbsterklärend, wichtig ist nur, dass man den richtigen Modus wählt und das Sende- und Empfangsmodul auf dem selben Kanal liegen.

Kommen wir abschließend zum Sender, hier benötigen wir als erstes einmal Testdaten, die wir anschließend versenden möchten:

uint8_t test[20]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78,0x06,0x11,0x99};

Dann verläuft das ganze fast analog zum Empfänger, nur diesmal müssen wir den Modus natürlich auf Senden stellen.

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "uart.h"
#include "rfm70.h"

#define UART_BAUD_RATE 9600

int main()
{
	uint8_t test[20]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78,0x06,0x11,0x99};
	uint8_t buffer[32];

	sei();
	uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

	DDRA |= (1<<PA4);
	_delay_ms(1000);
	uart_puts("System Ready\n");
	Begin();

	setMode(0);
	setChannel(8);

	while (1)
	{
		sendPayload(test,20, 0);
		_delay_ms(20);
	}
}

Sollte es Probleme beim Funken geben, dann muss man evtl. einmal den Kanal wechseln, auf dem beide Module funken. Da WLAN u.a. auch auf dieser Frequenz arbeitet, kann es da schon zu Beeinträchtigungen kommen, dann muss man mit den Kanälen ein wenig rumspielen. Eine automatische Kanalsuche wäre sicher auch sehr interessant.

Download

RFM70 Development-Board

Derzeit entwickel ich die Library unter verwendung meines Development-Boards weiter. Mehr Informationen dazu finden Sie unter dem Artikel RFM70 Funkmodul Development Board. Hier werden u.a. Funktionen wie automatische Kanalsuche, Sternnetzwerk etc. implementiert.

102 thoughts on “RFM70 Funkmodul

  1. Hallo Daniel

    Wollte gerne den RFM70 Module testen doch leider kann ich nur Bascom oder PicBasic Pro. Hast Beispielcode dafür?

    Danke
    Gruss
    Pedro

    • Hallo Petro,

      mit Bascom kann ich leider nicht weiterhelfen. Habe das vor Jahren mal benutzt. Ist vielleicht ein guter Zeitpunkt, um in die C-Programmierung einzusteigen?

      Viele Grüße
      Daniel

  2. Funktioniert dieser Code ohne Änderung auf einem ATmega 32 oder ATmega 16?
    Und sind die UART funktionen schon fertig implementiert, oder muss man sie noch ändern?

    • Hallo,

      ich habe diese Lib auf einem AtMega32 entwickelt, auf einem AtMega16 kann ich sie leider nicht testen. Sollte aber auch funktionieren. Vielleicht kannst du das ja mal testen und dazu ein kleines Feedback geben?

      Für die Uart Ausgabe verwende die Library von Peter Fleury. Der dazu steht im Blog.

  3. okay. ich werde sie testen und dir dann das Ergebnis schicken..
    Werde, wenn deine Funktionen funzen, wenn ichs schaffe eine Frequenzwahl einbauen..
    aber mehr dazu später

    • ok da bin ich gespannt. Meinst du jetzt eine Kanalsuche oder wirklich eine Frequenzwahl? Bin mir jetzt nicht mehr ganz sicher, weil schon ein wenig was her, ob man die Frequenz wählen konnte. Ich glaube das war nur über Kanäle realisiert. Die kann man mit meiner Lib schon manuell wechseln.

  4. Ja ich meine nicht die Frequenz, denn ich denke dass die Fix sind.
    Man hat aber eh 83 zur Auswahl :-)
    nein ich möchte die Kanalsuche machen, was eigentlich Frequenzhopping des 2,4 GHz Systems auszeichnet.
    Meine Teile müssen aber vorher mal geliefert werden...

    • stell ich mir nicht ganz so einfach vor, man muss ja Empfänger und Sender synchron auf einem Kanal halten. Also vielleicht in dieser Art:

      Empfänger stellt schlechten Empfang fest, teilt das dem Sender mit und gleichzeitig auf welchen Kanal er wechseln will. Dazu müsste er aber dann ein ACK vom Sender erhalten, was bei schlechten Empfang zu Problemen führen könnte.

      Eine andere Möglichkeit wäre ein linearer Suchlauf, der auf beiden Geräten implementiert ist; auch nicht ganz einfach.

      Hast du schon Ideen dazu?

      • ich muss dir gestehen, ich hätte mir auch so was gedacht, aber ich muss erst mal die Bauteile verlöten und grundsätzlich zum Laufen bringen, dann gehts weiter. :-)
        Hatte in letzter Zeit viel um die Ohren.
        Kannst du mir ein gutes SMD Lötset empfehlen?

        • ok dann wünsche ich dir da viel Erfolg; halt mich mal auf dem Laufendem :)

          hmm nein ich löte SMDs mit einer ganz normalen Lötstation, mit ein wenig Übung ist das kein Problem.

  5. Hallo,
    vielen Dank für die Lib mit Beispiel, ist schnell selbsterklärend! Habe das Beispiel mit WinAVR auf AtMega32 übersetzt, und auf zwei Targets gespielt, und siehe da, hat auf Anhieb funktioniert!!
    Zwei Anmerkungen:
    - Die Kommentare zu "Bank0 register initialization" passen scheinbar nicht zu den eingestellten Werten.
    - Das Ganze funktioniert bei mir nur bei einer Übertragung von 20Bytes (wie im Beispiel). Wenn ich 32Byte schicke, dann kommen nur 20Byte an....Hast DU diesen Effekt auch?

    Grüße

    • Hallo Sven,

      na das hört man doch gerne.
      Ich habe die Register Inits so aus der Arduino übernommen, ob die nun tatsächlich stimmen habe ich nicht überprüft. Das werde ich mal tun, sobald ich wieder eine Schaltung aufgebaut habe.

      Soweit ich mich erinnern kann, hat bei mir das Senden von größeren Paketen auch funktioniert, hast du evtl. vergessen die Datenlänge anzupassen? Also in deinem Fall wäre das dann so:
      sendPayload(test,32, 0);
      Wäre so das erste was mir einfällt.

      Testen kann ich es momentan leider nicht, da ich keine Schaltung aufgebaut habe.

      Viele Grüße
      Daniel

      • Hallo Daniel,
        ich glaube ich habe das Problem im Beispiel gefunden. Du übergibst einen Pointer an receivePayload für einen uint8. receivePayload schreibt aber eine ganze Folge von Bytes (Paketlänge). => Zeigerüberlauf.

        Habe daher die Zeile:

        uint8_t *buffer = 0;

        durch die Zeile:

        uint8_t buffer[32];

        ersetzt, da ich die vollen 32 Byte Nutzdaten verwende. Dann funktioniert es...

        Grüße Sven

        • vielen dank für den Hinweis, ich werde es bei Gelegenheit anpassen; wie ich solche Variablenüberläufe hasse ;)

  6. Ich habe nun die Module gelötet und nun ja, funzt nicht so ganz.
    Hast du berücksichtigt dass das SPI Interface des RFMs nur 8Mhz maximal kann.
    Also wenn den Mc mit 16Mhz betreibe kommt es zu Problemen?

    • also ich habe mal auf die schnelle einen Blick ins Datenblatt des Mega32 geworfen. Ich initialisiere den SPI mit einen Standartteiler von 4, also bei einem Oszillator Takt von 16Mhz müsste es eigentlich auch noch funktionieren. Der SPI würde dann mit 4Mhz laufen.

  7. Hi,
    Schon mal ein Danke für das umschreiben für AVRs, hat eine Menge Arbeit gespart.
    Nur hab ich ein kleines Problem. Ich bekomme nicht die Daten die ich sende. die Initialisierung läuft alles, senden tut er auch, empfange ja was. aber schon die uart Ausgabe beim senden stimmt nicht. Und ich finde den Fehler nicht. Senden will ich einfach nur 3 Byte {0x00,0xff,0x0f}; im Uart gibt er mir dann das hier aus:
    FF 2C 20 0F 2C 20 0A 2C ist ASCII das Komma und 0A die nächste Zeile. Aber zwischen den Kommas dürfte doch nur ein Byte stehen, oder? Des weiteren wird die 0x00 komplett übersehen. und was sucht die 20 da?

    Das Empfangene ist dann ganz kurios, da trifft manchmal die 0x00 und 0xff und 0x0f, aber eher selten. hab schon gedacht, dass da irgend ein WLAN stört und mehrmals den Kanal gewechselt aber das ändert auch nichts.

  8. Hallo Daniel , gute Arbeit !
    Ich habe das gerade mit 2 x Atmega328 getestet. Den muss man noch in der uart.h eintragen , dann funzts aber gut. Danke für deine Veröffentlichung , hat mir viel Arbeit ( und Kaffee ;) ) erspart. Sollte mir auch mal was einfallen werde ich es euch wissen lassen.
    Schönen Gruß
    Rex

  9. Hallo,

    ich will heute dein Projekt nachbauen.
    An PA4 hast du eine LED angeschlosen, die im Code immer mal wieder umgeschaltet wird?
    Beim Empfang muss es wirklich "uint8_t buffer[32];" heißen. 32, weil das die maximale Payload ist. Mit "uint8_t *buffer = 0;" werden die empfangenen Daten in die RAM-Adresse 0 und folgende geschrieben. Dort stehen, wenn die Adresse überhaupt existiert, i.d.R. andere Daten.

    Viele Grüße
    Ulrich

    • Hallo Ulrich,

      ja an PA4 hängt eine LED, sie dient nur zu Debug Zwecken, so konnte ich sehen, ob der Controller läuft.

      Wie weiter oben schon erwähnt, funktioniert der Code nur mit einer Payload von 20 Bytes, weil dann der Buffer überläuft, den Fehler muss ich wirklich mal korrigieren. Wenn du die volle Payload nutzen möchtest, dann muss es wie du richtig sagst "uint8_t buffer[32];" heißen.

      Viel Erfolg beim Nachbau, ich würde mich über ein Feedback von dir freuen.

      Viele Grüße
      Daniel

  10. Hi daniel
    great project
    I have tried to load the software into avr studio4 but it will not run is it possible for you to tell me what I am doing wrong
    thanks peter

    • Hi Peter,

      can you give me some more information about your problem. It is quite difficult to me help you without a detailed error message or like that.

      But it is nice to see that my blog is read by english people too :D

      best regards
      Daniel

  11. Hi daniel
    Thank you for replying
    I first down loaded your library and put it in a folder on my D drive
    then loaded into avr studio4 main .
    and this is a copy of the error message`s
    thank peter

    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:31: undefined reference to `uart_init'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:35: undefined reference to `uart_puts'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:36: undefined reference to `Begin'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:38: undefined reference to `setMode'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:39: undefined reference to `setChannel'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:51: undefined reference to `receivePayload'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:53: undefined reference to `uart_puts'
    D:\rfm70m32\rfm70m32\default/../rfm70m32.c:54: undefined reference to `uart_puts'
    make: *** [rfm70m32.elf] Error 1
    Build failed with 8 errors and 1 warnings...

  12. it seems like you have forgot to include the necessary libraries. Additional you need download the uart lib from Peter Fleury, the link to his website is in the article above.

    Please make sure, that you add the lines to your code:

    #include "inttypes.h"
    #include "avr/io.h"
    #include "avr/interrupt.h"
    #include "util/delay.h"

    #include "uart.h"
    #include "rfm70.h"

    An Example for using my library is in the article too. You find the code unter the german topic: "Benutzen der Libarary"

  13. Hi daniel
    I have down loaded the library and put it in the same folder
    As i do not under stand C code how should call the library`s
    as the same errors as printed before
    thanks peter

  14. Hi Daniel
    As I do not need the uart.h library if you could tell me witch registers are used as I want to use a key board on the transmiter and ports on the reciver for output
    have I got this program write
    I have checked the folder and there is in it main rfm & rfm.h & uart +uart.h
    is it poseble to tell me what I am doing wrong
    thanks peter

    # include
    # include
    # include
    # include

    # include "uart.h"
    # include "rfm70.h"

    # define UART_BAUD_RATE 9600

    // PIN SET

    # define DDRB DDR_SPI
    # define PORTB PORT_SPI
    # define PB3 CE
    # define PB4 CSN
    # define SCK PB7
    # define MISO PB6
    # define MOSI PB5
    # define IRQ PD2

    int main ()
    {
    uint8_t test[20]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78,0x06,0x11,0x99};
    uint8_t buffer [ 32 ];

    is ();
    uart_init ( UART_BAUD_SELECT ( UART_BAUD_RATE , F_CPU ) );

    DDRA = ( 1 << PA4 );
    _delay_ms ( 1000 );
    uart_puts ( "System Ready \ n" );
    Begin ();

    setMode ( 0 );
    SetChannel ( 8 );

    while ( 1 )
    {
    sendPayload ( test , 20 , 0 );
    _delay_ms ( 20 );
    }
    }

    This is the error mesage

    Build started 14.4.2012 at 13:25:32
    avr-gcc -mmcu=atmega32 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT rfmm.o -MF dep/rfmm.o.d -c ../rfmm.c
    In file included from ../rfmm.c:7:
    c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:85:3: warning: #warning "F_CPU not defined for "
    ../rfmm.c:9:20: error: uart.h: No such file or directory
    ../rfmm.c:18:1: warning: "DDRB" redefined
    In file included from c:/winavr-20100110/lib/gcc/../../avr/include/avr/io.h:206,
    from ../rfmm.c:5:
    c:/winavr-20100110/lib/gcc/../../avr/include/avr/iom32.h:94:1: warning: this is the location of the previous definition
    ../rfmm.c:19:1: warning: "PORTB" redefined
    c:/winavr-20100110/lib/gcc/../../avr/include/avr/iom32.h:95:1: warning: this is the location of the previous definition
    ../rfmm.c:20:1: warning: "PB3" redefined
    c:/winavr-20100110/lib/gcc/../../avr/include/avr/iom32.h:464:1: warning: this is the location of the previous definition
    ../rfmm.c:21:1: warning: "PB4" redefined
    c:/winavr-20100110/lib/gcc/../../avr/include/avr/iom32.h:463:1: warning: this is the location of the previous definition
    ../rfmm.c: In function 'main':
    ../rfmm.c:32: warning: implicit declaration of function 'is'
    ../rfmm.c:33: warning: implicit declaration of function 'uart_init'
    ../rfmm.c:33: warning: implicit declaration of function 'UART_BAUD_SELECT'
    ../rfmm.c:37: warning: implicit declaration of function 'uart_puts'
    ../rfmm.c:37:14: warning: unknown escape sequence: '40'
    ../rfmm.c:41: warning: implicit declaration of function 'SetChannel'
    ../rfmm.c:30: warning: unused variable 'buffer'
    make: *** [rfmm.o] Error 1
    Build failed with 1 errors and 16 warnings...

  15. Hi Daniel
    Have down loaded the program and run it in avr studio4
    It compiles with no errors or warnings
    for the transmitter do I alter main.c program to

    setMode(0);
    // uint8_t test[20]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78,0x06,0x11,0x99};

    /* sendPayload(test,20, 0);
    _delay_ms(20);

    or is there more to alter
    thanks peter

    • you can find the code for the sender in the second long code-listing in the article above.

      first you need a payload, this is the example the array with the name "test".
      Then you need configure the modus. 0 for sending and 1 for receiving.

      in the last step you send the payload with the method sendPayload(test,20, 0);
      I recommend you, do this in a loop, wait a second, send ... and so on... then you can check with the receiver modul...

  16. Hi daniel
    Thank you for your help I will try this and let you know how I go on.
    Also the project board you have made says it runs on a atmega8
    would this program run on it.
    thanks peter

  17. Hi daniel
    Have loaded the first program into the first chip and it loaded ok
    but the second program has a error

    D:\rfm70_test\default/../main.c:21: undefined reference to `is'
    this is in line 16 is ();
    could you please help .
    thanks peter

  18. Hi Daniel
    this email is write not the one before typo error
    Have downloaded the first program into the first chip and it loaded ok
    but the second has a program error

    D: \ rfm70_test \ / default / main.c: 21:.. Undefined reference to `is'
    this is in line 15 is (),
    . could you please help
    thanks peter

    • Hi Peter,

      change the line is(); to sei();
      I think you have translate the website to english and google has translate the word sei() to is(), but this is wrong :)

  19. Hi daniel
    Have done what you said but still getting error
    is the program right
    thanks peter

    #include
    #include
    #include
    #include

    #include "uart.h"
    #include "rfm70.h"

    #define UART_BAUD_RATE 9600

    int main()
    {
    uint8_t test[20]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78,0x06,0x11,0x99};
    uint8_t *buffer [32];

    (),
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

    DDRA |= (1<<PA4);
    _delay_ms(1000);
    uart_puts("System Ready\n");
    Begin();

    setMode(0);
    setChannel(8);

    while (1)
    {

    sendPayload(test,20, 0);
    _delay_ms(20);

    }
    }

    ../main.c:21: error: expected expression before ')' token

  20. Hi danel
    you are correct about the translation .
    it alters sei(); to is();
    I have a question is the chips running from a crystal or internal oscillator.
    could you tell me if there is any LEDs for the transmitter or receiver to let me know when it is transmitting or receiving ?
    I do not need the uart so is it possible to run with out them .
    If so do I just remove any line with uart in them .
    thanks peter

  21. Hi Peter,
    sorry for the late answer but i had a lot of work this week.
    Yes there is a LED on PA4. After sending or receiving, you can toggle this led.
    If you don't need the uart, you can delete all lines which includes a uart operation.

  22. Hi Daniel
    Thank you for answering my questions I will build the circuits and test them and let you know .
    thanks peter

  23. Hallo,
    erstmal danke für die echt gute Lib.
    Habe 2 RFM70 am laufen, auto-ack geht auch.
    Ich verwende dazu einmal einen Atmega88 und einen Atmega8.
    Mein Problem ist die Reichweite. Mehr als 5m ohne Hindernisse geht einfach nicht.
    Momentan habe ich den Chip auf maximale Leistung gestellt.
    Die 2 Funk-Chips sollen am Ende eine ca. 20m im Gebäude entfernt stehende Pumpe steuern.
    An welchen Stellen in den Einstellungen kann man die Reichweite erhöhen?
    Gibt es Hardwareseitige Kniffe mit denen man die Reichweite erhöhen kann?

    Gruß, sven

    • Hallo Sven,

      die Reichweite wundert mich jetzt etwas. Habe bisher selber aus Zeitgründen noch keine Versuche dazu gemacht, werde ich versuchen diese Woche einmal in Angriff zu nehmen. Du hast mittels der Methode configRfPower(3); die Sendeleistung voll aufgedreht? Hast du das bei beiden Stationen gemacht?

      Sonst könnte man es mal mit einer externen Antenne versuchen, dazu müsste man nur die Platinenantennen "cuten" und dann sollte man theoretisch eine normale 2.4Ghz Antenne nutzen können, die man auch beim WLAN verwendet.

      Oder was auch noch sein kann, nutzt du evtl. einen Kanal auf dem bereits viel los ist? Versuch vielleicht einfach mal einen anderen Kanal.
      Das sind so die Dinge, die mir so auf Anhieb einfallen. Mehr gibt es dann Ende der Woche, wenn ich das bis dahin schaffe.

      Viele Grüße
      Daniel

      • Hallo,
        Danke für die Hilfreiche Antwort.
        Ich habe die Leistung mit Hilfe von "configRfPower(3);" schon auf voller Leistung stehen gehabt. Aber das mit den externen Antennen war wohl der richtige Ansatz.
        Am Sender hab ich im Moment noch eine selbstgebaute Collinear-Antenne und am Empfänger eine Biquad-Antenne. Freifeld komm ich auf ca. 35m, im Gebäude reicht es für meine Anwendung auch.
        Gruß, Sven

        • super freut mich, dass ich dir helfen konnte.
          Wie hast du die Antenne angeschlossen? einfach vor die Platinenantenne geschaltet?

  24. Hi Daniel
    Have now built and tested with and without uart and the led on the receiver doesn`t always go off .
    Is there a reason for this?.
    Also the uint8 receivePayload could you please tell me where it is stored is it in 000060 data address to 000073 ?
    thanks peter

  25. Hallo zusammen,

    vielen Dank für den regen Meinungsaustausch und die guten Ansätze.

    Mein Problem ist zum Verrücktwerden. Ich erhalte eine gute, stabile Datenverbindung zwischen zwei Arduinos via RMF70-S, ca. 9kbps. Wir die Verbindung unterbrochen durch Hindernisse, nimmt er bei Rückkehr in die Reichweite auch die Verbindung wieder auf.

    PROBLEM: Zum AUFBAU der Verbindung, also zum Sicherstellen, dass der Empfänger den Sender akzeptiert, müssen beide Arduinos über gemeinsame Masse & VCC (+5V) miteinander verbunden sein. Danach kann ich sie trennen und beide z.B. auf eigenen Batterien laufen lassen - bis zum Reset. Sobald Sender oder Empfänger ein Reset erfahren, findet der Empfänger den Sender nicht mehr. Dann müssen beide zu Beginn wieder an GND und VCC miteinander verbunden sein.

    Einstellungen:
    Einer sendet (kontinuierlich oder auch nur alle 500 ms - egal) ein Festlängenpaket (habe 4...32-bit ausprobiert, alles gleich) mit seiner Systemzeit (millis()). Der Empfänger nimmst sie an und quittiert. (und zeigt sie auf einem LCD an als Nachweis der Verbindung). Sende- und Emfpangsaktivität wird via LED auf jedem Board angezeigt. Mehr passiert hier nicht-

    Was kann das sein? Das Auslesen des CarrierDetect-Registers zeigt immer NUll, auch wenn nachweislich eine Verbindung zustande gekommen ist.

    • Hallo Thomas,

      wirklich eine seltsame Sache, ist mir so auch noch nicht unter gekommen.
      Ich selbst weiß da jetzt leider auch keine Lösung.

      Solltest du rausfinden woran es liegt, dann wäre ich an der Lösung sehr interessiert :)

      Gruß
      Daniel

  26. Natürlich werde ich berichten. Habe ersteinmal zwei neue Module bestellt, um zu prüfen, ob es einen "Hardwarefehler" gibt.

    Übrigens, ich kann sowohl GND als auch VCC vom Funkmodul RMF70 trennen. Die MISO/MOSI-Eingänge scheinen die Module immer noch zu speisen.
    Auch sehr merkwürdig.

    • HEUREKA!

      Manchmal kommt es auf die Zentimeter an.
      Die Flachbandkabel zwischen Arduino und RFM70 habe ich von 10 cm auf 1,5 cm gekürzt. Dann klappt es mit dem Erkennen zwischen Sender und Empfänger auch ohne GND-Verbindung sofort.
      Offenbar gab es zu viele Einkopplungen auf dem kurzen Weg.

      • glückwunsch :)
        bin derzeit auch wieder in der Testphase mit meinen Develeopment-Boards.
        Da hatte ich auch ein kleines Problem, die Module scheinen recht empfindlich zu sein, daher immer gut entstören ;)

  27. Hi Daniel ,
    here i am once again . After 3-4 month testing with your code on varoius Atmel x8 with different cpu clocking i must say it works fine for all my purposes.
    I have build a RFM70 network with routing possibilities to send my DS1820 measurements from the garden into my deep grounded "office".
    My "base" consists of a 328 with 4x20 LCD, SDCard,RFM70 and stores periodiacly the measurements of all devices on SD.
    The clients are "barebone" are 8 or 168,with uart for my Attinys Dev, RMF70, and DS1820. All clients can route packets from far away clients to the base.
    Works good with 4-5 Clients , more i havent tested.
    When the code is quite clean i wil send a download link....
    Thank you for your "kick" in RFM70 using.
    Rex

    • Hi Rex,

      that sounds quite good. I am very interested for the code. Is it possible to make a download link to you code in this article?
      What can you say about the range? I have a very bad range(max. 5 meters). Do you use an antenna? If so, how did you connect them?

      regards
      Daniel

  28. Hello Daniel ,
    i am sorry , but the project is still so dirty ( 50 compiler warnings) and in progress , bad or no documentation , no circuit layout for the different boards /addons. Its all "hot-glued". On the other side RFM70 is out of focus at this time, no time. When i will have a "public" viewable version , you will get it.

    The ranges are really quite poor , that are my distance( only internal antenna tested) :
    -from cellar room to outside device(massive outdoor wall) : 3m , 2 m in the Ground
    -indoor to outdoor ( big Windows ) 5-10 m
    -garden outdoor 10-15m (no direct view) 25m+ (direct view)
    -indoor 1-2 walls ,

    Because of the poor ranges i programmed a router functionality.
    Every "station" sends/forwared received packets to the Base Station.
    Its tested with :
    4 Clients(barebone/minimum curcuit+RS232,RFM70,DS1820) +
    1 Base(LCD4+20,SD-CARD,RFM70,RS232,DS1820)

    I use another pipe for this packets as for my standard command packets, pipes make the handling easier.
    My code is not good for power/burst transmission ( at this time ) because the included SD-CARD and DS1820 handling costs so much time. TODO9345
    At this time no IRQ Handling is included. I have tested it sometimes but at this time i use polling. TODO0012
    Perhaps i got the code clean in some weeks , but i have so much TODOS and so less time ...
    Greetings
    Rex

    * Meine Frau , Computer Noob , ist immer ganz irritiert das ich auf den Code anderer Leute so scharf bin. Vielleicht muss ich mal an meiner Aussprache etwas feilen.

    Für die ganz Harten und nur zur privaten Nutzung : "link entfernt, da Download defekt!" , etwas älteres aber "stabiles" ALPHA Release. Nicht meckern !! Motzen ! ;)
    Irgendwo ist auch ein minimum Eagle layout dabei, suchen. Ist ein ungecleantes Zip aus nem Projekt Ordner.

    • ok, sonst kannst du es mir auch einmal per Email schreiben, dann schaue ich mal über den Quellcode.

  29. Hallo,
    erstmal vielen Dank für den Code, hat mir sehr geholfen meine zwei RFM70 zum kommunizieren zu bringen. Ich hab allerdings im Moment Probleme beim verstehen des Codes bzw. das autoACK ans laufen zu bringen, evtl. kannst du mir an der Stelle weiterhelfen, da ich gerade ein wenig den Überblick bei den ganzen Registern verloren habe...
    Erstmal vorweg, was ich mir Vorstelle, vielleicht scheitert, es bereits daran, dass meine Vorstellung ganz falsch ist.
    Ich habe wie gesagt, zwei RFM70, einer an einem ATMega32(Sender) und einen an einem ATMega8(Empfänger). Mit deinem Codebeispiel von oben, läuft es wunderbar, also ohne ACK. Ich hätte jedoch gerne ACK für den Fall, dass kurzfristig z.B. durch einen Reset des Empfängers keine Datenpakete verloren gehen. Ich hab deinem Code entnommen, wenn ich "sendPayload(test,20, 0);" zu "sendPayload(test,20, 1);" ändere, dass dann ACK angefordert wird. Beim angucken des Codes hätte ich zwar eher auf "-1" getippt, aber egal, ich hab beides geteset.
    Mein Problem ist, dass wenn ich den Wert von "0" zu "1" bzw. "-1" ändere und dann einen Reset meines Empfängers durchführe, danach keine Daten empfangen werden, erst wenn ich auch beim Sender einen Reset mache fließen wieder Daten. Hab auch schon versucht die Register für Anzahl Re-Trans und Re-Trans Delay zu ändern, jedoch ohne Erfolg.
    Ich werde weiterhin versuchen, mich durch die Register zu schlagen, aber evtl. hast du einen schnellen Tipp, der mich ans Ziel bringt.

    Schönen Gruß und vielen Dank
    Marcel

    • Hallo Marcel,

      du hast Recht zum Senden mit einem ACK musst du die Variable toAck auf den Wert "-1" setzen, das ist im Quelltext falsch dokumentiert. Ist mir nicht aufgefallen, da ich das ACK noch nicht so richtig verwendet habe.

      Verstehe ich das richtig, dass nach einem Reset des Empfängers das Empfangen bzw. Senden mit eine ACK funktioniert?

      Ich habe das selber leider noch nicht getestet, daher kann ich dazu wenig sagen, werde das aber am Wochenende mal genauer anschauen. Wenn du vorher was rausfindest immer her damit :)

      Viele Grüße
      Daniel

      • Komando zurück, die "1" als Parameter war doch korrekt von dir im Quelltext kommentiert, die "-1" ist für den Fall, dass ich mit den ACK noch Daten zurücksenden will, aber das ist erstmal nicht wichtig.

        Also ich habe eine Kommunikation wenn ich erst den Empfänger starte und dann den Sender. Sprich ich hab das Gefühl, sobald der Sender kein ACK bekommt hängt sich dieser "auf". Bin leider heute nicht weiter gekommen, aber ich bleib dran und lass es dich wissen sollte ich es hinbekommen. Möglich sein muss es ja wenn man hier deine Kommentare liest, dann haben es wohl bereits schon Leute geschafft ;-)

        • hmm vielleicht kann man irgendwo noch das Timeout bestimmen wie lange der Sender auf ein ACK wartet. Man sollte ja eigentlich erwartet, dass im Fehlerfall der Sender die Daten nochmal sendet. Vielleicht tut er das auch?

          • Ja genau, die Anzahl der Retransmissions und das Retransmisson Delay kann ich einstellen. Ich habe das Gefühl, dass das Retransmission Register "voll" ist und deswegen gar kein Retransmission stattfindet.

          • So, ich hab heute und gestern noch ein wenig mich mit'm Debuggen versucht und mir die Register ausgeben lassen. Wie ich vermutet habe springt bei mir der ARC_CNT direkt auf 1111, sobald der Empfänger weg ist und ich bekomm auch durch das setzen des MAX_RT auf 0 den Sender wieder in den Sendezustand. Ich vermute, dass es wirklich nur ne Kleinigkeit ist, aber das ist schon sehr nervenaufreiben, wenn man diese Kleinigkeit eben nicht findet. Vielleicht sollte ich es die Tage einfach mal mit'm "frischen" Code versuchen, evtl. hab ich deinen Code verschlimmbessert. Falls du am WE dazu kommen solltest das ganze bei dir erfolgreich zu testen würde ich mich über eine Nachricht freuen ;-)

          • So, AutoACK läuft und das auch mit deinem Code. Es lag mit unter an dem MAX_RT Interrupt. Ich bin gerade dabei das ganze auf Interrupt umzubauen um vom polling weg zu kommen.
            Wenn Interesse besteht kann ich gerne meinen Code dafür zeigen, ist im wesentlichen nicht viel, aber für jemanden der das gleiche Problem hat könnte es evtl. hilfreich sein.

          • Hallo Marcel,
            ja ich denke, alles was anderen dabei hilfreich sein kann ist wichtig. Kannst du ja einfach als Kommentar posten.
            Sorry, dass ich mich nicht mehr gemeldet hatte aber ich war leider nicht dazu gekommen, zeitlich sieht es bei mir momentan sehr eng aus.
            Aber super, dass es jetzt läuft :)

  30. Hat schon jemand geschafft, das ganze mit zwei Atmega168PA zu laufen zu kriegen?
    Bei mir klappt das einfach nicht :(

    Viele Grüße,
    Michael

    • Hallo Michael,

      eigentlich sollte das mit allen Atmel Controller funktionieren, vorausgesetzt es ist ein SPI an Board.
      Hast du evtl. die Pin Konfiguration nicht richtig eingestellt? Was genau klappt denn nicht?

      Gruß
      Daniel

      • Hi Daniel,

        ich habs zum laufen gekriegt, aber ich hab' keine Ahnung was das Problem war... seltsame Sache das ganze, aber jetzt klappt alles wunderbar :)

        Aber eine Sache, die ich nicht verstehe...
        Die Bitreihenfolge bei der Initialisierung der Registerbank 1 ist teilweise genau umgekehrt:
        Im Datenblatt steht "00 / 31:0 / 0 / W / Must write with 0x404B01E2" - initialisiert wird mit "{ (0x20|0x00), 0x40, 0x4B, 0x01, 0xE2 }". ABER Datenblatt: "0C / 31:0 / 0 / Please initialize with 0x00731200" - und initialisiert wird mit "{ (0x20|0x0C), 0x00, 0x12, 0x73, 0x00 }".

        Warum? Ich muss dazu sagen, ich bin noch blutiger Anfänger in Sachen µC, aber das kommt mir etwas seltsam vor...

        Danke schonmal!

        Viele Grüße,
        Michael

        • Hallo Michael,
          na das sind doch erfreuliche Neuigkeiten. Leider muss ich gestehen, dass ich nicht mehr all zu tief in der Thematik drin bin, ich habe die Registerinitialisierungen damals direkt von der C++ Library auf der meine basiert übernommen ohne erstmal groß zu hinterfragen. Es kann natürlich sein, dass hier etwas anderes initialisiert wird als im Standard vorgegeben. Wenn alles funktioniert nehme ich auch schonmal Dinge als gegeben hin, da man sich sonst schnell im Detail verliert :)

          Viele Grüße
          Daniel

  31. So, ich hab noch mit kleinen "timing" Problemen zu kämpfen, weshalb ich noch keinen Quellcode zu dem ACK online gestellt hab. Ich habe meine Sourcen auf mikrocontroller.net hochgeladen und hoffe dort auf Hilfe für mein Problem. Dort kannst du dir auch gerne meinen bisherigen Code angucken. Hab versucht soviel wie möglich zu kommentieren, damit es leicht verständlich ist.

    http://www.mikrocontroller.net/topic/273117

    Grüße
    Marcel

  32. Hallo Daniel,
    tolle Arbeit ! Ich versuche seit Tagen das auf einen mega8 zu bekommen.
    Leider nicht ganz erfolgreich. Ich habe die Port und das SPI angepasst.
    Obwohl ich auf der Console vom Sende und Empfänger
    die Meldung bekomme das alle Register erfolgreich geladen sind und am Sender die LED Blinkt, kommt auder anderen Seite nichts an.
    Hast du zufällig den Code mal auf einem Mega8 oder Mega88 laufen gehabt ?
    Vielen Dank und Gruß
    Stefan

    • Hallo Stefan,

      vielen Dank.
      Hast du Empfänger und Sender auf dem selben Kanal liegen? Sind andere Störeinflüsse bspw. WLAN ausgeschlossen?

      Gruß
      Daniel

      • Hallo Daniel,

        erstmal vielen Dank für deinen Tip.
        Ich habe es gerade einfach noch einmal probiert und es geht.
        Also habe ich mich auf die Suche gemacht was im Haus heute morgen anderes ist als gestern ?
        Es war tatsächlich ein Störenfried un Form eines 434Mhz Sender in einer Lampe, obwohl der ganz wo anders ist, ist es reproduzierbar. Lampe an, und es geht nicht mehr.

        Vielen Dank für deine Hilfe

        Grüße
        Stefan

        • Hallo Stefan,

          super freut mich, dass es geklappt hat. Das ist leider ein recht großer Nachteil an dem Modul.
          Es ist sehr empfindlich gegen äußere Störeinflüsse, versuch doch mal auf einen anderen Kanal zu funken, evtl. schafft das schon Abhilfe.

          Gruß
          Daniel

  33. Hallo Daniel,

    erst mal Danke für die Lib. verwende sie mit ein paar Atmega 169. Das einfügen in mein Projekt ging auch ohne Probleme und hat mir sehr geholfen den RFM70 ein wenig zu verstehen, ist bis jetzt noch Neuland für mich. Leider tun sich bei mir noch ein paar Fragen auf, die ich hier mal fragen wollte da ich denke dass es denn einen oder anderen auch interessieren könnte.
    Verständnis Frage: Beim RFM70 ist die Rede von 6 Daten Pipe's mit je einer eigenen Addresse. Was kann man sich da drunter vorstellen, und wofür ist dies? soweit ich gesehen habe sind sie alle eingeschaltet.

    Lib. Frage: Ich habe Schwierigkeiten einen Funk Dialog hinzubekommen, meine Versuche z.B.:
    if (Taster)
    {
    setMode(0); //Sender
    sendPayload(test,30, 1);
    setMode(1); //empfänger
    }

    if (receivePayload(buffer))
    {
    uart_puts((char*)buffer);
    uart_puts("\n");
    }
    funktionier leider nicht, wie habt Ihr das gelöst?

    Soweit erst mal vielen Dank und einen schönen Abend.
    gruß
    Matthias

    • Ok,
      die Frage zu denn Pipes habe ich glaube ich verstanden. So kann man einen Empänger von 6 verschiedenen Sendern mit je einer Addresse ansprechen ohne das man am Empänger das register ändern muss da jeder sender einer anderen Pipe des Empängers nutzt je seine addresse entsprechend.
      Bleibt noch die zweite Frage wie man hin und her funkt.

      gruß
      Matthias

      • Hallo Matthias,

        ich kann mir vorstellen, dass das Modul eine gewisse Zeit benötigt, um zwischen den einzelnen Modi hin- und herzuschalten.
        Daher teste bitte einmal, ob es schon klappt wenn du nach jedem Modus Wechsel ein paar ms wartest. Evtl. steht im Datenblatt wie lange genau das Umschalten dauert.

        Viele Grüße
        Daniel

        • Hallo Daniel,
          dass hatte ich schon Probiert, leider auch ohne erfolg. Bekomme aber Morgen noch ein Jtag MKII und kann so beide Seiten auf einmal genauer unter die Lupe nehmen und dann auch nochmal hier und da mit der Zeit Spielen, melde mich dann wieder.

          gruß
          Matthias

          • Hallo Daniel,
            also mit der Zeit hat es auch nichts zu tun.
            Mein Empfänger empfängt jedes gesendete Packet, sobald ich aber einmal nach setMode(0); //Sender und wieder zurück auf setMode(1); //empfänger schalte ( auch ohne ein sendPayload(test,20, 0); auszuführen) empfängt der empfänger nichts mehr. PRIM_RX wird immer richtig geschrieben, ich denke mal das der RMF70 noch auf irgendwas wartet um von TX auf RX zu schalten.
            Probiert habe ich auch schon die Auto ACK geschichten auszuschalten, also EN_AA aus und unter FEATURE den EN_ACK_PAY aus. Aber ohne erfolg.
            Hast du noch nee Idee?

            gruß
            Matthias

          • Hallo Matthias,

            hmm ich bin da momentan leider etwas raus aus dem Thema, daher fällt mir so spontan auch nicht mehr ein woran es noch liegen könnte. Sry

            Gruß
            Daniel

  34. Hallo Daniel,

    hast du schon mal versucht ein Byte mit Inhalt 0 zu übertragen.
    Wenn ich in die zu sendene Byte Kette ein Byte mit dem Wert '0' setzte ist ab der o der Rest abgeschnitten. Testaufbau ist beide Seiten am PC , Komplett deine Source
    auf Mega8, ich tausche lediglich aus der test Sende Byte Kette eins gegen 0x00 aus.

    Hast du eine Idee ?

    Viele Grüße
    Stefan

    • Hallo Daniel,

      habs gefunden die Funktion uart_puts sieht den String als beendet an wenn eine '0' kommt, hab das umgebaut nach uart_putc und das geht.
      Sorry für die Frage ich bin in C nicht fit, mache alles in Assembler.

      Gruüße

      Stefan

      • Hallo Stefan,

        kein Problem, vielleicht hat ja noch jemand das gleiche Problem, dann ist ihm auch mit deinem Post geholfen :)

        Weiterhin viel Erfolg beim Basteln.

        Gruß
        Daniel

  35. Hello Daniel,
    I use RFM70 for transfer 1byte (PWM signal). Then this signal is written in register timer.
    In transmit side

    uint8_t UART_Buff;
    setMode(0);
    ...
    sendPayload(UART_Buff,1, 0);

    In receive side

    uint8_t *buffer;
    setMode(1);
    ...
    i=receivePayload(buffer);
    if (i == 1) OCR0=*buffer;

    But receiver receive not something that is transmitted. For example, transmited 0x05 but receive 0x91. And it is all time. It doesn't depend from air lane lenght, controller's restart and etc. Do you have any ideas?

    • try this:
      // declare the buffer as an array with size 1
      uint8_t UART_Buff[1]={0x05};

      maybe it helps, otherwise I have no idea at the moment. Sorry

      many greetings
      Daniel

      • With this code it is word

        uint8_t UART_Buff;
        uint8_t *buffer=&UART_Buff;
        ...
        sendPayload(buffer,1, 0);

        Thank you, Daniel

  36. Hallo Daniel, aus Russland!

    Danke für die ausführliche Anleitung. Es war sehr schnell und einfach einzurichten Kommunikation.

    Entschuldigung für die google translate ..

  37. Hallo Daniel,

    ersteinmal ein großes Lob an deine Library, welche mir sehr geholfen hat!
    Nun würde ich allerdings gerne einen Attiny2313 nutzen, welcher ja keinen
    Hardwarespi hat...ein Austausch der Befehle funktionierte nicht...
    Wäre schön wenn du mir da helfen könntest! :-)

    mfg
    Robin

    • Hallo Robin,

      leider direkt helfen kann ich dir da nicht, da ich noch keinen Software SPI programmiert habe.
      Aber theoretisch sollte das Ganze auch per Software SPI funktionieren.

      Was meinst du mit austauschen der Befehle? Wie genau hast du den SPI in Software implementiert?

      Viele Grüße
      Daniel

  38. Hallo Daniel,

    Ich habe ein Problem, dein Code funktioniert auf dem Atmega32L super, leider kriege ich den nicht auf einem AtXmega trotz änderungen ans laufen, hast du evtl. eine Ahnung warum ich eine falsche Chip ID zurück bekomme ? :)

    Der Code:

    /*
    Diese Library bassiert auf der Arduino RFM70 Library, ich habe sie lediglich so
    angepasst, dass man sie auf einem AVR und ohne zusätzliche Libs von Arduino
    verwenden kann.

    Es sind nur die wichtigstens Funktionen implementiert!
    Bei Fragen oder Anregungen:
    Mein Blog: http:://projects.web4clans.com
    Meine Email: daniel.weber@web4clans.com

    */

    #include "rfm70.h"
    #include "display/Graphics.h"
    #include "display/display_lib.h"
    ///////////////////////////////////////////////////////////////////////////////
    // Register initialization values and command macros //
    ///////////////////////////////////////////////////////////////////////////////

    //************ Address definition commands
    const uint8_t PROGMEM RFM70_cmd_adrRX0[] = { (0x20|0x0A), 0x34,0x43,0x10,0x10,0x01};
    const uint8_t PROGMEM RFM70_cmd_adrTX[] = { (0x20|0x10), 0x34,0x43,0x10,0x10,0x01};
    const uint8_t PROGMEM RFM70_cmd_adrRX1[] = { (0x20|0x0B), 0x35,0x43,0x10,0x10,0x02};

    //************ Bank0 register initialization commands
    const uint8_t PROGMEM RFM70_bank0Init[][2] = {
    // address data
    { (0x20|0x00), 0x0F }, //Disable CRC ,CRC=1byte, POWER UP, TX
    { (0x20|0x01), 0x3F }, //Enable auto acknowledgement data pipe0-5
    { (0x20|0x02), 0x3F }, //Enable RX Addresses pipe0-5
    { (0x20|0x03), 0x03 }, //RX/TX address field width 5byte
    { (0x20|0x04), 0x08 }, //x = 250 ms = 4000ms, y = 15 tries
    { (0x20|0x05), 0x17 }, //channel = 0x17
    { (0x20|0x06), 0x3F }, //air data rate-2M,out power 5dbm,setup LNA gain high (0dBM)
    { (0x20|0x07), 0x07 }, //
    { (0x20|0x08), 0x00 }, //
    { (0x20|0x09), 0x00 }, //
    { (0x20|0x0C), 0xc3 }, //LSB Addr pipe 2
    { (0x20|0x0D), 0xc4 }, //LSB Addr pipe 3
    { (0x20|0x0E), 0xc5 }, //LSB Addr pipe 4
    { (0x20|0x0F), 0xc6 }, //LSB Addr pipe 5
    { (0x20|0x11), 0x20 }, //Payload len pipe0
    { (0x20|0x12), 0x20 }, //Payload len pipe0
    { (0x20|0x13), 0x20 }, //Payload len pipe0
    { (0x20|0x14), 0x20 }, //Payload len pipe0
    { (0x20|0x15), 0x20 }, //Payload len pipe0
    { (0x20|0x16), 0x20 }, //Payload len pipe0
    { (0x20|0x17), 0x20 }, //Payload len pipe0
    { (0x20|0x1C), 0x3F }, //Enable dynamic payload legth data pipe0-5
    { (0x20|0x1D), 0x07 } //Enables Dynamic Payload Length,Enables Payload with ACK
    };

    //************ Bank1 register initialization commands
    const uint8_t PROGMEM RFM70_bank1Init[][5] = {
    // address data
    { (0x20|0x00), 0x40, 0x4B, 0x01, 0xE2 },
    { (0x20|0x01), 0xC0, 0x4B, 0x00, 0x00 },
    { (0x20|0x02), 0xD0, 0xFC, 0x8C, 0x02 },
    { (0x20|0x03), 0x99, 0x00, 0x39, 0x41 },
    { (0x20|0x04), 0xb9, 0x9E, 0x86, 0x0B }, // b9? f9?
    { (0x20|0x05), 0x24, 0x06, 0x7F, 0xA6 },
    { (0x20|0x06), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x07), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x08), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x09), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x0a), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x0b), 0x00, 0x00, 0x00, 0x00 },
    { (0x20|0x0C), 0x00, 0x12, 0x73, 0x00 },
    { (0x20|0x0D), 0x36, 0xb4, 0x80, 0x00 }
    };

    //************ Bank1 register 14 initialization commands
    const uint8_t PROGMEM RFM70_bank1R0EInit[] = {
    // address Data...
    (0x20|0x0E), 0x41,0x20,0x08,0x04,0x81,0x20,0xCF,0xF7,0xFE,0xFF,0xFF
    };

    //************ other commands: { , , ... }
    const uint8_t PROGMEM RFM70_cmd_switch_cfg[] = { 0x50, 0x53 }; // switch Register Bank
    const uint8_t PROGMEM RFM70_cmd_flush_rx[] = { 0xe2, 0x00 }; // flush RX FIFO
    const uint8_t PROGMEM RFM70_cmd_flush_tx[] = { 0xe1, 0x00 }; // flush TX FIFO
    const uint8_t PROGMEM RFM70_cmd_activate[] = { 0x50, 0x73 }; // Activation command
    const uint8_t PROGMEM RFM70_cmd_tog1[]={ (0x20|0x04), 0xd9 | 0x06, 0x9e, 0x86, 0x0b }; //assosciated with set1[4]!
    const uint8_t PROGMEM RFM70_cmd_tog2[]={ (0x20|0x04), 0xd9 & ~0x06, 0x9e, 0x86, 0x0b}; //assosciated with set1[4]!

    void initSPI(uint8_t clk_div)
    {
    // set the pin direction to output
    PORTC.DIRSET = (1<<SCK) | (1<<MOSI) | (1<<CSN); // Ausgang
    PORTC.OUTCLR = (1<<MOSI)|(1<<SCK); // Set to Low

    // chip select to high
    PORTC.OUTSET = (1<<CSN);

    SPIC.CTRL = SPI_PRESCALER_DIV4_gc | SPI_MODE_0_gc | SPI_MODE_1_gc| (1<<SPI_ENABLE_bp) | (1<<SPI_MASTER_bp);
    SPIC.INTCTRL = SPI_INTLVL_OFF_gc;
    // other to low

    _delay_ms(RFM70_BEGIN_INIT_WAIT_MS);
    initRegisters();
    }

    void initHardware(uint8_t irq)
    {
    // set the CE ddr to output
    PORTC.DIRSET = (1<<CE);

    //DDR_SPI |= CE;
    // and set it to low
    //PORT_SPI &=~CE;
    PORTC.OUTCLR = (1<<CE);

    if (irq != -1)
    PORTC.DIR &=~ (1<<IRQ);

    }

    void initRegisters(void)
    {
    // init bank 0 registers
    selectBank(0);

    for (int i = 0; i < 20; i++)
    writeRegVal(pgm_read_byte(&RFM70_bank0Init[i][0]), pgm_read_byte(&RFM70_bank0Init[i][1]));

    // init address registers in bank 0
    writeRegPgmBuf((uint8_t *)RFM70_cmd_adrRX0, sizeof(RFM70_cmd_adrRX0));
    writeRegPgmBuf((uint8_t *)RFM70_cmd_adrRX1, sizeof(RFM70_cmd_adrRX1));
    writeRegPgmBuf((uint8_t *)RFM70_cmd_adrTX, sizeof(RFM70_cmd_adrTX));

    // activate Feature register
    if(!readRegVal(RFM70_REG_FEATURE))
    writeRegPgmBuf((uint8_t *)RFM70_cmd_activate, sizeof(RFM70_cmd_activate));

    // now set Registers 1D and 1C
    writeRegVal(pgm_read_byte(&RFM70_bank0Init[22][0]), pgm_read_byte(&RFM70_bank0Init[22][1]));
    writeRegVal(pgm_read_byte(&RFM70_bank0Init[21][0]), pgm_read_byte(&RFM70_bank0Init[21][1]));

    // init bank 1 registers
    selectBank(1);

    for (int i=0; i < 14; i++)
    writeRegPgmBuf((uint8_t *)RFM70_bank1Init[i], sizeof(RFM70_bank1Init[i]));

    // set ramp curve
    writeRegPgmBuf((uint8_t *)RFM70_bank1R0EInit, sizeof(RFM70_bank1R0EInit));

    // do we have to toggle some bits here like in the example code?
    writeRegPgmBuf((uint8_t *)RFM70_cmd_tog1, sizeof(RFM70_cmd_tog1));
    writeRegPgmBuf((uint8_t *)RFM70_cmd_tog2, sizeof(RFM70_cmd_tog2));

    _delay_ms(RFM70_END_INIT_WAIT_MS);

    //Check the ChipID
    if (readRegVal(0x08) != 0x63)
    debug(RFM70_DEBUG_WRONG_CHIP_ID);
    else
    ScrollText("load rfm70 register successful\n", to_rgb565(255,255,255));

    selectBank(0);
    setModeRX();
    }

    void Begin(void)
    {
    setBegin(-1, RFM77_DEFAULT_SPI_CLOCK_DIV);
    }

    void setBegin(uint8_t irq, uint8_t clk_div)
    {
    initHardware(irq);
    initSPI(clk_div);
    //_delay_ms(RFM70_BEGIN_INIT_WAIT_MS);
    //initRegisters();
    }

    uint8_t transmitSPI(uint8_t val)
    {
    SPIC.DATA = val;
    while (!(SPIC.STATUS & (1<<SPI_IF_bp)))
    ;
    return SPIC.DATA;
    }

    void selectBank(uint8_t bank)
    {
    uint8_t tmp = readRegVal(0x07) & 0x80;
    if(bank)
    {
    if(!tmp)
    writeRegPgmBuf((uint8_t *)RFM70_cmd_switch_cfg, sizeof(RFM70_cmd_switch_cfg));
    }
    else
    {
    if(tmp)
    writeRegPgmBuf((uint8_t *)RFM70_cmd_switch_cfg, sizeof(RFM70_cmd_switch_cfg));
    }
    }

    void setMode(uint8_t mode)
    {
    if (mode == 1)
    setModeRX();
    else
    setModeTX();
    }

    void setModeRX(void)
    {
    uint8_t val;

    writeRegPgmBuf((uint8_t *)RFM70_cmd_flush_rx, sizeof(RFM70_cmd_flush_rx)); // Flush RX FIFO
    val = readRegVal(RFM70_REG_STATUS); // Read Status
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_STATUS, val); // Reset IRQ bits
    PORT_SPI &=~ (1<<CE); // RFM chip disable
    // set PRIM_RX bit to 1
    val=readRegVal(RFM70_REG_CONFIG);
    val |= RFM70_PIN_PRIM_RX;
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_CONFIG, val);
    PORT_SPI |= (1<<CE); // RFM chip enable
    }

    void setModeTX(void)
    {
    uint8_t val;

    writeRegPgmBuf((uint8_t *)RFM70_cmd_flush_tx, sizeof(RFM70_cmd_flush_tx)); // Flush TX FIFO
    PORT_SPI &=~ (1<<CE); // disable rfm70
    // set PRIM_RX bit to 0
    val=readRegVal(RFM70_REG_CONFIG);
    val &= ~RFM70_PIN_PRIM_RX;
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_CONFIG, val);
    PORT_SPI |= (1< 32 || nr > 5 || en_aa > 1)
    return 0;

    // write address
    if(nr<2) // full length for rx pipe 0 an 1
    writeRegCmdBuf(RFM70_CMD_WRITE_REG | (RFM70_REG_RX_ADDR_P0 + nr), adr, sizeof(adr));
    else // only LSB for pipes 2..5
    writeRegVal(RFM70_CMD_WRITE_REG | (RFM70_REG_RX_ADDR_P0 + nr), adr[0]); //ODO:check this

    // static
    if (plLen) {
    // set payload len
    writeRegVal(RFM70_CMD_WRITE_REG | (RFM70_REG_RX_PW_P0 + nr), plLen);
    // set EN_AA bit
    tmp = readRegVal(RFM70_REG_EN_AA);
    if (en_aa)
    tmp |= 1 << nr;
    else
    tmp &= ~(1 << nr);
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_EN_AA, tmp);
    // clear DPL bit
    tmp = readRegVal(RFM70_REG_DYNPD);
    tmp &= ~(1 << nr);
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_DYNPD, tmp);
    // set Enable pipe bit
    enableRxPipe(nr);
    }
    // dynamic
    else
    {
    // set payload len to default
    writeRegVal(RFM70_CMD_WRITE_REG | (RFM70_REG_RX_PW_P0 + nr), 0x20);
    // set EN_AA bit
    tmp = readRegVal(RFM70_REG_EN_AA);
    tmp |= 1 << nr;
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_EN_AA, tmp);
    // set DPL bit
    tmp = readRegVal(RFM70_REG_DYNPD);
    tmp |= 1 < 5) return;
    uint8_t tmp;
    // set Enable pipe bit
    tmp = readRegVal(RFM70_REG_EN_RXADDR);
    tmp |= 1 < 5) return;
    uint8_t tmp;
    // set Enable pipe bit
    tmp = readRegVal(RFM70_REG_EN_RXADDR);
    tmp &= ~(1 << nr);
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_EN_RXADDR, tmp);

    }

    void configTxPipe(uint8_t * adr, uint8_t pltype)
    {
    // write TX address
    writeRegCmdBuf(RFM70_CMD_WRITE_REG | RFM70_REG_TX_ADDR, adr, sizeof(adr));
    // write RX0 address
    writeRegCmdBuf(RFM70_CMD_WRITE_REG | RFM70_REG_RX_ADDR_P0, adr, sizeof(adr));
    // set static or dynamic payload
    uint8_t tmp;
    tmp = readRegVal(RFM70_REG_DYNPD);
    if(pltype == TX_DPL) // dynamic
    tmp |= 1;
    else
    tmp &= ~(1 << 0);
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_DYNPD, tmp);
    }

    uint8_t sendPayload(uint8_t * payload, uint8_t len, uint8_t toAck) // choose 0=nAck, 1=AckRequest
    {

    // check TX_FIFO
    uint8_t status;
    status = readRegVal(RFM70_REG_FIFO_STATUS);
    if (status & RFM70_FIFO_STATUS_TX_FULL)
    {
    debug(RFM70_DEBUG_FIFO_FULL);
    return 0;
    }

    // send payload
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    if(toAck == -1)
    transmitSPI(RFM70_CMD_W_ACK_PAYLOAD);
    else if (toAck == 0)
    transmitSPI(RFM70_CMD_W_TX_PAYLOAD_NOACK);
    else
    transmitSPI(RFM70_CMD_WR_TX_PLOAD);
    while(len--)
    {
    transmitSPI(*(payload++));
    //ScrollText(*payload, to_rgb565(255,255,255));
    }
    PORTC.OUTSET = (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    //PORTA ^= (1<<PA4);
    return 1;
    }

    uint8_t receivePayload(uint8_t *payload)
    {
    uint8_t len;
    // check RX_FIFO
    uint8_t status;
    status = readRegVal(RFM70_REG_STATUS);
    if (status & RFM70_IRQ_STATUS_RX_DR) { // RX_DR
    //PORTA ^= (1<<PA4);
    //while(1) {
    uint8_t fifo_sta;
    len = readRegVal(RFM70_CMD_RX_PL_WID); // Payload width
    readRegBuf(RFM70_CMD_RD_RX_PLOAD, payload, len);
    fifo_sta = readRegVal(RFM70_REG_FIFO_STATUS);
    //if (fifo_sta & RFM70_FIFO_STATUS_RX_EMPTY) break; // read until RX_FIFO empty
    //}

    if (fifo_sta & RFM70_FIFO_STATUS_RX_EMPTY) {
    status|= 0x40 & 0xCF; // clear status bit rx_dr
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_STATUS, status);
    }
    return len;
    }
    else
    {

    return 0;
    }
    }

    void flushTxFIFO()
    {
    writeRegPgmBuf((uint8_t *)RFM70_cmd_flush_tx, sizeof(RFM70_cmd_flush_tx)); // Flush TX FIFO
    }

    void flushRxFIFO()
    {
    writeRegPgmBuf((uint8_t *)RFM70_cmd_flush_rx, sizeof(RFM70_cmd_flush_rx)); // Flush RX FIFO
    }

    uint8_t readRegVal(uint8_t cmd)
    {
    uint8_t res;
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);

    transmitSPI(cmd);

    res=transmitSPI(0);
    PORTC.OUTSET = (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    return res;
    }

    uint8_t writeRegVal(uint8_t cmd, uint8_t val)
    {
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    transmitSPI(cmd);
    transmitSPI(val);
    PORTC.OUTSET = (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    return 1;
    }

    void readRegBuf(uint8_t reg, uint8_t * buf, uint8_t len)
    {
    uint8_t status, byte_ctr;
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    status = transmitSPI(reg); // Select register to write, and read status UINT8
    for(byte_ctr = 0; byte_ctr < len; byte_ctr++)
    buf[byte_ctr] = transmitSPI(0); // Perform SPI_RW to read UINT8 from RFM70
    PORTC.OUTSET = (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    }

    uint8_t writeRegPgmBuf(uint8_t * cmdbuf, uint8_t len)
    {
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    while(len--) {
    transmitSPI(pgm_read_byte(cmdbuf++));
    }
    PORTC.OUTSET = (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    return 1;
    }

    uint8_t writeRegCmdBuf(uint8_t cmd, uint8_t * buf, uint8_t len)
    {
    PORTC.DIRSET &=~ (1<<CSN);
    _delay_ms(RFM70_CS_DELAY);
    transmitSPI(cmd);
    while(len--)
    {
    transmitSPI(*(buf++));
    }
    PORTC.OUTSET = (1< 3) return;
    uint8_t tmp = readRegVal(RFM70_REG_RF_SETUP);
    tmp &= 0xF9;
    tmp |= pwr <> 2) & SPI_2XCLOCK_MASK);
    }

    • Hallo,

      nein leider so auf den ersten Blick nicht. Evtl. liegt der Fehler schon beim Anschließen des Moduls an den Controller?
      Was genau kommt denn bei der Chip ID zurück?

      Gruß
      Daniel

  39. Hallo Daniel,

    Habe den Code nun auf einem xMega am laufen, das Problem lag hier am setzen der Port-Directions, die wurden durch die xMega befehle und falsche nutzung von mir wieder gelöscht, funktioniert wunderbar.

    Nun habe ich aber eine spezielle Frage, ich habe ja bereits 3 RFM Module am laufen (3 Sender/Empfänger, + 1 Station zur Kommunikation)

    Nun möchte ich weiter 4 Module (3 Clients) inkl. 1 Station hier aufbauen, möchte aber jedoch das die 3 Clients und die Station einen eigenen Adressbereich bekommen. Was müsste Ich ändern, das die neuen 3 Clients auf eine bestimmte RFM Adresse senden und die Station auch nur von dieser Adresse die gesendeten Daten ließt ohne das er die Daten von den bereits bestehenden Modulen empfängt? :)

    Liebe grüße,
    Daniel

    • Hallo Daniel S.
      Kannst du dich per Mail bei mir melden? Ich will das rfm70 auch an einem Atxmega laufen lassen und hab arge Probleme. Es wäre super, wenn du mir helfen könntest.

      Beste Grüße,
      Markus

  40. Hallo!

    Ich verstehe nicht ganz, warum das RX_DR bit zum löschen mit einer 0 überschrieben, anstatt wie im Datenblatt angegeben mit einer 1 gelöscht wird.
    Vielleicht kann da ja jemand ein bisschen Klarheit schaffen :-) Danke!

    if (fifo_sta & RFM70_FIFO_STATUS_RX_EMPTY) {
    status|= 0x40 & 0xCF; // clear status bit rx_dr
    writeRegVal(RFM70_CMD_WRITE_REG | RFM70_REG_STATUS, status);

  41. Okay, ich hab das ganze jetzt selber mal ausprobiert. Das 0xCF löscht die anderen Bits TX_DS und MAX_RT, dass diese nicht auch zurückgesetzt werden.
    Eigentlich müsste es dann aber "status = (status | 0x40) & 0xCF;" heißen weil AND eine höhere Priorität hat als OR.

  42. Hallo Daniel,

    Ersteinmal danke, dass du die Lib hier zur Verfügung stellst!

    Ich habe allerdings noch nicht so ganz durchschaut, wie ich eine
    Rückmeldung vom Funkmodul erhalten kann, ob die Übertragung
    funktioniert hat, bei verwendung von Autoacknowledge.
    Und wo und wie, kann ich die einstellungen vornehmen, wie oft das Funkmodul
    einen resend durchführen soll etc.?

    Kannst du mir da weiterhelfen?

    Grüße
    Robin

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*


8 + = sechszehn

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>