Forum: Mikrocontroller und Digitale Elektronik Attin84 I2C mit der USI läuft nicht


von Christian J. (Gast)


Lesenswert?

Hallo,

ohne Messgeräte schwierig zu sagen aber so ist es nunmal: Ich benutze 
die TinyWireM Lib für den Tiny84 um eine I2C Strecke zu einem ADXL345 zu 
bauen aber leider wird nur bei einem Power On Kaltstart das DeviceID 1 
Mal (!) richtig ausgelesen. Danach wird kein weiteres Byte mehr richtig 
geschrieben und gelesen und auch nicht bei einem Warmstart mit RESET.

Ich habe mit 8 und mit 1 Mhz herumgespielt, die Libs auf den Kopf 
gestellt. Aber alles ohne Erfolg und in die USI wollte ich nicht 
einsteigen,, nützt ohne Messgeräte sowieso nichts. Die Libs sind ja 
recht bekannt und scheinen zu funktionieren.

Kennt einer das Problem?

von Georg G. (df2au)


Lesenswert?

Seit Jahrzehnten bekanntes Problem, schwer zu lösen: In Zeile 42 deines 
Programms fehlt ein "-".

von Christian J. (Gast)


Lesenswert?

Dazu braucht es keinen Code hier. Einbinden und Benutzen, fertig. I2C 
ist ja kein Hexenwerk.

SPI geht leider kein Mode 3 mit dem USI, sonst würde ich den nehmen. Der 
ADXl345 unterstützt nämlich nur Mode 3.

von m.n. (Gast)


Lesenswert?

Christian J. schrieb:
> Dazu braucht es keinen Code hier. Einbinden und Benutzen, fertig. I2C
> ist ja kein Hexenwerk.

Du bist echt lustig! Alles ist ganz einfach und kein Hexenwerk, aber Du 
bekommst es nicht zum Laufen ;-)

Die Erfahrungen die ich mit 'fertigen' USI-Routinen gemacht habe, sind 
enttäuschend. Entweder muß ich mich noch einmal daran setzen, selber 
brauchbaren Code zu schreiben, oder ich verwende doch lieber AVRs mit 
TWI in Hardware.
Du bist hier ja bekannt, Alles ganz einfach frei Haus geliefert zu 
bekommen, aber das reale Leben sieht anders aus.

Wenn Du nur die Master-Funktion brauchst, nimm eine reine 
Softwarelösung. Da hat man die Funktion besser im Griff.

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Ich benutze
> die TinyWireM Lib für den Tiny84 um eine I2C Strecke zu einem ADXL345 zu
> bauen

Warum so aufwendig? Um einen Master zu implementieren ist das 
Herumgewürge mit der USI doch eher kontraproduktiv, diese Hardware kann 
am ehesten noch bei einem Slave hilfreich sein mit ihrer Fähigkeit 
Interrupts zu generieren bei den entscheidenden Ereignissen aber wenn 
man die USI entgegen ihrer Natur zur Arbeit als I²C Master überreden 
will braucht man mehr Code und kompliziertenen Code als würde man es mit 
simplem Bitbanging implementieren.

Mein Vorschlag ist also: Implementiere I²C master mit Bitbanging. Bitte 
beachte hierzu daß die Ausgänge über DDR (und nicht über PORT) gesteuert 
werden müssen um das Verhalten von open-collector-Ausgängen zu erhalten. 
Hierzu müsste aber auch reichlich funktionierender Beispielcode im Forum 
und andernorts zu finden sein.

von Klaus (Gast)


Lesenswert?

Christian J. schrieb:
> leider wird nur bei einem Power On Kaltstart das DeviceID 1
> Mal (!) richtig ausgelesen. Danach wird kein weiteres Byte mehr richtig
> geschrieben und gelesen und auch nicht bei einem Warmstart mit RESET.

Klassischer Fall.

1. Der Read wird nicht richtig beendet, vermutlich wird das letzte Byte 
nicht mit NAK quitiert. Damit bleibt er im Lesemodus und reagiert nicht 
auf einen STOP oder START.

2.Problem: Es wird ignoriert, daß der µC keinen START erzeugen kann, 
weil der Bus nicht idle ist oder das ACK beim Senden der Adresse wird 
nicht ausgewertet, daher wird nicht erkannt, daß der Chip sich garnicht 
angesprochen fühlt. Anschließend wird der hängende Bus ausgelesen und 
gesagt, der Chip liefert falsche Werte.

Zwei Maßnahmen sind nötig: das Lesen muß in Ordnung gebracht werden und 
Reset Routine ins I2C Init eingebaut werden
Beitrag "I2C hängt sich auf"

MfG Klaus

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> SPI geht leider kein Mode 3 mit dem USI, sonst würde ich den nehmen. Der
> ADXl345 unterstützt nämlich nur Mode 3.

SPI in Software, also ohne Hardware wie USI, ist nicht grad Raketenbau.

von Uwe (de0508)


Lesenswert?

Guten Morgen,

ich muss etwas widersprechen:

Aus dem Datenblatt geht für den ADXL345 hervor: SPI (3- and 4-wire)

SPI ist wirklich kein Hexenwerk und benötigt keine 
Hardwareunterstützung.

Christian J. schrieb:
> Dazu braucht es keinen Code hier. Einbinden und Benutzen, fertig. I2C
> ist ja kein Hexenwerk.
>
> SPI geht leider kein Mode 3 mit dem USI, sonst würde ich den nehmen. Der
> ADXl345 unterstützt nämlich nur Mode 3.

von Christian J. (Gast)


Lesenswert?

Uwe S. schrieb:
> Aus dem Datenblatt geht für den ADXL345 hervor: SPI (3- and 4-wire)
>
> SPI ist wirklich kein Hexenwerk und benötigt keine
> Hardwareunterstützung.

Wenn man sich ein wenig durchs Netz liest merkt man, dass das 
Begrifflichhkeiten oft verwechselt werden:

1) 3 Wire SPI heisst bei einigen, dass CS weggelassen wird und der Slave 
dauernd "selecteted" ist. Es gibt aber MISO und MOSI, bzw SDO und SDI

2) Bei anderen und auch beim ADXL345 ist es aber so, dass 3 Wire 
bedeutet, dass es einen SDI/O Pin gibt, der wechselweise Input und 
Output ist. Und das geht mit der USI nicht, deren Pins haben eine feste 
Direction.

