Forum: Mikrocontroller und Digitale Elektronik Probleme mit SS der AVR Hardware SPI im Slave Betrieb


von Tim T. (tim_taylor) Benutzerseite


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.

von karlman (Gast)


Lesenswert?

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?

von Stefan F. (Gast)


Lesenswert?

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

Warum nicht, SPI_MISO ist 4.

von karlman (Gast)


Lesenswert?

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

.. und DRB?

von Tim T. (tim_taylor) Benutzerseite


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);

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.