Probleme mit SS der AVR Hardware SPI im Slave Betrieb

Gast #5729619
Lesenswert?

Hallo,

ich versuche nun schon seit mehreren Stunden einen Atmega8 (oder auch 
Atmega328P) dazu zu überreden als SPI Slave zu laufen, aber es will 
einfach nicht funktionieren.

Wenn ich den !SS Pin manuell auf GND lege, funktioniert die Hardware-SPI 
wie gewünscht, nur eben nicht wenn sie selber den !SS Pin auswerten 
soll.

Minimal Beispiel Hardware-SPI (nur Empfang):
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <inttypes.h>
4

5
#define SPI_SS   PB2
6
#define SPI_MOSI PB3
7
#define SPI_MISO PB4
8
#define SPI_CLK  PB5
9

10
volatile uint8_t BUFFER[256];
11
volatile uint8_t r, w;
12

13

14
void init_uart(uint32_t baud){
15
 uint16_t ubrr = ( (F_CPU + baud * 8) / (16 * baud) ) - 1;
16
 UBRRH = (uint8_t)(ubrr >> 8);
17
 UBRRL = (uint8_t)(ubrr & 0xFF);
18
 UCSRB = (1 << TXEN);
19
 // Asynchron 8N1
20
 UCSRC = (1 << URSEL) | (0 << UMSEL) | (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (0 << UCSZ2) | (1 << UCSZ1) | (1 << UCSZ0);
21
}
22

23
static inline uint8_t send_byte(uint8_t data) {
24
 // Senden, wenn UDR frei ist
25
 if (UCSRA & (1 << UDRE)) {   
26
  UDR = data;
27
  return 1;
28
 }
29
 return 0;
30
}
31

32
ISR(SPI_STC_vect) {
33
 BUFFER[w++] = SPDR;
34
}
35

36
int main(void) {
37
 init_uart(115200);
38
 // MISO Output, Rest Inputs (aber eigentlich egal)
39
 DRB = (1 << SPI_MISO);
40
 // SPI data output register (MISO)
41
 SPDR = 0x00;
42
 // Enable SPI Interrupt, enable SPI, MSB first, SPI Slave, CPOL 1, CPHA 1
43
 SPCR = (1 << SPIE) |  (1 << SPE) | (0 << DORD) | (0 << MSTR) | (1 << CPOL) | (1 << CPHA);
44
 sei();
45
 while(1) {
46
  if ( r != w ) if ( send_byte(BUFFER[r]) ) r++;
47
 };
48
 return 0;
49
}


Das dass SS Signal nicht richtig funktioniert kann ich ausschließen, da 
eine schnell zusammengestrickte Software-SPI (auch nur Empfang) 
anstandslos funktioniert:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <inttypes.h>
4

5
#define SPI_SS   PB2
6
#define SPI_MOSI PB3
7
#define SPI_MISO PB4
8
#define SPI_CLK  PB5
9

10
volatile uint8_t BUFFER[256];
11
volatile uint8_t r, w;
12

13

14
void init_uart(uint32_t baud){
15
 uint16_t ubrr = ( (F_CPU + baud * 8) / (16 * baud) ) - 1;
16
 UBRRH = (uint8_t)(ubrr >> 8);
17
 UBRRL = (uint8_t)(ubrr & 0xFF);
18
 UCSRB = (1 << TXEN);
19
 // Asynchron 8N1
20
 UCSRC = (1 << URSEL) | (0 << UMSEL) | (0 << UPM1) | (0 << UPM0) | (0 << USBS) | (0 << UCSZ2) | (1 << UCSZ1) | (1 << UCSZ0);
21
}
22

23
static inline uint8_t send_byte(uint8_t data) {
24
 // Senden, wenn UDR frei ist
25
 if (UCSRA & (1 << UDRE)) {   
26
  UDR = data;
27
  return 1;
28
 }
29
 return 0;
30
}
31

32
int main(void) {
33
 uint8_t temp;
34
 uint8_t data = 0;
35
 uint8_t bitpos = 0;
36
 uint8_t old_clk = 1;
37
 init_uart(115200);
38
 // MISO Output, Rest Inputs (aber eigentlich egal)
39
 DDRB = (1 << SPI_MISO);
40
 while(1) {
41
  temp = PINB;
42
  // SS high, Reset der bereits empfangenen Daten und des Bitzählers
43
  if ( temp & (1 << SPI_SS) ) {
44
   bitpos = 0;
45
   data = 0;
46
   old_clk = 1;
47
   if ( r != w ) if ( send_byte(BUFFER[r]) ) r++;
48
  }
49
  // SS low
50
  else {
51
   // CLK high
52
   if ( temp & (1 << SPI_CLK) ) {
53
    // steigende Flanke?
54
    if ( !old_clk ) {
55
     if ( temp & (1 << SPI_MOSI) ) data |= 0x01;
56
     if ( ++bitpos > 7 ) {
57
      bitpos = 0;
58
      BUFFER[w++] = data;
59
      data = 0;
60
     }
61
     else {
62
      data <<= 1;
63
     }
64
     old_clk = 1;
65
    }
66
   }
67
   // CLK low
68
   else {
69
    old_clk = 0;
70
    if ( r != w ) if ( send_byte(BUFFER[r]) ) r++;
71
   }
72
  }
73
 };
74
 return 0;
75
}

Das Einzige was ich mir irgendwie vorstellen kann, ist das der SS vor 
der 1. SPI_CLK zu spät runter oder nach der letzten Clock zu schnell 
wieder hoch geht, hab dafür aber keine Information irgendwo gefunden, 
wie lange er vor der ersten SPI_CLK mindestens schon auf low stehen muss 
oder nach der letzten SPI_CLK noch low bleiben muss.

F_CPU ist 14.745600 MHz (Baudraten Quarz)
SPI CLK ist etwa 175 kHz
SS geht 2 SPI_CLK vor der 1. positiven SPI_CLK Flanke auf low und 2 
SPI_CLK nach der letzten positiven SPI_CLK Flanke auf high.

Falls irgendwer dazu Ideen oder Informationen hat, bitte gerne.
Gast #5729855
Lesenswert?

karlman schrieb:
> Tim T. schrieb:
>> Minimal Beispiel Hardware-SPI (nur Empfang):
>>
1
>>  // MISO Output, Rest Inputs (aber eigentlich egal)
2
>>  DRB = (1 << SPI_MISO);
3
>>
>
> Compiliert das denn überhaupt?

Jop, das kompiliert, ist nur beim Copy&Paste bzw. dem bearbeiten beim 
nachträglichen Einrücken ein D verloren gegangen, da steht natürlich 
DDRB = (1 << SPI_MISO);

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren