www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ethernet beim LPC2468


Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich möchte schon lange was mit Ethernet auf meinem LPC2468 machen, doch 
habe ich nach anfänglichen Versuchen mit dem lwip aufgegeben und mich 
anderen Dingen zugewandt (wie z.B. RTOS). Nachdem ich nun uC/OS am 
laufen habe, dachte ich, es wäre wieder einmal an der Zeit, das mit dem 
Ethernet nochmal in Angriff zu nehmen.
Dazu musste ich natürlich meinen Ethernet-Driver so zurechtbiegen, dass 
er mit uC/OS zurechtkommt. Herausgekommen ist folgender Code:
#include "mac.h"

#include "lpc2468.h"

#include "ucos_ii.h"
#include "os_cpu.h"

SDRAM OS_EVENT *macsem;
SDRAM OS_EVENT *macmbox;

void MAC_fInitialize(OS_EVENT* m)
{
  tDWord dwID;
  macsem = OSSemCreate(0);
  macmbox = m;
  tByte err;

  PCONP |= BIT_30; /* power up the mac */
  PINSEL2 |= (BIT_00 | BIT_02 | BIT_08 | BIT_16 | /* select the rmii pins */
    BIT_18 | BIT_20 | BIT_28 | BIT_30);
  PINSEL3 |= (BIT_00 | BIT_02); /* select the mdio and clk pins */
  MAC1 =  (BIT_08 | BIT_09 | BIT_10 | BIT_11 | BIT_14 | BIT_15); /* reset */
  Command = (BIT_03 | BIT_04 | BIT_05); /* reset the mac */
  MAC1 = 0; /* deassert the resets */
  MAC2 = 0; /* set the mac into the default state */
  IPGR = IPGR_DEFAULT; /* set the back-to-back inter packet gap */
  CLRT = CLRT_DEFAULT; /* set the collision window and retransmission count */
  MAXF = MAX_FRAME; /* maximum frame length */

  MCFG = (BIT_02 | BIT_03 | BIT_04 | BIT_15); /* divide clk by 20, reset mii */
  MCFG ^= BIT_15; /* deassert the mii reset */
  MCMD = 0; /* clear the command register */
  Command = (BIT_09 | BIT_06 /*| BIT_07*/); /* enable the rmii */
  SUPP = BIT_08; /* enable 100MBit mode */
  MAC_fWritePHY(PHY_BCR, BIT_15); /* reset the phy */
  while(MAC_fReadPHY(PHY_BCR) & BIT_15); /* wait until reset is done */
  dwID = (MAC_fReadPHY(PHY_ID1) << 16); /* get PHY manufacturer and revision */
  dwID |= (MAC_fReadPHY(PHY_ID2) & 0xFFF0);
  if(dwID != KSZ8001_ID) /* check if this is a KSZ8001L PHY */
  {
    return; /* abort */
  }
  MAC_fWritePHY(PHY_ICS, BIT_08 | BIT_10); /* enable link interrupt */
  MAC_fWritePHY(PHY_CTL, BIT_14); /* enable the link and act LEDs */
  MAC_fWritePHY(PHY_BCR, BIT_12 | BIT_09); /* enable & start autonegotiation */

  PINSEL4 |= BIT_22; /* enable EINT1 interrupt */
  VICVectPriority15 = 0; /* set up the phy interrupt */
  VICVectAddr15 = (tDWord)MAC_fPHYInterrupt;
  VICIntEnable |= BIT_15; /* enable the link up/down interrupt */

  OSSemPend(macsem, 0, &err); /* wait until link established */

  SA0 = (MAC_ADDRESS1 << 8) | MAC_ADDRESS2; /* set up the mac address */
  SA1 = (MAC_ADDRESS3 << 8) | MAC_ADDRESS4;
  SA2 = (MAC_ADDRESS5 << 8) | MAC_ADDRESS6;
  MAC_fInitRxDescriptors(); /* initialize rx descriptors */
  MAC_fInitTxDescriptors(); /* initialize tx descriptors */

  RxFilterCtrl = (BIT_01 | BIT_02 | BIT_05); /* uni-, multi- and broadcast */

  Command |= (BIT_00 | BIT_01); /* enable receiver and transmitter */
  MAC1 |= BIT_00; /* enable the receiver */

  VICVectPriority21 = 0; /* set up the mac interrupt */
  VICVectAddr21 = (tDWord)MAC_fMACInterrupt;
  VICIntEnable |= BIT_21; /* enable the mac interrupt */
  IntClear = 0xFFFFFFFF;
  IntEnable = BIT_03;
  return;
}

static void MAC_fPHYInterrupt(void)
{
  tWord wInterrupt = MAC_fReadPHY(PHY_ICS); /* get the interrupt source */
  if(wInterrupt & BIT_00)
  {
    tWord wMode = (MAC_fReadPHY(PHY_100BTX) & (BIT_04 | BIT_03 | BIT_02));
    switch(wMode)
    {
      case MODE_10M_HALF_DUPLEX:
      {
        MAC2 = (BIT_04 | BIT_05 | BIT_07); /* crc, padding, half duplex */
        SUPP = 0; /* 10MBit mode */
        Command &= ~BIT_10; /* issue half duplex command */
        IPGT = 0x12; /* default setting for 10 MBits, half duplex */
        break;
      }
      case MODE_10M_FULL_DUPLEX:
      {
        MAC2 = (BIT_00 | BIT_04 | BIT_05 | BIT_07); /* crc, padding, full duplex */
        SUPP = 0; /* 10MBit mode */
        Command |= BIT_10; /* issue full-duplex command */
        IPGT = 0x15; /* default setting for 10 MBits, full duplex */
        break;
      }
      case MODE_100M_HALF_DUPLEX:
      {
        MAC2 = (BIT_04 | BIT_05 | BIT_07); /* crc, padding, half duplex */
        SUPP = 0; /* enable 100MBit mode */
        Command &= ~BIT_10; /* issue half-duplex command */
        IPGT = 0x12; /* default setting for 100 MBits, half duplex */
        break;
      }
      case MODE_100M_FULL_DUPLEX:
      {
        MAC2 = (BIT_00 | BIT_04 | BIT_05 | BIT_07); /* crc, padding, full duplex */
        SUPP = BIT_08; /* enable 100MBit mode */
        Command |= BIT_10; /* issue full-duplex command */
        IPGT = 0x15; /* default setting for 100 MBits, full duplex */
        break;
      }
    }
    OSSemPost(macsem);
  }
  else if(wInterrupt & BIT_02)
  {
  }
  EXTINT |= BIT_01;
}

static void MAC_fMACInterrupt(void)
{
  tDWord dwIntStatus = IntStatus; /* get the interrupt source */
  if(dwIntStatus & BIT_00) /* rx overrun */
  {
    IntClear = BIT_00; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_01) /* rx error */
  {
    IntClear = BIT_01; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_02) /* rx finished */
  {
    IntClear = BIT_02; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_03) /* rx done */
  {
    tWord wIdx = RxConsumeIndex; /* get the index of the next received frame */
    OSMboxPost(macmbox, (void*)dwRxDescriptors[wIdx * 2]);
    wIdx++;
    if(wIdx == MAC_RX_FRAGMENTS)
      wIdx = 0;
    RxConsumeIndex = wIdx;
    IntClear = BIT_03;
  }
  if(dwIntStatus & BIT_04) /* tx underrun */
  {
    IntClear = BIT_04; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_05) /* tx error */
  {
    IntClear = BIT_05; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_06) /* tx finished */
  {
    IntClear = BIT_06; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_07) /* tx done */
  {
    IntClear = BIT_07; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_12) /* software interrupt */
  {
    IntClear = BIT_12; /* acknowledge interrupt */
  }
  if(dwIntStatus & BIT_13) /* wakeup */
  {
    IntClear = BIT_13; /* acknowledge interrupt */
  }
}

Dazu muss ich noch sagen, dass der Interrupt-Pin des Micrel KSZ8001 Phy 
mit dem External Interrupt 1 des LPC verbunden ist, sodass der 
MAC_fPHYInterrupt ausgeführt wird, wenn man ein Netzwerkkabel ein- oder 
aussteckt.
Der MAC selber hingegen hat den MAC_fMACInterrupt zugeordnet.
Der Driver funktioniert im Grossen und Ganzen, jedoch habe ich 
festgestellt, dass irgendwo der Wurm drin ist. Denn sporadisch - ich 
kann das Verhalten weder nachvollziehen noch irgendwie reproduzieren - 
wird im MAC_fInterrupt der "RX Error" interrupt ausgeführt. Das sollte 
ja eigentlich nicht passieren?! :o ist an meiner Initialisierung was 
faul, oder wodurch kann dieser RX error verursacht werden? Die 
Initialisierung habe ich mehr oder weniger von einem Sample von Keil 
entnommen. Kann natürlich schon sein, dass da was nicht ganz passt, da 
diese für ein anderes Board war - mein Board ist ja selbst gemacht.
Wenn natürlich da irgendwelche RX Errors auftauchen, muss ich mich nun 
natürlich nicht wundern, dass der lwip nie richtig gelaufen ist. 
Irgendwas bereitet der Hardware da Probleme, und ich weiss nicht was.
Könnt ihr mir helfen?

Ach ja, falls es von Belang ist:
MAC_fInitialize kriegt vom aufrufenden Task einen Pointer auf eine 
Mailbox mit. Dieser Pointer wird dann in einer internen Variable 
abgelegt (macmbox). Trifft ein Ethernet-Frame ein, wird der 
MAC-Interrupt aufgerufen, welcher die Adresse des Memory, wo das 
empfangene Paket liegt, ermittelt und diese als Message in diese Mailbox 
postet. Der Task, welcher für das Ethernet zuständig ist, wartet auf 
diese Message. Nach erhalt wird er vom OS ausgeführt, da er eine hohe 
Priorität hat. Der Task kennt dann die Adresse, wo ein Paket im Memory 
liegt, und kann dieses verarbeiten.

Ich hoffe, mir kann jemand einen Tipp geben!

Vielen Dank schon im Voraus.

Gruss Tobias

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.