Forum: Mikrocontroller und Digitale Elektronik SPI mit ATMEGA328 als Master und X25020 als slave


von Aa B. (aaab)


Angehängte Dateien:

Lesenswert?

Ich habe das letztes mal vor 2-3 Jahre, SPI mit fertige Arduino
Libraries programmiert.
Heute habe ich mit ATMEGA328p als Master und X25020P(EEPROM) als Slave
konfiguriert. Ich würde sagen 'auf gut Deutsch'- das ist das billigste
von billigste SPI Programm. :)

Also, das Ziel war ein Byte (0x01) schreiben auf Adresse 0x20 und die
geschriebene Byte wieder lesen. Wenn lesen erfolgreich war, leuchtet ein
LED.

Ich wusste was wo angeschlossen werden muss, also nicht zu viel HW
Aufwand.
Datenblatt von x25020p chip:
http://pdf.datasheetcatalog.com/datasheet_pdf/xicor/X25020P_to_X25020SI-2,7.pdf


C code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
#include <string.h>
5
6
7
8
void spi_master_init()
9
{
10
   DDRB = ( (1<<PB2) | (1<<PB3)  | (1<<PB5) );   // /SS as output, MOSI and SCK as output
11
   SPCR = ( (1<<SPE) | (1<<SPR1) | (1<<MSTR)); //SPI Enable, fosc/64, Master mode
12
}
13
14
15
void spi_slave_init()
16
{
17
   DDRB = 0<<PB4;     //MOSI as input
18
   SPCR = 1<<SPE ;
19
}
20
21
22
void SPI_Tx(char data)
23
{
24
   SPDR=data;
25
   while( !(SPSR & (1<<SPIF)) );   //wait until SPIF flag is set, to indicate transmission is complete
26
}
27
28
char SPI_Rx()
29
{
30
   char Rx_char;   
31
   SPI_Tx(0);
32
   while( !(SPSR & (1<<SPIF)) );
33
     Rx_char= SPDR;
34
     
35
   return Rx_char;
36
}
37
38
void write_to_slave()
39
{
40
   PORTB|=1<<PB2;    //take /CS on slave LOW
41
   SPI_Tx(0x06);  //WREN write enable command
42
   PORTB&=~(1<<PB2);    //take /CS on slave HIGH
43
   
44
   PORTB|=1<<PB2;    //take /CS on slave LOW
45
   SPI_Tx(0x02);  //WRITE instruction
46
   SPI_Tx(0x20);  //Address to write data to
47
   SPI_Tx(0x01);  //Data to be written
48
   PORTB&=~(1<<PB2);    //take /CS  on slave HIGH
49
}
50
51
char read_from_slave()
52
{
53
   char recvd_char;
54
   PORTB|=1<<PB2;    //take /CS on slave LOW
55
   SPI_Tx(0x03);  //READ instruction
56
   SPI_Tx(0x20);  //Address to be read from
57
 
58
   recvd_char = SPI_Rx();
59
   return recvd_char;
60
}
61
62
int main (void)
63
{
64
   DDRC=0xff;   //PORTC as output
65
  
66
   
67
   char recvdchar=0;
68
   
69
   spi_master_init();
70
   spi_slave_init();
71
   
72
   write_to_slave();
73
   
74
   recvdchar=read_from_slave();
75
76
   if(recvdchar==0x01)
77
    PORTC=1<<PC0;
78
79
80
81
82
}


Das Problem ist nun, LED leuchtet nicht wie erwartet. Was habe ich 
falsch gemacht!?

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Der uC ist der Master - wozu also dieses spi_slave_init()?

von Aa B. (aaab)


Lesenswert?

S. Landolt schrieb:
> Der uC ist der Master - wozu also dieses spi_slave_init()?

um die MOSI pin in DDRB explizit als Input zu deklarieren, hätte ich in 
spi_master_init() schreiben können aber fand ich übersichtlicher es 
separat zu schreiben!

von S. Landolt (Gast)


Lesenswert?

In spi_slave_init() steht
> SPCR = 1<<SPE ;
damit wird das
> SPCR = ( (1<<SPE) | (1<<SPR1) | (1<<MSTR));
aus spi_master_init() glatt überschrieben.

> PORTB|=1<<PB2;    //take /CS on slave LOW
> PORTB&=~(1<<PB2);    //take /CS on slave HIGH
Das ist doch jeweils genau umgekehrt, oder hängt ein Inverter 
dazwischen?

von Aa B. (aaab)


Lesenswert?

S. Landolt schrieb:
> In spi_slave_init() steht
>> SPCR = 1<<SPE ;
> damit wird das
>> SPCR = ( (1<<SPE) | (1<<SPR1) | (1<<MSTR));
> aus spi_master_init() glatt überschrieben.

Das stimmt, muss ich korrigieren!

>> PORTB|=1<<PB2;    //take /CS on slave LOW
>> PORTB&=~(1<<PB2);    //take /CS on slave HIGH
> Das ist doch jeweils genau umgekehrt, oder hängt ein Inverter
> dazwischen?
/CS ist ein active low auf dem IC, und auf dem Master /SS ist active 
low.

von Aa B. (aaab)


Lesenswert?

Das is auch quatsch!
DDRB = 0<<PB4;     //MOSI as input

Sollte so sein oder?
DDRB |= ~(1<<PB4);     //MOSI as input

von S. Landolt (Gast)


Lesenswert?

Ich hätte es ganz weggelassen, der Reset-Wert ist ja 0, ansonsten
DDRB &= ~(1<<PB4);     //MOSI as input

von S. Landolt (Gast)


Lesenswert?

Nicht nur der Reset-Wert, PB4 wird auch explizit auf 0 gesetzt mit dem
DDRB = ...
in spi_master_init().

von Aa B. (aaab)


Lesenswert?

S. Landolt schrieb:
> Nicht nur der Reset-Wert, PB4 wird auch explizit auf 0 gesetzt mit
> dem
> DDRB = ...
> in spi_master_init().

Ja dass stimmt, danke für den Tipp!

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.