0

Adafruit PCF8523 - interferring with Wire.onReceive event?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Adafruit PCF8523 - interferring with Wire.onReceive event?

by RobMohr on Wed Jun 13, 2018 6:15 pm

I am setting up an Adafruit Metro M0 Express as an I2C slave which receives a float (Garmin LIDAR-Lite distance) from another Arduino board (Arduino Uno Genuino). The Metro acts as a web server over WiFi (Adafruit WINC1500 WiFi shield) to display the data arriving over I2C. An Adafruit RTC PCF8523 will be used to generate timestamps. The RTC will be adjusted periodically via NTP over UDP via WiFi. Data received via the I2C master will be stored on the on-board SD card on the WiFi shield.

I have tested most of the pieces seperately, however I have run into a problem with the Wire.onReceive event, established to identify when data is received from the I2C master, ceasing to function properly when I enable the RTC code.

The code (with RTC related code commented out) is as follows:

Code: Select all | TOGGLE FULL SIZE
//
// WiFi Web server display of LIDAR-Lite data (float) recieved via I2C master
// Web-based control of LED via PIN 9
// PCF8523 RTC with adjustment via UDP over WiFi - Currently disabled due to interrupt conflict
// SD logging to WiFi shield w/timestamp - Currently not implemented
// I2C Slave: Adafruit Metro M0 Express, Adafruit WINC1500 WiFi shield, RTC PFC8523
// I2C master: Arduino Uno, LCD Keypad shield, Lidar-Lite

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include "I2C_Anything.h"
#include "arduino_secrets.h"

//#include "RTClib.h"
//#include <SD.h>

const byte MY_ADDRESS = 2;                                                        // Local I2C address
const int NTP_PACKET_SIZE = 48;                                                   // NTP time stamp is in the first 48 bytes of the message
//const int chipSelect = 4;                                                       // CS for SD card
const char* ntpServerName = "time.nist.gov";
char ssid[] = SECRET_SSID;                                                        // Network SSID (name)
char pass[] = SECRET_PASS;                                                        // Network password (use for WPA, or use as key for WEP)
//char filename[] = "00000000.CSV";
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday",
                             "Thursday", "Friday", "Saturday"};
int keyIndex = 0;                                                                 // Network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
int lastTime = -1;
int lastTime2 = -1;
unsigned int localPort = 8888;                                                    // Local port to listen for UDP packets
byte packetBuffer[ NTP_PACKET_SIZE];                                              // Buffer to hold incoming and outgoing packets
volatile boolean haveData = false;
volatile float length;

IPAddress timeServerIP;                                                           // time.nist.gov NTP server address
WiFiServer server(80);                                                            // Web server address
WiFiUDP udp;
//RTC_PCF8523 rtc;

void setup()
{
  Wire.begin(MY_ADDRESS);                                                         // Join i2c bus with address #8
  Wire.onReceive(receiveEvent);                                                   // Register event for I2C communications (Arduino to Arduino)
  Serial.begin(57600);                                                            // initialize serial communication
  pinMode(9, OUTPUT);                                                             // Set the LED control to PIN 9, output
  if (WiFi.status() == WL_NO_SHIELD)                                              // Check for the presence of the Adafruit WINC1500 WiFi shield
  {
    Serial.println("WiFi shield not present");
    while (true);                                                                 // don't continue
  }
  while ( status != WL_CONNECTED)                                                 // attempt to connect to WiFi network:
  {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                                                         // Print the network name (SSID);
    status = WiFi.begin(ssid, pass);                                              // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    delay(10000);                                                                 // Wait 10 seconds for connection:
  }
  printWiFiStatus();                                                              // Connected, so print out the status
  getNTPTime();
//  initializeRTC();
  server.begin();                                                                 // Start the web server on port 80
}

void loop()
{
  WiFiClient client = server.available();                                         // listen for incoming clients
  if (client)                                                                     // if you get a client
  {
    Serial.println("Incoming HTTP client");                                       // print a message out the serial port
    String currentLine = "";                                                      // make a String to hold incoming data from the client
    while (client.connected()) {                                                  // loop while the client's connected
      if (client.available()) {                                                   // if there's bytes to read from the client,
        char c = client.read();                                                   // read a byte, then
        Serial.write(c);                                                          // print it out the serial monitor
        if (c == '\n') {                                                          // if the byte is a newline character
                                                                                  // if the current line is blank, you got two newline characters in a row.
                                                                                  // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0)
          {
                                                                               
                                                                               
            client.println("HTTP/1.1 200 OK");                                    // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            client.println("Content-type:text/html");                             // Send a content-type so the client knows what's coming
            client.println("Connection: close");                                  // the connection will be closed after completion of the response
            client.println("Refresh: 5");                                         // refresh the page automatically every 5 sec
            client.println();                                                     // Blank line
                                                                                  // the content of the HTTP response follows the header:
                                                                               
            client.print("<br>Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>");
            if (haveData)
            {
              client.print("<br>LIDAR-Lite distance = ");
              client.print(length);
              haveData = false;
            }                                                                     // end if haveData
                                                                                  // The HTTP response ends with another blank line:
            client.println();
                                                                                  // break out of the while loop:
            break;
          }
          else {                                                                  // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {                                                     // if you got anything else but a carriage return character,
          currentLine += c;                                                       // add it to the end of the currentLine
        }
                                                                                  // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);                                                  // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                                                   // GET /L turns the LED off
        }
      }
    }
                                                                                     
    client.stop();                                                                // close the connection:
    Serial.println("client disconnected");
  }
}

