Forum: Mikrocontroller und Digitale Elektronik PIC I2C Problem beim Daten empfangen


von Mario G. (rodenberger)


Lesenswert?

Hallo,

ich komme einfach nicht mehr weiter.

Ich benutze einen PIC 16F877A und betreibe einen TMC222 über I2C damit.
Senden an I2C ist kein Problem.

Das auslesen von Adressen geht aber nicht, da erhalte ich immer 255.
Prinzipiell kann das auslesen aber nicht falsch sein, da sich der TMC222 
sonnst auch nicht ansprechen lassen würde. (Man MUSS erst Daten lesen)

Ein weiteres Problem ist, das ich wenn ich I2C OFF schalte das System 
hängt, wenn ich auf eine Reaktion warte....


; I2C-BUS WIEDER FREIGEBEN
I2C_OFF
        BANKSEL SSPCON2
        BSF     SSPCON2, PEN    ; BUS FREIGABE ANWEISEN
        BANKSEL 0

  Return <---Ohne steht das System, es gehört da aber nicht hin !!!

I2C_WARTE
        BTFSS   PIR1, SSPIF     ; FERTIG?
         GOTO    I2C_WARTE       ; NEIN, NOCH NICHT
        BCF     PIR1, SSPIF     ; JA, ALLES FERTIG, NUN NOCH SSPIF 
ZURÜCKSETZEN

        RETURN

; WEITERE UNTERPROGRAMME

I2C_ON  BCF PORTA , 0
        BCF     PIR1, SSPIF     ; SSPIF BIT LÖSCHEN
        BSF     STATUS, RP0
        BSF     SSPCON2, SEN    ; BUS ÜBERNAHME ANWEISEN
        BCF     STATUS, RP0
        GOTO    I2C_WARTE

; EIN BYTE AUS W SENDEN
I2C_TX
        MOVWF   SSPBUF          ; -> ZUM I2C-SLAVE ÜBERTRAGEN
        GOTO    I2C_WARTE

;EIN BYTE VOM SLAVE EMPFANGEN (NACH SSPBUF)
I2C_RX
        BSF     STATUS, RP0
        BSF     SSPCON2, RCEN   ; DATEN EMPFANG EINSCHALTEN
        BCF     STATUS, RP0


I2C_R7
        BTFSS   PIR1, SSPIF     ; FERTIG?
        GOTO    I2C_R7    ; NEIN, NOCH NICHT
        BCF     PIR1, SSPIF     ; JA, ALLES FERTIG, SSPIF ZURÜCKSETZEN

        MOVF    SSPBUF,0 ;DATEN NACH W <-----hier habe ich immer 255
        ;CALL SENDEN
         Return

ACK

        BANKSEL SSPCON2 ; ACK SENDEN
        BSF   SSPCON2, ACKEN
        BANKSEL 0
         RETURN

Das meiste ist von SPRUT!
Mit den PullUPs habe ich auch schon experimentiert, Nichts

Ich vermute das es ein Problem mit I2C OFF ist, da ich ja erst die 
Adresse an den TMC senden muss, dann I2C ausschalten und wieder 
einschalten zum lesen.
Das Prinzip I2C ist auch klar, einen EEPROM kann ich lesen und 
beschreiben.
Die Taktrate ist auch sehr niedrig eingestellt (mehreres probiert)

Vielen Dank für jeden Tipp.

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Den Bus nach dem Senden der Adresse wieder freizugeben ist meiner 
Meinung nach falsch. Du willst lesen, also holst du dir als erstes den 
Bus (I2C_ON), dann sendest du die Adresse mit Bit0=1 (lesen). Danach 
empfängst du einfach die beiden Bytes (I2C_RX). Erst wenn alle Daten 
empfangen wurden, gibst du den Bus mit I2C_OFF wieder frei.

Auch wenn du lesen willst liefert der Master den Takt. Die Daten werden 
also nicht vom Slave gesendet, sondern vom Master abgeholt. Wenn du vor 
dem Senden den Bus wieder frei gibst, könnte es sein, dass den TMC den 
Lesevorgang abbricht, weil dein Master dann auch kein ACK mehr sendet.

Sven

von Isabelle T. (isa08)


Lesenswert?

