Using C++ With PSoC Creator

Overview

With a few hacks, you can compile C++ with the PSoC Creator IDE and run C++ code on PSoC microcontrollers!

For more information about C++, check out the pages under Programming->Languages->C++.

Using “-x c++”

 

To some degree PSoC Creator disregards the code file extensions, and passes all files to GCC, so that calling the file main.cpp will not force it to compile as C++. This is why you need to enable the command-line parameter -x c++ to force GCC to use the C++ compiler.

 

But you’ll notice that if you right-click a file called main.cpp, the ‘Build Settings’ option has gone! To get this back, from the same menu, select properties. Then change the “File Type” to C_FILE. Now the “Build Settings” option will be availiable for main.cpp. Select this, and navigate to Compiler->Command Line. In the “Custom Flags” box, enter the flag -x c++.

 

psoc-creator-build-settings-command-line-custom-flags Adding custom command line flags in PSoC Creator to force GCC to use the C++ compiler.

 

Also, when you open up .hpp/.cpp files in PSoC Creator, they will not have syntax highlighting, which is rather annoying. Because of this and the C_FILE issue, I use the .h/.c file extension for C++ files, since the compiler doesn’t care anyway. The only difficulty with this is that it makes it hard to easily see what a C++ and what are C code files.

 

Note that you add -x c++ to the build settings of each individual C++ file, not the overall build settings (which are accessed via right clicking on the project in the Workspace explorer). If I add the compiler flags to the project build settings, I get compiler errors when the C++ compiler tries to compile C code. In a pure C++ project, this may be O.K. If someone has done this, please let me know.

 

Main Has To Return An Int

 

If you start a new PSoC project, and add -x c++  to the global build setting parameters, you will get the compiler error .\main.c:14: error '::main' must return 'int' . This has got to be the easiest fix, just obey the compiler and modify void main()  to int main() in main.c, as shown in the following code.

 

Wrapping External C Code

 

Wrap extern C{< C code goes here>} around all C header includes or global C functions (including device.h), that don’t have inbuilt protection. This is to provide C linkage. You don’t have to do this for standard C libraries, they all have this protection built into them.

 

The following code shows an example.

 

 

Defining New And Delete

 

The operators new and delete are not defined when compiling C++ with the ARM compiler. Before you can dynamically create objects with new and delete, you need to define them, as shown in the following code.

 

 

If your dealing with dynamically-allocated arrays, you’ll also want to declare these:

 

 

Preventing Exceptions

 

You’ll notice that if you are trying to use your own versions of new and delete, you will get a error from the linker saying undefined reference to __gxx_personality_v0 .

 

cplusplus-linker-error-undefined-reference-to-gxx-personality Add the custom compile flag "-fno-exceptions" to every .cpp file you want to compile in PSoC Creator to prevent the "undefined reference to __gxx_personality_v0" linker error.

 

and/or the reported error from PSoC Creator saying  undefined reference to __cxa_end_cleanup.

 

c-linker-error-undefined-reference-to-cxa-end-cleanup Add the custom compile flag "-fno-exceptions" to every .cpp file you want to compile in PSoC Creator to prevent the "undefined reference to __cxa_end_cleanup" linker error.

 

To prevent this, you have the to include the build flag -fno-exceptions  to every .cpp file that produces this error. To add the build flag to a particular file, right click the file in the Workspace Explorer and click “Build Settings”. Then click “Compiler”, then “Command Line”, and enter “-fno-excpetions” to the “Custom Flags” field.

 

psoc-creator-build-settings-to-use-new-delete-fno-exceptions Add the custom compile flag "-fno-exceptions" flag via the "Build Settings" menu in PSoC Creator.

 

Incase you didn’t wan’t to globally disable exceptoins, you can disable exceptions for the new operator on a case-by-case basis by using the nothrow keyword. For example:

 

 

When using the nothrow keyword, new will return NULL if the memory allocation failed.

 

Virtual Functions

 

If you get the linker error,  undefined reference to "__cxa_pure_virtual", it’s probably because you are trying to use virtual functions (it’s related to the vtable). Use the compiler flag -fno-rtti  to suppress this error.

 

An alternative is to provide the missing function, as shown below:

 

 

