Forum: Mikrocontroller und Digitale Elektronik SPI: EA DOGS102 verträgt sich nicht mit EEPROM 25C080


von Martin S. (maklin)


Angehängte Dateien:

Lesenswert?

Hallo allerseits!

Es geht um die im Bild dargestellte Schaltung, wobei ich nur den Teil 
darstelle, der meiner Meinung nach relevant ist.
Der Mikrocontroller (Atmega8L) soll über SPI sowohl mit einem EEPROM als 
auch mit dem Display EA DOGS102 kommunizieren. Dazu wird das jeweilige 
Bauteil per CS-Leitung aktiviert. Solange ich nur mit dem Display 
"spreche", funkioniert das ganze auch problemlos. Kommt allerdings ein 
einzelner Zugriff auf das EEPROM hinzu, dann werden keine Informationen 
mehr auf dem Display dargestellt.
Nun der Reihe nach:
1
int main(void)
2
{
3
  spi_init();
4
  EEPROM_INIT();
5
  EEPROM_READ_DATA(0);
6
  LCD_Init();
7
  zeile=7;
8
  spalte=16;
9
  LCD_Clear();
10
  write_zeichen8('T');
11
  write_zeichen8('e');
12
  write_zeichen8('s');
13
  write_zeichen8('t');
14
  while(1) asm volatile("nop");
15
}
Ich mache es mal ganz ausführlich. Zunächst wird das SPI initialisiert:
1
void spi_init(void)
2
{
3
  //SPI Data Direction Register
4
  DDR_SPI |= (1<<MOSI);
5
  DDR_SPI |= (1<<SCK);
6
  DDR_SPI &=~(1<<MISO);
7
8
  //SPI Control Register
9
  SPCR |= (1<<SPE);
10
  SPCR |= (1<<MSTR);
11
  SPCR |= (1<<CPOL); 
12
  SPCR |= (1<<CPHA);
13
  SPCR &=~ (1<<DORD);
14
  SPCR &=~ (1<<SPR1);
15
  SPCR &=~ (1<<SPR0);
16
17
  //SPI Status Register
18
  SPSR |= (1<<SPI2X); 
19
}
Nachfolgend kann das EEPROM initialisiert (lediglich deselektiert) 
werden (man kann die Funktion mit der SPI-Init tauschen, das macht 
keinen Unterschied):
1
void EEPROM_INIT(void)
2
{
3
  DDR_EEPROM |= (1<<CS_EEPROM); //Ausgang
4
  PORT_EEPROM |= (1<<CS_EEPROM); //deselect
5
}
Nun soll ein Zugriff darauf erfolgen, dies geschieht mit den folgenden 
Funktionen:
1
uint8_t EEPROM_READ_DATA(uint16_t adresse)
2
{
3
  EEPROM_check_busy();
4
  
5
  PORT_EEPROM &=~ (1<<CS_EEPROM); //select
6
  EEPROM_RW(READ);
7
  EEPROM_RW((uint8_t)(adresse>>8));
8
  EEPROM_RW((uint8_t)(adresse&0b0000000011111111));
9
  uint8_t ret_val=EEPROM_RW(0);
10
  PORT_EEPROM |= (1<<CS_EEPROM); //deselect
11
  return ret_val;
12
}
13
14
void EEPROM_check_busy(void)
15
{
16
  while (READ_SREG()&0b00000001) _delay_ms(1);
17
}
18
19
uint8_t EEPROM_RW(uint8_t data)
20
{
21
  SPI_SCK_IDLE_LOW();
22
  asm volatile("nop");
23
  uint8_t ret_val=spi_send_and_receive(data);
24
  asm volatile("nop");  
25
  return ret_val;
26
}
27
28
uint8_t READ_SREG(void)
29
{
30
  PORT_EEPROM &=~ (1<<CS_EEPROM); //select
31
  EEPROM_RW(RDSR);
32
  uint8_t ret_val=EEPROM_RW(0);
33
  PORT_EEPROM |= (1<<CS_EEPROM); //deselect
34
  return ret_val;
35
}
36
37
inline void SPI_SCK_IDLE_LOW(void)
38
{
39
  SPCR &=~ ((1<<CPOL)|(1<<CPHA));
40
}
41
42
char spi_send_and_receive (char data)
43
{
44
  SPDR = data;
45
  while (!(SPSR & (1<<SPIF)));
46
  data = SPDR;
47
  return data;
48
}
Jetzt folgt der Zugriff auf das Display. Hierzu wird es zuerst 
initialisiert:
1
void LCD_Init(void)
2
{
3
  EA_DDR|=(1<<EA_CS)|(1<<EA_CD)|(1<<EA_RST);
4
  EA_PORT|=(1<<EA_CS); 
5
  //Reset
6
  EA_PORT&=~(1<<EA_RST);
7
  _delay_ms(1);
8
  EA_PORT|=(1<<EA_RST);
9
  _delay_ms(5);
10
11
  //LCD-Init
12
  write_command(0b01000000); //Display start Line 0
13
  write_command(0b10100001); //SEG
14
  write_command(0b11000000); //COM0-63
15
  write_command(0b10100100); //Set all Pixels to on
16
  write_command(0b10100110); //Display normal/inverse off
17
  write_command(0b10100010); //1/9 (1/65)
18
  write_command(0b00101111); //Booster
19
  write_command(0b00100111); //Set VLCD Resistor Ratio
20
  write_command(0b10000001); //Contrast
21
  write_command(0b00010000); //Contrast
22
  write_command(0b11111010); //Temperatur Compensation
23
  write_command(0b10010000); //Temperatur Compensation
24
  write_command(0b10101111); //Display on
25
  //Ende Init.
26
}
27
28
void write_command(uint8_t cmd)
29
{
30
  SPI_SCK_IDLE_HIGH();
31
  EA_PORT&=~(1<<EA_CS);
32
  EA_PORT&=~(1<<EA_CD); //Command
33
  spi_send_and_receive(cmd);
34
  EA_PORT|=(1<<EA_CS);
35
}

