Forum: Mikrocontroller und Digitale Elektronik I2CEprom 24LC512 Page Write Bascom - TWI Experten gesucht


von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Hi,

stehe gerade vor einem gröberen Problem und weiß nicht was richtig ist, 
einerseits gibt es in der Literatur Beispiele, wie das EPROM 24LC64 oder 
24LC512 beschrieben wird (z.B. Stefan Hoffmann: ..BASCOM)

Hier gibts ein Beispiel für einen Datenlogger (Seite 442), der immer 10 
Bytes schreibt - ich benötige soetwas in meiner Applikation und 
programmiere das in etwa so

<code>
I2cinit
I2cstart
I2cwbyte Eprom_write  '160
Err = 0
Wrd = 0
I2cwbyte AdrHigh
I2cwbyte AdrLow
I2cwbyte Lngbytes(1)
I2cwbyte Lngbytes(2)
I2cwbyte Lngbytes(3)
I2cwbyte Lngbytes(4)
I2cwbyte Lngbytes2(1)
I2cwbyte Lngbytes2(2)
I2cwbyte Lngbytes2(3)
I2cwbyte Lngbytes2(4)
I2cwbyte Byt
I2cwbyte Bytfunktion
I2cstop
</code>

Ich hab das so ähnlich für einen Datenlogger programmiert. Nun lese ich 
auf diversen Seiten, dass der page-Write nicht so einfach wäre,
z.B. hier: http://www.grzesina.de/avr/i2c/i2c.html

Es müssen die Bytes immer in der 128-Byte Seite (von null begonnen) 
liegen
Also wenn immer 10 Bytes geschrieben werden
0-10-20-30-40-50-60-70-80-90-100-110-120
gibts beim 13.Log Eintrag ab Adresse 120 ein Problem,
in diesem Fall werden die 10 Bytes auf 120-127 und 128-129 geschrieben,
das können (angeblich) die EPROMS nicht und vergessen die Bytes 128-129

Wenn das wirklich so ist, dann ist das Buch von Stefan Hoffmann und 
diverse andere Literatur deutlich zu überarbeiten...
Soll ich jetzt die Bytes einzeln schreiben oder muss ich mein Programm 
so (kompliziert) überarbeiten, dass erkannt wird, in welchem 
Paging-Bereich ich schreibe und bei Schreiben ab Adresse 120 muss ich 
dann 2x schreiben (einmal 120-127 und den 2. Schreibvorgang mit 128-129)

Aus dem Datenblatt zum 24LC512 geht das leider auch nicht so recht 
hervor, bzw. steht nicht explizit, dass der SRAM-Buffer mit 128 Bytes 
auch genau einer 128-Byte Seite im EPROM zugeordnet werden muss

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Manfred S. schrieb:
> Aus dem Datenblatt zum 24LC512 geht das leider auch nicht so recht
> hervor

Also im Atmel Datenblatt steht das ganz eindeutig drin:

"The data word address lower 7 bits are internally incremented following 
the receipt of each data
word. The higher data word address bits are not incremented, retaining 
the memory page row
location. When the word address, internally generated, reaches the page 
boundary, the following
byte is placed at the beginning of the same page. If more than 128 data 
words are
transmitted to the EEPROM, the data word address will “roll over” and 
previous data will be
overwritten. The address roll over during write is from the last byte of 
the current page to the first
byte of the same page."


Manfred S. schrieb:
> in diesem Fall werden die 10 Bytes auf 120-127 und 128-129 geschrieben,
> das können (angeblich) die EPROMS nicht und vergessen die Bytes 128-129

Nö, der EEPROM schreibt Byte 128, 129 dann auf Adresse 0 und 1.
Das ist mit "The address roll over" gemeint.


Manfred S. schrieb:
> Soll ich jetzt die Bytes einzeln schreiben oder muss ich mein Programm
> so (kompliziert) überarbeiten

Das Testen ist ganz einfach möglich, indem man die nächste Adresse mit 
einer Maske für die unteren Bits undiert und dann 0 rauskommt.
In C sieht das so aus:
1
    do
2
      si2c_w( *sram++ );
3
    while( --len && (++eeaddr & (PAGE_SIZE-1)));  // end or next page

Anbei die komplette Routine in C (ich benutze kein Basic).


Peter

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Danke, Peter für die rasche Rückmeldung
Peter Dannegger schrieb:

> Also im Atmel Datenblatt steht das ganz eindeutig drin:
>
> "The data word address lower 7 bits are internally incremented following
> the receipt of each data
> word. The higher data word address bits are not incremented, retaining
> the memory page row
> location. When the word address, internally generated, reaches the page
> boundary, the following
> byte is placed at the beginning of the same page. If more than 128 data
> words are
> transmitted to the EEPROM, the data word address will “roll over” and
> previous data will be
> overwritten. The address roll over during write is from the last byte of
> the current page to the first
> byte of the same page."

