chipKIT® Development Platform

Inspired by Arduino™

Max32 with Ethernet Shield -- Link State detectable?

Created Tue, 28 Feb 2012 08:12:10 +0000 by owendelong


owendelong

Tue, 28 Feb 2012 08:12:10 +0000

I'm admittedly relatively new to micro controllers (about 3 weeks of experience so far) and even newer to the PIC and Max32 (started with Arduino and am evaluating the Max32 as a possible alternative).

One thing I like about the Max32 is that the on-board ethernet is just that, an ethernet chip, not a TCP/IPv4 chip like the W5100. (I want to dual-stack my application eventually).

At the moment, I'm just trying to do the basics. First, I want Ethernet.begin (from chipKITEthernet) to return a value indicating whether initialization succeeded or not.

I figured out how to patch the library to return success or failure based on the DHCP Bind state, but what I would like to do is, in the case where DHCP is not used, read the Ethernet Link State and return failure if there is no link present and success if link is present.

It is not super important for my application to be attached to the network, but, it is important not to spend a lot of time trying to initialize the ethernet and/or connect to the server if there is no link present.

I looked through this: ... Had to delete the link to Digilent Shield documentation because the BB thought it was spam ...

And it didn't tell me much.

I looked through this: ... Had to delete the link to PIC32MX Datasheet because BB thought it was spam...

And it seems to indicate that one of the MII registers contains a LINKFAIL bit.

It refers to this:

... Had to delete the link to Chapter 35 of the PIC32MX reference manual because BB thought it was spam...

For more data. Reading through that, I found page 48 (technically 35-48) of that document (chapter 35 of the PIC32 reference manual) does, indeed, indicate that there is a way to tell the MIIM module to scan the MII status registers to continuously detect LINK Fail states.

Page 35-52 indicates that there is a bit which is set/cleared by the MIIM when scanning indicating LINK FAIL conditions in the EMAC1MIND register.

However, in the software, I can't find any definition for the EMAC1MIND register and it's not clear to me how I go about reading this bit.