Da ich keine Bitbang Routinen schreiben werde (außer für SPI), sondern 
auf fertige Lösungen setze um mich dem eigentlichen Problem zu widmen 
bin ich auf Libs angewiesen. Ich habe (derzeit) keinerlei Messgeräte um 
ein Protokoll zu überprüfen und würde in einer Black Box herumstochern.

Den Beitrag von Klaus muss ich mir nochmal näher anschauen .... 
allerdings nahm ich an dass "bewährte Libs" das richtig machen und die 
TinyWire wird oft zitiert.

von Bernd K. (prof7bit)


Lesenswert?

Klaus schrieb:
> 1. Der Read wird nicht richtig beendet, vermutlich wird das letzte Byte
> nicht mit NAK quitiert. Damit bleibt er im Lesemodus und reagiert nicht
> auf einen STOP oder START.

Ich schließe mich dieser Meinung an.

von Christian J. (Gast)


Lesenswert?

A. K. schrieb:
> SPI in Software, also ohne Hardware wie USI, ist nicht grad Raketenbau

Aber sie ist langsam bei einem 1Mhz geclockten Chip und ich muss schnell 
auslesen, wenn der FIFO voll ist. Habe mir 2 Tage und Nächte um die 
Ohren gehauen den ADXL345 genau zu verstehen und richtig zu 
programmieren, wobei auch noch der blöde Chip einen Fehler hat, die 
Z-Achse ist beschädigt (Offset weit außerhalb der Spec, muss sowohl per 
Hardware als auch noch Software korriiert werden (-600) wurde vom 
Verkäufer bei ebay auch bestätigt, dass alle Chips defekt sind) und er 
sie reklamieren will.

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Da ich keine Bitbang Routinen schreiben werde

Warum?

Allein in der Zeit die Du damit verbracht hast das Eingangsposting zu 
formulieren hättest Du schon 8 Bits an einem Pin rausgeschoben, dabei am 
Taktpin gewackelt und das 9te Bit eingelesen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Bitbanging ist zu langsam! Das muss mit dem Chip Clock takten.

Hier ist mit die Hauptroutine des TinyWireM. Ich habe mich mit der USi 
nicht befasst, nur quer gelesen aber ist da ein Bug drin, dass der sich 
aufhängt? So ganz trivial ist das ja nicht, dass man da mal eben 
durchblickt.

von Christian J. (Gast)


Lesenswert?

Klaus schrieb:

> 1. Der Read wird nicht richtig beendet, vermutlich wird das letzte Byte
> nicht mit NAK quitiert. Damit bleibt er im Lesemodus und reagiert nicht
> auf einen STOP oder START.
>
> 2.Problem: Es wird ignoriert, daß der µC keinen START erzeugen kann,
> weil der Bus nicht idle ist oder das ACK beim Senden der Adresse wird
> nicht ausgewertet, daher wird nicht erkannt, daß der Chip sich garnicht
> angesprochen fühlt. Anschließend wird der hängende Bus ausgelesen und
> gesagt, der Chip liefert falsche Werte.
>
> Zwei Maßnahmen sind nötig: das Lesen muß in Ordnung gebracht werden und
> Reset Routine ins I2C Init eingebaut werden
> Beitrag "I2C hängt sich auf"

Ich vermute dass Klaus hier richtig liegt. Nur wo soll ich da suchen? 
Ohne Bus Analyzer?

Mehr als das hier habe ich nicht geschrieben in der Hoffung, dass das 
richtig umgesetzt wird.

/  Lies ein einzelnes Byte aus dem Sensor aus
uint8_t ReadADXL(uint8_t addr)
{
  uint8_t val;

  // Sensor adressieren
  TinyWireM.beginTransmission(DEVICE);
  TinyWireM.send(addr);
  TinyWireM.endTransmission();

  // Bytes anfordern
  TinyWireM.beginTransmission(DEVICE);
  TinyWireM.requestFrom(DEVICE, 1);
  val = TinyWireM.receive();
  TinyWireM.endTransmission();
  return (val);

}

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Ich vermute dass Klaus hier richtig liegt. Nur wo soll ich da suchen?
> Ohne Bus Analyzer?

Indem Du beim Lesen des letzten Bytes ein NAK veranlasst anstelle des 
sonst üblichen ACK. Nach dieser kleinen Änderung wird es magischerweise 
funktionieren.

von Christian J. (Gast)


Lesenswert?

Bernd K. schrieb:
> Indem Du beim Lesen des letzten Bytes ein NAK veranlasst anstelle des
> sonst üblichen ACK.

Und wie geht das? Ich bin da echt zu blond... lese mich nur grad hier 
mal ein:
http://support.saleae.com/hc/en-us/articles/200730905-Learn-I2C-Inter-Integrated-Circuit

UNd in der Lib scheint das auch richtig gemacht worden zu sein:
1
/* Else masterRead cycle*/
2
    else
3
    {
4
      /* Read a data byte */
5
      DDR_USI   &= ~(1<<PIN_USI_SDA);               // Enable SDA as input.
6
      *(msg++)  = USI_TWI_Master_Transfer( tempUSISR_8bit );
7
8
      /* Prepare to generate ACK (or NACK in case of End Of Transmission) */
9
      if( msgSize == 1)                            // If transmission of last byte was performed.
10
      {
11
        USIDR = 0xFF;                              // Load NACK to confirm End Of Transmission.
12
      }
13
      else
14
      {
15
        USIDR = 0x00;                              // Load ACK. Set data register bit 7 (output for SDA) low.
16
      }
17
      USI_TWI_Master_Transfer( tempUSISR_1bit );   // Generate ACK/NACK.
18
    }
19
  }while( --msgSize) ;                             // Until all data sent/received.
20
  
21
  if (!USI_TWI_Master_Stop())
22
  {
23
  return (FALSE);                           // Send a STOP condition on the TWI bus.
24
  }

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Und wie geht das? Ich bin da echt zu blond... lese mich nur grad hier
> mal ein:

Siehst Du? Du gewinnst keine Zeit beim Versuch eine fremde Library 
einzubinden, am Ende musst Du doch die Zeit aufwenden I²C zu verstehen 
(ist jedoch nicht schwer), das musst Du letzten Endes so oder so machen.

