ESP8266 MCP2515 CAN Bus to Wifi Gateway

It’s working! As far as I can find, this is the first example of an MCP2515 CAN SPI module working with an ESP8266.

Previous post on my setup with ESP8266 and MCP2515

Two Way CAN ESP8266


After lots of reading and learning about SPI and the MCP2515 control registers, it seems that I am able to transmit and receive CAN messages from the ESP8266. Currently I am using the Arduino CAN library for Arduino released by CoryJfowler on GitHub (found from this post on Arduino forum). I have made a few modifications to this library which I need to tidy up and determine whether they are required and will then release my version.

The key to getting this working seemed to be updating the bit timing registers because my board has an 8MHz oscillator rather than the 16MHz ones found on the Seeduino CAN boards

My recommended steps for testing:

  1. Set up a sketch with both transmit and receive functions in
  2. Put the MCP2515 into loopback mode
  3. Ensure you are able to both transmit and receive in loopback mode – this will ensure your code is correct
  4. Finally enable ‘normal mode’ to transmit, and use a reliable CAN transmit/receive device to check your messages

My sketch is as follows (requires the MCP_CAN_lib from CoryJfowler) plus mods to set

CNF1 = 0x40
CNF2 = 0xF1
CNF3 = 0x85

as found on http://www.canhack.org/board/viewtopic.php?f=1&t=1041

Send a serial ‘n’ or ‘l’ to switch between ‘loopback’ and ‘normal’ mode.

// demo: CAN-BUS Shield, receive data
#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(4);                               // Set CS to pin 4 (D2 on my NodeMCU)
unsigned char stmp[8] = {0, 1, 2, 3, 4, 5, 6, 7};

void setup()
{
  Serial.begin(115200);
  CAN0.begin(CAN_250KBPS);                       // init can bus : baudrate = 250k 
  pinMode(2, INPUT);                            // Setting pin 2 for /INT input (D4 on NodeMCU)
  Serial.println("MCP2515 Library Receive Example...");
  Serial.print("CANSTAT: ");Serial.println(CAN0.mcp2515_readRegister(MCP_CANSTAT),BIN);
   CAN0.mcp2515_modifyRegister(MCP_CANCTRL,MODE_MASK,MODE_LOOPBACK); // MODE_NORMAL MODE_LOOPBACK
   Serial.print("CANSTAT: ");Serial.println(CAN0.mcp2515_readRegister(MCP_CANSTAT),BIN);  

}