mea culpa - tja, sollt man halt nicht einfach so überfliegen..

> Manfred S. schrieb:
>> in diesem Fall werden die 10 Bytes auf 120-127 und 128-129 geschrieben,
>> das können (angeblich) die EPROMS nicht und vergessen die Bytes 128-129
>
> Nö, der EEPROM schreibt Byte 128, 129 dann auf Adresse 0 und 1.
> Das ist mit "The address roll over" gemeint.
>
>
> Manfred S. schrieb:
>> Soll ich jetzt die Bytes einzeln schreiben oder muss ich mein Programm
>> so (kompliziert) überarbeiten
>
> Das Testen ist ganz einfach möglich, indem man die nächste Adresse mit
> einer Maske für die unteren Bits undiert und dann 0 rauskommt.
> In C sieht das so aus:
>
1
>     do
2
>       si2c_w( *sram++ );
3
>     while( --len && (++eeaddr & (PAGE_SIZE-1)));  // end or next page
4
>
>
> Anbei die komplette Routine in C (ich benutze kein Basic).
>
>
> Peter

Tja, werd den Algorithmus für Bascom wohl anpassen müssen, dazwischen 
muss ich dann noch das acknowledge polling einbauen oder ich schreib die 
10 Bytes einzeln mit acknowledge polling - werd das morgen einmal 
testen!

Vielleicht sollte Stefan Hoffmann bei der nächsten Auflage das alles 
auch noch berücksichtigen... sein Buch in Ehren, ist wirklich super für 
Anfänger - aber das mit dem Page-Writing sollte kurz erwähnt sein!

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Aus dem Datenblatt zum 24LC512 geht das leider auch nicht so recht
> hervor, bzw. steht nicht explizit, dass der SRAM-Buffer mit 128 Bytes
> auch genau einer 128-Byte Seite im EPROM zugeordnet werden muss

Das steht doch sehr genau im DB, unter:

Page write operations are limited to writing bytes within a single 
physical page, regardless of the number of bytes ...

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

So, geschafft: hier Variante 1 vollständig in Bascom, die die 
Eigenheiten des Page Write richtig berücksichtigt:
1
$regfile = "m644def.dat"
2
$crystal = 8000000
3
$swstack = 128
4
$hwstack = 128
5
$framesize = 128
6
Config Twi = 100000
7
$lib "i2c_twi.lbx"
8
$baud = 19200
9
Config Serialout = Buffered , Size = 254
10
'**************************** Hardware-Definitionen
11
Config Sda = Portc.1                                        'I2C-Pins definieren, bei Atmega 8: PortC.4
12
Config Scl = Portc.0                                        'PortC.5 bei Atmega 8
13
Const Eprom_write = 160
14
Const Eprom_read = 161
15
Dim I As Byte
16
Dim Byt As Byte
17
Const Cbytes2write = 20
18
Dim Arrbytes(cbytes2write) As Byte
19
Dim Wrdadr As Word
20
Dim Wrd As Word
21
Dim Blnok As Bit
22
Dim Wrdbytes(2) As Byte At Wrd Overlay
23
Taster Alias Pina.1
24
Config Porta.1 = Input
25
'**************************** ab jetzt betriebsbereit
26
Enable Interrupts
27
Cls
28
Lcd "START"
29
Const Cpage = 128                                           'abhängig vom 24C, hier: 24LC512
30
I2cinit
31
Do
32
   If Taster = 1 Then                                       'ausnahmsweise gegen VCC
33
      Print "*************"
34
      Byt = Rnd(5)
35
      Print "Random=" ; Byt                                 'Testdaten erzeugen
36
      For I = 1 To Cbytes2write
37
         Arrbytes(i) = I * Byt
38
      Next I
39
      Wrdadr = 120
40
      Wrd = Wrdadr
41
      Byt = Wrd Mod Cpage
42
      Byt = Cpage - Byt
43
      Print "Byt=" ; Byt
44
      I2cstart
45
      I2cwbyte Eprom_write
46
      I2cwbyte Wrdbytes(2)
47
      I2cwbyte Wrdbytes(1)
48
      For I = 1 To Cbytes2write
49
         I2cwbyte Arrbytes(i)
50
         If Byt = I Then
51
            Wrd = Wrd + Byt
52
            I2cstop
53
            Waitms 20
54
            I2cstart
55
            I2cwbyte Eprom_write
56
            I2cwbyte Wrdbytes(2)
57
            I2cwbyte Wrdbytes(1)
58
         End If
59
      Next I
60
      I2cstop
61
      Waitms 20
62
'      Print "Geschrieben"
63
'      'nach dem letzten Schreiben nicht warten
64
'      'gewartet wird erst beim nächsten Zugriff, kann viel später sein!
65
      Wrd = Wrdadr
66
      I2cstart
67
      I2cwbyte Eprom_write
68
      I2cwbyte Wrdbytes(2)
69
      I2cwbyte Wrdbytes(1)
70
      I2cstart
71
      I2cwbyte Eprom_read
72
      Blnok = 1
73
      For I = 1 To Cbytes2write
74
         If I < Cbytes2write Then
75
            I2crbyte Byt , Ack
76
         Else
77
            I2crbyte Byt , Nack
78
         End If
79
         If Byt <> Arrbytes(i) Then
80
            Print Wrd ; "=" ; Byt
81
            Blnok = 0
82
         End If
83
         Incr Wrd
84
      Next I
85
      I2cstop
86
      If Blnok = 1 Then
87
         Print "Alle Bytes ok"
88
      Else
89
         Print "Fehlerhafte Bytes"
90
      End If
91
      Waitms 100
92
   End If
93
Loop
94
Return

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Und für die weiter Fortgeschrittenen, hier die Variante mit Acknowledge 
Polling - vielleicht schafft es jemand, das Acknowledge Polling 
ausschließlich mit Bascom zu realisieren. Aber die I2C-Routinen sind 
sehr "eigen".
1
$regfile = "m644def.dat"
2
$crystal = 8000000
3
$swstack = 128
4
$hwstack = 128
5
$framesize = 128
6
Config Twi = 100000
7
$lib "i2c_twi.lbx"
8
$baud = 19200
9
Config Serialout = Buffered , Size = 254
10
'**************************** Hardware-Definitionen
11
Config Sda = Portc.1                                        'I2C-Pins definieren, bei Atmega 8: PortC.4
12
Config Scl = Portc.0                                        'PortC.5 bei Atmega 8
13
Const Eprom_write = 160
14
Const Eprom_read = 161
15
Dim I As Byte
16
Dim J As Byte
17
Dim Byt As Byte
18
Const Cbytes2write = 20
19
Dim Arrbytes(cbytes2write) As Byte
20
Dim Wrdadr As Word
21
Dim Wrd As Word
22
Dim Blnok As Bit
23
Dim Wrdbytes(2) As Byte At Wrd Overlay
24
Taster Alias Pina.1
25
Config Porta.1 = Input
26
Declare Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
27
'**************************** ab jetzt betriebsbereit
28
Enable Interrupts
29
Cls
30
Lcd "START"
31
Const Cpage = 128                      'abhängig vom 24C, hier: 24LC512
32
'I2cinit geht nicht richtig, erst mit I2CStart, brauchen wir aber nicht
33
Twsr = &B00000000                                   'Prescaler=0, 1
34
Twbr = 32                                           'TWI=100000
35
Do
36
   If Taster = 1 Then                   'ausnahmsweise gegen VCC
37
      Print "*************"
38
      Byt = Rnd(5)
39
      Print "Random=" ; Byt                           'Testdaten erzeugen
40
      For I = 1 To Cbytes2write
41
         Arrbytes(i) = I * Byt
42
      Next I
43
      Wrdadr = 120
44
      Wrd = Wrdadr
45
      Byt = Wrd Mod Cpage
46
      Byt = Cpage - Byt
47
      Print "Byt=" ; Byt
48
      J = Fxi2cstart(eprom_write)
49
      If J > 255 Then
50
         Print "Baustein nicht verfübar"
51
      Else
52
         I2cwbyte Wrdbytes(2)
53
         I2cwbyte Wrdbytes(1)
54
         For I = 1 To Cbytes2write
55
            I2cwbyte Arrbytes(i)
56
            If Byt = I Then
57
               Wrd = Wrd + Byt
58
               I2cstop
59
               J = Fxi2cstart(eprom_write)
60
               I2cwbyte Wrdbytes(2)
61
               I2cwbyte Wrdbytes(1)
62
            End If
63
         Next I
64
         I2cstop
65
'      'nach dem letzten Schreiben nicht warten
66
'      'gewartet wird erst beim nächsten Zugriff, kann viel später sein!
67
         Wrd = Wrdadr
68
         J = Fxi2cstart(eprom_write)
69
         I2cwbyte Wrdbytes(2)
70
         I2cwbyte Wrdbytes(1)
71
         I2cstart
72
         I2cwbyte Eprom_read
73
         Blnok = 1
74
         For I = 1 To Cbytes2write
75
            If I < Cbytes2write Then
76
               I2crbyte Byt , Ack
77
            Else
78
               I2crbyte Byt , Nack
79
            End If
80
            If Byt <> Arrbytes(i) Then
81
               Print Wrd ; "=" ; Byt
82
               Blnok = 0
83
            End If
84
            Incr Wrd
85
         Next I
86
         I2cstop
87
         If Blnok = 1 Then
88
            Print "Alle Bytes ok"
89
         Else
90
            Print "Fehlerhafte Bytes"
91
         End If
92
      End If
93
      Waitms 100
94
   End If
95
Loop
96
Return
97
98
Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
99
'Acknowledge Polling, Wert zu groß=Timeout Fehler
100
Local Bytzaehler As Byte
101
Bytzaehler = 0
102
Do            
103
    Incr Bytzaehler   'Beschäftigung, wenn kein Zähler, dann Waitus 1
104
    Twcr = &B10100100                     'entspricht I2CWrite_EpromWrite
105
    Do
106
    Loop Until Twcr.twint = 1                       'entspricht I2CStart
107
    Twdr = Byti2cadr
108
    Twcr = &B10000100
109
    Do
110
    Loop Until Twcr.twint = 1
111
Loop Until Twsr.5 = 0 Or Bytzaehler = 255                   'TWSR.5 = Bit, ob Ack empfangen wurde, wird 0 bei ACK
112
Fxi2cstart = Bytzaehler
113
End Function

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

So einfach geht es, den 512kBit Baustein mit FF zu füllen, dauert nur 
wenige Sekunden:
1
      For Wrd = 0 To 65535 Step Cpage
2
         Call Si2cepromstart
3
         I2cwbyte Wrdbytes(2)
4
         I2cwbyte Wrdbytes(1)
5
         For Byt = 0 To 127
6
            I2cwbyte &HFF
7
         Next Byt
8
         I2cstop
9
         Print "L=" ; Wrd
10
      Next Wrd

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Und der ganze TWI-Bus zu Fuß codiert - wir benötigen überhaupt keine 
Bascom Library oder Bascom I2c-Befehle

So und jeztt die Frage: welche Variante ist die Beste?
1
$regfile = "m644def.dat"
2
$crystal = 8000000
3
$swstack = 128
4
$hwstack = 128
5
$framesize = 128
6
$baud = 19200
7
Config Serialout = Buffered , Size = 254
8
'**************************** Hardware-Definitionen
9
Config Sda = Portc.1                                        'I2C-Pins definieren, bei Atmega 8: PortC.4
10
Config Scl = Portc.0                                        'PortC.5 bei Atmega 8
11
Const Eprom_write = 160
12
Const Eprom_read = 161
13
Dim I As Byte
14
Dim J As Byte
15
Dim Byt As Byte
16
Const Cbytes2write = 20
17
Dim Arrbytes(cbytes2write) As Byte
18
Dim Wrdadr As Word
19
Dim Wrd As Word
20
Dim Blnok As Bit
21
Dim Wrdbytes(2) As Byte At Wrd Overlay
22
Taster Alias Pina.1
23
Config Porta.1 = Input
24
Declare Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
25
'**************************** ab jetzt betriebsbereit
26
Enable Interrupts
27
Cls
28
Lcd "START"
29
Const Cpage = 128                                           'abhängig vom 24C, hier: 24LC512
30
'wir brauchen überhaupt keine Bascom TWI-Libraries
31
Twsr = &B00000000                                           'Prescaler=0, 1
32
Twbr = 32                                                   'TWI=100000
33
Do
34
   If Taster = 1 Then                                       'ausnahmsweise gegen VCC
35
      Print "*************"
36
      Byt = Rnd(5)
37
      Print "Random=" ; Byt                                 'Testdaten erzeugen
38
      For I = 1 To Cbytes2write
39
         Arrbytes(i) = I * Byt
40
      Next I
41
      Wrdadr = 120
42
      Wrd = Wrdadr
43
      Byt = Wrd Mod Cpage
44
      Byt = Cpage - Byt
45
      Print "Byt=" ; Byt
46
      J = Fxi2cstart(eprom_write)
47
      If J > 255 Then
48
         Print "Baustein nicht verfübar"
49
      Else
50
         Twdr = Wrdbytes(2)
51
         Twcr = &B10000100
52
         Do
53
         Loop Until Twcr.twint = 1
54
         Twdr = Wrdbytes(1)
55
         Twcr = &B10000100
56
         Do
57
         Loop Until Twcr.twint = 1
