Um einen einfachen ersten Zugang zu I2C-Funktionen zu haben, wurden diese mittels Bitbanging realisiert. Dieses erleichtert
ein Portieren von einem anderen Mikrocontrollersystem oder auf ein anderes Mikrocontrollersystem ungemein. Es sind lediglich
entsprechende Header zu ändern und das Ansprechen von GPIO-Pins zu implementieren.
Bei diesem Bitbangingfunktionen hier geschieht ein Setzen und Rücksetzen eines GPIO-Pins folgenderweise:
- eine logische 1 wird realisiert, in dem der entsprechende Pin als floatender Eingang (Eingang ohne Pull-Up Widerstand)
geschaltet wird. Die logische 1 komm durch den externen "I2C-Pullup Widerstand" von 2,2k zustande und ist u.a. deswegen
wichtig, damit ein Slave die SDA-Leitung bei einem Acknowledge auf 0 legen kann
- eine logische 0 wird realisiert, in dem der entsprechende Pin als Ausgang geschaltet und eine logische 0 angelegt wird.
Zum Verständnis der I2C-Adresse:
|
Es "streiten" sich die Gelehrten, ob die Adresse eines I2C-Gerätes nun eine 7-Bit oder eine 8-Bit Adresse besitzt.
Technisch gesehen ist dieses sogar klar definiert: Es hat eine 7-Bit Adresse, gefolgt von einem read- (logisch1)
oder einem write-Bit (logisch 0). Jetzt kommt das große ABER:
Da die 7-Bitadresse um eine Bitposition innerhalb eines Bytes um eine Position nach links verschoben werden muß,
kann man innerhalb eines Bytes die Adresse so "interpretieren", dass das read/write Bit Bestandteil der Adresse ist (was
in vielen Fällen den Umgang erleichtert). Am Beispiel des HT16K33A WÄRE die Adresse in Wirklichkeit 0x70, die um eine
Stelle nach links geschoben werden muß (was dann 0xE0 ergibt).
0xE0 wäre demzufolge ein Schreibzugriff auf die Adresse 0x70,
0xE1 wäre ein Lesezugrif auf die Adresse 0x70.
Innerhalb dieser I2C Bitbangingfunktionen wird die I2C-Adresse als ein 8-Bit Wert begriffen bei dem das niederwertigste
Bit mittels logischer Verknüpfung AND / OR zwecks Zugriff zum Schreiben oder Lesen gelöscht oder gesetzt wird.
Innerhalb dieser Headerdatei kann folgendes eingestellt werden:
Die GPIO-Pins mit denen eine I2C-Kommunikation vorgenommen wird (hier default
PA1 für SDA und PA2 für SCL)
#define i2c_sda_hi() PA1_float_init()
#define i2c_sda_lo() { PA1_output_init(); PA1_clr(); }
#define i2c_is_sda() is_PA1()
#define i2c_scl_hi() PA2_float_init()
#define i2c_scl_lo() { PA2_output_init(); PA2_clr(); }
Manchen I2C-Devices ist selbst das I2C-Bitbanging noch zu schnell (bspw. dem HT16K33A) und über die aufgeführten
defines kann das Timing verlangsamt werden. Der angegebenen Verzögerungszeiten hinter den #define entspricht etwas
mehr als 1 Mikrosekunde mal dem angegebenen Wert.
#define short_puls 1 // Einheiten fuer einen langen Taktimpuls
#define long_puls 1 // Einheiten fuer einen kurzen Taktimpuls
#define del_wait 1 // Wartezeit fuer garantierten 0 Pegel SCL-Leitung
Die Funktionen von i2c_sw
|
Folgende Funktionen sind in i2c_sw.c definiert:
void i2c_master_init(void);
setzt die Pinanschlüsse, die den I2C Bus realisieren auf logisch 1
void i2c_sendstart(void);
erzeugt die Startcondition des I2C Buses
uint8_t i2c_start(uint8_t addr);
erzeugt die Startcondition auf dem I2C Bus und schreibt anschließend eine 8-Bit Deviceadresse auf den Bus
Rückgabe:
0 wenn ein I2C-Slave geantwortet hat (Acknowledge)
1 wenn kein I2C-Slave geantwortet hat
uint8_t i2c_startaddr(uint8_t addr, uint8_t rwflag);
Diese Funktion ist eine "Kompatibilitätsfunktion" für eine Startfunktion, bei der die I2C-Deviceadresse als 7-Bit Adresse
und das read/write Flag getrennt von einander als Argumente angegeben werden.
Übergabe:
addr : 7-Bitadresse des I2C-Slaves
rwflag : 0 wenn auf den Bus geschrieben werden soll, 1 wenn vom Bus gelesen werden soll
Rückgabe:
0 wenn ein I2C-Slave geantwortet hat (Acknowledge)
1 wenn kein I2C-Slave geantwortet hat
void i2c_stop(void);
erzeugt die Stopcondition des I2C Buses
uint8_t i2c_write(uint8_t data);
schreibt den Wert in data auf dem I2C Bus und liest ein Acknowledge ein.
Rückgabe:
0 wenn ein I2C-Slave geantwortet hat (Acknowledge)
1 wenn kein I2C-Slave geantwortet hat
void i2c_write_nack(uint8_t data);
schreibt den Wert in data auf dem I2C Bus OHNE ein Acknowledge einzulesen
uint8_t i2c_read(uint8_t ack);
liest ein Byte vom I2C Bus
Übergabe:
ACK:
1 : nach dem Lesen wird dem Slave ein Acknowledge gesendet
0 : es wird kein Acknowledge gesendet
Rückgabe:
vom I2C-Bus gelesenes Byte
|