Photon CAN Bus [Completed]

I posted a comment on github.
can.addFilter needs a parameter to specify if it is filtering extended or standard CAN frames.

I can confirm that the CAN driver reads real messages from my car’s OBD-II port.

2 Likes

Sweet! When will this be merged back to the trunk? Do I need to do something to create the pull request?

Thanks gents for your efforts! This turned out really well!

It will be merged before we release 0.4.9 in the next week. But since you’re building locally there’s nothing to stop you building from that PR. Only online use (via Build or Dev, or CLI) that requires waiting for the next release.

1 Like

Hi all,
Fantastic effort all round, can’t wait to get experimenting!
Would it be possible for someone lay it out plane and simply on getting started using the CAN implementation for those new to working with particle and CAN?

@jvanier I have cloned the latest commit to a new directory. Compiled it as modules and downloaded it to my photon. It appears that everything is working.

I tested transmitting large amounts of data to overflow the transmit buffers. It transmitted what it could before the buffers filled. So that is good.

I also tried to receive large bursts of messages and got the same results, good!

The last thing I tried was to compile that application standalone. I have not done this before so I could be doing it wrong. But it did not compile.
What I did:
went to the firmware\user> directory.
ran the following command:

make clean all -s PLATFORM=photon COMPILE_LTO=n APP=can program-dfu PARTICLE_DEVELOP=1

I got the following results.

    C:\Particle\firmware\user>make clean all -s PLATFORM=photon COMPILE_LTO=n APP=can program-dfu PARTICLE_DEVELOP=1
c:/particle/toolchain/gcc-arm/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000
../build/target/user/platform-6/applications/can/applications/can/application.o: In function `__static_initialization_and_destruction_0':
C:\Particle\firmware\user/../wiring/inc/fast_pin.h:113: undefined reference to `HAL_Pin_Map'
../build/target/user/platform-6/applications/can/applications/can/application.o: In function `__static_initialization_and_destruction_0':
C:\Particle\firmware\user/applications/can/application.cpp:29: undefined reference to `CANChannel::CANChannel(HAL_CAN_Channel, unsigned short, unsigned short)'
../build/target/user/platform-6/applications/can/applications/can/application.o: In function `startup0':
C:\Particle\firmware\user/applications/can/application.cpp:34: undefined reference to `__dso_handle'
C:\Particle\firmware\user/applications/can/application.cpp:34: undefined reference to `system_thread_set_state'
c:/particle/toolchain/gcc-arm/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld.exe: ../build/target/user/platform-6/applications/can/libuser.elf: hidden symbol `__dso_handle' isn't defined
c:/particle/toolchain/gcc-arm/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld.exe: final link failed: Bad value
collect2.exe: error: ld returned 1 exit status
make: *** [../build/target/user/platform-6/applications/can/libuser.elf] Error 1

To compile the application as 1 binary (non-modular) instead of system 1, system 2 and user modules, you need to be in the firmware/main directory and do

make all program-dfu PLATFORM=photon MODULAR=n APP=can PARTICLE_DEVELOP=1

I wanted to compile the application so that it used system 1 and system 2, but not have to compile the system parts, only the application. I had not done that without using CLI or Web.

Not sure if that is possible or not, but I have an old laptop and compiling everything takes a while. I guess I could choose not to do a clean…

Got it. You have to build in firmware/main to build only the user module. You can use the same build command you use in firmware/modules when you build all 3 modules.

I added a list of common firmware build commands a while back. You can refer back to that later.

So are we all good to have this in the next release, next week?

I’ll have a chance to test on some big machinery in the next month. Some CAT marine engines. Love the potential here. Does anyone have a step by step procedure to follow for utilization? I’ll help write if one does not exist…

This will be released next week in 0.4.9 with docs! :smile:

Better docs are on the way, here's a start.

You'll need a CAN transceiver with the TX pin connected to D1 and the RX pin connected to D2.

Here's sample code for receiving and transmitting messages.

CANChannel can(CAN_D1_D2);

void setup() {
    can.begin(125000); // pick the baud rate for your network
    // accept one message. If no filter added by user then accept all messages
    can.addFilter(0x100, 0x7FF);
}

void loop() {
    CANMessage Message;

    Message.id = 0x100;
    can.transmit(Message);

    delay(10);

    if(can.receive(Message)) {
        // message received
    }
}

The CAN message struct has these members:

struct CANMessage
{
   uint32_t id;
   bool     extended;
   bool     rtr;
   uint8_t  len;
   uint8_t  data[8];
}
4 Likes

Great job, I am able to build, download and run either tinker or my version of the CAN application from the 0.4.9 https://github.com/spark/firmware. What is involved with getting the WEB IDE to use the 0.4.9 firmware for building? It is saying “You are building with firmware: Latest (0.4.7)” and it doesn’t recognize existence of the CANChannel.

0.4.9 hasn’t been released yet. RC1 was tagged in github, but we have found a stop-ship issues that we need to resolve before shipping the release.

1 Like

So if we build from that firmware link using CLI we should be able to use the CAN driver? Its just the WEB IDE that won’t work until they resolve issues with the 0.4.9 Firmware?

Thank you, great help. I’m sure its in the data sheet but do you know how many message id filters are available?

14 id/mask filters. So a filter could accept many messages, for example id=0x300 mask=0x700 accepts 0x300 to 0x3FF.

I'm having a bit of trouble getting this to work. I'm fairly new to coding, so chances are that I just made an ignorant mistake.

Here's what I've got:

CANMessage unlockMsg;
unlockMsg.id = 0x1C0;
unlockMsg.extended = false;
unlockMsg.rtr = false;
unlockMsg.len = 6;
unsigned char unlockData[8] = {23, 00, 00, 90, 11, 00};
unlockMsg.data = unlockData;
can.transmit(unlockMsg);

It is giving an invalid array assignment error regarding unlockData. I appreciate the help.

@flyingfedora
unlockMsg.data is an array of 8 bytes. So you do not have to create an additional array.

struct CANMessage
{
   uint32_t id;
   bool     extended;
   bool     rtr;
   uint8_t  len;
   uint8_t  data[8];
}
1 Like