Nachdem Du es dann jedoch verstanden haben wirst wird sich die eigene 
Implementation (in nur einem drittel des Codes ganz ohne USI) quasi von 
selbst aufdrängen und Du wirst fortan nie wieder Probleme damit haben, 
bis ans Ender aller Zeiten.

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> UNd in der Lib scheint das auch richtig gemacht worden zu sein:

Diese Lib ist 5 mal so umfangreich wie es für ein simples Bitbanging 
(inclusive Clock stretching und allem Pipapo) erforderlich wäre. Und am 
Ende benutzt sie doch nur while()-Schleifen um zu warten und keine 
Interrupts, also null Vorteil durch Hardware. Und vom Lesen obigen Codes 
bekommt man übrigens Kopfschmerzen.

Ich würde diesen Code in die Kategorie Softwaresatire einordnen. 
Wahrscheinlich wurde er geschrieben um zu demonstrieren wie überaus 
ungeeignet dieser Ansatz mit USI als Master doch ist.

von Christian J. (Gast)


Lesenswert?

Bernd K. schrieb:
> Siehst Du? Du gewinnst keine Zeit beim Versuch eine fremde Library
> einzubinden, am Ende musst Du doch die Zeit aufwenden I²C zu verstehen
> (ist jedoch nicht schwer), das musst Du letzten Endes so oder so machen.

Bernd, sie mir nicht böse aber an einem Schreibtisch, wo nur ein PC, ein 
Programmer, ein paar AVR Boards stehen und ein paar Bauteile aber kein 
einziges Messgerät sieht es düster aus mit "selbst machen". Außerdem 
haben sich schon tausende darin verewigt  I2c Libs zu schreiben. Wie I2C 
funktioniert ist nicht schwer, zusammen mit der ominösen USI aber ist 
das ein Wochenwerk bis das läuft und dafür habe ich keine zeit nd keine 
Mittel, da es ein Herumgestochere wäre zu sehen was abgeht.

Notfalls fliegt der Attiny raus und ein 328er kommt rein, auch wenn der 
mehr Platz braucht. Mit dem geht es ja einwandfrei.

von Georg G. (df2au)


Lesenswert?

Bernd K. schrieb:
> null Vorteil durch Hardware

Einfach nur mal ein "grep delay *.cpp" ist schon sehr aufschlussreich.

von Christian J. (Gast)


Lesenswert?

Georg G. schrieb:

> Einfach nur mal ein "grep delay *.cpp" ist schon sehr aufschlussreich.

Einzeiler enthalten keine verwertbare Informationen.

von Bastler (Gast)


Lesenswert?

Den 328er gibt es in noch gut lötbar als 9x9mm oder eben auch in 4x4mm, 
jeweils Außenkante des Footprints. Muß es kleiner sein?

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Georg G. schrieb:
>
>> Einfach nur mal ein "grep delay *.cpp" ist schon sehr aufschlussreich.
>
> Einzeiler enthalten keine verwertbare Informationen.

Die verwertbare Information in diesem Falle ist daß _delay-Funktionen 
zum Einsatz kommen um Bitzeiten abzuwarten. Würde das Ding die Hardware 
autonom arbeiten lassen dann wäre vielleicht ein Interrupt pro Byte 
nötig und kein einziges Delay.

Der obige Code ist letztendlich auch nur ein verkapptes Bitbanging mit 
Warteschleifen, aber nicht direkt mit simplem Pin-Wackeln sondern 
schmerzhaft umständlich per Vergewaltigung der USI-Hardware und 
manuellem Erzeugen des Clocks um von hinten durch die Brust ins Auge das 
Ausgangsbit in gewünschter Weise wackeln zu lassen, jeder andere hätte 
es direkt über PIN, PORT und DDR gemacht in einem fünftel des Codes.

von Christian J. (Gast)


Lesenswert?

Bernd K. schrieb:
> Der obige Code ist letztendlich auch nur ein verkapptes Bitbanging mit
> Warteschleifen, aber nicht direkt mit simplem Pin-Wackeln sondern
> schmerzhaft umständlich per Vergewaltigung der USI-Hardware und
> manuellem Erzeugen des Clocks um von hinten durch die Brust ins Auge das
> Ausgangsbit in gewünschter Weise wackeln zu lassen, jeder andere hätte
> es direkt über PIN, PORT und DDR gemacht in einem fünftel des Codes.

Ich habe gesehen. Ich weiss nicht wieso die eine USI erfunden haben, 
vermutlich um die Chipfläche zu reduzieren und den Aufwand auf Software 
umzulegen. Dennoch nehme ich an, dass diese USi funktioniert und auch 
der Lib Code. Grad mal mit einem 2402 Eprom geprüft, das gleiche 
Theater.

Ich weiss jetzt mit I2C auch nicht weiter, keine Ahnung was ich da 
ändern könnte, von daher werde ich mal SPI umverdrahten auf dem 
Testboard. Die USI scheint das ja zu beherrschen und Mode 0 und Mode 3 
sind so ähnlich, dass sie austauschbar sein müssten. Und wenn das nicht 
geht dann eben per Software SPI und 8 mhz statt 1Mhz.

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> und ein 328er kommt rein

Vorsicht: Der 328er hat einen Bug im I2C Master der noch viel mehr 
Arbeit und graue Haare macht, auch dort empfiehlt sich also 
Nichtverwendung desselben und Bitbanging stattdessen. Also nichts 
gewonnen.

Du könntest schon fertig sein mit der Implementation, es sind schon 90 
Minuten vergangen. Auch ohne Oszi.

von Christian J. (Gast)


Lesenswert?

Bernd K. schrieb:
> Vorsicht: Der 328er hat einen Bug im I2C Master der noch viel mehr
> Arbeit und graue Haare macht,

Mit dem 328 habe ich es aber vorher aufgebaut und es spielte 
einwandfrei. Also treibt der Bug sein Unwesen woanders und Bugs werden 
meist in einer neuen Revision ausgemerzt wenn sie wesentlich sind.  Der 
ADXL345 war auch total buggy in der Rev A.

von Christian J. (Gast)


Lesenswert?

Gefällt dir der Code für die TWI besser?

http://www.ermicro.com/blog/?p=744

von Georg G. (df2au)


Lesenswert?

Für sehr wenig Geld bekommst du aus China einen Logik Analysator. Und 
mit passendem Werkzeug ist die Fehlersuche deutlich angenehmer und 
schneller.

