Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 10 of 10

Thread: Porting C code to Teensyduino for MCP2517FD CAN FD Project

  1. #1

    Porting C code to Teensyduino for MCP2517FD CAN FD Project

    What is the best way to port C code to Teensyduino ?

    I want to use the Microchip MCP2517FD CAN FD controller with Teensy 3.2
    The code is in C but Teensy wants C++.

    I've tried adding:
    #ifdef __cplusplus // Provide C++ Compatibility
    extern "C" {
    #endif

    to the C code but when I want to access the SPI bus by adding SPI.begin() it won't compile.

    Another method I've tried is to creating a class and copy each function into the class but it was a bit of a mess and won't compile.

    The C code is at:
    http://www.microchip.com/development...artno=adm00576
    It is the MCP2517FD canfdspi API (v1.0)

    Any idea?

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,270
    You can move the C code to its own file in the project directory by using a .c suffix instead of .cpp, However, I doubt the general Arduino headers will work in a C environment.

    So, one method is to create a .h header that encapsulates the communication between the Arduino bits and the library. The Arduino side would do I/O, etc. It would call into the C functions for setup, and they in turn would call back to the Arduino libraries to do the actual I/O. It is s bit of a mess, but it might be simpler than just rewriting the whole function.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,598
    I looked at the Microchip code briefly.

    Their .h files already have this:

    Code:
    #ifdef  __cplusplus
    extern "C" {
    #endif
    First, I'd copy everything from mcp2517fd_api/firmware/src/system_config/mcp2517fd_evb_api/framework/driver/canfdspi and mcp2517fd_api/firmware/src/system_config/mcp2517fd_evb_api/framework/driver/spi into your sketch folder. Do this while Arduino is not running. I'd rename drv_spi.c to drv_spi.cpp. My personal preference would be the put all the files into the sketch folder, without any subdirectories, and then edit the #include lines as necessary to remove folder names. These massive folder hierarchies make sense for huge software projects, but they make everything a lot harder when you're just trying to get stuff done with a few files!

    You CAN leave all the other files as .c type. Arduino does indeed support using C (not C++) files. Normally this isn't done, because it's simpler to just make everything .cpp. But if the .h files that define the C stuff have those 'extern "C"' sections, then you can use the C stuff from C++ code. Those just tell the C++ compiler to call those functions as C code, rather than C++.

    Then run Arduino. The very first step will be to edit drv_spi.cpp. It only has 3 functions. You'll need to delete all their code. Because you renamed this one to .cpp, you'll be able to #include <SPI.h> and call the SPI library functions.

    The Microchip code has these includes.

    Code:
    #include "peripheral/spi/plib_spi.h"            // SPI PLIB Header
    #include "system_config.h"
    #include "system_definitions.h"
    I would just comment those out and click Verify in Arduino. You'll probably get tons of errors about undefined stuff. For each thing, I'd search all the .h files from Microchip's code. Hopefully most will be fairly simple, maybe just copy and paste the define into the code needing it.

    If you've never done this sort of porting work, the massive number of compiler errors can feel overwhelming. The key is knowing the difference between intractable errors and "easy" errors which merely involve simple but tedious work to go find each thing and either adapt that header file or code, or if the file contains lots of other difficult stuff (a pretty common problem) just copy the small piece into one of the files you're using.

  4. #4
    Thanks Michael and Paul for the advice.

    I've changed the drv_spi.c to drv_spi.cpp and added the SPI.h and SPI.begin() to the init function and that part compiles ok.

    Now I'm stuck on a enum problem. There is a function that I'm calling in the .ino file:

    uint32_t selectedBitTime = CAN_500K_2M;
    DRV_CANFDSPI_BitTimeConfigure(DRV_CANFDSPI_INDEX_0 , selectedBitTime, CAN_SSP_MODE_AUTO, CAN_SYSCLK_40M);

    but it is giving me this error:
    invalid conversion from 'uint32_t {aka long unsigned int}' to 'CAN_BITTIME_SETUP' [-fpermissive]

    the function has this prototype:
    int8_t DRV_CANFDSPI_BitTimeConfigure(CANFDSPI_MODULE_ID index,
    CAN_BITTIME_SETUP bitTime, CAN_SSP_MODE sspMode,
    CAN_SYSCLK_SPEED clk);


    The "selectedBitTime" variable is the uint32_t and 'CAN_BITTIME_SETUP' has this typedef enum:


    Code:
    typedef enum {
        CAN_500K_1M,    // 0x00
        CAN_500K_2M,    // 0x01
        CAN_500K_3M,
        CAN_500K_4M,
        CAN_500K_5M,    // 0x04
        CAN_500K_6M7,
        CAN_500K_8M,    // 0x06
        CAN_500K_10M,
        CAN_250K_500K,  // 0x08
        CAN_250K_833K,
        CAN_250K_1M,
        CAN_250K_1M5,
        CAN_250K_2M,
        CAN_250K_3M,
        CAN_250K_4M,
        CAN_1000K_4M,   // 0x0f
        CAN_1000K_8M,
        CAN_125K_500K   // 0x11
    } CAN_BITTIME_SETUP;
    Googling around and some has suggested I change the typedef to this:

    Code:
    typedef enum  CAN_BITTIME_SETUP{
        CAN_500K_1M,    // 0x00
        CAN_500K_2M,    // 0x01
        CAN_500K_3M,
        CAN_500K_4M,
        CAN_500K_5M,    // 0x04
        CAN_500K_6M7,
        CAN_500K_8M,    // 0x06
        CAN_500K_10M,
        CAN_250K_500K,  // 0x08
        CAN_250K_833K,
        CAN_250K_1M,
        CAN_250K_1M5,
        CAN_250K_2M,
        CAN_250K_3M,
        CAN_250K_4M,
        CAN_1000K_4M,   // 0x0f
        CAN_1000K_8M,
        CAN_125K_500K   // 0x11
    };
    But that just moves the error to somewhere else. Looks like there is some differences on enum between C and C++

    What is the best way to solve this enum issue ?

  5. #5
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,535
    It’s not the Enum’s fault. The enum just does enumerate values and assign them a type. Then you assign an enum type and value to an unsigned 32bit integer which the compiler casts without problem. But then, in the function call, you give the casted uint32_t as a parameter while that enum type is expected, and the compiler can not cast back.

    Thus, I would not do this implicit uint32_t casting, but try to declare selectedBitTime with the correct type before the function call:
    Code:
     CAN_BITTIME_SETUP selectedBitTime = CAN_500K_2M; 
    DRV_CANFDSPI_BitTimeConfigure(...);

  6. #6
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,270
    Quote Originally Posted by Theremingenieur View Post
    It’s not the Enum’s fault. The enum just does enumerate values and assign them a type. Then you assign an enum type and value to an unsigned 32bit integer which the compiler casts without problem. But then, in the function call, you give the casted uint32_t as a parameter while that enum type is expected, and the compiler can not cast back.

    Thus, I would not do this implicit uint32_t casting, but try to declare selectedBitTime with the correct type before the function call:
    Code:
     CAN_BITTIME_SETUP selectedBitTime = CAN_500K_2M; 
    DRV_CANFDSPI_BitTimeConfigure(...);
    Or alternatively, pass an int, and use const int or #define. You could also use an explicit cast of the enum to int (or vice versa).

  7. #7
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,119

    CAN-FD Tested and Working on T3.2 and T3.5

    Just for reference I used @skprang code on a T3.2 and a T3.5 using a MIKROE MCP2517FD Click board. The porting to the Teensy worked no issues (once I fixed my wiring to the boards ). I did order his boards but would take too long to get and I have no patience to wait.

    Thanks for the conversion @skprang. Opens up a couple of new doors.

  8. #8
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,080
    I might order a few too, looks like it could need a sister library like IFCT It all depends on my free time of course

    Tony

  9. #9
    Quote Originally Posted by mjs513 View Post
    Just for reference I used @skprang code on a T3.2 and a T3.5 using a MIKROE MCP2517FD Click board. The porting to the Teensy worked no issues (once I fixed my wiring to the boards ). I did order his boards but would take too long to get and I have no patience to wait.

    Thanks for the conversion @skprang. Opens up a couple of new doors.
    Good to hear you got it working.

    For those who want to try Teensy with the MCP2517FD the code is in GitHub:

    For Teensy 3.2
    https://github.com/skpang/Teensy32_w...FD_CAN_FD_demo

    For Teensy 3.6
    https://github.com/skpang/Teensy36_w...FD_CAN_FD_demo

  10. #10
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,119
    Just as note the T3.6 code will run on a T3.5 as well as I mentioned in an earlier post.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •