NMEA 2000 Shield

For any normal bus devices use mode N2km_NodeOnly or N2km_ListenAndNode. N2km_ListenAndNode has extra feature for simple data forwarding to forward stream so that you do not need to write handler function and print message data e.g. text or actisense format. Other modes are for special cases like being invisible on bus.

Both mentioned modes can read and sent messages. For handling received messages you need to call
NMEA2000.SetMsgHandler(HandleNMEA2000Msg);

and write HandleNMEA2000Msg handler function as in e.g. in example DataDisplay.ino. Note that example uses default mode, which makes it invisible on bus, but you can still send messages to bus as normally with NMEA2000.SendMsg(). That is not prefered, since normally MFD:s requires devices are registered right on the bus.

So in conclusion, if you take e.g. TemperatureMonitor as base and add NMEA2000.SetMsgHandler(HandleNMEA2000Msg); to it, you have rigth device for listen and sent. Note that as in TemperatureMonitor we define messages we are going to transmit with

const unsigned long TransmitMessages[] PROGMEM={130310L,130311L,130312L,0};
...
NMEA2000.ExtendTransmitMessages(TransmitMessages);

You have to do the same for messages you are going to receive:

const unsigned long ReceiveMessages[] PROGMEM={127505UL,0};
...
NMEA2000.ExtendReceiveMessages(ReceiveMessages);

Note also that if you are going to send or receive proprietary fast packet messages, you have to tell system those otherwise library handles them as single framed messages:

const unsigned long ExtraFastPacketMessages[] PROGMEM={126720L,0};
...
NMEA2000.ExtendFastPacketMessages(ExtraFastPacketMessages);

Take also care that you use board with enough memory. Arduino Mega can handle small systems, but also runs easily out of memory. You will see it, when it does not run at all.

autopilotNOR:
Shouldn't the serial monitor show the data send to the bus even the bus isn't connected since "Forward false" is set. Any idea what I am doing wrong or what I have forgotten?

THX!

If you set forward false, it does not forward anything. EnableForward and SetForwardOwnMessages are actually default so it should be enough to set forward stream.

Small fix. There is no Actisense format in clear text. It is either binary Actisense format or clear text, which shows data in hex. Use Actisense format, you you want to read data with Actisense Reader or OpenSkipper.

timolappalainen:
You could try to change
#define EngineDataUpdatePeriod 500
Which is right default period. I have seen Garmin skipping e.g. temp data, if one send it with too long period.

I tried with 500 ms update period. Still no luck.

I noticed that it comes 1 or 2 TX errors every time I turn ESP32 on. I don't know reason for that.

Tx error comes on ESP32 CAN initialization time. I am investicating that and will update library, if I find solution. This is fatal for me, since ESP32 devices will not pass NMEA2000 certifications test due to those errors.

Thanks very much Timo...

timolappalainen:
Both mentioned modes can read and sent messages. For handling received messages you need to call
NMEA2000.SetMsgHandler(HandleNMEA2000Msg);

and write HandleNMEA2000Msg handler function as in e.g. in example DataDisplay.ino. Note that example uses default mode, which makes it invisible on bus, but you can still send messages to bus as normally with NMEA2000.SendMsg(). That is not prefered, since normally MFD:s requires devices are registered right on the bus.

My code actually does have the handler and works well in receiving messages and parsing messages.

I also made the recommended changes as far as listing the PGNs to be sent and received as you described. That didn't help.

I then pulled up the temperature monitor example as you said. It compiled nd uploaded just fine, but it also does not publish any data on the bus. This is the unmodified example.

My hardware is an EPS32-Wrover module. I do have another app that can publish data, including fast-packet data, on the bus. I'll compare the two to see what's happening. But do you know of any reason the temp monitor example would not publish data? I tried both the mode types you mentioned.

Thanks again!

UPDATE - I just read the above messages about ESP32, perhaps my issue is related? If I can help debug or anything I'm happy to assist.

Also, I'm able to run the Temp Monitor example on my Teensy 3.6 and it works fine on that board.

Do you have right Tx/Rx pin definitions for your ESP32 module. TemperatureMonitor example works for 100% sure on ESP32, if your hw is OK and you have right pin definitions for your module.

timolappalainen:
Do you have right Tx/Rx pin definitions for your ESP32 module. TemperatureMonitor example works for 100% sure on ESP32, if your hw is OK and you have right pin definitions for your module.

This had not occurred to me, since it reads data fine. I suppose the TX pin could be wrong, I'll check thanks.

UPDATE - Ug, that was the problem. The RX pin was correct, the TX pin was wrong. The apps I wrote that send were on the Teensy. Thanks again Timo, I'm sorry I wasted your time.

Hi Timo thanks again for all your great work.
Thanks to you my esp8266 D1mini works well with the mcp2515 can interface and now testing your n2k to nmea0183 over wifi with esp32 with mcp2562 which works very well for TCP. In the example I don't see any specifics for TCP protocol and I was wanting to change it to UDP protocol for various Android apps, what would I need to change to achieve UDP instead of TCP ?

skyjumper:
This had not occurred to me, since it reads data fine. I suppose the TX pin could be wrong, I'll check thanks.

Also remember that MCP2562 has pin 8 STBY pin and has to connect to ground.

