Forum: Mikrocontroller und Digitale Elektronik ENC28J60 Interrupt hängt sich auf nach zu vielen Paketen


von C. H. (hedie)


Lesenswert?

Hallo zusammen

Ich habe hier einen ENC28J60

Dieser läuft grundsätzlich einwandfrei.

Wenn ich ihm jedoch viele Pakete schnell hintereinander sende, dann 
hängt sich der interrupt nach ca. 10 Paketen auf.

(damit meine ich, dass der ENC28J60 keinen INT Impuls mehr ausgibt bei 
einem neuen Paket)

Ich habe den ENC wie folgt konfiguriert:
1
// perform system reset
2
3
  enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
4
  // check CLKRDY bit to see if reset is complete
5
  delay(50);
6
  while(!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));
7
  // do bank 0 stuff
8
  // initialize receive buffer
9
  // 16-bit transfers, must write low byte first
10
  // set receive buffer start address
11
  NextPacketPtr = RXSTART_INIT;
12
  enc28j60Write(ERXSTL, RXSTART_INIT&0xFF);
13
  enc28j60Write(ERXSTH, RXSTART_INIT>>8);
14
  // set receive pointer address
15
  enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
16
  enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
17
  // set receive buffer end
18
  // ERXND defaults to 0x1FFF (end of ram)
19
  enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
20
  enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
21
  // set transmit buffer start
22
  // ETXST defaults to 0x0000 (beginnging of ram)
23
  //uart_puts("- enc28j60init - Schreibe erstes nibble - 03\n");
24
  enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
25
  //uart_puts("- enc28j60init - Schreibe zweites nibble - 03\n");
26
  enc28j60Write(ETXSTH, TXSTART_INIT>>8);
27
  // do bank 2 stuff
28
  // enable MAC receive
29
  enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
30
  // bring MAC out of reset
31
  enc28j60Write(MACON2, 0x00);
32
  // enable automatic padding and CRC operations
33
  enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
34
  // set inter-frame gap (non-back-to-back)
35
  enc28j60Write(MAIPGL, 0x12);
36
  enc28j60Write(MAIPGH, 0x0C);
37
  // set inter-frame gap (back-to-back)
38
  enc28j60Write(MABBIPG, 0x12);
39
  // Set the maximum packet size which the controller will accept
40
  enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF);  
41
  enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8);
42
  // do bank 3 stuff
43
  // write MAC address
44
  // NOTE: MAC address in ENC28J60 is byte-backward
45
  enc28j60Write(MAADR5, ENC28J60_MAC0);
46
  enc28j60Write(MAADR4, ENC28J60_MAC1);
47
  enc28j60Write(MAADR3, ENC28J60_MAC2);
48
  enc28j60Write(MAADR2, ENC28J60_MAC3);
49
  enc28j60Write(MAADR1, ENC28J60_MAC4);
50
  enc28j60Write(MAADR0, ENC28J60_MAC5);
51
  // no loopback of transmitted frames
52
  enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);
53
  // switch to bank 0
54
  enc28j60SetBank(ECON1);
55
  // enable interrutps
56
  enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
57
  // enable packet reception
58
  enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);

Im Interrupt sieht dies wie folgt aus:
1
ISR(INT1_vect)
2
{
3
  interrupt_INT1(0); //Deaktivieren
4
  process_packet(enc28j60PacketReceive(ETH_buffer_SIZE, ETH_buffer));
5
  interrupt_INT1(1); //Interrupt aktivieren
6
}
7
...
8
9
enc28j60PacketReceive()
10
....
11
  // check if a packet has been received and buffered
12
  if( !(enc28j60Read(EIR) & EIR_PKTIF) )
13
    return 0;
14
......
15
  // decrement the packet counter indicate we are done with this packet
16
  enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);


Ich weiss ehrlich gesagt nicht woran es liegen könnte...

Ist dieses Problem bereits bekannt?

Danke schonmal

von Obstfliege (Gast)


Lesenswert?

Wahrscheinlich ist der interne Speicher voll. Abhilfe: auslesen bevor er 
überläuft. Der Speicher ist nämlich nicht sehr üppig bemessen.

von C. H. (hedie)


Lesenswert?

Obstfliege schrieb:
> Wahrscheinlich ist der interne Speicher voll. Abhilfe: auslesen bevor er
> überläuft. Der Speicher ist nämlich nicht sehr üppig bemessen.

Der Speicher wird im Interrupt mit der Funktion enc28j60PacketReceive()
ausgelesen.

Hier der C-Code
1
  // Set the read pointer to the start of the received packet
2
  enc28j60Write(ERDPTL, (NextPacketPtr));
3
  enc28j60Write(ERDPTH, (NextPacketPtr)>>8);
4
  // read the next packet pointer
5
  NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
6
  NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
7
  // read the packet length
8
  len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
9
  len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
10
  // read the receive status
11
  rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
12
  rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8;
13
14
  // limit retrieve length
15
  // (we reduce the MAC-reported length by 4 to remove the CRC)
16
  len = MIN(len, maxlen);
17
18
  // copy the packet from the receive buffer
19
  enc28j60ReadBuffer(len, packet);
20
21
  // Move the RX read pointer to the start of the next received packet
22
  // This frees the memory we just read out
23
  enc28j60Write(ERXRDPTL, (NextPacketPtr));
24
  enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);

von Stefan (Gast)


Lesenswert?

Und das Auslesen kann durchaus erheblich länger dauern, als der Empfang 
des nächsten Paketes. In der Zeit kann der Chip locker 10 Pakete 
empfangen, aber nicht so viele Puffern. Der Chip kann keinen weiteren 
Interrupt auslösen, solange die Interruptroutine aktiv ist.

Wenn Du im Interrupt ein Paket ausgelesen hast, solltest Du danach 
(immer och in der Interrupt-Routine) abfragen, ob der Chip noch weitere 
Pakete empfangen hat und diese ggf. auch auslesen.

von User_Y (Gast)


Lesenswert?

Würde das Paket nicht unbedingt im Interrupt auslesen!

process_packet(enc28j60PacketReceive(ETH_buffer_SIZE, ETH_buffer));

Besser wäre es im Interrupt nur ein FLAG zu setzten oder noch besser 
einen COUNTER zu inkrementieren der die Pakete zählt. Und in der Main() 
kannst dann schauen ob counter>0 ist und bei Bedarf Daten kopieren!

Mit welcher Frequenz betreibst Du Deine  SPI?

Beste Grüße!

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.