PIC16F886: I2C Problem mit ACK Expander PCF8575

OP Persönliche Seite #7555751
Lesenswert?

Hallo, Guten Morgen. Ich habe ein Problem und bin fast am Verzweifeln. Also frage ich euch mal. Mein Projekt:

  • mit PIC 16F886
  • Programmiersprache: pmp (IDE mit Turbo Pascal)...bitte nicht lachen, aber ich komme damit am besten zurecht
  • ein I2C Bus mit Expandern PCF8574 (8 I/O pins) und PCF8575 (2x8 Pins)
  • das I/O mit dem PCF8574 funktioniert, keine Probleme, das eine Byte wird gelesen
  • beim PCF7575 hab ich Probleme, ich kann nur 1 Byte Input lesen, das zweite Byte wird nicht richtig gelesen.

Also hab ich mal den Oszi angeworfen und sehe dass beim Lesen etwas mit den ACK Bits nicht stimmt. Mein Wissensstand ist dieser:

  • bei einer Write Sequenz sendet der Empänger, also der Expander, jeweils nach 8 empfangenen Bits das ACK Bit (zu sehen als 9. Bit)
  • bei einer Read Sequenz sendet der Slave nach Empfang des Adress Bytes sein ACK bit und sendet die aktuellen Daten des ersten Ports an den Master, der Master quittiert den Empfang mit seinem ACK Bit,
  • nach dem ACK des ersten Datenbytes sendet der Slave die aktuellen Daten des zweiten Ports. Wenn das ACK des Masters aber fehlt (wie in meinem Problemfall, siehe angehängte Bilder), sendet der Slave keine aktuellen Daten sondern lauter 1'.

Mein Problem ist also vermutlich, dass der Master bei einem Read mit 2 Datenbytes kein ACK sendet. Ja, das ACK fehlt schon bei dem ersten Byte. Da das ACK aber erst nach dem Empfang der Daten gesetzt wird, wird das erste Datenbyte noch korrekt empfangen, aber nicht mit einem ACK vom Master bestätigt.

Nun meine Frage, weiß jemand wie ich den PIC Master dazu bringe sein ACK zu senden bei einer Read Sequenz?

