www.mikrocontroller.net

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


Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include "../main.h"
#include "lanDriver.h"

typedef struct enc{

  volatile unsigned char   current_bank;
  volatile unsigned int    next_packet_ptr;
  unsigned char       revision;

}enc28j60_t;

char initSequence[] = {
  // Address,   Value
    //setup bank0 (config stored in progmem, see above)
    //tx buffer:
    ENC28J60_REG_ETXSTL, lo8(ENC28J60_TX_BUFFER_START), //start lo
    ENC28J60_REG_ETXSTH, hi8(ENC28J60_TX_BUFFER_START), //start hi
    ENC28J60_REG_ETXNDL, lo8(ENC28J60_TX_BUFFER_END  ), //end lo
    ENC28J60_REG_ETXNDH, hi8(ENC28J60_TX_BUFFER_END  ), //end hi
    //rx buffer
    ENC28J60_REG_ERXSTL, lo8(ENC28J60_RX_BUFFER_START), //start lo
    ENC28J60_REG_ERXSTH, hi8(ENC28J60_RX_BUFFER_START), //start hi
    ENC28J60_REG_ERXNDL, lo8(ENC28J60_RX_BUFFER_END  ), //end lo
    ENC28J60_REG_ERXNDH, hi8(ENC28J60_RX_BUFFER_END  ), //end hi
    //rx ptr:
    //ENC28J60_REG_ERDPTL, lo8(ENC28J60_RX_BUFFER_START+1),
    //ENC28J60_REG_ERDPTH, hi8(ENC28J60_RX_BUFFER_START+1),

    //setup bank2: (see microchip datasheet p.36)
    //1.) clear the MARST bit in MACON2.
    ENC28J60_REG_MACON2,   0x00,
    //2.) mac rx enable, activate pause control frame support
    ENC28J60_REG_MACON1,   ((1<<ENC28J60_BIT_MARXEN)|(1<<ENC28J60_BIT_RXPAUS)|(1<<ENC28J60_BIT_TXPAUS)),
    //3.) setup MACON3: auto padding of small packets, add crc, enable frame length check:
    ENC28J60_REG_MACON3,   ((1<<ENC28J60_BIT_PADCFG0)|(1<<ENC28J60_BIT_TXCRCEN)|(1<<ENC28J60_BIT_FRMLNEN)),
    //4.) dont set up MACON4 (use default)
    //5.) setup maximum framelenght to 1518:
    ENC28J60_REG_MAMXFLL, lo8(1518),
    ENC28J60_REG_MAMXFLH, hi8(1518),
    //6.) set up back-to-back gap: 0x15 for full duplex / 0x12 for half duplex
    ENC28J60_REG_MABBIPG, 0x12, //half duplex
    //7.) setup non-back-to-back gap: use 0x12
    ENC28J60_REG_MAIPGL,   0x12,
    //8.) setup non-back-to-back gap high byte: 0x0C for half duplex:
    ENC28J60_REG_MAIPGH,   0x0C, //half duplex
    //9.) dont change MACLCON1+2 / MACLCON2 might be changed for networks with long wires !

    //setup bank3:
    //10.) programm mac address: BYTE BACKWARD !
    ENC28J60_REG_MAADR5, NIC_MAC0,
    ENC28J60_REG_MAADR4, NIC_MAC1,
    ENC28J60_REG_MAADR3, NIC_MAC2,
    ENC28J60_REG_MAADR2, NIC_MAC3,
    ENC28J60_REG_MAADR1, NIC_MAC4,
    ENC28J60_REG_MAADR0, NIC_MAC5
};


static char read_LAN(char adr);
static char write_LAN(char adr, char data);
static void select_bank(char bank);
static char cmd_LAN(char cmd, char data);
static void write_phy_LAN(char adr, unsigned int data);
void cmd_write_LAN(char hi, char lo);

enc28j60_t enc;

/**
 * This function initiates the lan chip
 * @return Errorcode LANINIT_
 */
