Disabling Ethernet without freezing

Status
Not open for further replies.

shawn

Well-known member
When Ethernet is initialized in QNEthernet, the Ethernet clock in the the clock gating register CCM_CCGR1 (CG5) is enabled. I know that when a feature on an ARM processor is used without first having its clock enabled, things can freeze.

The issue I'm having is that when I disable Ethernet by turning off the appropriate bits in CCM_CCGR1, the system freezes. Are there specific steps I need to follow so that I can safely disable the clock? Maybe it's something as simple as undoing some of the configuration steps? I'm already disabling the PLL before shutting down the clock, but no luck.

Here's what I'm doing:
Code:
  // Stop the PLL
  CCM_ANALOG_PLL_ENET_SET = CCM_ANALOG_PLL_ENET_BYPASS;
  CCM_ANALOG_PLL_ENET_CLR = CCM_ANALOG_PLL_ENET_ENABLE;
  CCM_ANALOG_PLL_ENET_SET = CCM_ANALOG_PLL_ENET_POWERDOWN;

  // Disable the clock for ENET
  CCM_CCGR1 &= ~CCM_CCGR1_ENET(CCM_CCGR_ON);
 
I solved this by properly removing the netif ext callback (additions and removals were not matched). It doesn’t freeze, but now DHCP can’t get an IP address when Ethernet is restarted.
 
It turned out that the solution to the DHCP issue was to not "detach" or shut down the EventResponder (i.e. it's only "attached" once). When it needs to stop, a Boolean "active" variable is set to false. When it needs to start up again, that variable is set to true and then `triggerEvent()` is called.

Previously, the function was no longer getting called once it was detached and then reattached later. That's why no DHCP requests were getting through. EthernetClass::loop() was never getting called.
 
normally you disable the peripheral before turning off it's clock, also, if your sketch still runs remnants of ethernet code while the peripheral/clocks are disabled, then yes it will crash. You could add registry checks to see if the peripheral is enabled, if not, just return the function with an error, and it *shouldn't* crash.
 
Currently, I'm shutting down the PHY, disabling the PLL (just re-added), and then disabling the ENET clock.
Here's the link to the code (enet_deinit()): https://github.com/ssilverman/QNEth...945996036c3a0665f75829af8/src/lwip_t41.c#L572
Here's the Ethernet.end() function (calls enet_deinit()): https://github.com/ssilverman/QNEth...96036c3a0665f75829af8/src/QNEthernet.cpp#L184

@tonton81 Does this look right to you? Do you suggest any changes, additions, or removals?

Here's my test code showing the procedure doesn't hang (if you try it, get the latest release from GitHub):
Code:
#include <QNEthernet.h>

using namespace qindesign::network;

extern Print *stdPrint;

constexpr uint32_t kDHCPTimeout = 10000;

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 4000) {
    // Wait for Serial to initialize
  }
  stdPrint = &Serial;
  delay(2000);
  printf("Starting...\n");

  Ethernet.onLinkState([](bool state) {
    printf("Link %s\n", state ? "ON" : "OFF");
  });

  Ethernet.onAddressChanged([]() {
    printf("Address changed\n");

    IPAddress ip = Ethernet.localIP();
    printf("    Local IP    = %d.%d.%d.%d\n",
           ip[0], ip[1], ip[2], ip[3]);
    ip = Ethernet.subnetMask();
    printf("    Subnet mask = %u.%u.%u.%u\n",
           ip[0], ip[1], ip[2], ip[3]);
    ip = Ethernet.gatewayIP();
    printf("    Gateway     = %u.%u.%u.%u\n",
           ip[0], ip[1], ip[2], ip[3]);
    ip = Ethernet.dnsServerIP();
    printf("    DNS         = %u.%u.%u.%u\n",
           ip[0], ip[1], ip[2], ip[3]);
  });

  uint8_t mac[6];
  Ethernet.macAddress(mac);
  printf("MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  for (int i = 0; i < 4; i++) {
    Serial.println("Starting Ethernet with DHCP...");
    if (!Ethernet.begin()) {
      Serial.println("Failed to start Ethernet");
      continue;
    }
    if (!Ethernet.waitForLocalIP(kDHCPTimeout)) {
      Serial.println("Failed to get IP address from DHCP");
    }

    printf("Ending Ethernet...\n");
    Ethernet.end();
    printf("Done ending Ethernet.\n");
  }
}

void loop() {
  // Nothing
}
 
Status
Not open for further replies.
Back
Top