When building a PSoC Creator project there are a number of “sources” of “source code” including:
- Cypress PSoC Component Code from the Cypress Component Library (which end up in the Generated_Source directory)
- Your C Source code files .h/.c e.g main.c
- Your Components from your Component Library (which end up in the Generated Source Source directory)
- Other Libraries of code (e.g. FreeRTOS or Percepio Tracelyzer)
There are (at least) five tools which need to “know” about where the source code for your project resides including:
- Workspace Explorer (so you can browse the files and open the code in an editor)
- PSoC Creator Code Editor (so Intellisense works correctly)
- GCC Compiler
Here is a video where I talk about the files structure of PSoC Creator Projects:
PSoC Creator takes care of so many of these details automatically for you, so I have not put much thought into how these things work. But, in the last few months, I have been building projects that use FreeRTOS, which has made me contemplate how things go together. This is the genesis of this Article.
Lets start with a blank project (which I created for the CY8CKIT-044). When you make this project you can see that you get:
- A Workspace (called Workspace07) that contains one project. The name is just a default name + a number that Creator made for you.
- A Project (called Design01)
- A Schematic (called TopDesign.cysch)
- Design Wide Resources (called Design01.cydwr)
- A folder for Header Files which contains a file called cyapicallbacks.h
- A folder for Source Files that contains main.c
When you look at the disk you will see a directory at the top level called “Workspace07”. This directory contains:
- The workspace file called Workspace07.cywrk and a user specific settings file called Workspace07.cywrk.arh (the .arh is my windows login). This binary file contains references to all of the projects that are part of the Workspace. Plus other Workspace configuration.
- A directory called “Design01.cydsn”. This directory contains everything required for the project.
When I look in the directory called “Design01.cydsn” I see
- Design01.cyprj (an xml file that contains all of the information about the project)
- Design01.cydwr (an xml file that contains all of the Design Wide Resource settings)
- The two source files main.c and cyapicallbacks.h
- A directory called “TopDesign”
In the TopDesign directory you will find the TopDesign.cysch which is the binary file of the schematic.
Now that we have accounted for all of the “basic” project stuff. I will run “Generate Application” from the build menu.
Cypress PSoC Creator Components
After the Application Generation is done you will see a bunch of more stuff in the Workspace Explorer. Specifically a new folder called “Generated_Source”. In that folder you will see a folder called “PSoC4” that contains a bunch of files plus some more folders. These folders are created by the application generation process to hold the source code for components including cy_boot, cy_dmac, and cy_lfclk. But you say, “I didn’t place any components”, and that is true, but PSoC Creator did this automatically for you when you made the project. These source files are used to get the PSoC booted, the linker setup, the CMSIS core definitions etc.
When you look on the disk, you will see a completely different hierarchy than you see in the Workspace Explorer. In fact you will see all of these files in a directory called “Generated_Source/PSoC4”. This tells us something important. The workspace explorer gives you hierarchy so that you can see the different files grouped together logically. BUT this hierarchy is completely unrelated to how the build process works (more on this in a minute) or how the files reside on the disk. DANGER DANGER WILL ROGERS!!! (these Folders are actually called “Filter Folders” and you can read about them in the PSoC Help Topic “Creating Folders”)
When you place a component in the schematic (e.g. a UART) and run the build again you will find more folders & files in the Generated_Source section of the Workspace Explorer
But when you look in Generated_Source directory on the disk, you will find ALL of those files in one directory.
When you place a component, PSoC Creator takes the API from the Component Library, processes it, names it correctly, adds it to your “.cyprj” file so that the Workspace Explorer can see it, then copies the code into your Generated_Source directory. You could edit it there, but if you do, you are at risk to having it overwritten the next time you build the project. All of the configuration you do to a component gets turned into c-source that resides in the Generated_Source directory
When you delete a component, the related generated source code (e.g., UART_1.*) won’t be visible in Workspace Explorer, but IT STILL LIVES ON DISK. This is a consequence of our legacy “merge region” support. The user may have edited the file and PSoC Creator doesn’t want to destroy those edits. This can cause inconsistencies between what Workspace Explorer shows the user and what the compiler actually sees:
- PSoC Creator will NOT compile any irrelevant .c files present in the file system.
- However, the compiler WILL see any stale .h files that happen to be lying around when it processes #includes.
So, what is a merge region? When PSoC Creator was originally created, it was recognized that there was occasionally need for a user to put code into a generated file e.g. an interrupt handler. And we also wanted PSoC Creator to be able to regenerate that file. If you look around in Generated_Source files, you will find sections of code that look like lines 27-30. If you put code between those funny looking comments, it will not be blown away when you regenerate your application. In other words PSoC Creator preserves all of the code in merge regions. This mode has mostly be supplanted by the use of the “cyapicallbacks.h” functionality.
* Function Name: isr_1_Interrupt
* The default Interrupt Service Routine for isr_1.
* Add custom code between the START and END comments to keep the next version
* of this file from over-writing your code.
* Note You may use either the default ISR by using this API, or you may define
* your own separate ISR through ISR_StartEx().
#endif /* isr_1_INTERRUPT_INTERRUPT_CALLBACK */
/* Place your Interrupt code here. */
/* `#START isr_1_Interrupt` */
/* `#END` */
Your Code in C Source Files (.h/.c)
All of the files in “Header Files” and “Source Files” are considered to be owned by you. In other words, PSoC Creator will never make changes to those files. PSoC Creator starts by giving you copies of two template files, main.c and cyapicallbacks.h. These files are yours to edit and you are responsible for the contents.
If you are making a project that is to big to logically fit into just main.c you may want to split it up into multiple .c and .h file. You can do this by adding .c and .h source files to your project. Right click the “Header Files” folder (or “Source Files”) and select “New Item”
Then enter the name of the file and select the FileType (in this case I did “blahblah.h”)
After doing that I will have a new file in the Workspace Explorer
Plus I will have the same file in the Design01.cydsn directory
All of the files that I add by doing “New Item” will end up in the “right” folder and reside in the project directory on the disk.
In PSoC Creator, it is possible to create your own Components. You can read or watch videos about this process
- IoT Expert Component Examples
- Video Tutorial
- PSoC Creator Help –> Documentation –> Component Author Guide
After you have a library with Custom Components, you can add it as a dependency to your project by right clicking on the project and selecting “Dependencies …” Then navigating to the .cyprj file with your components. In this case I added the IoTExpert_PSoC_Components library
You can see that the “IoTExpert_Components” shows up in the User Dependencies
Once this is done you will see the new Component Libraries in the Component Catalog.
Components from your custom libraries act exactly the same as the Cypress Components. Specifically, after you place a custom component in your schematic, when you build the project, it will process the source code, copy it into the “Generated_Source” directory, add the files to your WorkSpace Explorer etc.
A custom component is a good way to easily add a library of source code to your project.
3rd Party Libraries
The last class of source code comes from 3rd Party Libraries. Classically, these libraries have one more more directories with .c, .h and .a (static libraries) files. There are some of the files which you might want to modify to configure your version of the library, there are other files that you just need to be compiled into your project. This situation leaves you with some choices.
- You can copy all of the library files into your project directory (then add existing item)
- You can copy some of the library files into your project directory and leave some of the files in the library directory
- You can add references to the library files into your project
The main issue that you need to consider is Source Code Control – Version Management of your project. If you copy the library files into your project directories, then you are sure that they won’t change out from underneath you. BUT, if the library has a bug fix, then you won’t automatically get it. It is often considered a best practice to have a “single source of truth”. When you copy files into your project, you violate that principal. This is a choice that you will need to grapple with.
This is probably best explained with a real example, FreeRTOS. I have been using the hybrid model. Specifically I copy the configuration files into my project, but leave the rest of FreeRTOS in my downloaded directory and use references in my PSoC Creator Project. The process is:
- In the Windows Explorer copy FreeRTOSConfig.h into my project directory
- Right click the project and “Add Existing Item”
Then select “FreeRTOSConfig.h” from my project directory
After that you can see that “FreeRTOSConfig.h” is part of my project in the “Header Files” section
I like the rest of the FreeRTOS Files to be part of the project but not actually copied into my project directory. To do this, I add the required C-Files using the same technique of “Add Existing” To make FreeRTOS work you need to add all of the C-Files and H-Files in:
PSoC Creator will automatically take care of telling the compiler where to get the C-Files. However, it will not take care of the H-Files. In order to do this you need to change the build settings to add the path to all of the H-Files that you use. Modify the build settings by right-clicking the project and selecting “Build Settings …”
Then selecting the “…” on Design01 –> Arm GCC … –> Compiler –> Additional Include Directories
Then press the “New” and then the “…” to browse to the directory you want to add.
Finally you will end up with a window that looks like this:
And when you look at the build options you will see the “-I..\..\..\FreeRTOSv9.0.0\FreeRTOS\Source\include” is added to the compiler options (look at the little window at the bottom)
Thank you to Nick from the PSoC Creator Team for reviewing my Article. He is one of the lead technical genius’ that made PSoC Creator the bad-ass software that it is.