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
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
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.
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
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
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
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
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.
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
spess53 schrieb: > Was heisst das in Deutsch? Was willst du genau wissen, außer ich schon geschrieben habe?
Hast du die Kommunikation mit einem Logic-Analyzer aufgezeichnet und kontrolliert? Das würde ich beides mal als erstes tun, anstatt zu raten.
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.