Forum: Mikrocontroller und Digitale Elektronik Master <->Slave SPI - Kommunikationsprotokoll


von Viktor (Gast)


Lesenswert?

Hallo allerseits!

Ich versuche zur zeit ein Kommunikationsprotokoll zwischen ATmega128 und 
ATMega8 aufzubauen.

Der Master schick zuerst ein CMDByte an den Slave, dieser entscheidet 
was demnächst geschieht. Wenn der MSBit(R/W-Bit) im CMDByte gesetzt ist, 
dann sollen die Daten gelesen wereden, d.h. es kommen nach dem CMDByte 
keine Daten mehr an. Slave wertet die untersten 5Bits aus dem CMDByte 
aus und entscheidet je nach Befehl, welche Daten in den Sendepuffer 
gelegt werden sollen. Anschließend teilt er dem Master mit Hilfe des 
BUSY Signals mit, dass er die Daten jetzt abholen kann. Darauf hin 
schickt Master die entsprechende anzahl der Dummy-Bytes zum Slave.

Im Schreibmodus soll Master die Möglichkeit haben, entweder sehr kurze 
Befehle an Slave (nur den Befehlsbyte(CMDByte)), oder nach dem CMDByte 
auch weitere Bytes mit dazugehörigen Parametern senden zu können.

CMDByte
MSB
[RWBit|X|X|CMDBit4|CMDBit3|CMDBit2|CMDBit1|CMDBit0]

Pinbelegung________
ATMega182    ATMega8
MISO <======= MISO
MOSI =======> MOSI
SCK ========> SCK
/SS ========> /SS
PE7 <======== PB1(BUSY)

Nun zu meinem Problem...
Die Hardware funktioniert schon, die Übertragung funktioniert in beiden 
Richtungen. Ich kann mehrere Bytes aus dem voreingestellten Puffer 
lesen.
Auch wenn ich zuerst ein CMDByte mit dem Schreibbefehl sende um den 
Puffer zu manipulieren, klappt es ebenfalls, denn ich finde die Zahl 
auch in den gelesenen Daten wieder.

Nun, wenn ich jetzt aber beim Schreibvorgang auch paar Bytes hinterher 
sende und anschließend versuche die Daten aus dem Puffer zu lesen, 
erhalte nur 0 0 0 0 anstatt 9 33 1 1.

Hat jemand schon so etwas gemacht?
Wie könnte man das ganze noch verbessern (Programmiertechnisch)?

Da ich mich noch nicht soo gut in Sachen C auskenne, bitte ich um Hilfe.
1
//######### Master ############################################################
2
int main(void){
3
4
  unsigned char i,dummy,data,k=0;
5
  unsigned char rxdata[5]= {};
6
  unsigned char txdata[5]= {9,1,2,9};
7
  char buffer [10]= {0};
8
  
9
  glcd_print(0,0,"write...");
10
  
11
  PORTB &= ~(1<<PB0);       // /SS Pin am Slave auf low
12
  dummy= spi_transceive(0x12);    // Commandobyte (RWBit(7)=0,lesen + Befehl 0x12)
13
  PORTB |= (1<<PB0);      // /SS Pin am Slave auf high
14
  _delay_us(5);
15
  /*
16
  while(!(PINE & (1<<PE7)));    // Warte bis Slave bereit(solange PE7=0)
17
  PORTB &= ~(1<<PB0);       // /SS Pin am Slave auf low
18
  for(i=0;i<4;i++){      // sende daten
19
    data= txdata[i];
20
    dummy= spi_transceive(data);
21
    _delay_us(5);
22
  }*/
23
24
  delay_nms(2000);
25
  glcd_print(0,0,"read...");
26
  
27
  PORTB &= ~(1<<PB0);       // /SS Pin am Slave auf low
28
  dummy=spi_transceive(129);    // Commandobyte (RWBit(7)=1,lesen + Befehl 0x01)
29
  PORTB |= (1<<PB0);      // /SS Pin am Slave auf high
30
  _delay_us(5);        // !muss noch evtl. noch verringert werden
31
  
32
  while(!(PINE & (1<<PE7)));    // Warte bis Slave bereit(solange PE7=0)
33
  PORTB &= ~(1<<PB0);       // /SS Pin am Slave auf low
34
  for(i=0;i<4;i++){      // Hole die Daten
35
    rxdata[i]= spi_transceive(0x00);
36
    _delay_us(5);
37
  }
38
  PORTB |= (1<<PB0);      // /SS Pin am Slave auf high
39
  
40
  //Daten ausgeben
41
  for(i=0;i<4;i++){
42
    data= rxdata[i];
43
    sprintf(buffer,"%1d",data);
44
    glcd_print(k,1,buffer);
45
    k+=2;
46
  }
47
48
  return(0);
49
}
50
51
52
//######### Slave ############################################################
53
54
//************************************************************************
55
//    GLOBAL VARIABLES
56
//************************************************************************
57
volatile unsigned char rx_buf[12]= {0x00};  //Schreibpufer
58
volatile unsigned char tx_buf[12]= {0x00};  //Lesepufer
59
volatile unsigned char rx_cnt= 0;                //RX Zähler
60
volatile unsigned char tx_cnt= 0;                //TX Zähler
61
volatile unsigned char CFREG= 0x00;              //ControlFlagRegister
62
static unsigned char cmd_byte= 0x00;            //Commando byte
63
64
enum{DB0= 0,DB1,DB2,DB3,DB4,DB5,DB6,DB7,DB8,DB9,DB10,DB11};
65
volatile unsigned char buffer[10] = {9,1,1,1,5,6,7,8,9,0};
66
67
68
//************************************************************************
69
//    I S R
70
//************************************************************************
71
ISR(SPI_STC_vect){
72
  rx_buf[rx_cnt++]= SPDR;  //Daten Byteweise ins Puffer schreiben
73
  SPDR= tx_buf[++tx_cnt];  //Daten Byteweise aus dem Puffer lesen
74
}
75
76
//************************************************************************
77
//    MAINLOOP
78
//************************************************************************
79
int main(void){
80
  main_init();
81
  
82
  while(1){
83
    if(!(PINB & (1<<P_SS))){      //Übertragung beginnt
84
      while(!(PINB & (1<<P_SS)));    //Warte bis CMDByte übertragen wurde
85
      P_BUSY_LOW();        //Master wartet
86
      cmd_byte= rx_buf[DB0];      //CMDByte abholen
87
      
88
      if(!(cmd_byte & (1<<RW))){      //R/W-Bit=0, Master schreibt
89
        rx_cnt= 0;        //RX Zähler zurücksetzen
90
        P_BUSY_HIGH();        //Master kann die Daten übetragen
91
        while(!(PINB & (1<<P_SS)));    //Warte bis Übertragung abgeschlossen
92
        cmd_byte= cmd_byte & CMDBITS;
93
        switch(cmd_byte){
94
          case 0x12:{
95
            buffer[1] = 33;
96
            //tx_buf[1] = 99;
97
            //unsigned char i;
98
            //for(i=0;i<2;i++){
99
            //  buffer[i]= rx_buf[i];
100
            //}
101
          } break;
102
          
103
        }
104
      }
105
      if((cmd_byte & (1<<RW))){
106
      //else{
107
        cmd_byte= cmd_byte & CMDBITS;
108
        switch(cmd_byte){
109
          case 0x01:{
110
            unsigned char i;
111
            for(i=0;i<4;i++){
112
              tx_buf[i]= buffer[i];
113
            }
114
          } break;
115
        }
116
        
117
        tx_cnt= 0;      //TX Zähler zurücksetzen
118
        SPDR= tx_buf[tx_cnt];    //Erstes Byte in SPDR laden
119
        P_BUSY_HIGH();      //Master kann die Daten abholen
120
        while(!(PINB & (1<<P_SS)));  //Warte bis Übertragung abgeschlossen
121
      }
122
    }
123
    
124
    
125
    
126
  }
127
  return(0);
128
}

von Peter Diener (Gast)


Lesenswert?

Hallo,

wie wird sichergestellt, dass in der ISR im Slave nicht eine zu hohe 
Pufferadresse angesprochen wird, wenn schnell hintereinander Daten 
kommen?

Außerdem weiß ich nicht was passiert, wenn man in einem array nur ein 
Element initialisiert
1
volatile unsigned char rx_buf[12]= {0x00};  //Schreibpufer
Mach das besser in einer Initialisierungsroutine, wenn es wichtig ist, 
dass 0 drin steht.
Außerdem würde ich den Empfangspuffer als Ringpuffer implementieren, es 
sollte aber auch so gehen.

Sonst fällt mir im Moment nichts auf, was nicht funktionieren sollte.

Viele Grüße,

Peter

von Viktor (Gast)


Lesenswert?

Tut ich habe einfach nicht dran gedacht. Die beiden Zähler werden in der 
main_init();
mit 0 initializiert

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.