element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog Port an MBED design to non-MBED - Phase 1: compile without errors
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 9 Nov 2019 7:25 PM Date Created
  • Views 1803 views
  • Likes 8 likes
  • Comments 7 comments
  • mbed
Related
Recommended

Port an MBED design to non-MBED - Phase 1: compile without errors

Jan Cumps
Jan Cumps
9 Nov 2019

There are many good MBED examples. It's a popular platform, supported by many manufacturers.

Here's my story on how to port one of those excellent MBED example program to another platform.

 

The program I want to port is the SemTech LoRa Ping-Pong example.

The goal is to get a reusable C++ library that can be used on micro controllers, Raspberry Pi, BeagleBone etc...

I need to find what part of the code is dependent on MBED and factor that out.

The factored-out part is the one that will have to be implemented for the target non-MBED platform.

If I get this working, in the end I have to provide an abstract C++ library that only depends on standard libraries, and a document that specs, for the missing parts, what extra functionality is needed.

I expect that the missing  (to be ported) parts are GIO, SPI and UART (optional image).

 

As test bed, I'm using a Texas Instruments Hercules micro controller. It could be any platform that supports SPI and GPIO.

I selected this one because I have two identical boards and my example is a radio Send + Receive scenario (two SemTech radios pinging and ponging each other).

 

There are several ways to replace one utility/service library by another.

In the case where there is documentation of dependencies, one can start from that.

In the case where the dependencies are to be detected from sources, there are also a few options.

You can walk through the code and flag all constructs that are dependent on the library you want to replace.

Another option is to hide that library from the build process and let the build log point out what's broken.

That's the approach I'm using here.

 

 

 

Task 1: Break the Dependency with MBED

 

The easiest way to find dependencies is to cut away the MBED sources and libraries. Then use the tool chain build errors to point at the gaps. Tools are more efficient than a full manual gap analysis in many cases.

You can start from an empty project for your target platform.

For a Pi, that could be a "Hello, world!" Linux project in Eclipse. For my platform, I used a minimal Hercules project.

As long as you have a project that successfully runs on your target (it does not have to do anything functional), you are good to go.

If you do that, you have broken the MBED link. You now have a non-MBED project as starting point.

Take care that you don't have any build errors or warnings left. We'll use the build error log in the next step to help replace the functions provided by MBED.

 

Task 2:  Integrate the MBED Example Code in your Project

 

This is the step where you copy the sources (h and cpp) from the MBED example to your project.

Usually, the library code can just be copied and pasted into your project.

You'll have to do some manual work to merge your project's main file with the main from the MBED example.

Take care that you take over all includes, move all declarations above your project's main() declaration, and add the example's main() functionality to that of your project.

Save everything. Then, just for kicks, build the example. You'll have many errors.

 

Task 3: Collect Unresolved MBED Dependencies

 

For all the errors that you have now during compilation, you'll have to provide a replacement.

My approach is to create a honeypot to put all the unresolved issues. I use a header file called missing.h for that.

First, I replace any occurance of mbed.h with missing.h in the project.

Then I compile again.

 

I then look at the errors in the build log and look for the ones that occur a lot.

I investigate the top one and try to find out what the dependency is.

A common miss is the digital i/o api from MBED.

What I then do, is look up the declaration of the missing dependency online (example: DigitalInOut).

I then create a minimal replacement of the declaration, without implementation, in the missing.h file.

 

Example:

 

class DigitalIn {
public:
  DigitalIn(PinName pin) {}
};

class DigitalOut {
public:
  DigitalOut(PinName pin) {}
  DigitalOut &operator= (int value) {}
  DigitalOut &operator= (DigitalOut &rhs) {}
};

class DigitalInOut {
public:
  DigitalInOut(PinName pin) {}
  DigitalInOut &operator= (int value) {}
  DigitalInOut &operator= (DigitalInOut &rhs) {}
  operator int() {}
  void input() {}
  void output() {}
};

 

You'll see that my classes are not complete. I only put those dependencies that break the build. And they have an empty implementation.

But those are the indicators of what functionality is missing.

 

I perform this exercise iterative.

  • find a build error
  • implement an empty implementation in missing.h
  • check that the build error is resolved
  • rinse and repeat

 

The number of comilation errors has to decrease whle doing that exercise. Repeat until no compilation errors (ignore link issues)

In my case, at the end of the exercise, I end with this missing.h file:

 

/*
 * missing.h
 *
 *  Created on: 9 nov. 2019
 *      Author: jancu
 */


#ifndef CPP_MISSING_H_
#define CPP_MISSING_H_


#include "HL_sys_common.h"


#include <stdio.h>
#include <string.h>


// define all MBED APIs, classes and defines used in the example


typedef enum {
    PIN_INPUT,
    PIN_OUTPUT
} PinDirection;