Ich kann nicht mehr weiter!!!
kann jemandem mir sagen wie man der Compiler scb9328 installieren kann 
und zwar unter Linux?Ich habe das Programm mir per mail zugeschickt,aber 
kann nicht aufrufen und damit das einfache Programm "Hallo world" 
schreiben.
Ich brauche eure hilfe Bitte!!!!!!

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Und was hat das jetzt mit dem Originalthema zu tun?

von Mario G. (rodenberger)


Lesenswert?

Hallo Sven,

das verstehe ich jetzt nicht.
Wenn ich an den Slave etwas senden möchte, gebe ich die Adresse vom 
Slave an und sende dann gleich die Daten.
Beim lesen geht das doch nicht. Hier muss ich doch erst die Adresse vom 
Slave senden und die Adresse was ich möchte. Dann muss ich aber I2C OFF 
und wieder ON schalten um dem Slave zu sagen das ich wieder lesen will. 
(Bit 0 von 0 auf 1). Jedenfalls habe ich das so verstanden.
Bei einem EEPROM funktioniert das so.
Laut Datenblatt des TMC ist das auch so, nur das er nach dem letzten 
gelesenem Byte ein NoACK möchte.

Den Bus gebe ich erst frei, wenn die Daten auch angekommen sind, bzw das 
NoACK gesendet ist.( etwa wie in I2C_R7 )
Nur scheint unter gewissen Umständen der Bus nicht auf H zu gehen und 
das System hängt dann.

Aber mal agesehen von dem letzen empfangenen Byte, ist das erste auch 
schon 255, obwohl es einen anderen Wert haben sollte.
RS232 ist ok!

Gruß Mario

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Ich kenne zwar deinen Chip nicht, aber bei einem LM75 Temperatursensor 
habe ich das Lesen des Statusbyte ähnlich programmiert. Allerdings habe 
ich nach dem senden der Adresse und dem senden des gewünschten Registers 
den Bus nicht frei gegeben. Das Lesen der Antwortdaten wird dann mit 
einem Restartkommando eingeleitet. Dadurch kannst du auf Lesen 
umschalten ohne den Bus freizugeben. Eventuell reagiert dein IC ja 
ähnlich. Ich hänge mal meine I2C Routinen mit an.
1
;***I2C UNTERPROGRAMME************************************************************
2
;
3
; I2C-Bus im Master-Mode übernehmen
4
; Warten bis MSSP-Modul frei ist
5
i2c_idle
6
  Bank1
7
    btfsc   SSPSTAT, R_W  ;läuft eine Übertragung?
8
    goto    $-1        ;ja, warten...
9
i2cidle_loop2
10
    movfw   SSPCON2      ;nein, läuft ein anderes Ereignis?
11
    andlw   0x1F            ;test auf ACKEN, RCEN, PEN, RSEN, SEN
12
    btfss   STATUS,Z    
13
    goto    i2cidle_loop2  ;ja, warten...
14
  Bank0
15
  return          ;MSSP Modul ist nicht beschäftigt
16
17
i2c_start
18
  call    i2c_idle    ;Bus frei?
19
    Bank1
20
    bsf     SSPCON2, SEN    ;Bus Übernahme anweisen und Startbit senden
21
    btfsc   SSPCON2, SEN  ;Auf das Ende der Startkondition warten
22
    goto    $-1
23
   Bank0
24
  return
25
26
;Restart aktivieren
27
i2c_rstart
28
    call    i2c_idle    ;Bus frei?
29
  Bank1
30
    bsf     SSPCON2, RSEN   ;Restart Sequence einleiten      
31
  btfsc   SSPCON2, RSEN
32
    goto  $-1
33
  Bank0
34
    return
35
36
;ein Byte aus W senden
37
;Rückgabewert in W: 0=ACK empfangen, 1=ACK nicht empfangen 
38
i2c_tx
39
  movwf  i2c_Puffer
40
    call    i2c_idle      ;Bus frei?
41
    bcf     PIR1, SSPIF     ;Lösche Interrupt Flag
42
  movfw  i2c_Puffer
43
    movwf   SSPBUF          ;Byte wird gesendet
44
    btfss   PIR1, SSPIF     ;Senden fertig?                
45
    goto  $-1
46
47
    Bank1
48
  btfss   SSPCON2, ACKSTAT ;Test ob ACK vom Slave empfangen wurde
