Hallo Mikrocontroller-Gemeinde =) Ich verzweifel an einem Problem und hoffe auf ein bisschen Hilfe! =) Zu meinem Problem: Ich habe einen Atmega8 (Master) über TWI an einen TAS5518 (Slave) angeschlossen. Dass es jetzt ein TAS5518 ist, ist wohl irrelevant... TWI Clock ist 100kHz. Bei Schreibbefehlen tritt keinerlei Fehler auf, nach jedem Byte bekomme ich ein ACK. Nun möchte ich die Speicherstelle 0x02 des TAS5518 auslesen. (ist ein Fehler-Status-byte) Grundlage ist die lib von Peter Fleury... Dazu muss ich die Addresse des TAS5518 senden(00110110=0x36) mit einem Write, dann 0x02 senden, danach ein rep_start machen, danach wieder die Adresse des TAS5518 aber mit einem Read-bit... Hier der mit Oszi abgelesene Datenstrom: 00110110 0 00000010 0 restart 00110111 0 Adr.Write ACK 0x02 ACK cond. Adr.Read ACK Hier sieht man dass der Slave brav nach jedem byte ACK sendet. Die ersten beiden ACKs erkennt der Atmega auch noch. Z.B. steht nach dem senden von 0x02 im TWSR 0x28 (Databyte gesendet und Ack empfangen).... Leider steht nach dem Senden vom Adresse-Read-Byte 0x48 im TWSR, was ja bedeutet dass KEIN ACK empfangen wurde... Das ACK kommt aber (laut Oszi)... Woran kann das liegen?? Ich bin wirklich dankbar für jeden Hinweis! Hier noch die Aufrufe die ich verwende: Hauptprogramm: i2c_start_wait(TAS5518+I2C_WRITE); i2c_write(0x02); i2c_rep_start(TAS5518+I2C_READ); ret = i2c_readNak(); //Hier bleibt der Controller hängen Hier die i2c_readNack(): unsigned char i2c_readNak(void) { TWCR = (1<<TWINT) | (1<<TWEN); while(!(TWCR & (1<<TWINT))); return TWDR; }/* i2c_readNak */ Da im TWSR steht dass kein ACK empfangen wurde fängt die TWI-Einheit nicht an zu laufen beim Versuch TWEN zu setzen, so dass TWINT nie 0 gesetzt wird. Danke, Lukas Hier noch alle anderen Routinen: /*********************************************************************** ** * Title: I2C master library using hardware TWI interface * Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury * File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 * Target: any AVR device with hardware TWI * Usage: API compatible with I2C Software Library i2cmaster.h ************************************************************************ **/ #include <inttypes.h> #include <compat/twi.h> #include <util/delay.h> #include "i2cmaster.h" /* define CPU frequency in Mhz here if not defined in Makefile */ #ifndef F_CPU #define F_CPU 1000000UL #endif /* I2C clock in Hz */ #define SCL_CLOCK 100000L /*********************************************************************** ** Initialization of the I2C bus interface. Need to be called only once ************************************************************************ */ void i2c_init(void) { /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ TWSR = 0; /* no prescaler */ TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */ }/* i2c_init */ /*********************************************************************** ** Issues a start condition and sends address and transfer direction. return 0 = device accessible, 1= failed to access device ************************************************************************ */ unsigned char i2c_start(unsigned char address) { uint8_t twst; // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed and ACK/NACK has been received while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; return 0; }/* i2c_start */ /*********************************************************************** ** Issues a start condition and sends address and transfer direction. If device is busy, use ack polling to wait until device is ready Input: address and transfer direction of I2C device ************************************************************************ */ void i2c_start_wait(unsigned char address) { uint8_t twst; while ( 1 ) { // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) continue; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) { /* device busy, send stop condition to terminate write operation */ TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // wait until stop condition is executed and bus released while(TWCR & (1<<TWSTO)); continue; } //if( twst != TW_MT_SLA_ACK) return 1; break; } }/* i2c_start_wait */ /*********************************************************************** ** Issues a repeated start condition and sends address and transfer direction Input: address and transfer direction of I2C device Return: 0 device accessible 1 failed to access device ************************************************************************ */ unsigned char i2c_rep_start(unsigned char address) { return i2c_start( address ); }/* i2c_rep_start */ /*********************************************************************** ** Terminates the data transfer and releases the I2C bus ************************************************************************ */ void i2c_stop(void) { /* send stop condition */ TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // wait until stop condition is executed and bus released while(TWCR & (1<<TWSTO)); }/* i2c_stop */ /*********************************************************************** ** Send one byte to I2C device Input: byte to be transfered Return: 0 write successful 1 write failed ************************************************************************ */ unsigned char i2c_write( unsigned char data ) { uint8_t twst; // send data to the previously addressed device TWDR = data; TWCR = (1<<TWINT) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits twst = TW_STATUS & 0xF8; if( twst != TW_MT_DATA_ACK) return 1; return 0; }/* i2c_write */ /*********************************************************************** ** Read one byte from the I2C device, request more data from device Return: byte read from I2C device ************************************************************************ */ unsigned char i2c_readAck(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); while(!(TWCR & (1<<TWINT))); return TWDR; }/* i2c_readAck */ /*********************************************************************** ** Read one byte from the I2C device, read is followed by a stop condition Return: byte read from I2C device ************************************************************************ */ unsigned char i2c_readNak(void) { TWCR = (1<<TWINT) | (1<<TWEN); while(!(TWCR & (1<<TWINT))); return TWDR; }/* i2c_readNak */
Probier mal folgende Varianten aus, was da passiert: A): i2c_start_wait(TAS5518); i2c_write(0x02); i2c_stop(); i2c_rep_start(TAS5518 | 0x01); ret = i2c_readNak(); //Hier bleibt der Controller hängen i2c_stop(); i2c_start_wait(TAS5518); i2c_write(0x02); i2c_stop(); i2c_start_wait(TAS5518 | 0x01); ret = i2c_readAkc(); //Hier bleibt der Controller hängen i2c_stop();
Hi Artur! Ist ne gute Idee gewesen =) Leider bleibt der controller jedes mal in der while()-Schleife sowohl beim readNak oder readAck "hängen". Auch mit nem "richtigem" Stop, und start... Die Funktion i2c_start_wait(TAS5518|0x01) wird ausgeführt, sprich die Funktion erkennt dass ein Ack empfangen wurde, nur leider steht beim Aufruf der I2c_readNak() im TWSR 0x48, also KEIN Ack empfangen... Danke trozdem! Lukas
Hi, mach mal vor dem Repeated Start ne 50µs Pause (oder weniger, ich war aber zu faul weiter zu testen, funzte ja), dann hat es bei mir geklappt mit nem TDA 7318. Also so: i2c_start_wait(TAS5518+I2C_WRITE); i2c_write(0x02); _delay_us(50); i2c_rep_start(TAS5518+I2C_READ); ret = i2c_readNak(); Gruß und viel Erfolg.
hallo! ich habe eine ähnliche konstellation.möchte den SMB380 Beschleunigungssensor von bosch mit einem ATmega1281 im Master-Receive-Mode auslesen.mein problem ist,dass sich der µC in einem funkmodul befindet und ich aufgrund dessen,die twi-schnittstelle über die API´s des funkprotokolls verwenden muss. eigentlich ist aber der ablauf genau wie sonst beim TWI-protokoll. damit ich sehen kann ob überhaupt etwas passiert,wollte ich zuerst eimal ein register des SMB380 auslesen (genauerer gesagt die register address 0x00 die mir die chip-id liefert). dafür hat das funkprotokoll die funktion "HAL_ReadI2cPacket(HAL_I2cParams_t *reparams)" die typedef struct sieht dabei so aus: typedef struct { /** \brief slave address */ uint8_t id; /** \brief number of bytes to be written to the bus */ uint16_t length; /** \brief pointer to the data (for avr internal address include to data field)*/ uint8_t *data; /** \brief callback function */ void (*f)(bool result); } HAL_I2cParams_t; meine frage geht vor allem in die richtung,was ich bei "uint8_t *data" reinschreibe? wie mache ich der Read-Funktion klar,dass sie der Adresse ausgibt,die ich auslesen will? wenn ich der struktur folgende werte übergebe: accessI2c.id = 0x38; // slave-adresse des SMB380 accessI2c.length = 2; // 2byte schreiben accessI2c.data = (uint8_t *) & ?????; accessI2c.f = f; HAL_ReadI2cPacket(&accessI2c); liefert mir das statusregister TWSR anfangs 0x08 zurück und dann 0x50.also wurden daten erfolgreich empfangen. wie konfigurier ich das nun für den wert,den ich aus einem register lesen will?
kann mir hier keiner helfen? mir geht es hauptsächlich darum,was ich für die definition: /** \brief pointer to the data (for avr internal address include to data field)*/ in mein programm schreibe! ich dachte mir halt nach folgendem code accessI2c.data = (uint8_t *) & ?????; das ich für "?????" evtl ein feld rein schreibe,worin die registeradresse 0x00 die ich auslesen will drin steht? bin für jede hilfe dankbar! Im datenblatt des SMB380 steht folgendes: "To be able to access registers in read mode,first address has to be send in write mode.Then a stop and a start condition are issued and data bytes are transferred with automatic address increment."
Hallo Gemeinde. Wäre gut,wenn mir jemand helfen könnte.habe ein ähnliches Problem,nur anders herum: Ich nutze auch die lib von Peter Fleury und lese damit einen Sensor aus. Ich will auch erstmal probieren,um Register ausgelesen werden können. Im AVR-Studio zeigt es mir das erfolgreiche Auslesen des Register an,d.h. wenn ich Register "0x00" auslesen will,steht dann auch im TWDR "0x02". Das Problem was ich habe ist,dass mir der Datenstrom im Oszi einen völlig anderen Registerinhalt anzeigt!!Anstatt der 0x02 steht dann meistens ein 0x07 oder 0x05. Komischerweise sehe ich auch keinen ACK-Impuls nach dem repeated start,aber debugge ich mein Programm bis dahin gibt mir das TWI-Statusregister trotzdem 0x40 aus,was heißt: "SLA+R has been transmitted;ACK has been received" Kann mir jemand helfen? Hier noch mein Code: void startInclinationSensor(void) { uint8_t inclination; DDRC = 0x00; initI2c(); while(1) { startI2c(0x70); writeI2c(0x0B); rep_startI2c(0x71); inclination = readAckI2c(); PORTC = inclination; stopI2c(); } }
noch ein kleiner Nachtrag: Wenn ich while-Schleife weglasse zeigt es mir auch dann im AVR-Studio meistens den falschen Registerinhalt (also die 0x05 oder 0x07) an...
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.