Ressourcen-Icon

SAM D21J17A im Modularen Board System 2017-06-18

Hallo Achim,
Ich denke der Fehler liegt an dem Argument der if-Anweisung, an der Konstanten.

dein Code:


CodeBox C
if (i2c_read_buffer[0] & 0xf1)       // Taster gedrückt


0xF1 = 0b11110001

Das Argument wird wahr, wenn Bits 7..4 oder 0 high sind,
also im Moment wahrscheinlich immer.


So müsstest du abfragen (Beispiele) ...



CodeBox C
// Aktuell bei dir Taster an Input Bit 2:
if (!(i2c_read_buffer[0] & (1<<2)))       // Taster Input Bit 2 gegen GND


// Taster an anderen Pins:
if (!(i2c_read_buffer[0] & (1<<0)))       // Taster Input Bit 0 gegen GND
if (!(i2c_read_buffer[0] & (1<<1)))       // Taster Input Bit 1 gegen GND
...
if (!(i2c_read_buffer[0] & (1<<7)))       // Taster Input Bit 7 gegen GND



Alternative zu diesem Argument:
(so hast du es in deinem Code gelöst, allerdings nun den ~ Operator vergessen und die Konstante nicht richtig)



CodeBox C
if (~meinbuffer[0] & 0x02)
// oder
if (~meinbuffer[0] & (1<<2))


~ binär 1er Komplement Operator (alle Bits werden invertiert)

(ich bevorzuge die Schreibweise mit !)


Dirk :ciao:
 
Hallo Dirk


CodeBox C
while (1)
     {
         
       read_data();

damit rufe ich den Lesevorgang auf


CodeBox C
void read_data(void)
    {   
     uint16_t timeout;
     timeout = 100;
     packet.address     = SLAVE_ADDRESS_2;
     packet.data_length = 0;
     packet.data        = i2c_write_buffer_a;
     i2c_write_buffer_a[0] = 0xff;
     while (i2c_master_write_packet_wait(&i2c_master_instance, &packet) != STATUS_OK)
       {
         if (timeout++ == Timeout)
           {
             // Error LED_PB30_ON
             break;
           }
       }
     packet.address     = SLAVE_ADDRESS_2;
     packet.data_length = 0;           //DATA_LENGTH_1;
     packet.data        = i2c_read_buffer;
     while (i2c_master_read_packet_wait(&i2c_master_instance, &packet) != STATUS_OK)
       {
         if (timeout++ == Timeout)
           {
             // Error LED_PB30_ON
             break;
           }
       }
    }

Der Fehler scheint im letzten Teil zu liegen. Sobald ich das lesen aufrufe kommt der IC nicht mehr aus dem Code raus. Konnte aber noch keine Zeile genau lokalisieren.
achim
 
Der Fehler scheint im letzten Teil zu liegen. Sobald ich das lesen aufrufe kommt der IC nicht mehr aus dem Code raus. Konnte aber noch keine Zeile genau lokalisieren.
Schau dir die Zeilen 6 und 18 an.
Auch mit dem timeout spätestens beim Read stimmt was nicht, falls wiederholt gelesen werden soll, da es vor dem Read nicht initialisiert wird.
 
Hallo Dirk
habe die Sachen geändert. Leier keine Änderung.


CodeBox C
void read_data(void)
    {   
     uint16_t timeout;
     timeout = 0;
     packet.address     = SLAVE_ADDRESS_2;
     packet.data_length = 1;
     packet.data        = i2c_write_buffer_a;
     i2c_write_buffer_a[0] = 0;
     while (i2c_master_write_packet_wait(&i2c_master_instance, &packet) != STATUS_OK)
       {
         if (timeout++ == Timeout)
           {
             // Error LED_PB30_ON
             break;
           }
       }  
     packet.address     = SLAVE_ADDRESS_2;
     packet.data_length = 32;           //DATA_LENGTH_1;
     packet.data        = i2c_read_buffer;
     timeout = 0;
     while (i2c_master_read_packet_wait(&i2c_master_instance, &packet) != STATUS_OK)
       {
         if (timeout++ == Timeout)
           {
             // Error LED_PB30_ON
             break;
           }
       }
    }

Es entspricht genau deiner Angabe.
achim
 
Ich habe im Moment auch keine direkte Idee mehr,

Aber wieso möchtest du nun 32 Byte lesen, Zeile 18?

Was ich auch nicht ganz verstehe, in der Read Routine schreibst du zuvor ein 0x00.

Ich dachte erst es ist eine Registeradresse, die du setzen musst, aber ich habe ins Datenblatt geschaut du musst ja einfach nur die Adresse+R senden und das Byte lesen.
Das wäre der untere READ Block mit Bufferlänge 1 Byte.
 
Hallo Dirk
habe noch weiter gesucht und im Code einiges getestet. Dabei ist mir was aufgefallen. Konnte es leider mit den Angaben zu ASF von Atmel nicht klären.
Verwende die Adresse 0x21, ist sind 7 Bit. Nach dem Datenblatt des Herstellers wird mit letzten Bit angegeben ob geschrieben oder gelesen wird. Schreibe ich die 0x21 ( 010 000 1 ) mit einem zusätzlichen Bit zum lesen/schreiben als 010 000 1 0 so ergibt das 0x42 bzw 0x43. Diese Angabe habe ich sonst immer bei den AVR verwendet. Gebe ich die 0x42 zum schreiben und die 0x43 zum lesen ein, so geht es nicht. Könnte es sein, das die Adresse falsch ist bzw nicht auf lesen schaltet (7 Bit oder 8 Bit)?
achim
 
Du hattest ja schon einmal erfolgreich einen Output gesetzt und dadurch eine LED angesteuert.

Dafür hattest du eine 7bit Adresse angegeben, keine 8bit Read- oder Write-Adresse.

Code:
A2   A1   A0   7bit Adresse
L    L    L    0x20     
L    L    H    0x21
L    H    L    0x22
...
H    H    H    0x27

Aus der ASF Dokumentation ...
Address Packets
The slave address consists of seven bits. The 8th bit in the transfer determines the data direction (read or write). An address packet always succeeds a Start or Repeated Start condition. The 8th bit is handled in the driver, and the user will only have to provide the 7-bit address.

Gebe ich die 0x42 zum schreiben und die 0x43 zum lesen ein, so geht es nicht.
Da die Adresse als 7bit Adresse interpretiert wird, stimmt diese nicht. Dadurch fühlt sich der Slave nicht angesprochen.
 
Hallo Dirk
habe diese Tabelle im Datenblatt gefunden. Es stimmt, konnte bereits LEDs ansteuern auch unter verschiedenen Adressen, z.B. 0x21 und 0x22. Wenn das die Schreibadresse ist, wie ist die Leseadresse dazu?
Adressen 2.png
achim
 
Die 0x21 zum Beispiel ist keine Schreib-Adresse, hier fehlt das R/nW Bit.

Es gibt eine Funktion für Write und eine Funktion für Read.
i2c_master_write_packet_wait()
i2c_master_read_packet_wait()
Das ASF managed das R/nW Bit, Bit0.

Es gibt je Device nur eine I2C Slave Adresse, egal ob du Schreiben oder Lesen möchtest
 
Hallo Dirk
habe in der Datei i2c-master.h das folgende Stück Code gefunden:


CodeBox C
enum i2c_master_interrupt_flag {
   /** Interrupt flag used for write */
   I2C_MASTER_INTERRUPT_WRITE = 0,
   /** Interrupt flag used for read */
   I2C_MASTER_INTERRUPT_READ  = 1,
};

Muss das nicht eingebunden werden? z.B. hier:


CodeBox C
void configure_i2c(void)  // ok configuraton SERCOM 2 als I2C-Master
  {
   struct i2c_master_config config_i2c_master;                   // ok generate the configure-struct
   i2c_master_get_config_defaults(&config_i2c_master);           // ok get the defaults
   config_i2c_master.pinmux_pad0 = PINMUX_PA08C_SERCOM0_PAD0;   // PA08 SDA
   config_i2c_master.pinmux_pad1 = PINMUX_PA09C_SERCOM0_PAD1;   // PA09 SCL
   config_i2c_master.baud_rate = 100;                           // Setzt Baudrate auf 100kHz
   while(i2c_master_init(&i2c_master_instance, SERCOM0, &config_i2c_master) != STATUS_OK);  //initialization
   i2c_master_enable(&i2c_master_instance);                   // I2C interface einschalten
  }

achim
 
Hallo Achim.

es ist nur eine Definition der Interruptflags, das muss nicht eingebunden werden, bzw. ist ja schon bekannt durch das Einbinden von asf.h

Außerdem nutzt du ja I2C APIs mit Polling, nicht mit Interrupt.

Wenn es immer noch nicht funktioniert, poste noch mal den kompletten aktuellen Code.
(Du hast wahrscheinlich alles Wichtige in main.c, dann reicht diese Datei)

Das mit dem Display am Portexpander hat ja auch funktioniert, da ist übrigends auch ein READ im Protokoll,
also grundsätzlich funktioniert es ja.
 
Hallo Dirk
habe (wie du vermutest) alles in einer Datei. Erst wenn alles funktioniert wird es getrennt. Ansonsten verwende ich die Teile vom ASF. Einige Teile sind nocg drin aber auskommentiert. Vielleicht siehsz du was.
achim
 

Anhänge

  • main.c
    5,3 KB · Aufrufe: 3
Hallo Achim,

ich hatte noch einen Fehler gefunden. Das korrigierte Programm habe ich angehängt.

Den ersten Block in read_data() verstehe ich nicht ganz. Du schreibst hier ein Byte 0x00 zum zweiten Slave. Ist das eine Initialisierung und notwendig um Taster abzufragen?
Ich müsste das Datenblatt anschauen, mir fehlt gerade die Zeit.

In diesen Write-Block überschreibst du auch
i2c_write_buffer_a[0] = 0;
Der buffer wird auch noch woanders verwendet. Das nur als Hinweis um weitere Fehler zu vermeiden.

Da du eigentlich immer nur ein Byte schreibst oder liest, könnte man auch Funktionen verwenden die nur ein Byte übertragen und kein packet übertragen.
Teste aber erst mal so, sonst hat man wieder eine neue "Baustelle" ;)

