Forum: Mikrocontroller und Digitale Elektronik Probleme beim Auslesen zweier MCP23S17 mit ATmega2560


von Wilfried S. (wilfried_s)


Lesenswert?

Ich habe zwei MCP23S17, jeweils die Eingänge 0-7 von GPIOA und die 
Eingänge 0-1 von GPIOB beschaltet. Die Eingänge 2-7 von GPIOB sind somit 
ungenutzt und liegen auf Masse.

Als Mikrocontroller verwende ich einen ATmega2560 vom Arduino-Board, 
wobei ich den Controller direkt mit einem ISP-Programmer vom Atmel 
Studio 7 aus beschreibe und nicht die Arduino-IDE dafür verwende.

Die beiden MCP23S17 liegen zusammen auf dem SPI-Bus und haben einen 
gemeinsamen Slave-/Chip-Select (welcher mit einem 10 kOhm 
Pull-up-Widerstand auf High gezogen wird), da ich für die beiden ICs 
Hardware-Adressen (0x01 und 0x02) verwende. Der SPI-Bus ist über 330 Ohm 
Widerstände auf den Leitungen CLK, MOSI und MISO vom Mikrocontroller 
getrennt, da der Mikrocontroller ja über den ISP programmiert wird.

Wenn ich nun den ISP-Programmer vom Mikrocontroller trenne, werden keine 
Daten von den beiden MCPs ausgelesen (auch nicht nach einem Reset). Wenn 
der ISP-Programmer wieder angeschlossen wird, erhalte ich Daten. Aber 
auch in diesem Fall treten merkwürdige Phänomene auf.

Wenn alle Eingänge auf Low sind, erhalte ich von den beiden GPIOs den 
Wert 0 (lasse ich mir auf eine LCD-Anzeige ausgeben). Wenn alle 
verwendeten Eingänge auf High sind erhalte ich von GPIOA auch den Wert 
255 (0xFF) und von GPIOB 3 (0x03). Soweit scheint es ja zu passen.
Wenn alle GPIOs auf High sind (GPIOA Wert 255 und GPIOB Wert 3) und ich 
das Bit 0 an GPIOA auf Low ziehe, wird dieses korrekt erkannt. Wird das 
Bit 0 wieder auf High gesetzt und das Bit 1 auf Low gezogen, werden 
sowohl das Bit 1 (korrekt) als auch das Bit 0 (falsch) als Low erkannt. 
Wenn nun das Bit 2 auf Low ist, werden das Bit 2 (korrekt) und Bit 0 
(falsch) als Low erkannt usw. Wenn also irgendeins der Bits 1 bis 7 an 
GPIOA auf Low gezogen wird, wird fälschlicherweise das Bit 0 ebenfalls 
als Low erkannt.
Dazu kommt dann noch zusätzliches Phänomen: Wenn ich das Bit 7 von GPIOA 
auf Low ziehe, wird das Bit 1 von GPIOB ebenfalls als Low erkannt, 
obwohl ich am GPIOB nichts verändert habe.
Ich vermute, dass entweder der SPI-Bus nicht sauber arbeitet oder aber 
die Register von den GPIOs nicht ganz korrekt ausgelesen werden.

Zunächst wird im Main der SPI als Master initialisiert:
1
 void SPI_Master_Init(void)
2
 {
3
   
4
   DDRB |= (1<<PB2);          // MOSI out
5
   DDRB &=~ (1<<PB3);          // MISO in
6
   DDRB |= (1<<PB1);          // SCK out
7
   DDRB |= (1<<PB0);          // SS out
8
   
9
   PORTB |= (1<<PB0);
10
   
11
   SPCR &=~ (1<<DORD);        // erst MSB senden
12
   SPCR |= (1<<MSTR);          // SPI Master
13
   
14
   // SPI-Mode 0
15
   SPCR &=~ (1<<CPOL);        // Takt Polarität
16
   SPCR &=~ (1<<CPHA);        // Takt Phase
17
   
18
   // CLK-Teiler (128)    // 16 MHz / 128 = 125 kHz
19
   SPCR |= (1<<SPR1);          // CLK-Teiler
20
   SPCR |= (1<<SPR0);          // CLK-Teiler
21
   
22
   SPCR |= (1<<SPE);          // SPI aktivieren
23
}

Dann werden die MCPs initialisiert, da diese ja nach dem Reset "dumm" 
sind, haben die noch die Adresse 0x00.
1
void mcp_init(void)
2
{
3
  mcp_write(0x00, 0x0A, 0x28); // BANK = 0, MCP_SEQOP = 1, MCP_HAEN = 1
4
}

Zum Lesen und Schreiben habe ich folgende Funktionen:
1
uint8_t spi_transfer(uint8_t data)
2
{
3
  SPDR = data;
4
  while(!(SPSR & (1<<SPIF)));
5
  return SPDR;
6
}
1
uint8_t mcp_write(uint8_t adr, uint8_t reg, uint8_t data)
2
{
3
  
4
  PORTB &=~ (1<<PB0);
5
  spi_transfer((0x40 | (adr<<1)));
6
  spi_transfer(reg);
7
  spi_transfer(data);
8
  PORTB |= (1<<PB0);
9
  _delay_ms(1);
10
}
1
uint8_t mcp_read(uint8_t adr, uint8_t reg)
2
{
3
  uint8_t data = 0;
4
  PORTB &=~ (1<<PB0);
5
  spi_transfer((0x41 | (adr<<1)));
6
  spi_transfer(reg);
7
  data = spi_transfer(0xFF);
8
9
  PORTB |= (1<<PB0);
10
  _delay_ms(1);
11
  
12
  return data;
13
}

Im Hauptprogramm wird folgendes in der while-Schleife ausgeführt:
1
wertra = (mcp_read(0x01, 0x12));        // rechts, GPIO A
2
wertrb = (mcp_read(0x01, 0x13));      // rechts, GPIO B
3
4
wertla = (mcp_read(0x02, 0x12));        // links, GPIO A
5
wertlb = (mcp_read(0x02, 0x13));      // links, GPIO B
6
7
8
itoa (wertla, output_linksa, 10);
9
itoa (wertra, output_rechtsa, 10);
10
itoa (wertlb, output_linksb, 10);
11
itoa (wertrb, output_rechtsb, 10);
12
13
14
lcd_clear();
15
_delay_ms(5);
16
lcd_setcursor(0, 1);
17
_delay_ms(5);
18
lcd_string(output_linksa);
19
_delay_ms(5);
20
lcd_setcursor(8, 1);
21
_delay_ms(5);
22
lcd_string(output_linksb);
23
_delay_ms(5);
24
lcd_setcursor(0, 2);
25
_delay_ms(5);
26
lcd_string(output_rechtsa);
27
_delay_ms(5);
28
lcd_setcursor(8, 2);
29
_delay_ms(5);
30
lcd_string(output_rechtsb);
31
_delay_ms(5);

von Geschichten Hörer (Gast)


Lesenswert?

Eine schöne Geschichte hast du uns da erzählt.

Und jetzt?

von S. Landolt (Gast)


Lesenswert?

> da der Mikrocontroller ja über den ISP programmiert wird

Also Frage, am Rande: dieser uC hat 4 USARTs, warum nicht einen davon 
als SPI-Master verwenden?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

> Wenn ich nun den ISP-Programmer vom Mikrocontroller trenne, werden keine
> Daten von den beiden MCPs ausgelesen (auch nicht nach einem Reset). Wenn
> der ISP-Programmer wieder angeschlossen wird, erhalte ich Daten. Aber
> auch in diesem Fall treten merkwürdige Phänomene auf.

Daher vermute ich Probleme mit der Resetbeschaltung und/oder 
Spannungsversorgung des µC und/oder MCP. Dem MCP muss man nach jedem 
Reset seine Registereinstellungen neu mitteilen.

von Maxim B. (max182)


Lesenswert?

Wilfried S. schrieb:
> Der SPI-Bus ist über 330 Ohm
> Widerstände auf den Leitungen CLK, MOSI und MISO vom Mikrocontroller
> getrennt, da der Mikrocontroller ja über den ISP programmiert wird.

Das ist übertrieben und überflüssig: solange RESET aktiv ist (das ist 
beim Programmieren so), werden alle Kontroller-Ausgänge passiv. D.h. IC 
auf SPI können Programmieren nicht stören.

Solche Schutz kann eigentlich nur dann helfen, wenn SPI in Slave-Modus 
sein kann, d.h. von einem anderen Controller als Slave angesprochen.

: Bearbeitet durch User
von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,

und bisher haben wir noch nichts über die Beschaltung der 
Reset-Anschlüsse der MCPs erfahren. Kannst Du Dich dazu bitte noch 
auslassen.

MfG

von Maxim B. (max182)


Lesenswert?

Hätte er kein RESET, so könnte er nicht programmieren. So sollte hier 
alles in Ordnung sein.
Wenn Reset von MCP23S17 nicht angeschlossen ist, dann arbeitet POR.

Wilfried S. schrieb:
> Ich vermute, dass entweder der SPI-Bus nicht sauber arbeitet

So sieht das aus. Die Wege zu MCP23S17 sollten geprüft werden, bei SCK, 
MISO und MOSI. Vielleicht irgendwo schlechte Kontakt. Hilfreich wäre SPI 
auf verschiedenen Frequenzen und sogar mit Programm-SPI versuchen zu 
steuern.

Wilfried S. schrieb:
> _delay_ms(1);

Ich verstehe den Sinn dieses Befehls nicht.

Wilfried S. schrieb:
> Wenn ich nun den ISP-Programmer vom Mikrocontroller trenne, werden keine
> Daten von den beiden MCPs ausgelesen (auch nicht nach einem Reset). Wenn
> der ISP-Programmer wieder angeschlossen wird, erhalte ich Daten. Aber
> auch in diesem Fall treten merkwürdige Phänomene auf.

Das ist klare Indiz dafür, daß man Hardwarenverbindung prüfen sollte.

: Bearbeitet durch User
von Wilfried S. (wilfried_s)


Lesenswert?

Vielen Dank für eure Antworten, die mich nochmal dazu veranlasst haben, 
die elektrische Geschichte zu überprüfen. Manchmal sieht man den Wald 
vor lauter Bäumen nicht und in diesem Fall fehlte eine gemeinsame 
Masse-Verbindung zwischen der Einheit mit dem Mikrocontroller und der 
Einheit mit den beiden MCPs.
Die Einheit mit dem Mikrocontroller versorge ich nämlich über ein 
kleines USB-Netzteil und die Einheit mit den MCPs über ein anderes 
Netzteil. Durch den ISP-Programmer über USB -> PC -> Steckdose -> 
Netzteil kam scheinbar halbwegs eine Masse-Verbindung zustande, sodass 
es zusammen mit dem ISP-Programmer zumindest teilweise (aber auch nicht 
korrekt) funktionierte. Ohne ISP-Programmer ging ja gar nichts, das 
würde immerhin dieses Phänomen erklären.
Mit der nun bestehenden Masse-Verbindung scheint nun alles wie gewünscht 
zu funktionieren. Danke nochmal für eure Anstubser. Da ich zuvor noch 
nichts mit SPI gemacht habe und beim Recherchieren auch nicht auf 
derartige Probleme gestoßen bin, war ich echt verzweifelt. Umso 
peinlicher, dass die Ursache nun etwas Grundlegendes war.


S. Landolt schrieb:
> Also Frage, am Rande: dieser uC hat 4 USARTs, warum nicht einen davon
> als SPI-Master verwenden?

Gute Frage - da habe ich noch nicht drüber nachgedacht.


Maxim B. schrieb:
> Das ist übertrieben und überflüssig

Naja, diese "Empfehlung" habe ich aus der Application Note zu den "AVR 
Microcontroller Hardware Design Considerations" (AN2519) von Microchip.


Christian S. schrieb:
> bisher haben wir noch nichts über die Beschaltung der
> Reset-Anschlüsse der MCPs erfahren

Die Reset-Pins von den beiden MCPs habe ich standardmäßig mit einem 
Pull-up-Widerstand auf High gezogen.

von Maxim B. (max182)


Lesenswert?

Wilfried S. schrieb:
> Naja, diese "Empfehlung" habe ich aus der Application Note

Sie ist "allgemein" gedacht, für alle mögliche Fälle. Und wirklich, wenn 
SPI als Slave arbeiten sollte, oder teilweise als Slave, dann sind diese 
Widerstände wirklich notwendig, da SCK und MOSI von anderen Controller 
gesteuert sein können auch, wenn Reset von zu programmierenden 
Controller aktiv ist. Wenn aber SPI ausschließlich als Master in der 
Schaltung arbeitet, so gibt es niemand außer zu programmierenden 
Controller und Programmator, der diese Leitungen aktiv bedienen kann. 
Laut Datenblatt ist garantiert, daß bei Reset alle Pins hochimpedant 
sind. Deshalb Widerstand an ~CS absolut richtig,anderen aber nicht 
notwendig.

Wilfried S. schrieb:
> Die Reset-Pins von den beiden MCPs habe ich standardmäßig mit einem
> Pull-up-Widerstand auf High gezogen.

Die darfst du auch ohne Widerstand an Vcc schalten. Noch besser, vor 
allem wenn Platine als Versuchsplatine gedacht ist, die mit System-Reset 
zu verbinden. Dann werden die beiden MCP garantiert auch bei dem 
Neustart von Controller in Anfangszustand. Jetzt werden sie resettet nur 
wenn Vcc aus- und dann eingeschaltet wird.

: Bearbeitet durch User
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.