Forum: Mikrocontroller und Digitale Elektronik R8C23: I²C; Steuerung Porterweiterung


von D. F. (fabiand)


Lesenswert?

Guten Tag zusammen!

Ich versuche mit dem R8C23 über I²C eine Porterweiteurng anzusteuern. 
Leider funktioniert dies nicht ganz so wie ich das gern hätte.
Um dem Fehler auf den Grund zu gehen habe ich das ausgehende Signal vom 
Controller mit dem scope gemessen: Es werden nicht die richtigen Bytes 
versandt (zumindest glaub ich das :-)). Ebenso erhelte ich kein 
Acknowledge vom Slave.
Wenn ich das alles richtig sehe, dann stimmt irgendetwas mit der 
Kommunikation zwischen den beiden Teilen nicht.

Hat irgendjemand schon mal ähnliches versucht und hat evtl. sogar einen 
C-code?!?
Bin über jede Hilfe dankbar!

Beste ...

von Martin (Gast)


Lesenswert?

Angenummen du sendest wirklich falsche Byte ... Warum sollte der Chip 
ein Ackn senden, wenn er sich nicht angesprochen fühlt?

Warst du schon mal auf der Renesas Seite? Dort gibt es Code-Beispiele 
ohne Ende.

von D. F. (fabiand)


Lesenswert?

Danke für deine Antwort!

Ja eben, das ist mir auch klar. Wenn der Master nix anständiges sendet 
kann der Slave auch nix antworten.
Eigenartig ist es, dass der master, wenn ich ihm z.b. 0b11101000 über 
das register icdrt senden lasse auf dem SDA port 101010101 sendet. Der 
SCL schmeißt bloß undefinierbares raus.

Suche der Weil mein Passwort für renesas ... :-)

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

VERMUTLICH hast du eine Falsche Adresse. Aus z.b. 01100110 wird 
00110011, die 0 am Rechten Ende (R/W) Bit muss für manche Libraries 
abgeschnitten werden, für andere nicht.

von D. F. (fabiand)


Lesenswert?

Danke ...
Die Änderung der Adresse macht leider keinen Unterschied ...
Ich glaube ich habe insgesamt etwas falsch eingestellt.
:-(

von D. F. (fabiand)


Lesenswert?

bracuhe ich eigentlich für IIC unbedingt einen Interrupt?

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


Lesenswert?

Fabi D. schrieb:
> bracuhe ich eigentlich für IIC unbedingt einen Interrupt?

Nein, kannst ja mit einem Timer oder sonstwie (un)regelmäßig den Slave 
ansteuern und Daten austauschen

von Martin (Gast)


Lesenswert?

Fabi D. schrieb:
> Suche der Weil mein Passwort für renesas ... :-)

Dafür brauchst du kein Benutzernamen oder Passwort.

von Martin (Gast)


Lesenswert?

Fabi D. schrieb:
> bracuhe ich eigentlich für IIC unbedingt einen Interrupt?

Da musst du mal ins Datenblatt schaun, da gibt es bestimmt ein Bit 
welches gesetzt wird, wenn ein Byte gesendet wurde. Dises kannst du dann 
auch per polling abfragen. Dieses Bit nutzt üblicherweise auch die 
Interruptlogik.

von Juergen (Gast)


Lesenswert?

Bist du an den richtigen Pins? 101010101 sieht wie ein Taktsignal aus.

von D. F. (fabiand)


Lesenswert?

Moin Moin!
Habe die pins noch einmal kontrolliert; sind die richtigen ...

So, SCL läuft perfekt und auch SDA. Spricht die Clock rattert und die 
Daten bzw. die Slave Adresse wird übertragen. ... Nur leider kein 
Ackowledge in Sichtweite.
Was sagt ihr zum code?     (Ich hoffe er ist noch net zu lang fürs 
Forum)

void master_transmit (void)
{  unsigned char temp;

  stop_icsr = 0;  //Stop bit zum Reset
  ice_iccr1 = 1;  //I²C Bus enable
  iicsel= 1;
  wait_icmr = 1;
  mls_icmr = 1;  // Daten werden als MSB-first versandt

  while (bbsy_iccr2 != 0);// I2C besetzt? warten bis frei

  trs_iccr1 = 1;    // 11 --> Master transmit mode
  mst_iccr1 = 1;

  //start condition:
  temp = iccr2;
  temp &= 0b10111111;      //scp = 0    b6
  temp |= 0b10000000;      //bbsy = 1    b7
  iccr2 = temp;

  icdrt = port_erweiterung_master_transmit;   // read/write Data: 
slaveadress + R/W

  while (tend_icsr != 1);  // warten bis byte übermittelt wurde


  if (ackbr_icier == 0)// Acknowledge/Bestätigung vom slave
  { [...] }else{
  tend_icsr = 0;
  stop_icsr = 0;

  temp = iccr2;
  temp &= 0b10111111;  //scp = 0    b6
  temp |= 0b01111111;  //bbsy = 0    b7
  iccr2 = temp;

  while (stop_icsr != 1); // warten bis stopcondition gesetzt ist

  trs_iccr1 = 0;
  mst_iccr1 = 0;

  tdre_icsr = 0;
  }}

von Martin2 (Gast)


Lesenswert?

Geht es um einen PCF8574?

von D. F. (fabiand)


Lesenswert?

nein. um einen PCA9539.

Nun kann ich ohne Probleme vom Master zum Slave daten senden und an der 
Porterweiterung z.b. LEDs steuern.

Aber schon steht das nächste Problem ins Haus: Wie kann ich einen taser 
am Slave betreiben? Dazu muss ich doch den auslesen, oder? bzw. 
Master_receive mode, oder?

Sobald ich das LSB von 0 auf 1 setzte, um ein Auslesen zu initiieren 
(alle anderen bits bleiben --> Slaveadresse), passiert nichts mehr.

Besten Gruß!

von Tobyas H. (tobyas)


Lesenswert?

Fabi schrieb:
> Sobald ich das LSB von 0 auf 1 setzte, um ein Auslesen zu initiieren
> (alle anderen bits bleiben --> Slaveadresse), passiert nichts mehr.

Nur um sicherzugehen...

Du hast beachtet, dass du zunächst einen Schreib -Zugriff machst um 
mittels Command Byte das Register zu definieren, von dem du danach den 
Lese -Zugriff wünscht.

Siehe Datenblatt Seite 7 Absatz 2 "Reading the port registers"
und Figure 8 "READ from register"

> Dazu muss ich doch den auslesen, oder?

Ja.

> bzw. Master_receive mode, oder?

Dein R8C bleibt im Master mode und führt (nach dem transmit) ein receive 
durch.

von D. F. (fabiand)


Lesenswert?

Danke für die Antwort!
Ich glaube ich habe all diese Dinge berücksichtigt. Aber irgendetwas 
wohl nicht, sonst würde es funktionieren.

Auszug aus code:

icdrt = adresse_iic_chip_write;
icdrt = command_input_port;
while (tdre_icsr != 1);
while (ackbr_icier != 0);
icdrt = adresse_iic_chip_receive;
while (tend_icsr != 1);
tend_icsr = 0;
trs_iccr1 = 0;
mst_iccr1 = 1;
tdre_icsr = 0;
ackbt_icier = 0;
icdrt = adresse_iic_chip_receive;     --> hier hängt er sich auf
while (tend_icsr != 1);
dummy_data_0 = icdrr;
while (rdrf_icsr != 1);
ackbr_icier = 1;
dummy_data_1 = icdrr;

Achso, ich möchte einen Taster betreiben und LEDs. Die LEDs kann ich 
ansteuern. Allerdings nur über das Configuration Register.

Munter bleiben!

von D. F. (fabiand)


Lesenswert?

Ich bin's noch einmal ...

welche Register muss ich steuern, um LEDs bzw./und Taster an der 
Porterweiterung anzusteuern/zu lesen.

Ich kann, wie ich oben beschrieben habe, die LEDs nur per 
Configurationsregister an und ausschalten. beim Output bekomme ich kein 
Signal, d.h. die Leds rühren sich nicht; obwohl das Signal auf dem Scope 
gar nicht schlecht aussieht.

Probleme über Probleme ... Fragen über Fragen ... :-)

von Tobyas H. (tobyas)


Lesenswert?

Hallo Fabi,

also mit deinem Code stimmt noch vieles nicht. Ohne mir das korrekte 
Handling der I2C bits im R8C anzuschauen, fällt mir schonmal das 
Folgende auf. (siehe Kommentare)
1
icdrt = adresse_iic_chip_write;    // schreib-operation ausloesen
2
icdrt = command_input_port;    // setzte input port register (per command byte)
3
while (tdre_icsr != 1);
4
while (ackbr_icier != 0);
5
icdrt = adresse_iic_chip_receive;  // lese-operation ausloesen
6
while (tend_icsr != 1);
7
tend_icsr = 0;
8
trs_iccr1 = 0;        // irgendwo hier sollten mal die Daten GELESEN werden.
9
mst_iccr1 = 1;
10
tdre_icsr = 0;
11
ackbt_icier = 0;
12
icdrt = adresse_iic_chip_receive;     --> hier haengt er sich auf  
13
          // lese-operation ausloesen (Aber von welchem command byte nur?)
14
while (tend_icsr != 1);
15
dummy_data_0 = icdrr;      // lese ??? register
16
while (rdrf_icsr != 1);
17
ackbr_icier = 1;
18
dummy_data_1 = icdrr;      // lese ??? register nochmal (Warum? Jedes Register hat nur 8 byte)

Du solltest den ganzen Code systematischer und in Funktionen gegliedert 
schreiben. Dann fällt dich auch viel schneller auf, was du eigentlich 
machst.

> Achso, ich möchte einen Taster betreiben und LEDs.
> Ich kann die LEDs nur per Configurationsregister an und ausschalten.
> beim Output bekomme ich kein Signal, d.h. die Leds rühren sich nicht

