Forum: Mikrocontroller und Digitale Elektronik Software I2C


von Philipp (Gast)


Lesenswert?

Hallo,

ich habe eine Software I2C auf einem Atmega32 angebunden. Jetzt habe ich 
da ein merkwürdiges Verhalten:

An PD1 SDA und PD0 SCL läuft der Bus auf ca. 100Khz (Oskar) und der 
angeschlossene SAA1064 arbeitet einwandfrei (blinkende  LED).

Wenn ich SDA und SCL hardwaremässig tausche und dann die Zuweisung 
ebenfalls tausche, also PD1 SCL und PD0 SDA dann liegt die Frequenz bei 
200KHz.... abgesehen davon kommt am SDA-Pin kein Rechtecksignal mehr 
raus eher schlechtes Dreieck mit 100Hz. Und Daten kommen auch keine 
sinigen mehr am SAA1064 an. Wenn ich dann die delay-Routinen verdopple 
gehts wiederum!?

Weiterhin auch der Anschluss an PD4 und PD5 und der entsprechenden 
Zuweisung geht nicht. Hier bringt dann auch keine Anpassung der Delays 
etwas.
Grundlegend nehme ich an, dass es an den Delay-Routinen also dem Timing 
liegt.

Die Frage die mich interessiert ist:
Warum verhalten sich die Pins an den Ports unterschiedlich oder übersehe 
ich etwas?

Sonderfunktionen sind bei PD2 und PD0 ja RX und TX. Bei PD4-5 ja 
Timerfunktionen, die sind aber alle deaktiviert.

Wer kann mir da mal auf die Sprünge helfen?

von Oliver (Gast)


Lesenswert?

Der Fehler steckt in Zeile 42...

Die IO-Ports beim Mega32 verhalten sich nicht unterschiedlich, daran 
kann es also nicht liegen.

Oliver

von Philipp (Gast)


Lesenswert?

Lustig,

42... Die Frage nur? :-)

Okay, das war also nur das Grundlegende was ich wissen wollte, alle 
Ports gleich.. dachte ich mir auch schon, da ich aber seit heute Morgen 
daran bastle... glaubt man ja an alles :-)

Im Prinzip ist es so, dass wirklich nur PD0 und PD1 funzen.
Werde später mal den Code posten.

Danke schon mal

von Philipp (Gast)


Lesenswert?

Hallo,

also hier die Routinen die ich am Atmega32 mit 16MHz teste:
(GCC 3.4.6)
i2c_software_master.c:
1
#ifndef   F_CPU        
2
#define   F_CPU 16000000UL
3
#endif
4
////////////////////////////////////////////////////////////////////////////////////////////
5
#include <avr/io.h>
6
#include <util/delay.h>
7
////////////////////////////////////////////////////////////////////////////////////////////
8
#define I2C_DDR      DDRD          // Register für die I2C Kommunikation
9
#define I2C_DDR_REG_BIT  DDD5          //
10
#define I2C_PORT    PORTD          // I2C Port definition
11
12
#define SCL        PD4          // Port D
13
#define SDA        PD5            // Port D
14
15
#define SDA_LESE_PIN   PIND
16
#define SDA_LESE_BIT   SDA
17
////////////////////////////////////////////////////////////////////////////////////////////
18
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
19
void sda_low()
20
{
21
  I2C_PORT     &=  ~(1<<SDA);          // internen Pull-Up aus
22
  I2C_DDR     |=   (1<<I2C_DDR_REG_BIT);  // Pin von SDA als Ausgang
23
24
}
25
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
26
void sda_high()
27
{
28
  I2C_DDR     &= ~(1<<I2C_DDR_REG_BIT);    // Pin von SDA als Eingang 
29
  I2C_PORT     |=  (1<<SDA);          // internen Pull-Up an 
30
} 
31
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
32
////////////////////////////////////////////////////////////////////////////////////////////
33
34
#define I2C_SCL_LOW    I2C_PORT &= ~(1 << SCL)  // Clock Low Output
35
#define I2C_SCL_HIGH  I2C_PORT |=  (1 << SCL)  // Clock High Output
36
37
#define I2C_SDA_LOW    sda_low()        // Daten Leitung Low
38
#define I2C_SDA_HIGH  sda_high()        // Data Wire High
39
40
#define  ACK        0            // Ack empfangen
41
#define  NACK      1            // Ack nicht empfangen
42
43
//#define S_DELAY    _delay_loop_1(1);    // ca. 2.76µs H-Time Begrenzt auf 262.14 ms / F_CPU in MHz
44
#define M_DELAY      _delay_us(1);      // Begrenzt auf 768us/F_CPU in MHz also bei 16MHz 48us / 8MHz 96us
45
//#define DELAY      _delay_ms(1);      // Begrenzt auf 262.14 ms/F_CPU in MHz  also bei 16MHz 16,38ms / 8MHz 32,7675ms
46
#define S_DELAY         _delay_loop_1((F_CPU * 0.000001) / 3)   /**< 1 us delay */
47
//#define wait1ms       _delay_loop_2((F_CPU * 0.001) / 4)   /**< 1 ms delay */     
48
49
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
50
unsigned char i2c_try_scl(unsigned char start_trials)
51
{
52
  // 10 Mal kurz warten, wenn SCL auf LOW gehalten wird
53
  while((!SCL) && (start_trials <50))
54
  {
55
    start_trials++;
56
    S_DELAY;
57
  }
58
  if(!SCL) return 0 ; return 1;
59
}
60
61
void i2c_master_stop(void);
62
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
63
64
////////////////////////////////////////////////////////////////////////////////////////////
65
// I2C-Master Interface Standard Routinen
66
////////////////////////////////////////////////////////////////////////////////////////////
67
void i2c_master_init(void)
68
{
69
  I2C_DDR |=  (1<<SCL);              // SCL Leitung als Ausgang definieren
70
    S_DELAY;
71
  I2C_SCL_HIGH;                // Cockleitung auf H setzen
72
  I2C_SDA_HIGH;                // Datenleitung auf H setzen
73
    S_DELAY;                // kurz warten
74
  i2c_master_stop();
75
}
76
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
77
void i2c_master_clk_toggle(void)
78
{
79
  i2c_try_scl(0x0A);
80
81
  I2C_SCL_HIGH;
82
    S_DELAY;
83
    S_DELAY;
84
  I2C_SCL_LOW;
85
     S_DELAY;
86
}
87
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
88
void i2c_master_start(void)
89
{
90
  // Übergang von H->L auf SDA, wobei SCL H ist.
91
  i2c_try_scl(0x0A);
92
93
  I2C_SDA_HIGH;      // SDA vorsichtshalber auf HIGH ziehen
94
  //  S_DELAY;
95
  I2C_SCL_HIGH;      // SCL auf High  
96
    S_DELAY;
97
  I2C_SDA_LOW;      // SDA auf Low ziehen
98
    M_DELAY;
99
    M_DELAY;
100
    M_DELAY;
101
  I2C_SCL_LOW;      // SCL auf low
102
    S_DELAY;
103
}
104
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
105
void i2c_master_stop(void)    
106
{
107
  // Übergang von L->H auf SDA, wobei SCL H ist.
108
  i2c_try_scl(0x0A);
109
    S_DELAY;
110
  I2C_SDA_LOW;      // SDA vorsichtshalber auf LOW ziehen
111
    S_DELAY;      // Kurz abwarten
112
  I2C_SCL_HIGH;      // SCL auf High setzen
113
    S_DELAY;    
114
  I2C_SDA_HIGH;      // SDA von L auf H ziehen
115
    S_DELAY;
116
}
117
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
118
unsigned char i2c_master_write(unsigned char b)
119
{  
120
  char i=0;
121
  for(i=0;i<8;i++)
122
  {
123
    if (b & 0x80)  
124
    {
125
      I2C_SDA_HIGH;
126
    }
127
    else
128
    {
129
      I2C_SDA_LOW;
130
    }
131
    b=b<<1;
132
    S_DELAY;
133
    i2c_master_clk_toggle();
134
  }
135
  // Auf ACK vom Slave Prüfen   
136
  I2C_SDA_HIGH;
137
  i2c_master_clk_toggle();                                                                                                                       
138
  if(SDA==1)  
139
  {
140
    return 0;
141
  }
142
  else
143
  { 
144
    return 1;
145
  }  
146
}
147
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
148
unsigned char i2c_master_read(unsigned char a)
149
{  
150
  unsigned char i,c=0b00000000;
151
  I2C_SDA_HIGH;      
152
153
  for(i=0;i<8;i++)    
154
  {
155
    c=c<<1;        
156
157
    // Bitweise OR verknüpfen mit dem Eingang, MSB zuerst
158
    if(SDA_LESE_PIN & (1 << SDA_LESE_BIT)) c|=1;      
159
    i2c_master_clk_toggle();
160
  }
161
162
  // ACK oder NACK | ACK=0; NACK=1
163
  if(a==ACK)  {I2C_SDA_LOW;} else {I2C_SDA_HIGH;}  
164
  i2c_master_clk_toggle();
165
  return c;
166
}

i2c_software_master.h
1
void       i2c_master_init(void);
2
void      i2c_master_clk_toggle(void);
3
void        i2c_master_start(void);
4
void       i2c_master_stop(void);
5
6
unsigned char     i2c_try_scl(unsigned char start_trials);
7
unsigned char      i2c_master_write(unsigned char b);
8
unsigned char     i2c_master_read(unsigned char a);

Und die Main:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "i2c_software_master.h"
4
#include <util/delay.h>
5
6
7
int main(void) 
8
{
9
  
10
11
12
// I2C Test
13
14
// Beispiel
15
/*
16
i2c.start (0x70); //Adresse 70 for writing
17
i2c.write (0x00); //Subaddress 01 for digit 1
18
i2c.write (0x47); //Control C6 bis C0
19
i2c.write (0x00); //Data bit 10 - 17
20
i2c.write (0x04); //Data bit 20 - 27
21
i2c.write (0x00); //Data bit 40 - 47
22
i2c.write (0x00); //Data bit 40 - 47
23
i2c.stop ();
24
*/
25
26
27
//TCCR1B   &= ~(1<<COM1A0)|(1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);
28
i2c_master_init();
29
30
  
31
  // Setzt beim SAA1064 alle Ausgänge auf High
32
while(1){
33
  i2c_master_start();
34
  i2c_master_write(0x70);
35
  i2c_master_write(0x07);
36
  i2c_master_write(0x47);
37
  i2c_master_write(0xff);
38
  i2c_master_write(0xff);
39
  i2c_master_write(0xff);
40
  i2c_master_write(0xff);
41
  i2c_master_stop();
42
  }
43
44
}

Dann noch mal zum Verständnis des Problems:

Wenn ich also SDA an PD1 und SCL an PD0 anschliesse (PullUps extern sind 
vorhanden und die interneen habe ich testweise mal ausgeschaltet... 
ändert nichts) und dann
#define I2C_DDR_REG_BIT          DDD1
#define SCL      PD0
#define SDA            PD1
setze funktioniert der I2C mit ca 100KHz an SCL gemäß dem Oskar.

Wenn ich aber
Wenn ich also SDA an PD5 und SCL an PD4 anschliesse und dann
#define I2C_DDR_REG_BIT          DDD5
#define SCL      PD4
#define SDA            PD5
setze funktioniert der I2C mit ca 178KHz an SCL gemäß dem Oskar.
SDA zeigt dabei nur Mist an ähnlich Enladekurve Kondi mit ca 100Hz.

Wie kann das sein?

von Niemand (Gast)


Lesenswert?

Hi,
ist das wirklich eine gültige Abfrage des Portpinstatus ?:
"if(!SCL)"

von Niemand (Gast)


Lesenswert?

Hi,
schau mal hier rein: Beitrag "LM75 mit Software TWI auslesen (Atmega 16, C)"
Dort wird ebenfalls das nicht-funktionieren des !SCL gezeigt.
Bei #define SCL PD0 ist SCL=0 --> if(!0) kann gehen, ist aber unsinn
Im Falle von #define SCL PD4 ist SCL=4 --> if(!4) geht auf jeden Fall 
schief.

von Philipp (Gast)


Lesenswert?

Danke,

jetzt habe ich mal die Fleury-Routinen genommen.
Allerdings ist die ASM-Routine ja für Software I2C und die i2cmaster.c 
ja für TWI Hardware.
Also habe ich eine Main erstellt und die i2cmaster.h eingebunden.
Als Source im AVR Studio dann die i2cmaster.S hinzugefügt und dann das 
Projekt gebuildet.

Jetzt mault der Compiler an der i2c_master.S rum:

../source/i2cmaster.S:295: Error: missing ')'
../source/i2cmaster.S:295: Error: missing ')'
../source/i2cmaster.S:295: Error: missing ')'
../source/i2cmaster.S:295: Error: constant value required
../source/i2cmaster.S:295: Error: `,' required
../source/i2cmaster.S:295: Error: constant value required
../source/i2cmaster.S:295: Error: garbage at end of line
make: *** [i2cmaster.o] Error 1
Build failed with 1 errors and 5 warnings...

Wie bindet man die ASM richtig hinzu?

von spess53 (Gast)


Lesenswert?

Hi

Und was steht in Zeile 295?

MfG Spess

von Philipp (Gast)


Lesenswert?

Hallo,

In der Zeile steht wie in der ganzen Source Assembler-Code.
Also ich muss ja das Makefile anpassen damit der Compiler weiss das es 
eine Assembler-Datei ist... dachte eigentlich das kann AVR-Studio 
selbst erkennen!? Naja.

Also in dem Makefile dann ASRC = i2cmaster.S hinzufügen und dann...?
Da fehlen dann doch noch ein paar Infos...
Momentan behandelt AVR-Studio die ASM-Source als C-Source im Makefile...

von spess53 (Gast)


Lesenswert?

Hi

>In der Zeile steht wie in der ganzen Source Assembler-Code.

Ach. Bist du nicht in der Lage die Fehlermeldungen zu verstehen?

MfG Spess

von Philipp (Gast)


Lesenswert?

Hallo,

also die Fehlermeldung besagt das überall Klammern fehlen etc... ist 
aber Quatsch da es eine ASM-Library ist.
Es geht darum, da ich jetzt das Makefile angepasst habe, so dass er 
jetzt die ASM-Source richtig linkt!

Jetzt läuft mein Bus mit 297KHz. Im Normalmode...
Da ich nicht so der ASM-Freak bin müsste ich diese Routine ändern da ich 
nicht mit 4 sondern mit 16 MHz arbeite.

Also das Vierfache:
1
;*************************************************************************
2
; delay half period
3
; For I2C in normal mode (100kHz), use T/2 > 5us
4
; For I2C in fast mode (400kHz),   use T/2 > 1.3us
5
;*************************************************************************
6
  .stabs  "",100,0,0,i2c_delay_T2
7
  .stabs  "i2cmaster.S",100,0,0,i2c_delay_T2
8
  .func i2c_delay_T2  ; delay 5.0 microsec with 4 Mhz crystal  
9
i2c_delay_T2:        ; 4 cycles
10
  rjmp 1f      ; 2   "
11
1:  rjmp 2f      ; 2   "
12
2:  rjmp 3f      ; 2   "
13
3:  rjmp 4f      ; 2   "
14
4:  rjmp 5f      ; 2   "
15
5:   rjmp 6f      ; 2   "
16
6:  nop          ; 1   "
17
  ret          ; 3   "
18
  .endfunc     ; total 20 cyles = 5.0 microsec with 4 Mhz crystal

von Philipp (Gast)


Lesenswert?


von Philipp (Gast)


Lesenswert?

So nun,

gehts damit:
1
;*************************************************************************
2
; delay half period
3
; For I2C in normal mode (100kHz), use T/2 > 5us
4
; For I2C in fast mode (400kHz),   use T/2 > 1.3us
5
;cycle= 0.5 * FCPU / FI2C
6
;das heißt bei 100khz I2C Takt und 6MHz FCPU brauchst du
7
;0.5 * 16000000 / 100000 = 80 Zyklen.
8
;*************************************************************************
9
  .stabs  "",100,0,0,i2c_delay_T2
10
  .stabs  "i2cmaster.S",100,0,0,i2c_delay_T2
11
  .func i2c_delay_T2  ; delay 5.0 microsec with 4 Mhz crystal  
12
i2c_delay_T2:        ; 4 cycles
13
  rjmp 1f      ; 2   "
14
1:  rjmp 2f      ; 2   "
15
2:  rjmp 3f      ; 2   "
16
3:  rjmp 4f      ; 2   "
17
4:  rjmp 5f      ; 2   "
18
5:   rjmp 6f      ; 2   "
19
6:  rjmp 7f
20
7:  rjmp 8f
21
8:  rjmp 9f
22
9:  rjmp 10f
23
10: rjmp 11f
24
11: rjmp 12f
25
12: rjmp 13f
26
13: rjmp 14f
27
14: rjmp 15f
28
15: rjmp 16f
29
16: rjmp 17f
30
17: rjmp 18f
31
18: rjmp 19f
32
19: rjmp 20f
33
20: rjmp 21f
34
21: rjmp 22f
35
22: rjmp 23f
36
23: rjmp 24f
37
24: rjmp 25f
38
25: rjmp 26f
39
26: rjmp 27f
40
27: rjmp 28f
41
28: rjmp 29f
42
29: rjmp 30f
43
30: rjmp 31f
44
31: rjmp 32f
45
32: rjmp 33f
46
33: rjmp 34f
47
34: rjmp 35f
48
35: rjmp 36f
49
36: rjmp 37f
50
37: rjmp 38f
51
38: nop          ; 1   "
52
  ret          ; 3   "
53
  .endfunc     ; total 80 cyles = 5.0 microsec with 16 Mhz crystal

Allerdings immer noch kurios warum alle Pins gehen ausser der Pin PD5, 
an diesem kommt statt ein Rechteck ein Sägezahn heraus.
An dem zweiten Atmega32 dasselbe... was ist da mit dm PD5? Ob da am 
Fertig-Testboard ein Kondi dran klebt?
Merkwürdig...

von Philipp (Gast)


Lesenswert?

Hallo,

und so siehst aus... da ist ein Kondi dran und ein PullUp, der da den 
einzigen Taster auf dem gesamten Board bedient. Im Schaltplan ist das so 
was von klein eingezeichent, das man nur die Pins an der Steckleiste 
sehen konnte. Da frage ich mich warum da die freien Ports an der 
Steckleiste liegen und dann ist einer doch belegt.. so ein Quatsch, da 
ist die Anleitung ja in sich falsch.

Da ich dann alles mit dem Oskar gemessen habe stellte ich fest, dass ich 
mit der Berechnung:
1
;cycle= 0.5 * FCPU / FI2C
2
;das heißt bei 100khz I2C Takt und 6MHz FCPU brauchst du
3
;0.5 * 16000000 / 100000 = 80 Zyklen.

doch ganz schön daneben liege...nur 88KHz

Für 100KHz mit dem Atmega32 bei 16MHz habe ich jetzt empirisch mit dem 
Oskar für saubere 100KHz 69 Zyklen herausbekommen. Also dann die 
Delay-Routine so umgesetzt:
1
;*************************************************************************
2
; delay half period
3
; For I2C in normal mode (100kHz), use T/2 > 5us
4
; For I2C in fast mode (400kHz),   use T/2 > 1.3us
5
;cycle= 0.5 * FCPU / FI2C
6
;das heißt bei 100khz I2C Takt und 6MHz FCPU brauchst du
7
;0.5 * 16000000 / 100000 = 80 Zyklen.
8
;*************************************************************************
9
  .stabs  "",100,0,0,i2c_delay_T2
10
  .stabs  "i2cmaster.S",100,0,0,i2c_delay_T2
11
  .func i2c_delay_T2  ; delay 5.0 microsec with 4 Mhz crystal  
12
i2c_delay_T2:        ; 4 cycles
13
  rjmp 1f      ; 2   "
14
1:  rjmp 2f      ; 2   "
15
2:  rjmp 3f      ; 2   "
16
3:  rjmp 4f      ; 2   "
17
4:  rjmp 5f      ; 2   "
18
5:   rjmp 6f      ; 2   "
19
6:  rjmp 7f      ; 2   "
20
7:  rjmp 8f      ; 2   "
21
8:  rjmp 9f      ; 2   "
22
9:  rjmp 10f      ; 2   "
23
10: rjmp 11f      ; 2   "
24
11: rjmp 12f      ; 2   "
25
12: rjmp 13f      ; 2   "
26
13: rjmp 14f      ; 2   "
27
14: rjmp 15f      ; 2   "
28
15: rjmp 16f      ; 2   "
29
16: rjmp 17f      ; 2   "
30
17: rjmp 18f      ; 2   "
31
18: rjmp 19f      ; 2   "
32
19: rjmp 20f      ; 2   "
33
20: rjmp 21f      ; 2   "
34
21: rjmp 22f      ; 2   "
35
22: rjmp 23f      ; 2   "
36
23: rjmp 24f      ; 2   "
37
24: rjmp 25f      ; 2   "
38
25: rjmp 26f      ; 2   "
39
26: rjmp 27f      ; 2   "
40
27: rjmp 28f      ; 2   "
41
28: rjmp 29f      ; 2   "
42
29: rjmp 30f      ; 2   "
43
30: rjmp 31f      ; 2   "
44
31: rjmp 32f      ; 2   "
45
32: rjmp 33f      ; 2   "
46
33: ret          ; 3   "
47
  .endfunc     ; total 69 cyles = 100KHz  with 16 Mhz crystal measured on Oszilloscope

von Philipp (Gast)


Lesenswert?

Jetzt wäre noch die Frage an die ASM-Freaks ob der Aufruf der Funktion:
1
i2c_delay_T2:        ; 4 cycles

Auch tatsächlich 4 Zyklen dauert?
Dann wären es ja insgesamt 73 Zyklen für 100KHz?

Wer klärt mich auf?

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.