Forum: Mikrocontroller und Digitale Elektronik ATmega 328P - SPI Interrupt Flag setzt sich nicht zurück


von Viktor B. (coldlogic)


Lesenswert?

Hi Leute,
Ich hab hier ein Problem, wo ich langsam nicht mehr weiter weiß. Mein 
Ziel ist es, mit einem Drehencoder (über Interrupt angebunden, in 
sämtlichen anderen Projekten benutzt => zu 99,8% keine Fehlerquelle) 
8-Bit-Zahlen in einem Array zu speichern und das Array auf Knopfdruck 
per SPI auszugeben. Das Problem dabei: Das Programm bleibt da stecken, 
wo die Daten eigentlich gesendet werden. Interruptangebundene Version 
des Programms hatte den Interrupt genau einmal aufgerufen, und zwar zum 
Zeitpunkt des Hochfahrens - aber auch nicht mehr. Die Polling-Variante 
(beigelegt) steckt in der while(!SPCR&(1<<SPIF))-Schleife fest.
Also der Standardfehler mit dem CS-Pin ist es nicht. Abgesehen davon 
wüsste ich echt nicht, was da noch so falsch sein soll. Das Datenblatt 
dazu hab ich schon quasi als Desktophintergrund, werde aber auch daraus 
nicht schlauer.
Hat irgendjemand einen Ansatz?


-upd.: Ein paar Klammern hinzugefügt. Kein Effekt sichtbar
MfG, Viktor
1
/*
2
 * mainof_SPI_Tx.cpp
3
 *
4
 *  Created on: 08.03.2017
5
 *      Author: Victor
6
 */
7
8
9
#define SR_DATA PD1
10
#define SR_CLOCK PD0
11
#define SR_UPDATE PD2
12
#define SR_PORT PORTD
13
14
#include <avr/io.h>
15
#include <avr/interrupt.h>
16
17
volatile unsigned char code, shift, argl = 0, argp = 0, byte = 0;
18
volatile char argv[42];
19
volatile bool tx_flag, sync_button = 0;
20
21
void out(unsigned char x){              // Function which shows a byte in binary on a shift register w. 8 LEDs
22
  unsigned int last = x;              //get actual parameters
23
  unsigned char i1 = 128;
24
25
  for(char z1=0; z1<8; z1++){            // 8 times decision if 1 or 0 should be written
26
    SR_PORT &= ~(1 << SR_CLOCK);                // PD0 as clock pin held down
27
    if(last>=i1){
28
      SR_PORT |= (1 << SR_DATA);        // PD1 as data pin
29
      last = last-i1;
30
    }
31
    else{
32
      SR_PORT &= ~(1 << SR_DATA);
33
    }
34
    SR_PORT |= (1 << SR_CLOCK);          // Clock pin pulled up to save the data pin position
35
    i1=i1/2;
36
  }
37
  SR_PORT &= ~(1 << SR_UPDATE);          // Pulse the update pin to get the actual value to LEDs
38
  SR_PORT |= (1 << SR_UPDATE);
39
}
40
41
ISR(PCINT2_vect){                  // ISR of port D; rotary encoder interface
42
  if(PIND&(1<<PIND5)){              // ISR called by pushing button?
43
    shift = 3;                  // Set flag
44
  }
45
  else{
46
    if(PIND&(1<<PIND6)){
47
      if(PIND&(1<<PIND7)){          // ISR called by change in pin 6?
48
        shift = 1;              // Encoder turned right if pin 7 already high,
49
      }                    // turned left if pin 7 still low
50
      else{
51
        shift = 2;              // Ze end
52
      }
53
    }
54
  }
55
}
56
57
int main(){
58
  /*Setup*/
59
  cli();                      // No interrupts
60
  DDRD  = 0x0F;                         // Port D i/o: 7--iiiioooo--0
61
  PORTD = 0xF0;                  // Pull-ups D: 7--11110000--0
62
  DDRB  = (1<<PB2)||(1<<PB3)||(1<<PB5);           // Port B i/o: 7--iioiooii--0
63
  PORTB = (1<<PB2)||(1<<PB3)||(1<<PB5);      // Pull-ups B: 7--11010011--0
64
  PCICR = 0b00000100;                // Enabling PCI on port D
65
  PCMSK2 = 0x60;                  // Enable PCI on pin 6 & 5 of port D
66
  SPCR = (1<<SPE)||(1<<MSTR)||(1<<DORD)||(1<<SPR0);//SPI w/o interrupots on; Master; LSB first; Fck/16
67
  sei();                      // Y u no interrupts
68
  /*Program as it is*/
69
  while (1){
70
    if (shift != 0){              // Encoder flag routine
71
      switch (shift) {
72
      default:
73
        break;
74
      case (1):
75
        shift = 0;
76
        byte++;
77
        break;
78
      case (2):
79
        shift = 0;
80
        byte--;
81
        break;
82
      case (3):
83
        shift = 0;
84
        argv[argl] = byte;
85
        argl++;
86
        byte = 0;
87
        break;
88
       }
89
    }
90
    if(!byte){
91
      out(code);
92
    }else{
93
      out(byte);
94
    }
95
96
    if(PIND&(1<<PIND4)){            // if pin D4 is set (standard pulse generator code)
97
      if (!sync_button){            // and its the first cycle being so
98
        tx_flag = 1;              // set transmission start
99
      }
100
      sync_button = 1;
101
    }else{
102
      sync_button = 0;
103
    }
104
    if(tx_flag){
105
      code = 0x01;
106
      PORTD |= (1 << PD3);            // Draw pin PD3 high
107
      while (argp < argl) {
108
        code = 0x02;
109
        SPDR = argv[argp];
110
        while (!(SPSR & (1<<SPIF))){
111
          code = 0x04;
112
          out(code);
113
        }
114
        argp++;
115
      }
116
      argp = 0;
117
      argl = 0;
118
      PORTD &= ~(1 << PD3);            // Draw pin PD3 low
119
      tx_flag = 0;
120
    }
121
  }
122
return 0;
123
}

: Bearbeitet durch User
von Tom (Gast)


Lesenswert?

Wofür ist PD3 gedacht?

von Viktor B. (coldlogic)


Lesenswert?

PD3 ist der CS-pin. Er sagt dem Slave, er sei angesprochen

von Tom (Gast)


Lesenswert?

aber nur bei Low fühlt er sich angesprochen, oder?

von Viktor B. (coldlogic)


Lesenswert?

Der Slave - Chip ist ein wenig komisch, was das angeht. Der wird 
angesprochen, wenn CS auf high ist. Das Problem liegt ja noch davor - 
wie eine Oszilloskopmessung gezeigt hatte, rührt sich weder auf SDA noch 
auf SCL was, und die SPI-Einheit des ATmega verweigert einfach mal den 
Dienst.

von Arno (Gast)


Lesenswert?

Du schreibst die Daten per Software bitweise auf den Portpin, erwartest 
aber, dass die SPI-Hardware erkennt, wenn ein Byte fertig ist? Das kann 
nicht funktionieren.

Entweder du musst dir selbst ein SPIF-Flag generieren oder du musst, 
wenn du das Flag im SPSR nutzen willst, auch den Rest der SPI-Hardware 
nutzen. Also deine Daten senden, indem du sie nach SPDR schreibst. Dann 
kümmert sich die Hardware für dich darum, SR_DATA und SR_CLOCK richtig 
zu setzen. Natürlich bist du dann auf die Pins festgelegt, an die die 
SPI-Hardware angeschlossen ist.

Ein Beispiel dafür ist im Datenblatt enthalten, danach solltest du noch 
einmal genau schauen. Außerdem kannst du auch mal ein paar Beiträge 
weiter nach dem Thema SPI auf ATMega8 funktioniert nicht (oder so 
ähnlich) schauen, da wird das lang und breit diskutiert.

MfG, Arno

von Jim M. (turboj)


Lesenswert?

Viktor B. schrieb:
> rührt sich weder auf SDA noch
> auf SCL was, und die SPI-Einheit des ATmega verweigert einfach mal den
> Dienst.

SDA und SCL wären aber I²C und nicht SPI. Du sprichts in Rätseln.

von Stefan E. (sternst)


Lesenswert?

Viktor B. schrieb:
> Also der Standardfehler mit dem CS-Pin ist es nicht.

Doch, ist es vermutlich, denn ...
1
  DDRB  = (1<<PB2)||(1<<PB3)||(1<<PB5);
du setzt nur PB0 auf Ausgang. ;-)

PS: Ganz davon zu schweigen, dass natürlich auch die ganze 
SPI-Initialisierung auf Grund des gleichen Problems defekt ist.

: Bearbeitet durch User
Beitrag #4947230 wurde vom Autor gelöscht.
von Viktor B. (coldlogic)


Lesenswert?

Arno schrieb:
> Du schreibst die Daten per Software bitweise auf den Portpin

Sorry für die Verwechselung. Die Funktion out(); da oben sendet ein Byte 
an ein angeschlossenes Schieberegister; mit dem SPI hat es gar nichts zu 
tun.

Jim M. schrieb:
> SDA und SCL wären aber I²C und nicht SPI.

Jep, das sollten eig SCK und MOSI sein. Hatte die I^2C-Namen noch im 
Kopf

von Viktor B. (coldlogic)


Lesenswert?

Stefan E. schrieb:
> du setzt nur PB0 auf Ausgang.

Setze ich damit nicht PB2 (SS), PB3 (MOSI) und PB5 (SCK) als Ausgang?

von Stefan E. (sternst)


Lesenswert?

Viktor B. schrieb:
> Stefan E. schrieb:
>> du setzt nur PB0 auf Ausgang.
>
> Setze ich damit nicht PB2 (SS), PB3 (MOSI) und PB5 (SCK) als Ausgang?

Nein.

|| vs |

von Arno (Gast)


Lesenswert?

Viktor B. schrieb:
> Arno schrieb:
>> Du schreibst die Daten per Software bitweise auf den Portpin
>
> Sorry für die Verwechselung. Die Funktion out(); da oben sendet ein Byte
> an ein angeschlossenes Schieberegister; mit dem SPI hat es gar nichts zu
> tun.

Ah, du hast Recht, und beim zweiten Versuch findet die Suchfunktion auch 
die Stelle in deinem Code, an der du SPDR setzt. Muss ich mich vorhin 
vertippt haben...

Viktor B. schrieb:
> Stefan E. schrieb:
>> du setzt nur PB0 auf Ausgang.
>
> Setze ich damit nicht PB2 (SS), PB3 (MOSI) und PB5 (SCK) als Ausgang?

...aber Stefan hat Recht. || ist logisches Oder, | ist bitweises Oder.

MfG, Arno

von Viktor B. (coldlogic)


Lesenswert?

Wusste ich's doch, das der Fehler irgendwas unscheinbares sein wird. Auf 
jeden Fall vielen Dank, der µC scheint sich nicht mehr aufzuhängen! 
Später, wenn ich Zugriff aufs Oszi hab, werde ich weiter schauen. Kudos 
to you!

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.