Include Cypress Headers in Library Project

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
PaSw_2578827
Level 4
Level 4
25 replies posted 10 replies posted 10 questions asked

I'm trying to create a library project for source that will be reused across a few platforms (PSoC6 and PSoC4). But I haven't been able to find a way to include any Cypress specific header files. For normal application projects these files all get pulled in when the source is generated by PSoC Creator, is there a way to manually include necessary header files so I can at least use Cypress #defines in my library?

0 Likes
1 Solution

PaSw,

The component strategy might be a better approach for now.

I'm within a few days of release to the forum with a library that includes library functions and one component.

As I mentioned in an earlier post, the library functions used to be components.  If found that there was a limited connection in the function calls to other components.  I was able to remove the component structure and make them library calls once I installed a new function that allowed the component references by using a callback function.

For example, my library functions used GetChar() and PutChar() inside them.  By creating a callback function that needs to be executed early at initialization, the designer inserts the pointers to these functions in the callback.  When the library function is executed, the internal function code executes the callbacks to GetChar() and PutChar().

Hope this helps.

Len

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
21 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

PaSw,

The project.h file and all the files referred to in it are generated based on the application.  In many cases, the constants and other references can change as your application build changes.  For example:  BCLK__BUS_CLK__HZ can change if you define a different BUS_CLK in the Clocks DWR panel.

I realize you're trying to test out your library .h and .c files independent of the project.  This can be done with a "compile-only" if you don't need project.h defines.

I've created library files (.h and .c) before and I try to avoid calling project.h or any defines listed in the project.

If I must use anything defined in project.h in my library files, I create a demo project with calls to the library files.  I compile the project (with TopDesign application) and the library .h and .c files get tested with the project.h defines.

Are there specific project.h defines you want to access?  There might be an alternate method.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Specifically looking for cypress system level defines (in the PDL they are mostly in cy_syslib.h), for example I can't use and cy_ types or cy_ registers, or CY_ definitions. In the case of the PSoC6 I can't use any IPC stuff.

I can find the headers in the PDL and manually copy them in but that doesn't seem very portable, I'm just wondering if there is a 'correct' way to do it. An alternative approach is to build the library as a component, but that's extremely cumbersome to compile and debug.

0 Likes

PaSw,

I've built components too.  In fact, some of my library functions started out as components with NO schematic elements.  Since they didn't need calls to project.h then it made more sense to remove the component aspect.

If you need certain calls to the underlying PDL calls, you can set the Build Settings...\Compiler\General\Additional Include Directories

To the directory where the PDL files you're interested are located.

pastedImage_0.png

The downside is that you are tied to the PDL version you select.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Yea I tried including the PDL file directly but it's not ideal but it could work. I ran into some issues with it looking for the "cy_device.h" file, which I think is a generated file, along with that the PSoC4 doesn't use the PDL so that's a whole other ball game.

I think the component strategy might be a better approach for now, it's just unfortunate that components are so difficult to compile and debug.

0 Likes

PaSw,

The component strategy might be a better approach for now.

I'm within a few days of release to the forum with a library that includes library functions and one component.

As I mentioned in an earlier post, the library functions used to be components.  If found that there was a limited connection in the function calls to other components.  I was able to remove the component structure and make them library calls once I installed a new function that allowed the component references by using a callback function.

For example, my library functions used GetChar() and PutChar() inside them.  By creating a callback function that needs to be executed early at initialization, the designer inserts the pointers to these functions in the callback.  When the library function is executed, the internal function code executes the callbacks to GetChar() and PutChar().

Hope this helps.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Follow up question (and perhaps this warrants a new thread). I'm porting into a component which should actually work fairly well but I'm having an issue with one thing. How do I include common source code along with platform specific code?

90% of my code is platform agnostic but one or two files needs to be rewritten depending on the target hardware. Thankfully it's easy to make target specific code in a component but I can't get it to pull in the generic API code unless I also make it target specific (in which case I would need multiple copies of it which makes it painful for updating).

I tried adding the generic code as an API doc with the 'Target Generic Device' box ticked, but when I added it to an application it ignored that and just used the device specific code instead (I want it to use both). This is my preferred method if I can make it work.


My second option was to create a second component that has all of the generic code and then add both components to the project. This works but it is super messy and I need to add the name of the generic component as a parameter for the platform specific component in order for it to find the the header files.

