I2C Geschwindigkeit

OP #5975512
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.
OP #5975527
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
Gast #5975536
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.
OP #5975543
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.
Gast #5975591
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
OP #5975630
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.
Gast #5975678
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
OP #5975800
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren