Hallo zusammen.
Ich habe ein Problem. Ich habe einen funktionierenden RFM70 Code,
welchen ich auf einem Atmega88 @ 8 MHz benutze. Diesen wollte ich nun
auf einen Attiny2313 portieren.
Beim Atmega88 benutze ich den Hardware SPI, welchen es beim Attiny2313
nicht gibt. Hier muss man mit dem USI arbeiten oder das ganze per
Software machen.
Entsprechend müsste rein theoretisch nur die SPI-Transfer Routine
geändert werden. (ja ich habe bedacht, dass beim USI der "MOSI" der DI
ist und der "MISO" der DO, also genau verdreht)
Beim Atmega88 sah das ganze so aus:
und da es bei mir nicht geklappt hat, habe ich das ganze auch nochmal in
Software gemacht:
1
unsignedcharSPI_transfer(unsignedcharvalue)
2
{
3
uint8_tbit_ctr;
4
for(bit_ctr=0;bit_ctr<8;bit_ctr++){
5
if(value&0x80)
6
PORTB|=(1<<PB6);//MOSI
7
else
8
PORTB&=~(1<<PB6);
9
10
value=(value<<1);
11
12
PORTB|=(1<<PB7);
13
if(PINB&(1<<PB5))
14
value|=1;
15
else
16
value&=~1;
17
PORTB&=~(1<<PB7);
18
}
19
returnvalue;
20
}
Beide Varianten führen jedoch zum gleichen Ergebnis. Ich kann zwar alles
aus dem RFM70 lesen und geschrieben wird scheinbar auch richtig, aber er
empfängt einfach nichts von meinem Sender (Statusregister bleibt bei
0x0E).
Ich habe auch schon zwischen dem SCK HIGH/LOW ( PORTB |= (1<<PB7)) /
PORTB &= ~(1<<PB7)) ein paar _delay_us(...) eingebaut um den Takt zu
verringern. Laut Oszi sieht auch alles gut aus.
Stelle ich nun aber den Systemclock des Attiny2313 auf 1 MHz (CKDIV8)
klappt es auf einmal. Scheinbar ist da also ein Timing-Problem, die
frage ist nur, was der Hardware-SPI vom Atmega88 anders macht als meine
(Semi)-Softwarelösung. Wie gesagt, der Code ist ansonsten 1:1 gleich.
1MHz geht, 8MHz geht nicht. Bei 8MHz am Atmega88 gehts hingegen
(SPI-Clock = 125 kHz). Beim Tiny habe ich via _delay_us den Clock sogar
schon auf bis 20 kHz runtergedreht, aber selbst das geht nicht. Erst
wenn der Systemclock auf 1 MHz steht geht es.
Ich würde ja auch mit 1MHz arbeiten, aber dann schaffe ich über den
USART nicht die benötigte Datenrate.
Interrupts habe ich momentan keine, also kanns auch nicht daran liegen.
Jemand eine Idee? Ich bin meinem Latein erstmal am Ende. Ich habe
eigentlich schon an jeder erdenklichen Stelle vergebens Delays eingebaut
(CE, CSN, SCK, etc). Bin für jeden Hinweis dankbar.
Timmo H. schrieb:> Bin für jeden Hinweis dankbar.
Ich weiß zwar nicht ob es hilft,
aber prüfe mal folgende SPI-Einstellungen:
Clock-Idle-State: LOW und Senden mit steigender Clockflanke.
Hope schrieb:> Timmo H. schrieb:>> Bin für jeden Hinweis dankbar.>> Ich weiß zwar nicht ob es hilft,> aber prüfe mal folgende SPI-Einstellungen:>> Clock-Idle-State: LOW und Senden mit steigender Clockflanke.
Ja das passt schon. In meiner "SPI-Init" (sorry, habs vergessen zu
posten) sind die Start-States folgendermaßen:
Dann hilft wohl nur der Vergleich der verwendeten Leitungen der
funktionierenden Atmega88 @ 8 MHz Variante mit der nicht
funktionierenden Attiny2313 @ 8MHz Variante per DSO oder
Logic-Analyzer.
Genau das wollte ich eigentlich vermeiden, da ich leider keinen Logic
Analyzer habe. Mit einem 2 Kanal DSO wird das wohl ein ziemliches Hin-
und Hergemesse. Naja ich werde mir nachher mal nach und nach die
Leitungen ansehen müssen, wo genau da die Timing Unterschiede sind.
Beim Atmega88 mit USART im SPI-Mode hatte ich schonmal ein ähnliches
Problem. Dort haben ein paar NOPs zwischen Register schreiben und lesen
geholfen
1
unsignedcharspi_transfer(unsignedcharvalue)
2
{
3
// Wait for empty transmit buffer.
4
do{}while((UCSR0A&(1<<UDRE0))==0);
5
6
// Send data.
7
UDR0=value;
8
9
// Wait for transfer to complete and return received value.
So, ich habe mir jetzt einige Stunden einen ziemlichen Wolf gemessen,
aber kann absolut keine Unterschiede sehen. Dennoch klappt es nicht.
Ich vermute bald, dass es daran liegt, dass der Tiny2313 einige Befehle
nicht hat, die der atmega88 jedoch besitzt. Vielleicht gehen dadurch
einige dinge langsamer und/oder schneller wodurch irgendwelche
Timing-Probleme ergeben.
Ich wüsste zu gerne woran das liegt. Beim Atmega klappt es auch ohne
Probleme mit einem SPI-Clock von 500 kHz. Wie gesagt, die Werte die ich
mit dem Attiny lese passen, die Kommunikation geht also, nur will er
partout nicht die Pakete empfangen.
Da hier scheinbar keiner eine Idee hat, muss ich wohl oder übel auf
einen atmega umsteigen. Dennoch würde es mich brennend interessieren
woran es nun genau liegt.
Hallo,
machst Du die SPI-Routine jetzt in Software oder über den USI?
Funktioniert es auch, wenn Du das Programm, das auf dem Tiny nicht
läuft, mal auf den Atmega ummünzt?
Timmo H. schrieb:> nur will er partout nicht die Pakete empfangen.
sendet er ein ACK zurück?
Gruß
Gerhard
Gerhard schrieb:> Hallo,>> machst Du die SPI-Routine jetzt in Software oder über den USI?
Habe wie gesagt beides Probiert. Ich habe mir auch schon die RFM70
Register Dumpen lassen, es steht das drin was ich reinschreiben wollte.
> Funktioniert es auch, wenn Du das Programm, das auf dem Tiny nicht> läuft, mal auf den Atmega ummünzt?
Das Programm kommt schon 1:1 vom Atmega, ich habe halt nur die
SPI_Transfer Routine angepasst (und natürlich die Ports für CE und CSN),
aber ich glaube ich werde nachher mal den SoftwareSPI 1:1 auf den Atmega
übersetzen, mal gucken ob es dann geht.
> sendet er ein ACK zurück?
AutoACK habe ich momentan aus. Könnte ich zum testen natürlich mal
wieder aktivieren. Vermutlich macht er es aber auch dann nicht.
Für mich siehts bisher einfach so aus, als wenn der Receiver einfach
nicht aktiv ist. PRIM_RX steht aber auf "1" Genauso wie PWR_UP
Ich teste nachher nochmal rum
Hallo Werner,
ja deine Anmerkungen sind natürlich richtig. Habe wie gesagt auch schon
überall Delays und nops zwischen gebaut (auch direkt nach
PORTB|=(1<<PB7)), was jedoch auch nichts änderte. Und wie gesagt, werden
alle Werte richtig übertragen und auch wieder ausgelesen.
Zudem bin ich jetzt auch wieder bei der Semi-Hardware USI-Variante, da
es eh keinen Unterschied machte und ich so ein paar Bytes an Code spare.
Ich werde nachher nochmal versuchen den anderen Code soweit zu
reduzieren, dass ich die Codeoptimierungen abschalten kann, bisher muss
ich -Os oder -O2 nehmen. Vielleicht hat avrgcc beim Tiny2313 auch ne
Macke und kloppt mir da was kaputt. Mal schauen was passiert.
Benutzt Du den ATtiny 2313 oder den 2313A?
Der 2313A unterscheidet sich zwar nur geringfügig vom 2313, aber in
seiner Definitionsdatei tn2313Adef.inc sind mir z.B. im Interrupt
Bereich folgende Fehler aufgefallen:
original:
; GIMSK - General Interrupt Mask Register
.equ PCIE = 5 ;
abgeändert, weil der 2313A auf allen Portpins Change Interrupts hat:
; GIMSK - General Interrupt Mask Register
.equ PCIE1 = 3 ;
.equ PCIE2 = 4 ;
.equ PCIE0 = 5 ;
Vielleicht sind in den USI-Definitionen ähnliche Fehler eingebaut,
die zu unerwünschten Resultaten führen?
So, es läuft nun endlich.
Es war nicht die SPI-Routine schuld.
Und zwar ist es so, dass es scheinbar eklatant wichtig ist, dass beim
RFM70 das Bank1_Reg0_13 in einer gewissen Geschwindigkeit geschrieben
werden muss.
Wenn ich z.B. aus diesen Zeilen
1
for(i=0;i<=8;i++)//reverse
2
{
3
for(j=0;j<4;j++){
4
WriteArr[j]=(Bank1_Reg0_13[i]>>(8*(j)))&0xff;
5
}
6
SPI_Write_Buf((WRITE_REG|i),&(WriteArr[0]),4);
7
}
soetwas mache
1
for(i=0;i<=8;i++)//reverse
2
{
3
for(j=0;j<4;j++){
4
WriteArr[j]=(Bank1_Reg0_13[i]>>(8*(j)))&0xff;
5
_delay_us(10);
6
}
7
SPI_Write_Buf((WRITE_REG|i),&(WriteArr[0]),4);
8
}
oder
1
for(i=0;i<=8;i++)//reverse
2
{
3
for(j=0;j<4;j++){
4
WriteArr[j]=(Bank1_Reg0_13[i]>>(8*(j)))&0xff;
5
6
}
7
_delay_us(40);
8
SPI_Write_Buf((WRITE_REG|i),&(WriteArr[0]),4);
9
}
macht, dann geht es nicht mehr. Also es wird wohl nicht direkt die Zeit
sein, denn den SPI-Clock kann man ja auch verlangsamen, sondern es geht
wohl um die "Anzahl" der fehlenden Clocks zwischen dem Schreiben des
Blocks. Wenn man also das Bank1_Reg0_13-Array anders speichert, sodass
die Zugriffe zu lange dauert (z.B. im PGM-Space) dann gehts nicht mehr,
oder mit etwas glück geht es manchmal.
Schon merkwürdig... muss man nicht verstehen... steht leider auch
nirgends...