Forum: Mikrocontroller und Digitale Elektronik I2C Geschwindigkeit


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Maxim B. (max182)


Lesenswert?

Guten Tag!
Ich habe folgende Frage:
LCD ist über mcp23008 und I2C an AT Mega 324PA angeschlossen.
Ich habe zwei Varianten von Programm: Programm-I2C und TWI. Während 
Programm-I2C keine Mindestgeschwindigkeit zeigt und stabil wie mit 842 
kHz so auch mit 10,3 kHz (unter 10,3 kHz ging ich nicht) bleibt, gibt es 
mit TWI komische Beschränkungen.

1. Laut Formel (Datenblatt für ATMega324PA - 1284P, Seite 210) sollte 
bei TWBR = 0 (und F_CPU = 16 MHz) I2C-Geschwindigkeit 1000 kHz möglich 
sein. Es stehen im Datenblatt keine Beschränkungen. Trotzdem will TWI 
mit TWBR = 0 nicht arbeiten. Das liegt nicht in Geschwindigkeit selbst, 
da auch bei TWSR = (1<<TWPS0) und TWSR = (1<<TWPS1) keine Funktion.

2. TWI will funktionieren nur zwischen 888 kHz und 258 kHz (TWBR = 
1...23). Hier liegt das in Geschwindigkeit, da auch mit TWBR = 1 und 
TWSR = (1<<TWPS1)|(1<<TWPS0) keine Arbeit, so wie bei TWBR = 2 und TWSR 
= (1<<TWPS1) und mit TWBR = 6 und TWSR = (1<<TWPS0).
Normale Arbeit:
TWPS1 = TWPS0 = 0 und TWBR = 1..23
TWPS0 = 1 und TWBR = 1..5
TWPS1 = 1 und TWBR = 1

Für mich ist diese Beschränkung von unten sehr komisch.

Vielleicht kennt jemand die Antwort?

Ich könnte schon denken, chinesische LCD kann nicht so langsam Daten 
nehmen. Aber Programm-I2C läuft auch langsam! Mit TWI unter 258 kHz: nur 
blinkt die Beleuchung (das ist bei mir an Port0 angeschlossen) und wenn 
ich JTAG benutze, sehe ich, daß bei LCD-Init Bildschirm nicht gelöscht 
wird und bei Zeilenausgabe kommen komische Zeichen an falschem Platz.

: Bearbeitet durch User
von Jens G. (jensig)


Lesenswert?

>Vielleicht kennt jemand die Antwort?

Auf was?

von Maxim B. (max182)


Lesenswert?

Warum arbeitet TWI nicht unter 258 kHz - obwohl Standart 100 kHz in 
jedem Fall funktionieren sollte.
Auch warum trotz Datenblatt TWBR = 0 nicht arbeitet.
Funktionen:
1
static inline void i2c_init (void) {
2
  TWBR = FTWI;
3
  I2C_DDR &= ~(1<<I2C_SDA);
4
  I2C_DDR &= ~(1<<I2C_SCL);
5
  I2C_PORT &= ~(1<<I2C_SDA);
6
  I2C_PORT &= ~(1<<I2C_SCL);
7
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
8
}
9
10
static inline void i2c_stop_cond (void){
11
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
12
}
13
14
static inline void i2c_start_cond (void){
15
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
16
  while  (!(TWCR & (1<<TWINT)));
17
}
18
19
static inline void i2c_restart_cond (void){
20
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
21
  while  (!(TWCR & (1<<TWINT)));
22
}
23
24
static inline unsigned char i2c_send_byte (unsigned char data){
25
  unsigned char ack=0;  // ACK, wenn ACK=1 – Fehler
26
  TWDR = data;
27
  TWCR = (1<<TWINT) | (1<<TWEN);
28
  while (!(TWCR & (1<<TWINT)));
29
  if ((TWSR & 0xF8) != TW_MT_DATA_ACK) {
30
    ack = 1;
31
  }
32
  return ack; // ACK (0) NACK (1) zurueckgeben
33
}
34
35
static inline unsigned char i2c_get_byte (unsigned char last_byte){
36
  if(last_byte==0)
37
  {
38
    // ackFlag = TRUE: ACK the recevied data
39
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
40
  }
41
  else
42
  {
43
    // ackFlag = FALSE: NACK the recevied data
44
    TWCR = (1<<TWINT)|(1<<TWEN);
45
  }
46
  while (!(TWCR & (1<<TWINT)));
47
  return TWDR;
48
}
Alles andere wie mit Programm-I2C

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

I2c läuft bis runter zu 0Hz. Dein Problem ist ein anderes.

Z.b. falsche Register, Doppelimpulse, interupts, ...

Maxim B. schrieb:
> Aber Programm-I2C läuft auch langsam!

Falls das bedeuten soll, dass es selbst programmiert ist, ja, da gibt's 
viele Fallstricke, meist im Zusammenhang mit clock-stretching.

von Maxim B. (max182)


Lesenswert?

A. S. schrieb:
> Z.b. falsche Register, Doppelimpulse, interupts, ...

Natürlich.
Deshalb habe ich hier relevante Code angegeben. Deshalb frage ich, was 
falsch.

Nur ISR kann das nicht sein: sonst wäre auch Programm-I2C gestört.
ISR gibt es jede 1 ms und jede 1 S. Das stört aber wenig, da alles als 
Flagautomat gebaut ist, Flag wie ein Zähler. D.h. auch wenn 
I2C-Operation zu lange dauert, werden verpasste ISR danach doch alle 
bearbeitet. In ISR selbst wird nur Flag incrementiert, Bearbeitung in 
Hauptschleife.

