PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Gepuffertes Senden mit RFM12



Sauerbruch
27.02.2010, 14:46
Ich habe gerade eine funktionierende Funkübertragungsstrecke mit 2 RFM12 aufgebaut. Im FSK-Modus funktioniert alles bestens, ein Rechteck-Tetsignal wird einwandfrei übertragen.

Jetzt taste ich mich langsam an den Sendepuffer heran. Unklar ist trotz intensiven Studiums des Datenblattes und anderer Quellen folgende Frage:

Wenn ich per SPI mehrere Nutzbytes in den Puffer schieben möchte, muss ich dann vor jedem Byte die Sequenz &B10111000 (Transmitter Register Write Command) übertragen, oder reicht &B10111000 einmalig, gefolgt von den Nutzbytes?

Ich habe beides versucht, aber seltsamerweise bleibt der nIRQ-Pin andauernd auf 0. Irgendwann muss der Sendepuffer aber doch auch mal "satt" sein, oder? Ich habe extra eine sehr langsame Übertragungsrate gewählt (0,6 kbps), damit die SPI-Übertragung garantiert schneller geht als das "absenden" der Bytes.

Bin für Tips jeder Art dankbar!!

Jaecko
27.02.2010, 15:51
Es muss zu jedem zu übertragenden Byte das Kommando 0xB8 vorher geschickt werden. Sonst weiss das RFM ja nicht, was es mit dem Byte tun soll.

Sauerbruch
27.02.2010, 19:47
Okay, das hatte ich vermutet, war mir aber nicht sicher. Trotzdem funktioniert irgendetwas an meinem Code nicht richtig, und ich weiß nicht was... Das Ganze soll einfach nur permanent das "Nutzbyte" 0xAA übertragen - das ist alles. nIRQ des RFM12 geht hierzu an INT0.

Hier ist mal der Code:


$regfile = "m8def.dat"
$crystal = 1000000

Ddrb.1 = 1
Portb.1 = 1
Led Alias Portb.1

Portd.2 = 1 'PullUp für INT0

Config Int0 = Falling
On Int0 Tx_ready
Enable Int0
Enable Interrupts

Config Spi = Soft , Din = Portc.5 , Dout = Portc.2 , Clock = Portc.3 , Ss = Portc.4
Spiinit

Dim A(12) As Byte
Dim Flag As Bit
Flag = 1

Waitms 100 '"Aufwärmpause" für RFM12

A(1) = &B10000000 '1.: Configuration Setting Command
A(2) = &B10010000

A(3) = &B10000010 '2.: Power Management Command
A(4) = &B00111000

A(5) = &B10100110 '3.: Frequency Setting Command (434,000 MHz)
A(6) = &B01000000

A(7) = &B10011000 '10.: TX Configuration Control Command
A(8) = &B00000111 ' -21dB Sendeleistung, Hub = 15 kHz

A(9) = &B11000110 '4.: Data rate command (0,6 kbps)
A(10) = &B10111111

A(11) = &B10111000 '11.:Transmitter Register Write Command
A(12) = &B10101010 '"Nutzbyte"

Spiout A(1) , 10

Do

If Flag = 1 Then
Spiout A(11) , 2 'Daten an Puffer übertragen
Spiout A(11) , 2
Flag = 0
End If

Loop


Tx_ready:
Toggle Portb.1
Flag = 1
Return



Das Modul geht korrekt auf Sendung und überträgt ein einziges mal die Bytes (kann man bei 0,6 kbps mit einem Empfänger hören), aber dann nichts mehr, nur noch Träger. Auch die ISR wird nicht angesprungen (zu erkennen an der LED). nIRQ bleibt auf 0, obwohl der doch 1 werden müsste, sobald die ersten 2 Bytes den internen Puffer gefüllt haben, oder?

Weiß irgendjemand, wo mein Fehler liegt??

guenter1604
27.02.2010, 23:00
Hallo Sauerbruch,

guck mal hier:

http://www.gerold-online.de/cms/wheelie/mein-wheelie/telemetrie.html

Günter

Sauerbruch
28.02.2010, 15:39
Moin Günter,

das sieht nach einem ziemlich interssanten Link aus, den ich morgen nach dem Dienst mal genauer untrer die Lupe nehmen muss. Endlich mal was nicht in C :-) Da auch der Schaltplan dabei ist, müssten sich eine Menge Anregungen rausziehen lassen.

Allerdings muss ich mich jetzt mal mit ´ner Frage outen, die mich schon lange beschäftigt. Man liest immer, dass "Subs" den Vorteil haben, Variablen "mitzunehmen". Da dieser Code ja voller Subs steckt, würde ich das gerne einmal richtig verstehen. Ich kann doch eigentlich an jeder beliebigen Stelle, d.h. auch in einem GOTO-Abschnitt, einer ISR oder sonstwo Variablen aus der Hauptschleife verändern - wozu muss ich sie denn "mitnehmen"?

Ansonsten erstmal vielen Dank für den Link!!

Daniel

guenter1604
28.02.2010, 17:06
Hallo Sauerbruch,

schau dir dazu erstmal die ByRef und ByVal Geschichte an.
Man kann Variablen in einer Sub nämlich ByRef oder ByVal übergeben.

Im Accessforum habe ich das mal so erklärt:

In deiner aufrufenden Hauptschleife ist eine Variable namens "Kiste Bier".

Wenn diese ByVal übergeben wird, wird eine Kopie dieser Kiste Bier an die Sub oder Funktion "DieDurstigenProgrammierer" übergeben.
Was die dort damit machen kann dir egal sein, dir bleibt dein Bier in der Hauptschleife.

Wenn die Kiste ByRef übergeben wird, wird nur ein Zettel übergeben mit der Beschreibung wo deine Bierkiste steht.

Was die Funktion DieDurstigenProgrammierer mit deiner Variable (Bierkiste) in der Hauptschleife anrichten kannst du dir ausmalen ;-)

Günter

Jaecko
28.02.2010, 17:17
Noch ein Hinweis, wenn viele Subs/Functions/übergebene Variablen verwendet werden:
Aufpassen, dass in Bascom die Werte für Softstack/HWStack/Framesize nicht zu klein sind. Sonst läuft schnell mal was über.

guenter1604
28.02.2010, 17:20
und daß standardmäßig byref übergeben wird, also die Variablen in der Haupschleife verändert werden können.

Sauerbruch
28.02.2010, 19:25
Erstmal vielen Dank für diese handfesten Vergleiche :-)

So ganz verstaden hab ich die Vorteile aber noch nicht. Wahrscheinlich stehe ich gerade auf der (Bier)leitung:


und daß standardmäßig byref übergeben wird, also die Variablen in der Haupschleife verändert werden können.

[grübel]
Wenn ich eine Variable verändern will, die auch in der Hauptschleife verwendet wird, kann ich das in der Sub nicht einfach á la "Bierkiste = Bierkiste+1" tun? Der neue Wert müsste dann doch auch in der Hauptschleife verwendet werden, oder??
[/grübel]

guenter1604
28.02.2010, 20:20
Wenn du eine Variable deklarierst ist sie Public. Das heißt du kannst sie auch in der Sub verwenden, ohne sie irgendwie übergeben zu müssen. Wenn du den Wert in der Sub änderst ist er überall verändert. Das hört sich im ersten Moment cool an, jedoch birgt das große Gefahren!

Stell dir vor, im Hauptprogramm steht die Bierkiste und du rufst die Sub auf. Dort wird Code abgearbeitet und dann auf die Variable Bier zugegriffen, jedoch das Bier ist leer! Das gibts doch nicht, beim Aufruf der Sub war die doch noch voll!
Was ist passiert? Inzwischen war der Interrupt da, der ebenfalls vom Bier erfahren hat und hat es leergesoffen.
Soll heißen, du kannst nicht sicher sein, daß andere Programmteile die Variable in der Zwischenzeit nicht verändert haben. Wird der Wert aber byval an die Sub übergeben, kommt der Wert sicher so an der Sub an, wie er im Moment des Subaufrufs war. Beides hat Vorteile, man muß sich aber über die Unterschiede klar werden, sonst baut man sich ganz fiese Fehler ein!

guenter1604
28.02.2010, 21:09
Hallo sauerbruch,

