Forum: Mikrocontroller und Digitale Elektronik DDR Wechsel I2C


von Dennis A. (dede1989)


Lesenswert?

Hallo,

möchte ich Daten über I2C aus einem Speicherbauchstein auslesen muss ich

1. Die Adresse in den IC schreiben

und dann 2. die Daten empfangen.

Da das ja beides über einen PIN (SDA) laufen soll, muss ich zwischen 1 
und 2 folglich irgendwie von Output auf Input wechseln. Kann ich das so 
machen ohne irgendwelches Fehlverhalten zu erzeugen oder muss das anders 
gelöst werden?


Viele Grüße

Dennis

von Dr.PillePalle (Gast)


Lesenswert?


von Dennis A. (dede1989)


Lesenswert?

Dr.PillePalle schrieb:
> Da hilft nur lesen
> http://de.wikipedia.org/wiki/I2c

Hätte wohl nicht gefragt wenn ich mich nicht schon eingelesen hätte. Für 
mich steht da (Wikipedia) keine Antwort auf meine Frage.

von Ma (Gast)


Lesenswert?

Warum sollte der Wechsel zwischen Aus- und Eingang Fehlverhalten 
erzeugen?
Was für ein Fehlverhalten stellst Du Dir vor?

Wie der Lesevorgang aus Deinem (für und unbekannten) Speicher auszusehen 
hat, steht normalerweise sehr ausführlich im zugehörigen Datenblatt. Je 
nach Controller (welcher wissen wir ebenfalls nicht) gibt es auch noch 
bergeweise Beispielcode oder Bibliotheksfunktionen, die wahrscheinlich 
genau das machen, was Du gerne hättest...

von spess53 (Gast)


Lesenswert?

Hi

>möchte ich Daten über I2C aus einem Speicherbauchstein auslesen

Womit? Bei einem Controller mit I2C-Interface brauchst du dich um so 
etwas nicht kümmern.

MfG Spess

von Andreas (Gast)


Lesenswert?

Deine Frage ist Vergleichbar mit folgender:

"Ich möchte mein Auto rückwärts einparken. Dazu brauche ich ja den 
Rückwärtsgang. Ist der jetzt vorne Links, oder hinten Rechts bei der 
H-Schaltung? Und muss ich sonst noch etwas beim Einparken beachten?"

Überleg mal was wir alles wissen sollten um dir Fragen überhaupt 
beantworten zu können.

von Borsty B. (mantabernd)


Lesenswert?

Ich denke der TO will wissen ob er beim Lesen / Schreiben dass 
DDR-Register seines Controllers von Output auf Input umstellen muss.

-> Im Falle eines Atmel µC und falls du die Hardware TWI Schnittstelle 
verwendest musst du das nicht, da sich die Hardware selbst darum 
kümmert.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Dennis A. schrieb:
> Dr.PillePalle schrieb:
>> Da hilft nur lesen
>> http://de.wikipedia.org/wiki/I2c
>
> Hätte wohl nicht gefragt wenn ich mich nicht schon eingelesen hätte. Für
> mich steht da (Wikipedia) keine Antwort auf meine Frage.

Naja ob du dich wirklich eingelesen lässt Zweifel.
Wegen dieser Aussage:

Dennis A. schrieb:
> Da das ja beides über einen PIN (SDA) laufen soll, muss ich zwischen 1
> und 2 folglich irgendwie von Output auf Input wechseln.

Wenn du dich eingelesen hättest wäre dir jetzt bekannt, dass I2C Pins 
open drain oder open collector sind...

Außerdem haste nocht nicht gesagt mit welchem Prozessor ausgelesen 
werden soll.

von Dennis A. (dede1989)


Lesenswert?

Borsty Bürste schrieb:
> Ich denke der TO will wissen ob er beim Lesen / Schreiben dass
> DDR-Register seines Controllers von Output auf Input umstellen muss

Richtig

Borsty Bürste schrieb:
> Im Falle eines Atmel µC und falls du die Hardware TWI Schnittstelle
> verwendest musst du das nicht, da sich die Hardware selbst darum
> kümmert.

Es handelt sich um einen Atmel uC, allerdings einen Attiny 2313. Keine 
TWI Schnitstelle. Ich weiß dafür gibt es dann USI....

Es muss aber auch möglich sein das Ganze über normale I/O Pins zu 
realisieren. Dann wäre halt meine Frage die oben genannte. Muss ich Da 
zwischen Input undOutput wechseln?

von Helmut L. (helmi1)


Lesenswert?

Dennis A. schrieb:
> Muss ich Da
> zwischen Input undOutput wechseln?

Im Prinzip ja. Es wird folgendermassen vorgegangen.

Bei I2C sind an den beiden Leitungen Pullup Widerstaende vorzusehen ad 
die Bausteine Opendrain/Opencollector Ausgaenge haben. Das heist der 
Highpegel wird durch den Widerstand erzeugt und der Lowpegel durch das 
durchschalten des Transistors. Fuer dich im Programm bedeutet das du 
must einen Opendrain Ausgang simulieren in deiner Software.

Wenn du eine '1' uebertragen willst stellst du deinen Pin auf Eingang 
(der Pullup sorgt fuer die '1'). Willst du einen '0' uebertragen 
schaltest du das Richtungsregister auf Ausgang und gibts dabei eine '0' 
raus.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Also anstatt auf PORTX zu schreiben, schreibste invertiert auf DDRX.

Ansonsten gibts schon genug Software I2C Librarys im Netz.
http://homepage.hispeed.ch/peterfleury/group__pfleury__ic2master.html
(je nach include ist die mit Hardwaremodul oder nur in Software)

Hätteste das im ersten Post bereits erwähnt, dasse Software I2C machen 
willst, dann hätteste dir so manchen Spruch sparen können!

: Bearbeitet durch User
von Dennis A. (dede1989)


Lesenswert?

Helmut Lenzen schrieb:
> Bei I2C sind an den beiden Leitungen Pullup Widerstaende vorzusehen ad
> die Bausteine Opendrain/Opencollector Ausgaenge haben. Das heist der
> Highpegel wird durch den Widerstand erzeugt und der Lowpegel durch das
> durchschalten des Transistors. Fuer dich im Programm bedeutet das du
> must einen Opendrain Ausgang simulieren in deiner Software.
>
> Wenn du eine '1' uebertragen willst stellst du deinen Pin auf Eingang
> (der Pullup sorgt fuer die '1'). Willst du einen '0' uebertragen
> schaltest du das Richtungsregister auf Ausgang und gibts dabei eine '0'
> raus.

Das ist eine Antwort auf meine Frage. Danke!

Martin Wende schrieb:
> Hätteste das im ersten Post bereits erwähnt, dasse Software I2C machen
> willst, dann hätteste dir so manchen Spruch sparen können!

Hm ja, das liegt glaube ich daran, dass man irgendwie in seiner 
Gedankenwelt ist und es für selbstverständlich hält, dass andere dich 
ad-hoc verstehen. Dafür entschuldige ich mich.

Martin Wende schrieb:
> Also anstatt auf PORTX zu schreiben, schreibste invertiert auf DDRX.
Hab ich auch verstanden. Bleibt nur noch die Frage wie ich dann die 
Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR 
gesprochen..

: Bearbeitet durch User
von Helmut L. (helmi1)


Lesenswert?

Dennis A. schrieb:
> Bleibt nur noch die Frage wie ich dann die
> Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR
> gesprochen..

Dann must du selbstverstaendlich die '0' vom Bus nehmen indem du eine 
'1' auf die oben geschilderte Weise ausgibst. Also das DDR wieder auf 
Eingang stellen.

von Peter D. (peda)


Lesenswert?

1
               PORTx  DDRx
2
Output low:      0     1
3
Output high:     0     0
4
Input:           0     0

High und Input ist also dasselbe.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Dennis A. schrieb:
> Bleibt nur noch die Frage wie ich dann die
> Outputs des EEPROMS lese. Hier wurde ja nur von schreiben durch DDR
> gesprochen..

SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt. 
Währenddessen liest du über das PINx Register die Daten von SDA, nachdem 
du wie oben beschrieben den SDA Pin auf Input gestellt hast.

: Bearbeitet durch User
von Dennis A. (dede1989)


Lesenswert?

Hallo nochmal,

ich habe nun etwas experimentiert und wollte in einer ersten Funktion 
eine Schreiboperation initiieren. Dabei muss ich laut Datenblatt ( 
http://pdf1.alldatasheet.com/datasheet-pdf/view/246254/STMICROELECTRONICS/M24C01WBN3TG.html) 
erst einmal die Folge 1010 000 0 übertragen. Die ersten Bits 
identifizieren den Hersteller, die drei nachfolgenden die Nummer des 
Slaves (bei mir sind E0,E1 und E2 beide auf LOW) und die letzte 0 gibt 
an, dass es sich um einen Schreibvorgang handelt. Wie man in meinem Code 
sieht wird zwischen den Schritten geclockt.

Die Funktionen SDALOW setzt den SDA Pin als Ausgang und schreibt an den 
Port eine 0

Die Funktion SDAHIGH setzt den SDA Pin als Eingang und schreibt an den 
Port eine 1 (Pullup).

Das wurde alles bereits diskutiert. Wenn ich mich nun im 9. Clockzyklus 
befinde sollte ein ACK vom EEprom gesendet werden. Dabei gebe ich die 
Werte des SDA PORTS nach dem 8. und nach dem 9. Clockzyklus mit 
readSDA() per UART in der Konsole aus. Leider wird das Ack nicht 
empfangen da beide male der Wert 0xFF übertragen wird. (Wenn das Ack 
gesendet worden wäre, würde 0xFD stehen)

Wäre schön wenn mal einer drüber schauen könnte und hoffe auf 
konstruktive Tipps.

Hier die Funktionen:
1
void SDAHIGH ()
2
{
3
    DDRB &= ~(1);  //PB2 auf Eingang (HIGH übertragen)
4
    PORTB = 0xFF;
5
}
6
7
void SDALOW ()
8
{
9
    DDRB|= (1 << 2);  //PB2 auf Ausgang (LOW übertragen)
10
    digitalWrite(1,2,0);
11
}
12
13
void initIC2toWrite()
14
{
15
    SDALOW();
16
    SDAHIGH(); //Schreibe eine 1
17
    clock();
18
    SDALOW();  //Schreibe eine 0
19
    clock();
20
    SDAHIGH(); //Schreibe eine 1
21
    clock();
22
    SDALOW();  //Schreibe eine 0
23
    clock();
24
    SDALOW();  //Schreibe eine 0
25
    clock();
26
    SDALOW();  //Schreibe eine 0
27
    clock();
28
    SDALOW();  //Schreibe eine 0
29
    clock();
30
    SDALOW();  //Schreibe eine 0
31
    clock();
32
    //FERTIG nun warten auf ACK
33
    SDAHIGH();  //Schreibe eine 1 (Als Eingang schalten)
34
    readSDA();   //Lese Eingang
35
    clock();   //9. Clockzyklus
36
    readSDA();  //Lese Eingang (sollte ACK empfangen)
37
      _delay_ms(100);
38
}
39
int main(void)
40
{
41
    USART_Init();
42
    DDRD =(1<<2);       //PB1 = CLOCK (Ausgang)
43
    digitalWrite(2,2,1);     //Clock = High
44
    SDAHIGH();              //SDA=HIGH
45
    initIC2toWrite();
46
}

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Was macht genau clock()?

von Peter D. (peda)


Lesenswert?

Matthias Sch. schrieb:
> SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt.

Halt!

Das ist nur bei dummen Slaves erlaubt.
Ist der Slave auch ein MC, muß er ja Interrupts verabeiten können und 
für diese Zeit zieht der Slave SCL auf low.
Der Master darf also kein strong High auf SCL legen!

von Dennis A. (dede1989)


Lesenswert?

Peter Dannegger schrieb:
> Halt!
>
> Das ist nur bei dummen Slaves erlaubt.

Der EEPROM kann ja als dummer Slave gesehen werden.

Ralf schrieb:
> Was macht genau clock()?

Clock macht im Prinzip einen Taktzyklus : der Clockpin wird auf LOW HIGH 
LOW gesetzt. Dies geschieht analog zu SCL.

von Karl H. (kbuchegg)


Lesenswert?

Dennis A. schrieb:

> Wäre schön wenn mal einer drüber schauen könnte und hoffe auf
> konstruktive Tipps.


Das ist doch Schei...e

Mach dir doch als erstes gleich mal 2 Funktionen, die ein 0-Bit ausgeben 
bzw. ein 1 Bit ausgeben.

Sowas ist doch Blödsinn

>     SDAHIGH(); //Schreibe eine 1
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();
>     SDAHIGH(); //Schreibe eine 1
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();
>     SDALOW();  //Schreibe eine 0
>     clock();

Und als nächstes kommt dann eine 3.te Funktion, die 1 Byte mit allen 8 
Bits unter Zuhilfenahme der beiden Hilfsfunktionen für 0 und 1 ausgibt.

Und mit dieser 3.ten Funktion, die ein komplettes Byte ausgeben kann, 
arbeitest du dann in weiterer Folge in den höherliegenden Funktionen.

Hier siehst du doch vor lauter Lows und Highs und Clocks die Bäume vor 
lauter Wald nicht mehr.


Ausserdem:
> void initIC2toWrite()
> {
>     SDALOW();
>     SDAHIGH(); //Schreibe eine 1

Das ist doch keine gültige Startbedingung.

http://www.rn-wissen.de/index.php/I2C#Startbedingung

Am Besten du liest dir auch noch mal diesen Artikel komplett durch

von Dennis A. (dede1989)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Mach dir doch als erstes gleich mal 2 Funktionen, die ein 0-Bit ausgeben
> bzw. ein 1 Bit ausgeben.

Machen die beiden Funktionen doch SDAHIGH => 1 und SDALOW => 0

aber verstehe schon das Problem.

Noch dazu:

Karl Heinz Buchegger schrieb:
>> void initIC2toWrite()
>> {
>>     SDALOW();
>>     SDAHIGH(); //Schreibe eine 1
>
> Das ist doch keine gültige Startbedingung.

Naja ich ziehe SDA auf LOW während vorher SCL schon sowieso auf HIGH 
Steht. Bedingung erfüllt. Im nächsten Schritt geht es dann an die 
übertragung mit SDAHIGH() wird das 1. Bit gesetzt

von Karl H. (kbuchegg)


Lesenswert?

> void SDAHIGH ()
> {
>     DDRB &= ~(1);  //PB2 auf Eingang (HIGH übertragen)

Das ist doch nicht PB2!

Hier

> void SDALOW ()
> {
>    DDRB|= (1 << 2);  //PB2 auf Ausgang (LOW übertragen)

Hast du es fachlich korrekt geschrieben. Warum nicht bei SDAHIGH?

  DDRB &= ~( 1 << 2 );


> digitalWrite(1,2,0);
entweder du benutzt die digital_Dingsbums Funktionen oder du machst das 
mit den Portzugriffen. Aber nicht mischen. Da kommt nur Verwirrung raus.
1
Bit setzen
2
     register |= ( 1 << Bitnummer )
3
4
Bit löschen
5
     register &= ~( 1 << Bitnummer )
6
7
Bit auf 1 abfragen
8
     register & ( 1 << Bitnummer )
9
10
Bit auf 0 abfragen
11
     !( register & ( 1 << Bitnummer ) )

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Dennis A. schrieb:

> Karl Heinz Buchegger schrieb:
>>> void initIC2toWrite()
>>> {
>>>     SDALOW();
>>>     SDAHIGH(); //Schreibe eine 1
>>
>> Das ist doch keine gültige Startbedingung.
>
> Naja ich ziehe SDA auf LOW während vorher SCL schon sowieso auf HIGH
> Steht.

So?
Tut es das?

Warum macht das die Funktion nicht selbst, sondern verlässt sich darauf, 
dass das vom Aufrufer schon gemacht wurde?

: Bearbeitet durch User
von Dennis A. (dede1989)


Lesenswert?

Karl Heinz Buchegger schrieb:
> So?
> Tut es das?
>
> Warum macht das die Funktion nicht selbst, sondern verlässt sich darauf,
> dass das vom Aufrufer schon gemacht wurde?

Okay ich mach mich mal dran das alles schöner zu machen und in die 
Funktion zu schreiben. Hoffe ich komme da weiter. Danke

von Karl H. (kbuchegg)


Lesenswert?

AUsserdem
1
int main(void)
2
{
3
    USART_Init();
4
    DDRD =(1<<2);       //PB1 = CLOCK (Ausgang)
5
    digitalWrite(2,2,1);     //Clock = High
6
    SDAHIGH();              //SDA=HIGH
7
    initIC2toWrite();
da geht zuerst der Clock auf High und erst dann kommt die SDA auf High. 
Das ist ist nicht das was gefordert war. Ja, ich weiss schon. Der 
Default ist Input und damit zieht der Pullup die Leitung auf high. 
Trotzdem. Das ist schon wieder implizites Zusatzwissen. Schreibs anders 
rum
1
  erst SDA auf High
2
  dann Clock auf High
3
  dann SDA auf Low
4
  dann Clock auf Low
und du hast eine direkte 1:1 Entsprechnung von der I2C Doku zu deinem 
Code. Und dann kann man das auch lesen und verstehen und muss nicht 200 
Zusatzbedingungen im Kopf haben.

?
1
  DDRD =(1<<2); //PB1 = CLOCK (Ausgang)
Das ist NICHT PB1!

Du hast da einen schönen Mischmasch.
Mach dir doch ein paar Define
1
#define SDA_PIN   PB2
2
#define SCLK_PIN  PB1
und mit denen schreibst du
1
  DDRB |= ( 1 << SDA_PIN );
dann kannst du dir auch einen Kommentar dazu sparen UND das Beste am 
ganzen: im Code steht selbst schon, welche Bedeutung dieser Pin hat. 
Hier wird ganz offensichtlich der SDA_PIN mittels DDR auf Ausgang 
geschaltet. Welcher konkreter Pin am Port B das dann auch immer war.
Keine magischen Konstanten im Code! In 3 Tagen weißt du nicht mehr ob 
mit
1
  PINB & ( 1 << 1 )
da jetzt die Clock Leitung oder die Datenleitung abgefragt wird. Mit
1
  PINB & ( 1 << SCLK_PIN )
weisst du es aber. Steht ja im Code, welche der beiden es sein soll.

: Bearbeitet durch User
von Hugo (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
>   erst SDA auf High
- Delay();
>   dann Clock auf High
- Delay();
>   dann SDA auf Low
- Delay();
>   dann Clock auf Low
- Delay();

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Peter Dannegger schrieb:
>> SCL bleibt ja ein Ausgang und wird weiterhin vom MC geclockt.
>
> Halt!
>
> Das ist nur bei dummen Slaves erlaubt.
> Ist der Slave auch ein MC, muß er ja Interrupts verabeiten können und
> für diese Zeit zieht der Slave SCL auf low.
> Der Master darf also kein strong High auf SCL legen!

Ich habe bis jetzt noch kein I2C EEPROM gesehen, das sich durch die CLK 
Verlängerung mehr Zeit ausgebeten hätte, z.B. beim Schreibvorgang. Du 
kannst bei den meisten lediglich auf 'Busy' checken durch ein fehlendes 
ACK. Obwohl die CLK Verlängerung ein legitimes Verfahren wäre, wird es 
bei den EEPROMs nicht genutzt, vllt., um den MC nicht zu blocken.

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.