PSOC 5LP, Mac, C++, libm.a error (Updated)

I ran into an issue with the OneThinx pack for MacOs. For some reason, it can’t pick up the libm.a library when compiling on the Macintosh. The only reason I have time to fight this is that it helps during my day job, so I can document what is happening with me.

I contacted Rolf NooteBoom at OneThinx, and after a few days (he is *very* busy) and at about 6 am in the morning his time, he gave me some good hints. Turned out they were not needed. After turning my Macintosh off and coming back after the weekend, the program compiles and links with the Math library. I have NO clue why.

The CMakeLists.txt file in this post is what I used. Oh, Well. One thing to take a note about: To add a *specific* library to your link, look for lines in the CMakeLists.txt file that are after Libraries. Follow that pattern to add a *one off* library to your link. Do a Clean-Reconfigure in VSCode and you are good to go.

OneThinx Pack for Mac Good Points

The beauty of compiling and testing on the Mac for the PSOC5 is the speed of the code/debug/fix cycle. Compiles that take minutes on the Windows VM are seconds on the Mac. And it is not because of it being a VM. I am now running a 3ghz+ i9 processor with 8 cores and 40gb of memory. With 8 gig Ram and 4 cores for Windows 7, with graphics turned off so it is Plain Jane, builds still take quite a bit of time.

As a contrast, on the Mac the native compile is so fast I often do it again just to make sure I clicked the button.

The OneThinx folks did a lot of *good* work for this system. It was not easy. Look into their products. Their ingenuity and willingness to share makes me think their other stuff will be astounding. (Note: I am NOT compensated by OneThinx for this. I am just so impressed I want to recognize their good work publicly.)

CMakeLists.txt And C++ And PSOC Creator

One of the things you can do with PSOC Creator is compile your code as C++ code. Embedded Ninja came up with this trick years ago. There are *several more* steps in regards to compiling files as c++ than what I present here. Visit the Embedded Ninja page about this here: https://blog.mbedded.ninja/programming/microcontrollers/psoc/using-cplusplus-with-psoc-creator/ He explains everything in *much more detail* than here. You may get some linker errors unless you follow his information.

There are some things you have to keep in mind as you do it. Also some tricks you can pull off with Creator that makes it smoother when switching back and forth between the Mac and Windows.

How To: Make Individual Files Compile C++ In Creator

To make a file compile as c++ in Creator, find the file in the left hand pane, and right-click on it. A popup menu will appear. Select the “Build Settings…” on the menu:

Select Build Settings…

Then, in the box that shows, enter “-x c++” under command line. This allows you to compile the file as c++

Once you do this, there are several issues. Standard C functions in your same project can’t be called. Sometimes library functions fail. It can get messy. The solution for this is to make sure the header files for includes are bracketed with extern “C” { }

But this fails if you do this with a normal C compile. The solution is that if you are compiling with c++, then the macro __cplusplus is defined. The solution is (see first image above for real world example) as follows:

#ifdef __cplusplus
    extern "C" {
#endif        
#include "project.h"
#include "math.h"
#ifdef __cplusplus
    }
#endif 

That way, if the file is being compiled as c++ it is good. if not, it is still good.

OBJECTS NOTE

This alone works well for non-dynamic objects. For dynamically creating class based objects, read the Embedded Ninja website’s information.

Tricks to fool Creator into Compiling cpp files

Trick 1: Now that you have the C file compiling as C++, rename the file to .cpp. (foo.c becomes foo.cpp). Right-click on the file and select rename (or hit F2)

Now, normally, if you add a .cpp file to the Creator Make System, it sits there as a whited out icon and does not participate in the make system. However, if you add a .c file and then rename it, the file continues to participate in the make system.

Trick 2: You can also change the .cpp file type to C file in the properties part of the pop up menu for the file without doing the name change stunt.

Either trick works.

CMakeLists.txt changes

First, I want to say I have no experience with CMake. I stumble around in the dark, so I miss thing. Everything is done by trial and error. If you have a problem with this, I can’t help you, literally. You need to join the CMake forums and ask your questions there.

Mac and CPP

If you are switching between platforms, you want to identify certain files as c++ for CMakeLists.txt. You have two choices. All files can be labeled as .c and compile as c++. In that case, you want to add this line in CMakeLists.txt:

# use the line below to make all "c" files compile as C++
SET_SOURCE_FILES_PROPERTIES( ${SOURCE_SRCS} PROPERTIES LANGUAGE CXX )

Otherwise, you want CPP files to compile as c++, not c files. That requires a bit more surgery.

In the CMakeLists.txt supplied by Rolf Nooteboom and OneThinx, simply change the lines in the file so that c++ files are compiled properly.

In the CMakeLists.txt, look for the following line:

FILE(GLOB_RECURSE SOURCE_SRCS ${SOURCE_DIR}/*.c)

and change it to

FILE(GLOB_RECURSE SOURCE_SRCS ${SOURCE_DIR}/*.c ${SOURCE_DIR}/*.cpp)

Create the following line under set(CMAKE_C_FLAGS “${PROJECT_FLAGS_ARCH}”) directive:

set (CMAKE_CXX_FLAGS “${PROJECT_FLAGS_ARCH}”)

Under the string(REGEX REPLACE “;” ” ” CMAKE_C_FLAGS “${CMAKE_C_FLAGS}”) add the following line

string(REGEX REPLACE “;” ” ” CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS}”)

Thats it!

Results of the Mod

My CmakeLists.txt file looks like this. Yours may be different:

cmake_minimum_required(VERSION 3.7.2)

set(DEBUG_ON true)
######################################################################
#
#	Toolchain Setup
#
######################################################################
# NOTE TO SELF
# add folling into main.c in psoc_creator cross compile in mac
#// Fix for linker error.cyeeprom data will not fit in EEPROM 
# static volatile uint8_t dummy __attribute__ ((section(".cyeeprom"),unused));   
#
macro(FIND_DIRECTORIES return_list dir_in)
    FILE(GLOB_RECURSE new_list ${dir_in})
    SET(dir_list "")
    FOREACH(file_path ${new_list})
        GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
        SET(dir_list ${dir_list} ${dir_path})
    ENDFOREACH()
    LIST(REMOVE_DUPLICATES dir_list)
    SET(${return_list} ${dir_list})
endmacro()

if(${DEBUG_ON})
    set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON")
    message("INFO: path=$ENV{PATH}")
endif()

set(TOOLS_DIR $ENV{ONETHINX_PACK_LOC}/tools_2.0)
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/source)
set(CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/config)
set(CREATOR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/PSoC_Creator.cydsn)
set(CREATOR_SOURCE_DIR ${CREATOR_DIR}/Generated_Source/PSoC5)

if (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
    find_program (BASH_TOOL ${TOOLS_DIR}/bash/bash.exe DOC "The bash executable")
else()
    find_program (BASH_TOOL bash DOC "The bash executable")
endif()

find_program(CYPRESS_ELF_TOOL CyMcuElfTool "${TOOLS_DIR}/cymcuelftool-1.0/bin" DOC "Cypress ELF tool executable")
find_program(READELF_TOOL arm-none-eabi-readelf "${COMPILER_DIR}" DOC "ReadELF tool executable")

#Get the top directory name. This will be used as project_name in later section
string(FIND ${CMAKE_CURRENT_SOURCE_DIR} / POSITION REVERSE )
MATH(EXPR POSITION "${POSITION}+1")
string(SUBSTRING ${CMAKE_CURRENT_SOURCE_DIR} ${POSITION} -1 TOP_DIR_NAME)
set(ENV{TOP_DIR_NAME} ${TOP_DIR_NAME})

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/local.cmake)
    include (${CMAKE_CURRENT_SOURCE_DIR}/local.cmake)
endif()

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)

# Without that flag CMake is not able to pass test compilation check
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

######################################################################
#
#	Project
#
######################################################################

message("INFO: Project \"${TOP_DIR_NAME}\"")
project(${TOP_DIR_NAME})
enable_language(ASM)

#Check if the correct compiler is installed
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-multi-lib OUTPUT_VARIABLE GCC_VERSION)
string(FIND "${GCC_VERSION}" "armv7-m" ARM_V7M_DETECTED)
if (${ARM_V7M_DETECTED} EQUAL "-1")
    message( FATAL_ERROR "Wrong compiler selected, CMake will exit." )
endif()

#Include common settings
include(${CONFIG_DIR}/common.cmake)

######################################################################
#
#	Project compiler & linker options
#
######################################################################

set(PROJECT_FLAGS_ARCH
    "-mthumb"
    "-mcpu=cortex-m3"
    "-DCY_CORE_ID=0"
    "-Wall"
    "-Wtype-limits"
    "-Wunused"
    "-Wunused-parameter"
    "-ffunction-sections"
    "-ffat-lto-objects"
    "-Og"
)
#-g -D DEBUG -D CY_CORE_ID=0 -Wall -ffunction-sections -ffat-lto-objects -Og -c
# wsm added "-l m", but that did not seem to help, even for straight c compile.
set(PROJECT_LINKER_FLAGS
    "-Wl,-Map=${PROJECT_NAME}.map"
    "-L${CREATOR_SOURCE_DIR}"
    "-l m"
    "-Tcm3gcc.ld"
    "-mcpu=cortex-m3"
    "-mthumb"
    "-specs=nano.specs"
    "-Wl,--gc-sections"
    "-g"
    "-ffunction-sections"
    "-Og"
    "-ffat-lto-objects"
)

######################################################################
#
#	Sources
#
######################################################################

# include these paths
FIND_DIRECTORIES(SOURCE_INCLUDE_DIRS ${SOURCE_DIR}/*.h)
include_directories (
    ${SOURCE_INCLUDE_DIRS}
    ${CREATOR_SOURCE_DIR}
)

# Find Source files (containing *.c)
#FILE(GLOB SOURCE_SRCS ${SOURCE_DIR}/*.c)
# the following worked
FILE(GLOB_RECURSE SOURCE_SRCS ${SOURCE_DIR}/*.c ${SOURCE_DIR}/*.cpp)
#list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS C_EXTENSIONS )
#FILE(GLOB_RECURSE SOURCE_SRCS ${SOURCE_DIR}/*.c)


set(PROJECT_SRCS
    ${SOURCE_SRCS}
    ${CREATOR_SOURCE_DIR}/CyBootAsmGnu.s
    ${CREATOR_SOURCE_DIR}/cyfitter_cfg.c
    #${CREATOR_SOURCE_DIR}/cymetadata.c
    ${CREATOR_SOURCE_DIR}/Cm3Start.c
)

if(${DEBUG_ON})
    message("INFO: Project sources        = ${PROJECT_SRCS}")
    message("INFO: Project source folder  = ${PROJECT_SOURCE_DIR}")
    message("INFO: Source include folders = ${SOURCE_INCLUDE_DIRS}")
    message("INFO: Source folders         = ${SOURCE_SRCS}")
    message("INFO: Design source folders  = ${DESIGN_SRCS}")
endif()

# use the line below to make all "c" files compile as C++
#SET_SOURCE_FILES_PROPERTIES( ${SOURCE_SRCS} PROPERTIES LANGUAGE CXX )


######################################################################
#
#	TARGET
#
######################################################################
#TODO: Evaluate ASM FLAGS
set (CMAKE_ASM_FLAGS "${C_FLAGS} ${C_FLAGS_WARNINGS} ${FLAGS_OPTIMIZATION} ${PROJECT_FLAGS_ARCH}")
#set (CMAKE_C_FLAGS "${C_FLAGS} ${C_FLAGS_WARNINGS} ${FLAGS_OPTIMIZATION} ${PROJECT_FLAGS_ARCH}")
set (CMAKE_C_FLAGS "${PROJECT_FLAGS_ARCH}")
#wsm added cxx flags
set (CMAKE_CXX_FLAGS "${PROJECT_FLAGS_ARCH}")
#set (CMAKE_CXX_FLAGS "${CXX_FLAGS} ${CXX_FLAGS_WARNINGS} ${FLAGS_OPTIMIZATION} ${PROJECT_FLAGS_ARCH}")
set (CMAKE_EXE_LINKER_FLAGS "${PROJECT_LINKER_FLAGS}")

# CMake lists are separated by semicolons, remove these
string(REGEX REPLACE ";" " " CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS}")
string(REGEX REPLACE ";" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REGEX REPLACE ";" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE ";" " " CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")

#set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS}")
#set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS}")
#set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS}")

#set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS}" CACHE STRING "" FORCE)
#set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS}" CACHE STRING "" FORCE)
#set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS}" CACHE STRING "" FORCE)
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "" FORCE)
#set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING "" FORCE)

if(${DEBUG_ON})
    message("INFO: ASM Options    = ${CMAKE_ASM_FLAGS}")
    message("INFO: C Options      = ${CMAKE_C_FLAGS}")
    message("INFO: C++ Options    = ${CMAKE_CXX_FLAGS}")
    message("INFO: Linker Options = ${CMAKE_EXE_LINKER_FLAGS}")
endif()

add_executable(${PROJECT_NAME}.elf ${PROJECT_SRCS})

######################################################################
#
#	LIBRARIES  Adding the CyComponent libraries
#
######################################################################
add_library(cycomponentlib STATIC IMPORTED)
add_library(designlib STATIC IMPORTED)

SET_TARGET_PROPERTIES(cycomponentlib PROPERTIES IMPORTED_LOCATION "${CREATOR_DIR}/CyComponentLibrary.a")
TARGET_LINK_LIBRARIES(${PROJECT_NAME}.elf cycomponentlib)

SET_TARGET_PROPERTIES(designlib PROPERTIES IMPORTED_LOCATION "${CREATOR_DIR}/CortexM3/ARM_GCC_541/Debug/PSoC_Creator.a")
TARGET_LINK_LIBRARIES(${PROJECT_NAME}.elf designlib)

######################################################################
#
#	Build actions
#
######################################################################

add_custom_target(
    ${PROJECT_NAME} ALL
    #POST BUILD
    COMMAND ${CONFIG_DIR}/cyelftool -C "${PROJECT_NAME}.elf" --flash_row_size 256 --flash_size 262144 --flash_offset 0x00000000
    COMMAND "${READELF_TOOL}" -Sl ${PROJECT_NAME}.elf > ${PROJECT_NAME}.readelf
    COMMAND "${BASH_TOOL}" ${CONFIG_DIR}/memcalc.bash ${PROJECT_NAME}.readelf "262144" "65536" "0" "536838144" #Flash 0x40000   SRAM 0x10000   Flash start 0x00000000   SRAM start 0x1FFF8000
    DEPENDS "${PROJECT_NAME}.elf"
)

Do a Clean-Reconfigure under VSCode or a rescan under QTCreator before building.

LIBM.A error (resolved, but not sure how)

During my work, I started looking at gyros. I believe they will eventually integrate nicely with OneThinx Loran. In the meantime, I was playing with the MPU6050, and trying to calculate current orientation.

TMS (To My Surprise), I found that the ‘m’ library for math that you use for atan, pow, sin, cos, tan, etc. type of functions was not found. That’s easy, just add -l m to the build.

Nope. Did not work. I backed out the CMakeLists.txt changes. Nope. I tried direct paths. I tried copying libraries into different paths. Nothing worked.

For some reason, the functions inside the standard libm.a are inaccessible to the build environment on the Mac.

After fighting it for a few hours, I realized that it was a dead end for me. I could not do it. A waste of time.

So, I found a few functions that do what I want, and included them in the build on the Mac. Sine can be calculated with a Taylor series (slow). All that info is freely available, although it takes quite a bit of searching. (StackOverflow.com is your friend.) I can easily exclude those home-grown functions when building on the PSOC Creator running under the VM, so I will.

To do that I use the Creator’s Project Menu -> Build Settings… ->Dialog and set up under the ARM GCC… section, Compiler (+), General position, a PSOC_CREATOR=1 definition. Then #ifdef PSOC_CREATOR brings in code under Creator that I don’t want brought in under the Mac builds. #ifndef PSOC_CREATOR excludes code in Creator and includes it on a Mac build.

A PSOC_CREATOR define. (Click New Button)

UPDATE: By turning the computer off and going home, backing out the c source files i created to emulate the library functions, doing another clean-reconfigure (after restoring the questionable CMakeLists.txt), and doing a build it suddenly started working. I HATE THAT! I am not going to look a gift linker in the mouth, though.

It does remind me of developing code for DOS and MsWindows, though. A computer reboot often fixes strange errors on that platform. I guess the Mac is joining the circus with Big Sur and later.

Final Comments

Since the build on the Mac is only for debugging and quick turn around, I can wait until the final testing and do that with a VM to use libraries that are stubbornly refusing to work with me.

My possibly slower and less accurate sin, atan, etc. functions continue to work for me in the meantime while doing it natively. I found they were quick enough (48mhz ARM), repeatable, and seemingly accurate.

If you play with Gyroscopes, you will do a *lot* of floating point math. Since gyroscopes are slow, you can get away with that, for the most part.

However, you really need to use an RTOS to make your life easier. An RTOS lets you push the calculation task(s) into the background (i.e. a low priority task) and use the RTOS to schedule high priority (User Interfacing and other control) tasks so the user has a responsive system. This works because gyros are slow, and calculating such data slowly (more or less), does work without losing too much responsiveness, especially on slower CPU’s.

If you go backwards in my posts, I have posted a version of FreeRTOS for CY8CKit-059 that includes a task for flashing an led, and communicating over USB UART and RS232 UART in two separate tasks.

User Interaction and control interaction almost never take more than a few microseconds worth of decision computation at a time. So, having a high priority task swoop in and deal with the interfacing and controlling tends to create a working system that does not bog down.

Enjoy!

Add a Comment

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