gerne nimmt man ja eine Variable als Zwischenspeicher für Rechenwerte. Hier sieht man was passiert, wenn da jemand dazwischenpfuscht, eigentlich sollte D ja immer 6 sein. Lass das mal im Simulator laufen und drück immer wieder mal den Interruptknopf.


$regfile = "m8def.dat"
$crystal = 16000000

Config Timer0 = Timer , Prescale = 1024
On Timer0 Int_timer0
Start Timer0
Enable Timer0
Enable Interrupts
Dim A As Byte
Dim B As Byte
Dim C As Byte
Dim D As Byte
Dim E As Byte

Dim Tempvar As Byte

A = 2
B = 2
C = 2
Do
Tempvar = A + B
Waitms 10
D = Tempvar + C
Print D
Loop

Int_timer0:
Tempvar = A + 10
E = Tempvar + 10
Return

Sauerbruch
28.02.2010, 22:50
Hi Günter,

jetzt ist der "Kronkorken" gefallen - tnx!
Bislang waren meine Programme insoweit einfach unkompliziert, dass es in der Tat cool war, wenn mehrere Subs, ISRs usw. an der gleichen Variablen herumgefeilt haben. Von daher hat sich mir der Sinn von Byval und Byref nicht erschlossen. Das Beispiel mit der Interrupt-Taste macht´s aber sehr deutlich klar.

Mit diesem Wissen bewaffnet werde ich sicherlich auch den RFM12-Code aus Deinem Link aufdröseln und verstehen können.

Besten Dank,

Daniel

guenter1604
06.03.2010, 22:49
Daniel,

was macht dein Bierfunk?

Günter

Sauerbruch
08.03.2010, 07:18
Moin Günter!

Tja, der Bierfunk (*lach :-) )...

Ich dachte mir, ich mach mal einen kleinen Szenenwechsel und wende mich dem Empfänger zu. Wäre ja auch ganz schlau, denn sonst kann man ja nicht überprüfen, ob das mit dem Senden klappt. Dabei bin ich aber an einer Reihe von ungelösten Fragen gescheitert:

Ich übertrage per SPI ein &Hb000 um den FIFO auszulesen - und dann?? Woher weiß der Controller denn, dass er jetzt mit Lesen dran ist? Und wer sagt dem Controller, wann die übertragenen 2 Bytes fertig sind? Die Verbindung µC -> nSEL scheint mir ja nur in eine Richtung zu gehen.

Außerdem habe ich mir lange über dem Code von "Gerold-Electronic" den Kopf zerbrochen, zu dem Du mir ja den Link gepostet hattet. Besonders interessant fand ich die Geschichte mit dem Flag namens "warten", da mir irgendwo hier ganz in der Nähe die Lösung meines Problems zu sein schien:


Function Spi_write(byval Befehl As Word , Byval Warten As Byte) As Byte
Local A As Byte
Local B As Byte
If Warten = 1 Then
Reset Rfm12_cs
Bitwait Rfm12_sdo , Set
End If
Reset Rfm12_cs
B = High(befehl)
A = Spimove(b)
B = Low(befehl)
A = Spimove(b)
Set Rfm12_cs
Spi_write = A
End Function

Obwohl ich mir den Code auf der Gerold-Homepage unzählige male durchgeesen habe, finde ich nirgendwo eine Zeile, die das Flag "warten" setzt oder löscht... es wird immer nur mittels byval an die Subs übergeben und abgefragt. Auch das hat mein Verständnis dieser Dinge nicht gerade gefördert.

An diesem Punkt fiel mir dann wieder ein, dass die Datenübertragung in meinem Projekt im ungepufferten FSK-Modus über die UART-Schnittstelle ja eigentlich ziemlich gut funktioniert - und das auch im praktischen Einsatz der Geräte seit über einem Jahr. Bidirektional wäre halt sicherer, aber weil ich auch eine Prüfsumme mit übertrage, kann ich fehlerhafte Bytes zumndestens schon mal empfängerseitig aussortieren.

Leider muss ich im Moment aus Zeitgründen wichtige von weniger wichtigen Aufgaben trennen, und die RFM12-Geschichte fällt insgesamt zur Zeit definitiv in Rubrik 2... Trotzdem wurmen mich solche ungelösten Fragen ja schon immer ziemlich, und irgenwann (spätestens Weihnachten) wird auch der Spieltrieb wieder auf seine Kosten kommen. Vielleicht habe ich bis dahin ja die eine oder andere Erkenntnis gewonnen, die mir weiterhilft :-)

