Forum: Compiler & IDEs TWI Start-Problem: ATMEGA 16, STK-500


von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Hallo!
Ich habe ein Problem mit dem Starten des TWI:
Ich verwende die TWI kommunikation, so wie sie im Datenblatt verwendet 
wird. Allerdings:
Er geht mir nicht mehr aus der While Schleife unter twi_start() raus.

while (!(TWCR & (1<<TWINT)));//Wenn Bus Frei ist:

Außerdem habe ich keine ahnung, wie das mit den auskommentierten zeilen 
darunter funktionieren soll (habe ich aus dem datenblatt, da ich nicht 
weiß was in der Konstanten START drinstehen sollte...

Ich bitte um Hilfe.

main:
#include <avr/io.h>
#include "uart.h"
#include "twi_bib.h"
#include "lcd.h"
#include <util/delay.h>

#define F_CPU 3000000UL
#define DevPCF8574P  0b01000000      // device address of DS1678, see 
datasheet
#define Display 0x74

int main(void)
{
   twi_init();                                // init I2C interface
   uart_init();

    DDRB  = 0xff;                              // use all pins on port B 
for output
    PORTB = 0xff;
   GICR|=0x20;
   MCUCR=0x00;
   MCUCSR=0x40;
   GIFR=0x20;
   TIMSK=0x05;
   uart_puts("\n\n\rHallo! Ich melde mich sofort am System an:\n\r");
   uart_puts("\n\n\rProbiere zu Starten:\n\r");
   twi_start();
   PORTB = 0xf0;
   uart_puts("\n\n\rStart hat funtktioniert!");
   while(1);

   return 0;   //Wird nie erreicht

}

verwendete TWI-funktionen:

void twi_init() {
   TWAR=0x00;//Slave Adress für I2C wird aber nicht benötigt

   //scl-Freq=CPU-Freq/(16+2(TWBR)*4^(Prescaler-Bits(siehe 1)))
   TWBR=0x00;//Da wir 1/16 der CPU-Frequenz wollen.

   TWCR=0x04;//Kein Interrupt/Kein Acknol./TWI Aktivieren
}

short int twi_start() {
   TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);//Setzt Start
   while (!(TWCR & (1<<TWINT)));//Wenn Bus Frei ist:
   //if((TWSR&0xF8)!=START)
   //   return 0;
   //else
      return 1;

}

von Maximilian K. (laplace)


Lesenswert?

Schau mal ob du die Pull-Ups drin hast und ob du du ein Acknowledge 
bekommst (von einem TWI-Slave).

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Danke für deine Antwort:
Also Pull Ups sind drin, gnd ist mit dem GND von dem stk-500 
verbunden...
Der slave hat auch die benötigten 5V.

Allerdings habe ich keine ahnung wie ich das acknolage kontrollieren 
sollte...

Wäre es möglich, dass ich das TWSR register irgendwie überprüfen kann?
irgendwie steht da was im datenblatt von dem register, allerdings habe 
ich keine ahnung wie das funktionieren sollte.

Also das Problem nochmals....
Er geht in das Start-Unterprogramm rein und dann warte ich ca. 4 min und 
erst dann kommt er aus dem unterprogramm raus...

Ich habe am I2C nur ein Display angeschlossen(EAT123A-I2C)

von Maximilian K. (laplace)


Lesenswert?

Ein Logic-Analyzer oder ein DSO wäre hilfreich. Dann könntest du schauen 
was dein TWI treibt.

Schon mal das I2C Master Interface von Peter Fleury ausprobiert? Man 
muss das Rad ja nicht nochmal erfinden. 
(http://homepage.hispeed.ch/peterfleury/avr-software.html#libs)
Einfach twimaster.c ins Projekt und i2cmaster.h einbinden. Dann noch 
i2c_init(); und i2c_start(); usw. Nicht vergessen die Rückgabewerte 
auszuwerten.

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Hallo!
Danke für die Antwort:
Ja ich habe es schon mal ausprobiert mit dem fleury, aber auch ohne 
erfolg...
Ich weiß wirklich nicht was da schuld sein soll.

Es müsste doch auch so gehen, wenn ich den code vom MEGA 16 datenblatt 
verwende...
oder sehe ich das falsch...

ich bin schon sehr frustriert, da ich schon seit wochen den fehler 
versuche zu finden....

gibt es denn sonst nichts?

(Logic analyser ist denke ich ein problem, da dies ein schulprojekt ist 
und wir an der schule nicht das nötige kleingeld dafür haben.

von Sebastian B. (sfreak) Benutzerseite


Lesenswert?

Also erstmal musst du pruefen ob an den SDA und SCL Pins vom AVR 
tatsaechlich high-pegel liegen (I2C braucht Pull-ups! entweder externe 
oder die von den Portpins muessen eingeschaltet sein).

Wenn nicht beide Pins im Ruhezustand high sind wird der AVR glauben der 
I2C Bus sei belegt und NIE das START-Signal ausgeben.

zu der Konstante "START": jedes mal wenn irgendwas auf dem Bus passiert 
ist (START gesendet, daten gesendet, daten empfangen etc.) wird das 
TWINT-Flag in TWCR gesetzt, das du ja schon auswertest. TWSR gibt dann 
an, was genau passiert ist. Du willst pruefen ob die START-Bedingung 
tatsaechlich gesendet wurde (es koennte auch z.B. Busfehler auftreten 
oder sowas, musst mal im Datenblatt nachlesen).  Das tust du indem du 
auf die entsprechende Konstante vergleichst, alle die im Datenblatt 
vorkommen sind auch in der avr-libc in der Datei <util/twi.h> definiert.

von Maximilian K. (laplace)


Lesenswert?

Also wenn ihr an der Schule öfter mit Embedded Systemen arbeitet ist die 
Anschaffung eines Intronic Logigport zu empfehlen. Den bekommt man für 
knapp 300€ und deine wochenlange Suche verkürzt sich in den meisten 
Fällen auf einige Stunden.

Ich denke dein Problem liegt bei der Adressierung des EAT123A. Was du 
noch überprüfen solltest:
- Verwendest du die richtige I2C Slave-Adresse für dein Display?
Wenn ich das richtig gesehen habe verwendet dein EAT123A entweder die 
0x36 oder die 0x37 (hängt wohl von einem SA0-Pin ab?)
- teste mal nochmal mit Fleury und achte darauf, daß du die Adresse 
richtig übergibst:
  i2c_start((slave_address<<1)+I2C_WRITE)

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Hallo nochmal...

Also das mit dem Intronic Logigport liegt nicht in meiner hand, da ich 
nur schüler bin und nicht bestimmen kann, was wann wo gekauft wird. Aber 
danke für den hinweis, ich werde es einem verantwortlichen sagen.

und das START entspricht das dann unter GCC dem TW_START?
würde die zeile dann so lauten: if((TWSR&0xF8)!=TW_START)

Ich habe nochmal die Library von dem fleury genommen und bin darauf 
gekommen, dass das i2c display zumindest darauf reagiert...
also wenn ich es anspreche, dann bekomme ich ein ack. zurück und wenn 
ich dem display sage, es soll gelöscht werden, dann tut es das auch, 
allerdings wenn ich ihm sage es sollte was anzeigen, dann macht es das 
nicht mehr...
kann das daran liegen, dass zwischen den einzelnen paketen die gesendet 
werden eine kurze pause sein soll? (habe mit 200us pause und ohne pause 
probiert, geht aber beides nicht!)
und ich glaube dass auch kein hardware-fehler mehr vorhanden ist, da er 
sofort einen fehler schreibt, wenn ich irgendwas ausstecke, also fehler 
erkennen das tut er.
er löscht ja auch das display ordnungsgemäß (Das display ist vorher nur 
schwarz)

hier mein code:

//zur info: #define Display 0x74
ret = i2c_start(Display+I2C_WRITE);       // set device address and 
write mode
  uart_putshortint(ret);
    if ( ret == 1) {//Wenn Fehler
        /* failed to issue start condition, possibly no device found */
        i2c_stop();
  uart_puts("Error beim Starten der Kommunikation:\n\r");

    }
  else {
    PORTB=0xf0;
    uart_puts("Juhuu I hob starten kinna.\n\r");
        /* issuing start condition ok, device accessible */
    //_delay_us(200);
        //i2c_write(Display);                       // Control byte for 
init
    //_delay_us(200);
    i2c_write(0x00);                       // Control byte for init
    //_delay_us(200);
        i2c_write(0x3C);             //Selects 4-line display

//bis einschließlich hierher macht er alles, was er machen sollte... 
alles darunter ist sinnlos, da er es nicht macht//

    //_delay_us(200);
    i2c_write(0x0E);             //turns on display and cursor
    //_delay_us(200);
    i2c_write(0x06);                       //Laut datenblatt benötigt

    i2c_start(Display+I2C_WRITE);

    //_delay_us(200);
        i2c_write(0x00);                       // Controll Byte for 
Write
    //_delay_us(200);
        i2c_write(0x50);             //P
    //_delay_us(200);
    i2c_write(0x48);             //H
    //_delay_us(200);
    i2c_stop();


Das PDF zum Displays ist hier:
http://www.mpi.ch/files/attach/000013d1.pdf

greetz

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Also mich würde es trotzdem interessieren, warum bei mir das TWINT-Bit 
nicht gesetzt werden kann..
Habt ihr eine idee?
Wenn ich mit der anderen bibliothek eine "verbindung" zusammenbringe, 
dann kann es ja wohl schlecht ein hardware-fehler sein oder?
Also müsste ich irgendwas beim intitalisieren falsch haben oder?
Oder muss ich irgendwo interrupts oder so aktivieren...

von Maximilian K. (laplace)


Lesenswert?

Martin Wührer wrote:

> und das START entspricht das dann unter GCC dem TW_START?
> würde die zeile dann so lauten: if((TWSR&0xF8)!=TW_START)

Da kann ich auf die Schnelle nix dazu sagen weil ich eben mit dem I2C 
Master Interface arbeite.

> kann das daran liegen, dass zwischen den einzelnen paketen die gesendet
> werden eine kurze pause sein soll? (habe mit 200us pause und ohne pause
> probiert, geht aber beides nicht!)

Ich wüsste nicht warum man da eine Pause machen soll. Wie kommst du 
darauf?
Du bist auf dem richtigen Weg. Wenn du noch ein bisschen das Datenblatt 
und den Abschnitt "Two-wire-Interface" von der µC-Spec durchforstest 
findest du deinen Fehler denk ich mal.

> //bis einschließlich hierher macht er alles, was er machen sollte...
> alles darunter ist sinnlos, da er es nicht macht//
>
>     //_delay_us(200);
>     i2c_write(0x0E);             //turns on display and cursor
>     //_delay_us(200);
>     i2c_write(0x06);                       //Laut datenblatt benötigt
>
>     i2c_start(Display+I2C_WRITE);

Versuchs hier mal mit einem i2c_rep_start() statt i2c_start().

Ein Hardwarefehler ist es nicht. Interrupts aktivierst du übrigens mit 
sei(); und deaktivierst sie mit cli();

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Hallo

braucht man für i2c interrupts?

Wo ist denn sei() definiert?

Wo könnte denn deiner ansicht nach der fehler am ehesten liegen?

von Maximilian K. (laplace)


Lesenswert?

Nein, man braucht nicht unbedingt Interrupts. Man kann auch das TWCR 
auch pollen. Das machen z.B. die Fleury-Routinen.

Der Fehler liegt denk ist da, daß du nicht wirklich tief drin steckst in 
deinem Thema. Dir fehlen Grundkenntnisse in Bezug auf µC als auch in 
Sachen strukturierte Programmierung. Vielleicht solltest du dir das eine 
oder andere AVR-GCC-Tutorial vornehmen.

Dein I2C-Bus funktioniert ja anscheinend, deshalb liegt der Fehler wohl 
eher darin wie du das Display an sich ansteuerst. Schau dir das 
Datenblatt genauer an.

von Erdbeer G. (Firma: HTL-Braunau) (erdbeergulasch)


Lesenswert?

Hallo nochmal!
Naja mir ist aufgefallen, dass ich die SDA/SCL Pins nicht definiert 
habe!
(das erklärt auch, warum meine selbstgeschriebenen funktionen nicht 
funktionieren! jedoch die anderen schon!)

Wie definiert man die?

mfg

von Guy B. (guyso)


Lesenswert?

I have a LCD display (EA T123A-I2C) but the code erase all the display 
and do not show any character, do you have any idea ?

;____________________________________________________________________
  ; SENDDATA
  ; Send all the sequence to the slave (slave address + data (OUTPUT))
  SENDDATA:
    Again:


    ; send start bit
    CALL STARTBIT ; acquire bus and send slave address
    ; send slave address
    MOV A, SLAVEADD
    LCALL SENDBYTE ; sets NOACK if NACK received
    JB NOACK, STOPSEND ; if no acknowledge send stop

    ;send the control byte for fonction set RS = 0
    MOV A, #00h
    LCALL SENDBYTE ; sets NOACK if NACK received --many control commands 
follow

    MOV  A, #2Ch  ;send  fonction set for 4-lines display
    LCALL   SENDBYTE
    call DELAY
    MOV  A, #0Eh  ;turns ON display and cursor
    LCALL   SENDBYTE

    MOV  A, #06h  ;turns ON display and cursor
    LCALL   SENDBYTE
  AAA:
    call DELAY
    CALL STARTBIT ; acquire bus and send slave address

    MOV  A, #074h  ;turns ON display and cursor
    LCALL   SENDBYTE

    MOV  A, #40H  ;send the control byte for fonction set RS = 1
    LCALL   SENDBYTE

    MOV  A, #50H  ;write to DDRAM (value ' P_ ' )
    LCALL   SENDBYTE

    MOV  A, #48h  ;send a control byte (value ' PH_ ' )
    LCALL   SENDBYTE
    NOP
    STOPSEND:
    CALL STOPBIT ; sends stop bit
    JNB NOACK, SENDRET ; if slave sends NACK send error
    SETB ERR ; sets the error flag

    SENDRET:

    JMP SENDRET
  RET

; SENDBYTE
  ; Send 8-bits in ACC to the slave
  SENDBYTE:
    MOV BITCNT,#8 ; 8 bits in a byte
    MOV R0,#8 ; 8 bits in a byte
    mov delayTime,#10
    SETB MDE ; to enable SDATA pin as an output
    CLR MCO ; make sure that the clock line is low

    SENDBIT:
    RLC A ; put data bit to be sent into carry
    MOV MDO,C ; put data bit on SDATA line

    SETB MCO ; clock to send bit

    CLR MCO ; clear clock

    ;DJNZ BITCNT,SENDBIT ; jump back and send all eight bits
    DJNZ R0,SENDBIT ; jump back and send all eight bits
    ;NOP; wait small  for the slave to acknowledge
    CLR MDE ; release data line for acknowledge
    SETB MCO ; send clock for acknowledge --->the is the 9th bit
    NOP
    ;call  DELAY

    JNB MDI,NEXT ; this is a check for acknowledge

    SETB NOACK ; no acknowledge, set flag
    NEXT:
      CLR MCO ; clear clock

    NOP

  RET

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.