Building a CAN API for Arduino DUE

Anybody?

Here's my CAN_RX code if that helps (can't find the CAN_TX at the moment, I will have to search around for that if it's needed):

CAN_RX.ino:

// CAN_RX.ino
// Arduino Due - CAN Test based on CAN Sample 3
// RX Side
 
// Required libraries
#include "variant.h"
#include <due_can.h>
 
#define TEST1_CAN_COMM_MB_IDX    0
#define TEST1_CAN_TRANSFER_ID    0x07
#define TEST1_CAN0_TX_PRIO       15
#define CAN_MSG_DUMMY_DATA       0x55AAAA55
 
// CAN frame max data length
#define MAX_CAN_FRAME_DATA_LEN   8
 
uint32_t receivedFrames;
 
void setup() {
 
// start serial port at 115200 bps:
  Serial.begin(115200);
 
  // Verify CAN0 initialization, baudrate is 1Mb/s:
  if (CAN.init(SystemCoreClock, CAN_BPS_1000K)) {
 
    // Disable all CAN0 interrupts
    CAN.disable_interrupt(CAN_DISABLE_ALL_INTERRUPT_MASK);
 
    // Configure and enable interrupt of CAN0, as the tests will use receiver interrupt
    NVIC_EnableIRQ(CAN0_IRQn);
  }
  else {
    Serial.println("CAN initialization (sync) ERROR");
  }
 
}
 
// Test the transmission from CAN0 Mailbox 0 to CAN1 Mailbox 0
static void test_1(void)
{
  //Reset all CAN0 and CAN1 mailboxes:
  CAN.reset_all_mailbox();
 
  //setup four receive mailboxes that each accept a different frame id
  for (uint8_t count = 0; count < 4; count++)
  {
    CAN.mailbox_set_mode(count, CAN_MB_RX_MODE);
    CAN.mailbox_set_accept_mask(count, 0x7FF, false); //only accept the exact ID
    CAN.mailbox_set_id(count, TEST1_CAN_TRANSFER_ID + count * 4, false);
    Serial.print("ID: ");
    Serial.print(TEST1_CAN_TRANSFER_ID + count * 4);
    Serial.print("\n");
   
  }
 
  // Enable interrupt for mailboxes 0-3 on first canbus
  CAN.enable_interrupt(CAN_IER_MB0 | CAN_IER_MB1 | CAN_IER_MB2 | CAN_IER_MB3);
 
  // Wait for the communication to come in.
  Serial.print("Waiting for a frame...\n");
  Serial.print(CAN.rx_avail());
  while (!CAN.rx_avail()) { //while no frame is received
  }
 
  RX_CAN_FRAME inFrame;
  while (CAN.rx_avail()) {
      CAN.get_rx_buff(&inFrame);
      receivedFrames++;
  }
}
 
// can_example application entry point
void loop()
{
 
// Run test
while (Serial.available() == 0)
{
  Serial.print("Testing...\n");
  test_1();
  delay(8);
  Serial.print(" R: ");
  Serial.println(receivedFrames);
  Serial.print("\n");
}
 
// Disable CAN0 Controller
CAN.disable();
 
while (1) {
        }
}