von Klaus (Gast)


Lesenswert?

Christian J. schrieb:
> // Sensor adressieren
>   TinyWireM.beginTransmission(DEVICE);
>   TinyWireM.send(addr);
>   TinyWireM.endTransmission();

Da geht das Elend schon los. Ich bin ziemlich sicher, daß 
TinyWireM.beginTransmission(DEVICE) einen Rückgabewert hat, in dem 
mitgeteilt wird, ob es geklappt hat. Leider unterscheiden die gängigen 
Libraries nicht zwischen "BUS nicht Idle" und "kein ACK vom Slave", 
daran könnte man auch ohne Analyzer etwas erkennen. Auch 
TinyWireM.send(addr) wird einen Rückgabewert haben, wenn nicht, gehören 
diese Funktionen ins Bitbucket.

MfG Klaus

von Christian J. (Gast)


Lesenswert?

Boah..... ne Soft i2c nervt aber auch... vor allem wenn man den fehler 
nicht findet, warum da nur FF kommt, wenn man ein Byte lesen will.

Da kann ja erstmal nicht falsch dran sein, oder?

void WriteADXL(uint8_t addr, uint8_t val)
{
  i2c_start();
  i2c_write(DEVICE);
  i2c_write(addr);
  i2c_write(val);
  i2c_stop();
}


uint8_t ReadADXL(uint8_t addr)
{
  uint8_t val;

  // Sensor adressieren ( Zeiger auf Zielbyte)
  i2c_start();
  i2c_write(DEVICE);
  i2c_write(addr);

  // Bytes anfordern
  val = i2c_read(1);
  i2c_stop();
  return (val);

}

von Christian J. (Gast)


Lesenswert?

Und die habe ich mir geklaut und optisch etwas aufbereitet:

http://www.avrfreaks.net/forum/program-i2c-atmega16-problem?name=PNphpBB2&file=viewtopic&t=77455
1
/ PORT A 
2
#define DDR  DDRA    
3
#define PORT PORTA
4
#define PIN  PINA    
5
6
// Pins im Port festlegen
7
#define SDA 6      // Definition der Port Pins
8
#define SCL 4
9
10
// Makros für Pin Wackeln
11
#define SCL_set() (PORT |= _BV(SCL))
12
#define SCL_clr() (PORT &= ~_BV(SCL))
13
#define SCL_out() (DDR  |= _BV(SCL))
14
15
#define SDA_set() (PORT |= _BV(SDA))
16
#define SDA_clr() (PORT &= ~_BV(SDA))
17
#define SDA_read() (PIN  & _BV(SDA)) 
18
#define SDA_out() (DDR  |= _BV(SDA))
19
#define SDA_in()  (DDR  &= ~_BV(SDA))
20
21
////////////////////////////////////////////////////////////////////////////////////////////
22
void delay(void)
23
{
24
  delayMicroseconds(10);
25
}
26
////////////////////////////////////////////////////////////////////////////////////////////
27
void i2c_write(unsigned char data)
28
{
29
  char index;
30
  
31
  SDA_out();
32
  SCL_out();
33
34
  SCL_clr();
35
  delay();
36
  
37
  for(index=0; index<9; index++)
38
  { 
39
    if(data & 0x80)
40
    SDA_set();
41
    else
42
    SDA_clr();
43
  
44
    delay();
45
    SCL_set();
46
    delay();
47
    SCL_clr();
48
    delay();
49
    data<<=1;
50
  }
51
  
52
  SDA_clr();
53
}
54
55
///////////////////////////////////////////////////////////////////////////////////////////
56
// ACK = 0 => letztes Byte, NAK senden
57
// ACK = 1 => es geht nooch weiter, ACK senden
58
unsigned char i2c_read(unsigned char ACK)
59
{
60
  unsigned char data=0x00;
61
  char index;
62
63
  SDA_in();
64
  SCL_out();
65
  SCL_clr();
66
  
67
  for(index=0; index<8; index++)
68
  { 
69
    delay();
70
    SCL_set(); 
71
    delay();
72
    data <<= 1;
73
    if(SDA_read())
74
    data++;
75
  
76
    delay();
77
    SCL_clr();
78
  }
79
80
  // Folgt noch was oder nicht?
81
  if(ACK == 0x00)
82
    SDA_set();      // Ja, fertig
83
  else
84
    SDA_clr();      // Nein, es wird noch mehr gelesen
85
 
86
  delay();
87
  SCL_set();
88
  delay();
89
  SCL_clr();
90
91
  return data;
92
}
93
94
95
void i2c_start(void)
96
{
97
  SCL_out();
98
  SDA_out();
99
100
  SDA_set();
101
  delay();
102
  SCL_set();
103
  delay();
104
  SDA_clr();
105
  delay();
106
  SCL_clr();
107
} 
108
109
void i2c_stop(void)
110
{
111
  SCL_out();
112
  SDA_out();
113
   
114
   SDA_clr();
115
   delay();
116
   SCL_set();
117
   delay();
118
   SDA_set();
119
   delay();
120
}

von (prx) A. K. (prx)


Lesenswert?

Wenn ich das richtig verstanden habe, dann hast Du die Wahl zwischen I2C 
und Mode 3 SPI. Weshalb du dann allerdings per Bitbanging lieber I2C 
machst als das viel einfachere SPI, das ist mir ein Rätsel.

von Christian J. (Gast)


Lesenswert?

A. K. schrieb:
> Wenn ich das richtig verstanden habe, dann hast Du die Wahl zwischen I2C
> und Mode 3 SPI. Weshalb du dann allerdings per Bitbanging lieber I2C
> machst als das viel einfachere SPI, das ist mir ein Rätsel.

Das ist einfach Bequemlichkeit, da der Aufbau hier für I2C fertig steht. 
SPI wäre auch wieder die Wahl zwischen Bitbang und der ominösen und 
unverständlichen USI. Wenngleich die SPI Routinen winzig sind im 
Vergleich zu den I2C.

Der Tag ist noch lang und draußen wechselt es eh zwischen Sonne, 
Weltuntergang und Gewitter...

Irgendwo fliegt auch noch so ein China Logic Analyzer rum.... gucken ob 
ich den wiederfinde....

von Frank K. (fchk)


Lesenswert?

Christian J. schrieb:

> Notfalls fliegt der Attiny raus und ein 328er kommt rein, auch wenn der
> mehr Platz braucht. Mit dem geht es ja einwandfrei.

Falsche Wahl. Ein PIC12F1822 oder ein PIC12F1840 im SO08 oder DIL08 hat 
SPI und I2C in Hardware, so wie es sich gehört, dazu eine UART, auch in 
Hardware. Inkl. Noise Filtering bei I2C, was die USI NICHT hat.

Nur um Dir mal zu zeigen, was es sonst noch alles gibt.

fchk

von Georg G. (df2au)


Lesenswert?

Christian J. schrieb:
> uint8_t ReadADXL(uint8_t addr)
> {
>   uint8_t val;
>
>   // Sensor adressieren ( Zeiger auf Zielbyte)
>   i2c_start();
>   i2c_write(DEVICE);
>   i2c_write(addr);
>
>   // Bytes anfordern
>   val = i2c_read(1);
>   i2c_stop();
>   return (val);
>
> }

Gängige I2C Sklaven wollen vor dem "Bytes anfordern" ein (re)start. Und 
bitte nicht vergessen: Immer das letzte Byte, das gelesen wurde, mit NAK 
abschließen. Aber das wurde ja weiter oben schon mehrfach erwähnt. Du 
hast es wohl nur überlesen.

Ich empfehle dir, das Datenblatt zu konsultieren. In Rev. D | Page 18 of 
40 ist es Figure 41. I2C Device Addressing

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> #define SCL_set() (PORT |= _BV(SCL))

Falsch.

Erstens hab ich gesagt nimm DDR statt PORT und zweitens braucht es nach 
dem Freigeben von SCL noch ne while-schleife die wartet bis er 
tatsächlich auf high ist (clock-strectching).

Diese Lib die Du da gefunden hats kannst Du getrost in die Tonne treten, 
wer immer das verbrochen hat hat nicht den geringsten Schimmer. Nicht 
den geringsten.

Daß dieser Code vollkommen untauglich und falsch ist wird übrigens auch 
von allen Teilnehmern in dem verlinkten Thread ausdrücklich gesagt!

: Bearbeitet durch User
von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Was ein Gefrickel :-(

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Aber rücken wir dem Problem mal mit China zu Leibe... an einem 24LC02, 
vielleicht ist der ADXL345 ja auch schon tot.

von Georg G. (df2au)


Lesenswert?

Und nun nimm bitte endlich das Datenblatt zur Hand und vergleiche deine 
Aufzeichnung mit dem Bild 41. Dann sollte dir auffallen, dass nach dem 
re-Start etwas fehlt.

So könnte ein Lesevorgang aussehen:

                i2c_start();
                i2c_write(SLAVE_ADR);
                i2c_write(adresse);
                i2c_start();
                i2c_write(SLAVE_ADR +1);
                for (i = 0; i < 15; i++) {
                    i2c_read(ACK);
                }
                i2c_read(NAK);
                i2c_stop();

(die gelesenen Werte werden hier nicht ausgewertet)

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

Georg G. schrieb:
> Und nun nimm bitte endlich das Datenblatt zur Hand

Ich bin dabei, grad genau an dieser Baustelle aber mit einem E2PROm, was 
ich erst umbauen musste....... also hör auf zu drängeln :-)

Bei der zitierten Soft I2C scheint aber das W/R Bit manuell noch gesetzt 
zu werden müssen. In den Konfort Libs wird das mit eingearbeitet und 
noch weiter gekapselt.

Was fehlt denn in dem Bild? grüne Punkte sind Start, rote Punkte sind 
Stop.

von (prx) A. K. (prx)


Lesenswert?

Georg G. schrieb:
> Gängige I2C Sklaven wollen vor dem "Bytes anfordern" ein (re)start.

Nicht unbedingt. Manche kennen auch reine Lese-Transaktionen, 
insbesondere solche ohne Registeradresse nach der I2C-Adresse.

Bei vielen I2C Slaves kann man erfahrungsgemäss auch auf die korrekte 
repeated start condition verzichten und die write transaction mit einer 
stop condition beenden, um dann eine reine read transaction 
anzuschliessen. Aber das funktioniert eben nicht bei allen Slaves und da 
kann man bei bestehendem Code Slave schon man auf die Nase fallen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Mit dem 24lc32 e2prom geht es jedenfalls, da wird ein Wert ausgelesen

 i2c_start();
  i2c_write(0b10100000);
  i2c_write(0);
  i2c_write(addr);

  // Byte anfordern
  i2c_start();
  i2c_write(0b10100001);
  val = i2c_read(1);
  i2c_stop();
  return (val);

von Georg G. (df2au)


Lesenswert?

Fielmann? Im ersten Versuch fehlt das Schreiben der Slave Adresse. Nun 
hast du es richtig gemacht. Allerdings sagte der von dir gezeigte 
Quelltext, dass ein i2c_read(1) ein ACK sendet. Aktuell kommt aber ein 
NAK.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Wahrscheinlich sollte ich mal ne Pause machen..... jedenfalls erzeugt 
ein Schreiben von 0x75 auf 0x00 nicht das gewünschte Ergebnis. Das R/W 
Bit habe ich manuell eingefügt. 1010 ist die Adresse des 24lc032, was 
auf 0x00 geetzt wude an A0-2.

Kaffeepause....

////////////////////////////////////////////////
// Schreibe ein Byte auf I2C Bus in eine Adresse
// Eingabe: Adresse, Byte
void WriteADXL(uint8_t addr, uint8_t val)
{
  i2c_start();
  i2c_write(0b10100000);
  i2c_write(0);
  i2c_write(addr);
  i2c_write(val);
  i2c_stop();
}

//  Lies ein einzelnes Byte aus dem Sensor aus
uint8_t ReadADXL(uint8_t addr)
{
  uint8_t val;

  // Sensor adressieren ( Zeiger auf Zielbyte)
  i2c_start();
  i2c_write(0b10100000);
  i2c_write(0);
  i2c_write(addr);

  // Byte anfordern
  i2c_start();
  i2c_write(0b10100001);
  val = i2c_read(1);
  i2c_stop();
  return (val);

}

von (prx) A. K. (prx)


Lesenswert?

Woher kommt eigentlich der SDA-Glitch ganz vorne? Fasche Reihenfolge 
beim Pin-Setup?

