0

I have been working on a problem for a couple of days that I can't figure out.

I am using a Teensy3.6 with Arduino IDE to build a CAN Bus monitor for a car. For those familiar, I am trying to save the data in the format of can-utils so it can be easily replayed on Linux machines. The board uses the FlexCAN library to facilitate communication.

Everything works well using the Arduino Serial Monitor. However, I want to save the output to a host computer. Unfortunately, I've not been able to get any other serial programs to work. I have tried PuTTY & Python via PySerial. The output seems to get interrupted & doesn't print on a new line correctly.

Sample Output from Arduino Serial Monitor:

(1302.864746) can0 1C5#2C032C032E01
(1302.864868) can0 1F4#000000000000
(1302.865356) can0 287#0000
(1302.865601) can0 F1#340000400000
(1302.865845) can0 96#BFF00A120000
(1302.866455) can0 97#35800A1518300A0A
(1302.866821) can0 98#00000A0080000A13
(1302.867065) can0 1E5#4400335000000103
(1302.867554) can0 C7#00000000
(1302.867798) can0 1E9#FF8300EFFC0000
(1302.868042) can0 232#0000000000000000
(1302.868652) can0 1E1#00000000001CC0
(1302.868896) can0 2F9#83000000000007
(1302.869019) can0 222#001607AD0C00
(1302.869629) can0 BC#A11E005C00000000
(1302.869751) can0 D3#2C02
(1302.869995) can0 186#44005D0000017C
(1302.870483) can0 224#CBC8C8
(1302.870605) can0 228#005B5F5B
(1302.870850) can0 1F3#80BC00
(1302.871460) can0 B9#000A800002000000

Output from PuTTY/PySerial:

(1443.927002) can0 C1#10026B0210037D86
(1443.927246) can0 C5#10026B0310026B02
(1443.927490) can0 D1#40007FFF00FF00
(1443.927856) can0 1EB#0241(1444.011230) can0 AA#2C032C030253FC00
(1444.011597) can0 C9#8000002000101800
(1444.012085) can0 1E7#019000000000316D
(1444.012329) can0 1ED#019000000000316D
(1444.012451) can0 34A#000000001B
(1444.012939) can0 1EF#00000000

My naive opinion is it seems the CAN data comes faster than the serial is writing. However, it's odd that it works fine in the Arduino IDE. It happens about 1x/second--which is well enough to cause a headache.

Outside of SD cards or writing locally--does anyone know why this might happen? Or how I could save this data to a host computer? Worst case I can copy/paste the output from the Arduino Serial Monitor, but that isn't very elegant.

Thank you!

Edit: Here is some relevant code from my Arduino IDE. I modified the object oriented can example from flexcan to print in my desired format.

#include <FlexCAN.h>
static CAN_message_t msg;
elapsedMicros sinceStart;

class CANHandler : public CANListener{
  void printFrame(CAN_message_t &frame);
  void gotFrame(CAN_message_t &frame, int mailbox); //overrides the parent version so we can actually do something
};

void CANHandler::printFrame(CAN_message_t &frame){
   Serial.print("("); Serial.print(sinceStart / 1000.0 / 1000.0, 6); 
   Serial.print(") "); //cast to 6 decimals to make compatible with can-utils
   Serial.print("can0 "); // to identify a CAN channel for can-utils
   Serial.print(frame.id, HEX);
   Serial.print("#");
   for ( uint8_t i = 0; i < frame.len; i++ ) {
     if(frame.buf[i] < 15){
        Serial.print("0"); Serial.print(frame.buf[i], HEX);
     } else {
        Serial.print(frame.buf[i], HEX);
     }
 } 
 Serial.println();
}

void CANHandler::gotFrame(CAN_message_t &frame, int mailbox){
printFrame(frame);
}

CANHandler canHandler;

void setup() {
    Serial.begin(115200);
    Can0.begin(500000);
    Can0.attachObj(&canHandler);
    CanHandler.attachGeneralHandler();
}

void loop() {
//run until exit
}
  • so, one thing about interrupt-driven routines (I am assuming that the CANHandler is one such) is that they can truly fire at any time, including during while the handler is already running. There are a few strategies for dealing with this. One is to have the handler return as soon as possible and then deal with the slow task (serial output in this case) in a main program loop. But you'd have to find a way to stash the CAN frame somewhere for later processing in this case. – Chris Combs Dec 27 '19 at 18:37
  • The IDE buffers what it is sending to the screen. As Chris points out, the interrupt driven routine is likely your issue. I use a ramdrive to stash data in cases like this. – Wendall Dec 27 '19 at 20:56
  • @ChrisCombs Can the handler really be started again, if it is already running? If the handler function is called from an interrupt routine, it will not be interrupted by another interrupt, as long as you don't re-enable interrupts on purpose inside it (and why would you do this in such a case). If another interrupt fires during the ISR execution, it will be executed after the current ISR exited. That's at least, how I understand it. – chrisl Dec 28 '19 at 1:00
  • My understanding is that you have to explicitly disable interrupts inside your ISR if you want this behavior. But I could certainly be mistaken! – Chris Combs Jan 2 at 17:21
0

If your data input rate is higher than, or even close to, your serial output rate (baudRate/10 char/s), your system will be unable to keep up.

With an interrupt driven system, make sure your interrupt function executes and returns as quickly as possible, i.e., does as little as needed to not lose data. Let the background process (the main sketch code) deal with the incoming data as it appears. Make sure the both processes are short enough to deal with the worst-case input-data bursts without losing any. For the background process, use as high a baud rate as it is capable of - and as it's downstream neighbor (Storage device? Another MCU or PC?) is capable of - keeping up with.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.