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.
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?
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
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
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
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
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
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.
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
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.
Arduino F. schrieb: > Sind in Bank0 keine Register? Doch es sind Register. Wo hast du diese Register denn gefunden? Lg Felix.
Felix N. schrieb: > Wo hast du diese Register denn gefunden? Im Datenblatt. Habs mal kurz überflogen.
Felix N. schrieb: > Wo hast du diese Register denn gefunden? In meinem Datenblatt ab Seite 12. Überschrift "Control Registers"
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.
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
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.
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.
> (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.
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"
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.
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.
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.
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
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
> 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.