NMEA2000 icon indicating copy to clipboard operation
NMEA2000 copied to clipboard

Two Nodes on one Network

Open TyphoonSB opened this issue 4 years ago • 16 comments

Hello Together,

I have a Simrad GO7 XSR Chart Plotter..... and I have two nodes created by my own on an ESP8266....

1st is sending a Heading Signal 2nd is sending Humanity and Teperaturs

Strange is that the GO7 is not showing both on the correct way if both nodes are connected to the bus (see pictures) Name of Node is most like --------- and both nodes are shown together ....

Code1:


#include <Arduino.h>

#include <EEPROM.h>
#define USE_MCP_CAN_CLOCK_SET 8
#define N2k_SPI_CS_PIN 15
#include <NMEA2000_CAN.h>
#include <N2kMessages.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#define ONE_WIRE_BUS 2
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <Wire.h>
#include "DFRobot_SHT20.h"

DFRobot_SHT20    sht20;

#ifndef STASSID
#define STASSID "ssid"
#define STAPSK  "password"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;



const int SPI_CS_PIN = 15;

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

#define RapidDataUpdatePeriod 2000 //167 // Some strange periot to cause Slow and rapid to run unsync.


// List here messages your device will transmit.
const unsigned long TemperatureTransmitMessages[] PROGMEM={130316L,0};
const unsigned long HumidityTransmitMessages[] PROGMEM={130313L,0};


#define DEV_TEMP 0
#define DEV_HUMI 1

void setup() {
  
 Serial.begin(115200);
 EEPROM.begin(512);
 
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  int count;
  EEPROM.get(0 ,count);
  Serial.print("Boot Counter: ");
    Serial.println(count);
  
  while (WiFi.waitForConnectResult() != WL_CONNECTED && count <= 10) {
    Serial.println("Connection Failed! Rebooting...");
    count++;
    EEPROM.put(0, count);
    EEPROM.commit();
    delay(5000);
    ESP.restart();
  }
  EEPROM.put(0, 0);
  EEPROM.commit();


sht20.initSHT20();
delay(100);
    sht20.checkSHT20();


  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
     ArduinoOTA.setHostname("SB Environmental");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
     ArduinoOTA.setPasswordHash("hash");
     
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  


  

  
   // Reserve enough buffer for sending all messages. This does not work on small memory devices like Uno or Mega
  NMEA2000.SetN2kCANSendFrameBufSize(450);
  // Set Product information
  
NMEA2000.SetDeviceCount(2); // Enable multi device support for 2 devices
  
  NMEA2000.SetProductInformation("00000002", // Manufacturer's Model serial code
                                 102, // Manufacturer's product code
                                 "SB_Temperatur",  // Manufacturer's Model ID
                                 "V1.0",  // Manufacturer's Software version code
                                 "V1.0", // Manufacturer's Model version
                                 0xff, // load equivalency - use default
                                 0xffff, // NMEA 2000 version - use default
                                 0xff, // Sertification level - use default
                                 DEV_TEMP
                                 );
  NMEA2000.SetProductInformation("00000003", // Manufacturer's Model serial code
                                 103, // Manufacturer's product code
                                 "SB_Humidity",  // Manufacturer's Model ID
                                 "V1.0",  // Manufacturer's Software version code
                                 "V1.0", // Manufacturer's Model version
                                 0xff, // load equivalency - use default
                                 0xffff, // NMEA 2000 version - use default
                                 0xff, // Sertification level - use default
                                 DEV_HUMI
                                 );
  // Set device information
  NMEA2000.SetDeviceInformation(00000002, // Unique number. Use e.g. Serial number.
                                130, // Device function=Analog to NMEA 2000 Gateway. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                75, // Device class=Inter/Intranetwork Device. See codes on  http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                1857, // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf                               
                                4, // Marine
                                DEV_TEMP
                               );
NMEA2000.SetDeviceInformation(00000003, // Unique number. Use e.g. Serial number.
                                170, // Device function=Analog to NMEA 2000 Gateway. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                75, // Device class=Inter/Intranetwork Device. See codes on  http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                1857, // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf                               
                                4, // Marine
                                DEV_HUMI
                               );                              

   
  // Uncomment 3 rows below to see, what device will send to bus                           
   //NMEA2000.SetForwardStream(&Serial);  // PC output on due programming port
  // NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); // Show in clear text. Leave uncommented for default Actisense format.
  // NMEA2000.SetForwardOwnMessages();

  // If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
  NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly,22);
  //NMEA2000.SetDebugMode(tNMEA2000::dm_ClearText); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega
  NMEA2000.EnableForward(false); // Disable all msg forwarding to USB (=Serial)
  NMEA2000.Open();
  

  sensors.begin();
  
}