Gruß & co.,

Daniel

guenter1604
08.03.2010, 20:41
Hallo Daniel,

falls du Fragen zum Gerold-Code hat, frag den Verfasser: mich :-)

Die Funktion kann mit 0 oder 1 bei warten gesetzt werden.
Bei 0 wird einfach der Command ans RFM12 geschickt.
Bei 1 wartet die Funktion auf eine Antwort des RFM12 und gibt diese Antwort zurück.

Günter

Sauerbruch
09.03.2010, 00:11
Hey - diese Chance kann ich mir nicht entgehen lassen :-)


Die Funktion kann mit 0 oder 1 bei warten gesetzt werden.

Diese Bedeutung des Bytes "Warten" habe ich schon geahnt - aber nicht verstanden, wo im Programm der aktuelle Wert von "Warten" geändert wird. Ich sehe immer nur Zeilen im Sinne von "If warten = 1 then...". Wenn Du jetzt sagst, dass das innerhalb einer Funktion geschieht, müsste ich meine Frage vielleicht dahingehend umformulieren dass mir nicht klar ist, wie der Wert von "Warten" verändert wird. Aber das mag daran liegen, dass ich in der Kategorie "Funktion" noch nicht flüssig denken kann.


Bei 1 wartet die Funktion auf eine Antwort des RFM12 und gibt diese Antwort zurück.


Aber das ist wirklich nahe dran - wie entlockt die "Funktion" dem RFM12 das empfangene Byte? Bis zum SPI-Kommando &Hb000 komme ich noch mit, und dass am Schluss der FIFO-Speicher mit &Hca81 und &Hca83 gelöscht wird, ist auch okay. Aber was dazwischen passiert, da versagt meine Phantasie vollständig 8-[

Wie auch immer - das Video von dem Wheelie ist beeindruckend!!

guenter1604
09.03.2010, 07:45
Wenn ich eine Funktion aufrufe, kann ich ihr Werte mitgeben.


Declare Function Spi_write(byval Befehl As Word , Byval Warten As Byte) As Byte

Hier sage ich, daß ich 2 Werte mitgeben will, der erste ein Word, der zweite ein Byte.
Das "as Byte" am Schluß ist der Rückgabewert der Funktion.


A = Spi_write(&H8239 , 0)

Übergibt also &H8239 an Spi_write und zwar an "Befehl" und 0 an "Warten"
Falls die Funktion was zurückgibt ist das nachher in "A" gespeichert
Den Kern des Empfängers bildet:


For I = 1 To L
Rxbuf(i) = Spi_write(&Hb000 , 1)
Next
Es wird also &Hb000 gesendet und auf Antwort gewartet. Das Ergebnis ist dann im Array Rxbuf(i).

Sauerbruch
09.03.2010, 11:28
Hmmm, Puzzleteilchen finden langsam zusammen... Das mit den Funktionen ist mir jetzt klar - und auch, an welcher Stelle "Warten" auf 0 oder 1 gesetzt wird.

Eins verstehe ich aber noch nicht ganz:

Es gibt doch auch viele Befehle an den RFM12, auf die das Modul nicht mit irgendeinem Byte antwortet, z.B. Frequenzeinstellung, Baudrate, etc., etc. Weshalb werden die denn auch alle über die Funktion (!) Spi_write übertragen, wenn man nach dem Befehl gar keine Antwort erwartet? Ginge da denn nicht auch ganz banal der Bascom-Befehl Spiout?

Und das mit dem FIFO-Auslesen ist mir auch noch nicht so ganz klar - wahrscheinlich habe ich (trotz intensiver Bemühung der Bascom-Hilfe) den Befehl SPIMOVE noch nicht ganz kapiert... ich stell´s mir so vor:

X = Spimove(Y)

sendet Y an das Modul und weist X den Wert des Bytes zu, das das Mdul zurückschickt. Richtig??

Aber das Modul weiß doch erst nach dem zweiten gesendeten Byte (z.B. &Hb0 und &H00 für FIFO-read) , dass es etwas zurückgeben soll. Wie kann denn dann in den ersten beiden "Rück"-Bytes schon die gewünschte Information drin sein??

Sorry für meine Begriffsstutzigkeit, aber wenn ich´s jetzt nicht anpacke, werde ich´s nie verstehen...

guenter1604
09.03.2010, 16:35
Hallo Daniel,

ich wollte einfach alles mit einer Funktion erschlagen. Klar könnte man für den Konfigurationsbefehl eine extra Sub machen, da ja nichts zurückgegeben wird. Dann kann man sich auch das Wartenbyte sparen.

Wir warten doch extra bis das RFM12 meldet, daß was da ist. Dann sagen wir mit &Hb0, daß wir den FiFo-Puffer lesen wollen. Dann stellen wir mit &H00 einen leeren Eimer hin, der gefälligst gefüllt werden soll. Wir hohlen also immer nur 1 Byte mit der Funktion.

Günter

Sauerbruch
09.03.2010, 18:05
Okay - langsam verstehe ich es glaube ich...

Wenn ich folgendes schreibe:

X = Spimove (&Hb0)
Y = Spimove (&H00)

dann ist X irgendein Müll-Byte, und Y das Nutz-Byte aus dem FIFO???

Wenn der RFM12 sowieso erst nach &Hb0 merkt, dass er was zurückgeben soll, könnte man dann auch folgendes schreiben:

Spiout &Hb0, 1
Y = Spimove (&H00) ?

Und eine letzte Frage habe ich noch (zumindst bis zur nächsten =P~ ):

Wie ist das mit dem nSEL-Eingang: Wird der nicht automatisch auf 0 gezogen, wenn die SPI-Befehle ins Spiel kommen? Und wenn ja, weshalb machst Du es in Deinem Code dann mit extra Befehlen - kommt sich das denn nicht in die Quere? Und wie sähe das bei Verwendung von Soft-SPI aus?

Sorry für die vielen Fragezeichen - und vielen Dank für die bisherige Nachhilfe!!

Daniel

guenter1604
09.03.2010, 18:37
Tja Daniel,

an dieser Stelle habe ich dann meine RFM12-Forschungen vorerst eingestellt. Das Ergebnis war tauglich, jedoch ist das bestimmt nicht das Ende der Fahnenstange. Die sehr spärliche Dokumentation des RFM12 macht das Ganze nicht leichter.
Mit diesem Code habe ich es zumindest geschafft in eine Richtung mit 49k zu senden (&HC606, mit 5ms Lücken durch die Wheeliefirmware), mehr war für die Wheelie Telemetrie auch nicht nötig.
Es ist ein Artikel für Elektor in Arbeit, dafür wird alles noch gehübscht. Den Empfänger passt in einen USB-Stick:
http://www.elektor.de/forum/foren-ubersicht/foren-zu-elektor-projekten/elektorwheelie/telemetrie-modul.1022508.lynkx?pageStart=41

Auch eine GUI für den PC habe ich dazugebastelt (siehe obiger Link), auch dieser Code ist OpenSource. Selbst die Konfiguration des Installers (Innosetup), der die GUI mitsamt USB-Treibern auf einem PC installiert, ist offen.

Günter

Sauerbruch
09.03.2010, 19:43
Das beruhigt mich ja, dass nicht nur ich die Datenblätter des RFM12 als etwas dünn empfinde. Aber mit den neuen Erkenntnissen und vielleicht der einen oder anderen Zeile aus Deinem Wheelie-Code werde ich mich in den nächsten Tagen bestimmt nochmal dransetzen - Zeitmangel hin oder her!

Wenn´s klappt, schicke ich Dir ´ne PN :-)

Vielen Dank nochmal,

Daniel

Holli_
25.03.2010, 21:07
Hier gibt es übrigens eine Sammlung von Sende- und Empfangsroutinen in Bascom für den RFM12.

http://bascom-forum.de/index.php/topic,3421.0.html

Der Code ist auf das wesentliche reduziert um übersichtlich zu bleiben. Es werden eigentlich alle Möglichkeiten der Kommunikation mit dem RFM abgedeckt.

Sauerbruch
25.03.2010, 22:26
Hey - das sieht sehr verheißungsvoll aus...

...aber was ist eine *.rar-Datei???