Forum: Compiler & IDEs falscher Rückgabewert aus SoftSPI


von Gregor B. (gregor54321)


Lesenswert?

Hallo Zusammen!
Ich verwende das unten stehende Programm, um die SoftSPI am RFM12 
auszulesen. Am LogicAnalyzer kann ich gut sehen, wann und wie ausgelesen 
wird und was hätte auch im uC ankommen müssen.
Leider wird nicht der korrekte Wert unter der Variablen abgelegt sondern 
immer nur 0xFFFF. Woran kann das liegen? Ich suche mir daran schon seit 
Ewigkeiten einen Wolf, bis ich es nun schließlich endlich als Ursache 
identifizieren konnte!
1
unsigned int rf12_rxstatus(void)              {
2
  unsigned int werti=0;
3
  unsigned char i;
4
    uint8_t i_sreg = SREG;      // SREG sichern
5
    cli();                      // Interrupts unterbinden
6
7
  cbi(RF_PORT, CS);
8
    cbi(RF_PORT, SDI);
9
10
  for (i=0; i<16; i++) {  
11
    werti<<=1;
12
    if (RF_PIN&(1<<SDO))
13
      werti|=1;
14
    sbi(RF_PORT, SCK);
15
    _delay_us(0.3);
16
    cbi(RF_PORT, SCK);
17
  }
18
  sbi(RF_PORT, CS);
19
    SREG = i_sreg;
20
  return werti;
21
}
22
23
ISR (INT0_vect) {
24
  [...]
25
    rf12_int0_handler();
26
  [...]
27
}
28
29
void rf12_int0_handler() {
30
  uint16_t status_reg = 0;
31
  status_reg = rf12_rxstatus();
32
  [...]
33
  
34
  char buffa[30];
35
  sprintf(buffa, "Ergebnis: 0x%X\r\n",status_reg);
36
  uart_puts(buffa);
37
}
38
39
uint8_t main(void) {
40
  Activate_INT0;
41
  while(!) {
42
    nop();
43
  }
44
}

von Floh (Gast)


Lesenswert?

Ähm, normalerweise wird beim SPI in der Taktflanke gesampled, nicht 
davor.

>     _delay_us(0.3);
übrigends glaub ich nicht, dass das funktioniert. Was sagt der Compiler?

von Floh (Gast)


Lesenswert?

übrigends, lass als C-Progger das SREG in Ruhe. Wenn du Interrupts 
deaktivierst, dann brauchst du da nichts sichern.
:-)

von Gregor B. (gregor54321)


Lesenswert?

Floh schrieb:
>>     _delay_us(0.3);
> übrigends glaub ich nicht, dass das funktioniert. Was sagt der Compiler?

Der Compiler nimmt's gelassen. Laut delay.h:
     void   _delay_us (double __us)
wird also gleich zu _delay_us(0) optimiert. Der High-Impuls dauert bei 
mir etwa 0.6us. ICH HAB'S ABER AUCH BLOß AUS 'NER LIBRARY KOPIERT... 
schäm
Die Sache mit dem SREG hab ich mir (aus alten ASM Zeiten) so angewöhnt. 
So kann ich solche Funktionen auch z.B. aus einer ISR anspringen, ohne 
das mir die INTs freigegeben werden.

Ich verstehe aber trotzdem nicht, warum bei SDO Dauer-Low 0xFFFF zurück 
gegeben wird. Stimmen denn die Übergaben der Variablenkopien und sind 
deren Typen kompatibel?

von Floh (Gast)


Lesenswert?

Schreib die Schleife mal testweise so um, damit du in der Taktflanke 
statt davor samplest:

Gregor B. schrieb:
> for (i=0; i<16; i++) {
>     werti<<=1;

>     sbi(RF_PORT, SCK);

>     _delay_us(0.3);

>     if (RF_PIN&(1<<SDO))
>       werti|=1;

>     _delay_us(0.3);

>     cbi(RF_PORT, SCK);

:-)

von Edi R. (edi_r)


Lesenswert?

Obwohl ein paar Unschönheiten enthalten sind, sollte zumindest die 
Routine rf12_rxstatus funtionieren. Stimmt denn der Rest des Programms, 
speziell die defines für RF_PORT, RF_PIN, CS, SDI, SDO und SCK? Sind die 
Datenrichtungsregister richtig eingestellt (SDO als Eingang)?

von Gregor B. (gregor54321)


Lesenswert?

In der Lib sind wahrlich noch mehrere Unschönheiten wie
1
RF_DDR  = (1<<SDI)|(1<<SCK)|(1<<CS);
anstelle von
1
RF_DDR  |= (1<<SDI)|(1<<SCK)|(1<<CS);
 Ich hab auch den Sample-Zeitpunkt geändert. Danke Floh!
Aber daran allein hat es hier nicht gelegen! Ich hab nochmal den 
Messkopf in die Hand genommen: ICH HASSE DAS BLÖDE JTAG-INTERFACE!!! 
Ich hab JTAG schon über die Software ausgeschaltet wenn PINx auf Low. 
Aber wenn der Stecker von Dragon noch drauf steckt, zieht der die 
Pegel(!!), die ich über Widerstände zum RFM gelegt hatte. LA natürlich 
am RFM angesteckt, an dem natürlich noch das Richtige rauskommt, nur 
eben nicht mehr beim uC rein...

ICH DAAAANKE EUCH !!

so, genug rumgebrüllt. ;o)

von Rolf M. (rmagnus)


Lesenswert?

Gregor B. schrieb:
> Floh schrieb:
>>>     _delay_us(0.3);
>> übrigends glaub ich nicht, dass das funktioniert. Was sagt der Compiler?

Warum sollte es nicht?

> Der Compiler nimmt's gelassen. Laut delay.h:
>      void   _delay_us (double __us)
> wird also gleich zu _delay_us(0) optimiert.

Kommt halt auf den Prozessortakt an. Bei z.B. 3,3 Mhz sind 0,3 µs ja 
gerade mal ein Taktzyklus.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.