bool IsTimeToUpdate(unsigned long NextUpdate) {
  return (NextUpdate<millis());
}
unsigned long InitNextUpdate(unsigned long Period, unsigned long Offset=0) {
  return millis()+Period+Offset;
}

void SetNextUpdate(unsigned long &NextUpdate, unsigned long Period) {
  while ( NextUpdate<millis() ) NextUpdate+=Period;
}



void loop() {
  ArduinoOTA.handle();
  

  SendN2kRapidData();
  NMEA2000.ParseMessages();
  
}

void SendN2kRapidData() {
  static unsigned long RapidDataUpdated=InitNextUpdate(RapidDataUpdatePeriod);
  tN2kMsg N2kMsg;


  if ( IsTimeToUpdate(RapidDataUpdated) ) {
    SetNextUpdate(RapidDataUpdated,RapidDataUpdatePeriod);
    
    sensors.requestTemperatures();
    float EngineTemp = sensors.getTempCByIndex(0);
    float OutsideHumd = sht20.readHumidity();                 
    float OutsideTemp = sht20.readTemperature();
    
    
// Temperature
// Temperatures should be in Kelvins
// Input:
//  - SID                   Sequence ID.
//  - TempInstance          This should be unic at least on one device. May be best to have it unic over all devices sending this PGN.
//  - TempSource            see tN2kTempSource
//  - ActualTemperature     Temperature in °K. Use function CToKelvin, if you want to use °C.
//  - SetTemperature        Set temperature in °K. Use function CToKelvin, if you want to use °C. This is meaningfull for temperatures,
//                          which can be controlled like cabin, freezer, refridgeration temperature. God can use value for this for
//                          outside and sea temperature values.


SetN2kTemperatureExt(N2kMsg, 1, 0, N2kts_OutsideTemperature, CToKelvin(OutsideTemp), 0.0);

NMEA2000.SendMsg(N2kMsg, DEV_TEMP);

SetN2kTemperatureExt(N2kMsg, 1, 0, N2kts_EngineRoomTemperature, CToKelvin(EngineTemp), 0.0);

NMEA2000.SendMsg(N2kMsg, DEV_TEMP);
    





//*****************************************************************************
// Humidity
// Humidity should be a percent
// Input:
//  - SID                   Sequence ID.
//  - HumidityInstance      This should be unic at least on one device. May be best to have it unic over all devices sending this PGN.
//  - HumiditySource        see tN2kHumiditySource
//  - Humidity              Humidity in percent

SetN2kHumidity(N2kMsg, 1, 0, N2khs_OutsideHumidity, OutsideHumd);

NMEA2000.SendMsg(N2kMsg, DEV_HUMI);



  }
}

Code2:


#include <Arduino.h>

#include <EEPROM.h>
#define USE_MCP_CAN_CLOCK_SET 8
#define N2k_SPI_CS_PIN 15
#include <NMEA2000_CAN.h>
#include <N2kMessages.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <QMC5883LCompass.h>

#ifndef STASSID
#define STASSID "ssid"
#define STAPSK  "password"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

QMC5883LCompass compass;
float azimuth;

#define RapidDataUpdatePeriod 500 