von Georg G. (df2au)


Lesenswert?

Christian J. schrieb:
> nicht das gewünschte Ergebn

Weil du wieder das Datenblatt nicht gelesen hast.

Schreiben:
                i2c_start();
                i2c_write(SLAVE_ADR);
                i2c_write(adresse);
                for (i = 0; i < 16; i++) {
                    i2c_write(wr_data[i]);
                }
                i2c_stop();

Und nach dem i2c_stop musst du warten, bis das Byte wirklich geschrieben 
wurde, entweder eine feste Zeit oder per "ACK-Polling".

Ich geh Kaffee trinken.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Gute Frage... muss ich mal schauen...

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> Christian J. schrieb:
>> #define SCL_set() (PORT |= _BV(SCL))
>
> Falsch.
>
> Erstens hab ich gesagt nimm DDR statt PORT und zweitens braucht es nach
> dem Freigeben von SCL noch ne while-schleife die wartet bis er
> tatsächlich auf high ist (clock-strectching).

Clock stretching braucht man hauptsächlich dann, wenn der Slave ein µC 
ist. Sonst eher selten.

Deinem Kommentar zu der Lib muss ich zustimmen, die ist Unfug. Open 
Collector/Drain Leitungen steuert man mit der Richtung, nicht dem Wert, 
wenn der verwendete µC nicht sowieso solche Pins hat (8051) oder 
entsprechenden Port-Setup (viele ARMs).

Und wenn man es schon falsch macht, dann sollte besser aufpassen, dass 
man keine Glitches durch falsche Reihenfolge der PORT/DDR-Steuerung 
produziert.

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

Bernd K. schrieb:
> Diese Lib die Du da gefunden hats kannst Du getrost in die Tonne treten,
> wer immer das verbrochen hat hat nicht den geringsten Schimmer. Nicht
> den geringsten.

Hast du ne bessere? Ich bin jetzt nicht so der Crack was den AVR innen 
drin angeht.

von (prx) A. K. (prx)


Lesenswert?

Christian J. schrieb:
> Hast du ne bessere? Ich bin jetzt nicht so der Crack was den AVR innen
> drin angeht.

Kannst mal damit anfangen, die Makros zu korrigieren.
I2C Leitungen steuert man so:

Init ab Reset:
      nix, d.h. PORTx.y = DDRx.y = 0.

Out0: DDRx.y auf 1 setzen.
Out1: DDRx.y auf 0 setzen.
In:   vorher DDRx.y auf 0 setzen.

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

> #define SCL_set() (PORT |= _BV(SCL))

Das ist echt Blödsinn, weil man den Bus ja eh nur ziehen oder loslassen 
kann..... arbeite mich grad da durch..... dauert was.... mit set scheint 
er "auf 0 ziehen" zu meinen und mit clear "loslassen".

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Das ist echt Blödsinn, weil man den Bus ja eh nur ziehen oder loslassen
> kann.

Genau!

Und bei der SCL-Leitung baust Du zusätzlich nach dem Loslassen noch ne 
while-schleife ein die so lange wartet bis der Pin auch tatsächlich auf 
high gegangen ist, damit hast Du dann mit nur einer Zeile zusätzlichem 
Code noch das Clock-Stretching ebenfalls berücksichtigt (denn nichts 
anderes ist das: der Slave darf jederzeit die SCL nach unten ziehen und 
der Master muss bei jedem Loslassen der SCL-Leitung so lange warten bis 
sie tatsächlich auf high gegangen ist.)

von Bernd K. (prof7bit)


Lesenswert?

Christian J. schrieb:
> Das ist echt Blödsinn, weil man den Bus ja eh nur ziehen oder loslassen
> kann.

Genau!

Und bei der SCL-Leitung baust Du zusätzlich nach dem Loslassen noch ne 
while-schleife ein die so lange wartet bis der Pin auch tatsächlich auf 
high gegangen ist, damit hast Du dann mit nur einer Zeile zusätzlichem 
Code noch das Clock-Stretching ebenfalls berücksichtigt (denn nichts 
anderes ist das: der Slave darf jederzeit die SCL nach unten ziehen und 
der Master muss bei jedem Loslassen der SCL-Leitung so lange warten bis 
sie tatsächlich auf high gegangen ist.)

Du bist also schon nahe dran, das bekommst Du heute noch hin.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Es klappt...... einfach die Sch.. in die Tonne und woanders mal was 
runterladen von einer Firmenpage. Nicht viel nachdenken, einfach ändern 
und benutzen und siehe da, 0x19 reingschrieben mit einem HV Programmer 
und 0x19 wieder ausgelesen. Die Soft I2c ist sehr schön klein, nur 300 
Bytes, das freut.

Das ACK überlesen die aber alle, kein stretching. Kann man machen, 
ja....

So kann man sich auch dden Tag um die Ohren hauen :-)

[code]

/**********************************************************

Software I2C Library for AVR Devices.

Copyright 2008-2012
eXtreme Electronics, India
www.eXtremeElectronics.co.in
**********************************************************/

#include <avr/io.h>
#include <util/delay.h>


#define SCLPORT  PORTA  //TAKE PORTD as SCL OUTPUT WRITE
#define SCLDDR  DDRA  //TAKE DDRB as SCL INPUT/OUTPUT configure

#define SDAPORT  PORTA  //TAKE PORTD as SDA OUTPUT WRITE
#define SDADDR  DDRA  //TAKE PORTD as SDA INPUT configure

#define SDAPIN  PINA  //TAKE PORTD TO READ DATA
#define SCLPIN  PINA  //TAKE PORTD TO READ DATA

#define SCL  PA4    //PORTD.0 PIN AS SCL PIN
#define SDA  PA6    //PORTD.1 PIN AS SDA PIN


#define SOFT_I2C_SDA_LOW  SDADDR|=((1<<SDA))
#define SOFT_I2C_SDA_HIGH  SDADDR&=(~(1<<SDA))

#define SOFT_I2C_SCL_LOW  SCLDDR|=((1<<SCL))
#define SOFT_I2C_SCL_HIGH  SCLDDR&=(~(1<<SCL))


#define Q_DEL _delay_loop_2(3)
#define H_DEL _delay_loop_2(5)

void i2c_init()
{
  SDAPORT&=(1<<SDA);
  SCLPORT&=(1<<SCL);

  SOFT_I2C_SDA_HIGH;
  SOFT_I2C_SCL_HIGH;

}
void i2c_start()
{
  SOFT_I2C_SCL_HIGH;
  H_DEL;

  SOFT_I2C_SDA_LOW;
  H_DEL;
}

void i2c_stop()
{
   SOFT_I2C_SDA_LOW;
   H_DEL;
   SOFT_I2C_SCL_HIGH;
   Q_DEL;
   SOFT_I2C_SDA_HIGH;
   H_DEL;
}

uint8_t i2c_write(uint8_t data)
{

   uint8_t i;

   for(i=0;i<8;i++)
   {
    SOFT_I2C_SCL_LOW;
    Q_DEL;

    if(data & 0x80)
      SOFT_I2C_SDA_HIGH;
    else
      SOFT_I2C_SDA_LOW;

    H_DEL;

    SOFT_I2C_SCL_HIGH;
    H_DEL;

    while((SCLPIN & (1<<SCL))==0);

    data=data<<1;
  }

  //The 9th clock (ACK Phase)
  SOFT_I2C_SCL_LOW;
  Q_DEL;

  SOFT_I2C_SDA_HIGH;
  H_DEL;

  SOFT_I2C_SCL_HIGH;
  H_DEL;

  uint8_t ack=!(SDAPIN & (1<<SDA));

  SOFT_I2C_SCL_LOW;
  H_DEL;

  return ack;

}


uint8_t i2c_read(uint8_t ack)
{
  uint8_t data=0x00;
  uint8_t i;

  for(i=0;i<8;i++)
  {

    SOFT_I2C_SCL_LOW;
    H_DEL;
    SOFT_I2C_SCL_HIGH;
    H_DEL;

    while((SCLPIN & (1<<SCL))==0);

    if(SDAPIN &(1<<SDA))
      data|=(0x80>>i);

  }

  SOFT_I2C_SCL_LOW;
  Q_DEL;            //Soft_I2C_Put_Ack

  if(ack)
  {
    SOFT_I2C_SDA_LOW;
  }
  else
  {
    SOFT_I2C_SDA_HIGH;
  }
  H_DEL;

  SOFT_I2C_SCL_HIGH;
  H_DEL;

  SOFT_I2C_SCL_LOW;
  H_DEL;

  return data;

}

[code]

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

PS: Die Frage ist vielleicht dämlich aber mir dreht sich eh der Schädel:
Wann benutzt man i2c_read(0) und wann i2c_read(1)?  Das NAK muss doch 
den Leesezyklus beenden, gell?

@AK: Der Glitch ist auch weg :-)


Auf die Terminal Meldung habe ich seit gestern gewartet :-)))))

ID:0xE5 ADXL345 ok!

Fragt man sich natürlich schon etwas wieso man einen Riesen-USI Trümmer 
einbauen soll, der fast 1k frisst anstatt einer Soft I2C, die mit einem 
1/3 auskommt und genauso gut funktioniert? Schneller läuft die CPU damit 
auch nicht, fehlen halt nur die ganzen Fehlermeldungen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Ich bräuchte nochmal eure Hifle, verpacke das jetzt mal in 2 Posts.
Hier wäre als erstes das Diagramm der Kommunikation, des ADXL345.
Ok, soweit gut.....

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Dann hier meine 1-Byte lese Routine (man beachte das ACK) und was dabei 
herauskommt.... E5 ist richtig und danach kommt ein NAK, also könnte man 
denken read(0) erzeugt ein NAK.

/  Lies ein einzelnes Byte aus dem Sensor aus
uint8_t ReadADXL(uint8_t addr)
{
  uint8_t val;

  // Sensor adressieren ( Zeiger auf Zielbyte)
  i2c_start();
  i2c_write(DEVICE_W);
  i2c_write(addr);

  // Byte anfordern
  i2c_start();
  i2c_write(DEVICE_R);
  val = i2c_read(0);
  i2c_stop();
  return (val);

}

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Da ich aber auch gern einen Burst Read durchführen möchte habe ich diese 
Routine so geschrieben... die Schleife wurde für Tests mal weggelassen
Da steht eine (1) drin und das I2C Bild sieht so aus wie gezeigt, nur 
das erste Byte ist richtig, danach sind alle 0. Was sie aber nicht sind 
und nicht sein können.

Ein read(1) erzeugt also jetzt ein ACK und ein read(0) ein NAK. Ok NAK = 
NO ACK, eben keines.

Bloss wieso kommen da nur noch Nullen bei raus nach dem ersten Byte?

static void Read_Mult_ADXL(int address, int num, uint8_t* bptr)
{
  // Sensor adressieren
   i2c_init();
   i2c_start();
   i2c_write(DEVICE_W);
   i2c_write(address);

   // Bytes anfordern
   i2c_start();
   i2c_write(DEVICE_R);
   *bptr++ = i2c_read(1);
   *bptr++ = i2c_read(1);
   *bptr++ = i2c_read(1);
   *bptr++ = i2c_read(1);
   *bptr++ = i2c_read(1);
   *bptr   = i2c_read(0);
  i2c_stop();
}

von Peter D. (peda)


Lesenswert?

Meine Erfahrung ist, das USI taugt nur als I2C-Slave.
I2C-Master oder SPI ist einfacher, kürzer und nervenschonender mit 
Bit-Banging erledigt.

Wenn man die Wahl zwischen I2C und SPI hat, ist SPI eindeutig im 
Vorteil. Man braucht keine Adresse, ACK, Delays usw., d.h. man ist 
erheblich schneller und der Code kleiner.
Auch das Umschalten des DIO ist in SW ein Klacks.

Wenn man von irgendwo her Libs nimmt, hat man 2 Fehlerquellen:
1. die Lib hat Fehler.
2. man benutzt die Lib falsch.
Man sollte also vorher wissen, ob die Lib schon von vielen in der 
gleichen Konfiguration erfolgreich eingesetzt wure.

von Christian J. (Gast)


Lesenswert?

Danke für die Antwort aber beim  Bitbang sind wir ja schon, ich wurde 
überzeugt, zudem der Code extrem kurz ist. Und die Lib funktioniert 
ja.... naja, das meiste jedenfalls, sind ja nur 5 Routinen drin, die man 
kombinieren kann.

Zudem der Analyzer ja sofort meckert, wenn das Codemuster falsch ist. 
Dieses Chinateil ist schon echt nett.

Also bleiben die Nullen ungeklärt... die sind ja hardwaremäßßig da wie 
man sieht. Er hört einfach auf zuu funken nach dem ersten Byte :-(

von Georg G. (df2au)


Lesenswert?

Ich weiß, ich bin penetrant... DATENBLATT (dieses Mal groß und ganz 
langsam geschrieben).

Mehrere Bytes nacheinander gelesen kommen von aufeinander folgenden 
Adressen (Auto-Increment). Und was finden wir für die Register 
0x01-0x1c? "RESERVED, DO NOT ACCESS!"

Noch ein Hinweis: Du bist stolz auf deine Routinen, die nun 
funktionieren. Dabei hast du aber konsequent ignoriert, wie man die Port 
Umschaltung machen soll (per DDR). Du fragst hier nach Hilfe. Dann nimm 
sie auch an. So demotiviert das jeden, zukünftig auf deine Probleme ein 
zu gehen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Und was steht da ? Sieht für mich nach DDR aus..

#define SOFT_I2C_SDA_LOW  SDADDR|=((1<<SDA))
#define SOFT_I2C_SDA_HIGH  SDADDR&=(~(1<<SDA))

#define SOFT_I2C_SCL_LOW  SCLDDR|=((1<<SCL))
#define SOFT_I2C_SCL_HIGH  SCLDDR&=(~(1<<SCL))

>>Mehrere Bytes nacheinander gelesen kommen von aufeinander folgenden
>>Adressen (Auto-Increment). Und was finden wir für die Register
>>0x01-0x1c? "RESERVED, DO NOT ACCESS!

Gilt übrigens für alle Register, egal welche ich da einstelle. Eines der 
Rätsel, deren Ursache nur schwer zu finden sein dürften....

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

@Georg:

ich nerv nochmal, da mir das keine Ruhe lässt und aufgeben nicht drin 
ist.
Derzeit an einem Eprom, weil mir das besser bekannt ist. Die 0xOD habe 
ich in eine Zelle geschrieben. 1101 sind die letzten Bits.

Der Source Code steht ja oben. Ich vermute, dass am Ende der i2c_read 
was nicht stimmt, dass die nur einmal funktioniert und dann nie wieder. 
Aufgefallen ist mir das an einem Clock Puls der kürzer war als alle 
anderen.
Ich habe zusätzlich in der Leseschleife eine Pause von 20us eingefügt, 
damit man die Lesezyklen unterscheiden kann.

Das Bild oben entsteht, wenn ich die letzten Zeilen auskommentiere, 
damit SCL wieder auf "Idle" geht nach einem Lesevorgang, sonst .... 
siehe dazu nächstes Posting.

Routine zum Bild:

uint8_t i2c_read(uint8_t ack)
{
  uint8_t data=0x00;
  uint8_t i;

  for(i=0;i<8;i++)
  {
    // SCL clocken
    SOFT_I2C_SCL_LOW;
    H_DEL;
    SOFT_I2C_SCL_HIGH;
    H_DEL;

    while((SCLPIN & (1<<SCL)) == 0);

    if(SDAPIN & (1<<SDA))
      data |= (0x80>>i);

  }

  SOFT_I2C_SCL_LOW;
  Q_DEL;            //Soft_I2C_Put_Ack

  if(ack) {
    SOFT_I2C_SDA_LOW;
  }
  else {
    SOFT_I2C_SDA_HIGH;
  }
  H_DEL;

  SOFT_I2C_SCL_HIGH;
  H_DEL;

  //SOFT_I2C_SCL_LOW;
  //H_DEL;

  return data;

}

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Und jetzt die Geschichte, wenn ich

 SOFT_I2C_SCL_HIGH;
  H_DEL;

  SOFT_I2C_SCL_LOW;
  H_DEL;

  return data;

wieder reinmache. Der Peask da ist 2us lang, kürzer als alle anderen im 
gesamten Telegramm, die mindestens 3us und 5us lang sein. SCL bleibt 
gezogen auch in der Pause, der Bus ist blockiert. Seltsam. Leider sind 
es immer noch 0en, mit beiden Versionen aber da ist doch was faul....

Die Leseroutine für die Aufzeichung
1
void read_ee(uint8_t adr, uint8_t num, uint8_t* ptr)
2
{
3
  i2c_init();
4
  i2c_start();
5
  i2c_write(0b10100000);
6
  i2c_write(0);
7
  i2c_write(adr);
8
  
9
  i2c_start();
10
  i2c_write(0b10100001);
11
  for (int i = 0;i < (num-1);i++) 
12
  {  
13
    *(ptr++) = i2c_read(1);
14
    delayMicroseconds(20);
15
  }    
16
  
17
  *(ptr++) = i2c_read(0);
18
  i2c_stop();
19
  
20
}

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Anbei noch die Aufzeichnung des "Selea Logic", einem Billig Analyzer. 
Vielleicht hat ja jemand so einen und kann sich das dann anschauen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

PS:

Nachdem ich mich totgesucht habe hier nun die Auflösung: Die letzte 
Codezeile musste da noch hin und dann läuft es auch. Mannomann, das war 
ne schwere Geburt....
1
uint8_t SoftI2CReadByte(uint8_t ack)
2
{
3
uint8_t data=0×00;
4
uint8_t i;
5
6
for(i=0;i<8;i++)
7
{
8
9
SOFT_I2C_SCL_LOW;
10
H_DEL;
11
SOFT_I2C_SCL_HIGH;
12
H_DEL;
13
14
while((SCLPIN & (1<<SCL))==0);
15
16
if(SDAPIN &(1<>i);
17
18
}
19
20
SOFT_I2C_SCL_LOW;
21
Q_DEL;  //Soft_I2C_Put_Ack
22
23
if(ack)
24
{
25
//H_DEL;
26
SOFT_I2C_SDA_LOW;
27
}
28
else
29
{
30
SOFT_I2C_SDA_HIGH;
31
}
32
H_DEL;
33
34
SOFT_I2C_SCL_HIGH;
35
H_DEL;
36
37
SOFT_I2C_SCL_LOW;
38
H_DEL;
39
40
SOFT_I2C_SDA_HIGH; // was missing!!
41
42
return data;
43
44
}

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.