LowPowerLab Forum

Hardware support => Moteino => Topic started by: scott216 on December 20, 2017, 01:10:22 PM

Title: Detect Moteino board type at compile time?
Post by: scott216 on December 20, 2017, 01:10:22 PM
I'm modifying w5100.h so I can use a different slave select pin when using a Moteino and Ethernet shield together.  By default they both use D10.  At compile time, is there a way to distinguish if the board selected is a Moteino?  This is already done with some boards in w5100.h with this code.

    #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      inline static void initSS()    { DDRB  |=  _BV(4); };
      inline static void setSS()     { PORTB &= ~_BV(4); };
      inline static void resetSS()   { PORTB |=  _BV(4); };
    #elif defined(__AVR_ATmega32U4__)
      inline static void initSS()    { DDRB  |=  _BV(6); };
      inline static void setSS()     { PORTB &= ~_BV(6); };
      inline static void resetSS()   { PORTB |=  _BV(6); };
    #elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__)
      inline static void initSS()    { DDRB  |=  _BV(0); };
      inline static void setSS()     { PORTB &= ~_BV(0); };
      inline static void resetSS()   { PORTB |=  _BV(0); };
    #else
      inline static void initSS()    { DDRB  |=  _BV(2); };
      inline static void setSS()     { PORTB &= ~_BV(2); };
      inline static void resetSS()   { PORTB |=  _BV(2); };
    #endif



I'd like to add a Moteino specific #elif block that would work for Moteino and MoteinoMega if possible.

--Scott


Title: Re: Detect Moteino board type at compile time?
Post by: TomWS on December 20, 2017, 03:19:22 PM
I don't have the specifics handy, but, when you select the board in the IDE, it sets environment variables based on what is in the boards.txt file for that particular platform.  So... if you look in the Moteino Boards file, you should find the prefix that's being used.

Sorry I can't be more specific...
Tom
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 20, 2017, 03:49:15 PM
I checked my boards.txt file and Moteino isn't in there, but it does show up in the boards drop down.  Maybe the IDE is using the json link for the Moteino info and not boards.txt

https://lowpowerlab.github.io/MoteinoCore/package_LowPowerLab_index.json

Title: Re: Detect Moteino board type at compile time?
Post by: TomWS on December 20, 2017, 04:15:40 PM
It will be in a folder where platform specific packages reside.
On a windows system it is something like:
C:\Users\<yourUserName>\AppData\Local\Arduino15\packages\arduino\hardware\Moteino

But I think the macro you're looking for is:
AVR_MOTEINO

Tom
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 20, 2017, 04:37:44 PM
Thanks Tom. 

I still didn't find the boards.txt, but I did find a forum link where they list the moteino info for boards.txt
https://lowpowerlab.com/forum/moteino/timing-using-8mhz/msg13837/#msg13837
The last line of the moteino section reads:
MoteinoLP.build.board=AVR_MOTEINO

Assuming you're right about AVR_MOTEINO macro, how would I check for the Moteino board?

--Scott
Title: Re: Detect Moteino board type at compile time?
Post by: Felix on December 21, 2017, 08:36:10 AM
Scott,
I don't have a quick answer but are you just looking to switch between boards quickly?
I have had this problem too for many years (switching between boards a lot when testing them), using the menus for serial port and boards is a pain and terrible time waste.
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 21, 2017, 01:21:57 PM
I want the program to compile differently when a Moteino is selected.  Specifically I want the Ethernet and w5100 libraries to use a different slave select pin for Ethernet communication.  The default Ethernet SS pin D10, but this is also the pin Moteino uses for the radio SS.  So, in order to use the Moteino with an Ethernet board, I have to force it Ethernet library to use a different SS pin.

Currently, in the w5100.h file, there's code like this:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      inline static void initSS()    { DDRB  |=  _BV(4); };
      inline static void setSS()     { PORTB &= ~_BV(4); };
      inline static void resetSS()   { PORTB |=  _BV(4); };
    #elif defined(__AVR_ATmega32U4__)
      inline static void initSS()    { DDRB  |=  _BV(6); };
      inline static void setSS()     { PORTB &= ~_BV(6); };
      inline static void resetSS()   { PORTB |=  _BV(6); };
    #elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__)
      inline static void initSS()    { DDRB  |=  _BV(0); };
      inline static void setSS()     { PORTB &= ~_BV(0); };
      inline static void resetSS()   { PORTB |=  _BV(0); };
    #else
      inline static void initSS()    { DDRB  |=  _BV(2); };
      inline static void setSS()     { PORTB &= ~_BV(2); };
      inline static void resetSS()   { PORTB |=  _BV(2); };
    #endif


Both Moteino's fall into the #else group.  I'd prefer only the Moteino's are compiled differently.  Ideally I'd want something like this:


    #elif defines (__MOTEINO__)
        // Code to set Moteino SS Pin
    #else
      inline static void initSS()    { DDRB  |=  _BV(2); };
      inline static void setSS()     { PORTB &= ~_BV(2); };
      inline static void resetSS()   { PORTB |=  _BV(2); };
    #endif


There's other library changes too, but this gives you an idea of what I'm trying to do. 
Title: Re: Detect Moteino board type at compile time?
Post by: Felix on December 22, 2017, 09:39:18 AM
Understood. Only, there are 2 main MCUs on Moteinos, the 328p, and the 1284p. So you'd need a combination of __MOTEINO__ and the MCU (__AVR_ATmegaXXXX__) to really tell which it is. Or the __MOTEINO__ would require more info on the MCU, like __MOTEINO_328P__ / __MOTEINO_1284P__.
This has been asked for before so I will keep it in mind for a future mod to the Moteino core. If anyone has already done and tested something like this, let me know.
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 22, 2017, 04:35:02 PM
Either way would work fine

#if defined(__AVR_ATmega1284P__) && defined(__MOTEINO__)
#elif defined(__AVR_ATmega328P__) && defined(__MOTEINO__)

or

#if defined(__MOTEINO_1284P_)
#elif defined(__MOTEINO_328P_)


I'm gonna be switching my project over to the MoteinoMega.  I'm a bit low on memory and my sketch keeps hanging after a few hours or days (it varies). I don't think I have anything else that uses a 1284p CPU, so just checking the CPU should be okay for now.

For the MoteinoMega, the radio SS pin uses D4. In w5100 it looks like be default Ethernet SS would assigned to use Port B, bit #2. I looked at the MoteinoMega schematic and it looks like that's pin D2.  Is that correct?
Title: Re: Detect Moteino board type at compile time?
Post by: Felix on December 26, 2017, 03:20:59 PM
Quote from: scott216 on December 22, 2017, 04:35:02 PM
For the MoteinoMega, the radio SS pin uses D4. In w5100 it looks like be default Ethernet SS would assigned to use Port B, bit #2. I looked at the MoteinoMega schematic and it looks like that's pin D2.  Is that correct?

Yes. D2 is used by the radio module interrupt.
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 26, 2017, 03:45:39 PM
So, if I use a Moteino Mega with the Ethernet library, I won't have a conflict where they both use the same SS pin.
Title: Re: Detect Moteino board type at compile time?
Post by: perky on December 26, 2017, 08:01:08 PM
Quote from: Felix on December 26, 2017, 03:20:59 PM
Yes. D2 is used by the radio module interrupt.
So in other words D2 can't be used for SS on the ethernet, onother SS pin would need to be selected. I assume the ethernet also has an interrupt. This is going to get complicated if the ethernet and radio share the same SPI port and both are interrupt driven and both try to access the SPI their ISRs (unless I've misunderstood, I'm assuming a Moteino and ethernet would be used together).

Mark.
Title: Re: Detect Moteino board type at compile time?
Post by: Felix on December 26, 2017, 08:58:30 PM
The D2 on MoteinoMEGA (digital pin 2) cannot be used by anything else when there is a radio module installed on it.
You will need to use another SPI CS/SS pin in the Ethernet library.
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 26, 2017, 11:48:46 PM
Thanks.  I was thinking that I could use D2 for Ethernet slave select since Moteino uses D4.  But I see the Moteino radio needs D2 for an interrupt. I can modify the w5100.h library so Ethernet uses a free pin.  I'm doing that now with the Moteina and and Ethernet board. The problem I'm having is it hangs after a while.  It's usually good for 1/2 day to a couple days.  I'm using most of the memory on the Moteino, so I'm hoping that if I switch to a Moteino Mega, it will stop hanging. 

--Scott
Title: Re: Detect Moteino board type at compile time?
Post by: perky on December 27, 2017, 10:40:51 AM
I suspect this is down to SPI being a shared resource and during an SPI access for one device it is interrupted by the other device which then tries to use the same resource. You woud need to put some protection mechanisms in there to prevent it, for example disabling the interrupt for the other device while the SPI is being used. If the radio library ISR only sets a flag rather than accessing the SPI, and all accesses to SPI for the radio are done in the main loop, then you may get away with simply disabling the ethernet interrupt during those accesses. You'd need to look carefully at what the code is doing, but hanging like this is typical of this type of problem.

Mark.
Title: Re: Detect Moteino board type at compile time?
Post by: Felix on December 27, 2017, 02:24:11 PM
Ethernet lib hanging and tandem with RFM69 has been discussed on several occasions in the forum, I don't have a link offhand but if you search, I think some folks posted solutions and perhaps forks of the lib(s), maybe some good stuff there.
Title: Re: Detect Moteino board type at compile time?
Post by: scott216 on December 27, 2017, 08:02:44 PM
Quote from: perky on December 27, 2017, 10:40:51 AM
I suspect this is down to SPI being a shared resource and during an SPI access for one device it is interrupted by the other device which then tries to use the same resource. You woud need to put some protection mechanisms in there to prevent it, for example disabling the interrupt for the other device while the SPI is being used. If the radio library ISR only sets a flag rather than accessing the SPI, and all accesses to SPI for the radio are done in the main loop, then you may get away with simply disabling the ethernet interrupt during those accesses. You'd need to look carefully at what the code is doing, but hanging like this is typical of this type of problem.

Mark.

You're entering territory that's above my pay grade. I'm not very well versed in interrupts and I have no idea what the Ethernet and Radio libraries are doing behind the scenes with interrupts.  I do use the watchdog timer library to reboot if it hangs, but I have to disable the WDT when I'm using the radio because it takes so long. I'm thinking I might be better not having the Ethernet library running on my Moteine.  Instead get a 2nd Arduino device or RPi and send the data to it via I2C.  Then the 2nd device would run Ethernet.

BTW - The Moteino is listening to weather station data from my Davis weather station.  Getting new data from the weather station normally takes about 2.5 seconds, but every once in a while I get a CRC error and then it take about 70 seconds to get.
Title: Re: Detect Moteino board type at compile time?
Post by: perky on December 28, 2017, 05:15:59 PM
If your watchdog timer is timing out it implies there's blocking code in your main loop (by that I mean you are waiting in a loop for an external event to happen before moving to the next instruction). I'm not sure of the ethernet library but it may well have functions that need to be called regularly in a timely fashion.  Are you polling receiveDone() in a loop and waiting for it to be become active?

Mark.
Title: Sketch hanging
Post by: scott216 on December 28, 2017, 05:39:04 PM
Quote from: perky on December 28, 2017, 05:15:59 PM
If your watchdog timer is timing out it implies there's blocking code in your main loop (by that I mean you are waiting in a loop for an external event to happen before moving to the next instruction). I'm not sure of the ethernet library but it may well have functions that need to be called regularly in a timely fashion.  Are you polling receiveDone() in a loop and waiting for it to be become active?

Mark.

Every 30 seconds, from loop() I'm calling this routine to upload data to Weather Underground.  I time how long it takes to upload to weather underground, and it's usually a couple seconds.  I've got the WDT set to timeout at 8 seconds.  From what I can tell, the sketch usually locks up when the radio is busy doing something.  I think there's some frequency hopping stuff that occasionally takes a while.  I didn't write the library for the radio, so I don't know much about how it works behind the scenes.



//=============================================================================
// Upload to Weather Underground
//=============================================================================
bool uploadWeatherData()
{
  uint32_t uploadApiTimer = millis();  // Used to time how long it takes to upload to WU
 
  wdt_reset();

  // Send the Data to weather underground
  if (client.connect(g_server, 80))
  {
    #ifdef PRINT_DEBUG_WU_UPLOAD
      Serial.print(F("Connected to: "));
      Serial.println(g_server); 
    #endif
   
    client.print("GET /weatherstation/updateweatherstation.php?ID=");
    client.print(WUNDERGROUND_STATION_ID);
    client.print("&PASSWORD=");
    client.print(WUNDERGROUND_PWD);
    client.print("&dateutc=now");
    client.print("&winddir=");
    client.print(g_windDirection_Avg);
    client.print("&windspeedmph=");
    client.print(g_windSpeed);
    client.print("&windgustmph=");
    client.print(g_windgustmph);
    client.print("&tempf=");
    client.print((float)g_outsideTemperature / 10.0);
    client.print("&rainin=");
    client.print(g_rainRate); 
    client.print("&dailyrainin="); 
    client.print("&softwaretype=Arduino%20Moteino");
    client.print(VERSION);
    client.print("&action=updateraw");
    client.print("&realtime=1&rtfreq="); 
    client.print(UPLOAD_FREQ_SEC);       
    client.println("/ HTTP/1.1\r\nHost: host:port\r\nConnection: close\r\n\r\n");
  }
  else
  {
    #ifdef PRINT_DEBUG_WU_UPLOAD
      Serial.println(F("\nWU connection failed"));
    #endif
    client.stop();
    delay(500);
    return false;
  }
 
  uint32_t lastRead = millis();
  uint32_t connectLoopCounter = 0;  // used to timeout ethernet connection
  wdt_reset();

  while (client.connected() && (millis() - lastRead < 1000))  // wait up to one second for server response
  {
    while (client.available())
    {
      char c = client.read();
      connectLoopCounter = 0;  // reset loop counter
      #ifdef PRINT_DEBUG_WU_UPLOAD
        Serial.print(c); 
      #endif
    } 
   
    connectLoopCounter++;
    // if more than 10000 loops since the last packet, then timeout
    if( connectLoopCounter > 10000L )
    {
      client.stop();
      #ifdef PRINT_DEBUG_WU_UPLOAD
        Serial.print(F("\n\nEthernet Timeout. Waited "));
        Serial.print((long)(millis() - uploadApiTimer));
        Serial.println(F(" mS"));
      #endif
      return false;
    }   
  }  // end while (client.connected() )
 
  wdt_reset();
 
  client.stop();

  #ifdef PRINT_DEBUG_WU_UPLOAD
    if ( (long)(millis() - uploadApiTimer) > 1500 )
    {
      Serial.print(F("WU upload took (mS): "));
      Serial.println((long)(millis() - uploadApiTimer));
    }
  #endif
 
  wdt_reset();

  return true;
 
}