Rossp:
In the example I don't see any specifics for TCP protocol and I was wanting to change it to UDP protocol for various Android apps, what would I need to change to achieve UDP instead of TCP ?

This is not part of NMEA2000 library and I do not have just now time to make sample. Just google ESP32 wifi UDP and try to find examples.

timolappalainen:
Tx error comes on ESP32 CAN initialization time. I am investicating that and will update library, if I find solution. This is fatal for me, since ESP32 devices will not pass NMEA2000 certifications test due to those errors.

I thought that maybe it would solve this if I update my Triton T41 software, if it was some problem with it. However I found out that I already have the latest version. So no help from there with this ESP32 problem of mine :frowning:

Can CAN transceiver have something to do with this problem? I am now using SN65HVD230 because ESP32 does not have 5V easily available and MCP2562 needs 5V voltage.

Hello Timo,
Is there plan to support Teensy 4.0 https://www.pjrc.com/store/teensy40.html? I try to compile small examples with no success, even with adding pins definition in FlexCan library for new chip.

Yes, but I not got my Teensy 4 yet. I ordered 2, but got a Teensy 3.6 in package. Took month to get those, will take month or two, before I can test.

Hi Timo

With the success of my first device based on your fantastic code I'm now starting on something a bit more challenging.

My engine transmits data to the dashboard gauges via can bus so I intend to use a Teensy 3.6 to extract some of the data such as rpm, temperature, boost etc and put this onto the N2K network.

I have successfully identified the can bus messages and data bytes of interest but am struggling to understand how FlexCAN should be set up with filters and masks to select this data. As you obviously have very good knowledge of FlexCAN is there any chance you could give me some pointers please.

I am only interested in messages with ID 0x280, 0x288, 0x380 and 0x588 (they are all 11 bit standard ID). Should I be setting up 4 individual mailboxes with filters or is there another way? From my research if I use mailboxes I need a default mask of 0x7FF and then each mailboxes will have a filter of 0x280, 0x288 etc. Is this correct?

If this is the way to do it, how do I then get the data bytes of interest out of the mailboxes? Does the data automatically get put into buffers?

Any way you can help would be appreciated as there are so few examples on the net that make sense to me.

Keith

I do not see that there is any reason to setu FlexCAN filtering. You could just catch all messages and filter them on sw - Teensy 3.6 has enough and lot more power to do that. Also if you use other CAN on Teensy 3.6 just for connecting it to engine, it will not have much messages on that bus. I have been testing Teensy 3.6 on bus, where I have over 100 frames/s on the bus and it still do filtering and graphics at same time.

Take a look for NMEA2000_Teensy module and create new module for handling standard CAN messages with interrupts. Then just poll the buffer like on NMEA2000 library and filter messages you are interested.

Thanks Timo, that sounds like a sensible way forward. There's a lot I don't understand yet so I might be back!

timolappalainen:
Then just poll the buffer like on NMEA2000 library and filter messages you are interested.

Humour me please: I'm still very much a noob and need some high level pointers :slight_smile:

Presumably the frames from the engine canbus are being put into buffers within an array as they arrive.

Presumably your NMEA code sends out its packets to the N2K network at preset intervals. Faster for some things like Engine Rapid PGN's I suppose and slower for Temperature PGN's.

Presumably I need to get your N2K code to look for the correct frame ID (e.g. 0x288) in the array and then extract the data I'm interested in (e.g. byte 1 for coolant temp).

How do I do this last part? Is it some form of If ID=0x288 then get the data from buf[2] or some such into a variable.

Your help, as ever, is appreciated.

Hi Timo, thanks for your hard work.
I would like to make an arduino project who's light a lamp when it see on the nmea2000 bus the alarm msg PGN126983.
Do you think I can use your library for that? and could you suggest me how?
Thanks
Bye
Benoit :slight_smile:

keith-i,

The simplest way is just poll other CAN on Teensy 3.6. It would be something like this:

void PollEngineCAN() {
  CAN_message_t Msg;

  if ( Can1.available()>0 ) {
    Can1.read(Msg);
    if ( Msg.flags.extended==0 ) { // Standard message
      //Filter and parse message here to global data EngineRPM, EngineOilPressure, etc.
    }
  }
}

void SendN2kEngineRapid() {
  static unsigned int NextSendTime=5000;

  if ( NextSendTime<millis() ) {
    NextSendTime+=100;
    tN2kMsg N2kMsg;
    
    SetN2kEngineParamRapid(N2kMsg,0,EngineRPM); 
    NMEA2000.SendMsg(N2kMsg);
  }
}

void SendN2kEngineDynamic() {
  static unsigned int NextSendTime=5000;

  if ( NextSendTime<millis() ) {
    NextSendTime+=500;
    tN2kMsg N2kMsg;
    
    SetN2kEngineDynamicParam(N2kMsg,0,EngineOilPressure,EngineOilTemp,EngineCoolantTemp,
                                               N2kDoubleNA,N2kDoubleNA,N2kDoubleNA);
    NMEA2000.SendMsg(N2kMsg);
  }
}

void loop() {
  NMEA2000.ParseMessages();
  PollEngineCAN();
  SendN2kEngineRapid();
  SendN2kEngineDynamic();
}

Note that you should provide NA value for each data, which is not available. Also you should take care that if your Engine CAN will not send some data anymore, you should update that data value to NA after some timeout. This can be easily done by using class for values.