typedef enum {
  PA_0  = 0x00,
  PA_1  = 0x01,
  PA_2  = 0x02,
  PA_3  = 0x03,
  PA_4  = 0x04,
  PA_5  = 0x05,
  PA_6  = 0x06,
  PA_7  = 0x07,
  PA_8  = 0x08,
  PA_9  = 0x09,
  PA_10 = 0x0A,
  PA_11 = 0x0B,
  PA_12 = 0x0C,
  PA_13 = 0x0D,
  PA_14 = 0x0E,
  PA_15 = 0x0F,
  PB_0  = 0x10,
  PB_1  = 0x11,
  PB_2  = 0x12,
  PB_3  = 0x13,
  PB_4  = 0x14,
  PB_5  = 0x15,
  PB_6  = 0x16,
  PB_7  = 0x17,
  PB_8  = 0x18,
  PB_9  = 0x19,
  PB_10 = 0x1A,
  PB_12 = 0x1C,
  PB_13 = 0x1D,
  PB_14 = 0x1E,
  PB_15 = 0x1F,


  PC_0  = 0x20,
  PC_1  = 0x21,
  PC_2  = 0x22,
  PC_3  = 0x23,
  PC_4  = 0x24,
  PC_5  = 0x25,
  PC_6  = 0x26,
  PC_7  = 0x27,
  PC_8  = 0x28,
  PC_9  = 0x29,
  PC_10 = 0x2A,
  PC_11 = 0x2B,
  PC_12 = 0x2C,
  PC_13 = 0x2D,
  PC_14 = 0x2E,
  PC_15 = 0x2F,


  PD_2  = 0x32,


  PH_0  = 0x70,
  PH_1  = 0x71,
  A0          = PA_0,
  A3          = PB_0,
  A4          = PC_1,


  D1          = PA_2,
  D2          = PA_10,
  D3          = PB_3,
  D4          = PB_5,
  D5          = PB_4,
  D6          = PB_10,
  D7          = PA_8,
  D8          = PA_9,
  D9          = PC_7,
  D10         = PB_6,
  D11         = PA_7,
  D12         = PA_6,
  D13         = PA_5,
  D14         = PB_9,
  D15         = PB_8,


    // Generic signals namings
    LED1        = 0x05,
    LED2        = 0x05,






    // Not connected
    NC = (int)0xFFFFFFFF
} PinName;


class SPI {
public:
 SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC) {}
 virtual int write(int value){return 0;}
 void format(int bits, int mode = 0) {}
};


class DigitalIn {
public:
  DigitalIn(PinName pin) {}
};


class DigitalOut {
public:
  DigitalOut(PinName pin) {}
  DigitalOut &operator= (int value) {}
  DigitalOut &operator= (DigitalOut &rhs) {}
};


class DigitalInOut {
public:
  DigitalInOut(PinName pin) {}
  DigitalInOut &operator= (int value) {}
  DigitalInOut &operator= (DigitalInOut &rhs) {}
  operator int() {}
  void input() {}
  void output() {}
};


template <typename F>
 class Callback;


class InterruptIn {
public:
  InterruptIn(PinName pin) {}
  void rise(void) {}
};


class Timeout{
protected:
  virtual void handler() {}
public:
  void detach() {}
};


// placeholder for all calls used in the MBED example that don't have an implementation
static inline void debug(const char *format, ...) {}
static inline void debug_if(int condition, const char *format, ...) {}




void wait_ms( int ) {}


void wait( int ) {}


double ceil(double) {return 0.0;}


double floor(double) {return 0.0;}


double rint(double) {return 0.0;}


#endif /* CPP_MISSING_H_ */

 

Some constructs are cumbersome to resolve, e.g.: the MBED Callback template construct.

In those cases, where it takes longer to do this exercise than it would be to build a final solution, I comment out the failing code and put a // todo: comment in the source.

Eclipse and other editors have a Task view that shows the things that have to be resolved in source code.

 

image

 

Work Items at This Stage

 

At this point, where there are 0 compilation errors left, we have a list of manageable work items.

    • All code in missing.h. Each of those will need a MBED-independent implementation.
      There's no need to implement it identical to MBED. But it's a good starting point. I think that the MBED object oriented abstractions are neat. Better than what I usually come up with.
    • The tasks in the Todo window. hose are all pieces of code you commented out but are needed for a working design.
      This is a good time to try and dig into those constructs, get a better understanding and create a solution that works on your non-MBED target platform.

Next steps for this blog: Resolve these gaps for my project and document them.

 

Because the Hercules projects are typically C, and the MBED libs are C++, I also had to provide a bridge between the two. A non-intrusive one.

Here's the write-down of that Hercules Safety Microcontroller: Use C++ with HALCoGen C Projects..

 

Related blog
Use C++ with HALCoGen C Projects

Port an MBED design to non-MBED - Phase 1: compile without errors

Port an MBED design to non-MBED - Phase 2a: DigitalOut Class Constructor
Port an MBED design to non-MBED - Phase 2b: DigitalOut Class and Blinky example
Port an MBED design to non-MBED - Phase 3: InterruptIn Class and example
Port an MBED design to non-MBED - Phase 4: Timeout Class and Blinky example
Port an MBED design to non-MBED - Phase 5: OO Callbacks Simplified
  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps over 5 years ago +1
    The main functionality I'm missing at this point is difital GPIO and SPI and interrupt callbacks. It should not be too hard to come up with a design for the first two that's close to the MBED design. The…
  • Jan Cumps
    Jan Cumps over 5 years ago +1
    ... next steps are to solve those parts that are not strictly MBED dependencies, but C++ dependencies that are resolved somewhere in th MBED includes. I have these instances: memory copy and I/O (not gpio…
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to shabaz +1
    I often do the same The MBED example for the SemTech chip doesn't use the MBED OS's job scheduler - it's a straightforward main loop approach. They use some library functions though. The deeper I drill…
Parents
  • Jan Cumps
    Jan Cumps over 5 years ago

    ... next steps are to solve those parts that are not strictly MBED dependencies, but C++ dependencies that are resolved somewhere in th MBED includes.

    I have these instances:

    memory copy and I/O (not gpio) functions

    ceil, floor and rint templates.

     

    The memory copy functions are declared in the following headers

    #include <stdio.h>
    #include <string.h>

     

    ceil, floor and rint in this one:

    #include <tgmath.h>

     

    I have added a header file called includes.h to my implementation, in the subfolder "client_platform"

    /*
     * includes.h
     *
     *  Created on: 10 nov. 2019
     *      Author: jancu
     */
    
    #ifndef CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_
    #define CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_
    
    #include "./client_platform/hard_includes.h"
    #include <stdio.h>
    #include <string.h>
    
    // for ceil, floor, rint:
    #include <tgmath.h>
    
    #endif /* CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_ */

     

    this one will have all required standard C++ header includes that are available for MBED programs via the MBED headers.

    There's also a specific include:

     

    #include "./client_platform/hard_includes.h"

     

    That file will not be part of the device independent port.

    Any implementer (read: me) will have to provide it, and put device dependent neccesary includes there that are needed to compile the solution.

    There will alse be room for  a "client_platform" location to put the device dependent implementation code.

     

    The deal is that you'd (I'd) have to adapt only files in the external "client_platform" folder to make the library work for different microcontroller families.

    A more advanced way of doing this is by creating abstract classes that would need to be implemented by your personal C++ device dependent classes.

    That's for later. No use in abstracting something I don't have working yet.

     

    edit: the goal is that you'd only have to modify files in the external client_platform sources. And that the rest is an as clean as possible port from MBED.

    I could make it less-intrusive by calling my header file mbed.h instead of includes.h. In that case non of the MBED dependent sources would need to change. But that would give a signal that the support lib is mbed, while it isn't.

    I'd even have to use the mbed namespace in my code, and that's a nono

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • Jan Cumps
    Jan Cumps over 5 years ago

    ... next steps are to solve those parts that are not strictly MBED dependencies, but C++ dependencies that are resolved somewhere in th MBED includes.

    I have these instances:

    memory copy and I/O (not gpio) functions

    ceil, floor and rint templates.

     

    The memory copy functions are declared in the following headers

    #include <stdio.h>
    #include <string.h>

     

    ceil, floor and rint in this one:

    #include <tgmath.h>

     

    I have added a header file called includes.h to my implementation, in the subfolder "client_platform"

    /*
     * includes.h
     *
     *  Created on: 10 nov. 2019
     *      Author: jancu
     */
    
    #ifndef CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_
    #define CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_
    
    #include "./client_platform/hard_includes.h"
    #include <stdio.h>
    #include <string.h>
    
    // for ceil, floor, rint:
    #include <tgmath.h>
    
    #endif /* CPP_IMPLEMENTATION_DEPENDENT_CLIENT_PLATFORM_INCLUDES_H_ */

     

    this one will have all required standard C++ header includes that are available for MBED programs via the MBED headers.

    There's also a specific include:

     

    #include "./client_platform/hard_includes.h"

     

    That file will not be part of the device independent port.

    Any implementer (read: me) will have to provide it, and put device dependent neccesary includes there that are needed to compile the solution.

    There will alse be room for  a "client_platform" location to put the device dependent implementation code.

     

    The deal is that you'd (I'd) have to adapt only files in the external "client_platform" folder to make the library work for different microcontroller families.

    A more advanced way of doing this is by creating abstract classes that would need to be implemented by your personal C++ device dependent classes.

    That's for later. No use in abstracting something I don't have working yet.

     

    edit: the goal is that you'd only have to modify files in the external client_platform sources. And that the rest is an as clean as possible port from MBED.

    I could make it less-intrusive by calling my header file mbed.h instead of includes.h. In that case non of the MBED dependent sources would need to change. But that would give a signal that the support lib is mbed, while it isn't.

    I'd even have to use the mbed namespace in my code, and that's a nono

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube