Transitioning to C++ with KDS, KSDK, and Processor Expert

Document created by dave408 on Jun 4, 2015Last modified by dave408 on Sep 11, 2015
Version 2Show Document
  • View in full screen mode

I have definitely experienced some of the growing pains of using the Kinetis tools as they have underdone some changes.  I started tinkering with KDS last year when KSDK and MQX were separate packages.  I didn't mess around with it much, other than to prove that I could toggle some GPIO.  I then got more serious with KDS 2.0 and KSDK 1.1 when MQX was integrated into the installer.  I started with simple projects, and eventually got a pretty good demo put together that incorporated ethernet (using lwIP), RS485, Modbus TCP/RTU, motion control, and barcode reading.  Unfortunately, at that time there were some small issues with the KSDK 1.1 which prevented us from being able to easily write applications in C++.  I definitely think better in C++ than in C, so this was a bummer.

 

I was quite excited when the C++ issues were fixed in KSDK 1.2.  So now I need to port my application from C to C++.  At this point, I am faced with two hurdles:

  1. Directly porting my currently-working application (written for KDS 2 / KSDK 1.1) doesn't work.  I have written some posts here about it and could use some help solving those problems.
    1. lwIP project that was working in KDS 2.0 with MQX and PEx no longer works in KDS 3.0
    2. How do you force PEx to be totally C++ compatible?
    3. Adding HardFault handlers in KDS3/KSDK1.2?
  2. Figuring out how to call into C++ wrappers

This post is about #2, where I believe I have a usable solution.  It's basically covered in Re: How to call C functions that use "restrict" keyword from C ?  but with a small twist or two.  I am currently using KDS 3, KSDK 1.2, and my project requires MQX Standard as well as Processor Expert.When you create a project like mine, you will likely go through the following basic steps:

  1. Create new project
  2. Enable KSDK and Processor Expert
  3. Change osa from BareMetal to MQX
  4. Change MQX from Lite to Standard
  5. Disable DbgCs1
  6. Enable new fsl_uart in MQX settings and disable its pins
  7. Add OS_Task components and other PEx components
  8. Specify your CPU type in the C++ compiler settings, as shown below
  9. Generate code

 

In addition to main.c, after you generate code, you'll also end up with os_tasks.c.  Your PEx components will have C code added to the Generated Code folder.  At this point, it should be possible to wrap components in C++ classes.  Tonight, I ran a simple test where I wanted one of my MQX tasks to blink an LED.  The LED blink code was wrapped in a simple C++ class, and in order to be able to create the C++ object to call into, you have to call it from C++ code!

 

The solution ends up being pretty simple.  Rename main.c to main.cpp, and rename os_tasks.c to os_tasks.cpp.  Then generate code again.  Click on your Sources folder and hit F5.  You will see that main.c and os_tasks.cpp reappear, because they get re-created.  Right click on each of them and click Resource Configuration -> Exclude from Build.

 

 

Click Select All, then Close.  This will prevent those files from being compiled.  Note that if you add more OS_Task components, you will need to manually update os_tasks.cpp accordingly.

 

At this point, it's very simple to create a wrapper class and call it.  I wrote one called DebugLed.cpp:

 

#include <DebugLed.h>
#include "Cpu.h"
#include "gpio_comp.h"


namespace Peripherals {


DebugLed::DebugLed() {
  // TODO Auto-generated constructor stub


}


DebugLed::~DebugLed() {
  // TODO Auto-generated destructor stub
}


void DebugLed::BlinkGreen()
{
  GPIO_DRV_SetPinOutput( LEDRGB_GREEN);
  OSA_TimeDelay(150);                 /* Example code (for task release) */
  GPIO_DRV_ClearPinOutput( LEDRGB_GREEN);
  OSA_TimeDelay(150);                 /* Example code (for task release) */
}
} /* namespace Peripherals */

 

(hopefully all of the code shows up when I post this!  I don't see all of it in the preview)

 

Then you can instantiate the DebugLed object before the while(1) in your OS_Task:

 

void Blink_task(os_task_param_t task_init_data)
{
  /* Write your local variable definition here */
  Peripherals::DebugLed led;


#ifdef PEX_USE_RTOS
  while (1) {
#endif
    /* Write your code here ... */
   led.BlinkGreen();


#ifdef PEX_USE_RTOS   
  }
#endif    
}


/* END os_tasks */


#ifdef __cplusplus
}  /* extern "C" */
#endif 

 

Build, debug, and set a breakpoint on your call into your C++ object, and it should hit it!

 

It's a lot easier than I thought it would be.  I figured there would be more manual labor involved with the code generation aspect of it, but it seems to basically boil down to two files, and you don't even need to disable code generation for any of the PEx components, which means you can still use the GUI to change settings if necessary (even though manually changing the header is just as simple).

 

When I get to the office tomorrow, I'll probably start wrapping more complex peripherals, but I really need to figure out the HardFault problem with my lwIP project.  If you have any suggestions, please visit my post: Adding HardFault handlers in KDS3/KSDK1.2? and comment if you can. 

 

I hope my first document here on the Freescale Community was helpful to someone here!

Attachments

    Outcomes