0 Likes

PaSw,

There are two ways to do this that I'm aware of.

Option 1

In the Components tab of the Workspace Explorer select your Component (Shown here as Term_v2_2).

Right mouse button click on Add Component Item ...

On the Add Component Item window select either API C File or API Header file.

As you know, Selecting Target generic device will add a file in the API directory of your component.

If Target generic device is deselected, you can select the Family, Series and/or Device to make the file specific to a Target.

pastedImage_3.png

As you can see in the component Term_v2_2 shown above, I can create both generic and specific API files.  When the component gets called and built, both the generic and specific items get pulled into the project.

Option 2

If you create only general API files, there are Cypress-defined #defines for the Family/Series/Device that are generated when the project is assigned a device.  You can use these defines to perform conditional compiles.  The down-side with this approach is that the API code can get pretty bloated with compile-disabled code.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
As you can see in the component Term_v2_2 shown above, I can create both generic and specific API files.  When the component gets called and built, both the generic and specific items get pulled into the project.

I have found this not to be the case, that was my first attempt also but if API files exist for both the generic device and a specific device it prefers the device specific files and ignores the generic device API files.

Len, I appreciate your responses.

Thanks

0 Likes

PaSw,

Question:  Are the file names the same in the generic and specific folders?

If so.  This might be the reason why Creator favors one over the other.  In this case, rename the generic files.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

They are not the same filenames. Even if I just add a simple 'test.c' file in the generic target API folder it doesn't get included in the generated source. Have you been able to achieve this? Is it possible there's a setting I'm missing, seems like it should be available functionality.

0 Likes

PaSw,

Sorry.  I thought Cypress would include both.

pastedImage_0.png

I added "PaSw_test.h" in my Component's Family specific directory but it does not get included during the "Generate Application" phase.

pastedImage_2.png

Maybe Cypress Tech can provide a solution.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

PaSw,

I haven't given up yet.

A thought:

I know you are trying to avoid repeating the same code across multiple Family specific configurations.  Hopefully you can achieve this.

I have an idea.

  • Place the generic code in separate .h and .c files.  Locate it somewhere in the Component directory.
  • DO NOT include the generic .h and .c files as Target generic device.  Therefore there is no API folder at the root of the Component.
  • Include these generic files under EACH Family/Series/Device as "Add Existing" instead of "Create New".  Hopefully in this case, the generic files only exist ONCE on the Component's directory but each specific configuration will logically include it.
  • Add the Family/Series/Device specific files under each configuration as needed.

(Shoulders shrugged!?)

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Great thought but it seems like when you use the "Add Existing" feature Creator makes a copy of that file in the target specific folder, it does not reference the original file. I guess I'll have to stick with making the common code be a separate component, that works ok, it's just super messy at least in part due to the prefix that Creator adds when it generates the common code.

0 Likes

PaSw,

I agree.  I personally dislike having multiple copies of the common code in the specific API folders.

If I make a change to the common code, I have to make sure that the change is duplicated in EACH copy in the specific folders.  Yuck!

... just super messy at least in part due to the prefix that Creator adds when it generates the common code.

Do you know about the Doc.APIPrefix parameter in the .cysym file?  Maybe this will help.

pastedImage_3.png

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

I looked at that and I'm not sure what it's purpose is to be honest, for me it's the instance name that's the problem. If the user changes the instance name of the common component then my API component can't find the header files. My workaround has been to put a parameter field in the API component that needs to be configured in the TopDesign, this parameter needs to be the name of the common library. I haven't found a way to embed a hidden component within another component other than to create a Macro.

0 Likes

PaSw,

As you can see in the Doc.APIPrefix parameter I set, I called it "Term".  The API files I have for the component are called "Term.h", "Term.c" and "Term_cyapicallbacks.h".  

When I use the component in a project and name it anything other than "Term" (because of instancing it names it a default of "Term_1"), the resultant files for the Term component get loaded in the "Generated_Source" folder with the Term component's folder name given in the project (let's say I named it "UART") and the files in it are named "UART.h", "UART.c" and "UART_cyapicallbacks.h.  Because of the Doc.APIPrefix parameter, it finds the "Term" in the component API file names and replaces it with the instanced component name "UART".  You will also notice

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

PaSw,

