Hallo zusammen
schon länger bewegt mich die Idee mir meine eigene netzwerkfähige
Steckdosenleiste zu bauen und habe mir daher den Pollin Bausatzes
AVR-NET-IO gekauft. Nach etwas hin und her läuft das Ding auch mit der
originalen Pollin Firmware, die mich aber nicht wirklich überzeugt. Habe
daher beschlossen selber etwas zusammen zu stellen, Projekte dieser Art
gibt es ja zur genüge.
(siehe http://www.lochraster.org/etherrape/ o.ä.
http://www.mikrocontroller.net/articles/AVR_Net-IO_Bausatz_von_Pollin )
Dabei habe ich festgestellt das die ENC28J60.c und ENC28J60.c bei allen
Projekten die ich gefunden habe ziemlich tief mit anderen Teilen des
Projektes verzahnt ist und ein entsprechender Umbau fast genauso viel
Arbeit wäre wie sie gleich neu zu schreiben. (natürlich in Anlehnung,
niemand erfindet das Rad neu)
Jetzt hänge ich aber schon bei den ersten Grundschritten, dem Ansprechen
per SPI.
Meine spi.c sieht folgendermaßen aus.
1 | void spi_init(void)
| 2 | {
| 3 | unsigned char tmp;
| 4 | /* configure MOSI, SCK, CS lines as outputs */
| 5 | DDRB = _BV(PB5) | _BV(PB7) | _BV(PB4);
| 6 |
| 7 | /* set all CS high (output) */
| 8 | PORTB = _BV(PB4);
| 9 |
| 10 | /* enable spi, set master and clock modes (f/2) */
| 11 | SPCR = _BV(SPE) | _BV(MSTR);
| 12 | SPCR = _BV(SPI2X);
| 13 |
| 14 | tmp = SPSR;
| 15 | tmp = SPDR;
| 16 | }
| 17 |
| 18 | void spi_send(uint8_t data)
| 19 | {
| 20 | UART_send_str("Sende data:",11); //NUR FÜR DEBUG ZWECKE
| 21 | SPDR = data;
| 22 | UART_send_str("Gesende data:",13); //NUR FÜR DEBUG ZWECKE
| 23 | while (!(SPSR & _BV(SPIF)))
| 24 | {
| 25 | UART_send_str("Warte:",6); //NUR FÜR DEBUG ZWECKE
| 26 | UART_send_U8(SPSR); //NUR FÜR DEBUG ZWECKE
| 27 | UART_send_U8(SPIF); //NUR FÜR DEBUG ZWECKE
| 28 | }
| 29 | UART_send_str("Ende:",5);
| 30 | data = SPDR;
| 31 | }
| 32 |
| 33 | uint8_t spi_send_read(uint8_t data)
| 34 | {
| 35 | uint8_t redata;
| 36 | UART_send_str("Sende data:",11); //NUR FÜR DEBUG ZWECKE
| 37 | SPDR = data;
| 38 | UART_send_str("Gesende data:",13); //NUR FÜR DEBUG ZWECKE
| 39 | while (!(SPSR & _BV(SPIF)))
| 40 | {
| 41 | UART_send_str("Warte:",6); //NUR FÜR DEBUG ZWECKE
| 42 | }
| 43 | redata = SPDR;
| 44 | return redata;
| 45 | }
| 46 |
| 47 | void spi_cs_on(void)
| 48 | {
| 49 | SPCR &= ~_BV(PB4);
| 50 | }
| 51 |
| 52 | void spi_cs_off(void)
| 53 | {
| 54 | SPCR |= _BV(PB4);
| 55 | }
|
und wird so benutzt.
1 | int main(void)
| 2 | {
| 3 | uint8_t u_data;
| 4 | UART_init();
| 5 | spi_init();
| 6 | UART_send_str("----Beginne----", 15); //NUR FÜR DEBUG ZWECKE
| 7 |
| 8 | //Read ECON1
| 9 | spi_cs_on();
| 10 | UART_send_str("Sende: 0b00011111", 17); //NUR FÜR DEBUG ZWECKE
| 11 | spi_send(0b00011111);
| 12 | UART_send_str("Empfange: 0b00011111", 20); //NUR FÜR DEBUG ZWECKE
| 13 | u_data = spi_send_read(0b00011111);
| 14 | UART_send_U8(u_data); //NUR FÜR DEBUG ZWECKE
| 15 | ....
| 16 | spi_cs_off();
| 17 | UART_send_str("-ENDE", 5); //NUR FÜR DEBUG ZWECKE
| 18 | return 0;
| 19 | }
|
Die UART geschichte habe ich zur Zeit nur für einen Debug eingebaut.
Das Problem hier bei ist ich komme nie über die erste 1 | while (!(SPSR & _BV(SPIF)));
|
Schleife hinaus. SPIF weigert sich und bleibt beharrlich auf 0b00000111
stehen.
Die ganze Console sieht so aus.....
1 | ----Beginne----
| 2 | Sende: 0b00011111
| 3 | Sende data:
| 4 | Gesende data:
| 5 | Warte:
| 6 | 00000000
| 7 | 00000111
| 8 | Warte:
| 9 | 00000000
| 10 | 00000111
| 11 | Warte:
| 12 | 00000000
| 13 | 00000111
| 14 | Warte:
| 15 | 00000000
| 16 | 00000111
| 17 | ...
| 18 | ..
| 19 | .
|
Wieso??????? Was mache ich falsch?????
Schon mal Danke
Magier
Hallo Philipp,
Schoen, das dir mein Code als Inspiration dient :)
Du hast leider an einer Stelle etwas verschlimmbessert, in spi_init()
setzt du erst ein paar Bits in SPCR, und anschliessend moechtest du
SPI2X im Register SPSR setzen, schreibst den Wert aber in SPCR:
Dein Code: 1 | /* enable spi, set master and clock modes (f/2) */
| 2 | SPCR = _BV(SPE) | _BV(MSTR);
| 3 | SPCR = _BV(SPI2X);
|
Besser ist (achte genau auf die letzte Zeile): 1 | /* enable spi, set master and clock modes (f/2) */
| 2 | SPCR = _BV(SPE) | _BV(MSTR);
| 3 | SPSR = _BV(SPI2X);
|
Dein Code fuehrt dazu, dass du die SPI-Schnittstelle effektiv direkt
wieder abschaltest ;)
Kennst du eigentlich das ethersex-Projekt? -> http://www.ethersex.de
Gruss,
- Alexander
Hallo Alexander
Ganz herzlichen Danke für deine Fehler-"verschlimmbessert"-Korrektur...
:-) "lustiges Wort"!
Habe das natürlich sofort umgeschrieben, nur das Ergebnis ist nicht so
ganz das was ich erhofft habe.
SPSR wird jetzt 1 aber SPIF bleibt bei 7.
Die Console sagt also folgendes:
1 | ----Beginne----
| 2 | Sende: 0b00011111
| 3 | Sende data:
| 4 | Gesende data:
| 5 | Warte:
| 6 | 00000001
| 7 | 00000111
| 8 | Warte:
| 9 | 00000001
| 10 | 00000111
| 11 | Warte:
| 12 | 00000001
| 13 | 00000111
| 14 | Warte:
| 15 | ...
| 16 | ..
| 17 | .
|
Bist du der Alexander der die ENC28J60 API aus dem Etherrape-Projekt
geschrieben hat?
Muss ja echt mal sagen. RESPEKT... finde ich mega cool, das ist echt nen
Traum.
Und hätte da gleich mal ne Frage direkt zum ENC28J60.
Wo liegt der genau Unterschied zwischen "Write Control" Register
Kommando und dem "Bit Field Set" und "Bit Field Clear" Kommando? Machen
die nicht im Prinzip das selbe?
Mit "Wirte Control" überschreibt man doch ein Byte, wo liegt jetzt der
ganz tiefer Sinn noch ein Kommando für eine OR und NOTAND Anweisung zu
haben? Eigentlich könnte man doch gleich das ganze Byte neu schreiben
oder?
Bedankt und Gruß
Philipp
P.S. Habe ich ganz vergessen. Ja sicher kenne ich das Ethersex Projekt,
habe ich hier auf der Platte, nur hatte ich es auf der Suche nach einer
simplen ENC28J60 Api gelesen und aussortiert, da sie mir nicht
grundlegend anderes als die des Etherrape-Projekt schien.
Hi,
Philipp H. schrieb:
> Habe das natürlich sofort umgeschrieben, nur das Ergebnis ist nicht so
> ganz das was ich erhofft habe.
> SPSR wird jetzt 1 aber SPIF bleibt bei 7.
Uhm, das ist in soweit korrekt, als dass "SPIF" eine Konstante mit dem
Wert 7 ist, da wird sich nichts dran aendern. Diese Konstante (in der
avr-libc definiert) nutzt du ja auch nur, um auf das richtige Bit in
SPSR zuzugreifen.
Welcher Controller ist das eigentlich? ATmega32? Bist du sicher, das du
da den SS-Pin als Ausgang (bzw. mindestens als Eingang mit aktiviertem
Pullup) konfiguriert hast? Wenn nicht, kanns passieren, das der
Controller sich ploetzlich als SPI-Slave angesprochen fuehlt (weil ein
voellig in der Luft haengender CMOS-Input-Pin manchmal Null, manchmal
Eins liest...), und dann in den SPI-Slave-Mode umkippt (wo dann SPIF
garnicht gesetzt wird, hat mich mal zwei Tage gekostet, das zu
debuggen...).
> Die Console sagt also folgendes:
> ----Beginne----
> Sende: 0b00011111
> Sende data:
> Gesende data:
> Warte:
> 00000001
> 00000111
> Warte:
> 00000001
> 00000111
> Warte:
> 00000001
> 00000111
> Warte:
Find ich grad was merkwuerdig, kann ich so nicht nachvollziehen (ausser
der SPIF-Konstante ;)
> Bist du der Alexander der die ENC28J60 API aus dem Etherrape-Projekt
> geschrieben hat?
Ja, bin ich.
> Muss ja echt mal sagen. RESPEKT... finde ich mega cool, das ist echt nen
> Traum.
Uhm, was meinst du? Du findest die Api gut durchdacht, oder wie? Aber
danke fuer die Lorbeeren ;)
> Und hätte da gleich mal ne Frage direkt zum ENC28J60.
> Wo liegt der genau Unterschied zwischen "Write Control" Register
> Kommando und dem "Bit Field Set" und "Bit Field Clear" Kommando? Machen
> die nicht im Prinzip das selbe?
> Mit "Wirte Control" überschreibt man doch ein Byte, wo liegt jetzt der
> ganz tiefer Sinn noch ein Kommando für eine OR und NOTAND Anweisung zu
> haben? Eigentlich könnte man doch gleich das ganze Byte neu schreiben
> oder?
Klar koennte man das. Der Unterschied ist, dass man mit
write_control_register einen Wert in einem Register nur veraendern kann,
wenn man das in drei Schritten (read-modify-write) macht. Bei manchen
Registern (zb. fuer die Interrupt-Flags) koennen sich dazwischen Bits
veraendern, die der enc28j60 dann selber setzt, zb. bei einem gerade
aufgetretenen Interrupt. Tritt das NACH dem Lesen, aber VOR dem
Schreiben des Registerwerts ein, geht der neue Wert verloren.
Deshalb gibts, speziell zum Setzen und Ruecksetzen von einzelnen Flags
(zb. Interrupt-Flags) das bit_field_set() und bit_field_clear(), die
aendern atomisch (also in einem Zug) nur die angegebenen Bits, und alles
andere bleibt unangetastet.
> P.S. Habe ich ganz vergessen. Ja sicher kenne ich das Ethersex Projekt,
> habe ich hier auf der Platte, nur hatte ich es auf der Suche nach einer
> simplen ENC28J60 Api gelesen und aussortiert, da sie mir nicht
> grundlegend anderes als die des Etherrape-Projekt schien.
Stimmt. Ethersex ist ein (sehr viel weiter fortgeschrittener) Fork
meiner originalen Firmware fuer das etherrape. GPL ist toll :)
Gruss,
- Alexander
Hallo
Ja ich benutze einen ATmega32, allerdings nicht den mitgelieferten von
Pollin, der hatte nämlich nen Schuss weg und fehlerhafte Flashzellen.
Also so weit ich das begreife sollte der SS-Pin als Ausgang geschaltet
sein..
1 | void spi_init(void)
| 2 | {
| 3 | unsigned char tmp;
| 4 | /* configure MOSI, SCK, CS lines as outputs */
| 5 | DDRB = _BV(PB5) | _BV(PB7) | _BV(PB4);
| 6 |
| 7 | /* set all CS high (output) */
| 8 | PORTB = _BV(PB4);
|
Und nach meinem Datasheet sollte PB4 SS oder CS sein. Das SPIF ne
Konstante ist war mir nicht bewusst... betreibe das Projekt um mir
selber was beizubringen und habe das Datenblatt des ATmega nicht
wirklich Zeile für Zeile gelesen... werde ich aber nachholen, sonst
laufe ich dauernd in solche Fallen.
Naja die Lorbeeren sind für das ganze Projekt, das aus einer Idee mal so
was werden kann finde ich gut und erstrebenswert. Deine ENC28J60 API ist
bestimmt ganz toll, auf sehr wenig Speicherplatz getrimmt, als nicht so
geschulter C Benutzer fehlt mir da etwas das Wissen um die Details zu
verstehen.
Ich für mein Projekt brauche aber sehr sehr vieles von dem was im
Etherrape oder Ethersex Projekt mit eingebaut ist aber nicht. Meine
Kiste soll in ein eigenes Sub-Netz und nur mit einem zentralen Server
reden und sonst auch mit keinem, Http ist schon viel zu hoch gegriffen.
UDP ist mein erstes Ziel das ich ansteuere. Der zweite Grund ist das
mich das Interesse antreibt genau zu verstehen wie "es" geht und nicht
nur mal den Quell-Code gelesen zu haben.
Darf ich mal fragen wie lange es so in etwa gedauert hat vom ersten
lesen des ENC28J60 Datasheets bis du die erste stabile Version eines
Treibers hattest?
Habe dich übrigens auf meiner erste Recherche im Netz in einem Video von
23rd Chaos Communication Congress gesehen, nachdem ich mir gedacht habe.
"Hey das klingt gut, so was versuchst du auch mal."
Danke für deine Hilfe
Philipp
HA-------HABE-ES--------------!!!!!!!!!!!!!!!!!!!!!
Habe was rumprobiert und siehe da der Fehler lag wirklich im CS!!!!!!!
Habe das ein und ausschalten des CS Pins verwechselt.
1 | void spi_cs_off(void)
| 2 | {
| 3 | SPCR &= ~_BV(PB4);
| 4 | }
| 5 |
| 6 | void spi_cs_on(void)
| 7 | {
| 8 | SPCR |= _BV(PB4);
| 9 | }
|
Ist die richtige Version!!!!! ARGGGGGG...... (da sieht man den Wald vor
lauter Bäumen nicht)!!!!!!!!!!
Trotzdem DANKE, jetzt läuft mein Testprogramm ganz durch!!!!!!!!
Grüße Philipp
Und so soll das jetzt funktionieren? Das bezweifle ich doch ganz stark.
Statt des SPCR gehört da PORTB hin. Und die High/Low-Logik war in der
ersten Version richtig, und ist jetzt falsch.
Hi,
Philipp H. schrieb:
> Darf ich mal fragen wie lange es so in etwa gedauert hat vom ersten
> lesen des ENC28J60 Datasheets bis du die erste stabile Version eines
> Treibers hattest?
Puh, die erste Version eines Treibers bereits nach ein paar Tagen, da
hatten anderen auch schon vorgearbeitet, ich hab das nur nochmal
"sauber" implementiert. Bis das stabil war, dauerte aber noch etwas
laenger (der enc28j60 hat auch ein paar sehr nervige Bugs, auf die man
dann im Treiber eingehen muss, schau mal in die Errata...)
Stefan Ernst schrieb:
> Und so soll das jetzt funktionieren? Das bezweifle ich doch ganz stark.
> Statt des SPCR gehört da PORTB hin. Und die High/Low-Logik war in der
> ersten Version richtig, und ist jetzt falsch.
Korrekt. Philipp, waer besser wenn du das auch korrigierst ;)
Grus,
- Alexander
Stefan Ernst schrieb:
> Und so soll das jetzt funktionieren? Das bezweifle ich doch ganz stark.
> Statt des SPCR gehört da PORTB hin. Und die High/Low-Logik war in der
> ersten Version richtig, und ist jetzt falsch.
Ja du hast recht......
Danke
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|