NMEA2000 YAPP

AngusMcDoon

Well-Known Member
Joined
20 Oct 2004
Messages
9,046
Location
Up some Hebridean loch
Visit site
Time for a new YAPP. All my previous efforts have used Seatalk 1 and NMEA0183, because that's what I had on the boat I owned at the time. That boat has gone now, and the new one is coming with a NMEA2000 set of instruments, so I've been having a play.

NMEA2000 is a closed standard and is very expensive to buy - far too much for home tinkerers. However, some Finns have reverse engineered it (which is legal) and created an open source library which they have put in the public domain license free on Github here...

GitHub - ttlappalainen/NMEA2000: NMEA2000 library for Arduino

The library is aimed at various Arduinos for hardware (including the Espressif ESP32 DevKitC board) and the Arduino IDE for building the software. I don't do Arduino of any type, but it was pretty easy to modify it slightly to build using the native ESP-IDF software development kit. This first project uses a BMP280 atmospheric pressure sensor breakout board from Pimoroni. From this the pressure is read periodically, packaged up in a NMEA2000 message and sent out using a Microchip MCP2551 Canbus driver chip. The whole circuit is only 2 small boards and 3 passive components. Currently it's powered by the USB connector on the DevKitC board but a simple voltage regulator will be sufficient to power the circuit from the NMEA2000 power lines. This is the state of the circuit at the moment...

3.jpg

The device is recognised on the network by a MFD on the same network shown here...

2.jpg

and here's the pressure shown on an instrument head display...

1.jpg

The code to get the pressure from the BMP280 pressure sensor via I2C I've lifted from a previous YAPP, modifying it slightly to use the ESP-IDF I2C library rather than the STM32 one. Similarly I did the same to save the device address in non-volatile storage. Other than minor changes to the NMEA2000 library to get it to build using ESP-IDF nothing needed to be done to that library. The code that I wrote new for this project that links these 3 bits together is less than 100 lines long and so small I can stick it here...

Code:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "NMEA2000_CAN.h"
#include "N2kMessages.h"
#include "hal_non_vol.h"
#include "pressure_sensor.h"
#include "main.h"

#define PRESSURE_SENSOR_TASK_STACK_SIZE            8096U

const unsigned long transmit_messages[] = {130310UL, 0UL};

static TaskHandle_t main_task_handle;
static StaticQueue_t pressure_sensor_queue;
static uint8_t pressure_sensor_queue_buffer[sizeof(float)];
static QueueHandle_t pressure_sensor_queue_handle;

TaskHandle_t get_main_task_handle(void)
{
    return main_task_handle;
}

static struct non_vol_t
{
    uint32_t signature;
    uint8_t deviceAddress;
} non_vol;

extern "C" void app_main(void)
{
    uint8_t task_started_count = 0U;

    main_task_handle = xTaskGetCurrentTaskHandle();
    mw_hal_non_vol_init();
    pressure_sensor_init();
    pressure_sensor_queue_handle = xQueueCreateStatic((UBaseType_t)1, (UBaseType_t)(sizeof(float)), pressure_sensor_queue_buffer, &pressure_sensor_queue);
    (void)xTaskCreate(pressure_sensor_task, "pressure sensor task", PRESSURE_SENSOR_TASK_STACK_SIZE, &pressure_sensor_queue_handle, (UBaseType_t)1, NULL);
     
    // wait until all server tasks have started
    do
    {
        (void)ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        task_started_count++;
    }
    while (task_started_count < 1U);      

    // load previous N2K device address from non vol
    mw_hal_non_vol_load((uint8_t *)&non_vol, sizeof(non_vol_t));
    if (non_vol.signature != 0xdeadbeef)
    {
        memset(&non_vol, 0, sizeof(non_vol_t));
        non_vol.signature = 0xdeadbeef;
        non_vol.deviceAddress = 22U;
        mw_hal_non_vol_save((uint8_t *)&non_vol, sizeof(non_vol_t));  
    }

    // set up N2K
    NMEA2000.SetN2kCANMsgBufSize(16);
    NMEA2000.SetProductInformation("00000001", 1, "Simple pressure monitor", "1.0", "1.0");  
    NMEA2000.SetDeviceInformation(1,  140,  75,  2040);
    NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly, non_vol.deviceAddress);
    NMEA2000.EnableForward(false);
    NMEA2000.ExtendTransmitMessages(transmit_messages);
    NMEA2000.Open();  

    while (true)
    {
        // check if a pressure reading is available
        float pressure_data;
        if (xQueueReceive(pressure_sensor_queue_handle, (void *)&pressure_data, (TickType_t)0) == pdTRUE)
        {    
            tN2kMsg N2kMsg;
            SetN2kOutsideEnvironmentalParameters(N2kMsg, 1, N2kDoubleNA, N2kDoubleNA, mBarToPascal((double)pressure_data));
            NMEA2000.SendMsg(N2kMsg);
        }

        // do N2K routine stuff
        NMEA2000.ParseMessages();
        if (NMEA2000.ReadResetAddressChanged())
        {
            non_vol.deviceAddress = NMEA2000.GetN2kSource();
            mw_hal_non_vol_save((uint8_t *)&non_vol, sizeof(non_vol_t));
        }
   
        vTaskDelay(1);  
    }
}

The ESP32 has built in Bluetooth, so I might extend the code to send the pressure in a NMEA0183 format message via that interface so that OpenCPN running on a phone or tablet can grab the data and show it.

I need to get hold of a proper NMEA2000 connector and do a proper circuit board - and find a box to put it in. Then my intention is to replicate my previous Anchor Watcher YAPP to use NMEA2000 rather than Seatalk 1 which had an atmospheric pressure sensor as one of its features.
 
Last edited:
Refreshing to see someone using proper millibars instead of some long - dead Spanish opera singer - who was he? Hector Pasquales or something?
Otherwise I barely understood a word of it but it sounds very impressive.
Can you figure how I can get a split-screen display of boat speed and SoG on that same Raymarine instrument?
£1500 system and it can't even display SoG! (The SoG figures on the chartplotter need a microscope to read them and the GPS is below.)
 
Looks very interesting. Can the design manage more inputs? For instance I'm thinking of replacing my useless fuel tank sensor with a more linear device and it would be great if fuel level was available for display on my N2K instruments. Exhaust temperature is another possible candidate.
 
This is great work, @AngusMcDoon, and very interesting.

I plan similar projects myself in the fullness of time, but had not yet investigated the details - I had got as far as understanding that "you can program an Arduino to do stuff, and make that talk to NMEA" but not yet explored further.

You have sent me down a rabbit hole, though which I have been running for the last hour or so, and I think I have a much better understanding now.

Is there a reason you're designing your own circuits and not using the Sailor Hat with ESP32? It seems very well documented and is available from €42, with discounts if you buy an enclosure and engine temperature sensors.
 
Looks very interesting. Can the design manage more inputs? For instance I'm thinking of replacing my useless fuel tank sensor with a more linear device and it would be great if fuel level was available for display on my N2K instruments. Exhaust temperature is another possible candidate.

There are more pins on the ESP32 which could be used for more inputs or outputs - either analog, digital or data comms. It doesn't have a huge number as it's mainly designed as a radio comms system on a chip device. Other development boards without the radio interface have dozens of extra pins.

The NMEA2000 library and examples can be loaded and built directly using the Arduino IDE on a variety of boards that the Arduino IDE supports. That would be the easiest way rather than the hair shirt way I go of using the native development environments for the processors I work with.

Do you have an exhaust temperature sensor in mind as it's something I would like?
 
I've built a few of these, and have some experience in what works etc. I use the Teensy board, which I find to be fast and reliable, and the actisense connector, with a decent 3.3V regulator (like Murata Power). I have 2 main devices - the first does navigation (upload routes from OpenCPN over Bluetooth), it has its own GPS, and it spits out BTW, DTW, XTE as well as barometric pressure. The second is a WiFi gateway that takes all the NMEA2K traffic and broadcasts it over a ESP8266 wifi interface to whoever is interested (e.g. OpenCPN on my phone). They have been in use for around 5 years and rock solid. Its a great platform for tinkering, and it was good fun being an early contributor to the NMEA github project.
 
  • Like
Reactions: vas
Yes. I like doing it.

(Did I mention that I'm a tightwad? :p)
I didn't realise that bare ESP32 boards were so much cheaper - a quarter of the price or less. I would not have asked the question had I known.

The library's "beginners' document" it talks quite a bit on pages 3-5 about CAN controllers, CAN transceivers and isolation, much of which went over my head (googling that was what found me the Sailor Hat with ESP32, in fact). Anything you could explain about that would be helpful - when picking a chip, how do you know whether or not it has a CAN controller? Do all those with CAN controllers have built in CAN transceivers?
 
Anything you could explain about that would be helpful - when picking a chip, how do you know whether or not it has a CAN controller? Do all those with CAN controllers have built in CAN transceivers?

Most 32 bit microcontrollers will have a CAN controller in them. The datasheet will be the authority on that but they are often heavyweight documents. Often there's a summary at the beginning that lists the chip's features. Microcontrollers do not have CAN transceivers. They are extra but are simple to connect and are cheap. In picture 1 above it's the small 8 legged chip on the top right of the board.

Espressif, just to confuse things, sometimes call CAN TWAI.
 
Do you have an exhaust temperature sensor in mind as it's something I would like
I bought some basic two wire temperature sensors from Openplotter for RPi but never got round to using them. Perhaps obviously I am thinking of measuring the pipe temperature downstream of the elbow to warn of poor or reduced water flow. ISTR they have individual codes and can be strung in series with a single connection. I can't find the same items for sale offhand but I think they're pretty standard.
 
I need to get hold of a proper NMEA2000 connector and do a proper circuit board - and find a box to put it in. Then my intention is to replicate my previous Anchor Watcher YAPP to use NMEA2000 rather than Seatalk 1 which had an atmospheric pressure sensor as one of its features.

There is this ESP32 with NMEA 2000 connectivity built in: Sailor Hat with ESP32 (SH-ESP32) - Hat Labs

Disclaimer: I haven’t tried the ESP32 myself (though I’m planning to order one for some summer projects). But I have the Raspberry Pi hat from the same manufacturer, and it works great.
 
There is this ESP32 with NMEA 2000 connectivity built in: Sailor Hat with ESP32 (SH-ESP32) - Hat Labs

Disclaimer: I haven’t tried the ESP32 myself (though I’m planning to order one for some summer projects). But I have the Raspberry Pi hat from the same manufacturer, and it works great.

That looks like the same thing that KompetentKrew highlighted. It looks good, but I'm not using it so far because 1) it's quite expensive compared to a bare bones ESP32 dev board, and 2) I haven't got one right now. I've got a DevKitC board sculling around already, so I'm using that. I quite like making a PCB anyway. It looks like the Sailor Hat enclosure is an off the shelf type.

The ESP32 has limited pins but uses less amps than a Pi. The ESP32 Arduino core library makes it easy and everything seems to work that I have tried. I'm using Espressif's native ESP-IDF development kit though, which is a bit more tricky to use.
 
Most 32 bit microcontrollers will have a CAN controller in them. The datasheet will be the authority on that but they are often heavyweight documents. Often there's a summary at the beginning that lists the chip's features. Microcontrollers do not have CAN transceivers. They are extra but are simple to connect and are cheap. In picture 1 above it's the small 8 legged chip on the top right of the board.

Espressif, just to confuse things, sometimes call CAN TWAI.

Thanks for the GIT lib pointer.

Just for interest. There is one MCU I know of that has the CAN transceiver built in. The NXP11C24, an ARM Cortex M0+.

There is an eval board available from Farnell (and others) which includes the debugging hardware.
https://uk.farnell.com/nxp/om13093ul/dev-board-lpcxpresso-32bit-cortex/dp/2820395?CMP=grhb-nxp
The PCB has a footprint for the D-9 but it isn't populated.
I used this board's predecessor a few years ago with the free IDE from NXP and it worked well.

No wireless.
Not Arduino. Programming language is C.
No easy way to add CAN isolation since you can't access the TX and RX signals.

John
 
Top