49
  goto  i2c_tx_ack
50
  Bank0
51
    retlw   d'1'      ;ACK wurde nicht empfangen
52
i2c_tx_ack
53
  Bank0
54
    retlw   d'0'            ;ACK wurde empfangen
55
56
;ein Byte vom Slave empfangen ohne ACK
57
;Rückgabewert in W
58
i2c_rx
59
    call    i2c_idle
60
    bcf     PIR1,SSPIF    ;Interrupt Flag löschen
61
  Bank1                   
62
    bsf     SSPCON2, RCEN   ;Empfang einschalten
63
  Bank0     
64
  btfss   PIR1,SSPIF      ;Byte empfangen?
65
    goto  $-1        ;noch nicht
66
67
    Bank1
68
  bsf     SSPCON2, ACKDT  ;kein ACK senden (ACK=High)
69
    bsf     SSPCON2, ACKEN  ;sende negatives ACK
70
    btfsc   SSPCON2, ACKEN  ;fertig?
71
    goto    $-1
72
  Bank0
73
  movfw  SSPBUF      ;Empfangenen Wert nach W
74
    return
75
76
;ein Byte vom Slave empfangen mit ACK
77
;Rückgabewert in W
78
i2c_rx_ack
79
    call    i2c_idle
80
    bcf     PIR1,SSPIF    ;Interrupt Flag löschen
81
  Bank1
82
    bsf     SSPCON2, RCEN   ;Empfang einschalten
83
  Bank0     
84
  btfss   PIR1,SSPIF      ;Byte empfangen?
85
    goto  $-1        ;noch nicht
86
87
    Bank1
88
  bcf     SSPCON2, ACKDT  ;ACK senden
89
    bsf     SSPCON2, ACKEN
90
    btfsc   SSPCON2, ACKEN  ;fertig?
91
    goto    $-1
92
  Bank0
93
  movfw  SSPBUF      ;Empfangenen Wert nach W
94
    return
95
96
; I2C-Bus wieder freigeben
97
i2c_stop
98
    call    i2c_idle
99
  Bank1
100
    bsf     SSPCON2, PEN    ;Stop Bit senden und Bus frei geben
101
    btfsc   SSPCON2, PEN  ;fertig?
102
  goto  $-1
103
  Bank0
104
    return
105
106
;***ENDE UNTERPROGRAMME**********************************************************

von Mario G. (rodenberger)


Lesenswert?

Hallo Sven,

Du bist mein Retter ;o)
Ich habe jetzt deinen Code übernommen und in der Programiersprache 
entsprechend angepasst.
Ich benutze zwar den RESTART nicht, aber es funktionierte auf anhieb.
Nun wüste ich gerne warum das so ist, da ich nicht nur den Code kopieren 
sondern auch verstehen will.
Mir fällt allerdings schon auf, das Du andere Bits abfragst ob I2C 
beschäftigt ist oder nicht.
Mein Code entspricht in etwa dem von der Microchip-Seite.
Wie schon geschrieben funktionierte das auch mit einem EEPROM.

Bin mal gespannt ob es später mit dem EEPROM auch noch geht, da der auch 
an diesen I2C-Bus kommt.

Also nochmals BESTEN DANK!!!

Gruß Mario

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Ehrlich gesagt, hatte ich die Routinen auch nur irgendwo im iNet 
gefunden, nachdem die sprut Routinen bei meinem LM75 nicht klappten (der 
Fehler lag allerdings woanders, glaube ich). Ich hatte vor ein paar 
Wochen den Fehler hier beschrieben allerdings finde ich den Beitrag 
nicht mehr. Wie sucht man hier eigentlich nach seinen eigenen Beiträgen?

Ich habe mich aber ein wenig mit den Routinen beschäftigt und mit dem 
Datenblatt verglichen. Mir erschienen diese Routinen irgendwie richtiger 
als die von sprut, da hier immer genau die Bits abgefragt werden, welche 
für den jeweiligen Vorgang relevant sind. Auch die Abfrage auf Idle ist 
so im Datenblatt beschrieben. Bei mir laufen die Routinen mit dem LM75 
und einem I/O Driver am Bus bisher problemlos. Ein EEPROM soll auch noch 
dran, das hab ich aber noch nicht probiert.

Freut mich das es bei dir geht.

Sven

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.