Becuase it’s only the linker that looks for this function, you can normally get by with only providing the declaration and omitting the definition, and the definition can be placed in any C file. Perhaps you want to replace this empty function with some error reporting/debug code to detect if you either attempt to call a derived class whose virtual function has not been defined.

 

Guard Acquire And Guard Release Errors

 

If you get the error undefined reference to '__cxa_guard_aquire'  and/or  undefined reference to '__cxa_guard_release', it’s because C++ is looking for a few functions which implement thread safety for static variables. You usually get this error while initialising static variables/classes which are inside functions (statics that are global to the file will not cause this error).

 

To prevent this error, add the compile flag -fno-threadsafe-statics  to the build options for that C++ file. Note that you must make sure that the static is only used in one thread (or provide your own locks to make it thread-safe)!

 

To provide your own locks, you need to complete function definitions and declarations as shown below:

 

 

Becuase it’s only the linker that looks for these functions, you can normally get by with only providing the declarations and omitting the definitions, and they can be placed in any C file. Note that these functions only serve to stop the linker from complaining, and don’t actually offer any thread-safe static support. This will have to be implemented yourself! (or only use an object from one thread).

Being Careful About What C++ Library Features You Use

The standard C++ library contains many powerful utilities, however, most of these come at the expense of using plenty of code/RAM space, as well as potentially using exceptions (I have not got exceptions to work correctly on a PSoC device).

For example, including <iostream> can cause your memory to instantly overflow. I assume this is probably because of advanced features such a locale support. Upon removing the include, the memory usage didn’t shrink back to normal until I did a clean build.

Because of this, I almost use no standard C++ library features for embedded firmware. Instead, I have written a number of firmware modules which emulate the most useful standard C++ library features (such as strings, vectors, e.t.c) but are suitable for running on microcontrollers. You can download the modules from the MToolkit repository on GitHub.

 

Build Warnings That Are O.K.

 

You can safely ignore the “warning: IO function ‘xxx’ used” messages that pop up while compiling (xxx tends to be _close, _fstat, _isatty, _kill, _lseek, _read, and _write). I don’t know exactly what these do, but the programs seem to work fine even though they are used.

 

psoc-creator-io-function-gcc-build-warnings-cpp The PSoC Creator build warnings that pop up if you compile C++ code. You can safely ignore these.

 

Debugging

 

C++ code can be debugged using the MiniProg3 and the in-built debugging facilities in the PSoC Creator IDE, as long as code optimisation is turned off. Optimisation is turned off in the build settings for the project, as shown in the image below.

 

psoc-creator-build-settings-compiler-optimisation-none Setting the compiler optimisation to none in the PSoC Creator project build settings so that C++ code can be debugged just like normal C code.

 

Interrupts

 

A useful feature about interrupts on the PSoC is that you can create one schematically, and then pass in a callback function for the interrupt using the auto-generated API Interrupt_StartEx(&CallbackFunction); . However, this poses a problem if you are creating a class, and want the interrupt to call one of the classes functions. C++ will not allow you to take the address of the member function (as a single parameter, although you can have method callbacks if you store both the object and a method reference, see the project slotmachine-cpp). One way to get around this is to declare your class interrupt callback functions as static  as shown in the following code.

 

 

Note that if you start creating multiple objects of classes with these static interrupt handler functions inside, bad things will happen. But at that point you have to stop and ask why you are creating multiple objects which both use the same resource.

 

Compiling/Linking With arm-none-eabi-g++.exe

 