Your CANH/L signals look awful. There is way too much slope on those signals. Are you terminating each end with 120 ohm resistors? Your pictures look to have something like 100k and 22k resistors (it's hard for me to make out all the colors) which doesn't seem to make sense unless I'm looking at the wrong thing.

Collin80:
Your CANH/L signals look awful. There is way too much slope on those signals. Are you terminating each end with 120 ohm resistors? Your pictures look to have something like 100k and 22k resistors (it's hard for me to make out all the colors) which doesn't seem to make sense unless I'm looking at the wrong thing.

Looks like that's the error... accidentally read that off the schematic as a 120k (didn't have any in stock which is why I had the 120k+22k series combo). I'll have to solder in a 120ohm and see if it works.

Thanks for your help,
Shep

This may be a silly question, but I'd like to ask about the status of this library's API....

Specifically, is this really the final "official" API for CAN on Arduino?

The reason I ask is because this API seems to disregard many of the common conventions and the overall style of Arduino APIs. Most communication libraries inherit Stream or mimic Stream. The init(), rx_avail(), get_rx_buff() and sendFrame() are pretty close, but they do require users to deal with structs, which is not commonly done with Arduino APIs. The mailbox API seems to be particularly complex, and tied to Due's specific hardware, rather than attempting to provide a simplified abstraction that most Arduino users expect, with just a few easy-to-learn functions which cover most common needs.

Another common design feature of many Arduino APIs is the use of hardware neutral base classes. Stream doesn't neatly fit CAN. The closest is probably Udp.h, which Arduino 1.0 added to the core library. The idea is you can write a UDP-based library or sketch using the base class functions, and then it will work when used with different libraries (eg, both Ethernet and Wifi). Perhaps CAN needs its own abstract base class? This sort of abstraction seems particularly valuable for developing the higher level protocols, like ODB-II.

So my question is whether this API is now forever fixed, or if it's still in significant development, and if it is, would a migration towards a more Arduino-like API be welcome?

I'd call the current state of the canbus library "just barely operational enough to be useable." And, I say that being one of the people responsible for it. It does include a total mish-mash of API formats. I suppose the proper answer to your question is that it's still in a state of significant development and, yes, migrating to a more Arduino friendly format would probably be a good thing. The library is used in a project of mine and I think we added a couple of convenience functions that maybe didn't make their way back into the library but either way the library is a mess. I had always meant to go back and clean it up but you know how that goes. It works so nobody ever quite gets back around to making it pretty. I do still want to fix it up though.

Thanks Collin, for such an honest appraisal.

Within the next few months, I plan to work on a new CAN library for different hardware. I had hoped to work towards compatibility with a well-defined official Arduino CAN API. Seems such an API is still some distance in the future?

When talking about APIs for Arduino, it's usually good to refer to Arduino's style guide.

Bringing up new hardware AND designing an official API (implementing and testing on Due as well) might be more work that I can realistically take on? Then again, I'll need to implement something for an API. I really do care deeply about compatibility. I know from experience that starting without an API plan usually results with an API deeply rooted in the hardware's specific details. From what I can see, it looks like the Atmel guy did this, then you've been adding the higher level stuff?

My hope at this point, if you and others are willing, would be to discuss what the final, official Arduino CAN API might be, in a perfect universe where we all had plenty of time to actually work on the code?

I've been reviewing the existing CAN APIs. So far, I've found 3 Arduino libraries: this one, Seeed's for their MCP2515-based shield, and ChipKit. Seeed's API is fairly simple, just 8 public functions. ChipKit's API is horribly complex. The other API I've seen which seems the most Arduino-like, is mbed's:

http://mbed.org/handbook/CAN#api

I'd like to ask a couple specific API questions...

#1: How do you feel about using a special typedef or object for message data, versus primitive types? Currently Due, Chipkit and mbed use these. It does allow passing more info together, like the ID, length, timestamp. But it also doubles the API, from just one object that communicates to 2 objects, with more stuff to learn to create and extract the data.

#2: Does providing mailboxes in the API add more benefit for users than the increase in complexity and overall size of the API they require? For many Arduino users, the ease of learning is key. An API with fewer than 10 functions, where all have simple names, seems approachable. Seeed and mbed don't expose mailbox functionality. Due and ChipKit have APIs with dozens of functions and long lists of constants. So my question is whether mailbox access (rather than simple read & write) is really beneficial for some uses, and what those applications might be?

I made a quick PCB layout for the schematic in message #33. Here the shared design, if anyone's interested.

http://www.oshpark.com/shared_projects/e2BC6FkW

Any progress on this effort?

What can be done to help?

bvernham:
Any progress on this effort?

What can be done to help?

Sorry, I haven't gotten around to working on the library in some time. I do hope to get back to it soon.

At this point what needs to happen is for someone (me, you, someone) to create a sensible API that we would then follow. The way it works currently is very convoluted and silly. You shouldn't need to know so much about the hardware to use the library. Paul had wanted to do all of this a while back and things just sort of fell by the wayside - probably my fault. He had mentioned looking at the APIs for things like mbed. That's probably a good idea. Ideally we'd have an API where you initialize a canbus port by giving the speed and then you can set the filters in an easy way and send frames just by giving an ID, whether it is extended or standard, and the data bytes. There should be a structure or class that we use for canbus frames. It probably would be easiest if we used the same structure/class for both RX and TX frames even though they've got slightly different info (RX frames have no priority while TX frames do).

I am still planning to work on this. Since mid-November, a number of things have happened.

PJRC released Teensy 3.1 on December 9. Obviously my main interest is developing a library to support CAN on Teensy. I do want to work towards a really good, hardware-neutral API, even if that means getting somewhat involved in redesigning Due's library.

So far, the only real "work" I've done on CAN is buying and building hardware. I built up that little circuit board for Due, and a CAN interface board for Teensy 3.1, and I purchased a couple MCP2515-based modules and connected them to the other Teensy boards. As you can see, I've been putting together the hardware side for working on a CAN library.....

Paul. I'm watching this intently, but helping would be way beyond my skill level. My main interest in this is automotive, and specifically motorbike at that. I already have an Uno with Sparkfun CAN shield which I've used to monitor and subsequently decode much of the data on my Ducati Multistrada. An easy to DIY teensy solution will address my current space issues.

P.s. Excuse the slightly arrogant user name, it up was one that I used on a Ducati forum so dealers wouldn't link the posts back to me and then deny and future (unrelated) warranty claims!

I have some experience with the MCP2515 with both the ISO and the J1939.

I built logger and gateways using the UNO and the 1284P.

I also have access to buss analysis tools and would be willing to help out as needed.

Thanks

Bruce

What bus analyzer do you use? I've been considering getting one of these, but mainly because I have their USB analyzer that works quite well.

Truth is, I have pretty much zero experience with CAN bus. But I do have 20+ years experience developing with microcontrollers and several years on Arduino libraries and code.

I could use a little advice about what to do on the CAN side of things.....

I use the Vector CANALYZER PRO with J1939 option.

These are pretty expensive and I have tried to replace this with some small micros. I have 4 gateways running with UNO's right now. $80 bucks ~$2000.

Any help is greatly appreciated, you guys are the greatest. I just want to send and receive one message in 11 bit and 29 bit. When I change the example DUMMY_DATA to 0x1234 and 0x5678, I get some kind of endian format with number pairs reversed. And the 29 bit message header is always 0. I can't get the message header for 29 bit. I have a seeeduino shield to monitor also. The seeeduino receives the right bit header, but not the Due. It also does not seem to send the 11 bit correctly. I tried to clear codes on my car but was not successful. The message never got interpreted by the ecu correctly.
Would someone be able to post simple code that I can analyse? I only want one mailbox to send, and then receive for 11 and 29 bit - all masks will do.
I too am watching this forum closely. I agree that the code should be simplified, like seeeduino with less concern for the Due internals.

I put in an order for the OSH Park Arduino Due CAN Test Board.
Does anyone have a parts list or link to a shopping cart (jamco, mouser, digikey) I can use for the can transceiver, resistor, caps, and DB9 header.
I am fairly new to surface mount components and am not sure what physical size components were used in the design.
I already have a DB9 to OBD adapter from the UNO can shield.

Yes pm me. Fwiw I finally have a production run of shields on order and I can share some of my prototyping stuff and parts list.

Arbies:
I put in an order for the OSH Park Arduino Due CAN Test Board.
Does anyone have a parts list or link to a shopping cart (jamco, mouser, digikey) I can use for the can transceiver, resistor, caps, and DB9 header.

Yes, here you go. I also updated the description at OSH Park.

    Qty   Digikey P/N       Description
    ---   -----------       -----------
     2    296-27991-1-ND    CAN transceiver
     2    445-7660-1-ND     Capacitor, 10uF, 805
     2    399-1170-1-ND     Capacitor, 0.1uF, 805
     2    609-4003-ND       DB9M connector
     2    CF14JT120RCT-ND   Resistor, 120 ohm
     2    3M9447-ND         Header, 2 pin
     2    3M9580-ND         Jumper

Ok, it seems I had to send three times to the ecu before it responded.
id = 0x7DF
databyte[0]=0x2
databyte[1]=0x1
databyte[2]=0x0
databyte[3 to 7] = 99
global send three times in succession did the trick. I guess my jury-rigged shield needs help.

Well I finally got my shield to work reliably, bad soldering was the problem.
Now I am faced with a 29 bit extended frame problem.
I modified the Sample 4 to Serial print some data

#define TEST1_CAN_TRANSFER_ID 0x11AE756A //random 29 bits

CAN.get_rx_buff(&inFrame); //read the message
//display the message
Serial.print(" fid ");Serial.println(inFrame.fid);
Serial.print(" ide ");Serial.println(inFrame.ide);
Serial.print(" inFrame id = "); Serial.println(inFrame.id, HEX);
Serial.print(" id len = "); Serial.println(sizeof(inFrame.id), HEX);

What I don't see correctly is the inFrame.id.
This is what I get:
inFrame id = 2756A
id len = 4
fid 40000000
ide 1

The due_can.cpp file has the following:
ul_id = m_pCan->CAN_MB[uc_index].CAN_MID;
if ((ul_id & CAN_MID_MIDE) == CAN_MID_MIDE) { //extended id
rxframe->id = ul_id & 0x3ffffu;
//rxframe->id = (ul_id); // I wanted to look at the id - it always returns a 3 in the leftmost position
rxframe->ide = 1;
}
else { //standard ID
rxframe->id = (ul_id >> CAN_MID_MIDvA_Pos) & 0x7ffu;
rxframe->ide = 0;
}

inFrame id = 2756A //should be 11AE756A that was set as the id
id len = 4
fid 40000000
ide 1
Here is the modified cpp file result:
inFrame id = 31AE756A

I modified the file to look at the id and it returns 31AE756A (always a 3 in front)

I am hoping someone will show me just how dumb I am that I am overlooking an obvious parameter.