Forum: Mikrocontroller und Digitale Elektronik enc 28 j 60 bankwechsel geht nicht


von Sonke A. (soeni)


Lesenswert?

Hallo, ich habe ein kleines Problem und zwar wollte ich eein enc 28 j 60 
lan chip benutzen. Schaltung ist fertig, nun ging es um die 
Treiberschicht für den chip.

atmega 128 <= SPI => enc 28 j 60

erstes initialisieren klappt, nach Reset ist er bereit. status lässt 
sich prima auslesen. dann alles in bank 0 setzen und verifizieren (hier 
erstmal nur probeweise mit einem Register) geht auch prima.

nun soll ein register einer anderen bank beschrieben werden.

der bankwechsel wird korrekt erkannt, d.h. aus der adresse wird 
richtigerweise extrahiert, das zur bank 2 oder 3 gewechselt werden muss. 
leider klapp das jedoch nicht, irgendwie wird der wechsel nicht gesetzt 
und das schrieben und oder lesen geht in die Hose.

hier mal der code:
1
#include "../main.h"
2
#include "lanDriver.h"
3
4
typedef struct enc{
5
6
  volatile unsigned char   current_bank;
7
  volatile unsigned int    next_packet_ptr;
8
  unsigned char       revision;
9
10
}enc28j60_t;
11
12
char initSequence[] = {
13
  // Address,   Value
14
    //setup bank0 (config stored in progmem, see above)
15
    //tx buffer:
16
    ENC28J60_REG_ETXSTL, lo8(ENC28J60_TX_BUFFER_START), //start lo
17
    ENC28J60_REG_ETXSTH, hi8(ENC28J60_TX_BUFFER_START), //start hi
18
    ENC28J60_REG_ETXNDL, lo8(ENC28J60_TX_BUFFER_END  ), //end lo
19
    ENC28J60_REG_ETXNDH, hi8(ENC28J60_TX_BUFFER_END  ), //end hi
20
    //rx buffer
21
    ENC28J60_REG_ERXSTL, lo8(ENC28J60_RX_BUFFER_START), //start lo
22
    ENC28J60_REG_ERXSTH, hi8(ENC28J60_RX_BUFFER_START), //start hi
23
    ENC28J60_REG_ERXNDL, lo8(ENC28J60_RX_BUFFER_END  ), //end lo
24
    ENC28J60_REG_ERXNDH, hi8(ENC28J60_RX_BUFFER_END  ), //end hi
25
    //rx ptr:
26
    //ENC28J60_REG_ERDPTL, lo8(ENC28J60_RX_BUFFER_START+1),
27
    //ENC28J60_REG_ERDPTH, hi8(ENC28J60_RX_BUFFER_START+1),
28
29
    //setup bank2: (see microchip datasheet p.36)
30
    //1.) clear the MARST bit in MACON2.
31
    ENC28J60_REG_MACON2,   0x00,
32
    //2.) mac rx enable, activate pause control frame support
33
    ENC28J60_REG_MACON1,   ((1<<ENC28J60_BIT_MARXEN)|(1<<ENC28J60_BIT_RXPAUS)|(1<<ENC28J60_BIT_TXPAUS)),
34
    //3.) setup MACON3: auto padding of small packets, add crc, enable frame length check:
35
    ENC28J60_REG_MACON3,   ((1<<ENC28J60_BIT_PADCFG0)|(1<<ENC28J60_BIT_TXCRCEN)|(1<<ENC28J60_BIT_FRMLNEN)),
36
    //4.) dont set up MACON4 (use default)
37
    //5.) setup maximum framelenght to 1518:
38
    ENC28J60_REG_MAMXFLL, lo8(1518),
39
    ENC28J60_REG_MAMXFLH, hi8(1518),
40
    //6.) set up back-to-back gap: 0x15 for full duplex / 0x12 for half duplex
41
    ENC28J60_REG_MABBIPG, 0x12, //half duplex
42
    //7.) setup non-back-to-back gap: use 0x12
43
    ENC28J60_REG_MAIPGL,   0x12,
44
    //8.) setup non-back-to-back gap high byte: 0x0C for half duplex:
45
    ENC28J60_REG_MAIPGH,   0x0C, //half duplex
46
    //9.) dont change MACLCON1+2 / MACLCON2 might be changed for networks with long wires !
47
48
    //setup bank3:
49
    //10.) programm mac address: BYTE BACKWARD !
50
    ENC28J60_REG_MAADR5, NIC_MAC0,
51
    ENC28J60_REG_MAADR4, NIC_MAC1,
52
    ENC28J60_REG_MAADR3, NIC_MAC2,
53
    ENC28J60_REG_MAADR2, NIC_MAC3,
54
    ENC28J60_REG_MAADR1, NIC_MAC4,
55
    ENC28J60_REG_MAADR0, NIC_MAC5
56
};
57
58
59
static char read_LAN(char adr);
60
static char write_LAN(char adr, char data);
61
static void select_bank(char bank);
62
static char cmd_LAN(char cmd, char data);
63
static void write_phy_LAN(char adr, unsigned int data);
64
void cmd_write_LAN(char hi, char lo);
65
66
enc28j60_t enc;
67
68
/**
69
 * This function initiates the lan chip
70
 * @return Errorcode LANINIT_
71
 */