So glaube ich nicht, daß das an ISR liegt. Bei langsamsten Tempo wird 
Melodie (die ich zu Kontrolle einprogrammiert habe) etwas arythmisch 
gespielt, das ist aber einzige negative Folge.

Für mich ist sehr wichtig, zu verstehen, warum TWI nicht langsam will. 
jetzt bringt das zwar kein Problem. Aber in der Zukunft kann so etwas 
ganz überraschend irgendwie wirken.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Auch warum trotz Datenblatt TWBR = 0 nicht arbeitet.

In der Anfangszeit der AVRs lief TWI nur mit TWBR>=10. Außerdem ist das 
TWI nur bis SCL-Clock 400kHz spezifiziert.

>TWPS0 = 1 und TWBR = 1..5
>TWPS1 = 1 und TWBR = 1

Die TWPS-Bits sind bei mir immer 0. TWPS0:1= 11 bedeutet einen Prescaler 
von 64.

MfG Spess

von Maxim B. (max182)


Lesenswert?

Vor allem ist für mich wichtig, TWI zu langsamer Arbeit zu zwingen. Kann 
sein, daß ich später IC habe, die nur für 100 kHz spezifiziert sind.

spess53 schrieb:
> Die TWPS-Bits sind bei mir immer 0. TWPS0:1= 11 bedeutet einen Prescaler
> von 64.

Mit TWPS habe ich nur deshalb versucht, um zu verstehen, daß Problem 
nicht in TWBR als solchen sondern in Geschwindigkeit liegt.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mit Peter Fleurys I²C Lib (twimaster.c, also die Hardware Variante) 
drücke ich die Datenrate auch herunter auf 30kHz für z.B. den SMBus.
Du solltest dir evtl. mal den Quellcode anschauen:

http://homepage.hispeed.ch/peterfleury/avr-software.html

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Matthias S. schrieb:
> Mit Peter Fleurys I²C Lib (twimaster.c, also die Hardware Variante)
> drücke ich die Datenrate auch herunter auf 30kHz

Danke! Ich werde sie ankucken.

Ich möchte jetzt TWI gut verstehen, weil ich danach TWI mit ISR benutzen 
möchte, auch als Slave.

von spess53 (Gast)


Lesenswert?

Hi

>Vor allem ist für mich wichtig, TWI zu langsamer Arbeit zu zwingen. Kann
>sein, daß ich später IC habe, die nur für 100 kHz spezifiziert sind.

Ja und? Das klappt mit TWPS=0 bis ca. 3,5MHz CPU-Takt.

>Mit TWPS habe ich nur deshalb versucht, um zu verstehen, daß Problem
>nicht in TWBR als solchen sondern in Geschwindigkeit liegt.

Was heisst das in Deutsch?

MfG Spess

von Maxim B. (max182)


Lesenswert?

spess53 schrieb:
> Was heisst das in Deutsch?

Was willst du genau wissen, außer ich schon geschrieben habe?

von Stefan F. (Gast)


Lesenswert?

Hast du die Kommunikation mit einem Logic-Analyzer aufgezeichnet und 
kontrolliert?

Das würde ich beides mal als erstes tun, anstatt zu raten.

von Maxim B. (max182)


Lesenswert?

Stefanus F. schrieb:
> Hast du die Kommunikation mit einem Logic-Analyzer aufgezeichnet

Den habe ich noch nicht. ich habe einfach mit JTAGICE gekuckt.
Hätte ich Problem in der Schaltung, so würde auch Programm-I2C nicht 
arbeiten. Wahrscheinlich vergesse ich etwas bei TWI-Init, aber was 
genau?

von Stefan F. (Gast)


Lesenswert?

Maxim B. schrieb:
> Hätte ich Problem in der Schaltung, so würde auch Programm-I2C nicht
> arbeiten.

Es geht darum, die Kommunikation zu überprüfen, nicht die Hardware.

von Maxim B. (max182)


Lesenswert?

Matthias S. schrieb:
> Mit Peter Fleurys I²C Lib (twimaster.c, also die Hardware Variante)
> drücke ich die Datenrate auch herunter auf 30kHz für z.B. den SMBus.
> Du solltest dir evtl. mal den Quellcode anschauen:
>
> http://homepage.hispeed.ch/peterfleury/avr-software.html

Das hat mit geholfen!

Jetzt funktioniert TWI auf allen möglichen Geschwindigkeiten.
Problem war in Code.
Bei mir:
1
static inline void i2c_start_cond (void){
2
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
3
  while  (!(TWCR & (1<<TWINT)));
4
}
5
6
static inline unsigned char i2c_send_byte (unsigned char data){
7
  unsigned char ack=0;  // ACK, wenn ACK=1 – Fehler
8
  TWDR = data;
9
  TWCR = (1<<TWINT) | (1<<TWEN);
10
  while (!(TWCR & (1<<TWINT)));
11
  if ((TWSR & 0xF8) != TW_MT_DATA_ACK) {
12
    ack = 1;
13
  }
14
  return ack; // ACK (0) NACK (1) zurueckgeben
15
}

Nach Korrektur:
1
static inline u8 i2c_start_cond (void){
2
  u8 twst;
3
4
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);  // send START condition
5
  while(!(TWCR & (1<<TWINT)));  // wait until transmission completed
6
  twst = TW_STATUS & 0xF8;
7
  if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
8
  return 0;
9
}
10
11
static inline unsigned char i2c_send_byte (unsigned char data){
12
  u8 twst;
13
14
  TWDR = data;
15
  TWCR = (1<<TWINT) | (1<<TWEN);
16
  while (!(TWCR & (1<<TWINT)));
17
18
  twst = TW_STATUS & 0xF8;
19
20
  if((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) return 1;
21
  return 0;
22
}

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.