void loop()
{
    if(!digitalRead(2))                         // If pin 2 is low, read receive buffer
    {
      CAN0.readMsgBuf(&len, rxBuf);              // Read data: len = data length, buf = data byte(s)
      rxId = CAN0.getCanId();                    // Get message ID
      Serial.print("ID: ");
      Serial.print(rxId, HEX);
      Serial.print("  Data: ");
      for(int i = 0; i<len; i++)                // Print each byte of the data
      {
        if(rxBuf[i] < 0x10)                     // If data byte is less than 0x10, add a leading zero
        {
          Serial.print("0");
        }
        Serial.print(rxBuf[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
      // send data:  id = 0x00, standrad flame, data len = 8, stmp: data buf
  if(Serial.available()){
    stmp[0] = Serial.read();
    if(stmp[0] == 'l'){
      CAN0.mcp2515_modifyRegister(MCP_CANCTRL,MODE_MASK,MODE_LOOPBACK); // MODE_NORMAL MODE_LOOPBACK
    }
    if(stmp[0] == 'n'){
      CAN0.mcp2515_modifyRegister(MCP_CANCTRL,MODE_MASK,MODE_NORMAL); // MODE_NORMAL MODE_LOOPBACK
    }
    
  }
  CAN0.sendMsgBuf(0x00, 0, 8, stmp);
  //Serial.print("CANSTAT: ");Serial.println(CAN0.mcp2515_readRegister(MCP_CANSTAT),BIN);  
  delay(100);                       // send data per 100ms
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

41 thoughts on “ESP8266 MCP2515 CAN Bus to Wifi Gateway

  1. ss

    Wonderful blog you have here but I was curious if you knew of any community forums that cover
    the same topics discussed here? I’d really love to be a part of online community where I can get responses from other experienced people that share the same interest.
    If you have any recommendations, please let me know.

    Bless you!

    Reply
    1. Scott Snowden Post author

      I dont really, but I think I seem to remeber a CAN bus forum floating around at some point…

      Reply
  2. zeze

    Hi everyone, it’s my first go to see at this web site, and paragraph is truly fruitful for
    me, keep up posting such content.

    Reply
  3. recently

    Hello dear Scott,
    this project is absolutely great. After I found your page page with google I immediately buyed all parts and I`m now trying to get your brilliant concept run.

    Actually I want to connect the NodeMCU with the MCP2512 but I`m stumbling over the used pins :

    Here the pins of the MCP-Board:
    INT: ok, sourcecode says it is D4 on NodeMCU
    SCK: is it CLK (SCLK) or D5 (HSCLK )?
    MOSI: is it SD1 (MOSI) or D7 (HMOSI) ?
    MISO: is it SD0 (MISO) or D6 (HMISO) ?
    CS: ok, sourcecode says it is D2 on NodeMCU (not CMD(CS) and not D8 (HCS))
    GND: ok
    VCC: ok

    Can you give me a hint, please ?

    friendly regards
    recently

    Reply
  4. Al

    This is great work! Thanks for sharing. How do you intend to make use of WiFi?

    SS: I agree, a forum on CAN Bus would be great. It wouldn’t take much to start one but I’m not so sure there would be a lot of interest.

    Reply
  5. ArduWin

    thank you for this fantastic article!
    i started to work with canbus and want to read that data wireless.
    did you try to send those canbus data to a mqtt broker?
    this is want i want to realize.

    canbus device (data) -> esp8266 (client)-> mosquitto ( broker) -> mobilphone (client)

    this weekend i try to setup my raspberry pi (archl inux) with mosquitto.
    i will order a esp8266 and mcp2515 the next days.

    Reply
    1. Scott Snowden Post author

      Hi, yes I did look into this and there is no reason why not. There are lots of MQTT examples with the ESP8266

      Reply
  6. Piotr

    “I have made a few modifications to this library which I need to tidy up and determine whether they are required and will then release my version.”

    Can you publish your code and some examples ??
    It’s very hard to find some examples with CAN module.

    Reply
    1. Scott Snowden Post author

      If you take a look at the latest version of the library from Cory, i believe these changes are incorporated.

      Reply
    1. Scott Snowden Post author

      To be honest, I hadn’t noticed I was, but this was just a quick stab at fetting this working, so wasn’t too worrie about good practices.

      Reply
  7. coryjfowler

    Well, small world! I found your site because of your fuel injected Briggs project and I am doing something similar with an old 5hp flathead I picked up recently. Then I seen your CAN topic on the side and it sparked my curiosity. If you weren’t aware, the sub-development version of the library brought out a mode control function and the use of 8MHz, and 20MHz crystals on the MCP2515. I also just recently made the sub-development branch the main version, so just update your library with the main branch.

    Reply
    1. Scott Snowden Post author

      Hiya, thanks for the comment! It is a small world, and a big coincidence that I actually came home today to start work on this project again! Thanks for your contribution to the cause.

      Ok, great, will pull the main branch, that will make life easier for others too.

      What’s your ECU project? I would take a look at speeduino, its very well progressed!

      Reply
  8. Michael L

    Hi,

    Just tried this with my NodeMCU v1.0 & Arduino. For some reason I always get ‘Error initializing library”.

    Does this mean SPI is not working between the breakout board and NodeMCU ?

    Reply
  9. MIchael L

    output from:

    can-calc-bit-timing -b 250000

    Bit timing parameters for mcp251x with 8.000000 MHz ref clock
    nominal real Bitrt nom real SampP
    Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error CNF1 CNF2 CNF3
    250000 250 6 7 2 1 2 250000 0.0% 87.5% 87.5% 0.0% 0x01 0xb5 0x01

    this suggests:
    CNF1 0x01
    CNF2 0xb5
    CNF3 0x01

    Reply
      1. Michael L

        In Linux install ‘can-tools’. That provides program called ‘can-calc-bit-timing’.

        Reason I mentioned this is that it suggests different values that are found in the MCP_CAN lib defs.

        For 8Mhz 500kBPS:

        #define MCP_8MHz_500kBPS_CFG1 (0x00)
        #define MCP_8MHz_500kBPS_CFG2 (0x90)
        #define MCP_8MHz_500kBPS_CFG3 (0x82)

        can-calc-bit-timing suggests 8MHz and 500kBPS:

        CNF1 0x00
        CNF2 0xb5
        CNF3 0x01

        I have no means to check which is correct or it may that both work. But it would be a nice to hear some good explanation for the difference.. Thanks!

        Reply
  10. Michael Luyten

    I have tried your code with cory’s CAN library and i’m getting a heap of compile errors. Have you got a more recent version of your code you could post?

    Reply
    1. Scott Snowden Post author

      I’m afriad i dont actually. I do intend working on this project again soon. Whats the error you’re getting?

      Reply
  11. Pingback: Inspiration: CAN Bus links - Experimental Avionics

  12. chris

    HI, this is very interesting and encouraging… however i’m having some difficulty..

    the code seems to load and begins to run (although i do see “Entering Configuration Mode Failure” from mcp_can.cpp in the serial output).

    Then after this sketch initializes, it drops down to 74880 baud and just does :

    Fatal exception (0):
    epc1=0x40100003, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000000, depc=0x00000000

    Any ideas? I have tried with two different Nodemcu, two different cables, and have built with both arduino ide and platformio, all same results.

    thanks

    Reply
  13. chris

    Sorry never mind the bit about the error in mcp_can – that was because the MCP was disconnected.

    With it connected, it always boots and goes directly to the fatal exception.

    Reply
  14. Jeroen

    For my BEV I made a gateway between a Bluetooth ELM327 dongle (a KONNWEI902) and the home WiFi network using an EP8266 (WeMos). The Wemos is a webserver implementing in essence three primitives: Init (obviously!), getFreeFrame (to snif operational frames the car is sending between it’s ECUs), getIsoTpFrame (to query-response diagnostic commands OBD2-ish style). I needed this for two purposes:
    – integrating my BEV charging with my PV;
    – testing of an Android app ( canze.fisch.lu ) without going back and forth to the car. The ELM is the “normal”, consumer grade device that the app uses; the gateway is an alternative driver the app can use.

    Because things are now http based, I can emulate it through a simple webserver for testing, test thins with simple PC tools, run it in the Androis emulator, but I digress.

    My intention is to build another one that on the WiFi side will do exactly the same as said gateway, but do it straight on the CANbus using the MCP2515 instead of a Bluetooth interface to the dongle. Should be much, much faster than the dongle.

    Thanks for the coding head-start. And to Cory of course for the mcp library! I will post progress on mentioned website for anyone interested.

    Reply
  15. Erol S

    Scott,
    I am trying to duplicate your result in my setup, but I could not get it working, I complied the code (example CAN loopback example comes with library), it compiled fine and then upload the code to esp-12e module through usb, my problem with wiring of SPI communication since esp is 3.3V device but 5 V tolerant I connected CAN module to 5V power, then MOSI and MISO connection was not without any level converter it was directly connected, but I am not getting loopback connection successful, I looked at datasheet of MCP2515 controller VIHL figure is 0.7*Vsupply if supply voltage is 5, lowest voltage that CAN controller accept is 3.5 as high value but esp can only provide 3.3 volt as highest, therefore you have to use level converter (3.3V 5V ) if I apply 3.3 V as power to CAN controller TJA 1050 trans chip require 5V for operation, my question is how did you solve this predicament?
    btw I compiled the same code for Arduino UNO and wired CAN module to its SPI bus, it worked fine, that is sort of expected since it is 5V device

    Reply
    1. Scott Snowden Post author

      Hi Erol,

      I did find the same thing with mine. You’re right, the ESP12e wants 3.3V supply (I didn’t think the pins were 5V tolerant either but I may be wrong…) The MCP appears to be able to handle 3.5 to 5V as you say, no should be no problems there, and the TCP needs 5V, so I supplied my CAN board with 5V, and just connected the SPI lines directly. I believe this is exactly what you have done by the sounds of it. Have you also got the CS line connected?

      I don’t really have any ideas why it wouldn’t be working, I suppose it could be that mine was only barely working by chance, and some tolerance difference on your setup means it’s just outside working voltage ranges, however I think this seems unlikely. May it be that you’ve got a slightly different breakout board to me and it has other components e.g. LEDs or Pull-somewhere resistors? It could be worth changing the pins to a different set of possible. I do also know the pin numbering can get a bit confusing, double check you’re happy with that…

      Good luck, let me know how you get on!

      Reply
  16. Erol S

    Sctott,
    thank you for your quick reply, yes I did connect 5 V power supply and SPI connection is made without level converter, it sounds you did not use any level converter either, I connected CS line to one of the GPIO data pin as your code suggested, (I used D2 like yours) but CAN.begin() process fails (to more accurate when I completely do complete power cycle sometimes it says loopback communication successful, but when I reset esp module it falls to Communication Unsuccessful, it is not consistent), if you notice on NodeMCU there is a CS pin available, is that for hardware SPI communication?

    Reply
  17. Jeroen

    I know there is a lot of confusion about this, but the ESP is 99% sure not 5 volt tolerant on the inputs. If you insist, at least put a small resistor in the line (i.e. 1K) so you won’t slowly fry out the over voltage protection diodes to VCC. Worst case, your entire VCC line will be pulled up.

    Usually overvoltage on IO pins will not immediately blow up a chip. Just saying is “oh it works” “it is tolerant”.

    Reply
    1. Jeroen

      Oh darn, blog software removes the “unequal symbol. Read that as:
      “oh it works” is not the same as “it is tolerant”.

      Reply
  18. wjr

    Great work, as I can tell so far.
    I am looking for a CAN driver to implement in the nodemcu ecosystem
    https://nodemcu.readthedocs.io/en/master/

    This is basically ESP8266 hardware, but a special firmware on it that allows interactive development using lua high level language.

    Is anybody aware of a port of your lib to nodemcu?

    Reply
  19. Christian

    Hey Scott,

    I’m currently trying to duplicate you code, but cant get it to run.
    I codes everything as written above, but its always has some problems with the library. Can you please upload your version of the lib somewhere?

    Reply
  20. Christian

    One more question:
    Did you change anything in the SPI.h? Or does the ESP8266 already know the correct SPI pins?

    Reply
  21. Nikolay Pushkar

    Got it working: NodeMCU ESP8266 CAN MCP2515_CAN board like yours.
    Notice that on NodeMCU: D2 is pin 4 (put CS there), and D4 is pin 2 (interrupt).
    Use GPIO12,13,14 which are marked HSPI and D7,6,5 respectively.
    Supply CAN board with 5V and Ground. No other connections needed.
    Coryjfowler’s loopback works fine.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *