Forum: Mikrocontroller und Digitale Elektronik Atmega als SPI Slave


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von spi (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, ich möchte mit einem Atmega als SPI Slave Daten von einem anderen 
IC empfangen, der als Master läuft. Den Atmega habe ich wie folgt 
konfiguriert:
1
SPI.c
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include "uart.h"
5
6
unsigned char status;
7
8
void spi_slave_init (void) {
9
  DDRB |= (1<<PB6);              //MISO output
10
  //SPI on + Interrupt, MSB first, Slave select, CLK idle low, sample rising edge
11
  SPCR = (1<<SPE) | (1<<SPIE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA);        
12
  status = SPSR;                //Status löschen
13
}
14
15
char spi_slave_receive(void)
16
{uint8_t dummy;
17
/* Wait for reception complete */
18
while(!(SPSR & (1<<SPIF)));
19
dummy=SPDR;
20
/* Return Data Register */
21
return SPDR;
22
}

Allerdings bin ich beim Empfang nicht sicher, wie das richtig gemacht 
wird.
1
SETREG_DATA   // grün
2
SETRXTX       // blau
3
4
SPDR=0x00;
5
byte2=spi_slave_receive();
6
if(byte2==0x13) uart_puts_P("byte2");  // Inhalt soll testweise per UART ausgegeben werden (code von Peter Fleury)
7
else uart_puts_P("xxx");
8
  
9
_delay_ms(20);
10
CLRREG_DATA
11
CLRRXTX

Auf dem Bild im Anhang ist zu sehen, wie der Master-IC bei Aktivierung 
der beiden Ports (grün & blau) kurz den Clock inaktiv setzt und dann 24 
Bit sendet. Ein SS vom Master aus gibt es nicht, deshalb habe ich den 
Atmega SS dauerhaft auf GND gelegt.

von J.-u. G. (juwe)


Lesenswert?

spi schrieb:
> SPCR = (1<<SPE) | (1<<SPIE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA);
Wenn Du den SPI-Interrupt nicht nutzt, brauchst Du auch nicht SPIE 
setzen.

> dummy=SPDR;
> /* Return Data Register */
> return SPDR;
Warum dieser doppelt hintereinander ausgeführte Zugriff auf SPDR?

> Allerdings bin ich beim Empfang nicht sicher, wie das richtig gemacht
> wird.
Falls Dein Code nicht funktioniert, gib doch bitte eine richtige 
Fehlerbeschreibung.

> if(byte2==0x13) uart_puts_P("byte2");  // Inhalt soll testweise per UART 
>ausgegeben werden
Hier wird nicht der Inhalt ausgegeben, sondern der Text "byte2".

von spi (Gast)


Lesenswert?

J.-u. G. schrieb:
> spi schrieb:
>> SPCR = (1<<SPE) | (1<<SPIE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA);
> Wenn Du den SPI-Interrupt nicht nutzt, brauchst Du auch nicht SPIE
> setzen.
>
OK, das hatte ich mal testweise auch versucht.
>> dummy=SPDR;
>> /* Return Data Register */
>> return SPDR;
> Warum dieser doppelt hintereinander ausgeführte Zugriff auf SPDR?
>
Hatte irgendwo gelesen, dass man das vorher nochmal auslesen müsse.
>> Allerdings bin ich beim Empfang nicht sicher, wie das richtig gemacht
>> wird.
> Falls Dein Code nicht funktioniert, gib doch bitte eine richtige
> Fehlerbeschreibung.
>
Naja, wenn ich spi_slave_receive() aufrufe bleibt er halt in der while 
hängen und es passiert nichts mehr.
>> if(byte2==0x13) uart_puts_P("byte2");  // Inhalt soll testweise per UART
>>ausgegeben werden
> Hier wird nicht der Inhalt ausgegeben, sondern der Text "byte2".
Ja zumindest sollte der Inhalt geprüft werden.

Wenn ich im Debugmodus in das SPDR was schreibe, müsste ich das doch in 
der Registeranzeige rechts sehen oder? Wenn ich z.B. SPDR=0x01; 
schreibe, tut sich da allerdings gar nichts.

von spi (Gast)


Lesenswert?

Keiner ne Idee?

von J.-u. G. (juwe)


Lesenswert?

spi schrieb:
> Naja, wenn ich spi_slave_receive() aufrufe bleibt er halt in der while
> hängen und es passiert nichts mehr.
Woran erkennst Du, dass er genau da hängen bleibt?

Zeig doch mal mehr von Deiner main()-Funktion.

von schwarz (Gast)


Lesenswert?

Ist das Power Reduction Register richtig gesetzt?
  // Enable SPI (disable it in Power Reduction Register)
  PRR &= ~(1u << PRSPI);
Bin mir aber nicht sicher, ob das nicht schon standardmäßig gesetzt ist.

> Wenn ich im Debugmodus in das SPDR was schreibe, müsste ich das doch in
> der Registeranzeige rechts sehen oder? Wenn ich z.B. SPDR=0x01;
> schreibe, tut sich da allerdings gar nichts.

SPDR besteht aus zwei Registern, eins zum Lesen, eins zum Schreiben. 
Hier hatte ich auch schon das Problem, dass nicht das (für mich) 
richtige angezeigt wurde.

von spi (Gast)


Lesenswert?

J.-u. G. schrieb:
> spi schrieb:
>> Naja, wenn ich spi_slave_receive() aufrufe bleibt er halt in der while
>> hängen und es passiert nichts mehr.
> Woran erkennst Du, dass er genau da hängen bleibt?
>
> Zeig doch mal mehr von Deiner main()-Funktion.

Zumindest kommt er aus der Funktion nicht mehr haeraus, da darauf 
folgende Aufrufe nicht mehr ausgeführt werden.

schwarz schrieb:
> Ist das Power Reduction Register richtig gesetzt?
>   // Enable SPI (disable it in Power Reduction Register)
>   PRR &= ~(1u << PRSPI);
> Bin mir aber nicht sicher, ob das nicht schon standardmäßig gesetzt ist.
>
Da habe ich gar nix mit gemacht, das ist wohl standardmäßig auch nicht 
von Bedeutung.

von spi (Gast)


Lesenswert?

In main steht im Prinzip folgendes (UART-Kram mal entfernt):
1
/* define CPU frequency in Mhz here if not defined in Makefile */
2
#ifndef F_CPU
3
#define F_CPU 1000000UL
4
#endif
5
6
#include <stdlib.h>
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <avr/pgmspace.h>
10
#include <util/delay.h>
11
12
#include "uart.h"
13
#include "adc.h"
14
#include "timer.h"
15
#include "usartspi.h"
16
#include "spi.h"
17
18
19
20
21
/* 2400 baud */
22
#define UART_BAUD_RATE      2400      
23
24
25
/* ~SS line macros. (AD9833) */
26
#define SSPIN     PD6 //!< The pin used as ~SS to slave.
27
#define CSPIN     PD5 //!< The pin used as ~CS to slave.
28
#define SSDDR     DDRD //!< The data direction register for the ~SS line.
29
#define SSPORT    PORTD //!< The port register for the ~SS line.
30
#define SETSSDIR  SSDDR |= (1<<SSPIN); //!< Set output direction for ~SS line.
31
#define SETSSLINE SSPORT |= (1<<SSPIN); //!< Set ~SS line high.
32
#define CLRSSLINE SSPORT &= (0<<SSPIN); //!< Set ~SS line low.
33
#define SETCSLINE SSPORT |= (1<<CSPIN); //!< Set ~CS line high.
34
#define CLRCSLINE SSPORT &= (0<<CSPIN); //!< Set ~CS line low.
35
36
/* ST7540 line macros */
37
#define RSTO        PA2 //!< 
38
#define WD          PD2 //!< 
39
#define BUTHERM     PB7 //!< 
40
#define RXTX        PB2 //!< 
41
#define SETRXTX     PORTB |= (1<<RXTX);
42
#define CLRRXTX     PORTB &= (0<<RXTX);
43
#define REG_DATA    PB1 //!< 
44
#define SETREG_DATA PORTB |= (1<<REG_DATA);
45
#define CLRREG_DATA PORTB &= (0<<REG_DATA);
46
#define CD_PD       PB0 //!< 
47
#define SETSS    PORTB |= (1<<PB4);
48
#define CLRSS     PORTB &= (0<<PB4);
49
50
51
52
int main(void)
53
{
54
55
  CLRREG_DATA
56
  SETRXTX
57
58
  DDRA |= (0<<RSTO);
59
  DDRB |= (1<<RXTX) | (1<<REG_DATA) | (0<<BUTHERM) | (0<<CD_PD);
60
61
62
63
volatile unsigned char byte2, byte1, byte0;
64
65
      
66
          //SPDR=0x01;
67
          
68
          SETREG_DATA
69
      
70
          spi_slave_init();
71
          //SETRXTX
72
      
73
          byte2=spi_slave_receive();
74
          byte1=spi_slave_receive();
75
          byte0=spi_slave_receive();
76
77
          uart_puts_P("byte");
78
      
79
          _delay_ms(20);
80
          CLRREG_DATA
81
          //CLRRXTX
82
  
83
84
//(...)
85
  
86
}

von J.-u. G. (juwe)


Lesenswert?

spi schrieb:
> #define CLRSSLINE SSPORT &= (0<<SSPIN); //!< Set ~SS line low.
...
> #define CLRCSLINE SSPORT &= (0<<CSPIN); //!< Set ~CS line low.
...

> DDRA |= (0<<RSTO);
> DDRB |= (1<<RXTX) | (1<<REG_DATA) | (0<<BUTHERM) | (0<<CD_PD);

Nein, nein, nein! Bitte noch mal hier:
http://www.mikrocontroller.net/articles/Bitmanipulation
nachlesen, wie man Bits löscht.

Du scheinst ja einiges an Peripherie angeschlossen zu haben. Fehlerhaft 
beschriebene Konfigurationsregister können natürlich dann zu Hängern 
führen.

von spi (Gast)


Lesenswert?

Toll Fehler lag dann doch an der Hardware, SPI SCK fehlerhaft 
angeschlossen.

von spi (Gast)


Lesenswert?

J.-u. G. schrieb:
> spi schrieb:
>> #define CLRSSLINE SSPORT &= (0<<SSPIN); //!< Set ~SS line low.
> ...
>> #define CLRCSLINE SSPORT &= (0<<CSPIN); //!< Set ~CS line low.
> ...
>
>> DDRA |= (0<<RSTO);
>> DDRB |= (1<<RXTX) | (1<<REG_DATA) | (0<<BUTHERM) | (0<<CD_PD);
>
> Nein, nein, nein! Bitte noch mal hier:
> http://www.mikrocontroller.net/articles/Bitmanipulation
> nachlesen, wie man Bits löscht.
>
> Du scheinst ja einiges an Peripherie angeschlossen zu haben. Fehlerhaft
> beschriebene Konfigurationsregister können natürlich dann zu Hängern
> führen.

Wäre das so richtig?
1
DDRA |= (0<<RSTO);
2
DDRB |= (1<<RXTX) | (1<<REG_DATA);
3
DDRB &= ~((1<<BUTHERM) | (1<<CD_PD));

von J.-u. G. (juwe)


Lesenswert?

spi schrieb:
> Wäre das so richtig?

> DDRA |= (0<<RSTO);
Nein. Diese Anweisung bewirkt nichts.

> DDRB |= (1<<RXTX) | (1<<REG_DATA);
> DDRB &= ~((1<<BUTHERM) | (1<<CD_PD));

Ja. So ist es richtig.

von spi (Gast)


Lesenswert?

OK danke

von Mario S. (drm)


Lesenswert?

Hallo!
Offenbar handelt es sich hier um den Code für ein Powerline Modem.
Bin selbger grade am Basteln, möchte so etwas basierend auf dem Arduino 
machen.
Bin leider Anfänger, in diesem Bereich und man findet nicht sehr viel 
Code rund um den ST7540.
Würdest du den Code mit mir teilen, damit könnte ich mal starten? Auf 
welcher Schaltung basiert dein Modem?

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.