58
         For I = 1 To Cbytes2write
59
            Twdr = Arrbytes(i)
60
            Twcr = &B10000100
61
            Do
62
            Loop Until Twcr.twint = 1
63
            If Byt = I Then
64
               Wrd = Wrd + Byt
65
               Twcr = &B10010100                            'Stopp
66
               J = Fxi2cstart(eprom_write)
67
               Twdr = Wrdbytes(2)
68
               Twcr = &B10000100
69
               Do
70
               Loop Until Twcr.twint = 1
71
               Twdr = Wrdbytes(1)
72
               Twcr = &B10000100
73
               Do
74
               Loop Until Twcr.twint = 1
75
            End If
76
         Next I
77
         Twcr = &B10010100                                  'Stopp
78
'      'nach dem letzten Schreiben nicht warten
79
'      'gewartet wird erst beim nächsten Zugriff, kann viel später sein!
80
         Wrd = Wrdadr
81
         J = Fxi2cstart(eprom_write)
82
         Twdr = Wrdbytes(2)
83
         Twcr = &B10000100
84
         Do
85
         Loop Until Twcr.twint = 1
86
         Twdr = Wrdbytes(1)
87
         Twcr = &B10000100
88
         Do
89
         Loop Until Twcr.twint = 1
90
         J = Fxi2cstart(eprom_read)
91
         Blnok = 1
92
         For I = 1 To Cbytes2write
93
            If I < Cbytes2write Then
94
               Twcr = &B11000100                            'Ack
95
            Else
96
               Twcr = &B10000100                            'Noack
97
            End If
98
            Do
99
            Loop Until Twcr.twint = 1                       'I2CRead
100
            Byt = Twdr
101
            If Byt <> Arrbytes(i) Then
102
               Print Wrd ; "=" ; Byt
103
                Blnok = 0
104
            End If
105
            Incr Wrd
106
         Next I
107
         Twcr = &B10010100                                  'Stopp
108
         If Blnok = 1 Then
109
            Print "Alle Bytes ok"
110
         Else
111
            Print "Fehlerhafte Bytes"
112
         End If
113
      End If
114
      Waitms 100
115
   End If
116
Loop
117
Return
118
119
Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
120
'Acknowledge Polling, Wert zu groß=Timeout Fehler
121
Local Bytzaehler As Byte
122
Bytzaehler = 0
123
Do                                                          'Beschäftigung, wenn kein Zähler, dann Waitus 1
124
    Incr Bytzaehler                                         'entspricht I2CWrite_EpromWrite
125
    Twcr = &B10100100
126
    Do
127
    Loop Until Twcr.twint = 1                               'entspricht I2CStart
128
    Twdr = Byti2cadr
129
    Twcr = &B10000100
130
    Do
131
    Loop Until Twcr.twint = 1
132
Loop Until Twsr.5 = 0 Or Bytzaehler = 255                   'TWSR.5 = Bit, ob Ack empfangen wurde, wird 0 bei ACK
133
Fxi2cstart = Bytzaehler
134
End Function

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
> 'Acknowledge Polling, Wert zu groß=Timeout Fehler
> Local Bytzaehler As Byte
> Bytzaehler = 0
> Do
>     Incr Bytzaehler   'Beschäftigung, wenn kein Zähler, dann Waitus 1
>     Twcr = &B10100100                     'entspricht I2CWrite_EpromWrite
>     Do
>     Loop Until Twcr.twint = 1                       'entspricht I2CStart
>     Twdr = Byti2cadr
>     Twcr = &B10000100
>     Do
>     Loop Until Twcr.twint = 1
> Loop Until Twsr.5 = 0 Or Bytzaehler = 255                   'TWSR.5 = Bit, ob 
Ack empfangen wurde, wird 0 bei ACK
> Fxi2cstart = Bytzaehler
> End Function

Brrr, grausam. Wenn der restliche Codes auch so aufgeblasen ist und der 
vernünftig geschrieben würde, dann bliebe ja nix mehr über um den µC 
voll zu bekommen. :D

Acknowlede Polling geht so:
1
Do
2
  I2cstart
3
  I2cwbyte EEProm_Write_Address
4
Loop Until Err = 0

Manfred S. schrieb:
> Aber die I2C-Routinen sind sehr "eigen".
Übersetzung: Habe keine Ahnung.

von Weingut P. (weinbauer)


Lesenswert?

naja, die I2C-Routinen in Bascom sind standardmäßig Soft-I2C,
es sei denn der User ruft die Lib auf.
Bei dem Befehl I2CStart macht Bascom in der Soft-I2C-Variante
einen Restart statt einen reinen Start, das kann einem schon den Tag
versauen wenn ein TWI-Slave das nicht mag ... hatt ich nämlich schon
und hab erst mit dem Oszi nach Stunden das Problem gefunden weil
ewig im Code nach Fehlern gesucht.

von MWS (Gast)


Lesenswert?

Fhutdhb Ufzjjuz schrieb:
> Bei dem Befehl I2CStart macht Bascom in der Soft-I2C-Variante
> einen Restart statt einen reinen Start

Da hast Du auch noch in der aktuellen Version Recht.

> es sei denn der User ruft die Lib auf.

Was der TE offensichtlich macht, sonst würde er nicht selbst im TWCR 
rumwerken.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

>
> Manfred S. schrieb:
>> Aber die I2C-Routinen sind sehr "eigen".
> Übersetzung: Habe keine Ahnung.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Wenn schon Bacom, Acknowdlege Polling geht sicherer so:
1
.
2
j=Fxi2cstart(irgendeine_I2C_Adresse) 
3
if j<255 then
4
   'ok
5
else
6
   'Baustein nicht da oder defekt
7
endif
8
.
1
Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
2
'Universalroutine als Alternative zu normalem I2CStart und Adresse
3
Local Bytzaehler As Byte
4
Bytzaehler = 0
5
Do                                                          
6
    Incr Bytzaehler                                            
7
    i2cstart
8
    I2cwbyte byti2cadr
9
Loop Until Twsr.5 = 0 Or Bytzaehler = 255 'TWSR.5=Ack Bit 
10
Fxi2cstart = Bytzaehler
11
End Function

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Acknowdlege Polling geht sicherer so:

Was ist sicherer ?
Wenn die I2C-HW zuverlässig funktioniert, dann geht die einfachste 
Version, wenn Err = 0 ist, dann wurde der Befehl erfolgreich ausgeführt.
Was soll da unsicher sein ?

Wenn die HW dagegen unzuverlässig ist, dann kann man nach Belieben immer 
noch Sicherheiten, Zähler, Timeouts, etc. dazu bauen.

War aber nicht die Frage, die war: Wie geht's mit Bascom-Mitteln ?

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

MWS schrieb:
> Manfred S. schrieb:
>> Acknowdlege Polling geht sicherer so:
>
> Was ist sicherer ?
> Wenn die I2C-HW zuverlässig funktioniert, dann geht die einfachste
> Version, wenn Err = 0 ist, dann wurde der Befehl erfolgreich ausgeführt.
> Was soll da unsicher sein ?
>
> Wenn die HW dagegen unzuverlässig ist, dann kann man nach Belieben immer
> noch Sicherheiten, Zähler, Timeouts, etc. dazu bauen.
>
> War aber nicht die Frage, die war: Wie geht's mit Bascom-Mitteln ?

Naja, es sollt halt dann nicht gleich eine Endlosschleife sein - ein 
Timeout bei Hardwarefehlern muss einfach gegeben sein.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

> Manfred S. schrieb:
>> Aber die I2C-Routinen sind sehr "eigen".
> Übersetzung: Habe keine Ahnung.

Tja, hätt ich gern, da ist aber Bascom zu wenig ausführlich dokumentiert

Warum wird beim IC2INIT nicht gleich das TWI mit TWSR, TWBR richtig 
initialisiert, sondern erst beim I2CSTART - Und wo steht das in der 
Doku?

Wann wird ERR=1 gesetzt, wird dann TWSR ausgelesen oder wie genau wird 
ERR gesetzt? - manchmal ist ERR=1 nicht nachvollziehbar!

Fragen über Fragen..

Also da fühl ich mich dann auf der Registerebene einfach sicherer

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Naja, es sollt halt dann nicht gleich eine Endlosschleife sein - ein
> Timeout bei Hardwarefehlern muss einfach gegeben sein.

Kommt drauf an, wenn die komplette Schaltung z.B. auf 
Konfigurationsdaten des I2C-EEProms angewiesen ist und ohne nicht 
funktioniert, dann machst Du genau was ?

Und wenn's sicherheitskritisch ist, nimmt man den WD.

Die Bascom HW-I2C Routine selbst blockiert ja nicht, die hat ein eigenes 
Timeout drin. Wenn man also aufgrund Unwägbarkeiten einen sicheren Exit 
braucht, dann zählt man die Aufrufe in denen es einen Error gab und 
bricht nach 'ner bestimmten Anzahl ab.

Aber sowas bringt doch jeder selbst zustande, das muss ich doch nicht 
extra zu meinem Beispiel dazuschreiben.

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> Warum wird beim IC2INIT nicht gleich das TWI mit TWSR, TWBR richtig
> initialisiert, sondern erst beim I2CSTART - Und wo steht das in der
> Doku?

Hättest Du Dir nur einmal das zugehörige Beispiel (TWI-master.bas) 
angesehen, dann wüsstest Du daß die Prescaler-Bits im TWSR und das TWBR 
von "Config TWI" gesetzt werden.
Zitat:
  Config Twi = 100000                     ' wanted clock frequency
  'will set TWBR and TWSR

So steht's auch in der Hilfe, kann Bascom doch nix dafür, daß Du weder 
die Hilfe liest, noch Dir die Beispiele anschaust.

Beim I2CStart wird im Übrigen für TWBR/TWSR auch nix initialisiert.
Wenn Du Config TWI vergisst, dann bleiben die Prescalerbits als auch das 
Bitrateregister eben leer und die I2C arbeitet mit Maxspeed.

Ob das die angeschlossenen Busteilnehmer mitmachen, ist dann 'ne andere 
Sache.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

MWS schrieb:
> Manfred S. schrieb:
>> Warum wird beim IC2INIT nicht gleich das TWI mit TWSR, TWBR richtig
>> initialisiert, sondern erst beim I2CSTART - Und wo steht das in der
>> Doku?
>
> Hättest Du Dir nur einmal das zugehörige Beispiel (TWI-master.bas)
> angesehen, dann wüsstest Du daß die Prescaler-Bits im TWSR und das TWBR
> von "Config TWI" gesetzt werden.
> Zitat:
>   Config Twi = 100000                     ' wanted clock frequency
>   'will set TWBR and TWSR
>
OK, überlesen -danke , auch gerade gelesen I2CINIT ist dann gar nicht 
notwendig, da beim Reset des Prozessors die Hardware TWI eh richtig 
gesetzt ist.

Aber eine Frage bleibt noch:
wie und wann genau wird ERR gesetzt beim Hardware TWI?

von MWS (Gast)


Lesenswert?

Manfred S. schrieb:
> auch gerade gelesen I2CINIT ist dann gar nicht
> notwendig, da beim Reset des Prozessors die Hardware TWI eh richtig
> gesetzt ist.

I2CInit setzt das DDRx richtig und aktiviert die internen Pullups, falls 
man keine externen verwenden muss/möchte.

Manfred S. schrieb:
> wie und wann genau wird ERR gesetzt beim Hardware TWI?

Wenn vor dem Timeout kein TWINT kam, bricht I2CStart ab und es wird Bit 
2 von Err gesetzt.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

> Wenn vor dem Timeout kein TWINT kam, bricht I2CStart ab und es wird Bit
> 2 von Err gesetzt.

Ja, für I2CStart und auch die anderen I2C-Routinen, die auf TWINT warten 
stimmt da.

I2CWByte und I2CRByte können aber viel mehr. Hab mir gerade den 
Bascom-Assembler angesehen, entgegen anders lautenden Infoquellen (z.B. 
http://www.rn-wissen.de/index.php/Bascom_I2C_Master) wird bei I2CWrite 
sehr wohl das Statusregister TWSR eingehend geprüft.

Bei I2CWByte konkret:
1) TWINT Timeout (wie bei allen)
2) TWSR, Prescaler Bits maskieren
3) Timeout, solange TWSR $F8 bleibt
4) wenn TWSR nicht einen der Werte $18, $28, $40 oder $50 hat -> Fehler

Die Antwort gibt allerdings nur undifferenziert Bit2 des ERR-Registers 
zurück - wer will kann ja dann noch spezifischer testen: beim Starten 
der Kommunikation mit dem EEPROM als Slave sind nur die Stati $18 und 
$20 relevant, $18, Bit 5=0 = ACK empfangen und $20, Bit5=1 =NACK, daher 
habe ich spezifisch auf TWSR Bit5 getestet (übrigens Super Tabelle in 
den Atmega-Datenblättern, sh. "Formats and States in the Master 
Transmitter Mode"). Universeller ist natürlich die Prüfung auf ERR=1, 
weil sie alle Fehler umfasst.

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

Hier nun der "finale" Bascom-Code, um EEproms mit PageWrite (gilt schon 
ab 2 Bytes !!) zu beschreiben. Bitte beim Testen aufpassen, dass das 
EEPROM nicht in einer Endlosschleife getestet wird..
1
$regfile = "m644def.dat"
2
$crystal = 8000000
3
$swstack = 128
4
$hwstack = 128
5
$framesize = 128
6
$baud = 19200
7
$lib "i2c_twi.lbx"
8
Config Serialout = Buffered , Size = 254
9
'**************************** Hardware-Definitionen
10
Config Twi = 100000
11
Config Sda = Portc.1                                        'I2C-Pins definieren, bei Atmega 8: PortC.4
12
Config Scl = Portc.0                                        'PortC.5 bei Atmega 8
13
Const Eprom_write = 160
14
Const Eprom_read = 161
15
Dim I As Byte
16
Dim J As Byte
17
Dim Byt As Byte                                             '
18
Dim Bytwrite As Byte
19
Dim Wrdadr As Word
20
Dim Wrdadrbytes(2) As Byte At Wrdadr Overlay
21
Declare Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
22
Taster Alias Pina.1
23
Config Porta.1 = Input
24
'**************************** ab jetzt betriebsbereit
25
Enable Interrupts
26
Cls
27
Const Cpage = 128                                           'Paging-Größe lt. Datenblatt EEPROM
28
Const Cbytes2write = 20                                     'max. 20 Bytes, muss <=cPage sein
29
Wrdadr = 110                                                'Testadresse=110, 130, 150 usw.
30
'I2cinit                                                     'verwende eigene Pullups-Widerstände am Busende
31
Do
32
   'Achtung nicht als Endlosschleife, sonst neues EEPROM kaufen
33
   If Taster = 1 Then                                       'Achtung: normalerweise =0, meiner ist "anders"
34
      Bytwrite = 1 + Rnd(6)                                 'Würfeln
35
      Print "*************"
36
      Byt = Wrdadr Mod Cpage
37
      Byt = Cpage - Byt
38
      If Byt >= Cbytes2write Then
39
         Byt = 0
40
      End If
41
      J = Fxi2cstart(eprom_write)                           'Teste auf Kommunikation
42
      If J > 0 Then
43
         I2cwbyte Wrdadrbytes(2)
44
         I2cwbyte Wrdadrbytes(1)
45
         For I = 1 To Cbytes2write
46
            I2cwbyte Bytwrite                               'mit select case differenzieren, z.B. 1-4=Adresse,5-6=Logwerte
47
            If Byt = I Then                                 'oder Bytarray schreiben
48
               Wrdadr = Wrdadr + Byt
49
               I2cstop
50
               J = Fxi2cstart(eprom_write)                  'hier keine Fehlerprüfung
51
               I2cwbyte Wrdadrbytes(2)
52
               I2cwbyte Wrdadrbytes(1)
53
            End If
54
         Next I
55
         I2cstop
56
         Wrdadr = Wrdadr - Byt                              'wrd-Adresse richtig erhöhen
57
         Wrdadr = Wrdadr + Cbytes2write
58
      Else
59
         Print "EPROM antwortet nicht"
60
      End If
61
'      Print "Geschrieben"
62
'      'nach dem letzten Schreiben nicht warten
63
'      'gewartet wird erst beim nächsten Zugriff, kann viel später sein!
64
      Wrdadr = Wrdadr - Cbytes2write                        'Adresse zurücksetzen
65
      J = Fxi2cstart(eprom_write)
66
      If J > 0 Then
67
         I2cwbyte Wrdadrbytes(2)
68
         I2cwbyte Wrdadrbytes(1)
69
         I2cstart
70
         I2cwbyte Eprom_read
71
         For I = 1 To Cbytes2write
72
            If I < Cbytes2write Then
73
               I2crbyte Byt , Ack                           'Ack
74
            Else
75
               I2crbyte Byt , Nack                          'Nack
76
            End If
77
            Print Wrdadr ; "=" ; Byt
78
            Incr Wrdadr
79
         Next I
80
         I2cstop
81
      Else
82
         Print "EPROM antwortet nicht"
83
      End If
84
      Waitms 500                                            'Taster könnte ja prellen..
85
   End If
86
Loop
87
Return
88
89
90
Function Fxi2cstart(byval Byti2cadr As Byte) As Byte
91
'Bytzahler muss kleiner 0 sein, sonst Timeout
92
'Universalroutine als Alternative zu normalem I2CStart
93
'Gibts Baustein nicht: Timeout
94
'Acknowledge Polling bei I2CEEPROM - wartet bis Baustein antwortet
95
Local Bytzaehler As Byte
96
Bytzaehler = 0
97
Do                                                          'Beschäftigung, wenn kein Zähler, dann Waitus 1
98
    Incr Bytzaehler                                         'entspricht I2CWrite_EpromWrite
99
    I2cstart
100
    I2cwbyte Byti2cadr
101
Loop Until Err = 0 Or Bytzaehler = 0                        'ERR=1 universeller als TWSR.5, ACK empfangen
102
Fxi2cstart = Bytzaehler
103
End Function

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.