I may have another Option to create what you're trying to do.

A Creator Library project allows you to create and distribute components.  Because it is called a "Library" project, you can also create Library (shareable device-agnostic) code.  This might be the place to put the generic code.  Therefore the specifc code goes in the Family specific folders of the component and the generic goes in the library.  This should work.

Note:  The library files DO NOT inherit the component instanced name.  This is potentially a very good thing.  This allows this generic code to be easily shared among many components in the library as well as being used by the application independent of any of the components being installed in the TopDesign.

Here's how my Library project looks on the Components tab.

pastedImage_0.png

This is how the Library looks on the Source tab.

pastedImage_1.png

Give it a try.  If this works, a change in a generic file will ripple to ALL components (and Apps).

Len

One addition note:  I do not believe library functions can support the component variables (like `$INSTANCE_NAME` and others with the `$____` format).

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

After I get it working as a component I might try this approach! Thanks

0 Likes

PaSw,

Your post have intrigued me!!!

As you already realize, Component authorizing is not for the faint-of-heart.  Bravo to you!

My previous suggestion about using common as a library code does work.  I tried it after I wrote my suggestion.

However ... there is an issue regarding accessing the library (common code) .h files.  You need to do one of two things to make these .h files accessible to the Application:

  • Copy the .h files needed from the library into the Project Application's .cydsn directory. 
    Issue:  If there is a later update to the library .h files, the older files copies of the .h files in the Project App directory needs to be replaced.  A hassle and a half.
  • or ... Add the library directory as a Build Settings ...\Compiler\Additional Include Directories.  Then Add\Existing Item ... and select the .h files from the library. 
    Benefit: A later update to the .h file becomes automatically updated since you are using the actual files instead of copying them.  
    Issue: The above project configuration is a bit cumbersome.
    Issue:  Sharing your library or your application with others or making copies of the application can easily have the directory references to the library wrong and need to be corrected.

Now for a new Option!

I think we are at Option 4

Instead of placing the common code in a library with all the Issues listed above.

  • Create component for the common code. 
  • Place all the common code in the API directory for this new component.
  • You can now include these common code (function) components inside other components by dropping them into the component's schematic page (.cysch) and are easily accessible from the component.  This may solve your need to use the common code in all supported Family/Series/Devices configurations without having to duplicate the code in each specific API directory. (See the pic below.  The MenuCmds and String_Funcs components are my common code elements that I incorporated in my Term component's .cysch file.)   Also note that the cy_boot component is basically a common code component created by Cypress.
  • pastedImage_0.png

pastedImage_2.png

Benefit:The .h files get included in the "Generated_Source" directory can are automatically referenced in "project.h".  No need to copy them into your Project App.

Benefit: The Library strategy needs to have the .c files compiled in all supported CPUs and under "Debug" and "Release" build configurations.  This is not to difficult by is easy to forget to do.  The component is constructed automatically places the source and header files in the Project and is compiled for the Target Device.

Benefit: As a component you have access to Symbol Parameters of the TopDesign as well as parameters you can create.  These parameters can be used to conditionally compile operational methods and properties.

Benefit: These common code components are easily moved with your component library and shareable to others or with other projects.

Benefit: With optimizing compiler, only the functions that get called in the project are linked into the project.  All the non-used functions are compiled out which saves code.

Benefit: If applicable, the common code component can be used on its own without further incorporation into another component.

Issue:  Components by default inherit instancing.  I found no way to turn this off.  Therefore there may be compile issues with common code with more than one instance in a project.

I can tell you THIS WORKS!  I've just taken the Term component I'm planning on releasing to this Forum soon and put these tactics into it.

If anything comes out of this discussion, it may be used by others as a form of blog about a nuance of creating a Component and Library strategies.

Good coding!

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

We're on the same page, that was my component approach I mentioned earlier and ultimately what I implemented. I have 2 components one contains the common code and the other contains just the API and the platform specific stuff. It works fine and the only issue I have (albeit a minor one) is that I have to pass the instance names as parameters to each component so that they can find each others header files.

I also would like it if I could hide the common code in the schematic but that's not a big issue, I can hide it from the catalog so the user can't accidentally include it without having the API, instead I created a single macro that pulls in both required components.

0 Likes

PaSw,

I FINALLY uploaded my new components in a component library.

Terminal Support Component Library

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes