Hi ich habe ein Problem mit meinen SPI Funktionen und weiß nicht was ich
falsch mache, denn den Code habe ich eingentlich aus dem entsprechenden
Datenblatt entnommen.
Es geht hierbei um den ATmega44a mit dem ich den CC1100 von TI
ansprechen will.
Ich habe vorher noch nicht mit Hardware SPI geareitet, daher bin ich
erstmal dabei in dem CC1100 in die Register zu schreiben und dann wieder
auszulesen.
Hier ist mein Programm:
main.c
Die Register (Tabelle mit CC1100 Registern) und die IO Sachen sind
ausgiebig getestet das stimmt soweit aber wenn ich das Programm laufen
lasse bricht er in cc_config() ab und zwar wenn ich den ersten Register
beschreibe. Ich habe zum debuggen kommentare über die serielle
Schnittstelle ausgeben lassen.
Abbruch bzw Endlosschleife laut aufgabe bei:
cc_config() -> cc_writeRegister() -> spi_send(data) -> dort in der While
Schleife
Ausgabe auf dem Terminal:
cc1100 eingeschaltet
write 1
cc_writeRegister start
SPDR has received data content
end of while and spi_send()
SPDR has received data content
Sind meine SPI Funktionen richtig? Denn das auslesen Funktioniert auch
nicht. Das habe ich auch schon getestet um die Intertialwerte
auszulesen.
Den Programmteil habe ich aber verworfen um es simpler zu gestalten.
Wäre cool wenn ihr mir da helfen würdet.
Gruß cler
Hi
>char spi_read(char addr){> SPDR = (addr);> while(!(SPSR & (1 << SPIF)));> return SPDR;
Um etwas vom Slave zu lesen muss man ein Dummy-Byte senden.
MfG Spess
Aber ich sende doch die Addresse an den Chip reicht das nicht als
Dummybyte? Beim SoftSPI kenne ich das noch so:
Adresse schicken :
SPDR = (addr);
while(!(SPSR & (1 << SPIF)));
dann warten und Register lesen:
return SPDR;
Allerdings muss ich beim HardwareSPI doch nicht warten oder?
Hi
>Aber ich sende doch die Addresse an den Chip reicht das nicht als>Dummybyte?
Dann muss dein CC1100 hellseherische Fähigkeiten haben. Ein SPI-Slave
(dein CC1100) bekommt zu Senden und Empfangen den Takt vom Master
(ATMega). Und ein Takt wird nur erzeugt, wenn der ATMega etwas sendet
(und dabei gleichzeitig empfängt). So wie du es willst muss der CC1100
schon beim ersten Bit der Adresse wissen, welche Bits er mit dem Takt
rausschieben muss.
MfG Spess
SPI musst du dir wie das gleichzeitige Austauschen von Bytes vorstellen.
Wenn der Master etwas zum Slave sendet, überträgt gleichzeitig der Slave
1 Byte zum Master.
So wie wenn du und dein Kumpel euch am Tisch gegenüber sitzt.
Jeder hat ein Kuvert in der Hand, in dem die Nachricht steckt.
Du schiebst mit der rechten Hand dein Kuvert über den Tisch und dein
Kumpel macht genau dasselbe. D.h. mit der rechten Hand schiebst du dein
Kuvert rüber und mit der linken Hand nimmst du das Kuvert, welches dein
Kumpel dir zeitgleich rüberschickt.
So. Wenn du jetzt von deinem Kumpel etwas wissen willst, dann kann
logischerweise die Antwort auf deine Anfrage NICHT im ersten Kuvert
sein, welches dein Kumpel dir rüberschiebt. Denn der kann ja zu diesem
Zeitpunk noch gar nicht wissen, was du von ihm willst.
Du musst ihm also mal deine Anfrage in einem Kuvert rüberschieben. Das
Kuvert welches du von deinem Kumpel kriegst, enthält für dich nichts
wesentliches. D.h. das kannst du ignorieren.
Dann sieht dein Kumpel in des gerade gekriegte Kuvert rein, besorgt die
Information, die du angefragt hast, und schreibt sie in das Kuvert das
er hat.
Damit du dann diese Information wieder kriegen kannst, müsst ihr nochmal
die Kuverts tauschen.
Und erst dann hast du die Antwort auf deine Anfrage.
Stell es dir einfach bildlich vor, wie das abläuft. Dann ist es ganz
einfach.
> Danke, aber wo muss ich die denn einbauen?
Die Frage solltest du dir jetzt eigentlich selbst beantworten können.
Die Sequenz
1
...
2
SPDR=Bytewert;
3
while(!(SPSR&(1<<SPIF)))
4
;
5
...
entspricht EINEM Kuverttausch.
Mit der Zuweisung stösst du ihn an, und die while-Schleife wartet
darauf, dass der Austausch fertig vollzogen ist.
Danach kannst du durch Auslesen von SPDR in das gerade erhaltene Kuvert
reinschauen. Du kannst, aber du musst natürlich nicht.
Super Erklärung vielen Dank :)
Also ich habe dann die lesefunktion so umgeschrieben:
Von der Logik her muss ich dem Chip die Adresse mitteilen, dabei bekomme
ich Müll dafür bietet sich die Funktion spi_send() an. Dann muss ich
noch ein Dummybyte senden damit ich in der Antwort daraufhin die Info
bekomme.
Aber im /**/ habe ich makiert wo mein Programm nicht mehr funktioniert.
Ich bekomme keine Meldung über das Terminal
Was mache ich noch falsch?
Danke euch schonmal
1
indermainaufgerufen:
2
3
uart_puts("\nread FREQ2\n");
4
uart_putc(cc_readRegister(CC1100_FREQ2));
5
6
charcc_readRegister(charaddr){
7
chardata=0xff;
8
9
uart_puts("cc_readRegister(");
10
uart_putc(addr);
11
uart_puts(") start\n");
12
cc_select(1);
13
14
spi_send(addr|0x80);//anfrage nach inhalt der addresse
15
16
data=spi_read(addr);//addresse mit dummy byte zB addr
17
18
cc_select(0);
19
uart_puts("cc_readRegister end\n");
20
21
returndata;
22
}
23
24
charspi_read(charaddr){
25
uart_puts("spi_read() start\n");
26
27
SPDR=(addr);
28
uart_puts("spi_send() SPDR received data content\n");
29
30
/**/
31
32
while(!(SPSR&(1<<SPIF)));
33
uart_puts("spi_read() end returning data\n");
34
returnSPDR;
35
}
36
37
voidspi_send(chardata){
38
SPDR=data;
39
uart_puts("spi_send() SPDR has received data content\n");
40
while(!(SPSR&(1<<SPIF)));
41
uart_puts("end of while and spi_send()\n");
42
}
Debug Ausgabe auf dem Terminal:
cc1100 eingeschaltet<\n>
start<\n>
<\n>
read FREQ2<\n>
cc_readRegister(<\r>) start<\n>
spi_send() SPDR has received data content<\n>
end of while and spi_send()<\n>
spi_read() start<\n>
spi_send() SPDR received data content<\n>
cler :) schrieb:> Aber im /**/ habe ich makiert wo mein Programm nicht mehr funktioniert.> Ich bekomme keine Meldung über das Terminal>> Was mache ich noch falsch?
Nochmal.
Hast du den SS Pin der SPI auf Ausgang gestellt!
Das ist wichtig. Denn sonst fungiert dein µC nicht als Master. Selbst
dann nicht wenn du es im Konfigurationsregister angefordert hast!
(OK, die Wahrheit ist ein wenig komplizierter, aber in a Nutshell kann
man das vereinfacht so sagen: Wenn µC als Master fungieren soll, dann
MUSS der SS Pin der SPI auf Ausgang gestellt werden. Sonst generiert der
AVR keinen Clock und die Übertragung findet nicht statt)
Also ich bleibe jetzt nicht mehr in der Schleife hängen und das lag doch
tatsächlich an einem IO Pin der falsch gesetzt war.. der ss pin muss
beim atmega gesetzt sein, damit das ganze mit der spi funktioniert
Allerdings habe ich jetzt ein paar Register mit werten Beschrieben und
anschließend wollte ich die wieder auslesen aber ich bekomme mit der
Funktion spi() nur \0 zurück
1
charspi(chardata){
2
SPDR=data;
3
while(!(SPSR&(1<<SPIF)));
4
returnSPDR;
5
}
was läuft da immernoch falsch?
funktion um in die Register zu schreiben:
1
voidcc_writeRegister(charaddr,chardata){
2
chartmp=0xff;
3
4
cc_select(1);
5
6
tmp=spi(addr);
7
uart_puts("tmp = ");
8
uart_putc(tmp);
9
uart_putc('\n');
10
11
tmp=spi(data);
12
uart_puts("tmp = ");
13
uart_putc(tmp);
14
uart_putc('\n');
15
16
cc_select(0);
17
}
tmp ist immer \0 was ich auch nicht verwunderlich finde, aber ich dachte
mir wenn ich die Info habe kann ich sie auch rausrücken.
cler
Na was erwartest du?
Beim schreiben von Registern wird dir der IC nichts sinnvolles
zurückschicken. Der nimmt die Adresse, nimmt den Wert und beschreibt
sein internes Register. Mehr wird der nicht tun.
Irgendwas muss er zurückgeben, ob er will oder nicht - weil das ja immer
ein Bytetausch ist. Also wird der halt immer 0 zurückgeben. Ist ja
schliesslich auch eine Information. Nämlich: 'HuHu, ich bin da!'
Anders sieht es beim Lesen aus!
cler :) schrieb:> tmp ist immer \0 was ich auch nicht verwunderlich finde, aber ich dachte> mir wenn ich die Info habe kann ich sie auch rausrücken.
Ja, schon.
Aber warum gibst du sie nicht als Zahlenwert aus, sondern über
usart_putc?
Schreib dir halt ein usart_puth, welches die ein Byte als Hexzahl
ausgibt. Ist doch keine Hexerei, sich die Hilfsunktionen zu bauen, die
man braucht. Und gerade Zahlenausgabe braucht man immer wieder.
PS: wenn wir schon dabei sind.
Der angebrachte Datentyp für alles was im weitesten Sinne ein Byte ist,
ist ein unsigned char, oder ein uint8_t. Aber einen char willst du da
eigentlich nicht nehmen. Du willst an dieser Stelle es nicht dem
Compiler überlassen, ob er ein char als mit oder ohne Vorzeichen
ansieht.
Gewöhn dir an, dass es 3(!) Datentypen gibt
1
signed char kleine Zahlen mit Vorzeichen
2
unsigned char kleine Zahlen ohne Vorzeichen, also Bytes
3
char für alles, was mit Texten oder Textverarbeitung
4
zu tun hat.
Anstelle von signed char kannst du auch einen int8_t nehmen.
Anstelle von unsigned char kannst du auch einen uint8_t nehmen.
Aber akzeptiere, dass es einen Character in 3(!) unterschiedlichen
Ausprägungen gibt, orientier dich an der 'Tabelle', unter welchen
Umständen du welchen nimmst, und du hast auf lange Sicht weniger Ärger.
Danke für den Tipp werde mir das mit den 8 Bit Datentypen mal zu Herzen
nehmen. Ich habe das so auf den 8051ern gelernt. Aber mein Problem liegt
ja auch beim auslesen.. Das ich da immer \0 zurück bekomme.
Hier schreibe ich in die Frequenzregister:
1
uart_puts("write 4\n");
2
cc_writeRegister(CC1100_FREQ2,0x21);
3
uart_puts("write 5\n");
4
cc_writeRegister(CC1100_FREQ1,0x76);
5
uart_puts("write 6\n");
6
cc_writeRegister(CC1100_FREQ0,0x27);
Hier zB: lese ich die zuvor eingestellten Frequenzen aus:
1
uart_puts("\nread FREQ2\n");
2
uart_putc(cc_readRegister(CC1100_FREQ2));
3
uart_puts("\nread FREQ1\n");
4
uart_putc(cc_readRegister(CC1100_FREQ1));
5
uart_puts("\nread FREQ0\n");
6
uart_putc(cc_readRegister(CC1100_FREQ0));
Warum gibt der mir dann beim Lesen immer nur \0 aus obwohl da jetzt 0x21
0x76 und 0x27 zurückkommen müsste.
Hier nochmal die Funktion cc_readRegister:
holger schrieb:> Versuchs mal so:
:-)
oder zeig zumindest die Funktion cc_select her, zusammen mit der
Information, ob der angehängte IC eine 1 oder eine 0 an seinem
Select-Eingang sehen will um sich angesprochen zu fühlen.
Hier ist die Funktion mit dem select also wie schon im Datenblatt steht
CS muss low sein also wenn ich cc_select(1) hab aktiviere ich den Chip
und schalte demnach auf low:
1
voidcc_select(unsignedcharp){
2
if(p==1){
3
PORTB&=~(1<<PB1);
4
}else{
5
PORTB|=(1<<PB1);
6
}
7
}
Habe das sowohl mit der Polarität und der Phase ausprobiert. Und beides
nochmal mit vertauschtem cc_select() ich bin langsam mit meinem Latein
am Ende.
Oder mal alles zusammengenommen:
Zeig doch bitte endlich mal den kompletten Code!
Die UART Funktionen brauchen wir nicht. Aber alle Funktionen, egal ob du
sie für wichtig hältst oder nicht, die im Zusammenhang mit SPI stehen.
Und ja, die Datenrichtungen gehören da genauso dazu! Im Idealfall
versetzt du uns in die Lage, deinen Code zu nehmen, zu compilieren und
auf einen M44 zu brennen.
Du hast doch selber schon gesehen, dass dein erster Fehler (SS Pin)
nicht in dem aufgetaucht ist, was du präsentiert hast! Gefunden wurde er
nur, weil das ein Standardfehler ist und korrekt erraten wurde. Lass uns
nicht raten! Lass uns am Problem arbeiten. Dazu brauchen wir aber
vollständige Informationen.
Den musste ich so setzen damit die SPI Verbindung nicht mehr in der
whileschleife hängen bleibt. Habe noch vergessen die Kommentare zu
pflegen Danke :)
Entweder stell ich mich jetzt dumm an, oder irgendwas anderes stimmt
nicht. Ich kann vom Mega44 kein Datenblatt finden.
Nichts desto trotz
> void io_init(){> // I/O-Ports initialisieren>> /* Port B Initialisierung> // Port B1 - CS -> output default high> // Port B2 - GD0 -> input with pullup> */> PORTB = 0x06;> DDRB = 0x06;>> /* Port C Initialisierung> // Port C1 - SO -> output default high> // Port C2 - SI -> input without pullup> // Port C3 - SCLK -> output default low> */> PORTC = 0x02;> DDRC = 0x0A;
mir fehlt da immer noch das Setzen des SS Pins auf Ausgang
Warum schreibst du das eigentlich alles mit Hex-Zahlen
So...
1
/* Port B Initialisierung
2
// Port B1 - CS -> output default high
3
// Port B2 - GD0 -> input with pullup
4
*/
5
PORTB=(1<<PB1)|(1<<PB2);
6
DDRB=(1<<PB1)|(1<<PB2);
7
8
/* Port C Initialisierung
9
// Port C1 - SO -> output default high
10
// Port C2 - SI -> input without pullup
11
// Port C3 - SCLK -> output default low
12
*/
13
PORTC=(1<<C1);
14
DDRC=(1<<C1)|(1<<C3);
... wäre das alles viel einfacher zu kontrollieren, ob du auch wirklich
die richtigen Pins auf Output gesetzt hast.
Mit ein paar define davor
1
/* Port B Initialisierung
2
// Port B1 - CS -> output default high
3
// Port B2 - GD0 -> input with pullup
4
*/
5
#define CS PB1
6
#define GD0 PB2
7
8
PORTB=(1<<CS)|(1<<GD0);
9
DDRB=(1<<CS)|(1<<GD0);
10
11
/* Port C Initialisierung
12
// Port C1 - SO -> output default high
13
// Port C2 - SI -> input without pullup
14
// Port C3 - SCLK -> output default low
15
*/
16
#define SO PC1
17
#define SI PC2
18
#define SCLK PC3
19
20
PORTC=(1<<SO);
21
DDRC=(1<<SO)|(1<<SCLK);
... wirds dann gleich noch eine Spur leichter zu durchschauen. Vor allen
Dingen im Code danach, bei dem dann ein ...
... mir schon Codemässig erzählt, dass es hier um den CS (also Chip
Select) geht. Das der am PB1 hängt muss mich dann eigentlich nicht mehr
weiter interessieren. OK, das PORTB schränkt mich an dieser Stelle noch
ein wenig ein, aber gut, könnte man auch noch ändern.
Nichts desto trotz. Ich vermisse den Pin SS der SPI Schnittstelle. Der
wird nirgends auf Output gesetzt.
cler :) schrieb:> Den musste ich so setzen damit die SPI Verbindung nicht mehr in der> whileschleife hängen bleibt. Habe noch vergessen die Kommentare zu> pflegen Danke :)
Was sagt uns das?
Kommentare sind Scheisse. Wenn du eine Möglichkeit hast, einen Kommentar
dadurch wegzubringen, indem du direkt im Code genau dasselbe aussagen
kannst, DANN TU DAS UND LASS DEN KOMMENTAR WEG!
Karl Heinz Buchegger schrieb:> Entweder stell ich mich jetzt dumm an, oder irgendwas anderes stimmt> nicht. Ich kann vom Mega44 kein Datenblatt finden.
? Kann wer näheres dazu beitragen
Es gibt einen Tiny44
und einen Mega48
aber einen Mega44 kann ich nicht finden?
spess53 schrieb:> Hi>>>Ich kann vom Mega44 kein Datenblatt finden.>> Den gibt es auch nicht. Entweder meint er einen ATMega644A oder einen> ATMega48A.
Hab ich mir auch schon gedacht.
Aber die Pinbelegung des Hardware-SPI am Port C passt zu keinem von
beiden.
Habe mich was den Controller angeht vertippt tut mir Leid.
Ich habe den Fehler gelöst. Der CC1100 auf der Platine scheint defekt zu
sein zumindest macht es den Eindruck mit der Lupe das würde einiges
erklären, denke ich.
Gruß cler
Hi
>Der Atmega48a
Der hat aber kein SPI an PortC:
PC3 (ADC3/PCINT11)
PC2 (ADC2/PCINT10)
PC1 (ADC1/PCINT9)
sondern an PortB
PB5 (SCK/PCINT5)
PB4 (MISO/PCINT4)
PB3 (MOSI/OC2A/PCINT3
PB2 (SS/OC1B/PCINT2)
MfG Spess