Putting ENC28J60 ethernet controler in sleep mode on Arduino.

During my fabulous trip in the fantastic word of Arduinos, i had to gather some data from the Internet. As a lucky owner of an Arduino Mega Board (Or some kind of chinese counterfeit), i was quite disappointed when i finally discovered that there were no official Ethernet shield designed especially for the ATmega1280 based boards. In fact, SPI pin on the Arduino Mega are not physically located like on the Diecimila/Duemilanove boards. Someone hacked the official shield to work on the Mega, but, la flemme.

 

The beast

Anyway, after a quick search on eBay, I finally found a very cheap ethernet shield compatible with the mega board. This Shield is based on a ENC28J60 chip, contrary to the official board. A side effect is that the official library does not work. After doing some googling, I’ve found this absolutely perfect library. For example, it fully supports DNS, DHCP while the official does not. The library does not work de facto on my ekitzone Ethernet shield. I spent a few hours figuring out why the fuck it was malfunctioning on my board. Finally, I noticed a comment from Telek explaining what to change in the libraries. If I noticed it before, I would have gained a lot of time. From now, you should be glad of knowing it :P

Nevermind, that’s not what this article is about.

Briefly, my project involves controlling a few RGB leds from the Internet. The Arduino board have get some input data every 3 minuts on the internets. That mean the Ethernet shield is unused about 2min and 58second per cycle. During these nearly 3 minuts, the traffic and state leds keep blinking furiously each time le board recieves anything : even when it’s broadcasted paquets. The perpetual-furiously-yellow-blinking-led reassures at the beginning (wow, it WORKS) but becomes very annoying when dealing with RGB led smoothly and gently fading.
The other point is that the ENC28J60 chip drains power and warms up. After quickly reading the ENC28J60 data-sheet, I learned the chip had a low power consumption mode. Thanks to google, i sorely found this post explaining how to manipulate registers to put the chip in deep sleep. I could not find on the Internet a function doing that, so i finally written it. (yeah, sometimes i write functions, amazing uh ?). I thought i may actually interest someone, i decided to publish it. Here it comes. You have to add the following lines in your enc28j60.c file in your ethershield library :

void enc28j60PowerDown() {
 enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
 while(enc28j60Read(ESTAT) & ESTAT_RXBUSY);
 while(enc28j60Read(ECON1) & ECON1_TXRTS);
 enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
 enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
}

void enc28j60PowerUp() {
 enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
 while(!enc28j60Read(ESTAT) & ESTAT_CLKRDY);
 enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
 }

And then,

extern void enc28j60PowerDown();
extern void enc28j60PowerUp();

In enc28j60.h

Finally :

void EtherShield::ES_enc28j60PowerUp(){
 enc28j60PowerUp();
}

void EtherShield::ES_enc28j60PowerDown(){
 enc28j60PowerDown();
}

in EtherShield.cpp with the following prototypes in EtherShield.h :

void ES_enc28j60PowerDown();   
void ES_enc28j60PowerUp();

Finally, you can try the modification with a code like this one :

Serial.println("Pausing");
 es.ES_enc28j60PowerDown();
 Serial.println("Paused");
 delay(10000);
 Serial.println("Powering Up");
 es.ES_enc28j60PowerUp();
 Serial.println("Powered up");
 delay(2000);

If everything is okay, you should see that the shield goes off for ten second : the leds are off and the chip cools down. The two processes of putting to sleep and waking up are done very quickly (about 1ms). This will help me reducing power consumption, heat generation and among all, avoids me the pain of getting the two annoying leds off the board.

Edit : After more tests, i discovered that the chip (or the library) seems to forget some part of the configuration after beeing waked up : you could need to re-configure some settings. In my case, a es.ES_client_set_gwip(gwip); did the trick. See edit 4.

Edit 2 : Correction of a little mistake, thanks to Christian N. for reporting (see comments).

Edit 3 : According to Christian N (see comments), putting the chip in sleep mode reduce the consumption by 150mA. Also, he had to re-initialise the board after waking up : re-setting the gateway how I explain in my first edit is not enough. Do you own tests !

Edit  4 : Thanks to Peter (see comments), the PowerUp() and PowerDown() code is corrected : my implementation was missing something, so the powering up function was not 100% effective and I had to reinitialize the chip.

Cet article a été publié dans Arduino avec les mots-clefs , , , , , . Bookmarker le permalien. Laisser un commentaire ou faire un trackback : URL de trackback.

