Ich habe mir vor einiger Zeit mal eine Arduino Library für das RFM12B
Funkmodul an den Atmega 2560 angepasst, so dass ich das Arduino Gedöns
nicht brauche.
Um sie universeller für die Zukunft zu halte, habe ich auch noch
Bitbanging eingebaut. Die Library funktioniert einwandfrei.
Jetzt wollte ich das sie gerade mit einem Attiny2313 verwenden, aber das
ganze macht keinen Mucks. Am Atmega2560 funktioniert ein uns das selbe
Funkmodul aber.
nSel ist an B4
SCK ist an B7
SDO ist an B5
SDI ist an B6
nIRQ ist an D2
Controller läuft mit 8 Mhz ohne Vorteiler.
Die Änderungen die ich vorgenommen habe, inkl. original Code habe ich
mit dem Kommentar "//Für den Tiny geändert" versehen.
Es kommen Daten aus dem DO des Tiny raus, und ein Clock Signal kommt
auch an. Nur kommen augenscheinlich keine Daten aus dem Funkmodul zurück
(hab leider nur ein Oszi, weil LA kaputt).
In der Funktion void SendWait(uint8_t waitMode) hängt das ganze, weil
kein Interrupt vom Funkmodul erzeugt wird und somit die Variable für den
aktuellen Zustand (rxstate) nicht verändert wird.
Der Interrupt funktioniert. Es wird in den Handler gesprungen, wenn ich
den Pin manuell auf low ziehe.
Wenn sich jemand den Code ansehen könnte, ob die Änderungen von mir alle
so korrekt sind, das wäre nett.
Hier ist mal die c und die h Datei angehängt.
C-Datei
1
#include"RFM12B.h"
2
#include"avr/io.h"
3
#include"string.h"
4
5
#define F_CPU 8000000UL
6
#include<util/delay.h>
7
8
voidSPIInit(){
9
10
SS_DDR|=(1<<cs_pin);
11
//DI
12
DDRB&=~(1<<5);
13
//DO
14
DDRB=(1<<6);
15
//SCK
16
DDRB|=(1<<7);
17
//Interrupt Pin has Pullup
18
DDRD&=~(1<<2);
19
PORTD|=(1<<2);
20
}
21
22
23
uint8_tByte(uint8_tout){
24
25
uint8_treturnvalue=0;
26
int8_ti;
27
for(i=7;i>=0;i--){
28
29
//Bit low or high?
30
if(out&(1<<i))
31
PORTB|=(1<<6);
32
else
33
PORTB&=~(1<<6);
34
35
//Clock High
36
PORTB|=(1<<7);
37
_delay_us(1);
38
39
//Clock Low
40
PORTB&=~(1<<7);
41
42
//Read input
43
if(PINB&(1<<PINB5)){
44
returnvalue|=(1<<i);
45
}
46
_delay_us(1);
47
}
48
returnreturnvalue;
49
}
50
51
52
uint16_tXFERSlow(uint16_tcmd){
53
54
SS_PORT&=~(1<<cs_pin);
55
uint16_treply=Byte(cmd>>8)<<8;
56
reply|=Byte(cmd);
57
SS_PORT|=(1<<cs_pin);
58
returnreply;
59
}
60
61
voidXFER(uint16_tcmd){
62
SS_PORT&=~(1<<cs_pin);
63
Byte(cmd>>8)<<8;
64
Byte(cmd);
65
SS_PORT|=(1<<cs_pin);
66
}
67
68
voidInitialize(uint8_tID,uint8_tnetworkid)
69
{
70
71
72
Data=rf12_data;
73
DataLen=&rf12_buf[3];
74
75
uint8_ttxPower=0;
76
uint8_tairKbps=0x08;
77
uint8_tlowVoltageThreshold=RF12_2v75;
78
79
80
cs_pin=SS_BIT;
81
nodeID=ID;
82
networkID=networkid;
83
SPIInit();
84
XFER(0x0000);// intitial SPI transfer added to avoid power-up problem
85
XFER(RF_SLEEP_MODE);// DC (disable clk pin), enable lbd
86
87
// wait until RFM12B is out of power-up reset, this takes several *seconds*
88
XFER(RF_TXREG_WRITE);// in case we're still in OOK mode
89
//Für den Tiny geändert: while (!(PIND & (1 << 3) ))
90
while(!(PIND&(1<<2)))// digitalRead(18) == 0)
91
XFER(0x0000);
92
93
XFER(0x80C7|(RF12_868MHZ<<4));// EL (ena TX), EF (ena RX FIFO), 12.0pF
94
XFER(0xA640);// Frequency is exactly 434/868/915MHz (whatever freqBand is)
>> Da fehlt ein |, wodurch der CS-Pin wieder zum Eingang wird.
JAAAAAAAAAAAAAAAAAAAAAA, das ist es!!!!!
Felix, ich sitze an dem Ding jetzt seit 10 Stunden.... denkst du das
hätte ich gesehen? Oh mein Gott, du hast mir gerade den Tag versüßt,
jetzt kann ich beruhigt schlafen.
Danke dir tausendfach!
Hab den Fehler immer noch nicht gefunden.
Slave Select toggelt, Clock ist da und Daten auch. Modul antwortet aber
am Tiny nicht, am Mega schon.
Gibts da irgendwelche Eigenheiten oder reagiert das Teil sensibel auf
irgendwas?
Mike M. schrieb:> Gibts da irgendwelche Eigenheiten oder reagiert das Teil sensibel auf> irgendwas?
Ja, es reagiert sehr sensibel auf SPI-Zugriffe, bevor der im DB
definierte Startup-Timeout abgelaufen ist. Und macht dann in der Folge
oft nur noch völligen Quatsch und ist aus dieser Condition nur durch
einen erneuten Reset zu erlösen.
Also muss man nach Reset des RFM12 (natürlich auch nach PowerOn-Reset!)
einfach mal diese Zeit warten, bevor man versucht, per SPI mit dem Teil
zu kommunizieren. Datenblatt lesen bildet...
Dass es beim Mega funktioniert und beim Tiny nicht, liegt mit einiger
Wahrscheinlichkeit daran, dass du den Mega mit Quarz laufen läßt (und
deswegen sinnvollerweise mit recht hohem Startup-Delay), den Tiny
hingegen mit dem internen RC-Oszillator praktisch ohne Startup-Delay.
Also: Mindestens das, was du bei der Konfiguration des Taktsystems des
Mega als Startup-Delay per Fuse vorgegeben hast, musst du beim Tiny in
Software warten, bevor du das erste Mal mit dem RFM12 kommunizierst bzw.
eigentlich, bevor du überhaupt die Pins für das Software-SPI
konfigurierst.
Und selbst dann kann es noch gelegentlich Reset-Probleme geben (wenn der
Reset für beide ICs quasi gleichzeitig in einem "ungünstigen" Moment
während der laufenden Kommunikation erfolgt). Dagegen hilft dann nur
noch ein physischer PullUp am nSel-Pin des RFM12. Diese Sache kann
übrigens genausogut auch mit einem ATMega und Hardware-SPI zum Problem
werden...
Der eigentlich springende Punkt ist nämlich der Zeitpunkt der ersten
H/L-Flanke an nSel nach dem Ende eines Reset des RFM12. Dafür gibt es
einen wohldefinierten Mindestwert. Und der steht, wie schon oben gesagt,
im Datenblatt...
Das mit dem nSel mit Pullup habe ich gerade getestet, hat nicht
geholfen.
Ein Delay beim Starten hatte ich auch schon eingebaut gehabt.
Setup- und Holdtimes laut Datenblatt sollten mehr als eingehalten sein.
Ich habe mir gestern einen neuen Logic Analyser gekauft, ich werde jetzt
wohl mal damit drauf gehen, und schauen ob damit etwas zu finden ist.
Mike M. schrieb:> Ich habe mir gestern einen neuen Logic Analyser gekauft
OMG. Ein LA kann niemals Sachverstand und DB-Lektüre ersetzen!
Ein LA ist ein sehr praktisches Tool, um logische Fehler in der
Kommunikation über einen "laufenden" Bus aufzuspüren, aber völlig
ungeeignet, um Fehler bei der Businitialisierung zu entlarven.
Dazu müsste das Teil nämlich die Eigenheiten aller Busteilnehmer kennen,
was ich gerade im Bereich SPI für einigermaßen unmöglich halten würde...
Was willst du mir jetzt sagen? Das der LA nicht geeignet ist um
herauszufinden was laut Datenblatt aus meinem Controller kommen soll
oder wie?
DB habe ich gelesen, Sachverstand vorhanden. Menschen machen Fehler, den
suche ich, und was machst du so schönes?
So, Fehler gefunden:
Warum auch immer die Library auf dem Atmega geht, auf dem Tiny geht sie
nicht.
Und zwar aus mehreren Gründen:
Der "InterruptHandler" sollte so lange laufen, wie der Pin auf Low ist,
damit er seine Statemachine abhandeln kann. Dann wurden statt 16bit nur
8 Bit Statusinfo überprüft....
Die zwei Sachen geändert und schon läuft es.