void printWiFiStatus()
{
 
  Serial.print("SSID: ");                                                         // print the SSID of the network you're attached to
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();                                                 
  Serial.print("IP Address: ");                                                   // print your WiFi shield's IP address
  Serial.println(ip);
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");                                        // print the received signal strength:
  Serial.print(rssi);
  Serial.println(" dBm");
  Serial.print("To view server, open a browser at http://");                      // print where to go in a browser:
  Serial.println(ip);
}

void receiveEvent (int howMany)                                                   // called by interrupt service routine when incoming data arrives
{
  if (howMany >= (sizeof length))
  {
    I2C_readAnything (length);
    haveData = true;
  }                                                                               // end if have enough data
}                                                                                 // end of receiveEvent

unsigned long sendNTPpacket(IPAddress& address)                                   // send an NTP request to the time server at the given address
{
  Serial.println("sending NTP packet...");
                                                     
  memset(packetBuffer, 0, NTP_PACKET_SIZE);                                       // set all bytes in the buffer to 0
                                                                                  // Initialize values needed to form NTP request
                                                                                  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;                                                   // LI, Version, Mode
  packetBuffer[1] = 0;                                                            // Stratum, or type of clock
  packetBuffer[2] = 6;                                                            // Polling Interval
  packetBuffer[3] = 0xEC;                                                         // Peer Clock Precision
                                                                                  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

                                                                                  // all NTP fields have been given values, now
                                                                                  // you can send a packet requesting a timestamp:
  udp.beginPacket(address, 123);                                                  //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

void getNTPTime()
{
  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(localPort);
  WiFi.hostByName(ntpServerName, timeServerIP);
  sendNTPpacket(timeServerIP);                                                                  // send an NTP packet to a time server                                                                                         
  delay(2000);                                                                                  // wait to see if a reply is available
  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }
  else {
    Serial.print("packet received, length=");                                                   // We've received a packet, read the data from it
    Serial.println(cb);
                                                                                               
    udp.read(packetBuffer, NTP_PACKET_SIZE);                                                    // Read the packet into the buffer                                               
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);                          // The timestamp starts at byte 40 of the received packet and is four bytes,
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);                           // or two words, long. First, extract the two words:                                                                                         
    unsigned long secsSince1900 = highWord << 16 | lowWord;                                     // Combine the four bytes (two words) into a long integer
    Serial.print("Seconds since Jan 1 1900 = " );                                               // This is NTP time (seconds since Jan 1 1900):
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");                                                                                         
    const unsigned long seventyYears = 2208988800UL;                                            // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:                                                                                   
    unsigned long epoch = secsSince1900 - seventyYears;                                         // subtract seventy years:                                                                                     
    Serial.println(epoch);                                                                      // print Unix time:

    // print the hour, minute and second:
   
    Serial.print("The UTC time is ");                                                           // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600);                                                     // print the hour (86400 equals secs per day)
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 )
    {                                                                                         
      Serial.print('0');                                                                        // In the first 10 minutes of each hour, we'll want a leading '0'
    }
    Serial.print((epoch  % 3600) / 60);                                                         // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ( (epoch % 60) < 10 )
    {                                                             
      Serial.print('0');                                                                        // In the first 10 seconds of each minute, we'll want a leading '0'
    }
    Serial.println(epoch % 60);                                                                 // print the second
    Serial.print("Pacific time is ");                                                           // UTC is the time at Greenwich Meridian (GMT)
    Serial.print(((epoch  % 86400L) / 3600) - 7);                                               // print the hour (86400 equals secs per day)
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 )
    {
      Serial.print('0');                                                                        // In the first 10 minutes of each hour, we'll want a leading '0'
    }
    Serial.print((epoch  % 3600) / 60);                                                         // print the minute (3600 equals secs per minute)
    Serial.print(':');
    if ( (epoch % 60) < 10 )
    {
      Serial.print('0');                                                                        // In the first 10 seconds of each minute, we'll want a leading '0'
    }
    Serial.println(epoch % 60);                                                                 // print the second
  }
}

//void initializeRTC()
//{
//  if (! rtc.begin())
//  {
//    Serial.println("Couldn't find RTC");
//  }
//  if (! rtc.initialized()) {
//    Serial.println("RTC is NOT running!");
//    // following line sets the RTC to the date & time this sketch was compiled
//    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
//    // This line sets the RTC with an explicit date & time, for example to set
//    // January 21, 2014 at 3am you would call:
//    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//  }
//}


As soon as I un-comment the RTC code, I no longer get any values received over I2C from the master. It acts like the event callback is disabled.

I checked the RTC library and verified that the I2C address used for the RTC is 68, which does not conflict with any of the other devices (Metro (2), Arduino (1), LIDAR-Lite (62)) communicating on the I2C bus.

Any assistance with identifying why the event callbacks are broken when using the RTC would be greatly appreciated.

Rob

PS: I could include code running on the I2C master, however it is also using the I2C_Anything.h code written by Nick Gammon to put the float on the I2C bus.

Code: Select all | TOGGLE FULL SIZE
// Written by Nick Gammon
// May 2012

#include <Arduino.h>
#include <Wire.h>

template <typename T> int I2C_writeAnything (const T& value)
 {
   const byte * p = (const byte*) &value;
   unsigned int i;
   for (i = 0; i < sizeof value; i++)
         Wire.write(*p++);
   return i;
 }  // end of I2C_writeAnything

template <typename T> int I2C_readAnything(T& value)
 {
   byte * p = (byte*) &value;
   unsigned int i;
   for (i = 0; i < sizeof value; i++)
         *p++ = Wire.read();
   return i;
 }  // end of I2C_readAnything

RobMohr
 
Posts: 1
Joined: Tue Jun 12, 2018 8:20 pm

Please be positive and constructive with your questions and comments.