Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid PGN data after a soft reset (fix is applied) #5

Open
jimarcher opened this issue Aug 6, 2020 · 22 comments
Open

Invalid PGN data after a soft reset (fix is applied) #5

jimarcher opened this issue Aug 6, 2020 · 22 comments

Comments

@jimarcher
Copy link

jimarcher commented Aug 6, 2020

I'm using a board with an ESP32-WROOM-32U, 16MB module. My FW is an N2K projet using this code and also the companion NMEA2000 library (although a version from last November). Upon initial power up, my FW runs beautifully for days. However, often after a soft reset the library will receive invalid PGNs.

I see there is a fix related to this here and I verified I am using this code, with that fix. I checked Mr. Barth's driver on GitHub and it has not been updated in 3 years.

I realize this code has been in circulation quite a while but could there be a similar problem? I have searched, but of course its very hard to Google a term with the word "can" in it.

@ttlappalainen
Copy link
Owner

Yes, I made a fix for that and it fixed it at least for power up reset. What do you mean with soft reset? If it does not reset pin settings and CAN controller, it may be the problem.

@jimarcher
Copy link
Author

jimarcher commented Aug 7, 2020

Hi Timo, by soft reset, I mean if I issue a software restart command, such as after an OTA update, or after a remote update to the user configuration. The power is not interrupted and the enable pin is not pulled low.

I started a discussion on the Espressif forums (at esp32.com) and this seems to be a known issue. They report the Espressif driver handles it. The discussion is here:

https://www.esp32.com/viewtopic.php?f=2&t=16808&p=63664#p63664

I don't use the Espressif dev environment so I'm going to see what I can do about using their driver, or fixing this driver.

@ttlappalainen
Copy link
Owner

Is that critical? If you receive invalid PGNs, you can just ignore them.

My fix on November was for sending invalid PGNs after reset, which was more critical due to certification tests. Do you also see invalid PGN on other devices, when your device does reset?

@jimarcher
Copy link
Author

Sorry I was not clear. I start receiving invalid PGNs, and there are no valid ones. It seems all the data coming in is corrupted.

I have not actually looked at the PGNs I'm sending after this problem starts. I have Can King, and the PGNs on the N2K bus are valid, it's just that the data I'm getting is corrupted. I'll check to see if the data I'm sending is also corrupted. Over on esp32.com there is a gentleman who advises that while the Thomas Barth driver got CAN going three years ago, it has substantial issues and it's critical to move to the ESP-IDF driver. That looks to be non-trivial, but I'm looking to see what it would entail. I'm not using ESP-IDF so there is some extra work.

@jimarcher
Copy link
Author

Actually, maybe I misunderstood your question. Timo, by "other devices" did you mean different ESP32 boards or other N2K devices on the bus?

@ttlappalainen
Copy link
Owner

I meant other N2k devices.

But your problem is strange. I have two ESP32 devices on my boat and never seen that problem even after OTA update. But I have also rewritten several things and do not use published libraries. E.g. after my OTA update I generate watchdog to restart:
void Restart() {
esp_task_wdt_init(1,true);
while(true); // WD does full reset for CPU
}

@jimarcher
Copy link
Author

I'm using a different OTA mechanism, and Mongoose, and I don't believe I have a post-OTA hook I can capture. If that restart resets the peripheral interfaces then it probably works. But the driver should do that when it starts. I'll investigate and see if I can do a phepherial reset, thanks.

@jimarcher
Copy link
Author

Hi Timo, I have been working on this since it has caused me a lot of grief. Without a doubt, a soft reset, even when triggered by the built in watchdog timer, can leave the CAN controller in an undefined state. Fortunately, the ESP-IDF provides a mechanism to reset it as if it had come up from power on. I added this to my code and it solved this problem. The ESP32 CAN controller has other issues as well, but at least I can work around them.

The fix is to call:

periph_module_reset(PERIPH_CAN_MODULE);

I have added this early in my code, before initializing your library.

If you like, I can add it to code and open a PR.

@ttlappalainen
Copy link
Owner

Please do PR. It is easier to see there.

@jimarcher
Copy link
Author

PR opened.

@CelsoKupsch
Copy link

Bom dia, final de semana estive trabalhando com o meu projeto de enviar dados para o nmea2000, com o exemplo que tem do temperatura monitor verificando o sinal do Actisense NMEA reader não estava recebendo o sinal ISO somente os sinais temperatura. estava usando um arduino mega e um MCP2515/tja1050.
tentei usar um ModeMCU V3 e não consegui transferir o programa , ele esta dando o erro abaixo, voce tem idéia do que estou fazendo errado?
Arduino: 1.8.13 (Windows 7), Placa:"NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200"

In file included from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:161:0,

             from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\Examples\WindMonitor\WindMonitor.ino:4:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h:139:84: error: 'MCP_8MHz' was not declared in this scope

 tNMEA2000_mcp(unsigned char _N2k_CAN_CS_pin, unsigned char _N2k_CAN_clockset = MCP_8MHz,

                                                                                ^

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h: In member function 'void tNMEA2000_mcp::SetSPI(SPIClass*)':

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h:141:43: error: 'class MCP_CAN' has no member named 'setSPI'

 void SetSPI(SPIClass *_pSPI) { N2kCAN.setSPI(_pSPI); }

                                       ^

In file included from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\Examples\WindMonitor\WindMonitor.ino:4:0:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h: At global scope:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:173:27: error: 'MCP_16MHz' was not declared in this scope

#define MCP_CAN_CLOCK_SET MCP_16MHz

                       ^

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:176:56: note: in expansion of macro 'MCP_CAN_CLOCK_SET'

tNMEA2000 &NMEA2000=*(new tNMEA2000_mcp(N2k_SPI_CS_PIN,MCP_CAN_CLOCK_SET,N2k_CAN_INT_PIN,MCP_CAN_RX_BUFFER_SIZE));

                                                    ^

exit status 1

Erro compilando para a placa NodeMCU 1.0 (ESP-12E Module)

Este relatório teria mais informações com
"Mostrar a saida detalhada durante a compilação"
opção pode ser ativada em "Arquivo -> Preferências"

@ttlappalainen
Copy link
Owner

Please write in English!

@CelsoKupsch
Copy link

Good morning, weekend I was working with my project to send data to nmea2000, with the example that has the temperature monitor checking the signal of the Actisense NMEA reader was not receiving the ISO signal only the temperature signals. was using a mega arduino and an MCP2515 / tja1050.
I tried using a ModeMCU V3 and I was unable to download the program, it is giving the error below, do you have any idea what I am doing wrong?
Arduino: 1.8.13 (Windows 7), Placa:"NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200"

In file included from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:161:0,

         from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\Examples\WindMonitor\WindMonitor.ino:4:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h:139:84: error: 'MCP_8MHz' was not declared in this scope

tNMEA2000_mcp(unsigned char _N2k_CAN_CS_pin, unsigned char _N2k_CAN_clockset = MCP_8MHz,

                                                                            ^

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h: In member function 'void tNMEA2000_mcp::SetSPI(SPIClass*)':

C:\Users\celso\Documents\Arduino\libraries\NMEA2000_mcp-master/NMEA2000_mcp.h:141:43: error: 'class MCP_CAN' has no member named 'setSPI'

void SetSPI(SPIClass *_pSPI) { N2kCAN.setSPI(_pSPI); }

                                   ^

In file included from C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\Examples\WindMonitor\WindMonitor.ino:4:0:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h: At global scope:

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:173:27: error: 'MCP_16MHz' was not declared in this scope

#define MCP_CAN_CLOCK_SET MCP_16MHz

                   ^

C:\Users\celso\Documents\Arduino\libraries\NMEA2000-master\src/NMEA2000_CAN.h:176:56: note: in expansion of macro 'MCP_CAN_CLOCK_SET'

tNMEA2000 &NMEA2000=*(new tNMEA2000_mcp(N2k_SPI_CS_PIN,MCP_CAN_CLOCK_SET,N2k_CAN_INT_PIN,MCP_CAN_RX_BUFFER_SIZE));

                                                ^

exit status 1

Erro compilando para a placa NodeMCU 1.0 (ESP-12E Module)

@ttlappalainen
Copy link
Owner

Most likely you have loaded mcp_can library from wrong source. You have to download it from my git https://github.com/ttlappalainen/CAN_BUS_Shield. Remove other CAN_BUS_Shield libraries from your C:\Users\celso\Documents\Arduino\libraries folder and download right.

Other hints:

  • Do not modify libraries itself. NMEA2000_mcp.h:139:84 should be
    tNMEA2000_mcp(unsigned char _N2k_CAN_CS_pin, unsigned char _N2k_CAN_clockset = MCP_16MHz,

If you want to use different clock setting you do that on your .ino before including NMEA2000_CAN.h like this:
#define USE_MCP_CAN_CLOCK_SET 8
#include <NMEA2000_CAN.h>

  • NodeMCU is Esp32 and it should use internal CAN with NMEA2000_esp32, if you have not forced to use mcp_can. Is that your purpose?

  • This issue is not right subject.

@CelsoKupsch
Copy link

The libraries downloaded your git, I will try to reinstall to see if it works. from nodeMCU I was using your esp32 library I'm using the internal CAn via TX / RX. This is all doing as a test, my idea is to read a CAN network (J1939) from my motor and converter for NMEA2K, I believe that for that I will have to use an arduino because of the two internal CAN.

@ttlappalainen
Copy link
Owner

According your error messages mcp_can_dfs.h will be propably loaded from somewhere else. Check that you have only one CAN_BUS_Shield (or CAN_BUS_Shield-master) folder on your computer and there mcp_can_dfs.h on line 254 you have
#define MCP_16MHz 1
#define MCP_8MHz 2

Note that only Teensy 3.5, 3.6 and 4.x with multiple internal CAN are supported.

@CelsoKupsch
Copy link

Good morning Timo, this weekend I tried a little more to work with Nmea on the Arduino Mega and I still couldn't get him to read the ISO information, I don't know what I'm doing wrong, I already deleted all the libraries I had in the IDE and installed only yours (CAN BUS, NMEA2000 and NMEA2000 mcp) on my two computers and still without success. Is it a hardware problem?
nmea
nmea2

@ttlappalainen
Copy link
Owner

So do you have two computers each attached to Arduino Mega with Temperature monitor example and bot modified to be as NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode,22); so that you can use Actisense Reader on both computer? Do you have 8 MHz or 16 Mhz clock on CAN board?

When Temperture monitor starts up, it will send ISO address claim once to the bus and waits is anybody interested. If there would be e.g. MFD on bus, it should request device information, which library will automatically respond. Also if you have two Temperature monitors with same Source (=22), they should do address claiming and other should change to next free source (23). If your device does not respond to any requests, it is possible that your rx line is broken between tranceiver and CAN controller.

@CelsoKupsch
Copy link

I changed it to NMEA2000.SetMode (tNMEA2000 :: N2km_ListenAndNode, 22) and found that Actisense only reads the ISO if before I opened the IDE's serial monitor, now I connected the MCP2515 and I didn't have the CAN H / CAN L signal checking with the oscilloscope . My card is 8mhz and the connection is:
mcp2515
ligação

@ttlappalainen
Copy link
Owner

As I mentioned earlier, you must have clock set selection on your code, since default is 16. I also prefer to define bigger read buffer and use interrupt for reading. So wire module INT to e.g. pin 21 and put to the beginning:
#define N2k_CAN_INT_PIN 21
#define USE_MCP_CAN_CLOCK_SET 8
#define MCP_CAN_RX_BUFFER_SIZE 50
#include <NMEA2000_CAN.h>

remove #include <NMEA2000_mcp.h> from your .ino. #include <NMEA2000_CAN.h> does that.

@CelsoKupsch
Copy link

Good afternoon Timo, first of all thank you very much for the help / class you gave me, I managed to send the data from the Arduino Mega to the Garmin via N2k. My doubt now is if I could install a second MCP2515 on my arduino mega including a second CS port, so I would be able to read the CAN network data from the engine. In the libraries I searched I found Coryfowler's that has a DUAL CAN example:

// Demo: Dual CAN-BUS Shields, Data Pass-through
// Written by: Cory J. Fowler
// January 31st 2014
// This examples the ability of this library to support more than one MCP2515 based CAN interface.

#include <mcp_can.h>
#include <SPI.h>

unsigned long rxId;
byte len;
byte rxBuf[8];

byte txBuf0[] = {AA,55,AA,55,AA,55,AA,55};
byte txBuf1[] = {55,AA,55,AA,55,AA,55,AA};

MCP_CAN CAN0(10); // CAN0 interface usins CS on digital pin 10
MCP_CAN CAN1(9); // CAN1 interface using CS on digital pin 9

void setup()
{
Serial.begin(115200);

// init CAN0 bus, baudrate: 250k@16MHz
if(CAN0.begin(MCP_EXT, CAN_250KBPS, MCP_16MHZ) == CAN_OK){
Serial.print("CAN0: Init OK!\r\n");
CAN0.setMode(MCP_NORMAL);
} else Serial.print("CAN0: Init Fail!!!\r\n");

// init CAN1 bus, baudrate: 250k@16MHz
if(CAN1.begin(MCP_EXT, CAN_250KBPS, MCP_16MHZ) == CAN_OK){
Serial.print("CAN1: Init OK!\r\n");
CAN1.setMode(MCP_NORMAL);
} else Serial.print("CAN1: Init Fail!!!\r\n");

SPI.setClockDivider(SPI_CLOCK_DIV2); // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz)

CAN0.sendMsgBuf(0x1000000, 1, 8, tx0Buf);
CAN1.sendMsgBuf(0x1000001, 1, 8, tx1Buf);
}

void loop(){
if(!digitalRead(2)){ // If pin 2 is low, read CAN0 receive buffer
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
CAN1.sendMsgBuf(rxId, 1, len, rxBuf); // Immediately send message out CAN1 interface
}
if(!digitalRead(3)){ // If pin 3 is low, read CAN1 receive buffer
CAN1.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
CAN0.sendMsgBuf(rxId, 1, len, rxBuf); // Immediately send message out CAN0 interface
}
}

/*********************************************************************************************************
END FILE


@ttlappalainen
Copy link
Owner

Unfortunately with current code it is not possible. You can have ESP32 and use internal CAN and external mcp_can as second. Or why not use Teensy 3.6 or Teensy 4? They have two internal CAN controller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants