Forum: Mikrocontroller und Digitale Elektronik I2C Problem, ATMEGA64 zieht SDA dauerhaft auf Masse


von gr33n (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

Bin gerade dabei eine Kommunikation zwischen einem AT89C51CC03 und einem 
ATMEGA64 über I2C zu realisieren.
Der 8051 arbeitet als Master und die Steuerung ist über Software gelöst.
Im ATMEGA verwende die interne TWI-Hardware und eine Interruptsteuerung.

Wenn ich jetzt einen write-befehl an den Slave schicke, erkennt dieser 
seine eigene Adresse und schickt auch Daten zurück. Das sind wie im Bild 
zu erkennen zwei Byte (1.Byte: 19; 2.Byte: 27).
Dann sollte eigentlich die Stop-Condition kommen. Tut sie aber nicht. 
Soweit ich erkenne zieht der Slave die Datenleitung auf Masse und 
unterbricht so eine weitere Kommunikation.

Ein anderer Baustein (MAX520) kann problemlos angesteuert werden. Bei 
dem treten dann auch keine zeitlichen Abstände zwischen den einzelnen 
Bytes auf.

Hoffe mir kann jemand weiter helfen

von Sascha W. (sascha-w)


Lesenswert?

gr33n schrieb:
> Hoffe mir kann jemand weiter helfen

ohne deinen Code im M64?? - NEIN!

Sascha

von gr33n (Gast)


Lesenswert?

Guten Morgen,

habe hier das Programm vom ATMEGA64:
1
 
2
#include "defines.h"
3
#include "TWI2/TWI_Slave.h"
4
#include "lcd/lcd.h"
5
6
//---------------
7
8
volatile uint16_t SWSI[6];  //!< Register fuer AD-Werte (soll alle 100ms neu beschrieben werden)
9
10
uint16_t Zaehler=0;
11
12
char ausgabe[16];
13
14
volatile uint8_t akt=0;  //!< Aktiviert Schreibvorgang des Spannungswerts ins Menue
15
16
uint8_t jj=0, SWSIAuswahl=0;
17
18
//----------------
19
20
void init_io(void);      //!< Initialisierung Allgemein
21
void I2Cfkt(uint8_t TWIS_ResonseType);
22
23
24
int main(void)
25
{
26
  uint8_t uebergabe,jj=0,kk=0;
27
  uint8_t  TWIS_ResonseType;
28
29
  init_io();
30
  lcd_init();
31
  
32
  cli();
33
  _delay_ms(500);  // wait 500ms
34
  uebergabe = ATMEGA;
35
  
36
  if(!(TWIS_Init(uebergabe, 20000))) // IC Slave Einstellungen
37
  {
38
    lcd_string("i2c falsche bitrate");
39
    _delay_ms(1000);
40
  }
41
  sei();
42
43
//---------------- P R O G R A M M ------------------
44
45
  lcd_string(">>>");
46
  while (1)
47
  {
48
  }      
49
}
50
51
void I2Cfkt(uint8_t TWIS_ResonseType)
52
{
53
  uint8_t eingang, uebergabe;
54
  
55
  jj++;
56
  itoa(TWIS_ResonseType,ausgabe,16);
57
  lcd_string(ausgabe);
58
  lcd_string(",");
59
  switch (TWIS_ResonseType)
60
  {
61
    case TWIS_ReadBytes:
62
      uebergabe=TWIS_ReadAck();
63
      itoa(uebergabe,ausgabe,10);
64
      lcd_string(ausgabe);
65
      uebergabe=TWIS_ReadAck();
66
      itoa(uebergabe,ausgabe,10);
67
      lcd_string(ausgabe);
68
        
69
      TWIS_Stop();
70
      break;
71
72
    case TWIS_WriteBytes:
73
      TWIS_Write(19);
74
      TWIS_Write(27);
75
76
      TWIS_Stop();
77
      break;
78
          
79
    default:
80
      break;
81
  }
82
}/*I2Cfkt*/
83
84
85
/**
86
* Initialisierung Datenrichtung, Timer0, Timer1, Interruptenable
87
*/
88
void init_io()
89
{  
90
  DDRA = 0b00000100;  //HW Addresses and LDAC
91
  DDRB = 0b11110000;  //PORT B Outputs
92
  DDRC = 0x0FF;
93
  DDRD = 0b01100000;  //Enable signals
94
  DDRE = 0b00000011;
95
  DDRF = 0b10111111;
96
    PORTF = 0b01000000;
97
}
98
99
ISR (TWI_vect)
100
{
101
  uint8_t  TWIS_ResonseType;
102
  
103
  TWIS_ResonseType = TWSR;
104
  I2Cfkt(TWIS_ResonseType);
105
}

Die Funktion TWI_Slave.c ist übernommen von Manfred Langemann und 
abgeändert, damit sie auch mit der ISR läuft.
1
#include <stdio.h>
2
#include <avr/interrupt.h>
3
4
#include "TWI_Slave.h"
5
6
/**
7
* @brief Initialise the TWI Slave Interface
8
* @param[in] Address  Slave address
9
* @param[in] Bitrate  TWI_Bitrate (Hz)
10
*
11
* @return FALSE  Bitrate too high
12
* @return TRUE  Bitrate OK
13
*/
14
uint8_t TWIS_Init (uint8_t Address, uint32_t Bitrate)
15
  {
16
/*
17
** Set the TWI bitrate
18
** If TWBR is less 11, then error
19
*/
20
  TWBR = ((F_CPU/Bitrate)-16)/2;
21
  if (TWBR < 11) return FALSE;
22
/*
23
** Set the TWI slave address
24
*/
25
  TWAR = (Address << 1);
26
/*
27
** Activate TWI interface
28
*/
29
  TWCR = (1<<TWEN)|(1<<TWEA)|(1<<TWIE);
30
31
  return TRUE;
32
  }
33
/**
34
* @brief Stop the TWI Slave Interface
35
*/
36
void TWIS_Stop (void)
37
  {
38
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO)|(1<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(0<<TWWC)|(1<<TWIE);
39
  }
40
  
41
/**
42
* @brief Write a byte to the master
43
*
44
* @param[in] byte to be sent
45
*
46
* @return TRUE OK, Byte sent
47
* @return FALSE Error in byte transmission
48
*/
49
void TWIS_Write (uint8_t byte)
50
  { 
51
  TWDR = byte;
52
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
53
  while (!(TWCR & (1<<TWINT)));
54
  }
55
  
56
/**
57
* @brief Read a byte from the master and request next byte
58
* @return Read byte
59
*/
60
uint8_t  TWIS_ReadAck (void)
61
  {
62
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
63
  while (!(TWCR & (1<<TWINT)));
64
  return TWDR;
65
  }
66
  
67
/**
68
* @brief Read the last byte from the master
69
* @return Read byte
70
*/
71
uint8_t  TWIS_ReadNack (void)
72
  {
73
  TWCR = (1<<TWINT)|(1<<TWEN);
74
  while (!(TWCR & (1<<TWINT)));
75
  return TWDR;
76
  }
77
  
78
/**
79
* @brief Get the response type to be performed by slave
80
* @param[in] *TWI_ResonseType Pointer to response type
81
* - TWIS_ReadBytes  --> Read byte(s) from master
82
* - TWIS_WriteBytes  --> Write byte(s) to master
83
*
84
* @return Response required
85
* - TRUE: Yes, response required
86
* - FALSE: No response required
87
*/
88
uint8_t  TWIS_ResonseRequired (uint8_t *TWI_ResonseType)
89
  {
90
  *TWI_ResonseType = TWSR;
91
  return TWCR & (1<<TWINT);
92
  }

von gr33n (Gast)


Lesenswert?

So hab mein Problem gelöst. War ein typisches 30cm Problem...

Damit andere nicht vlt in die selbe Falle tappen, schreibe ich hier kurz 
worauf man auf jeden Fall achten sollte:

Möchte man mehrere Bytes übertragen sollte man darauf achten, dass nach 
dem letzten Byte ein NotAck zurück gegeben wird. Tut man das nicht 
passieren unerwartete Effekte...

Dachte man braucht das nur wenn man variable Byte-längen hat.

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

schön das es jetzt geht.
Was soll eigentlich das TWIS_Stop() wenn du der Slave bist? - das Stop 
kommt vom Master! Dieses Stop brauchst du eigentlich nur wenn der Bus 
einen ungültigen Zustand hat (TWSR=0x00).
Und noch was - die Displayausgabe hat in der ISR nichts zu suchen, kein 
Wunder wenn du in der Übertragung laaaange Pausen hast.

Sascha

von gr33n (Gast)


Lesenswert?

Hi Sascha,

> Was soll eigentlich das TWIS_Stop() wenn du der Slave bist? - das Stop
> kommt vom Master! Dieses Stop brauchst du eigentlich nur wenn der Bus
> einen ungültigen Zustand hat (TWSR=0x00).

Wenn ichs nicht mit rein nehme hängt sich der Bus auf -> nach dem 
letzten Byte bleiben beide Signale (scl und sda) auf Masse.
Die Funktionen habe ich von hier 
Beitrag "AVR TWI Master und Slave Funtionen in C".

Manfred Langemann macht es in dem Beispielcode TWI_Slave_main.c genauso:
1
main(){
2
//...
3
while(1){
4
5
//Check wether something is to do for the TWI slave interface
6
7
    if (TWIS_ResonseRequired (&TWIS_ResonseType))
8
      {
9
      switch (TWIS_ResonseType)
10
        {
11
/*
12
** Slave is requests to read bytes from the master.
13
** It is expliciltely assumed, that the master sends 8 bytes
14
*/
15
        case TWIS_ReadBytes:
16
          for (i=0;i<7;i++)
17
            {
18
            byte[i] = TWIS_ReadAck ();
19
            printf ("Byte read: %d\n",byte[i]);
20
            }
21
          byte[7] = TWIS_ReadNack ();
22
          printf ("Byte read: %d\n",byte[7]);
23
          TWIS_Stop ();
24
          break;
25
/*
26
** Slave is requested to send bytes to the master.
27
** It is expliciltely assumed, that the master expects 8 bytes
28
*/
29
        case TWIS_WriteBytes:
30
          for (i=0;i<8;i++)
31
            {                   
32
            TWIS_Write (j++);
33
            printf ("Byte sent:  %d\n", j-1);
34
            }
35
            TWIS_Stop ();
36
          break;
37
        }
38
      } 
39
    }
40
}

Was die Displayausgabe angeht: Da hast du recht! Hatte sie nur zu 
Testzwecken drinnen um mir das Statusbyte anzeigen zu lassen. Ohne gehts 
natürlich deutlich schneller :)
wobei 15kHz nicht wirklich schnell ist...

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.