Hi Leute !!!
Ich möchte gern eine Funkstrecke zwischen zwei ATTiny45 mittels zweier
nRF24L01+ Module aufbauen, welche über SPI angesprochen werden. Da ich
allerdings mit diesem Interface noch nicht gearbeitet habe, wollte ich
die SPI-Kommunikation zunächst einmal nur zwischen den direkt
miteinander verbundenen µCs testen.
Dabei sendet der Master abwechselnd im Abstand von 20 Sekunden jeweils
den Wert "1" und "2". Empfängt der Slave eine "1", schaltet er eine LED
an, empfängt er eine "2", wieder aus. Als Sendesignal blinkt am Master
eine LED kurz. Das Ganze sollte dementsprechend also folgendermaßen
ablaufen:
> Master-LED blinkt --> Wert "1" wird gesendet --> Slave empfängt "1" --> LED am
Slave leuchtet
> 20 Sekunden warten> Master-LED blinkt --> Wert "2" wird gesendet --> Slave empfängt "2" --> LED am
Slave aus
> 20 Sekunden warten
usw. .....
Leider tut sich am Slave nichts, d. h. die LED bleibt aus.
------------------------------------------------------------------------
' MASTER
$regfile = "attiny45.dat"
$crystal = 128000
$hwstack = 36
$swstack = 8
$framesize = 24
Dim Datatosend As Byte
Config Portb.2 = Output ' USCK ----> SCK (Slave)
Config Portb.1 = Output ' DO ----> SDI (Slave)
Config Portb.0 = Input ' DI ----> SDO (Slave)
Portb.0 = 1 ' Pullup
Config Portb.4 = Output ' Sende-LED
Portb.4 = 0
Usicr = Bits(usiwm0 , Usics1 , Usiclk , Usitc)
Do
Datatosend = 1
Gosub Transmission
Wait 20
Datatosend = 2
Gosub Transmission
Wait 20
Loop
End
Transmission:
Portb.4 = 1
Waitms 200
Portb.4 = 0
Usisr = Bits(usioif) ' USIOIF löschen und USI-Zähler auf 0
Usidr = Datatosend ' Datenregister beschreiben
While Usisr.usioif = 0 : Set Usicr.usitc : Wend
Return
------------------------------------------------------------------------
' SLAVE
$regfile = "attiny45.dat"
$crystal = 128000
$hwstack = 36
$swstack = 8
$framesize = 24
Dim Empfangsbyte As Byte
Config Portb.2 = Output ' USCK ----> SCK (Slave)
Config Portb.1 = Output ' DO ----> SDI (Slave)
Config Portb.0 = Input ' DI ----> SDO (Slave)
Portb.0 = 1 ' Pullup
Config Portb.4 = Output ' Signal-LED
Usicr = Bits(usiwm0 , Usics1 , Usiclk , Usitc)
Do
Usisr = Bits(usioif) ' USIOIF löschen und USI-Zähler auf 0
' 8 Takte warten bis Byte übertragen
While Usisr.usioif = 0 : Set Usicr.usitc : Wend
Empfangsbyte = Usidr ' Empfangsbyte aus USI-Datenregister lesen
If Empfangsbyte = 1 Then Portb.4 = 1 ' Empfangsbyte = 1 --> LED an
If Empfangsbyte = 2 Then Portb.4 = 0 ' Empfangsbyte = 2 --> LED aus
Waitms 100
Loop
End
------------------------------------------------------------------------
Was mache ich falsch?
Grüße,
The SphereX
In Bascom mach ich selber nichts. Aber solltest du nicht Bei dem Slave
die Ausgänge als Eingänge un die Eingänge als Ausgänge machen? Du hast
es doch sogar als Kommentar hinten gemacht.
The SphereX schrieb:> Config Portb.2 = Output ' USCK ----> SCK (Slave)> Config Portb.1 = Output ' DO ----> SDI (Slave)> Config Portb.0 = Input ' DI ----> SDO (Slave)
Es ist keine gute Idee, zum Kennenlernen der SPI Schnittstelle einen
Master und einen Slave selber zu machen. Besser nimmt man einen
funktionierden Slave und spricht den an. Denn das wird man später zu 99%
auch tun. Dann muss man nämlich das Datenblatt des Slaves lesen und den
Master dazu passend programmieren. Man kann sich nicht den Slave so
hinbiegen, dass es irgendwann läuft.
Zum SPI allgemein: das sind nur 2 gekoppelte Schieberegister. Siehe
http://www.lothar-miller.de/s9y/archives/15-SPI.html
@ m-obi
" ... Aber solltest du nicht Bei dem Slave die Ausgänge als Eingänge un
die Eingänge als Ausgänge machen? ... "
Ich habe mich an der Bascom-Hilfe zum Thema "Universal Serial Interface"
orientiert. Dort ist die Port-Konfiguration für den Slave so vorgegeben.
http://avrhelp.mcselec.com/index.html?using_usi_universal_serial_int.htm
@ Lothar Miller
" ... Es ist keine gute Idee, zum Kennenlernen der SPI Schnittstelle
einen Master und einen Slave selber zu machen. Besser nimmt man einen
funktionierden Slave und spricht den an. ... "
Ich dachte eigentlich gerade, daß meine Vorgehensweise logischer ist,
als gleich mit dem in der späteren Anwendung vorgesehenen nRF24L01+ als
Slave zu experiementieren. Denn wenn ich schon eine "einfache" µC --> µC
Kommunikation nicht hinbekomme, wird das für mich als Anfänger ungleich
kompliziertere Ansprechen des Funkmoduls natürlich erst recht nicht
funktionieren. Hier kommen nämlich noch zahlreiche weitere Fehlerquellen
hinzu, weshalb ich zunächst mal sicherstellen wollte, daß ich SPI (USI
bei ATTinys) verstanden habe und dieses ordentlich läuft.
Tja, und genau das tut es leider nach wie vor nicht :-( !!!
Ich habe den Slave entsprechend der Bascom-Hilfe nochmals modifiziert,
ohne Erfolg.
----------------------------------------------------------------------
' SLAVE
$regfile = "attiny45.dat"
$crystal = 128000
$hwstack = 36
$swstack = 8
$framesize = 24
Dim Empfangsbyte As Byte
Dim Usi_data_ready As Bit
Config Portb.2 = Output ' USCK ----> SCK (Slave)
Config Portb.1 = Output ' DO ----> SDI (Slave)
Config Portb.0 = Input ' DI ----> SDO (Slave)
Portb.0 = 1
Config Portb.4 = Output
Portb.4 = 1
Waitms 200
Portb.4 = 0
Usicr = Bits(usiwm0 , Usics1 , Usioie)
On Usi_ovf Usi_overflow_int
Enable Usi_ovf
Enable Interrupts
Do
If Usi_data_ready = 1 Then
Reset Usi_data_ready
If Empfangsbyte = 1 Then Portb.4 = 1
If Empfangsbyte = 2 Then Portb.4 = 0
End If
Loop
End
Usi_overflow_int:
Set Usi_data_ready
Empfangsbyte = Usidr
Usisr = &B01_000000 'Reset Overflow Flag and reset 4-Bit USI counter
Return
------------------------------------------------------------------------
Dann ist auch immer die Rede von "Slave Select" als Leitung, über die
der Master dem Slave den Beginn einer Übertragung signalisiert. Diese
Funktion ist bei dem USI der Tinys aber gar nicht vorgesehen und kann
laut Hilfe offensichtlich in diesem Fall auch weggelassen werden: "...
We do not use Slave Select in this example ... ". Das verwirrt mich
etwas. Ist es nun notwendig, den Übertragungsstart zu signalisieren,
oder nicht?
Außerdem verstehe ich nicht so ganz, wie es sich mit der
Clock-Einstellung verhält. Im Bascom-Beispiel wird diese für den Master
überhaupt nicht definiert, für den Slave dann allerdings schon: " ...
Clock Source: External, positive edge ; External, both edges ... " ?
Naja, und dann sollte nach meinem Verständnis während der Übertragung
doch eigentlich ein Pegel am USCK-Pin (Clock) messbar sein, oder liege
ich da falsch? Denn dort messe ich konstant 0 V.
Grüße,
The SphereX
Aber eine Verbindung von Ausgang zu Ausgang oder von Eingang zu Eingang
macht doch nun wirklich keinen Sinn. Dort steht doch auch z.B. DO
----> SDI (Slave), also sollte es doch beim Slave ein input sein, oder
was soll dass I bedeuten in SDI? Am Besten verwendet man auch die
Bezeichnungen MISO (Master In Slave Out) und MOSI (Master Out Slave In),
da sieht man genau wie was sein muss. Und SCK sollte beim Slave ein
Einagang sein, da du ja den Takt vom Master bekommst.
Da hast Du absolut recht! Logisch betrachtet macht diese Konfiguration
keinen Sinn. Dann gehe ich mal davon aus, daß es sich bei dem
Bascom-Beispiel um einen Schreibfehler handelt.
Allerdings habe ich es mittlerweile natürlich auch schon mit der logisch
korrekten Beschaltung probiert. Aber auch da funktioniert die
Datenübertragung nicht. Wenn die 0 V am USCK-Pin des Master während der
Übertragung aber wie gesagt tatsächlich bedeuten, daß kein
Synchronisationstakt generiert wird, kann's ja auch nicht funktionieren.
Nur warum erzeugt der Master den Takt nicht mit:
While Usisr.usioif = 0 : Set Usicr.usitc : Wend
nach dem Befüllen des Datenregisters?
Grüße,
The SphereX
The SphereX schrieb:> Ich dachte eigentlich gerade, daß meine Vorgehensweise logischer ist
Ist sie nicht. Denn wenn du beim Sender und beim Empfänger den gleichen
Fehler ins Programm schreibst, dann kann es sein, dass die Übertragung
gerade deshalb trotzdem klappt. Ein echter Slave verzeiht da nichts und
du musst das richtige/passende Timing (CPOL+CPHA) verwenden...
Mach zum Test deines Masters einfach mal eine Brücke vom MOSI zum MISO.
Dann musst du die gesendeten Daten gleich wieder empfangen.
Ich hab's trotzdem erst mal mit den zwei Tinys durchgezogen ;-). Und
nachdem ich die Port-Konfiguration nachmals geändert und auch die
Verkabelung unidirektional ausgelegt habe
> MASTER USCK (Out) ---> SLAVE USCK (In)> MASTER DO (MISO) ---> SLAVE DI (MOSI)
funktioniert's jetzt auch :-). Danke für Eure Hinweise!
Grüße,
The SphereX
Ja, ist schon klar, und vom Logischen her hast Du ja recht. Aber ich
beziehe mich hier auf die PIN-Beschriftung laut Atmel, für mein Beispiel
speziell die des ATTiny45. Danach ist beim "Universal Serial Interface"
der Tinys eben:
> PB1 (MASTER) = DO (Data Out) = MISO
und
> PB0 (SLAVE) = DI (Data In) = MOSI
Folglich ist die Verbindung MASTER ---> SLAVE hier nun mal MISO --->
MOSI, auch wenn's logisch keinen Sinn macht.
Um Verwirrungen zu vermeiden hätte Atmel im Datenblatt vielleicht
konsequenterweise die Begriffe MISO und MOSI komplett weglassen müssen,
wenn man bei USI sowieso andere Bezeichnungen (DO, DI) gewählt hat.
Folgende Seite:
http://gizmosnack.blogspot.de/2013/04/tutorial-nrf24l01-and-avr.html
beschäftigt sich z. B. sehr ausführlich mit dem Thema "nRF24L01 und AVR
µC". Auch hier wird extra noch mal hervorgehoben, daß man entgegen der
logischen Vorgehensweise, MISO vom µC mit MOSI vom nRF24L01 Funkmodul
verbinden muß, damit die Datenübertragung funktioniert.
" ... To get the USI to SPI up and running I found out that I had to
connect the MOSI pin from the nRF to the MISO pin on the AVR and set it
as output. Atmega88: PB3, ATtiny26: PB1, ATtiny85: PB1 ... "
Grüße,
The SphereX
Laut
Figure 32. nRF24L01+ schematic for RF layouts with single ended 50Ω RF
output
benötigt er 6 Steuersignale. Einem MC mit max 6 IOs zu nehmen dürfte
daher sinnlos sein.
Von den 6 ist der IRQ allerdings optional, d. h. für die
Datenübertragung nicht erforderlich. Da waren's nur noch 5. Aber selbst
wenn: Wofür gibt es denn Deinen super Fastboot ;-) :-) .... Reset-Pin
als I/O konfiguriert, und fertig is'.
Grüße,
The SphereX