(I'm not really a hardware or device driver guy, but I am learning. That's probably obvious. So please, no "just read the data sheet" comments. I've tried. If it's in there, I don't understand it and am asking for help to do so.)

Thanks,

Owen


owendelong

Tue, 28 Feb 2012 08:13:26 +0000

Shield reference page:

http://digilentinc.com/Data/Products/CHIPKIT-NETWORK-SHIELD/chipKIT%20Network%20Shield_rm.pdf

PIC32MX Datasheet: http://www.sparkfun.com/datasheets/Components/SMD/PIC32MX.pdf

PIC32MX Reference Manual Chapter 35: http://ww1.microchip.com/downloads/en/DeviceDoc/61155B.pdf


owendelong

Tue, 28 Feb 2012 08:14:46 +0000

Interestingly, by turning off auto parsing I was able to put the URLs into the second message, so, they are there for reference if they are helpful to anyone trying to answer my question.


MarkHoskins

Tue, 28 Feb 2012 17:16:00 +0000

On the Max32 the utitlity/ETHPIC32IntMac.c file defines the MAC interface. In this file there is a static integer _linkPresent, I don't know if this matches the criteria you are expecting of a link, but it has a similar name.

I wanted to poll the status of the link ( Made a promiscuous mode for this library ), so I externed _linkPresent in the MAC.H file and made it not static in ETHPIC32IntMac.c.

Then I could just print it out.


owendelong

Tue, 28 Feb 2012 19:14:53 +0000

This seems to always contain 1 regardless of the state of the Phy (cable connected and link detected or cable disconnected and no link).

#include <chipKITEthernet.h>
extern int _linkPresent;

void setup() {
  Serial.begin(9600);
  Serial.print("Initializing...");
  (int) Ethernet.begin();                                   // DHCP is used, default ENCX24J600 (ENC24J60) MAC address 

  delay(1000);
  Serial.println("Initialized.");
}

void loop()
{
  if(_linkPresent)
  {
    Serial.print("Link: UP -> ");
    Serial.println(_linkPresent, HEX);
  } else {
    Serial.println("Link: DOWN");
  }
  delay(500);
}

All I get is a constant string of "Link: UP -> 1" lines. Thanks for trying anyway. Hopefully someone more familiar with the actual chipsets involved has an answer.


MarkHoskins

Tue, 28 Feb 2012 19:58:37 +0000

Sorry if this is once again, not useful, but there exists a MACIsLinked function in MAC.h. I exposed this to the Ethernet class and called it, and when the ethernet cable wasn't plugged (and powered ) in it would be false, true otherwise.

It requires that the Ethernet initialization has already taken place and the periodic processing has been called.. unfortunately.

But I think you can call EthPhyGetLinkStatus( 0 ) ( Defined in ETHPIC32ExtPhy.h ) directly then & it with ETH_LINK_ST_UP manually.

This reads the MIIM register PHY_REG_BMSTAT.

I'm pretty much a software guy too, but it seems like this should work? You just want a boolean that basically indicates that the lights are blinking right?


owendelong

Tue, 28 Feb 2012 20:19:59 +0000

Yes, you are correct about my goal. I'm now trying to figure out how to get the MAC functions linked into my program.

(The file on my system is utility/ETHPIC32IntMac.c and there is o corresponding .h).

Unfortunately, I'm not much of a C/C++ guy (mostly I manage routers in their own configuration languages and my programming has been mostly in PERL, PHP, etc.), so these various interfaces between C++ classes and underlying C stuff get into linguistic esoterica that baffles me.

It does look like that function will do what I want if I can get it exported.

It boggles my mind as to why the developers didn't export it by default since it seems like it would be a very useful thing to have in many applications.


MarkHoskins

Tue, 28 Feb 2012 20:28:14 +0000

It is pretty tricky. Much more complicated than the Arduino libraries for the Wiznet5100.

But of course, this is a software stack.


owendelong

Tue, 28 Feb 2012 20:36:40 +0000

I found the function (and the underlying "TCPIP Stack/Mac.h" file). If you could provide any advice or recipe on how to expose it to C++, I think that will do what I need.


owendelong

Tue, 28 Feb 2012 20:47:23 +0000

Actaully, adding this:

extern "C" bool MACIsLinked();

To my program seems to have exported it to my code so that's now working.

Unfortunately, it doesn't wasn't updating.

Turns out that call to Ethernet.PeriodicTasks(); matters. That made it detect link down-ness.

However, after plugging the cable back in, it doesn't appear to re-attempt auto-negotiation. or detect link state. So, I'm on the right track and at least I can reliably detect that the link went away. Now I just need to figure out how to see if it came back.


MarkHoskins

Tue, 28 Feb 2012 20:56:00 +0000

I think a problem here is that it will break any sort of multi-hardware compatibility that the library had. But, I don't care about that because I'm not designing the library, so here's how I would go about it:

extern "C"

Add something like that to chipKitEthernet.cpp, at the top.

Then, anywhere in the CPP file, you should be able to do this:

EthPhyGetLinkStatus(0) & ETH_LINK_ST_UP;

Which should be the status of the link.

EDIT: Oh you posted already. Mine will poll the register directly, so I don't think that periodic processing needs to be running for it to work. But it compromises hardware independence, so there is that.


owendelong

Tue, 28 Feb 2012 21:12:15 +0000

Got it!!

#include <chipKITEthernet.h>

extern "C" bool MACIsLinked();
extern "C" void StackInit();
void setup() {
  Serial.begin(9600);
  Serial.print("Initializing...");
  (int) Ethernet.begin();                                   // DHCP is used, default ENCX24J600 (ENC24J60) MAC address 
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("Initialized.");
}

void loop()
{
  static unsigned long int then;
  if(MACIsLinked())
  {
    Serial.print("Link: UP -> ");
    Serial.println((int)MACIsLinked, HEX);
  } else {
    Serial.println("Link: DOWN");
    if (millis()-then > 5000)  // Retry every 5 seconds
    {
      StackInit();
      then = millis();
    }
  }
  delay(500);
  Ethernet.PeriodicTasks();
}

If you call StackInit too often, it will prevent the initialization from completing (Takes approximately 1 second reliably... a delay of 1000ms would come up correctly about 50% of the time).


MarkHoskins

Tue, 28 Feb 2012 21:16:22 +0000

I would think this line would print out some weird stuff:

Serial.println((int)MACIsLinked, HEX);

Shouldn't it be

Serial.println((int)MACIsLinked(), HEX);

Unless you want it to print out some sort of weird pointer to the function.

Anyway, glad you could get it working!


owendelong

Tue, 28 Feb 2012 21:32:39 +0000

Yes, you are correct.

Frankly, once it started accurately detecting whether the cable was plugged in or not, I sort of stopped debugging. ;-)