Forum: Mikrocontroller und Digitale Elektronik enc28j60 kann Adresse für die Bank Registers nicht finden im Datenblatt


von Felix N. (felix_n888)


Lesenswert?

Hallo µC Community,

Ich nutze denn ENC28J60 Ethernet Controller schon etwas länger. Und 
wollte nun ganz gerne mal so ein bisschen das Datenblatt und die 
Kommandos verstehen. Dazu habe ich mir das Datenblatt zur Hand genommen. 
Und gleichzeitig in meine Library geschaut, die denn ENC ansteuert. Und 
die Entsprechend Werte die in der Library sind aus dem Datenblatt zu 
entnehmen.

Naja, leider klappt das nicht ganz.

Zb. der Command EPMM0 steht in der ersten Bank des Enc28J60 und hat die 
Adresse 0x08. Dieses habe im Datenblatt in "TABLE 3-1" wiedergefunden. 
Jedoch steht in meiner Library "#define EPMM0 (0x08 | 0x20)" die 0x08 
habe ich ja schon gefunden. Aber 0x20 kann ich nirgendwo finden. Ich 
gehe davon aus das es dabei um die Adresse der ersten Bank handelt. 
Jedoch wo finde ich dieses Adresse?

Lg Felix.

von Einer K. (Gast)


Lesenswert?

Felix N. schrieb:
> 0x08 habe ich ja schon gefunden. Aber 0x20 kann ich nirgendwo finden.
Ich kenne den ENC nicht, weiß aber dass (0x08 | 0x20) 0x28 ergibt.
Einwände?

von spess53 (Gast)


Lesenswert?

HI

>Ich nutze denn ENC28J60 Ethernet Controller schon etwas länger. Und
>wollte nun ganz gerne mal so ein bisschen das Datenblatt und die
>Kommandos verstehen.

Merkwürdige Reihenfolge. Eigentlich fängt man erst mit dem Datenblatt. 
Aber das scheint in der C&P-Generation anders zu sein.

MfG Spess

von Einer K. (Gast)


Lesenswert?

spess53 schrieb:
> Merkwürdige Reihenfolge. Eigentlich fängt man erst mit dem Datenblatt.
> Aber das scheint in der C&P-Generation anders zu sein.

Als wenn Kinder erst Fahrrad fahren lernen dürften, wenn sie die 
Fahrphysik vollständig durchdrungen haben.
Nee...
Das wird erst Zeit, wenn es sich um die letzten Zehntel bei den 
Rundenzeiten dreht.


Datenblatt lesen ist richtig und gut. Mir ist völlig unverständlich, wie 
man sich darüber beschweren kann.

Einen Spruch: "Besser spät als nie!"
Den würde ich ja verstehen.
Aber ein "runtermachen" obwohl der "richtige" Weg gerade begonnen wurde, 
zeugt von einer neurotischen Fehlanpassung.
 ohne Gewähr 

von Felix N. (felix_n888)


Lesenswert?

spess53 schrieb:
> Merkwürdige Reihenfolge. Eigentlich fängt man erst mit dem Datenblatt.
> Aber das scheint in der C&P-Generation anders zu sein.

Ja eigentlich liest man dieses erst.

Damals wollte ich auch nur denn Chip zum Laufen zu bringen. Ohne es 
wirklich zu verstehen. Nun möchte ich gerne es aber wissen. Deswegen 
habe ich mir das Datenblatt zur Hand genommen.

Zu spät kann es meiner Meinung nach dafür ja nie sein.

Arduino F. schrieb:
> Ich kenne den ENC nicht, weiß aber dass (0x08 | 0x20) 0x28 ergibt.

Ja, wo weit wahr ich auch. Kann aber zu 0x28 auch nix im Datenblatt 
finden.

Lg Felix

von Einer K. (Gast)


Lesenswert?

Felix N. schrieb:
> Ja, wo weit wahr ich auch. Kann aber zu 0x28 auch nix im Datenblatt
> finden.

Das ist auch der falsche Ort!
Suche in der Datei, wo du es gefunden hast.
Und du wirst feststellen, dass Bank und Register Adresse zu einem Byte 
kombiniert werden. In den Zugriffsmethoden wird das Byte, unter 
zuhilfenahme von Masken usw.,  dann wieder aufgedröselt.

Das ist der einfache Grund dafür, warum der Hersteller diesen Umstand 
nicht in die Doku aufnehmen konnte.
Ein Programmiertrick ist keine Eigenschaft des Bausteins

von Felix N. (felix_n888)


Lesenswert?

Arduino F. schrieb:
> Und du wirst feststellen, dass Bank und Register Adresse zu einem Byte
> kombiniert werden

Stimmt. Es gibt ein Makro der sich BANK_MASK heißt und denn Wert 0x60 
hat. Dann gibt es eine Funktion die nennt sich enc28j60SetBank und in 
der findet man das hier:

(address & BANK_MASK)

Die Adresse von EPMM0 ist 0x08 und 0x20 zusammen 0x28.
In Binär: 0010 1000(0x28)
Wenn ich dann 0x60 auch in Binär umrechnen kommt: 0110 0000 raus. Es 
handelt sich ja um ein UND Bitweiser

    0110 0000
AND 0010 1000
    ---------
    0010 0000 -> in Hex 0x20

Wenn ich mich nicht verrechnet haben sollte. Also kommt die 0x20 aus der 
Maske

Lg Felix

von Einer K. (Gast)


Lesenswert?

Ja.
Felix N. schrieb:
> (address & BANK_MASK)
Lässt nur die gesetzten Bank Adressbits übrig.

Die Lib wird sich irgendwo die gerade gesetzte Bank merken, und erst 
wenn nötig den nächsten Bankswitch machen.

von Felix N. (felix_n888)


Lesenswert?

Arduino F. schrieb:
> Die Lib wird sich irgendwo die gerade gesetzte Bank merken, und erst
> wenn nötig den nächsten Bankswitch machen.

Die Funktion sieht so aus:
1
        // set the bank (if needed)
2
        if((address & BANK_MASK) != Enc28j60Bank)
3
        {
4
                // set the bank
5
                enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
6
                enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
7
                Enc28j60Bank = (address & BANK_MASK);
8
        }

Naja, ich sag mal so wenn ich jetzt die 0x20 nicht kenne. Und nur die 
0x08 habe dann wurde bei der Funktion 0x00 raus kommen. Da es keine 
doppel eins in der UND Funktion gäb. Somit würde das schon nicht mehr 
funktionieren. Also weis ich immer noch nicht wirklich woher die 0x20 
kommt.

Lg Felix.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Felix N. schrieb:
> Naja, ich sag mal so wenn ich jetzt die 0x20 nicht kenne. Und nur die
> 0x08 habe dann wurde bei der Funktion 0x00 raus kommen. Da es keine
> doppel eines in der UND Funktion gäb. Somit würde das schon nicht mehr
> funktionieren.

0x00 ist Bank0
Sind in Bank0 keine Register?

0x20 ist Bank1
0x40 ist Bank2
0x60 ist Bank3


Ein erfolgreicher Registerzugriff benötigt die richtige Bank und die 
Register Adresse.

Und dein enc28j60SetBank() tut genau das, was es soll!
Es schaltet die Bank um! Und das nur, wenn nötig.
Dagegen gibts nichts zu sagen.
Das lässt auch keinerlei Interpretationsspielraum, oder gar 
Unklarheiten, zu.

von Felix N. (felix_n888)


Lesenswert?

Arduino F. schrieb:
> Sind in Bank0 keine Register?

Doch es sind Register.

Wo hast du diese Register denn gefunden?

Lg Felix.

von Einer K. (Gast)


Lesenswert?

Felix N. schrieb:
> Wo hast du diese Register denn gefunden?

Im Datenblatt.
Habs mal kurz überflogen.

von Georg G. (df2au)


Lesenswert?

Felix N. schrieb:
> Wo hast du diese Register denn gefunden?

In meinem Datenblatt ab Seite 12. Überschrift "Control Registers"

von Felix N. (felix_n888)


Lesenswert?

Georg G. schrieb:
> In meinem Datenblatt ab Seite 12. Überschrift "Control Registers"

Ab Seite 13 kommt bei mir Control Registers. Davon steht "Notes:" und 
der Rest der Seite ist weiß.

Entweder bin ich einfach blind. Oder es steht in meinen Datenblatt nicht 
drin. Das einzige was ist finde mit Bank ist "FIGURE 3-1" und im 
Register ECON1 BSEL1 und BSEL0.

Lg Felix.

von Georg G. (df2au)


Lesenswert?

Felix N. schrieb:
> Oder es steht in meinen Datenblatt nicht

Ich habe eine Version von Microchip, 2006, "Preliminary", 910kB
Wenn du die Version hier auf der Webseite nimmst, ist es ab Seite 14 zu 
finden.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Felix N. schrieb:
> Das einzige was ist finde mit Bank ist "FIGURE 3-1" und im
> Register ECON1 BSEL1 und BSEL0.

Richtig!
Das sind die Beiden Bits!

> (address & BANK_MASK)>>5)
Da werden die Bits selektiert und an die richtige Position geschoben.
Und dann ins ECON1 geschrieben.
Und fertig ist die Magie, die Bank ist selektiert.

Felix N. schrieb:
> Entweder bin ich einfach blind. Oder es steht in meinen Datenblatt nicht
> drin.
Du hast das eigentlich schon richtig gefunden.
Nur nicht erkannt.

von Felix N. (felix_n888)


Lesenswert?

Arduino F. schrieb:
> Das sind die Beiden Bits!

Arduino F. schrieb:
> 0x00 ist Bank0
> Sind in Bank0 keine Register?
>
> 0x20 ist Bank1
> 0x40 ist Bank2
> 0x60 ist Bank3

Du sagst ja selbst schon welche Adressen die Banken haben. Wenn man im 
ECON1 Register schaut bei denn BSEL1 und 0 Bit. Dann steht dort ja 
drunter welche welche binär Code für welche Bank:

"00 = SPI accesses registers in Bank 0"

Okay. 00 entspricht ja 0000 0000 = 0x00.

"01 = SPI accesses registers in Bank 1"

01 entspricht doch eigentlich 0000 0001 = 0x01 oder vertut ich mich da 
mit dem Lesen und es entspricht eigentlich 0010 0000 dann wäre es ja 
0x20. Da bin ich mir jetzt nicht mehr ganz sich ob ich das von rechtes 
nach linkes oder umgekehrt lesen muss. Binär ist bei mir schon etwas 
länger her.

Lg Felix.

von Einer K. (Gast)


Lesenswert?

> (address & BANK_MASK)>>5)

Es sei:
address = (0x08|0x20);
BANK_MASK = 0x60;

Es ist:
address = 0x28;

((address & BANK_MASK)>>5)
Wird zu:
((0x28 & 0x60)>>5)
Wird zu:
(0x20>>5)
Wird zu:
0x01


Und fertig ist die Magie, die Bits sind an der richtigen Position.

Tipp:
Das ist nur solange Magie, bis man die Sprache gelernt hat.

von eProfi (Gast)


Lesenswert?

1
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1,(ECON1_BSEL1|ECON1_BSEL0));
2
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
Das ist nicht optimal, weil es sein kann, dass z.B. nur Bits gesetzt 
werden müssen, dann kann man sich das Löschen mit BIT_FIELD_CLR sparen.
Und umgekehrt: Beitrag "Re: enc 28 j 60 bankwechsel geht nicht"
Im Linux-Treiber ist diese Idee genial einfach gelöst.

Außerdem braucht man bei Addressen größer xB?? die Bankselect-Bits nicht 
setzen, da diese Register aus allen Bänken ansprechbar sind.

Beachte auch den korrekten Wert für das PHLCON-Register.
Beitrag "ENC28J60 correct value of PHLCON and mirrored registers"

von Einer K. (Gast)


Lesenswert?

eProfi schrieb:
> Außerdem braucht man bei Addressen größer xB?? die Bankselect-Bits nicht
> setzen, da diese Register aus allen Bänken ansprechbar sind.
>
> Beachte auch den korrekten Wert für das PHLCON-Register.
> Beitrag "ENC28J60 correct value of PHLCON and mirrored registers"

Leider sagt unser Felix nicht, welchen Code er da verwendet.
Also kann man nicht sagen, ob dieses nicht doch schon richtig gemacht 
wird.

Zumindest ich nicht.

von Felix N. (felix_n888)


Lesenswert?

Arduino F. schrieb:
> Und fertig ist die Magie, die Bits sind an der richtigen Position

Hallo Arduino F.

Danke dir das du mir das (address & BANK_MASK)>>5) erklärt hast. Ob du 
es glaubst oder nicht ein bisschen kann ich auch Bitmanipulation, Hex 
und Binär Zahlen. Nur halt nicht so gut das es aus dem FF kommt.

Mir ging es ja nicht um die Funktion mit dem (address & BANK_MASK)>>5) 
sondern wo ich die Bank Adressen im Datenblatt finde. Du hattest selbst 
ja schon gesagt das ich die Bits richtig gefunden habe, nur nicht 
erkannt habe(BSEL1:0).

Im Datenblatt steht ja:
BSEL1:BSEL0: Bank Select bits
11 = SPI accesses registers in Bank 3
10 = SPI accesses registers in Bank 2
01 = SPI accesses registers in Bank 1
00 = SPI accesses registers in Bank 0

Die Zahlen die am Anfang stehen sind ja Binär Codes. 0000 0000 ist 0x00 
für Bank 0. 0010 0000 ist ja 0x20. Ich wahr mir jetzt nur nicht mehr 
sicher von welcher Seite ich die Codes lesen muss also ob die 01 jetzt 
ganz links hin kommt(0000 0001) oder man rechtes anfängt(0010 0000).

Bzw. habe ich Bank Registers erst gar nicht gefunden.

Arduino F. schrieb:
> Leider sagt unser Felix nicht, welchen Code er da verwendet.
> Also kann man nicht sagen, ob dieses nicht doch schon richtig gemacht
> wird.

Die Library kommt von Tuxgraphics: 
http://tuxgraphics.org/electronics/200606/article06061.shtml

Lg Felix.

von Felix N. (felix_n888)


Lesenswert?

Felix N. schrieb:
> Die Zahlen die am Anfang stehen sind ja Binär Codes.

Upps, ich habe da wohl scheinbar was verwechselt. Die Codes geben an wie 
man die BSEL Bits setzten muss um die entsprechende Bank aus zu wählen.
Mein Fehler!

eProfi schrieb:
> Das ist nicht optimal, weil es sein kann, dass z.B. nur Bits gesetzt
> werden müssen, dann kann man sich das Löschen mit BIT_FIELD_CLR sparen.

Mal so eine Frage. Du schriebst in denn anderen Thread ja "ich verwende 
den BitSet - bzw. BitClr -Befehl nur, wenn nötig." tut die Funktion im 
Prinzip nicht das gleich mit "if((address & BANK_MASK) != Enc28j60Bank)" 
damit wird doch auch Abgefragt ob die Aktuelle Adresse mit der letzten 
Adresse nicht übereinstimmt falls ja wird die neue gesetzt. Bei gleicher 
Adresse trifft die Abfrage doch gar nicht oder?

eProfi schrieb:
> Außerdem braucht man bei Addressen größer xB??

Was meinst du damit??

eProfi schrieb:
> Beachte auch den korrekten Wert für das PHLCON-Register.

Ohh ja, bei mir wurde der falsche Wert rein geschrieben. Habe ich 
geändert. Kannst du mir eventuell auch erklären warum gerade der andere 
Wert falsch ist?

Lg Felix.

von eProfi (Gast)


Lesenswert?

