Teensy 3.1 and CAN Bus

wmcdonal - It's a Ducati Multistrada 1200.

Im using pawelsky''s board. Only issue was the onboard regulator wouldnt handle 12v and power the Teensy and SD board. I'm now using a 5v pololu switching regulator to drop the bike''s 12v and supply 5v to vin on the teensy. Should probably use the 3.3v version mind.
 
MrCanBus

On the MTS1200 you can send messages that come from the ECU to the dash or ECU to BBS without a problem.
Is it a 2010-2012 MTS1200 or 2013-2014 MTS1200.
Ducati changed the CAN message info on the 2013-2014 model.

What are you trying to do with the MTS1200 ?
 
This is great work. I just ordered the board from OSHPark. I'll start putting together when I get it.

I am converting an mbed project over to Teensy 3.1.

Just4Trionic

This library will make that much easier, thanks. Also the board will make it much easier to get this into the car to see what is going on.

Thanks!

KeithG
 
I did a total bodge for my testing.
I wired a 78L05 reg and a 2551 CAN chip by soldering the legs of the reg directly to the CAN chip.
Once I had the wires connected I covered it in hot melt glue then put it inside some heat shrink.

I am thinking of getting a prototype run of boards to hold the CAN transceiver and a micro SD socket.
I will make it line up so we can use a header strip to connect it to the Teensy 3.1.
 
It is a 2010-2012 model.

I was originally setting out to make a semi active suspension controller. I was going to send my own messages to the Ohlins SCU. In the end Ohlins beat me to it. Desiphering the messages to set the suspension took me a while - they have made it overly complicated, God knows why.

since then I've kept going out of curiosity, trying to map all the messages. At some point I'll get round to leaving the logger attached when it goes for a service and see what messages are used to reset the service light and read error codes.

I'm not interested in hacking the ecu to remap the bike (now im out of warranty I'll invest in tuneboy's product for that - I assume the user name is no coinsidence!), if anything I might try and build an android app/Teensy based hardware box that is capable of replacing the dashboard given the frequency with which they seem to fail (I'm most of the way there already). Unlikely to try and make a commercial venture out of this as I'll never have the time and I'm not sure if it will be MOT legal (I'm in the UK).
 
Last edited:
MrCanBus

send an eight byte packet with message ID 0x0500
0x6C,0x00,0x00,0x21,0x00,0x00,0x00,0x00

Oil service and/or Desmo service reset for your model.

With the reflash of the ECU I add extra CAN messages with the data needed to tune the bike.
The ECU on the MTS1200 uses less than half the CAN mailbox slots.

If you want to test sending CAN messages you can send the 0x80 message to test sending messages on the bus.
The ECU sends the 0x80 message and it does not care if other 0x80 messages are on the bus.
Send a message with RPM and you should see the dash show RPM and the headlight should turn on.
The 0x80 message is sent at 5 m/s intervals, You could wait until you get the 0x80 message then send 0x80, this will mean your message is the one the dash will use.
 
Thanks for the info ref service light. Even BMW let you DIY reset (cars) so not sure why Ducati require the DDS (money !).

Will give the 0x80 messages a go, it might allow me to fill in a couple of question marks that I have regarding 0x80 byte 0, 1 and 7. Hoping I find the messages that drive the fuel consumption display which is one of the last things I'm missing to build a 'Dash Board' App. I'd always assumed that it would be smart enough to decide that the message were conflicting , e.g. 0rpm followed immediately by 2000rpm and then 0 again and would throw an error.

May be you can clear something up for me. Am I right in thinking that byte 0 (if that is the right way to refer to them) for IDs 0x100, 0x110, 0x300, 0x360 is some sort of clock signal that is used to ensure each module on the bus is present and correct and communicating with the bus? They just seem to increment 0,2,4,6,8,A,C,E and then loop back to zero.

Apologies all, I'll try not to turn this into a Ducati thread
 
On the contrary, I'm glad we're getting into some real-world interfacing.
So the examples of sending messages on the last page are correct? What my next step will be is to try and spoof lets say a turn light signal (sometimes hard to filter out by just looking at the stream), then try to send that same message through the Tsy and see if something happens.
 
Fyod

I still can't send, not sure what I am doing wrong.

Has anyone on this thread got some working code to send a CAN message ???... Please...

MrCanBus

On the Panigale 1199
Message 0x100, byte 0 , bit 5, length 3 bits.
This is the ECU Counter.
Byte 7 is fuel consumption in cc

In the E-Lock messages you need to cycle the counter to fool the bike into thinking it is unlocked.
I tested this on a Panigale and I could unplug the dash, Key lock and BBS then start the bike.
In that case I used an Innovate OT-2 to send the CAN messages.
 
Sending works fine, I even managed it first go without any schoolboy coding errors. just fed an 0x080 message into the bus on the Multistrada and got RPM on the dashboard to sit at 5000rpm. All I did was add the CAN_send routine to my code (full sample code below);

Code:
// -------------------------------------------------------------
// based on CANtest for Teensy 3.1 example by teachop
//
#include <FlexCAN.h>

unsigned long time;  //used for time stamp
FlexCAN CANbus(500000);
static CAN_message_t msg, rxmsg, txmsg;

// -------------------------------------------------------------
void setup(void)
{

  Serial1.begin(115600);
  CANbus.begin();
  delay(5000);
  Serial1.println(F("Hello Teensy 3.1 CAN Test."));
}



// -------------------------------------------------------------

void loop()
{
  if (!CANbus.available()) {
    Serial1.println("Can bus not available.  Check connections");
  }
  
  while(!CANbus.available()) {
    Serial1.println("0");
    delay(100);
  }
  
  Serial1.println("Can Bus Connected and available");   //only comes out of the above loop if CAN is available
  
  CAN_Capture();

}//end loop 
 
 
void CAN_Capture(){
  Serial1.println("CAN_Capture loop");  
  
  while(1){                 //stay within this loop unless forced out
    if (CANbus.read(rxmsg)){    //while messages are available perform the following
      if (rxmsg.id == 0x80){
        CAN_Send();
      }  
    }
  }
}  


void CAN_Send(){

  txmsg.id = 0x080; 
  txmsg.len = 8; 
  txmsg.buf[0] = 0x00;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x00;
  txmsg.buf[3] = 0x00; 
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x13;
  txmsg.buf[6] = 0x88;
  txmsg.buf[7] = 0x00;

  int m = CANbus.write(txmsg);
  Serial1.println("MSG Sent: " + m);
}
 
It does glitch every couple of seconds, getting the RPM display to momentarily flash which I assume is it getting confused by 0 and 5000rpm signals intermixing. This is partly what I assumed would happen, but no errors flagged.

Might write something now to let me manipulate the messages I'm sending real time from the laptop as opposed to coding them into the sketch so I can test how it reacts to the other bytes
 
Last edited:
Great, can't wait to try it out. Sending directly from SerialMonitor would be nice too for testing purposes.
I think in the case of RPM the signal for 5000 for example would have to be repeated every 100ms or so and keep updating. That's just a guess though.

Is there an easy way we could transform

Code:
void CAN_Send(){

  txmsg.id = 0x080; 
  txmsg.len = 8; 
  txmsg.buf[0] = 0x00;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x00;
  txmsg.buf[3] = 0x00; 
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x13;
  txmsg.buf[6] = 0x88;
  txmsg.buf[7] = 0x00;

  int m = CANbus.write(txmsg);
  Serial1.println("MSG Sent: " + m);
}

to an easier format predefined in say an mycodes.h file?

Code:
void CAN_Send_lightson(){

  txmsg.id = 0x080; 
  txmsg.len = 8; 
  txmsg.buf[0] = 0x00;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x00;
  txmsg.buf[3] = 0x00; 
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x13;
  txmsg.buf[6] = 0x88;
  txmsg.buf[7] = 0x00;

  int m = CANbus.write(txmsg);
  Serial1.println("MSG Sent: " + m);
}

void CAN_Send_lightsoff(){

  txmsg.id = 0x080; 
  txmsg.len = 8; 
  txmsg.buf[0] = 0x00;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x00;
  txmsg.buf[3] = 0x00; 
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x13;
  txmsg.buf[6] = 0x88;
  txmsg.buf[7] = 0x00;

  int m = CANbus.write(txmsg);
  Serial1.println("MSG Sent: " + m);
}

main file

Code:
CAN_Send_lightson();
delay(3000);
CAN_Send_lightsoff();

...in other words to make a "database" of messages already known to work so we can just call the function without having to look up the message format each time?
 
Last edited:
I think in the case of RPM the signal for 5000 for example would have to be repeated every 100ms or so and keep updating. That's just a guess though.

my code above should be sending RPM 200 times a second (which is significantly faster than every 100ms if my maths is correct - 5ms) as that is the frequency with which the ECU sends the 0x080 ID. I'm sending every time I see 0x080. I'm assuming it is caused by the interval between the original 0x080 message from the ecu and my spoof message.

As for the "database" idea, I'm sure that would be possible, but you need to remember that each packet contains 8 bytes which in simple terms is likely to mean 8 different things (e.g. lights) being sent at once. They would therefore need combining before being sent. My example above filled everything other than RPM with zeros but in reality you wouldn't do that. I say in simple terms as with what I know about the multistrada there are often multiple things contained in a single byte, e.g. gear position and ABS status (god only knows why !).
 
MrCanBus

Here is an example of the 080 message for the Panigale
Byte 0, bit no 0, length 1 = Clutch in or out
Byte 0, bit no 1, length 7 = Horizontal throttle angle
Byte 1, bit no 0, length 1 = Wheel speed sync
Byte 1, bit no 1, length 7 = Vertical throttle angle
Byte 2, bit no 0, length 8 = Horizontal throttle %
Byte 3, bit no 0, length 8 = Vertical throttle %
Byte 4, bit no 0, length 8 = APS
Byte 5, bit no 7, length 1 = DTC related
Byte 5, bit no 6, length 15 = RPM (This is byte 5 and 6
Byte 7, bit no 0, length 8 = Exhaust flap target
 
Im fairly sure that clutch position isn't transmitten on the CANBuS on the multi (2010-12), but it was very early on that I looked for it. I've already got the throttle positions but hadn't looked for them twice, when you say percentage is that a value between 0-100, if so I've not seen that either (my APS and TPS go up to 160 or 190 cant remeber off hand). I've got front at rear wheel speeds but haven't looked for wheel sync. Have DTC on/off signal and level setting. Fromol memory most of these are on other ID's, not 0x080.
 
wmcdonal - when you say "length 7" or "length 8" what are you referring to (excuse my ignorance, despite the user name I'm a noob)

MrCanBus

Here is an example of the 080 message for the Panigale
Byte 0, bit no 0, length 1 = Clutch in or out
Byte 0, bit no 1, length 7 = Horizontal throttle angle
Byte 1, bit no 0, length 1 = Wheel speed sync
Byte 1, bit no 1, length 7 = Vertical throttle angle
Byte 2, bit no 0, length 8 = Horizontal throttle %
Byte 3, bit no 0, length 8 = Vertical throttle %
Byte 4, bit no 0, length 8 = APS
Byte 5, bit no 7, length 1 = DTC related
Byte 5, bit no 6, length 15 = RPM (This is byte 5 and 6
Byte 7, bit no 0, length 8 = Exhaust flap target
 
Number of bits.
RPM uses 15 bits of the 16 bits in byte 5 and 6, the last bit is DTC related info.
Bit numbering
7,6,5,4,3,2,1,0 7,6,5,4,3,2,1,0
 
I modified the CAN_Send so it is sending 0x082 instead of 0x080 and added a check to shows if the send worked or not.
Code:
void CAN_Send(){

  txmsg.id = 0x082; 
  txmsg.len = 8; 
  txmsg.buf[0] = 0x00;
  txmsg.buf[1] = 0x00;
  txmsg.buf[2] = 0x00;
  txmsg.buf[3] = 0x00; 
  txmsg.buf[4] = 0x00;
  txmsg.buf[5] = 0x13;
  txmsg.buf[6] = 0x88;
  txmsg.buf[7] = 0x00;

  int m = CANbus.write(txmsg);
  if (m == 0)
    Serial.println("MSG send failed:");
  else
    Serial.println("MSG Sent:");
}
When this runs I get the following serial output
Code:
Start CAN
Hello Teensy 3.1 CAN Test.
Can Bus Connected and available
CAN_Capture loop
MSG Sent:
MSG Sent:
MSG Sent:
MSG Sent:
MSG Sent:
MSG Sent:
MSG Sent:
MSG Sent:
MSG send failed:
MSG send failed:
MSG send failed:
MSG send failed:

It looks like the eight transmit message slots get filled up then the write returns 0 because it cannot find an empty slot.
Does anyone know if the 5v MCP2551 could be the problem ?
 
Right. My brain works in DEC, and can just get itself around HEX, but hadn't really thought about this in BIN (although I've used bitshift formula to combine BYTE 5 and 6 to get RPM etc.) The suspension setting decode would have been miles simpler if I'd looked at the BIN values !!!! Muppet !! Thanks.

Number of bits.
RPM uses 15 bits of the 16 bits in byte 5 and 6, the last bit is DTC related info.
Bit numbering
7,6,5,4,3,2,1,0 7,6,5,4,3,2,1,0
 
Thanks, i've placed the order at osh park, right now i'm struggling a bit in find the micro sd socket, non similar on RS, do you have a suggestion for a place to buy in small quantities ?
Thanks.

Me too. I ordered the boards and will put one together when I receive it. I also am having trouble finding the sd card socket... No on DigiKey, SparkFun, AdaFruit and Newark... Any hints?

As the link shows, these are available from Seed Studio:
http://www.seeedstudio.com/depot/index.php?main_page=opl_info&opl_id=29. I have not had any luck finding these or the alternate elsewhere even though adamtech is a US based company. Any other help appreciated. I have the board and it is soldered to a point, but no SD.

Keith
 
Last edited:
Teensy CAN speed capability

I'm not sure if this has been covered before, but if not I think it may be good information:

In regards to using the Teensy as an interface board, we were concerned about its ability to handle high CAN speeds and data rates.
As a test point, we just ran a Teensy 3.1 at 1Mb CAN speed and managed to receive and reply to 4000 standard address 8 byte packets a second for a net bus load of 8000 packets a second. The Teensy 3.1 was running the Teachop library and we were communicating with a Peak adaptor running Pcan-view.
I'm impressed by it!
 
After looking around there didn't seem to be a good logging sketch out of the box, so I modified the example that comes with Flexcan and came up with this:

Source Code:
http://github.com/finderman2/Teensy-CAN-Logger/tree/master

By default, the file format it outputs is designed to work with Collin Kidder's excellent software, SavvyCAN available for Mac, Win, and Linux. If you want to change it to output different information or in a different order just change the lines in the if statement.
 
Last edited:
P.S I'm sure most of you know about it already but there is an excellent shield available for CAN work that includes an SD card slot + voltage regulator. You have to order the boards from OSH park and solder the components yourself, however, if anyone is interested I am selling some boards for $25 each fully assembled, I only have about 7 I can sell, so it's first come first serve. PM me if you are interested.

You do realize that this project is meant for NON COMMERCIAL (i.e. personal) use only?
 
Me too. I ordered the boards and will put one together when I receive it. I also am having trouble finding the sd card socket... No on DigiKey, SparkFun, AdaFruit and Newark... Any hints?

As the link shows, these are available from Seed Studio:
http://www.seeedstudio.com/depot/index.php?main_page=opl_info&opl_id=29. I have not had any luck finding these or the alternate elsewhere even though adamtech is a US based company. Any other help appreciated. I have the board and it is soldered to a point, but no SD.

Keith

i found them on aliexpress, was tough!
 
You do realize that this project is meant for NON COMMERCIAL (i.e. personal) use only?

Maybe I should clarify selling, if I'm lucky I might recoup a $1 or $2 per board after components, solder, time, and shipping, I would hardly call it a commercial enterprise (I'm not selling 1000/week). Just as you contributed your design to the community, I'm offering an easy option for those that can't (or don't) want to hunt down components and solder SMD parts; buying bare boards isn't within everybody's wheel house. If you don't want me to offer them thats fine, however, I'm not the only member whose offered to assemble boards for people (@onehorse)
 
Last edited:
Back
Top