void setup() {
 Serial.begin(115200);
 EEPROM.begin(512);
 
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

int count;
  EEPROM.get(0 ,count);
  Serial.print("Boot Counter: ");
    Serial.println(count);
  
  while (WiFi.waitForConnectResult() != WL_CONNECTED && count <= 10) {
    Serial.println("Connection Failed! Rebooting...");
    count++;
    EEPROM.put(0, count);
    EEPROM.commit();
    delay(5000);
    ESP.restart();
  }

EEPROM.put(0, 0);
  EEPROM.commit();

  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
     ArduinoOTA.setHostname("SB Kompass");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
     ArduinoOTA.setPasswordHash("hash");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  


  // INIT Kompass Modul
  compass.init();
  compass.setMode(0x01, 0x0C, 0x00, 0x40);
  compass.setSmoothing(4,true);





  
  // Reserve enough buffer for sending all messages. This does not work on small memory devices like Uno or Mega
  NMEA2000.SetN2kCANSendFrameBufSize(250);
  // Set Product information
  NMEA2000.SetProductInformation("00000001", // Manufacturer's Model serial code
                                 1, // Manufacturer's product code
                                 "SB_Kompass",  // Manufacturer's Model ID
                                 "V1.0",  // Manufacturer's Software version code
                                 "V1.0" // Manufacturer's Model version
                                 );
  // Set device information
  NMEA2000.SetDeviceInformation(1, // Unique number. Use e.g. Serial number.
                                140, // Device function=Analog to NMEA 2000 Gateway. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                60, // Device class=Inter/Intranetwork Device. See codes on  http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                1857 // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf                               
                               );
  // Uncomment 3 rows below to see, what device will send to bus                           
   //NMEA2000.SetForwardStream(&Serial);  // PC output on due programming port
  // NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); // Show in clear text. Leave uncommented for default Actisense format.
  // NMEA2000.SetForwardOwnMessages();

  // If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
  NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly,22);
  //NMEA2000.SetDebugMode(tNMEA2000::dm_ClearText); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega
  NMEA2000.EnableForward(false); // Disable all msg forwarding to USB (=Serial)
  NMEA2000.Open();
  
}



bool IsTimeToUpdate(unsigned long NextUpdate) {
  return (NextUpdate<millis());
}
unsigned long InitNextUpdate(unsigned long Period, unsigned long Offset=0) {
  return millis()+Period+Offset;
}

void SetNextUpdate(unsigned long &NextUpdate, unsigned long Period) {
  while ( NextUpdate<millis() ) NextUpdate+=Period;
}


void loop() {
  ArduinoOTA.handle();


  // Read compass values
  compass.read();
  azimuth = compass.getAzimuth();
  

  SendN2kRapidData();
  NMEA2000.ParseMessages();
  
}

void SendN2kRapidData() {
  static unsigned long RapidDataUpdated=InitNextUpdate(RapidDataUpdatePeriod);
  tN2kMsg N2kMsg;


  if ( IsTimeToUpdate(RapidDataUpdated) ) {
    SetNextUpdate(RapidDataUpdated,RapidDataUpdatePeriod);
    
   //                               Kompasswert        Magnetische Abweichung, Ablenkung im Boot
    
    SetN2kMagneticHeading(N2kMsg, 0, DegToRad(azimuth), DegToRad(2.6), DegToRad(0.0));
        
    NMEA2000.SendMsg(N2kMsg);
    

    //Heading+=0.1; if (Heading>=360.0 ) Heading-=360.0;

  }
}

The nodes are sending the periodic data on the right way .... checked with CanOE.... they are also running stable... but only this identyfing makes trouble.

Pictures: http://dl2ksb.de/1.jpg http://dl2ksb.de/2.jpg http://dl2ksb.de/3.jpg

someone a soulution?

TyphoonSB avatar Mar 19 '20 20:03 TyphoonSB

Each PGN has its defined period. On NMEA2000.cpp, where PGNs has been listed there is mentioned default period, which you should use. So use 2000 for temp and humidity as you have. For naming RapidData is not, good, since in NMEA2000 point rapid is <200 ms period. Magnetic heading you should send with 100 ms period.

Then one problem is OneWire temperature. As default it does it by blocking, which means 700 ms stop for your code. During that period some messages may not be served and may cause problems. If you use async mode with OneWire, you get stops down to 10 ms, which is OK, but still not good. With ESP32 it is possible to run OneWire on other core, but then you need to do something with ArduinoOTA, since that runs other core. Other solution would be to put NMEA2000.ParseMessages to own task to other core. If you use other core or tasking you should prevent data concurrent access with mutexes.

Also you should check how compass reading stops tasking. If there is any delays, it poisons the loop.

Try first to comment all device access - sensors, sht20 and compass - and just set fixed values to them. Then check does devices appear on bus as they should.

ttlappalainen avatar Mar 20 '20 04:03 ttlappalainen

Hi Timo,

thanks for your great project, and your support.

I tryed to comment everything out, without no result. In my opinion the OTA Stuff is interupting /slowing down the loop. My problem is that I sealed the nodes with epoxy .... if I remove the OTA Stuff, I will not be able to reupload the software. So I need to build a new test node first, to check if the OTA code is the problem.

btw: offtopic do you have a dbc file for the NMEA2k messages?!

TyphoonSB avatar Mar 20 '20 18:03 TyphoonSB

What do you meant with dbc file? I do not have any more information than available on network.

ttlappalainen avatar Mar 23 '20 08:03 ttlappalainen

dbc is a format which is used for CAN busses, to describe the messages, the signals and there values...

So I did some more tests today .... I commented out all the communication with sensors, with no result. I also change the time value .... with no results. strange is that if the device is displayed on the poltter the Node Adress and the manufacturer are shown correct, rest is -------

I also tested with an Arduino Mega ... same code (without OTA), same heading sensor.... works fine. But when I put a second node (one of the above) to the network, also the Arduino Mega is shown as ---- ---- and data of both is showed togeter under one device ....

TyphoonSB avatar Mar 24 '20 18:03 TyphoonSB

I think I solved the problem....

I found in your code following...

NMEA2000.SendProductInformation(); NMEA2000.SendIsoAddressClaim();

When I send them periodically it seems to work fine.

So TNAKS again for this great libary and your support!!!

TyphoonSB avatar Mar 24 '20 20:03 TyphoonSB

That may be cure, but does not solve actual problem. ISO address claim and product information should be sent on request and library does that automatically, if you just poll ParseMessages. You do not seem to have interrupt enabled for mcp_can. You should wire interrupt line to 8266 and add also #define N2k_CAN_INT_PIN xx

If interrupt handling has not been enabled you may loose those requests, which will cause them to disappear. Check also that you do not have any delay(xx) calls anywhere on your code. Like I mentioned you should change one wire to async mode. Below is snap from my old code, where I used sensors with single line. With that code you have max about 10 ms delays, which is not bad, if you have interrupt receiving and sending. Now I normally add a DS2482-100 bus master to system.

In CanBoat and SignalK they have description file for messages. That has been designed on on big structure and does not compile on small Arduinos. That DB also does not include all important information. That is why I originally made it with functions. In my own systems I use a bit different method and have each PGN described on separated structure. In this way program takes memory only for selected PGNs. Then I also use class method, where each PGN has own class. Unfortunately it eats a bit more flash. For the beginners the function way is the easiest to understant - I think.

// *****************************************************************************
#define DataInstanceStart 0
#define InvalidInstance 0xff
tTemperatureSensorData SensorsData[] = {
  {DataInstanceStart+0,N2kts_FreezerTemperature,{0x28,0x50,0x0A,0xA1,0x07,0x00,0x00,0xD1,0x00},N2kDoubleNA,0.05,0},
  {DataInstanceStart+1,N2kts_RefridgerationTemperature,       {0x28,0xBA,0x22,0xA0,0x07,0x00,0x00,0x7E,0x00},N2kDoubleNA,-0.77,0},
  {DataInstanceStart+2,N2kts_HeatingSystemTemperature, {0x28,0x75,0xED,0x9F,0x07,0x00,0x00,0x5A,0x00},N2kDoubleNA,-0.87,0},
  {DataInstanceStart+3,N2kts_EngineRoomTemperature, {0x28,0x7B,0xDF,0x9F,0x07,0x00,0x00,0x4E,0x00},N2kDoubleNA,0.05,0},
  {InvalidInstance,N2kts_MainCabinTemperature,{},N2kDoubleNA,0,0}
};
void CheckTemperatures() { 
  static unsigned long lastTempRequest = 0;
  static int  resolution = 12;
  static unsigned long  delayInMillis = 0;
  static int LastSensorIndex = 0;
  double Temperature;

  if ( SensorsData[LastSensorIndex].Instance==InvalidInstance ) {
    LastSensorIndex=0;
    lastTempRequest=0;
    Serial.println("");
  }
  
  if ( lastTempRequest == 0 ) { // Initialization
    sensors.begin();
  
    sensors.setWaitForConversion(false);
    sensors.requestTemperatures();
    delayInMillis = 750 / (1 << (12 - resolution)); 
    lastTempRequest = millis(); 
  }

  if (millis() - lastTempRequest >= delayInMillis) // waited long enough??
  {
    Temperature = sensors.getTempC(SensorsData[LastSensorIndex].OneWireAddress);
    if (Temperature>-120) {
      SensorsData[LastSensorIndex].Temperature=CToKelvin(Temperature+SensorsData[LastSensorIndex].Offset);
      SensorsData[LastSensorIndex].FailCount=0;
      Serial.print(" Temperature ("); Serial.print(SensorsData[LastSensorIndex].Instance); Serial.print("):"); 
      Serial.println(KelvinToC(SensorsData[LastSensorIndex].Temperature), resolution - 8); 
    } else {
      SensorsData[LastSensorIndex].FailCount++;
      if (SensorsData[LastSensorIndex].FailCount++ > MaxSensorFailCount ) {
        SensorsData[LastSensorIndex].Temperature=N2kDoubleNA;
      }
    }
    LastSensorIndex++;
    // immediately after fetching the temperature we request a new sample in the async modus
    sensors.requestTemperatures(); 
    delayInMillis = 750 / (1 << (12 - resolution));
    lastTempRequest = millis(); 
  }
}

ttlappalainen avatar Mar 25 '20 04:03 ttlappalainen

Timo & TyphoonSB, sorry to chip in,

I also had issues with my v.long code taking something like 3.5sec to run a full loop and maretron DSM250 display timing out and flashing the values in-out... Following some testing I managed to drop that down to 800-1000ms but not down to 100 needed for some PGNs. So using Teensy and P. Stoffregen OneWire lib (there's a fork specifically for ESP chips btw) I managed to get the times down to 100ms easily.

code extract:

//temp sensor includes
#include <OneWire.h>                      // using teensy Paul Stoffregen lib
#include <DallasTemperature.h>            // split requestTemperaturesByIndex() to getTempCByIndex() to avoid 750ms delay

// Gearbox oil Temp sensor (DS18B20) includes
// Setup a oneWire instance to communicate with any OneWire devices
const unsigned char GBoxOilTemp = A18;
OneWire gboiltemp(GBoxOilTemp);
// Pass our oneWire reference to Dallas Temperature
DallasTemperature gboilsensor(&gboiltemp);
float TransOilTemp;
float TransOilTempB;

setup:

    gboilsensor.begin();

and on the loop:

  gboilsensor.requestTemperaturesByIndex(0);
  TransOilTemp = gboilsensor.getTempCByIndex(0);
  Serial.println("Transmission Oil Temp: " + String(TransOilTemp));

considering it really works, anything fundamentally wrong with this Timo?

cheers

V.

virtuvas avatar Mar 26 '20 10:03 virtuvas

Something...

For 1-wire temperature sensors you need to request conversion and then wait for 750 ms (for 12 bit sensors) before you can read temperatures. The OneWire and DallasTemperature will as default do it in blocking way. Like you would have: RequestTemperature(); delay(750); ReadTemperature(); So your code will not do much during delay. In ESP it may do task switching, but not on Teensy or Arduinos. DallasTemperature also offers "async" way as I used in my code example. The idea is just send request and do other things until 750 ms has been spent and you can read data. With that method code will be blocked only about 10 ms at time, which is acceptable in simple temperature sender. In complex system I used the chip I mentioned. I also rewrote its handling with i2c_t3c, which gives interrupt, when transfer is ready. In this way code spends some us with 1-wire.

So read the code above carefully and modify it for your system so you will get much better performance.

ttlappalainen avatar Mar 26 '20 11:03 ttlappalainen

some short update from my site ....

in my test all cummunication is commented out .... no no interuption from these (till now)

Timo, the definition of interupt pin was a good topic.... so I defined it .... and then the uC runs into an error....

ISR not in IRAM!

User exception (panic/abort/assert)
Abort called

>>>stack>>>

ctx: cont
sp: 3ffffe60 end: 3fffffc0 offset: 0000
3ffffe60:  3ffee5bc afbdfa76 00000000 00000000  
3ffffe70:  000000fe 00000000 00000000 00000000  
3ffffe80:  00000000 00000000 00000000 00ff0000  
3ffffe90:  5ffffe00 5ffffe00 3ffee82c 00000000  
3ffffea0:  00000002 00000003 3ffef574 4020c8de  
3ffffeb0:  401005ce 0000001f 3ffee5bc 4020c8f4  
3ffffec0:  00989680 00000001 3ffef574 4020cdf9  
3ffffed0:  00000000 0000001f 3ffef5e0 40206d17  
3ffffee0:  0000000f 00000001 3ffee5bc 00000000  
3ffffef0:  3ffee5c4 3ffef5e0 3ffef574 4020cea8  
3fffff00:  3ffee5c4 3ffef5e0 3ffef574 40207ce9  
3fffff10:  00000000 00000000 00000010 00000001  
3fffff20:  00000000 3fff0c4c 3ffef574 40204bba  
3fffff30:  3fff06bc 00000000 00000000 00000000  
3fffff40:  00000098 00000001 3ffef574 00000000  
3fffff50:  3ffee5c5 3ffee5e0 3ffee5a0 402015c5  
3fffff60:  00000000 0000ffff 000000ff 00000000  
3fffff70:  40213a80 00000000 40201188 4020108c  
3fffff80:  00000002 feefeffe feefeffe feefeffe  
3fffff90:  feefeffe feefeffe feefeffe 3ffee7cc  
3fffffa0:  3fffdad0 00000000 3ffee78c 4020c4d0  
3fffffb0:  feefeffe feefeffe 3ffe8500 40100ed9  
<<<stack<<<

so I changed in NMEA2000_mcp.cpp

void Can1Interrupt() {
  pNMEA2000_mcp1->InterruptHandler();
}

to

ICACHE_RAM_ATTR void Can1Interrupt() {
  pNMEA2000_mcp1->InterruptHandler();
}

now it´s not running into an overflow.... but need to test it on the Boat, to say if my problem is solved now

TyphoonSB avatar Mar 26 '20 12:03 TyphoonSB

I could add that as define for ESP8266, so default library will compile.

ttlappalainen avatar Mar 26 '20 12:03 ttlappalainen

that would be fine .... but let me check if it´s work on the NMEA network on the Boat. I will check that later today.

TyphoonSB avatar Mar 26 '20 12:03 TyphoonSB

Please test with:

...
#if defined(ESP8266)
ICACHE_RAM_ATTR void Can1Interrupt();
#else 
void Can1Interrupt();
#endif
...
//*****************************************************************************
#if defined(ESP8266)
ICACHE_RAM_ATTR void Can1Interrupt() {
#else 
void Can1Interrupt() {
#endif
  pNMEA2000_mcp1->InterruptHandler();
}

ttlappalainen avatar Mar 26 '20 13:03 ttlappalainen

Something...

For 1-wire temperature sensors you need to request conversion and then wait for 750 ms (for 12 bit sensors) before you can read temperatures. The OneWire and DallasTemperature will as default do it in blocking way. Like you would have: RequestTemperature(); delay(750); ReadTemperature(); So your code will not do much during delay. In ESP it may do task switching, but not on Teensy or Arduinos. DallasTemperature also offers "async" way as I used in my code example. The idea is just send request and do other things until 750 ms has been spent and you can read data. With that method code will be blocked only about 10 ms at time, which is acceptable in simple temperature sender. In complex system I used the chip I mentioned. I also rewrote its handling with i2c_t3c, which gives interrupt, when transfer is ready. In this way code spends some us with 1-wire.

So read the code above carefully and modify it for your system so you will get much better performance.

thanks Timo, looks v.similar to the WaitForConversion2 asynchronous example that comes with DallasTemperature library. Will convert my code this way.

V.

virtuvas avatar Mar 26 '20 15:03 virtuvas

Hi Timo,

I tryed it out, and it seems to work now. Interupts are triggered, and the node is show as it should.

I created already a pullrequest aginst your mcp lib.

Thanks for solving this problem!

TyphoonSB avatar Mar 27 '20 13:03 TyphoonSB

Did you remove periodic? NMEA2000.SendProductInformation(); NMEA2000.SendIsoAddressClaim();

ttlappalainen avatar Mar 27 '20 13:03 ttlappalainen

Yes I did!

TyphoonSB avatar Mar 27 '20 13:03 TyphoonSB