72
char init_LAN(){
73
74
  char str[12];
75
  // to force bank update
76
  enc.current_bank=0xff;
77
78
  // Reset ENC 28 J 60
79
  PORTC &=~(1<<LAN_RST);
80
  _delay_ms(10);
81
  // Release
82
  PORTC |=(1<<LAN_RST);
83
84
85
  // Wait for Startup (at least 50 us)
86
  _delay_us(60);
87
  // To prevent bad requests wait again at least 5 ms
88
  _delay_ms(10);
89
90
  sendStringRS232("vor while\r\n");
91
92
  itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
93
  sendStringRS232("Statusregister: 0b");
94
  sendStringRS232(str);
95
  sendStringRS232("\r\n");
96
97
  // Waiting until chip is ready
98
  while(!(read_LAN(ENC28J60_REG_ESTAT) & 0x01)){};
99
100
  sendStringRS232("nach while\r\n");
101
102
  itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
103
  sendStringRS232("Statusregister: 0b");
104
  sendStringRS232(str);
105
  sendStringRS232("\r\n");
106
107
  sendStringRS232("vor for\r\n");
108
109
  /*
110
  for(int i=0; i<(2*22);i += 2){
111
    write_LAN(initSequence[i], initSequence[1+1]);
112
  }
113
  */
114
115
116
117
  write_LAN(ENC28J60_REG_ETXSTL,lo8(ENC28J60_TX_BUFFER_START));
118
119
  itoa((int)read_LAN(ENC28J60_REG_ETXSTL),str,16);
120
  sendStringRS232("\r\nb0 ETXSTL: 0x");
121
  sendStringRS232(str);
122
  sendStringRS232(" sollte 0x00 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
123
124
  write_LAN(ENC28J60_REG_ETXSTH,hi8(ENC28J60_TX_BUFFER_START));
125
126
  itoa((int)read_LAN(ENC28J60_REG_ETXSTH),str,16);
127
  sendStringRS232("\r\nb0 ETXSTH: 0x");
128
  sendStringRS232(str);
129
  sendStringRS232(" sollte 0x1a heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
130
131
132
133
  write_LAN(ENC28J60_REG_MAIPGL,   0x12);
134
135
  itoa((int)read_LAN(ENC28J60_REG_MAIPGL),str,16);
136
  sendStringRS232("\r\nb2 MAIPGL: 0x");
137
  sendStringRS232(str);
138
  sendStringRS232(" sollte 0x12 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
139
140
  write_LAN(ENC28J60_REG_MAADR5, NIC_MAC0);
141
142
  itoa((int)read_LAN(ENC28J60_REG_MAADR5),str,16);
143
  sendStringRS232("\r\nb3 MAADR5: 0x");
144
  sendStringRS232(str);
145
  sendStringRS232(" sollte 0xac heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
146
147
  sendStringRS232("nach for\r\n");
148
149
  //no loop back of transmitted frames
150
  //write_phy_LAN(ENC28J60_PHY_PHCON2, (1<<ENC28J60_BIT_HDLDIS));
151
152
  sendStringRS232("nach loop while\r\n");
153
154
  //enable interrups
155
  //enc28j60_write_address(ENC28J60_REG_EIE, (1<<6)|(1<<7));
156
157
  //enable rx
158
  //enc28j60_write_address(ENC28J60_REG_ECON1, (1<<ENC28J60_BIT_RXEN));
159
  //enc28j60_spi_write_word(ENC28J60_OP_BFS|ENC28J60_REG_ECON1, (1<<ENC28J60_BIT_RXEN));
160
161
  // Set 16 Bit LED Register to configure LEDs
162
  // LEDA: link status, LEDB: RX&TX activity
163
  //write_phy_LAN(ENC28J60_PHY_PHLCON,0x0472);
164
  sendStringRS232("nach led enable\r\n");
165
166
167
168
169
  return LANINIT_FAILD;
170
}
171
172
173
/**
174
 * This function prints out the Errorcodes from Laninit
175
 * @param err Errorcode
176
 */
177
void printLanInitErrors(char err){
178
  switch (err){
179
    case LANINIT_FAILD:{
180
      sendStringRS232("fail (unknown reason)");
181
      break;
182
    }
183
    case LANINIT_SUCCESSFULL:{
184
      sendStringRS232("successfully");
185
      break;
186
    }
187
188
  }
189
190
}
191
192
193
/** PROTECTED
194
 *
195
 *  Reads from the config register
196
 */
197
static char read_LAN(char adr){
198
199
  // Select bank
200
  select_bank(adr);
201
  // Add Command
202
  adr = adr | LAN_RCR;
203
  // read
204
  return cmd_LAN(adr,0);
205
}
206
207
208
/**
209
 * This function writes to the PHY Registers
210
 *
211
 * @param ard   address of the Register
212
 * @param data   data to be write to tha PHY register
213
 *
214
 */
215
static void write_phy_LAN(char adr, unsigned int data){
216
217
  //see microchip datasheet p.21
218
  //set address to MIREGADR:
219
  write_LAN(ENC28J60_REG_MIREGADR,adr);
220
221
  // Send data
222
  write_LAN(ENC28J60_REG_MIWRL, data&0xff);
223
  write_LAN(ENC28J60_REG_MIWRH, data>>8);
224
225
  // wait until phy reg is written
226
227
  char str[12];
228
  sendStringRS232("read phy REG_MISTAT\r\n");
229
  itoa((int)enc.current_bank,str,10);
230
      sendStringRS232("bank: ");
231
      sendStringRS232(str);
232
      sendStringRS232("\r\n");
233
234
  while(read_LAN(ENC28J60_REG_MISTAT) & (1<<ENC28J60_BIT_MISTAT_BUSY))
235
  {
236
237
238
239
240
        _delay_ms(10000);
241
242
        /*
243
    itoa((int)read_LAN(ENC28J60_REG_MISTAT),str,2);
244
    sendStringRS232("Statusregister1: 0b");
245
    sendStringRS232(str);
246
    sendStringRS232("\r\n");
247
248
    itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
249
    sendStringRS232("Statusregister2: 0b");
250
    sendStringRS232(str);
251
    sendStringRS232("\r\n");
252
    _delay_ms(10000);
253
    */
254
  }
255
}
256
257
258
/**
259
 * Writes to the config registers
260
 */
261
static char write_LAN(char adr, char data){
262
263
  // Select bank
264
  select_bank(adr);
265
  // Add Command
266
  adr = adr | LAN_WCR;
267
  // Write
268
  return cmd_LAN(adr,data);
269
}
270
271
272
/**
273
 * Select a bank of config registers
274
 */
275
static void select_bank(char bank){
276
277
  if((bank & 0x60) != enc.current_bank){
278
    sendStringRS232("switch from bank ");
279
280
    char str[12];
281
282
    itoa((int)enc.current_bank>>5,str,10);
283
284
    sendStringRS232(str);
285
286
287
    enc.current_bank = (bank & 0x60);
288
289
    sendStringRS232(" to bank ");
290
291
    itoa((int)enc.current_bank>>5,str,10);
292
293
    sendStringRS232(str);
294
295
    sendStringRS232(" \r\n");
296
297
298
299
    // release old bank select
300
    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),((1<<ENC28J60_BIT_ECON1_BSEL0) | (1<<ENC28J60_BIT_ECON1_BSEL1)));
301
    // Set new one
302
    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),enc.current_bank>>5);
303
304
    char bk = (cmd_LAN((LAN_RCR | ENC28J60_REG_ECON1),0)) & ((1<<ENC28J60_BIT_ECON1_BSEL0) | (1<<ENC28J60_BIT_ECON1_BSEL1));
305
    //(read_LAN(ENC28J60_REG_ECON1)&((1<<ENC28J60_BIT_ECON1_BSEL0) | (1<<ENC28J60_BIT_ECON1_BSEL1)));
306
    if(bk == enc.current_bank>>5){
307
      sendStringRS232("bankset ok ");
308
309
      sendStringRS232("bank ");
310
      itoa((int)enc.current_bank>>5,str,10);
311
312
      sendStringRS232(str);
313
314
      sendStringRS232("\r\n");
315
    }else{
316
317
      sendStringRS232("Error while bankset ");
318
      sendStringRS232(" to bank ");
319
320
        itoa((int)enc.current_bank>>5,str,10);
321
322
        sendStringRS232(str);
323
324
        sendStringRS232(" anstatt ");
325
326
        itoa((int)bk,str,10);
327
328
              sendStringRS232(str);
329
330
      sendStringRS232("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
331
    }
332
333
  }
334
}
335
336
337
/**
338
 * This function sends a command with data or without data if data = 0
339
 *
340
 */
341
static char cmd_LAN(char cmd, char data){
342
343
  char ret=0;
344
  char str[12];
345
346
  // Release CS SD Card (low active)
347
  PORTB &=~(1<<LAN_CS);
348
349
  SPI_SEND(cmd);
350
351
  // Write
352
  if(data)
353
    SPI_SEND(data);
354
355
356
  //if MAC* or MI* is read a second dummy read is neccesary
357
  if(cmd & 0x80){
358
    ret = SPI_RECEIVE_0x00();
359
    /*
360
    itoa((int)ret,str,2);
361
    sendStringRS232("Statusregister-: 0b");
362
    sendStringRS232(str);
363
    sendStringRS232("\r\n");
364
    sendStringRS232("data & 0x80\r\n");*/
365
  }
366
367
  ret =  SPI_RECEIVE_0x00();
368
369
  // set CS LAN (low active)
370
  PORTB |=(1<<LAN_CS);
371
372
  return ret;
373
}
374
375
void cmd_write_LAN(char hi, char lo){
376
  // Release CS SD Card (low active)
377
  PORTB &=~(1<<LAN_CS);
378
379
  SPI_SEND(hi);
380
  SPI_SEND(lo);
381
382
  // set CS LAN (low active)
383
  PORTB |=(1<<LAN_CS);
384
}

irgendwo muss ich in der Funktion select_bank nen fehler haben wil er ja 
den wechsel richtig erkennt, nur halt die register nicht richtig gesetzt 
werden.

hier mal die Ausgabe des Programms (alles von sendStringRs232())
1
LAN INIT vor while
2
switch from bank 7 to bank 0
3
bankset ok bank 0
4
Statusregister: 0b1
5
nach while
6
Statusregister: 0b1
7
vor for
8
9
b0 ETXSTL: 0x0 sollte 0x00 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
11
b0 ETXSTH: 0x1a sollte 0x1a heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
switch from bank 0 to bank 2
13
Error while bankset  to bank 2 anstatt 0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14
15
b2 MAIPGL: 0xff sollte 0x12 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
16
switch from bank 2 to bank 3
17
Error while bankset  to bank 3 anstatt 0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
18
19
b3 MAADR5: 0xff sollte 0xac heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
20
nach for
21
nach loop while
22
nach led enable
23
fail (unknown reason)

danke schonmal

Gruß

von (prx) A. K. (prx)


Lesenswert?

Quelltextmonster bitte als Anhang.

Ich hab mich dadurch grad nicht durchgewühlt, erinnere mich aber vage an 
irgendwelche Dummy-Bytes im Protokoll, abhängig davon welche der 
internen Subkomponenten man ansprechen will.

von Sonke A. (soeni)


Lesenswert?

meinst du nen dummy read ? wenn ja was hat da mit dem banksetzen zu tun? 
ich hab mich da an einer Vorlage langgehangelt. Im Datenblatt hab ich 
diesbezüglich nichts gefunden.

von eProfi (Gast)


Lesenswert?

1.
//write_phy_LAN(ENC28J60_PHY_PHLCON,0x0472);
dazu siehe
Beitrag "ENC28J60 correct value of PHLCON and mirrored registers"

2.
Ich habe zu diesem Thema einen verbesserten Treiber geschrieben, der in 
Abhängigkeit der jetzigen Bank-Bits nur die notwendigen Bits ändert,
das spart den einen oder anderen SPI-Transfer.
Z.B. wenn Du auf Bank 0 wechseln willst, brauchst Du keine Bits setzen.
Oder wenn Du von 3 auf 2 wechseln willst, nur Bit0 löschen und keines 
setzen.

Habe ich nicht auf dem Rechner, auf dem ich gerade tippe, kann es aber 
später posten.

Zu Deinem Problem: ein typischer Copy-Past-Fall
Du musst die Bits nach dem Löschen wieder setzen, nicht nochmal löschen:

    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),enc.current_bank>>5);
