www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AT91SAM9260 EMAC Treiber Problem


Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich habe einen einfachen Treiber für das EMAC meines AT91SAM9260 
Mikrocontroller geschrieben, der leider nicht funktioniert. Ich bin 
schon länger erfolglos am Fehlersuchen und hoffe Ihr könnt mir helfen.

1. Kein Betriebssystem
2. ICache ist an, DCache nicht, MMU ist aus
3. PHY connection läuft, wird ja im Programm getestet
4. Auf einen Link wird gewartet (nicht zu sehen) und er ist da!
5. Die Pakete versuche ich mit Wireshark zu empfangen, leider vergebens.
6. Beim ersten senden eines Pakets zählt Frames Transmitted OK Register 
noch, dann nicht mehr. Also demnach sollte ein Paket gesendet werden.
7. PHY ist Micrel KSZ8721BL (habe das Olimex Board SAM9-9260)

Wo könnte der Fehler bloß liegen? Was sind häufige Fehlerquellen? Ich 
bin für jeden Hinweis dankbar!

Viele Grüße
Daniel

Hier der Treiber-Code
/*****************************************************************************
 *                                       *
 *  EMAC DRIVER                                 *
 *                                       *
 *****************************************************************************/

#include "eth.h"
#include "endian.h"
#include "part.h"
#include "main.h"
#include "gpio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/************************************************
 * VARIABLES AND STRUCTS            *
 ************************************************/

/* setting up the buffer descriptor list */
unsigned int RxBd[2048];        //1024 buffer descriptors of 2 words

/* setting up the receive buffer */
unsigned int RxB[1024][32];        //1024 buffer of 128byte


/* setting up 128 transmit buffer descriptors, thats enough! */
unsigned int TxBd[256];          //128 two word buffer descriptors

/* setting up the transmit buffer */
unsigned int TxB[128][512];          //128 buffers of 2048 byte


/* HEADER DEFINITIONS */

/* ethernet encapsulation */
struct ethheader {
  unsigned char destMAC[6];
  unsigned char srcMAC[6];
  unsigned char type[2];
} __attribute__ ((packed)) *eth;

/* ip header */
struct ipheader {
  unsigned char version_header;    //4bit version, 4 bit header length in 32bit-words
  unsigned char TOS;          //0x0 for default
  unsigned short length;        //total length of ip datagram
  unsigned short id;          //normally incrementet by every sent packet
  unsigned short flags_offset;    //3bit flags, 13bit offset
  unsigned char TTL;          //time to live, normally 32 or 64
  unsigned char prot;          //17 for UDP
  unsigned short chksum;        //header checksum
  unsigned int sourceIP;
  unsigned int destIP;
}__attribute__ ((packed)) *ip;

/* udp header */
struct udpheader {
  unsigned short srcPort;        //source portnumber
  unsigned short destPort;      //destination port number
  unsigned short length;        //total length of udp datagram
  unsigned short chksum;        //checksum (optional) pseudo-header, header and data
} __attribute__ ((packed)) *udp;


/************************************************
 * INITIALIZATION                *
 ************************************************/