Dirk :ciao:
 

Anhänge

  • main.c
    5,4 KB · Aufrufe: 3
Hallo Dirk
habe das Programm geladen und gestartet. Es läuft jetzt durch den Teilcode mit Read durch. und die Kontroll LED blinkt. Es erfolgt aber keine Auswertung der Tasten. Nehme ich das (!) weg, blinkt es auch nicht mehr.
achim
 
Wie hast du den oder die Taster an den Portexpander angeschlossen?

Wenn der Taster betätigt wird, sollte eine "0" an der entsprechenden Bitposition zurück kommen?
 
Sorry, da ist mir was eingefallen. Das lesen des PCF8574 geht so, das erst alle Pins auf H gesetzt werden und dann die änderung gelesen wird.
 
Sorry, da ist mir was eingefallen. Das lesen des PCF8574 geht so, das erst alle Pins auf H gesetzt werden und dann die änderung gelesen wird.

Ja, das wäre die Erklärung, warum immer eine 0 gelesen wird und die Bedingung in der if-Abfrage somit immer wahr ist (Kontroll-LED toggelt).

Eine 0xFF musst du aber bestimmt nur einmalig schreiben.

Dirk :ciao:


EDIT:
Du brauchst nichts initialisieren, die Ausgänge sind nach poweron schon auf 1.
Auf jedenfall darfst du keine 0 schreiben und das machst du im Moment.
 
Zuletzt bearbeitet:
Hallo Dirk
eine gute Nachricht. Nach der lezten Info von dir mit dem 0xff funktioniert es, noch ein paar Kleinigkeiten dazu. Egal es geht super. Kann jetzt damit anfangen die genauen Tasten und Zeiten zu ermitteln.
Habe es so gefühlte 10 mal alles gelöscht und neu angefangen. Wenn alles fertig ist stelle ich das komplette Projekt wieder ins Netz.
Danke für deine Hilfe und Geduld.
achim
 
Hallo Achim,

super, dass es nun funktioniert :) :cool:

Dann noch viel Spaß beim "basteln" an deinem Projekt. :gamer1:

Dirk :ciao:
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)