I have also experimented with building with the C++ compiler/linker directly (as opposed to the -c c++ method. Why would we want to do this? There are differences between building with the GCC compiler and -x c++ compared to building directly with arm-none-eabi-g++.exe. I believe most of the differences (if not all) are because in the first case, the C-linker is used, while in the latter case, the C++-linker is used. Without using the C++ linker, we can’t use virtual methods or exceptions in our code (note: all PSoC code with exceptions compiles fine with G++, I havn’t got it to actually work without crashing a PSoC microcontroller yet).

 

This is not easy, as unfortunately, PSoC creator is hard coded to call arm-none-eabi-gcc.exe, no matter what GCC/ARM toolchain you point it too. However, I have found that you can get around this by renaming arm-none-eabi-g++.exe to arm-none-eabi-gcc.exe.

 

These files are located in C:\Program Files (x86)\Cypress\PSoC Creator\3.0\PSoC Creator\import\gnu_cs\arm\4.7.3\bin (or similar) if you are on a modern Windows machine and using the default toolchain. Before you rename arm-none-eabi-g++.exe, rename the pre-existing arm-none-eabi-gcc.exe so that you won’t overwrite it.

 

Building with arm-none-eabi-g++.exe seems to get rid of the thread-safe static function definitions missing errors, exception fuction missing errors, and allows you to use virtual functions. This highlights the differences between building with the GCC compiler and -x c++ compared to building directly with arm-none-eabi-g++.exe.

 

Questions I Still Don’t Have An Answer Too…

 

Can we use exceptions with the PSoC microcontroller? Yes, I know they can be resource intensive, but none-the-less it would be interesting to know if it were possible. If you have had any luck with exceptions, please leave a comment below!

 

External Resources

 

There are some instructions on using C++ with PSoC Creator here. However, this method shows you how to edit custom machine-generated xml, which I don’t think you should unless absolutely needed.

Posted: April 3rd, 2013 at 4:17 pm
Last Updated on: October 21st, 2015 at 10:11 am

  • Pingback: How To Use C++ With PSoC Creator | Clandestine Laboratories()

  • Neil Hinckley

    Thank you for posting this information! It has mad things much easier for me, generally.

    I have been having a problem though, and was wondering if you have run into it. If I include an overloaded function definition in a header file I get an error:

    serial.h:19: error: declaration of C function ‘void serialWrite(uint32)’ conflicts with
    ./serial.h:18: error: previous declaration ‘void serialWrite(int16)’ here

    Have you seen this? Or have any ideas of how to correct it? All of my files are C++, and I even changed the whole project to be C++ by changing the build settings of the project (which has been working fine for me, by the way) but I still get this error.

    • gbmhunter

      The fact it says “declaration of C function” suggests that that the compiler is treating it as a C file at some point. Have you made absolutely sure that all source files calling this header are compiled with C++?

      One way to check and make sure they are is to add the code:

      #ifndef __cplusplus
      #error Please compile this file with C++
      #endif

      to the start of every source and header file that needs to be compiled in C++. Hope this helps!

      • gbmhunter

        Oh and sorry for the late reply, I’ve been rather busy lately!

      • Neil Hinckley

        It seems to be working now. It is possible that I was including it in a file that wasn’t compiling as C++.

        Actually, it looks like I was including it in another header file that was inside of the “extern “C”” wrapper.

        I fixed the issue a while ago by wrapping the functions into a class, which somewhat surprisingly resolved the issue. Not sure why.

        I also had to define a new[] function in order to dynamically create arrays, but that was also not a big deal.

        Thanks again for this information and for responding!

        • gbmhunter

          Yup, calling it from inside extern C{} would definitely do it. Yeah new is not inherently supported, you have to create a wrapper yourself, did you use a function similar to the new on this page?

          • Neil Hinckley

            Yup. I just had to add brackets after new, and it worked.

            Any ideas on getting C++ to work with Psoc Creator 3.0? I am getting a lot of errors after importing my project into the new version. I still have -x c++ in all the files, but it doesn’t want to compile.

          • gbmhunter

            No sorry, I’ve downloaded PSoC Creator 3, but I have yet to try and compile any C++ code with it. Will keep you posted when I do.

          • Neil Hinckley

            I’ve been able to get everything except “new” working. If I don’t define it, is doesn’t work. If I do define it is says that there are multiple definitions. If I figure it out I’ll post again.

          • gbmhunter

            Maybe just try declaring it?

          • Neil Hinckley

            That worked for the standard new, but not for new[]. (Although it could be that because I’m not using “new” it isn’t compiled.)

            In any case, with my definition of “new[]” I get “multiple definition of ‘operator new[](unsigned int)'” if I define it, “undefined reference to ‘operator new[](unsigned int)'” if I declare it, and the same if I don’t declare it.

            I’ll probably end up just going the vanilla malloc route I think.