int eth_init ( )
{
  int i;

  /* enable emac in power management controller PMC */
  writel( 1 << AT91C_ID_EMAC, AT91C_PMC_PCER);
  
   /* disable transmit and receive circuits */
   writel( 0, AT91C_EMACB_NCR );    //disabling by reset network control register

  /* disable all interrupts */
  writel( ~0, AT91C_EMACB_IDR );    //disabling by writing 0xffffffff to the interrupt disable register

  /* set the MAC address of this device */
  //necessary to receive packets
  
  /* clear statistics register, enable management port, make status registers writable */
  writel( AT91C_EMAC_CLRSTAT | 
      AT91C_EMAC_MPE |
      AT91C_EMAC_WESTAT
        , AT91C_EMACB_NCR );

  /* configure network */
  writel( AT91C_EMAC_SPD |      //set speed to 100Mbit/s
      AT91C_EMAC_FD |        //set full duplex mode
      AT91C_EMAC_CLK_HCLK_64    //set clock divider according MCK
        , AT91C_EMACB_NCFGR );

  /* enable transreceiver input clock and set to MII mode */
  writel( AT91C_EMAC_CLKEN, AT91C_EMACB_USRIO );


/************************************************
 * PHY SETUP                  *
 ************************************************/

  /* basic control register 0x0 */
  writel (  PHY_SOF |
        PHY_WRITE |
        PHY_ADDRESS |
        PHY_BCR |
        PHY_CODE |
        PHY_BCR_AUTONEG |
        PHY_BCR_AUTONEG_RESTART
          , AT91C_EMACB_MAN );
  while ( !(readl(AT91C_EMACB_NSR) & AT91C_EMAC_IDLE) );    //wait for transmission completed

  /* read and verify PHY register entry */
  /* read PHY identifier, shold be 0x0022 in register 0x2 */
  writel (  PHY_SOF |
        PHY_READ |
        PHY_ADDRESS |
        PHY_ID1 |
        PHY_CODE
          , AT91C_EMACB_MAN );
  while ( !(readl(AT91C_EMACB_NSR) & AT91C_EMAC_IDLE) );    //wait for transmission completed
  if ( (readl(AT91C_EMACB_MAN) & PHY_DATA_MASK) != 0x0022 )  //read and verify ID
    pio_set_value(AT91C_PIN_PA(9), 0);            //if doesn't match switch power LED off


/************************************************
 * BUFFER CONFIGURATION              *
 ************************************************/

  /* RECEIVE BUFFER */

  /* received frames are written into 128byte long receive buffers. these buffers 
   * are stored in memory. every start location of a buffer is stored in a list.
   * each entry of this list consists of 2 words and is called buffer desciptor.
   */

  /* initialize descriptor list */
  for (i = 0; i < 1024; i++) {
    RxBd[i*2] = ((unsigned int) RxB[i]) & ~3;      //mask the two least significant bits
  }
  RxBd[2047] |= 2;            //set wrap bit of the last descriptor

  /* write start address of descriptor list to receive buffer queue pointer register */
  writel( (unsigned int) RxBd & ~3, AT91C_EMACB_RBQP );  //mask the two least significant bits of the address

  /* enable receiver */
  writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_RE, AT91C_EMACB_NCR );


  /* TRANSMIT BUFFER */

  /* Frames to be transmitted are stored in one or more buffers. the buffer size is
   * between 0 and 2047 byte. the start location of each transmit buffer is stored
   * in a tramsmit buffer descriptor list. the transmit buffer queue pointer register
   * points to one of the descriptors.
   * each descriptor entry consists of two words. the first word contains the address
   * and the second control and status information.
   */

  /* initialize descriptor list */
  for (i = 0; i < 128; i++) {
    TxBd[i*2] = (unsigned int) TxB[i];          //write start address of each buffer to the descriptor
    TxBd[i*2+1] = TxBd_USED;              //set used bit, there's no frame to be sent
  }
  TxBd[255] |= TxBd_WRAP;                  //set wrap bit of the last buffer descriptor

  /* write start address of descriptor list to transmit buffer queue pointer register */
  writel( (unsigned int) TxBd, AT91C_EMACB_TBQP );

  /* enable transmitter */
  writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_TE, AT91C_EMACB_NCR );
  
  packet_setup();

  return 0;
}

/************************************************
 * PACKET SETUP                  *
 ************************************************/

void packet_setup () {

  /* ETHERNET HEADER */
  /* destination MAC Address */
  eth->destMAC[0] = 0xff;          //MAC: little endian
  eth->destMAC[1] = 0xff;
  eth->destMAC[2] = 0xff;
  eth->destMAC[3] = 0xff;
  eth->destMAC[4] = 0xff;
  eth->destMAC[5] = 0xff;
  /* Source MAC Address */
  eth->srcMAC[5] = 0x00;
  eth->srcMAC[4] = 0x2e;
  eth->srcMAC[3] = 0x44;
  eth->srcMAC[2] = 0xa2;
  eth->srcMAC[1] = 0x43;
  eth->srcMAC[0] = 0x00;
  /* Type */
  eth->type[0] = 0x08;          //big endian
  eth->type[1] = 0x00;

  /* IP HEADER */
  /* Version and Header length */
  ip->version_header = 4 << 4;      //version on higher-half-byte
  ip->version_header += 5 << 0;      //header length on lower-half-byte
  /* TOS */
  ip->TOS = 0x0;              //normal service
  /* total length */
  ip->length = endians(68);
  /* identification */
  ip->id = endians(0);
  /* flags and offset */
  ip->flags_offset = endians(0);
  /* Time To Live */
  ip->TTL = 32;
  /* Protocol */
  ip->prot = 17;              //17 means UDP
  /* source IP */
  ip->sourceIP = endianl(10 << 0 | 0 << 8 | 168 << 16 | 192 << 24);
  /* destination IP (broadcast) */
  ip->destIP = endianl(0xffffffff);
  /* checksum */
  ip->chksum = 0;                    //to calculate chksum, this field has to be zero
  ip->chksum = endians(ip_chksum(20, (char*)ip));    //calculate IP checksum

  /* UDP HEADER */
  /* source port */
  udp->srcPort = endians(1044);
  /* destination port */
  udp->destPort = endians(1044);
  /* length */
  udp->length = endians(48);
  /* checksum */
  udp->chksum = endians(0);        //checksum is not used

}

/* IP CHECKSUM CALCULATION */
short ip_chksum (short header_length, char header[])
{
  short word16;
  long sum = 0;
  short i;
    
  /* make 16 bit words out of every two adjacent 8 bit words in the packet
   * and add them up */
  for (i = 0; i < header_length; i += 2) {
    word16 = ((header[i] << 8) & 0xFF00) + (header[i+1] & 0xFF);
    sum = sum + (long) word16;
  }
  
  /* take only 16 bits out of the 32 bit sum and add up the carries */
  while (sum >> 16)
    sum = (sum & 0xFFFF) + (sum >> 16);

    /* one's complement the result */
  sum = ~sum;
                  
  return ((short) sum);
}


/************************************************
 * TRANSMIT                    *
 ************************************************/

int eth_send () //(*pBuffer, int length)
{

  if (readl(AT91C_EMACB_FTO) >= 3)
    return 1;
//  writel(0, AT91C_EMACB_FTO);

  if ( TxBd[1] & (TxBd_ERR | TxBd_UNDERRUN | TxBd_BUFFEXH ))
    return 1;
  if ( !(TxBd[1] & TxBd_USED) )
    return 1;

  writel (AT91C_EMAC_COMP, AT91C_EMACB_TSR);    //clear COMPLETE bit of transmit status register

  char *bptr = (char*) &TxB[0][0];
  /* copy frame in buffer */
  memcpy( bptr, eth, 14 );
    bptr += 14;
  memcpy( bptr, ip, 20 );
    bptr += 20;
  memcpy( bptr, udp, 8 );
    bptr += 8;
  memcpy( bptr, "1234567890helloworld1234567890helloworld", 40);

  /* write status and control information to TxBd */
  TxBd[1] = TxBd_NOCRC | TxBd_LASTBUF | 82;
  writel( (unsigned int) &TxBd[0], AT91C_EMACB_TBQP );

  writel( readl(AT91C_EMACB_NCR) | AT91C_EMAC_TSTART, AT91C_EMACB_NCR );

  while ( !(readl(AT91C_EMACB_TSR) & AT91C_EMAC_COMP) );

  /* check for error */
  return 0;
}
  

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.