--->cmd_write_LAN((LAN_BFS|ENC28J60_REG_ECON1),enc.current_bank>>5);
                         X

von (prx) A. K. (prx)


Lesenswert?

Weiteres mögliches Problem: Zwischen den letzten SPI-Bit und der 
Deaktivierung von SPI-CS müssen je nach Richtung und angesprochenem 
Register mindestens 210ns verstreichen.

von eProfi (Gast)


Lesenswert?

So hier die Idee mit dem Bankselect:

int ist=0,soll=0;
switch(ist|soll){
  case  0:break;
  case  5:break;
  case  9:clr(2);//in case 1 reinlaufen
  case 11://in case 1 reinlaufen
  case  1:set(1);break;
  case  6:clr(1);//in case 2 reinlaufen
  case  7://in case 2 reinlaufen
  case  2:set(2);break;
  case  3:set(3);break;
  case  4://in case 12 reinlaufen
  case  8://in case 12 reinlaufen
  case 12:clr(3);break;
  case 13:clr(2);break;
  case 14:clr(1);break;
  case 10:break;
  case 15:break;
  }
ist=soll<<2;

Das Prinzip ist einfach:
ich verwende den BitSet - bzw. BitClr -Befehl nur, wenn nötig.
Zu dieser Entscheidung dient die switch-Anweisung. Zwei Bits für die 
alte Banknummer, zwei für die neue Banknummer, 4 Bits ergeben 16 cases.
Die sind ein wenig umgestellt und optimiert (ergibt kürzeren Code, aber 
keinen Geschw.-Vorteil).

von Sonke A. (soeni)


Lesenswert?

Danke für die Antworten.

Was meinst du mit copy paste fehler? bei mir steht das nicht zweimal da.


Auch danke für die optimierungstipps aber bei mir geht das garnicht, 
auch wenn ich immer schreibe.

Gruß

von eProfi (Gast)


Lesenswert?

1.
Bei Dir steht:
    // release old bank select
    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),((1<<ENC28J60_BIT_ECON1_BSEL0 
)  | (1<<ENC28J60_BIT_ECON1_BSEL1)));
    // Set new one
    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),enc.current_bank>>5);

Es muss aber heißen:
    // release old bank select
    cmd_write_LAN((LAN_BFC|ENC28J60_REG_ECON1),((1<<ENC28J60_BIT_ECON1_BSEL0 
)  | (1<<ENC28J60_BIT_ECON1_BSEL1)));
    // Set new one
    cmd_write_LAN((LAN_BFS|ENC28J60_REG_ECON1),enc.current_bank>>5);

Es ist in der letzten Zeile ein S (Set) und kein C (Clear) in LAN_BFS.



2.
Nochmal ausführlich ohne Optimierung
switch(ist|soll){
  case  0:              break;
  case  1:set(1);       break;
  case  2:set(2);       break;
  case  3:set(3);       break;
  case  4:clr(1);       break; //oder clr(3);
  case  5:              break;
  case  6:clr(1);set(2);break; //oder clr(3);set(2);
  case  7:set(2);       break; //oder set(3);
  case  8:clr(2);       break; //oder clr(3);
  case  9:clr(2);set(1);break; //oder clr(3);set(1);
  case 10:              break;
  case 11:set(1);       break; //oder set(3);
  case 12:clr(3);       break;
  case 13:clr(2);       break;
  case 14:clr(1);       break;
  case 15:              break;

 Bit
3210 clr set      clr set
0000  -   -
0001  -   1
0010  -   2
0011  -   3
0100  1   -  oder  3  -
0101  -   -
0110  1   2  oder  3  2
0111  -   2  oder  -  3
1000  2   -  oder  3  -
1001  2   1  oder  3  1
1010  -   -
1011  -   1  oder  -  3
1100  3   -
1101  2   -
1110  1   -
1111  -   -

von Sonke A. (soeni)


Lesenswert?

aaaaaaaaarrrrrrg danke danke siehst du mal wie blind ich bin  ;)

Danke jetzt gehts.

manchmal braucht man einfach mal jemand der neutral über den code guckt.

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.