Forum: Mikrocontroller und Digitale Elektronik MCP23017 IOCON-Register Problem


von Student T. (hberg)


Angehängte Dateien:

Lesenswert?

Hi,

ich versuche mich gerade an einem MCP23017 (i2c) und habe etwas 
Schwierigkeiten beim setzen des IOCON-Registers.

Folgendes funktioniert hervorragend:
1
// reset ic
2
PORTB |= (1 << PORTB1);
3
_delay_ms(100);
4
PORTB |= (1 << PORTB1);
5
6
// GPIOA as OUTPUT
7
i2c_start(MCP23017_ADDR + I2C_WRITE);
8
i2c_write(0x00);
9
i2c_write(0x00);
10
i2c_stop();
11
  
12
// GPIOB as OUTPUT
13
i2c_start(MCP23017_ADDR + I2C_WRITE);
14
i2c_write(0x01);
15
i2c_write(0x00);
16
i2c_stop();
17
18
while (1) {
19
  i2c_start(MCP23017_ADDR + I2C_WRITE);
20
  i2c_write(0x00);
21
  i2c_write(0xFF);
22
  i2c_write(0xFF);
23
  i2c_stop();
24
25
  _delay_ms(100);
26
27
  i2c_start(MCP23017_ADDR + I2C_WRITE);
28
  i2c_write(0x00);
29
  i2c_write(0x00);
30
  i2c_write(0x00);
31
  i2c_stop();
32
33
  _delay_ms(100);
34
}

Um sicherzugehen, dass nach jedem Flash keine Werte in dem IC überleben, 
resette ich ihn vorher. Danach setze ich x00 == GPIOA und x01 == GPIOB 
auf OUTPUT.

http://ww1.microchip.com/downloads/en/devicedoc/21952b.pdf

Ich möchte nun zusätzlich zum oben gezeigten Beispiel das IOCON Register 
verändern. Ersteinmal möchte ich es auf 0x00 setzen, damit es identisch 
ist zum Defaultwert.

Im Datenbatenblatt ist das Register standardmäßig gesetzt auf IOCON = 
0x00. Dadurch ist IOCON.BANK = 0x00 und das wiederum bedeutet laut 
Datenblatt:
"0 = The registers are in the same bank (addresses are sequential)"

Durch IOCON.BANK kann man die Adressen der Register anders anordnen. 
IOCON.BANK = 1 bedeutet, die Adressen liegen in zwei Blöcken. IOCON.BANK 
= 0 bedeutet, die Adressen liegen nacheinander (0x00, 0x01 = GPIOA, 
GPIOB, ..). Laut dem Datenblatt sollte das IOCON Register auf 0x0A oder 
0x0B liegen, da IOCON.BANK = 0. In der Überschrift dagegen steht:
"IOCON – I/O EXPANDER CONFIGURATION REGISTER (ADDR 0x05)"

Welche ist nun die richtige Adresse? Meiner Meinung nach 0x0A und 0x0B, 
da eben IOCON.BANK = 0 durch IOCON = 0x00. Im Anhang der Abschnitt. Aber 
warum steht dann in der Überschrift 0x05, was auf IOCON.BANK = 1 
hindeuten würde? Das verstehe mal einer!

Um nun testweise das IOCON-Register mit 0x00 zu setzen (was es 
eigentlich lt. Datenblatt schon haben sollte), schreibe ich:
1
i2c_init();
2
3
i2c_start(MCP23017_ADDR + I2C_WRITE);
4
i2c_write(0x05); // oder auch 0x0A, geht beides nicht
5
i2c_write(0x00);
6
7
// ...

Danach ist nur noch Port A (0x00) auf OUTPUT gesetzt, Port B bleibt auf 
INPUT. Auch das schreiben auf Port B klappt nicht mehr.

Da ich aber den gleichen Wert für das Register setze, welcher im 
Register bereits gesetzt ist, sollte sich doch eigentlich nichts ändern? 
Ich überschreibe 0x00 mit 0x00. Warum verhält er sich da nun anders, wie 
davor?

Für jeder Hilfe bin ich dankbar.

Gruß,
Kevin

von Student T. (hberg)


Lesenswert?

