TWI mit Atmega: Bitte mal drüber schauen

Gast #2890977
Lesenswert?

Hi!

Ich mache erste Gehversuche mit Hardware-TWI und hätte gerne, dass mal 
jemand über meinen Code schaut, ob alles stimmt oder man etwas anders 
lösen sollte. Er funktioniert auf den ersten Blick, aber beim Lesen gibt 
es noch Ungereimtheiten.

Es geht um das Auslesen eines 16 Bit ADCs (MCP 3426A0-E/SN)
Datenblatt:
http://www.reichelt.de/index.html?;ACTION=7;LA=3;OPEN=0;INDEX=0;FILENAME=A200%252FMCP3426-27-28.pdf;SID=15mbpbf6wQAQ8AAErTpj4f6a3708b2c9f2202a217a92c8223acf3

Zunächst das Senden. TWI-Takt ist auf 100khz eingestellt, data ist vom 
Typ uint8_t und die Konfiguration für den ADC. Der Code funktioniert, 
ich kann später das data-Byte wieder aus dem ADC lesen. Der Code 
entspricht im Wesentlichen dem aus dem Datenblatt vom Atmega.
1
#define SLA_W 0b11010000; //4 Bits device code (1101), 3 Bits addres (factory programmed, hier 0), r/!w-Bit
2
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); //Start condition senden
3
while  (!(TWCR & (1<<TWINT))); //Warten bis start condition gesendet wurde.
4
if ((TWSR & 0xF8) != TW_START)  ERROR(1); //Fehler: Status ist nicht Start.
5
TWDR = SLA_W; //Master Transmitter (Slave-Write)
6
TWCR = (1<<TWINT) | (1<<TWEN); //TWINT-Bit löschen um Übertragung zu starten
7
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
8
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)  ERROR(2); //Fehler: Status ist nicht ACK.
9

10
TWDR = data; //Nutzdaten laden
11
TWCR = (1<<TWINT) | (1<<TWEN); //Senden
12
while (!(TWCR & (1<<TWINT))); //Auf ack des Slaves warten
13
if ((TWSR & 0xF8) != TW_MT_DATA_ACK) ERROR(3); //Status ist nicht ACK
14

15
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Stop-Condition senden
16
//Muss ich die Stop-Condition senden, wenn ich nur einen Master und nur ein Slave auf dem Bus habe?
Gast #2890992
Lesenswert?

Und das Auslesen. Hier stimmt noch etwas nicht. Laut dem ADC-Datenblatt 
sollte ich 3 Bytes (Highbyte, Lowbyte, Config-Byte) zurück bekommen, 
wobei das Config-Byte wiederholt wird, wenn man weiter liest. Ich 
bekomme aber vor dem Highbyte den Inhalt von SLA_R zurück.

receivedata1 bis 4 ist uint8_t.
1
#define SLA_R 0b11010001; //4 Bits device code (1101), 3 Bits address (factory programmed: Aufdruck A0 bedeutet 0, A1 bedeutet 1 usw.), r/!w-Bit
2
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); //Start condition senden
3
while  (!(TWCR & (1<<TWINT))); //Warten bis start condition gesendet wurde.
4
if ((TWSR & 0xF8) != TW_START)  ERROR(4); //Fehler: Status ist nicht Start.
5

6
TWDR = SLA_R; //Master Receiver (Slave-Read)
7
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
8
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
9
if ((TWSR & 0xF8) != TW_MR_SLA_ACK)  ERROR(5); //Fehler: Status ist nicht ACK.
10
receivedata1 = TWDR; //Messwert empfangen
11

12
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
13
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
14
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
15
if ((TWSR & 0xF8) != TW_MR_DATA_ACK) ERROR(6); //Fehler: Status ist nicht ACK.
16
receivedata2 = TWDR; //Messwert empfangen
17

18
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
19
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); //TWINT-Bit löschen um Übertragung zu starten
20
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
21
if ((TWSR & 0xF8) != TW_MR_DATA_ACK) ERROR(6); //Fehler: Status ist nicht ACK.
22
receivedata3 = TWDR; //Messwert empfangen
23

24
TWDR = SLA_R; //Master Receiver (Slave-Read) Notwendig?
25
TWCR = (1<<TWINT) | (1<<TWEN); //TWINT-Bit löschen um Übertragung zu starten. Letzte Übertragung, daher ohne TWEA. => Ergibt NACK.
26
while (!(TWCR & (1<<TWINT))); //Warten bis übertragen
27
if ((TWSR & 0xF8) != TW_MR_DATA_NACK) ERROR(6); //Fehler: Status ist nicht ACK.
28
receivedata4 = TWDR; //Messwert empfangen
29

30
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Stop-Condition senden
31

32
uart_putc (receivedata1); //Ergibt SLA_R. Warum?
33
uart_putc (receivedata2); //Ergibt 255 (ADC-Eingänge unbeschaltet)
34
uart_putc (receivedata3); //Ergibt 248 (ADC-Eingänge unbeschaltet)
35
uart_putc (receivedata4); //Ergibt config-Byte
Gast #2891210
Lesenswert?

Hi,
warum das Rad neu erfinden? Es gibt viele TWI-Bibliotheken für ATmega, 
die zumindest den Master-Mode können:
Von Atmel z.B. AVR Appplication Note AVR315 oder bei Sparkfun.com kannst 
du dir unter dem Suchbegriff BMP085 auch funktionierenden Beispielcode 
für einen anderen TWI-Sensor angucken, wenn du nach "Fleury TWI Master" 
googelst findest du auch was. Und auch bei mikrocontroller.net findest 
du einiges.

UM TWI zu verstehen, ist es wesentlich einfacher sich an den vorhandenen 
Dingern langzuhangeln als auf Basis der Beschreibung im ATmega-Manual 
die Kuh zum Fliegen zu bringen. Just my two cents...
Gast #2891506
Lesenswert?

So, das Einlesen des ADCs funktioniert, wenn ich ihn anfasse, zappeln 
die Werte herum :)

Warum vor dem Highbyte nochmal die Konfiguration gelesen wird, habe ich 
mir noch nicht näher angeschaut.

Vielen Dank für die Appnote, die habe ich mir heute Morgen angeschaut, 
aber mein eigener Code ist für mich doch verständlicher. Interrupts sind 
für diesen Zweck gut, aber ich kann es wohl einfacher lösen, wenn ich 
meinen Code immer wieder aufrufe. Ich schreibe ihn gerade um, damit er 
nicht blockierend arbeitet.
Da der Controller sonst fast nichts zu tun hat, sollte das fast so 
schnell laufen wie die Interruptlösung.

Gruß,
Chris

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