char init_LAN(){

  char str[12];
  // to force bank update
  enc.current_bank=0xff;

  // Reset ENC 28 J 60
  PORTC &=~(1<<LAN_RST);
  _delay_ms(10);
  // Release
  PORTC |=(1<<LAN_RST);


  // Wait for Startup (at least 50 us)
  _delay_us(60);
  // To prevent bad requests wait again at least 5 ms
  _delay_ms(10);

  sendStringRS232("vor while\r\n");

  itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
  sendStringRS232("Statusregister: 0b");
  sendStringRS232(str);
  sendStringRS232("\r\n");

  // Waiting until chip is ready
  while(!(read_LAN(ENC28J60_REG_ESTAT) & 0x01)){};

  sendStringRS232("nach while\r\n");

  itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
  sendStringRS232("Statusregister: 0b");
  sendStringRS232(str);
  sendStringRS232("\r\n");

  sendStringRS232("vor for\r\n");

  /*
  for(int i=0; i<(2*22);i += 2){
    write_LAN(initSequence[i], initSequence[1+1]);
  }
  */



  write_LAN(ENC28J60_REG_ETXSTL,lo8(ENC28J60_TX_BUFFER_START));

  itoa((int)read_LAN(ENC28J60_REG_ETXSTL),str,16);
  sendStringRS232("\r\nb0 ETXSTL: 0x");
  sendStringRS232(str);
  sendStringRS232(" sollte 0x00 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");

  write_LAN(ENC28J60_REG_ETXSTH,hi8(ENC28J60_TX_BUFFER_START));

  itoa((int)read_LAN(ENC28J60_REG_ETXSTH),str,16);
  sendStringRS232("\r\nb0 ETXSTH: 0x");
  sendStringRS232(str);
  sendStringRS232(" sollte 0x1a heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");



  write_LAN(ENC28J60_REG_MAIPGL,   0x12);

  itoa((int)read_LAN(ENC28J60_REG_MAIPGL),str,16);
  sendStringRS232("\r\nb2 MAIPGL: 0x");
  sendStringRS232(str);
  sendStringRS232(" sollte 0x12 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");

  write_LAN(ENC28J60_REG_MAADR5, NIC_MAC0);

  itoa((int)read_LAN(ENC28J60_REG_MAADR5),str,16);
  sendStringRS232("\r\nb3 MAADR5: 0x");
  sendStringRS232(str);
  sendStringRS232(" sollte 0xac heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");

  sendStringRS232("nach for\r\n");

  //no loop back of transmitted frames
  //write_phy_LAN(ENC28J60_PHY_PHCON2, (1<<ENC28J60_BIT_HDLDIS));

  sendStringRS232("nach loop while\r\n");

  //enable interrups
  //enc28j60_write_address(ENC28J60_REG_EIE, (1<<6)|(1<<7));

  //enable rx
  //enc28j60_write_address(ENC28J60_REG_ECON1, (1<<ENC28J60_BIT_RXEN));
  //enc28j60_spi_write_word(ENC28J60_OP_BFS|ENC28J60_REG_ECON1, (1<<ENC28J60_BIT_RXEN));

  // Set 16 Bit LED Register to configure LEDs
  // LEDA: link status, LEDB: RX&TX activity
  //write_phy_LAN(ENC28J60_PHY_PHLCON,0x0472);
  sendStringRS232("nach led enable\r\n");




  return LANINIT_FAILD;
}


/**
 * This function prints out the Errorcodes from Laninit
 * @param err Errorcode
 */
void printLanInitErrors(char err){
  switch (err){
    case LANINIT_FAILD:{
      sendStringRS232("fail (unknown reason)");
      break;
    }
    case LANINIT_SUCCESSFULL:{
      sendStringRS232("successfully");
      break;
    }

  }

}


/** PROTECTED
 *
 *  Reads from the config register
 */
static char read_LAN(char adr){

  // Select bank
  select_bank(adr);
  // Add Command
  adr = adr | LAN_RCR;
  // read
  return cmd_LAN(adr,0);
}


/**
 * This function writes to the PHY Registers
 *
 * @param ard   address of the Register
 * @param data   data to be write to tha PHY register
 *
 */
static void write_phy_LAN(char adr, unsigned int data){

  //see microchip datasheet p.21
  //set address to MIREGADR:
  write_LAN(ENC28J60_REG_MIREGADR,adr);

  // Send data
  write_LAN(ENC28J60_REG_MIWRL, data&0xff);
  write_LAN(ENC28J60_REG_MIWRH, data>>8);

  // wait until phy reg is written

  char str[12];
  sendStringRS232("read phy REG_MISTAT\r\n");
  itoa((int)enc.current_bank,str,10);
      sendStringRS232("bank: ");
      sendStringRS232(str);
      sendStringRS232("\r\n");

  while(read_LAN(ENC28J60_REG_MISTAT) & (1<<ENC28J60_BIT_MISTAT_BUSY))
  {




        _delay_ms(10000);

        /*
    itoa((int)read_LAN(ENC28J60_REG_MISTAT),str,2);
    sendStringRS232("Statusregister1: 0b");
    sendStringRS232(str);
    sendStringRS232("\r\n");

    itoa((int)read_LAN(ENC28J60_REG_ESTAT),str,2);
    sendStringRS232("Statusregister2: 0b");
    sendStringRS232(str);
    sendStringRS232("\r\n");
    _delay_ms(10000);
    */
  }
}