Fehler gefunden.. ich habe i2c_stop() nach dem i2c_write() beim 
IOCON-Register vergessen...

Falls jemand ähnliche Probleme hat, mit dem hier sollte es auf Anhieb 
klappen:
1
#define F_CPU 16000000
2
 
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include "i2cmaster.h"
6
 
7
#define MCP23x17_ADDR 0x40
8
 
9
// control registers
10
// ONLY VALID WHEN ICON.BANK = 0
11
#define MCP23x17_IODIRA   0x00
12
#define MCP23x17_IODIRB   0x01
13
#define MCP23x17_IOPOLA   0x02
14
#define MCP23x17_IOPOLB   0x03
15
#define MCP23x17_GPINTENA 0x04
16
#define MCP23x17_GPINTENB 0x05
17
#define MCP23x17_DEFVALA  0x06
18
#define MCP23x17_DEFVALB  0x07
19
#define MCP23x17_INTCONA  0x08
20
#define MCP23x17_INTCONB  0x09
21
#define MCP23x17_IOCON    0x0A
22
//#define MCP23x17_IOCON    0x0B
23
#define MCP23x17_GPPUA    0x0C
24
#define MCP23x17_GPPUB    0x0D
25
#define MCP23x17_INTFA    0x0E
26
#define MCP23x17_INTFB    0x0F
27
#define MCP23x17_INTCAPA  0x10
28
#define MCP23x17_INTCAPB  0x11
29
#define MCP23x17_GPIOA    0x12
30
#define MCP23x17_GPIOB    0x13
31
#define MCP23x17_OPLATA   0x14
32
#define MCP23x17_OPLATB   0x15
33
 
34
// IOCON register bit positions
35
#define MCP23x17_IOCON_BANK   7
36
#define MCP23x17_IOCON_MIRROR 6
37
#define MCP23x17_IOCON_SEQOP  5
38
#define MCP23x17_IOCON_DISSLW 4
39
#define MCP23x17_IOCON_HAEN   3
40
#define MCP23x17_IOCON_ODR    2
41
#define MCP23x17_IOCON_INTPOL 1
42
 
43
int main(void)
44
{
45
 
46
  // init i2c
47
  i2c_init();
48
 
49
  // IOCON
50
  // configuration register
51
  i2c_start(MCP23x17_ADDR + I2C_WRITE);
52
  i2c_write(MCP23x17_IOCON);
53
  i2c_write(0x00
54
    | (0 << MCP23x17_IOCON_BANK)
55
    | (0 << MCP23x17_IOCON_MIRROR)
56
    | (0 << MCP23x17_IOCON_SEQOP)
57
    | (0 << MCP23x17_IOCON_DISSLW)
58
    | (1 << MCP23x17_IOCON_HAEN)
59
    | (0 << MCP23x17_IOCON_ODR)
60
    | (0 << MCP23x17_IOCON_INTPOL)
61
  );
62
  i2c_stop();
63
 
64
  // IODIRA
65
  // set PORTA to OUTPUT
66
  i2c_start(MCP23x17_ADDR);
67
  i2c_write(MCP23x17_IODIRA);
68
  i2c_write(0x00);
69
  i2c_stop();
70
 
71
  // IODIRB
72
  // set PORTB to OUTPUT
73
  i2c_start(MCP23x17_ADDR);
74
  i2c_write(MCP23x17_IODIRB);
75
  i2c_write(0x00);
76
  i2c_stop();
77
 
78
  while (1) {
79
 
80
    // set GPIOA (first write) and GPIOB (second write)
81
    // to HIGH
82
    i2c_start(MCP23x17_ADDR);
83
    i2c_write(MCP23x17_GPIOA);
84
    i2c_write(0xFF);
85
    i2c_write(0xFF);
86
    i2c_stop();
87
 
88
    _delay_ms(100);
89
 
90
    // set GPIOA (first write) and GPIOB (second write)
91
    // to HIGH
92
    i2c_start(MCP23x17_ADDR);
93
    i2c_write(MCP23x17_GPIOA);
94
    i2c_write(0x00);
95
    i2c_write(0x00);
96
    i2c_stop();
97
 
98
    _delay_ms(100);
99
  }
100
}

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.