17 Commentaires

  1. Publié le 9 juillet 2011 à 10 h 54 min | Permalien

    Thank you for publishing this code! I’m attempting to build a board with ATmega328 and ENC28J60 and this would surely be useful.
    I’m planning to run the whole board at 3.3V. The datasheet specifies that ENC28J60 consumes between 160-180 mA while transmitting and 1.2-2 mA in standby.
    Have you measured the operating current for the Ethernet shield in both modes?

    • Simon
      Publié le 9 juillet 2011 à 11 h 07 min | Permalien

      Hi,
      I’m affraid i did not mesured the energy consumption of the ENC28J60, due to the fact I’m using the chip on an arduino shield, which makes the mesure harder. But i can tell it surely lowers the consumption since the leds are quite brighter when the chip is in sleep mode.
      By the way, further testings showed me that you have to do es.ES_client_set_gwip(gwip) after waking up ; i suppose that some registers of the enc chip are cleared in sleep mode.

      • Publié le 9 juillet 2011 à 11 h 43 min | Permalien

        I don’t intend to use a shield, not even the LED’s on the MagJack, in order to optimize battery usage. When the board will be ready I’ll come back with the measurements.
        Merci beaucoup de votre attention!

        • Simon
          Publié le 9 juillet 2011 à 11 h 58 min | Permalien

          My pleasure ;)
          Tell me when you have the result, it’s interesting. Good luck with your project !

  2. AlainF
    Publié le 13 juillet 2011 à 13 h 37 min | Permalien

    Bonjour
    J’étais ces jours derniers en train de me demander comment implanter les procédures indiquées sur Mikroe pour le mode veille !
    N’étant pas encore à l’aise avec les librairies Arduino votre travail est une aubaine !!
    De mon côté après avoir suivi les évolutions des librairies successives pour l’ENC28J60 je me suis arrêté à celle qui parait intégrer tout les travaux précedents tout en cherchant à permettre le maximum de lisibilité du code. Je veux parler de celle de Jean Claude Wippler (JeeLabs) .
    http://jeelabs.net/projects/cafe/wiki/EtherCard
    Je viens de lui signaler votre page sur le sujet en lui proposant d’y travailler.
    Cordialement

    • Simon
      Publié le 13 juillet 2011 à 14 h 06 min | Permalien

      Merci pour votre commentaire !
      Je vais également jeter un coup d’œil à la librairie dont vous me faites écho.
      Cordialement.

    • hanz83
      Publié le 11 septembre 2011 à 18 h 38 min | Permalien

      Hi All,
      firstly a big thanks to Simon for good work.
      And here is code rewritten for EtherCard (JeeLabs) library.
      The code changes are only in file enc28j60.cpp :
      ———————————————-
      void enc28j60PowerDown() {
      writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
      while(readRegByte(ESTAT) & ESTAT_RXBUSY);
      while(readRegByte(ECON1) & ECON1_TXRTS);
      writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
      }

      void enc28j60PowerUp() {
      writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
      while(!readRegByte(ESTAT) & ESTAT_CLKRDY);
      }
      ————————————-
      the rest is same just follow above instruction of Simon and instead of EtherShield.* files put the code to EtherCard.*

      For test use this code:
      ether.ES_enc28j60PowerDown();
      Serial.println(« Paused »);
      delay(10000);
      ether.ES_enc28j60PowerUp();
      Serial.println(« Powered up »);
      delay(2000);

      After power up you need call full re-initialisation. I’m using static IP configuration and initialisation from example « getStaticIP.pde » is working correctly.

      P.S. I apologize for my English

      • Simon
        Publié le 11 septembre 2011 à 18 h 42 min | Permalien

        Thanks for your comment !

  3. Christian Nold
    Publié le 13 juillet 2011 à 19 h 39 min | Permalien

    Hi there,

    Thanks for the guide! I think there might be a small mistake In the third code section where you write

    void EtherShield::ES_enc28j60SpiInit(){
    enc28j60SpiInit();
    }

    It should say:

    void EtherShield::ES_enc28j60PowerUp(){
    enc28j60PowerUp();
    }

    I am trying to use this code with a Nanode http://wiki.hackspace.org.uk/wiki/Project:Nanode
    and having the problem after I power down the chip the whole board is frozen. Is anyone else seeing this behaviour?

    best
    Christian

    • Simon
      Publié le 13 juillet 2011 à 19 h 59 min | Permalien

      Yes, you’re totally right : I must have made a mistake while copying-pasting from my source code, I corrected the article. Thanks!
      About your freeze problem, I had this too. After waking up the chip I was not able to use it again, although the leds were blinking, proving the board was physically awaken. To use the board again, I had to set gateway again with es.ES_client_set_gwip(gwip), a function from the ethernet library I used. If you don’t use this library you should give a look at its sources to see what does exactly this function in such a way to emulate it with the library you use. I’m afraid I have no idea about how it’s supposed to work on Nanode board, but since it’s very similar to Arduino platform, I can only suppose it should work as well.

  4. Christian Nold
    Publié le 14 juillet 2011 à 11 h 59 min | Permalien

    Thanks Simon, I can confirm that I managed to get the chip to sleep and wake up again on the Nanode. In my case I found, that to wake it up that I had to do more then the gwip reset. I had to call ethernet_setup_dhcp which did a full re-initalise. Anyway from a temperature of 33C when the chip is running it drops down to about 22C when sleeping which is great.

  5. Christian Nold
    Publié le 14 juillet 2011 à 12 h 05 min | Permalien

    In terms of power reduction when running the Nanode (ENC + Arduino) runs about 220ma when sleeping it drops to 70ma which is basically just the Arduino. (Both these figures are both a bit higher then normal because I have a RFID reader plugged in as well.)

    • Simon
      Publié le 14 juillet 2011 à 13 h 21 min | Permalien

      It’s pretty strange that you have to do something else to correctly wake the chip up. It could be inhere to the wiring differences between our two boards. Could be a network issue too, who knows. I may buy a Nanode in future : they’re perfect for little projects using Arduino + ethernet. Thanks for sharing it.
      Also, thanks for you data about power consumption, I’ll add it to my paper !

  6. Peter
    Publié le 29 octobre 2011 à 15 h 01 min | Permalien

    Hi Simon,

    When playing with my ENC28J60 + Arduino Uno, I came across the same problem mentioned above – i.e. the ENC won’t wake up unless a full Init is done again. When reading the Microchip datasheets, I noticed that there was a step missing from the power down sequence, and another from the power-up sequence. Don’t know if the power-down step makes any difference, but since the power-up step is to turn on the recieve capability, it seems to be important. With the addition of « enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); » to the powerDown so that it now looks like

    void enc28j60PowerDown() {
    enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
    while(enc28j60Read(ESTAT) & ESTAT_RXBUSY);
    while(enc28j60Read(ECON1) & ECON1_TXRTS);
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
    }

    and the addition of  » enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); » to the powerUp function, so it now looks like

    void enc28j60PowerUp() {
    enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
    while(!enc28j60Read(ESTAT) & ESTAT_CLKRDY);
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
    }

    My ENC + Arduino are happily powering down for 60 seconds at a time, powering back up, waiting for a HTTP request and powering back down again for 60 seconds. No other commands needed – no init, no gateway, nothing!

    And for power consumption, my ENC board is consuming approx 150 ma in normal mode, and approx 40 ma when sleeping. I’m sure it would be lower if there won’t a glowing red power led on the board!

    Thanks for the well explained article on how to make this silly chip run cooler when doing nothing!
    Peter

    Peter

    • Simon
      Publié le 29 octobre 2011 à 15 h 20 min | Permalien

      I’m glad this helped you, and thanks a lot for your additional informations,
      I’ll correct my article with those informations, The code will be cleaner without all the re-init stuff when powered up, and faster!

    • Publié le 19 mai 2015 à 11 h 45 min | Permalien

      Hey guys,

      thanks four your nice work. I exactly came across the same problem. My ENC needs 150mA when it’s up and running. I’m also using Ethercard as library for supporting Ethernet protocol. My problem is, that my UNO is used as a webserver. That means that the controller need to answer if a request came in.

      My question is: is there a possibility to raise an interrupt if valid packages (e.g. TCP) arrive? My idea is to catch the interrupt for awaking the ENC and forward the interrupt to the Arduinos external interrupt to awake the controller too.

      Thanks for helping

      Regards
      Raphael

  7. Ricardo
    Publié le 27 novembre 2014 à 23 h 39 min | Permalien

    Thank you for your work. I’m getting my ethernet board running 60 seconds off + 15 seconds on and it is running flawlessly.

Un trackback

  • Par Contrôle de chargeur solaire le 25 mars 2013 à 13 h 21 min

    […] Manuel d’utilisation du chargeur Tracer 2210RN Description des échanges avec la commande MT-5 Spécifications du protocole Modbus Librairie C de calcul de checksum Gestion de l’alimentation du ENC28J60 […]

Laisser un commentaire

Votre e-mail ne sera jamais publié ni communiqué. Les champs obligatoires sont indiqués par *

*
*

Vous pouvez utiliser ces balises et attributs HTML <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>