-diese Library dient zum benutzen der I2C-Schnittstelle im Master-Mode
-die I2C-Pins die benutzt werden sollen, müssen im C-File eingetragen werden
(im H-File kann die I2C-Clock-Frq eingestellt werden)
-auf der Hardware dürfen die zwei externen Pull-Up Widerstände (je 4k7) an SCL und SDA nicht vergessen werden, sonst funktioniert das ganze nicht.
-die Library kann als LoLevel-Funktion die Schnittstelle initialisieren und Daten zu einem Slave senden und von einem Slave empfangen.
-es gibt Funktionen um ein einzelnes Datenbyte zu senden/empfangen und Funktionen um mehrere Bytes zu senden/empfangen. In dem Fall müßen die Daten vor dem senden in einem Array stehen bzw. stehen nach dem empfangen in einem Array.
-Die Funktion “UB_I2C1_WriteCMD” sendet nur ein einzelnes Byte an den Slave.
-es gibt auch noch eine “Pausenfunktion” was einfach nur ein Zähler auf 0 ist um z.B. für langsame I2C-Devives eine Wartefunktion einfügen zu können.
-es gibt 3 identische Librarys, getrennt für I2C1, I2C2 und I2C3
-im Beispiel wurde I2C1 benutzt mit dieser Pinbelegung :
1 2 | SCL an PB6 SDA an PB7 |
Voraussetzungen :
1 2 | Benutzte Module der CooCox-IDE : GPIO, I2C Benutzte Librarys : keine |
Funktionen (für I2C1) :
1 2 3 4 5 6 7 8 9 | void UB_I2C1_Init(void); // zum initialisieren der I2C-Schnittstelle int16_t UB_I2C1_ReadByte(uint8_t slave_adr, uint8_t adr); // um ein Byte zu lesen int16_t UB_I2C1_WriteByte(uint8_t slave_adr, uint8_t adr, uint8_t wert); // um ein Byte zu schreiben int16_t UB_I2C1_ReadMultiByte(uint8_t slave_adr, uint8_t adr, uint8_t cnt); // um mehrere Bytes zu lesen int16_t UB_I2C1_WriteMultiByte(uint8_t slave_adr, uint8_t adr, uint8_t cnt); // um mehrere Bytes zu schreiben int16_t UB_I2C1_WriteCMD(uint8_t slave_adr, uint8_t cmd); // ein einzelnes Byte senden int16_t UB_I2C1_ReadByte16(uint8_t slave_adr, uint16_t adr); // 16bit adresse auslesen int16_t UB_I2C1_WriteByte16(uint8_t slave_adr, uint16_t adr, uint8_t wert); // 16bit adresse beschreiben void UB_I2C1_Delay(volatile uint32_t nCount); // Pausenfunktion |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | //-------------------------------------------------------------- // File : main.c // Datum : 07.03.2013 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.0 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der I2C-LoLevel-Library // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_i2c1.h" int main(void) { int16_t wert; SystemInit(); // Quarz Einstellungen aktivieren UB_I2C1_Init(); // Init der I2C1-Schnittstelle // ein Byte vom I2C-Slave mit Adr 0xA0 // aus Register-Adr 0x01 auslesen wert=UB_I2C1_ReadByte(0xA0,0x01); if(wert<0) { // Fehler } // den Wert 0x12 zum I2C-Slave mit Adr 0xC0 // in Register-Adr 0x02 speichern wert=UB_I2C1_WriteByte(0xC0,0x02,0x12); if(wert<0) { // Fehler } UB_I2C1_Delay(400); // kleine Pause nach dem schreiben while(1) { } } |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Hi,
erstmal vielen Dank für deine Lib, die bei mir sehr gut funktioniert.
Ich verwende dein I2C Besipiel und würde gerne 2 Bytes empfangen.
Leider habe ich es bisher nicht zum laufen gebracht.
Wie müsste ich deinen Code anpassen, damit ich das 2. Byte empfangen kann:
Danke!
MfG
Hi Slevin, lad dir mal die Version 1.1 von der Library runter. Da hab ich zwei neue Funktionen eingefügt. Mit denen kann man mehrere Bytes senden/empfangen. In deinem Fall zum empfangen von zwei Bytes würde ein Beispiel so aussehen :
probier das mal aus und schreib ob es funktioniert
dann mach ich die Änderung auch beim STM32F429
Hi, leider funktioniert die Funktion UB_I2C1_ReadMultiByte bei mir (teilweise) nicht. Der Slave (Beschleunigungssensor ADXL345) hängt sich beim lesen der Bytes bzw. bei der Übermittlung der Slave-Adresse (0xA6) auf – kurz bevor ich die Bytes lesen möchte.
Ich habe zusätzlich eine Stop-Sequenz vor der zweiten Start-Sequenz eingefügt (laut Datenblatt).
Ein einzelnes Byte kann ich problemlos lesen, nur zwei klappen irgendwie nicht.
lass mal die zusätzliche “STOP-Sequenz” weg, und probier es nochmal … und schau mal um Debugger nach welchen Rückgabewert die Funktion liefert. Da sieht man wo sie rausfliegt.
es klappt!!! Ich habe testweise das Auslesen der Register in den IRQHandler geschoben und nun funktioniert es. Irgendwie scheint der Timer die I2C Kommunikation zu stören, das muss ich nochmal genauer anschauen.
Also, deine I2C Funktionen laufen einwandfrei.
Vielen Dank nochmals!
Hi, könnte man die I2C Schnittstelle auch mit DMA realisieren?
Klar kann man das, sie StdLibs Beispiel 2 Boards
Hallo,
ich bin noch recht neu auf dem Gebiet der Mikrocontroller und habe seit kurzem mit dem stm32f4 zu tun.
Ich möchte mit I2C arbeiten, als IDE verwende ich KeilµVision 4 (Laborrechner unserer Uni).
Leider bekomme ich es nicht zum Laufen, über Hilfe freue ich mich sehr.
Grüße, Ilyas
deine Fehlerbeschreibung “leider bekomme ich es nicht zum laufen” ist zu kurz. Lese dich in die Funktionsweise vom I2C-Protokoll ein, messe die Signale nach, vergleiche den Ist-Zustand mit dem Soll-Zustand und schreib dann nochmal was genau nicht funktioniert wie es soll.
Hallo,
entschuldige, dass es bissl unglücklich (und zu kurz) formuliert habe, mein Fehler.
Die Funktionsweise des I2C ist mir im Grunde klar. Ich möchte das dicovery-board einem I2c-fähigen AD-Wandler verbinden (ADS7830 von Texas Instruments).
Wie die Anfrage vom Discoveryboard an den ADC aussehen soll ist mir klar. Leider bin ich mit der Vielzahl der Einstellmöglichkeiten am STM32F4 überfordert.
Ich habe mir dein Beispiel angesehen, bekomme es aber in meiner IDE (Keil µVision 4) nicht zum laufen.
Beste Grüße, Ilyas
schon wieder “bekomm es nicht zum laufen” !! du musst am F4 gar nichts “einstellen” das macht die Library alles für dich und die ist nicht compilerspezifisch.
Guten Abend,
habe mir in diesem Zusammenhang auch die Standard Peripherals Library von ST zum STM32F4 angeschaut. Beim Versuch die dort enthaltenen Beispiele zu nutzen stoße ich auf das Problem, dass während des Linkens Fehler auftauchen wie bespielsweise:
“.\STM32F40_41xxx\STM32F40_41xxx.axf: Error: L6218E: Undefined symbol LCD_Clear (referred from main.o).”
Im entsprechenden readme des Beispielprojekts wird darauf hingewiesen, dass 3 .c-files “Add the following files in the project source list” dem Projekt hinzugefügt werden müssen. Jedoch behebt dies den Fehler nicht.
Mein Board ist das STM32F407VGT6.
Vielen Dank für eure Hilfe.
Grüße, Ilyas
sorry, für linkerfehler bin ich nicht zuständig.
Guten Tag,
arbeite jetzt mit der CoIDE und deinem Beispielcode (18-I2C_LoLevel).
Ich finde die Kommentare und erläuterungen im Code sehr hilfreich, vielen Dank hierfür.
Zunächst will ich mich am Audio-DAC (Cirrus CS43L22) versuchen.
Dieser befindet sich an I2C1 (PB6 bzw. PB9). Von außen habe ich 2x 4,7 kOhm Widerstände mit +3V verbunden, da auf dem Discovery-Board selbst nur für I2C3 Pullups vorhanden sind.
In “stm32_ub_i2c1.h” habe ich für SCL PB6 und für SDA PB9 ausgewählt.
Wenn ich nun beispielsweise die Lautstärke für Kanal A (Master A Vol) schreiben möchte, erhalte ich als Rückgabewert der UB_I2C1_WriteByte eine -2.
Aufruf: UB_I2C1_WriteByte(0×94,0×20,0×00)
0×94 ist die Adresse des Audio-DAC, 0×20 die Register-Adresse für die Lautstärke von Kanal A und 0×00 der zu schreibende Wert für die Lautstärke.
Was habe ich vergessen zu beachten?
Grüße, Ilyas
Fehler gefunden:
Man muss den Audio-DAC noch einschalten. Mit dem Schaltplan des Discovery-Boards wird ersichtlich, dass RESET/ per 10k Widerstand mit Masse verbunden ist…
Ich hoffe, dass diese Information auch für andere User hilfreich ist.
Grüße, Ilyas
Hallo,
kurze Verständnisfrage, meine Main:
int main(void)
{
int16_t wert;
int16_t wert2;
SystemInit(); // Quarz Einstellungen aktivieren
UB_I2C3_Init(); // Init der I2C1-Schnittstelle
wert=UB_I2C3_WriteByte(0×88,0×00,0×02);
if(wert<0) {
// Fehler
}
UB_I2C3_Delay(400); // kleine Pause nach dem schreiben
wert2=UB_I2C3_ReadByte(0×88,0×00);
if(wert2<0) {
// Fehler
}
UB_I2C3_Delay(400);
while(1)
{
}
}
Also isch Schreibe einen Wert 0×02 in ein Register und lese ihn dann wieder aus.
Müsste dann nicht dieser Wert in der Variable wert2 stehen? Bei mir steht da nämlich nur 1 drinnen egal was ich mache ….
Danke
Gruß Michi
was für einen Slave hast du den angeschlossen ? Event. ist die Adresse 0×00 eine Read-Only.
Hallo,
Als Slave habe ich einen TDA7439 (Digitale Klangregelung):
http://www.st.com/web/en/resource/technical/document/datasheet/CD00004906.pdf
angeschlossen… Eine Read Only Adresse kann es nicht sein!
Die 4,7k Ohm Wid. auf 5V sind auch vorhanden.
im Datasheet steht nichts von READ also vermutlich geht das gar nicht. Wenn der Rückgabewert der Write Funktion =0 ist, dann hat das IC mit einem ACK geantwortet und alles sollte gut sein. Du kannst zum Spass ja mal eine andere Slave adresse senden z.B. 0×90 dann sollte eine Fehler zurueckgemeldet werden.
Danke für deine Hilfe!
Hast recht bei einer anderen Addresse kommt ein Fehler.
Hallo,
leider habe ich nun schon länger Probleme mit der I2C Schnittstelle. Ich habe dein Beispiele als Master und als Slave übernommen und diese aufeinander geschalten. Also die I2C1 Schnittstelle als Master auf die I2C2 Schnittstelle als Slave. Aber ich bekomme immer -1 zurück. Auch bei meinen Test mit einem MPU6050 kam immer nur -1 zurück.
Kann mir hier jemand weiterhelfen?
Vielen Dank
Hast du die Beispiel 1:1 übernommen oder was abgeändert ?
Sind die externen 4k7 Pull-Up Widerstände in SCL und SDA eingelötet ?
Ich denke doch du hast ZWEI STM32F4 benutzt, einer als Master und einer als Slave richtig ? Eine CPU kann nicht Master und Slave gleichzeitig sein (zumindest nicht mit meinen Librarys)
Ich habe nur den Master das richtige Byte schreiben lassen. Sonst habe ich nichts geändert (UB_I2C1_WriteByte(0×70,0×00,0×12);).
Ich habe 2 STMF4 und die Widerstände sind auch vorhanden. Habe auch schon versucht die internen zu nehmen. Habe PB8 mit PB8 und PB7 mit PB7 verbunden. Leider ohne Erfolg. LED bleibt Rot und return Value ist -1.
hast du auch GND von beiden Boards verbunden ?
Hast du die Änderung für PB8 in beiden C-Files (Master und Slave) gemacht ?.Laufen beide Boards mit der richtigen Frequenz ?. Zur Not wirst du mit dem Oszi Fehler suchen müssen. Die Librarys funktionieren (hab ich beide getestet)
Ja, habe ich alles gemacht. Hatte heute die Möglichkeit mit einem Oszi zu messen. Der Master scheint richtig zu arbeiten. Nur antwortet der Slave nicht.
sorry, da kann ich nicht helfen. Event. sendet der Master schon Daten bevor der Slave bereit ist.
Mach mal eine Pause von 1sec bevor das Byte zum Slave gesendet wird. Und schalte den Slave zuerst ein.
hallo alle zuzamen ..konnte vlt jemanden mir helfen !!!!
ich versuche mehere byte von meine Sensor zu lesen aber irgenwie klappt es nicht mit diese funktion
UB_I2C2_ReadMultiByte(uint8_t slave_adr, uint8_t adr, uint8_t cnt)!!!
ich kann nur eine byte lesen mit das andere funktion
bitte kann mir jemanden helfen ??
was für ein “Sensor” ist das ? Und welche Daten willst du auslesen ?
Hallo,
ich wollte diese Funktionen heute abend mal testen. da ich schon recht viel mit I2C gemacht habe frage ich mich allerdings, wie hier NAK und ACk gehandhabt werden, bzw das Einfügen von Stop Bits? Das ist bei jedem Baustein anders, daher macht es auch wenig Sinn I2C auf High-Level zu schreiben. Wichtig sind nur die Timeouts, da mit jedem beliebigen Busfehler gerechnet werden muss.
Ich wollte das heute abend mal mit einem 24LC32 von Microchip testen.