Schau Dir diesen Code an:
https://github.com/nishad/kobohacks/blob/master/u-boot/drivers/net/enc28j60.c
>> Außerdem braucht man bei Addressen größer xB??
> Was meinst du damit??
/* these are common in all banks */
#define CTL_REG_EIE   0x1B
#define CTL_REG_EIR   0x1C
#define CTL_REG_ESTAT   0x1D
#define CTL_REG_ECON2   0x1E
#define CTL_REG_ECON1   0x1F


und hier das vorbildliche Bank-Select:
http://git.ti.com/ti-linux-kernel/ti-linux-kernel/blobs/7dac6f8df607929e51f4fd598d80bd009c45a9f8/drivers/net/enc28j60.c
1
//select the current register bank if necessary
2
static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr){
3
  if ((addr & BANK_MASK) != priv->bank) {
4
    u8 b = (addr & BANK_MASK) >> 5;
5
    if (b != (ECON1_BSEL1 | ECON1_BSEL0))
6
      spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,ECON1_BSEL1 | EC1ON1_BSEL0);
7
    if (b != 0)spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b);
8
    priv->bank = (addr & BANK_MASK);
9
  }
10
}

hier ähnlich:
http://lists.infradead.org/pipermail/barebox/2014-June/019396.html

von Felix N. (felix_n888)


Lesenswert?

eProfi schrieb:
> /* these are common in all banks */
> #define CTL_REG_EIE   0x1B
> #define CTL_REG_EIR   0x1C
> #define CTL_REG_ESTAT   0x1D
> #define CTL_REG_ECON2   0x1E
> #define CTL_REG_ECON1   0x1F

Hi, danke für deine Antwort.

Ja die Register habe ich auch gefunden.

Ich glaube das ich ein Beitrag von Arduino Fanboy falsch verstanden 
habe. Er schrieb ja

Arduino F. schrieb:
> Sind in Bank0 keine Register?

Dabei habe ich die ganze Zeit unter "Control Registers" nach einer 
Adresse für Bank0,1,2,3 gesucht. Die stehen ja dort auch nicht. Sondern 
im ECON1 Register.

Mit der Bank Maske, Bitschifting und Bitweisern wird die Adresse 
entsprechend auf die Bank umgeschrieben. Und dann beim setbank gesetzt.

Doch woher weis man als Programmier z.b der von der Library das man bei
allen Registern die in der Bank 1 stehen noch das 0x20 davor setzten 
muss, um sie am ende wieder mit helfe der Maske auflösen und so richtig 
aufzulösen?

Also z.b "#define EPMM0 (0x08|0x20)" und nicht nur "#define EPMM0 
(0x08)".

Woher kommt die 0x20. Was wahr eigentlich meine Frage warum ich das 
Thema erstellt habe.

eProfi schrieb:
> und hier das vorbildliche Bank-Select:

vielen dank. Werde es nachher mal umsetzten und schauen ob es geht.

Lg Felix

von eProfi (Gast)


Lesenswert?

>  tut die Funktion im Prinzip nicht das gleich mit
> "if((address & BANK_MASK) != Enc28j60Bank)" damit wird doch auch
> Abgefragt ob die Aktuelle Adresse mit der letzten Adresse
> nicht übereinstimmt falls ja wird die neue gesetzt.
Das stimmt, ist aber nur ein Teilaspekt.
Dummerweise kann man die Banksel-Bits nicht direkt beschreiben, sondern 
nur getrennt setzen und löschen. dh. man braucht ggf. zwei Befehle.
In bestimmten Fällen, nämlich wenn nur Bit(s) gesetzt bzw. gelöscht 
werden müssen, reicht jedoch ein Befehl. Das spart ein wenig Zeit.


> Woher kommt die 0x20. Was wahr eigentlich meine Frage warum
> ich das Thema erstellt habe.
Ganz einfach: für die 32 Registeradressen braucht man 5 Bits.
Ein schlauer Programmierer hat sich gedacht: warum nicht 2 der 3 
verbleibenden Bits für die Banknummer nutzen?

Genauso gut hätte man ein zweites Array für die Bank anlegen können.
Vorteil : schneller, da die Shifts und Masks wegfallen
Nachteil: mehr Speicherverbrauch
Muss man selbst abwägen. Bei den modernen µC spielt Flash kaum mehr eine 
Rolle, sodass man ruhig Variante 2 verwenden kann.

Die oben von mir vorbildlich genannte Version ist soo toll auch nicht.
Sie nutzt nur, dass man bei Bank 3 nichts löschen braucht und bei Bank 0 
nichts setzen.
Schau dir meine Version mit der 16fach-Switch-case Variante an.
Die ist optimal. Lies den ganzen Thread durch.

Wenn's noch schneller gehen soll und man sicher weiß, was im Banksel 
steht, kann man ja die set- und clr-Befehle direkt im Sourcecode 
einsetzen.

von Felix N. (felix_n888)


Lesenswert?

eProfi schrieb:
> Dummerweise kann man die Banksel-Bits nicht direkt beschreiben, sondern
> nur getrennt setzen und löschen. dh. man braucht ggf. zwei Befehle.
> In bestimmten Fällen, nämlich wenn nur Bit(s) gesetzt bzw. gelöscht
> werden müssen, reicht jedoch ein Befehl. Das spart ein wenig Zeit.

Hmm, okay das macht irgendwie Sinn. Ich meine im Datenblatt was von 210 
ns Abstand Zeit zwischen denn Registerschreiben gelesen zu haben. Also 
einen bit mit löschen und setzten wären das 420 ns und bei 2 bits 
löschen/setzten 840 ns? Oder ich tut ich mich da?

eProfi schrieb:
> Ganz einfach: für die 32 Registeradressen braucht man 5 Bits.

Jo, steht ja im Datenblatt drin: "Each bank is 32 bytes long and 
addressed by a 5-bit address value"

eProfi schrieb:
> Ein schlauer Programmierer hat sich gedacht

Ich denke dazu gehöre ich im Moment wohl nicht.

eProfi schrieb:
> warum nicht 2 der 3
> verbleibenden Bits für die Banknummer nutzen?

Ok. Also wenn 5 Bits für die Adresse benutzt wird. Dann bleiben 3 Bits 
noch übrig.
Gehe ich mal vom Beispiel mit EPMM0 aus dieser hat ja die Adresse 0x08 
was in Binär ja 0000 1000 entspricht. Also sind die eingeklammerten 
Zahlen die Adresse des Registers(0x08): 000(0 1000). Dann bleiben dort 
ja noch die 3 Nullen übrig.

Da es sich ja um die erste Bank handelt in dem das EPMM0 Register steht 
muss im ECON1 Register Bit 0 auf 1 gesetzt werden und Bit 1 auf 0.

Wenn man jetzt für die dritte null 00(0)0 1000 denn Code für die Bank 1 
einsetzt steht dort 0010 1000. 0010 ist 2 und 1000 ist 8 ergibt 0x28.


Dann gibt es ja die Bank Maske diese hat denn Wert 0x60 entspricht 0110 
0000. Am 6 und am 5 Bit steht in der Maske eine Eins. Die entsprechende 
Bank die gesetzt werden soll steht dann ja am 6 und 5 Bit. Und mit der 
Und Bitweiser "Funktion" wird ja alles zu null wo keine Eins in der 
Maske und dem anderen "Adress Byte" steht. Also bleiben am Ende nur die 
Einsen übrig wo in der Maske und im Adress Byte eine Eins stand. In 
diesem Fall würde bei 0010 0000 0x20 rauskommen.

0010 1000 Adresse mit Bank
0011 0000 Maske

----------    UND

0010 0000 -> 0x20

Also könnte man vom Prinzip her anstatt (0x08 | 0x20) auch direkt 0x28 
schreiben oder nicht?

eProfi schrieb:
> Schau dir meine Version mit der 16fach-Switch-case Variante an.

Werde ich gleich auch noch ausprobieren

eProfi schrieb:
> Wenn's noch schneller gehen soll und man sicher weiß, was im Banksel
> steht, kann man ja die set- und clr-Befehle direkt im Sourcecode
> einsetzen.

Nöö, würde ich mir nicht zutrauen.

Lg Felix

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.