Leider fängt dein Problem schon etwas Grundlegender an;
Du hast den PCA9539 noch nicht richtig verstanden. Also mal von Anfang 
an.

Du hast 4 LEDs an Output 0.0 bis Output 0.3
und einen Schalter an Input 1.0.

Jetzt müssen zunächst die Teiber konfiguriert werden (Eingang oder 
Ausgang). Dazu wird ein Wert für beide 'Configuration Port Register' 
geschrieben.
1
PCA9539_Schreibe(Configuration_port_0, 0xF0);  // Port 0.0 bis 0.3 ist Ausgang für die LEDs (andere 0.x sind Eingang)
2
PCA9539_Schreibe(Configuration_port_1, 0xFF);  // Port 1.0 ist Eingang für den Schalter (andere 1.x sind Eingang)

Jetzt möchtest du zwei LEDs einschalten.
Dazu wird ein Wert für das 'Output port 0 Register' geschrieben.
Achtung: Wenn du nur den Wert in dieses Register schreibst, aber den 
Port nicht als Ausgang konfiguriert hast (s.o.) dann ist der Port ein 
Eingang und kann auch keinen Strom durch die LED treiben.
-> Das war einer deiner Fehler.
1
PCA9539_Schreibe(Output_port_0, 0x03);  // LEDs 0.0 und 0.1 an, LEDs 0.2 und 0.3 aus (0x03 = 0000_0011)

Und dann noch einen Schalter abfragen.
Dazu wird ein Wert vom 'Input port 1 Register' gelesen.
1
uint8_t wert;
2
wert = PCA9539_Lese(Input_port_1);  // lese Wert
3
wert = (wert & 0x01);      // ausmaskieren des bits für Ausgang 1.0 an dem der Schalter ist
4
if (wert == 0) {
5
  // Schalter nicht gedrueckt
6
} else {
7
  // Schalter gedrueckt
8
}

Bleibt die Frage, was machen die Funktionen PCA9539_Lese und 
PCA9539_Schreibe?
Sie sorgen dafür das die richtigen I2C Kommandos benutzt werden um vom 
PCA9539 zu scheiben und zu lesen. Und das steht auf Seite 7-9 im 
Datenblatt.

PCA9539_Schreibe besteht aus zwei I2C Operationen.
1. I2C schreiboperation, wert 'registernummer'
2. I2C schreiboperation, wert 'daten' welche in 'registernummer' 
beschrieben werden sollen.
1
void PCA9539_Schreibe(uint8_t register, uint8_t daten) {
2
  I2C_Write(PCA9539_SLAVE_ADDR, register);
3
  I2C_Write(PCA9539_SLAVE_ADDR, daten);
4
}

PCA9539_Lese besteht auch aus zwei I2C Operationen.
1. I2C scheiboperation, wert 'registernummer'
2. I2C lese operation, welche den Wert aus 'registernummer' ausliest.
1
uint8_t PCA9539_Lese(uint8_t register) {
2
  uint8_t daten;
3
  I2C_Write(PCA9539_SLAVE_ADDR, register);
4
  daten = I2C_Read(PCA9539_SLAVE_ADDR);
5
  return daten;
6
}

Die Funktionen I2C_Write und I2C_Read kannst du jetzt selber 
implementieren. Hier machst du die eigentlichen Registerzugriffe auf die 
I2C hardware des R8C. So wie du es schon mit deinem Code versuchst hast.

Du solltest versuchen diese Systematik ein wenig zu üben.
Alles direkt mit Registerzugriffen runterzuschreiben führt zu schnell zu 
Fehlern die man nur schwer findet. Und der Code wird unübersichtlich und 
nicht erweiterbar.
Stell dir nur vor was passiert, wenn du noch eine weitere LED anschießen 
möchtest. ;-)

von D. F. (fabiand)


Lesenswert?

Danke, Tobyas H., für die sehr detaillierte Hilfestellung!

von D. F. (fabiand)


Lesenswert?

... im Grunde habe ich alles schon so gemacht, wie du (Tobyas) es auch 
hier schreibst.
der oben geschriebene code ist wirklich nur minimal aus verschiedenen 
Funktionen herauskopiert.
Naja nichts desto trotz funzt das lesen nicht. der Taster gibt ein 
Signal, das ich auf dem scope lesen kann.
Vor dem Lesebefehl schreibe ich in das zu lesende Register ... usw.
doch wenn der Controller das Lese-Signal sendet. Bekomme ich kein 
Ackknowledge vom slave. Beim Schreibebefhl dagegen immer.
Ich fürchte eine Ferndiagnose ist nicht wirklich möglich ...

von Tobyas H. (tobyas)


Lesenswert?

Gerne geschehen Fabian.

Du solltest auf jeden Fall dran bleiben. Irgendwo gibt es bestimmt noch 
einen kleinen 'unbedeutenden' Fehler, der dir das Leben schwer macht.
Wenn du Ihn gefunden und gelöst hast lass es uns wissen...

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.