CANbus talker vs listener

Hello,

My goal is to use 1 electron to emulate the client’s large piece of equipment, and a 2nd electron as the data collection node.

The client equipment includes a CAN J1939 device (engine) as well as a number of other data sources (serial, analog …).

My first step, was to build a standalone program running on a single Electron, that generates simulated data using CAN in CAN_TEST_MODE (DAC to source ADC, Serial 4 to source Serial 5), acquire all the data, publish the data, etc. This all works as expected.

However, when I take the CAN out of CAN_TEST_MODE and jumper CAN Tx to Rx (as with a serial port) I do not receive messages.

So, I created a short test code with a bunch of diagnostic messages to help determine what the issue is.

The results are that the CANbus gets enabled, no CANerror, the first message gets queued but not sent, and then the CANbus goes into passive listen move, & no messages received.

enabled
no_error
tx msg queued

enabled
error_passive
tx msg queued

enabled
error_passive
tx msg queued

enabled
error_passive
tx msg queued

etc.

I strongly suspect that I am missing an acknowledgement after the CANbegin, that tells the device that it has been recognized as a member of the CANbus. Sadly, no o-scope on hand where I am at currently.

Code follows:

// --------------------------------------------
// can loopback test
// --------------------------------------------

//include

//

//define
int next = 0;
int rate = 5000;
long lastMeasurement = 0;
//

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

    CANChannel can(CAN_D1_D2);
    //can.begin(500000, CAN_TEST_MODE);
    can.begin(125000);

    }

//

void loop() {

//setup message tx rate

    if(millis()-lastMeasurement > rate) {
        
        //generate a short incrementing message

        CANChannel can(CAN_D1_D2);
        
        if(can.isEnabled()) {
            Serial.println("enabled");
            }
        if(can.errorStatus() == CAN_NO_ERROR) {
            Serial.println("no_error");
            }
        if(can.errorStatus() == CAN_ERROR_PASSIVE) {
             Serial.println("error_passive");
            }
        if(can.errorStatus() == CAN_BUS_OFF) {
            Serial.println("bus_off");
             }
        
        CANMessage message;
        message.id = 0x100;
        message.len = 1;
        message.data[0] = next;

        can.transmit(message);
        
        if(can.transmit(message)) {
            Serial.println("tx msg queued");
            }
        
        delay(10);
        
        if(can.available()>0) {
            Serial.println("rx msg waiting");
            }
        
        if(can.receive(message)) {
            //Serial.println(message.id);
            //Serial.println(message.len);
            Serial.printlnf("rcvd: %i, %im %i", message.id, message.len, message.data[0]);
            next++;
            }
       
        lastMeasurement = millis();
        Serial.println();
        
    //end of timer loop
    }
    
// end of main loop

}

Ping @jvanier :wink:

Thanks for invoking the CAN master :wink:

For a physical CAN bus to work it needs at least 2 active nodes.

So for your project the fastest way to test is to use both CAN buses on the Electron. No need to transmit anything on the second bus, just call channel.begin. Normally you would need 2 transceivers to convert the 0-3.3V CAN RX and TX to differential high speed CAN voltages, but in this case you may get away with using a transistor in open collector mode as the transceiver with a pull up to 3.3V.

Does this make sense?

1 Like

Please see this diagram on the back of a napkin. I apologize for any obvious hardware mistakes :sweat_smile: