Skip navigation
Home > All Places > ModusToolbox > Blog > 2019 > December

Managing GitHub Libraries

Posted by MarkS_11 Dec 29, 2019

In my last blog, Using the retarget-io library to enable printf(), I assuaged some of my guilt over not bothering to explain where the pin and baud rate defines come from in Extending and Re-Targeting My Second ModusToolbox Project. Now it is time to explain the library shenanigans! Actually, there are precisely zero shenanigans involved... it is all clean and above board... but I just wanted to say "shenanigans". I think it is out of my system now.

When you add a library from the command line using git clone, as I have been doing in my last few blogs, then you get all the firmware and a .git folder, where all the GitHub information is maintained. If you are good at using git (I am not!!!) then this is all you need to be able to update the firmware to new releases and all that good stuff. If you are not a git maven (like me) or are a bit lazy (a lot like me) then Library Manager can really help you out.

When you add a library using the manager then it creates a cunning extra file with the extension .lib. This lib file records where the library came from and its version. It contains just a single line, like this example for retarget-io:


Simple huh? There really is no shenanigans here - just the GitHub address and the version (after the #).

When you run the Library Manager it reads this file to figure out what libraries are included in the project and marks them with a checkbox. In this image the manager is showing that the retarget-io library is included. Also, if you click in the Version column you will see all the available versions. If you select a different version and press Apply the manager will replace the firmware for you.

The "Latest_v1.X" version is special. It means that the manager will update to the newest available v1 implementation. If we release a new version, the manager (or "make getlibs") will update your project without any extra effort on your part. Good eh? Of course, when you are deep into a project you will probably want to lock down the version. It's easy, just use the pull-down to choose a specific version, like "1.0.0 release" in our example, and press Apply. That will get the right software and only update it if you go back and request it explicitly.

This is probably my last blog of 2019. I hope you found some of this year's content helpful! I'll be back in January with some more descriptions of cool ModusToolbox features and examples of how to leverage them to make fabulous applications. And maybe some more shenanigans!

Last week I slid in a call to cy_retarget_io_init() in my application without explaining it. I felt a bit naughty about that and so promised to explain it to you. Here goes!

The Cypress retarget-io library implements low-level character I/O functions expected by the Arm and GNU C compilers. These functions are called from the printf() and scanf() functions that come from the STDIO C-language run-time library. The actual names of the functions depend on the compiler you are using, but the library is written so that the right implementations are enabled for you automatically. Here is some code to remind you how it works (this code works on all supported compilers).

Start by adding these two header files to tell the compiler about the low-level functions and printf(), respectively.

#include "cy_retarget_io.h"

#include <stdio.h>

In the main() function you need to just initialize the UART, check it worked correctly, and start printing with wild abandon.


    CY_ASSERT( result == CY_RSLT_SUCCESS );

    printf( "Program started...\r\n" );

Note that the CY_ASSERT() call just halts the application if the expression equates to false, which is probably a little simplistic in a real application but makes the point here. About the only reasons why this call would fail, though, are that you have a) passed in a pin that is not accessible from any of the PSoC SCB blocks, or b) requested a baud rate that cannot be achieved, or c) have already initialized the UART.

So, this is all fine and dandy but the arguments to cy_retarget_io_init() need a little explanation. The function just sets up the UART for the pins defined by the first two arguments - CYBSP_DEBUG_UART_TX and CYBSP_DEBUG_UART_RX. The prefix to those macros is a hint as to where they are defined - the BSP. Take a look in your project folder and jump down into the libs folder - this is where the Library Manager saves the content you select. There are folders with the prefix "TARGET", which are the kit BSPs. Looking in TARGET_CY8CKIT-062-WIFI-BT you will see a useful little file called cybsp_types.h. Here's a snippet from that file.

/** Pin: UART RX */

#define CYBSP_DEBUG_UART_RX         (P5_0)

/** Pin: UART TX */

#define CYBSP_DEBUG_UART_TX         (P5_1)

The author of the BSP has helpfully defined the pins that connect to the KitProg device. This means that, regardless of the kit you have, those macros will help you set up I/O across the KitProg bridge (to your computer). When you call cy_retarget_io_init() with those macros as the first two arguments, the library code figures out which SCB they are connected to and initializes it as a UART. If you wish to redirect the I/O then just change the arguments of the desired pins, such as P6_0 and P6_1.

The other argument in our function call is CY_RETARGET_IO_BAUDRATE, which is obviously the baud rate, but where is it defined. This is not a BSP macro. Rather, it is a retarget-io library define which helps all Cypress examples run UARTs at the same speed. Look in libs/retarget-io and you will see cy_retarget_io.h, the file that we included at the top of this blog. The following define is easy to find in that file.

/** UART baud rate */

#define CY_RETARGET_IO_BAUDRATE         (115200)

As you can see, if you want to run your UART at a different speed, just use a different number, such as 9600, like this:

    cy_retarget_io_init( P6_1, P6_0, 9600 );

Hopefully this explains what is going on with the library and explains how to make simple changes in your code to modify the printf() speed and hardware. I feel better for honoring my commitment from last week... next time I shall explain how the Library Manager works its magic!


In My Second ModusToolbox 2.0 Project I wrote about the project-creator tool and built a TCPWMSquareWave project for the CY8CKIT-062-WIFI-BT kit. Today I am going to add a library to the project and enable printf() through a device UART. Wooooooo! First, let's take a look at the libraries we already have (which came in with the code example project that I cloned last week).


There are two TARGET_* folders, which are the kit BSPs. Then there are things like capsense and psoc6pdl. Each folder contains a library and we are going to add a new one. I do this by starting the library-manager from my shell.


yfs@YFS-T550 ~/TCPWMSquareWave

$ ~/ModusToolbox/tools_2.0/library-manager/library-manager.exe &

[1] 2258

yfs@YFS-T550 ~/TCPWMSquareWave


After a short while the tool pops up and shows the BSPs that you can use. It also lists more that you can add, if you like.


Switching to the "Libraries" tab I can see the ones that are already on disk. Check the "retarget-io" box and press "Apply" to add that library.


A quick look at the folders shows that the manager has added the new folder and a .lib file (more on that next time).


Now that we have added the library, let's write a bit of code to try it out. Start by adding these two include files. These bring in the function definitions for the retarget-io library and also the C run-time printf() function, which is pretty much the raison d'etre of this blog.


#include "cy_retarget_io.h"

#include <stdio.h>


Note that I am using the angley bracketty thingies around stdio.h, also known as the less than and greater than signs, and probably a more mature and professional name as well. That is just because I am grabbing the header from a system rather than user path. It turns out that you can just use the regular quotes in ModusToolbox projects if you want but, if you set up your compiler paths using -J instead of -I, then angley thingies it must be!

Now we need to tell printf() where to print. Here is the code to do that - put it in main() somewhere after the call to cybsp_init() and before the PWM code. The cy_retarget_io_init() function sets up the UART that gets used when printf() has formatted the string and is sending out the characters via __write(), which is in libs/retarget-io/cy_retarget_io.c. Note that __write() is the function used by the GNU compiler printf() implementation. If you build with the Arm Compiler then the library automatically sets up fputc() instead - so you can change compilers and continue to print without torture!



    CY_ASSERT( result == CY_RSLT_SUCCESS );

    printf( "TCPWM Square Wave started...\r\n" );


To check this works just run "make program" and connect up a terminal emulator.


Woo hoo! Looks like I got it right. Now I am going to make another change with the library manager - switching to a new target board. I have touched on this before but switching hardware is really easy in ModusToolbox. The only essential change is to edit the "TARGET" rule in the Makefile. That works for command line builds but, as we saw in the comments for Re-Targeting My ModusToolbox 2.0 project, it does not regenerate the launch configurations for the IDE. So, to avoid confusion it is probably best to use the library-manager. There is a handy drop-down menu for that and so I have made it a habit to use that to change the BSP. Just choose the board, as shown here, then press "Apply" to safely switch the default BSP for your project.


As before, all I need to do now is "make program" (and remember to connect the new board to my laptop!). It works like a charm!

Now I have to admit that I kinda glossed over two things today. Firstly, I talked about the libraries but did not explain how the manager knows where to get them and how to update them, so I'll fix that soon. I also told you about the cy_retarget_io_init() function and completely glossed over where the arguments come from! I do not like the idea of you guys blindly copying the code and not understanding it fully - that makes me feel itchy - so I'll explain that too. Honest. I promise... next time!

With any luck, my last two blogs - My First ModusToolbox Project and Re-Targeting My ModusToolbox 2.0 Project - gave you some insight into the anatomy of ModusToolbox projects. The most important learning from them was not really to get used to the git clone and make commands, rather to understand where the files in a project come from and how to manage them. That said, I have to admit, it's a lot to keep in your brain. Let's face it, we've all got more important things to dedicate memory cells to!

Let's look at some easier methods of creating projects. In your ~/ModusToolbox/tools_2.0/project-creator folder there are two executables which automate the process for you.



As you might have guessed, this is the command-line tool. I am going to pretend to be a real engineer for a moment and advise you to start by running the command with the "--help" option to get started. Obviously, being lazy and obstinate, I did not do this, but it would have saved me some time so I'll ask you practice what I preach, not what I do! It will tell you about the --board-id, --app-id and --user-app-name options, which I'll use in a moment. But there is also the fiendishly clever --list-apps option which tells you all the GitHub-hosted projects that are compatible with a kit. Here are the options for the WIFI-BT kit.


$ ~/ModusToolbox/tools_2.0/project-creator/project-creator-cli.exe --list-apps CY8CKIT-062-WIFI-BT

Getting manifest...


Successfully acquired BSP/Application information from remote server.

List of template applications supported by the board "CY8CKIT-062-WIFI-BT":

































Nice! This is a convenient way to see the examples without trawling around I am going to try the tcpwm-square-wave example. I shall call my project "square-wave" and put it into the folder called "square" using those options we saw in the help output. Here goes...


$ ~/ModusToolbox/tools_2.0/project-creator/project-creator-cli.exe --board-id CY8CKIT-062-WIFI-BT --app-id mtb-example-psoc6-tcpwm-square-wave --user-app-name square_wave

Getting manifest...


Successfully acquired BSP/Application information from remote server.




= Cloning 'mtb-example-psoc6-tcpwm-square-wave' =


Cloning into C:/Users/yfs directory...

Cloning into 'square_wave'...

remote: Enumerating objects: 13, done.

remote: Counting objects: 100% (13/13), done.

remote: Compressing objects: 100% (10/10), done.

remote: Total 13 (delta 0), reused 10 (delta 0), pack-reused 0

Unpacking objects: 100% (13/13), done.



Cheking out latest-v1.X...

Note: checking out 'latest-v1.X'.



You are in 'detached HEAD' state. You can look around, make experimental

changes and commit them, and you can discard any commits you make in this

state without impacting any branches by performing another checkout.



If you want to create a new branch to retain commits you create, you may

do so (now or later) by using -b with the checkout command again. Example:



  git checkout -b <new-branch-name>



HEAD is now at 17f92ae Upload mtb-example-psoc6-tcpwm-square-wave




= Creating 'TARGET_CY8CKIT-062-WIFI-BT.lib' file(s) =





= Updating Makefile for 'square_wave' =


Tools Directory: C:/Users/yfs/ModusToolbox/tools_2.0



Initializing import: mtb-example-psoc6-tcpwm-square-wave




= Importing libraries =


Git is git version 2.17.0, found at /usr/bin/git



Searching application directories...

Application directories search complete.



Searching libs directory...

Found 2 file(s)

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W.lib

Libraries were processed. Re-evaluating libs directory...

Found 14 file(s)

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/capsense.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/core-lib.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6cm0p.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6hal.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6make.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6pdl.lib

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/capsense.lib

        Library "capsense.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/capsense.lib.

        Skipping current reference...

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/core-lib.lib

        Library "core-lib.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/core-lib.lib.

        Skipping current reference...

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6cm0p.lib

        Library "psoc6cm0p.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6cm0p.lib.

        Skipping current reference...

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6hal.lib

        Library "psoc6hal.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6hal.lib.

        Skipping current reference...

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6make.lib

        Library "psoc6make.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6make.lib.

        Skipping current reference...

    Processing file C:/Users/yfs/square_wave/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6pdl.lib

        Library "psoc6pdl.lib" was already processed at C:/Users/yfs/square_wave/libs/TARGET_CY8CKIT-062-WIFI-BT/libs/psoc6pdl.lib.

        Skipping current reference...

Libraries were processed. Re-evaluating libs directory...

Found 14 file(s)

libs directory search complete.




= Import complete =




Successfully created "square_wave" application.


In one command I have created a new project, added a BSP, set it as the default for build and program, and pulled in all firmware libraries needed to build the application. Just plugging in the kit and running "make program" is all it takes to build and program the board.




If the above is still too much typing then run the non-CLI executable - ~/ModusToolbox/tools_2.0/project-creator/project-creator.exe. You can start it from Windows Explorer or launch from the command line with "~/ModusToolbox/tools_2.0/project-creator/project-creator.exe &". Note that I do it in the background with the ampersand at the end of the line, so I can still use the shell.


The GUI tool (why is it not spelled "gooey"?) starts by grabbing a bunch of information from the mtb-super-manifest.xml file on GitHub (I'll write more about this file, and creating your own manifests, in a future blog).


Just press "Next>" to get to the good stuff.


Now pick your kit.


Choose the application and give it a name and a sensible location.


You then get a summary of what you ordered. Press "Create" and let the tool assemble all the parts. You'll recognize all the GitHub and make output in the dialog. Once it is all done you just "make program" in the shell to get the application onto the kit (you may want to edit main.c to change the value of PWM_FREQUENCY to make sure your new program is actually running rather than the old one!).


Next time, I shall show you how to add BSPs and firmware libraries to a project using another helpful tool, the library-manager.