/**
 * Writes to the config registers
 */
static char write_LAN(char adr, char data){

  // Select bank
  select_bank(adr);
  // Add Command
  adr = adr | LAN_WCR;
  // Write
  return cmd_LAN(adr,data);
}


/**
 * Select a bank of config registers
 */
static void select_bank(char bank){

  if((bank & 0x60) != enc.current_bank){
    sendStringRS232("switch from bank ");

    char str[12];

    itoa((int)enc.current_bank>>5,str,10);

    sendStringRS232(str);


    enc.current_bank = (bank & 0x60);

    sendStringRS232(" to bank ");

    itoa((int)enc.current_bank>>5,str,10);

    sendStringRS232(str);

    sendStringRS232(" \r\n");



    // 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);

    char bk = (cmd_LAN((LAN_RCR | ENC28J60_REG_ECON1),0)) & ((1<<ENC28J60_BIT_ECON1_BSEL0) | (1<<ENC28J60_BIT_ECON1_BSEL1));
    //(read_LAN(ENC28J60_REG_ECON1)&((1<<ENC28J60_BIT_ECON1_BSEL0) | (1<<ENC28J60_BIT_ECON1_BSEL1)));
    if(bk == enc.current_bank>>5){
      sendStringRS232("bankset ok ");

      sendStringRS232("bank ");
      itoa((int)enc.current_bank>>5,str,10);

      sendStringRS232(str);

      sendStringRS232("\r\n");
    }else{

      sendStringRS232("Error while bankset ");
      sendStringRS232(" to bank ");

        itoa((int)enc.current_bank>>5,str,10);

        sendStringRS232(str);

        sendStringRS232(" anstatt ");

        itoa((int)bk,str,10);

              sendStringRS232(str);

      sendStringRS232("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
    }

  }
}


/**
 * This function sends a command with data or without data if data = 0
 *
 */
static char cmd_LAN(char cmd, char data){

  char ret=0;
  char str[12];

  // Release CS SD Card (low active)
  PORTB &=~(1<<LAN_CS);

  SPI_SEND(cmd);

  // Write
  if(data)
    SPI_SEND(data);


  //if MAC* or MI* is read a second dummy read is neccesary
  if(cmd & 0x80){
    ret = SPI_RECEIVE_0x00();
    /*
    itoa((int)ret,str,2);
    sendStringRS232("Statusregister-: 0b");
    sendStringRS232(str);
    sendStringRS232("\r\n");
    sendStringRS232("data & 0x80\r\n");*/
  }

  ret =  SPI_RECEIVE_0x00();

  // set CS LAN (low active)
  PORTB |=(1<<LAN_CS);

  return ret;
}

void cmd_write_LAN(char hi, char lo){
  // Release CS SD Card (low active)
  PORTB &=~(1<<LAN_CS);

  SPI_SEND(hi);
  SPI_SEND(lo);

  // set CS LAN (low active)
  PORTB |=(1<<LAN_CS);
}


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())
LAN INIT vor while
switch from bank 7 to bank 0
bankset ok bank 0
Statusregister: 0b1
nach while
Statusregister: 0b1
vor for

b0 ETXSTL: 0x0 sollte 0x00 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!

b0 ETXSTH: 0x1a sollte 0x1a heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
switch from bank 0 to bank 2
Error while bankset  to bank 2 anstatt 0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

b2 MAIPGL: 0xff sollte 0x12 heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
switch from bank 2 to bank 3
Error while bankset  to bank 3 anstatt 0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

b3 MAADR5: 0xff sollte 0xac heisen                     !!!!!!!!!!!!!!!!!!!!!!!!!!!!
nach for
nach loop while
nach led enable
fail (unknown reason)

danke schonmal

Gruß

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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  -   -

Autor: Sonke A. (soeni)
Datum:

Bewertung
0 lesenswert
nicht 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.

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.