Ich erspare mir an dieser Stelle die genauen Funktionen zum designen der 
Schrift. Letztendlich läuft es auch dort auf diese Funktion hinaus:
1
void write_data(uint8_t data)
2
{
3
  SPI_SCK_IDLE_HIGH();
4
  EA_PORT&=~(1<<EA_CS);
5
  EA_PORT|=(1<<EA_CD); //Data
6
  spi_send_and_receive(data);
7
  EA_PORT|=(1<<EA_CS);
8
}

Wie gesagt, lässt man den Zugriff auf das EEPROM sein, so funktioniert 
die ganze Sache sehr gut. Dazu braucht man nur
1
EEPROM_READ_DATA(0);
auskommentieren.
Ich will natürlich den Zugriff auf das EEPROM ermöglichen. Ich komme 
jedoch in der Fehlersuche nicht mehr weiter. Ich kann am Oszi keine 
Überschneidung des CS-Signals erkennen (wäre ja denkbar). Ebenfall 
scheint das Programm sich nicht in der EEPROM-Funktion aufzhängen, es 
erscheinen erwartungsgemäß 6 SPI-Zugriffe und dann nach ca. 6 ms die 
Zugriffe auf das Display.
Interessanterweise kommt es zu einem zweiten Reset der Schaltung nach 
etwa 150 ms, wenn man den Programmierstecker dran lässt und einen 
elektrischen Reset durchführt (auch in der funktionstüchtigen 
Programmvariante).
Vielleicht hat jemand von euch ja mal eine ähnliche Schaltung aufgebaut 
und auch das Problem gehabt und gelöst, bzw kann mir anderweitig helfen?

Ich bedanke mich schon mal für konstruktive Antworten!

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.