Anhang: 2 Screenshots Bild 1: das Adressbyte wird vom Slave richtg ACKnowledged (=das 0 Bit als 9. Bit nach den 8 Adressbits, in dieser Sequenz schicke ich nur 1-Daten um die Pins auf Input zu schalten --- das funktioniert also Bild 2: in der Read Sequenz bleibt das ACK vom Master High --> Problem!

Kann mir jemand helfen? Gruß Bernd.

OP Persönliche Seite #7555765
Lesenswert?

bin's noch mal. Ich hab mir die Sache bei dem PCF8574 mit dem Oszi auch mal genauer angeschaut, er sendet ja nur ein Datenbyte. Auch bei dem fehlt wie ich richtig vermutete, das positive ACK vom Master (= value auf der SDA Leitung). Das war mir bisher nicht aufgefallen, weil das Byte die aktuellen Inputs richtig enthielt. Aber es fehlt das positive ACK des Masters.

Hoppla, und ich sehe es fehlt der 9. Clockimpuls nach dem Datenbyte.

Oder wird bei nur einem Datenbyte gar kein ACK gesetzt vom Master und er clockt gar nicht mehr den 9. Impuls?

Nun sehe ich auch dass bei den 2-Bytigen PCF8575 das erste Datenbyte nur 6 Clockimpulse hat, also kein ACK, das 2. Byte dann aber 9 Clocks aber der ACK ist nicht gesetzt.

Sehr komisch.

Bernd.

#7555879
Lesenswert?

Bernd K. schrieb:

im Datenblatt des PPCF8575 steht aber, dass bei einem Read der Slave das ACK generiert....s. Copy

Das ist doch genau das, was Clemens schrieb: Um die Übertragung seitens des Maters zu beenden, schickt dieser ein NACK. Alle anderen, fortlaufenden Lesevorgänge werden mit einem ACK quittiert. Der Fehler liegt demnach an der I²C-Leseroutine des Masters ==> Quewllcode zeigen!

OP Persönliche Seite #7555883
Lesenswert?

meine Quellcodes:

die I2C Procedures (das ist Turbo Pascal)

1
procedure PCF2_Read ();
2
begin
3
  //Adresse des zu lesenden PCF Expanders
4
  OPCODE := PCF_ADDR shl 1;
5
  //I2C Start
6
  I2C_Master_Start;
7
  //Lesen: zunächst Port auf HIGH schalten -->Pullups notwendig
8
  I2C_Master_Write(OPCODE);    //Opcode mit R/W = 0 = W
9
  I2C_Master_Write(0xFF);      //Outputs HIGH damit die Pins INPUT werden
10
  I2C_Master_Write(0xFF);      //Outputs HIGH damit die Pins INPUT werden
11
  I2C_Master_RepeatedStart;    // restart weil jetzt wieder eine Adresse mit W/R kommt
12
  I2C_Master_Write(OPCODE or 0x01);    //Opcode mit R/W = 1 = R
13
  //Daten empfangen  bei pcf8475 2x,  bei pcf8474 nur 1x
14
  PCF_Data_Read1 := I2C_Master_Read;
15
  PCF_data_Read2 := I2C_Master_Read;
16
  //I2C Stop
17
  I2C_Master_Stop;
18
end;
19
------------------------------------
20
Unit adI2C;
21
interface
22

23
//I2C Routinen
24
Procedure I2C_Master_Init;
25
procedure I2C_Master_Write(data:byte);
26
function  I2C_Master_Read : byte;
27
Procedure I2C_Master_Start;
28
Procedure I2C_Master_Stop;
29
Procedure I2C_Master_RepeatedStart;
30

31
//==================================================
32
//------------[ MCP und PCF ADRESSEN ]--------------
33
//--------------------------------------------------
34
Var
35
  SCL_D  : boolean @ TRISC.RC3;
36
  SDA_D  : boolean @ TRISC.RC4;
37

38
const
39
 I2C_CLOCK    = 100000; //100000;                              // Required I2C bit rate in Hz
40
 I2C_CLK_INIT = (FREQUENCY div 4 div I2C_CLOCK) - 1;           // I2C bit rate init value
41
 {$IF (I2C_CLK_INIT <= 0) or (I2C_CLK_INIT >= 256)}
42
     {$UERROR 'The requested I2C speed cannot be achieved with these settings'}
43
 {$IFEND}
44

45
Implementation
46

47
//==================================================
48
//---------------[ I2C-Master Routines ]------------
49
//--------------------------------------------------
50
Procedure I2C_Master_Init;
51
begin
52
  SSPCON  := 0x28;
53
  SSPCON2 := 0x00;
54
  SSPSTAT := 0x00;      //im I2C master-mode: sets transmit not in progress
55
  SSPADD  := I2C_CLK_INIT;
56
  SCL_D   := 1;         //das sind TRISC.3 und 4 --> Outputs
57
  SDA_D   := 1;
58
end;
59

60
Procedure I2C_Master_Waitforidle;
61
begin
62
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
63
end;
64

65
Procedure I2C_Master_Start;
66
begin
67
  //I2C_Master_WaitforIdle();
68
   while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
69
  SEN := 1;
70
end;
71

72
Procedure I2C_Master_Stop;
73
begin
74
  //I2C_Master_WaitforIdle;
75
   while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
76
  PEN := 1;
77
  nop;nop;nop;
78
end;
79

80
Procedure I2C_Master_RepeatedStart() ;
81
begin
82
  //I2C_Master_WaitforIdle;
83
   while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
84
  RSEN := 1;
85
  nop;nop;nop;
86
end;
87

88
procedure I2C_Master_Write(data:byte);
89
begin
90
  //I2C_Master_WaitforIdle;
91
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
92
  SSPBUF := data;
93
  while (NOT SSPIF) do; // Wait Until Completion
94
  SSPIF := 0;
95
end;
96

97
function I2C_Master_Read : byte;
98
begin
99
  //I2C_Master_WaitforIdle;
100
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
101
  RCEN :=1;
102
  while (NOT SSPIF) do; // Wait Until Completion
103
  //I2C_Master_WaitforIdle;
104
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
105
  return SSPBUF;
106
  SSPIF := 0;
107
end;
108

109
initialization
110
End.
111
*******************
OP Persönliche Seite #7555891
Lesenswert?

Rahul D. schrieb:

Der Fehler liegt demnach an der I²C-Leseroutine des Masters

ja, es muß an diesem Unterprogramm liegen, da fehlt noch irgendein Registersetzen oder an der Procedure I2C_Master_Init

1
Procedure I2C_Master_Init;
2
begin
3
  SSPCON  := 0x28;
4
  SSPCON2 := 0x00;
5
  SSPSTAT := 0x00;      //im I2C master-mode: sets transmit not in progress
6
  SSPADD  := I2C_CLK_INIT;
7
  SCL_D   := 1;         //das sind TRISC.3 und 4 --> Outputs
8
  SDA_D   := 1;
9
end;
10

11

12

13
function I2C_Master_Read : byte;
14
begin
15
  //I2C_Master_WaitforIdle;
16
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
17
  RCEN :=1;
18
  while (NOT SSPIF) do; // Wait Until Completion
19
  //I2C_Master_WaitforIdle;
20
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
21
  return SSPBUF;
22
  SSPIF := 0;
23
end;
OP Persönliche Seite #7555902
Lesenswert?

Rahul D. schrieb:

Ungünstig... Das sollte meiner Meinung nach erst am Ende des kompletten Lesevorgangs passieren. Dir fehlt da eine Schleife über die Anzahl der zu lesenden Bytes. Danach kann dann das Stop-Signal gesendet werden.

mache ich doch: Stop ist einmal am Ende und innen sind 2 Reads. // im Code sind Kommentare

1
procedure PCF2_Read ();
2
begin
3
  //Adresse des zu lesenden PCF Expanders
4
  OPCODE := PCF_ADDR shl 1;
5
  //I2C Start
6
  I2C_Master_Start;
7
  //Lesen: zunächst alles auf HIGH schalten
8
  I2C_Master_Write(OPCODE);    //Opcode mit R/W = 0 = W
9
  I2C_Master_Write(0xFF);      //Outputs HIGH damit die Pins INPUT werden
10
  I2C_Master_Write(0xFF);      //Outputs HIGH damit die Pins INPUT werden
11
  I2C_Master_RepeatedStart;    // restart weil jetzt wieder eine Adresse mit W/R kommt
12
  I2C_Master_Write(OPCODE or 0x01);    //Opcode mit R/W = 1 = R
13
  //Daten empfangen  bei pcf8475 2x,  bei pcf8474 nur 1x
14
  PCF_Data_Read1 := I2C_Master_Read;
15
  PCF_data_Read2 := I2C_Master_Read;
16
  //I2C Stop
17
  I2C_Master_Stop;
18
end;

Hier der Link zum Datenblatt https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/40001291H.pdf

OP Persönliche Seite #7556151
Lesenswert?

Jetzt hab ich's gepackt, es läuft.

Für das Lesen von 2 Datenbytes vom PCF8575 Expander hab ich jetzt 2 Routinen, eine für das erste Datenbyte und eine für das zweite.

Bei der ersten Sequenz wird am Ende der Übertragung noch das ACK eingeschoben.

Hier mein Code:

1
procedure PCF2_Read ();
2
begin
3
  OPCODE := PCF_ADDR shl 1;
4
  I2C_Master_Start;
5
  I2C_Master_Write(OPCODE or 0x01);    //Opcode mit R/W = 1 = R
6
  PCF_Data_Read1 := I2C_Master_Read1;   //<--- NEU: Sequenz mit ACK
7
  PCF_data_Read2 := I2C_Master_Read2;   //<--- NEU: Sequenz ohne ACK
8
  I2C_Master_Stop;
9
end;
10

11
------------------------------------------------------------
12
function I2C_Master_Read1 : byte;
13
begin
14
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do; //wait until in idle mode
15
  RCEN :=1;
16
  while (NOT SSPIF) do;           // Wait Until Completion
17
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do; //wait until in idle mode
18
  //neu
19
  I2C_Master_SetACK;  //<----------- NEU!!
20

21
  return SSPBUF;
22
  SSPIF := 0;
23
end;
24

25
procedure I2C_Master_SetACK;
26
begin
27
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do; //wait until in idle mode
28
  ACKDT := 0;   //ACK=0
29
  ACKEN := 1;   //Event setzen
30
end;
31

32
function I2C_Master_Read2 : byte;
33
begin
34
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
35
  RCEN :=1;                                                  //Read enable
36
  while (NOT SSPIF) do;                                   // Wait Until Completion
37
  while((SSPSTAT and 0x04) or (SSPCON2 and 0x1F)) do;     //wait until in idle mode
38
  return SSPBUF;
39
  SSPIF := 0;
40
end;

Damit wäre mein Problem dank eurer Hilfe (besonders von Clemens mit dem Hinweis auf das ANxx Papier) gelöst. Ich bedanke mich herzlich.

Gruß Bernd.

#7556299
Lesenswert?

Bernd K. schrieb:

Mich wundert nur, dass SDA nach dem ACK Clock bis zum nächsten Byte-Lesen LOW bleibt. Ist das normal?

Ja. Der Zustand von SDA wird nur während der steigenden Flanke von SCL gelesen; was mit SDA passiert, während SCL Low ist, ist egal. (Und da um das ACK-Bit herum zwischen Master und Slave umgeschaltet wird, kann es durchaus passieren, dass SDA hin und her wackelt.)

OP Persönliche Seite #7556849
Lesenswert?

Der Sinn des NACK am Ende leuchtet mir noch nicht ein.

Ich hab jetzt mal dieses getestet:

  1. Am Ende wird ein ACK geschickt: ----> gelesene Daten sind OK
  2. Am Ende wird ein NACK geschickt: ---> gelesene Daten sind OK
  3. Am Ende weder ein ACK noch ein NACK:--> alle Daten OK

Also wozu soll der Impuls dienen? Ich sehe es so: der ACK dient dazu, dass der Slave sich zum Senden des nächsten Bytes vorbereiten kann/soll, nach dem letzten Byte wird nichts mehr abgerufen, also wäre der ACK Impuls auch nicht nötig (es hat da keinen Sinn mehr).

OP Persönliche Seite #7556893
Lesenswert?

Peter D. schrieb:

Der Master muß als letztes ein NACK senden, damit der Slave weiß, daß er nun SDA loslassen muß. Ansonsten können weitere Daten das Stop des Masters verhindern.

scheint aber nicht so zu sein. Am Ende setzt meine Master Stop Procedure das Register PEN=1. Laut Datenblatt bewirkt das, dass SDA und SCL High gehen. Das Loslassen der SDA durch den Slave wird also initiiert durch die Stop Condition und nicht durch ein NACK.

Datenblatt des PIC 16F886: PEN: Stop Condition Enable bit (in I2C Master mode only) SCK Release Control: 1 = Initiate Stop condition on SDA and SCL pins. Automatically cleared by hardware. 0 = Stop condition Idle

Oder sehe ich da noch was falsch? In meinem angehängten Bild werden SDA und SCL released nach High auch ohne ein NACK, sondern vermutlich durch das PEN=1. Es ist wohl der Zustand dass die SCL permanent high geht, das den Slave veranlasst auch die SDA loszulassen.

Angehängte Dateien:
#7556916
Lesenswert?

Na dann setze mal den PCF8574 auf 0x00 und versuche ihn zurück zu lesen. Der Master kann dann kein Stop mehr senden. Es sei denn, der PIC hat auch ein I2C-Recovery implementiert, wie die alten Philips 80C51: "If the SDA line is obstructed by another device on the bus (e.g., a slave device out of bit synchronization), the problem can be solved by transmitting additional clock pulses on the SCL line (see Figure 14). The SIO1 hardware transmits additional clock pulses when the STA flag is set, but no START condition can be generated because the SDA line is pulled LOW while the I2C bus is considered free. The SIO1 hardware attempts to generate a START condition after every two additional clock pulses on the SCL line. When the SDA line is eventually released, a normal START condition is transmitted, state 08H is entered, and the serial transfer continues."

OP Persönliche Seite #7556954
Lesenswert?

Peter, ich hab mal deinen Fall getestet PCF8575 alle 16 Pins auf Output 0 und dann 2 Bytes lesen mit ACK oder NACK oder garnix nach dem 2. Byteread:

  1. Bei NACK und garnix wird die Sequenz mit der Stop Condition sauber beendet. Aber wie du schon vermutest, der Fall mit dem fehlenden ACK/NACK Puls ist nicht Spec-konform.
  2. Bei ACK am Ende hängt die Sequenz, naja der Slave wartet auf die Clocks....also erwartetes Verhalten.

Aber wie getestet, NACK oder garnix ist kein Unterschied.

Ich habe allerdings zZ nur einen einzigen Slave am Bus, kann also noch nicht die komplette Story in ihren Folen testen.

Sicherlich kann man über viele andere Fälle diskutieren. Ich hab nun das NACK nach dem letzten Read eingebaut, und gut ist's.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren