NMEA2000
NMEA2000 copied to clipboard
Disable frame sending for power saving mode
Hi Timo,
I'm currenty building a device, which should run on battery for serveral weeks and want to put the can transceiver in power saving mode (disables sending to the bus) during some periods. Is there a easy way to disable sending frames temporarily on the NMEA2000 library. When I enable the can transceiver after the power saving mode, I will receive all the queued heartbeat packets at once.
Thanks, Thorsten
If you do not call ParseMessages, library will not do anything.
I do not know your hw, but in some hw can tranceiver will not go to sleep. This means that they will still collect frames to controller internal hw buffer. Naturally the interrupt should not collect frames to ram. So when you wake system up and call ParseMessages, it may read frames from hw buffer and show them up. Normally these internal buffers are only few frames.
I will try this. Thanks
Hi Timo,
I've one more question...
I'm using a Teensy 3.2 at 4Mhz and now I'm able to put Flexcan to Freeze mode and disable the sending part of the CAN transceiver. For this I have added a NMEA2000.Close() routine to your library, where I set DeviceReady to false. Because of this, I'm able to do a NMEA2000.Open() again after reenabling the canbus and my device is doing a new address claim.
The device uses 2.4mA from 12V when flexcan is disabled and about 4,5mA with active canbus.
Are you planing to add a Close function to your library in future?
Thanks, Thorsten
Please send me the close code, I'll study it. I thought 24MHz was minimum for working CAN controller.
The Tennsy is running fine on 4Mhz. According to documentation the lowest clockrate is 2Mhz for 250kbps bitrate.
It's only a hack to set DeviceReady to false to be able to call Open again.
NMEA2000.cpp //***************************************************************************** bool tNMEA2000::Close() { DeviceReady = false; return DeviceReady; }
NMEA2000.h bool Close();
It is not that easy. That will cause e.g. creating new group function handlers. So slowly your device will run out of memory. There may be some other recreated structures or effects with can drivers. So I have to carefully look through all code where does it effect.
Close method is not either good name. I think better would be Pause or Sleep. Some CAN controllers has sleep feature, which stops their functions.
Fix, it does not recreate those handlers, but still need to check other can drivers.
For future compatibility we need other name for Close(). For close I have feeling that it would be called just befor descructor to free things. Name could be e.g. Pause(), Sleep() or Stop().
Thanks for your input. I'm currenty testing a new version with a Stop() and Continue() function. Then the handlers will not be recreated, but all missed Heartbeats will be send out at once. But I was able to solve it.
You can see the changes here: https://github.com/ttlappalainen/NMEA2000/compare/master...schwinn:master
I'll get back when I have more information.
I did not understood:
DeviceReady = true;
if ( (ForwardStream!=0) && (ForwardType==tNMEA2000::fwdt_Text) ) {
if ( DeviceReady ) { ForwardStream->println(F("CAN device ready")); } else { ForwardStream->println(F("CAN device failed to open")); }
}
Your if ( DeviceReady )
will be always true?
Do we really need StopActive and Continue. If you just modify
void tNMEA2000::SendHeartbeat(bool force) {
...
if ( Devices[iDev].NextHeartbeatSentTime==0 || Devices[iDev].NextHeartbeatSentTime+Devices[iDev].HeartbeatInterval<millis() ) { Devices[iDev].NextHeartbeatSentTime=millis(); }
That fixes HB sending also for cases someone just stops calling ParseMessages. For now it would be enough just have
void tNMEA2000::Stop() {
DeviceReady = false;
}
Keep it void, since we expect it always to do stop. If there will be later need for result, it can be added. But in compatibility view you can not remove return type.
Also now next call to ParseMessages will automatically continue.
With the StopActive in the library it is not necessary to rewrite the whole program to suppress the execution of ParseMessage()
and SendMsg()
. These routines call Open() and with DeviceReady=false
the routine would be executed again. I'm testing it with this logic right now, and it works fine.
The following was just copied from Open()
and I will remove it.
DeviceReady = true;
if ( (ForwardStream!=0) && (ForwardType==tNMEA2000::fwdt_Text) ) {
if ( DeviceReady ) { ForwardStream->println(F("CAN device ready")); } else { ForwardStream->println(F("CAN device failed to open")); }
}
I'll do the change of SendHeartbeat()
and I will test it.
Do we really need StopActive and Continue?
I like the idea to have a new AddressClaim after joining the bus again after having been offline. In case there's a new device on the bus, which is using our old address.
What do you think about that?
It depends do you want to have possibility to call ParseMessages and SendMsg so that they does not do anything. That would actually mean Enable/Disable feature. Stop could act as function for stopping CAN now so that next ParseMessages or SendMsg will start it automatically. After Stop system will initialize device and controllers as they would have been stopped and also start address claim. So you do not need Continue(). Note that your SendMsg will fail during address claim period (250 ms).
If the device is not listening the bus even short period or if you somehow flush received messages, it should do address claiming again. Currently with just DeviceReady=false it will do it now. At quick check Teensy driver does not need anything special - just CANOpen. Just noticed that you have to add to Open()
if ( N2kCANMsgBuf==0 ) InitCANFrameBuffers();
I have to check other drivers, does CANOpen() cause some harm, it it will be called again.
I have removed the Continue() function and I'm testing it now.
I have tested a similar variant in the past, but the teensy has frozen after a few hours. Maybe it ran out of memory because of calling InitCANFrameBuffers() always after stopping the library.
The changes are commited to my fork.
Hi Timo,
the Teensy was running about one week with the new code and then it stopped sending CAN frames. The rest of my code was still running, but without CAN.
Can this happen because CANOpen() is called every time, when I use the bus again after DeviceReady was set to false?
Can not say for sure. Putting system to sleep has different effects for CAN controller on any device. Also sleep mode effects. So you should study what sleep does for Teensy CAN controller and how it should be put to sleep state and opened from there. Just now I do not have time to do that. I can consult what I know.