ModusToolbox 2.0 – Libraries an Example for emWin & Super Manifests


In this article I will walk you through creating a library for ModusToolbox 2.0 that will glue the Cypress RTOS Abstraction layer, emWin, the SSD1306 and the PSoC 6 together.  In the end, the library will become available in the Modus Toolbox Library Manager by creating a Super Manifest file.

NOTE:  This blog was originally written about the Modus Toolbox 2.0 library scheme.  With the release of Modus Toolbox 2.2 this scheme was changed and this blog is now obsolete! Instead, you can use the Infineon display-oled-ssd1306 library.

The Story

I like using the Segger emWin graphics library.  And, I have always hated getting the “glue” into my project that makes the library work.  The glue includes the configuration files for emWin plus the hardware driver functions to talk to the SSD1306 screen.  I have always thought that it would be really nice to have a simple library scheme – yes I know that there are lots of schemes out there but I wanted one that was neatly integrated into our tools.  Well, with ModusToolbox 2.0 my wish was granted.

In ModusToolbox 2.0 if you create a file called “someLibraryName.lib” that contains a URL to a GitHub (or Git) repository, the make system will know how to bring that library into your project.  The make target “getlibs” does exactly that.  And, once it is on your computer in your project the Modus Toolbox make system will know how to include it as part of your project.

For this article I will create a library called “p6sdk-ssd1306-emWin-freerots-config” which will contain:

Files Purpose
GUIConf.h Configures emWins abilities, fonts etc.
GUIConf.c Defines & Assigns RAM for the GUI,initializes the font
GUI_X_CYRTOS.c Makes a connection between emWin and Cypress RTOS abstraction for things like timing, semaphore etc.
LCDConf.h A blank file
LCDConf.c Functions to configure screen,connect the emWin APIs to the I2C write functions, configures the display driver
SSD1306Driver.h Functions prototypes to initialize the I2C and read/write the I2C
SSD1306Driver.c Initialize the SSD1305 driver, write commands, write data, write datastream functions which are called by the LCDConf.c functions
template A directory (which is not compiled) that contains template c files for use as an example

SSD1306 Driver

In order to glue the hardware to the emWin library you need to provide functions that

  1. Initialize the driver – (Tell it what I2C hardware and I2C address the display is connected to)
  2. Write data/command bytes and streams
  3. Read data streams (which it actually never does)

The SSD1306Driver.h provides a public interface for these functions which are used in the LCDConf.c file.

#ifndef SSD1306_DRIVER_H
#define SSD1306_DRIVER_H
#include "cyhal.h"

void SSD1306DriverInit(cyhal_i2c_t *obj,uint8_t oledAddress);

void          SSD1306_WriteCommandByte(unsigned char c);
void          SSD1306_WriteDataByte(unsigned char c);
void          SSD1306_WriteDataStream(unsigned char * pData, int NumBytes);
void          SSD1306_ReadDataStream(unsigned char * pData, int NumBytes);


The first part of SSD1306Driver.c makes a pointer to and Cypress HAL I2C object.  In the initialization code, it connects the provided I2C object and the static pointer.  The purpose of this is to allow the application developer to use the I2C for other devices on the bus, in other words the I2C bus is shared.  On most of my screens the I2C address is 0x3C,  so I let the user not provide an I2C address.  Probably in hindsight I should have just made them always provide an I2C address.

#include "SSD1306Driver.h"
#include "GUI.h"
#include "cyhal.h"
#include "cybsp.h"
#include <stdlib.h>

*       Defines: Configuration
  Needs to be adapted to custom hardware.
/* I2C port to communicate with the OLED display controller */
static cyhal_i2c_t *I2C=0;

/* I2C slave address, Command and Data byte prefixes for the display controller */
#define OLED_CONTROL_BYTE_CMD       (0x00)
#define OLED_CONTROL_BYTE_DATA      (0x40)
static uint8_t OLED_I2C_ADDRESS     =    (0x3C);

void SSD1306DriverInit(cyhal_i2c_t *obj,uint8_t oledAddress)

		OLED_I2C_ADDRESS = oledAddress;

In order for emWin to update a display it needs to be able to write data to the display via “commands” and “data” writes.  However, it doesn’t know anything about the fact that these displays are typically attached via I2C.  The function SSD1306_WriteCommandByte uses the Cypress HAL master write API to send a command byte to the display.  This function is called by emWin via the configuration in LCDConf.c

void SSD1306_WriteCommandByte(unsigned char c)
    uint8_t buff[2];

    /* The first byte of the buffer tells the display that the following byte
        is a command */
    buff[0] = OLED_CONTROL_BYTE_CMD;
    buff[1] = (char)c;

    /* Write the buffer to display controller */
    cyhal_i2c_master_write(I2C, OLED_I2C_ADDRESS, buff, 2, 0, true);

And the write data byte function works exactly the same way as the write command byte, except it send a different first byte.

void SSD1306_WriteDataByte(unsigned char c)
	uint8_t buff[2];

    /* First byte of the buffer tells the display controller that the following byte
        is a data byte */
    buff[1] = c;

    /* Write the buffer to display controller */
    cyhal_i2c_master_write(I2C, OLED_I2C_ADDRESS, buff, 2, 0, true);

emWin Configuration Files

I have written extensively about how to configure emWin and specifically how to setup the files for the SSD1306.  You can see the articles here.  So, I am not going to describe those files in detail except to say that the ones that you need are GUIConf.h/.c, LCDConf.h/.c and GUI_X_CYRTOS.c.  The only changes from the previous configurations of LCDConf.c is to hookup the APIs we defined in the previous section.

    PortAPI.pfWrite8_A0  = SSD1306_WriteCommandByte;
    PortAPI.pfWrite8_A1  = SSD1306_WriteDataByte;
    PortAPI.pfWriteM8_A1 = SSD1306_WriteDataStream;


I checked in all of these files into GitHub at  Now they can be used as a Modus Toolbox library.

Test Library

Lets build a test project.  Start by creating  new project.  Notice that I am not using the built in project creator, but a standalone project creator which does not require Eclipse.  This is automatically installed for you as part of the Modus Toolbox installation (so, if you are one of the legions of people who don’t like Eclipse you don’t have to use it).  Run it from the start menu.

For this demo I will use the CY8CKIT-062-WiFi-Bt kit… but this works on all of of our PSoC 6 kits with Arduino headers.

I start using the IoT Expert FreeRTOS template.   And I store the project in the directory “~/iotexpert-projects/xxx”.  A long time ago I started using directories named “xxx” to mean that I can “rm -rf xxx” and I never store anything that matters in those files/directories.  Give the project a name then press next.

Now you have everything setup.  So click “Create”

And our software will do its thing.

Now if I look in the directory, I will have a complete project.

Now lets manually add the .lib for the p6sdk-ssd1306-emWin-cyrtos-config.  You can use whatever editor you want, but it’s emacs for me.

Enter the URL for the library.  Then put a “/”.  Then a branch.

Now that the file is updated you can run “make getlibs” which will search for all of the “.lib” files.  Then make sure those libraries are part of your project.

After the make getlibs is run you can see that the p6sdk-ssd1306-emWin-cyrtos-config directory is in your libs directory, with all of the stuff you need.

The next step is to edit your main.  I like to use vscode.  If you run  “make vscode” our build system will create a vscode project for you.  You can start vscode by running “code .”

Before the emWin library work you will need to add the EMWIN_OSNTS and FREERTOS components to your Makefile.


Here is what it looks like in vscode

Now, write the your main.c code to display a little message.

#include "cybsp.h"
#include "GUI.h"
#include "SSD1306Driver.h"

int main(void)
        /* Set up the device based on configurator selections */

        cyhal_i2c_t I2C;

        /* Configuration to initialize the I2C block */
        static cyhal_i2c_cfg_t i2c_config = {
                .is_slave = false,
                .frequencyhal_hz = 400000
        cyhal_i2c_init(&I2C, CYBSP_I2C_SDA, CYBSP_I2C_SCL, NULL);
        cyhal_i2c_configure(&I2C, &i2c_config);


        GUI_DispStringAt("Hello World", GUI_GetScreenSizeX()/2,GUI_GetScreenSizeY()/2 - GUI_GetFontSizeY()/2);

You can build your project by running “Build” from vscode or your can built it on the command line with “make build”

After building you should have output like this:

You can program by Pressing selecting or by pressing F5 or selecting “Run->Start Debugging”

Now you can press the play button and you are off to the races

Or on the command line you can program with “make program”

OK.  Looks like the library works!

Updating the IoT Expert MTB2 Manifests

I showed you how to manually add a library to your project.  But what if you want to have the library you built show up in the Library manager?  In the picture below you can see that is exactly what I did by adding a new category called “iotexpert”

To make this work you need a “Super Manifest” which is just a XML file that contains URLs references to your custom Application Templates manifest file(s), Middleware manifests file(s), and BSP manifest file(s). A “manifest” file is just an XML file with a list of URLs to Git Repos and some meta data.

In words you need:

  1. A file in your home directory called ~/.modustoolbox/manifest.loc which contains a URL for your cusom super manifest file
  2. A super manifest file that optionally contains a references to your application templates manifest file(s)
  3. And/Or contains a reference to your middleware manifest file(s)
  4. And/Or contains a reference to your board support manifest(s)

I start by creating the manifest.loc file to refer to a specific file on GitHub. “”.  Notice that it is stored in “.modustoolbo” which is a directory that starts with a “.” which is a PITA on Windows.  The only way I know how to edit/create this is by using the “modus shell” (which we provided as part of the Modus Toolbox installation.  Here is a screenshot from my Mac.  Notice that I use the GitHub URL mechanism to get to the “raw” file.

In my SuperManifest file I create references to the

  • board-manifest-list (of which I have none)
  • app-manifest-list which links to my application template manifest
  • middleware-manifest which links to my middleware manifest file

Notice that both of these files are on the same GitHub repository.


Then if you look at the actual middleware manifest you will see that I have two (currently) middleware repositories

  • (The NTSHell)
  • (The SSD1306 Middleware in this article)

The rest of the XML is meta data which specifies how the middleware is presented by the library manager.

    <desc>NT Shell</desc>
        <num>Latest 1.X release</num>
        <desc>Latest 1.X release</desc>
        <num>Latest 1.X release</num>
        <desc>Latest 1.X release</desc>

You can see that my GitHub repository contains

  1. iotexpert-super-manifest.xml  – amazingly enough the super manifest
  2. iotexpert-mw-manifest.xml – my middleware manifest file
  3. iotexpert-app-manifest.xml – my application template manifest file

Now if you look at the bottom of the library manager you will see that when it starts up it read the Cypress Super Manifest file, as well as the IoT Expert Super Manifest.

To be clear.  If you add my “manifest.loc” file to your ~/.modustoolbox directory you will access to all of my libraries.

Infineon SupIRbuck – Low Voltage/High Current Measurement


This article will show you the steps to produce 12A from and IRDC3894.  It also discusses low voltage high current measurement and burden voltage.

The Story

In the last few weeks I have been working on a TypeC to Infineon SupIRbuck power supply that will turn 20V@3A into 5V@12A.

In that process I have been working with a Keithley 2380-500-15 which can act as a load simulator for my design.  The 15 in name means that it can pull 15A which should be more an adequate to test my design.  Unfortunately when I was looking at the specs, I read the part about “15A” but not the part about the “Min Operating Voltage in the 15A range = 4.5V”

And what I really should have bought (and now have) is a 2380-120-60

Big Resistors

But I really wanted to be able to measure the current coming out of the IR3894.  So, I decided to buy some “Big” resistors.  Well they are not actually high resistance, but they are HIGH power. 35W and 50W.  Unfortunately they are also $4 each.  Here is a 0.33Ω 50W resistor.  (I will totally understand the value of that giant heat sink later on in this article)

My measurement setup looks like this:

And actually looks like this terrible mess:

Start the measurements

I bought 7 different resistors ranging from 0.1Ω to 1Ω.  This means that I should be able to get something like this table.  Note that the 0.1Ω is marked in red because it exceeds the current limit of my multimeter. (i.e. don’t do that)

V R A W Rating
1.2 0.10 12.0 14.4 35
1.2 0.15 8.0 9.6 50
1.2 0.20 6.0 7.2 35
1.2 0.33 3.6 4.4 50
1.2 0.50 2.4 2.9 35
1.2 0.75 1.6 1.9 50
1.2 1.00 1.2 1.4 50

I wasn’t exactly sure what was going to happen so I decided to start with the 0.33Ω resistor

I was hoping to get 1.2V/0.33Ω = 3.6A yet I end up with 1.99A where is my other 1.6A?

I put in a 0.1Ω, 0.15Ω and 0.75Ω and measured the current.  Then I calculate the effective resistance of the system and it turns out that there is essentially another 0.27Ω in series with my R1


V/I-R1 = Rb

V A R1Ω RbΩ R1+RbΩ
1.2 2.0 0.33 0.27 0.60
1.2 3.16 0.10 0.28 0.38
1.2 2.85 0.15 0.27 0.42
1.2 1.175 0.75 0.27 1.02

Where in the world is the other 0.27Ω?

Melt the Probe

This leads me to the great idea that is just the lead wires, and that I ought to just pull out the resistor and see what happens.  Well, what happens is that I melt the probe, and I still don’t get numbers that make sense.

Burden Voltage

The real story is, of course, that digital multimeters are hardly “ideal” and that when you are measuring current what you are really doing is measuring the voltage across a “shunt resistor”.  A shunt resistor is just a small valued highly precise resistor.  The voltage across this resistor is also known as the burden voltage (which is why I called it Rb above).  Here is a picture out of the Keysight documentation.

But how big is that resistor?  Well, unfortunately it is not specified directly in the documentation.  But, when you look at the data sheet you find that the maximum burden voltage is 0.5V at 10A.

This means that shunt resistor is no more than 0.5v/10A=0.05Ω.  I just ordered a new Keithley DAQ6510 Digital Acquisition System Multimeter (which Im very excited about) that has the following table in documentation where it says the shunt resistor is 100mΩ for the 3A range.

Measure the Lead Resistance

So now we know that the shunt resistor is something like 0.05Ω.  That means the rest of the resistance has to be in the test setup.  So

V=(R1 + Rl + Rb)*I … the lead resistance + the shunt resistor + the actual resistor.  I go ahead and calculate what the lead resistance with several different resistors.

This means the resistance of my lead wires must be something like 0.23Ω

V A R1 Rl Rb R1+Rb+Rl VR1 VRl VRb
1.2 2.00 0.33 0.23 0.04 0.37 0.66 0.46 0.08
1.2 3.16 0.10 0.23 0.04 0.15 0.32 0.73 0.16
1.2 2.85 0.15 0.23 0.04 0.19 0.43 0.66 0.12
1.2 1.18 0.75 0.23 0.04 0.79 0.88 0.27 0.05

Again I start to look for the lead wire resistance … 0.6Ω for the melted lead.  Curious.

It is pretty easy to get some crazy measurements.  2.7Ω just pushing two banana plugs together (though you can see it blinking)

If I measure the red banana plug wire looped back the measurement is 0.016Ω – OK that is pretty small

And the black one is almost the same.

After some experimenting mixing and matching cables together the lowest I manage to get in a configuration that I can actually plug together is 0.15Ω which gave me 7.8A.

So where does this leave me?  To tell you the truth it leaves me a bit frustrated.  I really wanted to get 12A out of my setup (which is what it should be able to do).  But the most I can safely measure is 10A.  And the lowest combination of resistors I seem to be able to get is 0.15Ω.  So I decide to solder the 0.1Ω resistor straight into the board and see what happens. (yes that is some ugly soldering)

And now Im really frustrated because when I turn on the bench power supply I get 9.9V and 0.6A … even though it is set for 12V

And when I look at the output voltage I get 0.4V.  Which means it isn’t working.  Why?  I don’t know…. which is beyond annoying.  Walk away now I say to myself (actually that was my wife yelling at me 🙂 )

24 Hours Later

After sleeping on it, I remember that the Enable pin is used as an “Under Voltage Lock Out”.  The purpose of the UVLO is to not turn on until the input voltage has enough power to supply the system.  Given that I am am asking for 12A I realize… maybe I need to “enable” later in the power supply voltage rise.

So what I do I solder in a jumper to “Enable” then I press fit it into the ground.  Then turn on the power supply.  I measure the output as 0V.  That is good.  Then pull the enable jumper wire and let the IR3894 turn on.

Sure enough.  When I look at the input it gets to 12V@1.4A and the output is still steady at 1.2v.  And my 0.1Ω is very hot.  I suppose that heatsink tab is there for a  reason.

I know from Ohms law that I am getting 12A@1.2V.  So the IR3894 seems to do the trick!

Cypress Type-C Barrel Connector Replacement + Infineon Buck DC/DC (Part 3)


This article walks you through the steps to test the CY4533 Type-C BCR & IR3894 under the load conditions from 1A to 12A.  In the previous article, I supplied power to the IR3894 using a bench top power supply.  For this set of experiments I will use a Type-C wall wart connected to the Cypress 4533 BCR development kit to supply power.

Test the BCR

The first thing that I do is connect the whole mess together like this:

Here is how it looks on my desk.  Note that the Keithey can measure current and voltage… but that I don’t have a way in this setup to measure either the voltage/current from the power supply or the current out of the CY4533

I step the output load from 1A to 12A in 1A increments.  I am super happy to see that the output voltage of the IR3894 is perfectly regulated to 1.198V.  It is also interesting to see that the Type-C power supply is able to keep the voltage within 3.25% of nominal even when I am using 12A on the IRDC3894 output (probably around 1.5A from the Type-C)

Measure the Input Current

In the previous article I used the current measurement from the Keithley bench top power supply.  In the setup above I don’t have a way to measure the actual input current.  To fix this put my new Keithley DAQ6510 in series with the IRDC3894 board.  Like this:

Then I step through the 1A-12A load conditions.  Once again the IR3894 provide a very well regulated voltage and current (exactly the same as before so I didn’t write them down)

Here is a table with the data from the previous post (without the Type-C power supply) versus the Type-C power supply.

2230-30-1 Power Supply With 6510 current meter in input path
Vin Iin Win Vout Iout Wout Eff Vin Iin Win Eff-C Loss
12 0.27 3.24 1.198 0 0 0%
12 0.129 1.548 1.198 0.998 1.195604 77% 11.91 0.129 1.53639 77.8% -0.6%
12 0.239 2.868 1.198 1.998 2.393604 83% 11.8 0.242 2.8556 83.8% -0.4%
12 0.345 4.14 1.198 2.998 3.591604 87% 11.7 0.352 4.1184 87.2% -0.5%
12 0.454 5.448 1.198 3.998 4.789604 88% 11.59 0.467 5.41253 88.5% -0.6%
12 0.564 6.768 1.198 4.999 5.988802 88% 11.47 0.586 6.72142 89.1% -0.6%
12 0.677 8.124 1.198 5.998 7.185604 88% 11.36 0.709 8.05424 89.2% -0.8%
12 0.792 9.504 1.198 6.998 8.383604 88% 11.25 0.837 9.41625 89.0% -0.8%
12 0.909 10.908 1.198 7.998 9.581604 88% 11.13 0.97 10.7961 88.8% -0.9%
12 1.029 12.348 1.198 8.998 10.779604 87% 10.95 1.115 12.20925 88.3% -1.0%
12 1.152 13.824 1.198 9.999 11.978802 87% 10.85 1.258 13.6493 87.8% -1.1%
12 1.277 15.324 1.198 10.998 13.175604 86% 10.8 1.401 15.1308 87.1% -1.1%
12 1.406 16.872 1.198 11.997 14.372406 85% 10.68 1.558 16.63944 86.4% -1.2%

These measurements use 1A/3A range on the Keithley DAQ6510 DMM, which means that they have a 100mΩ shunt resistor in series which drops the voltage by V=IR or about 0.1-ish volts.  This explains most of the difference from the Power Supply to the Type-C setup.

It is actually very interesting to look at the data to see the impact of lowering the input voltage on the efficiency of the IR3894.  It appears that at the highest load and lowest input voltage the efficiency is down by 1.2%

Watch the Sunrise

While I was sitting there at my desk thinking about what to do next, I decided that the best thing to do was go sit in my hottub and watch the sunrise on God’s country.

USB C Power Meter Tester

I was hoping to be able to measure the input current and voltage from the Type-C power supply so that I could calculate the efficiency of the CY4533 EZ BCR.  And as a result the efficiency of the whole system.  There wasn’t a place on the Type-C development kit to make these measurements, but the Cypress Apps manager for Type-C – Palani – said I should buy something like this from Amazon.


So I did.  You can plug it into Type-A or Type-C and it will tell you how much V/I are coming out.  In the picture below you can see 20.4v@0.11A

Even better it has a handy-dandy mode where it can display Chinese?

Here is a picture in my actual setup:

And a picture of the whole crazy setup.

Now I step through my 12 load conditions from 1A to 12A and record the V/I from the Fluke and the USB Power Tester.

Here is the data in table form with power and efficiency added.

Type C Power Tester
Vin Iin Win Eff-No Meter
11.99 0.15 1.7985 66.5%
11.95 0.26 3.107 77.0%
11.92 0.36 4.2912 83.7%
11.88 0.48 5.7024 84.0%
11.85 0.59 6.9915 85.7%
11.82 0.7 8.274 86.8%
11.79 0.82 9.6678 86.7%
11.75 0.94 11.045 86.8%
11.71 1.07 12.5297 86.0%
11.68 1.2 14.016 85.5%
11.64 1.33 15.4812 85.1%
11.6 1.46 16.936 84.9%

Next, I plot the new data with the previous two plots.  Obviously, it is screwed up.  I would bet money that the data points at 2A, 4A and 12A are wrong.  But, I don’t think that it is worthwhile to take steps to figure out the real current.  So, I suppose that is what you get from a $19 power meter.

Efficiency of CY4533 EZ-PD BCR

I had really wanted to measure the efficiency of the BCR setup.  To do that I needed to be able to measure the output power (V/I) and the input power (V/I).  Unfortunately the power meter doesn’t seem to be very good… so I suppose that I will have to wait to build my real board where I can install some power jumpers the real numbers.

Cypress Type-C Barrel Connector Replacement + Infineon Buck DC/DC (Part 2)


In this article I will show you how to use a Keithley 2380 (actually two different ones) to test the output of the IRDC3894 12V->1.2V 12A buck development kit.

The Story

To this point I have written several articles about my process of designing a power supply for my new IoT device.  It needs to provide for quite a bit of power, actually 60W is what I am planning on.  I really wanted to make sure that the IR3894 chip would do what it says it would, specifically supply 12A.  The development kit is pretty simple.  There are two banana plug to  provide power to Vin and two banana plus for the load.

For this round of tests I will Keithley 2230-30-1 to provide power and I will use my Keithley 2380-120-60 to serve as the load.

The two mini grabbers are attached to to remote sensing terminals on the Keithley 2380.

After I had it all hooked up I went in 1A increments from 0 to 12A, then I went in 0.1A increments until I ran out of input power.

Here is the actual data table.  Note that I added columns to show the calculated input power.  And I calculated the efficiency of the system Wout/Win

Vin Iin Win Vout Iout W Eff
12 0.27 3.24 1.198 0 0 0%
12 0.129 1.548 1.198 0.998 1.195604 77%
12 0.239 2.868 1.198 1.998 2.393604 83%
12 0.345 4.14 1.198 2.998 3.591604 87%
12 0.454 5.448 1.198 3.998 4.789604 88%
12 0.564 6.768 1.198 4.999 5.988802 88%
12 0.677 8.124 1.198 5.998 7.185604 88%
12 0.792 9.504 1.198 6.998 8.383604 88%
12 0.909 10.908 1.198 7.998 9.581604 88%
12 1.029 12.348 1.198 8.998 10.779604 87%
12 1.152 13.824 1.198 9.999 11.978802 87%
12 1.277 15.324 1.198 10.998 13.175604 86%
12 1.406 16.872 1.198 11.997 14.372406 85%
12 1.42 17.04 1.198 12.098 14.493404 85%
12 1.434 17.208 1.198 12.198 14.613204 85%
12 1.448 17.376 1.198 12.297 14.731806 85%
12 1.462 17.544 1.198 12.398 14.852804 85%
12 1.477 17.724 1.198 12.498 14.972604 84%
12 1.49 17.88 1.198 12.59 15.08282 84%

When I plot the data there is something sticking out like a sore thumb.  WTF?  At first I assume that I typed in the wrong number when I transposed the hand written data to the spreadsheet.  So I went and looked at the data table where it appears that I typed it in correctly.  Does the efficiency really have a peak like that?

I decided to go remeasure the 5A datapoint.

Then I looked at my handwritten data sheet where I find that I transposed the last two digits of the input current. (I definitely should automate this measurement)

OK… now the plot looks way better

When I compare the plot from the data sheet versus my data on the same scale (about) they look very similar.  All seems good.


Stupid Python Tricks: Install MBED-CLI on macOS


This article describes a good set of steps to install the ARM MBED-CLI onto your Mac into a Python Virtual Environment.  You COULD make MBED-CLI work on your Mac a bunch of other/different ways, but, what I describe in this article is the best way.  You could follow the specific ARM instructions here.

The big steps are:

  1. Install Homebrew
  2. Install Python3
  3. Create a Virtual Python Environment
  4. Use PIP to Install MBED-CLI
  5. Download the GCC Compiler
  6. Configure the Compiler
  7. Test

macOS Homebrew & Python3

You need to be able to run Python, and in my opinion, specifically Python 3.  There are problems with doing this, first most of the macOS versions do not have Python 3 built in (and the Python 2 is old).  But, on macOS Catalina, you could use the macOS built-in Python3 and install MBED-CLI into the system libraries.  But, I believe that you should never make changes to the macOS system which could collide with its normal functioning.  I think that the easiest way to get a standalone Python onto your computer is to use “Homebrew” package manager.   Homebrew will enable you to easily install Python3 (and a bunch of other stuff) into /usr/local/bin.

To install Homebrew run:

  • /usr/bin/ruby -e “$(curl -fsSL”

And after a bunch of streaming console messages, it finishes:

Now you can use Homebrew to install python3 into /usr/local/bin by running:

  • brew install python3

And it puts out a bunch of stuff on the console… finally ending like this:

Now you should be able to “which python3” and see that python 3.7.6 is installed.

Create a Virtual Environment and Install mbed-cli

I always use a virtual environment when I run python to insure that all of the packages I install are together.  Run:

Command Comment
mkdir mbed-cli-example Create a directory to hold the virtual environments
cd mbed-cli-example
python3 -m venv venv Create the virtual environment in the directory called "venv"
source venv/bin/activate Activate the virtual environment
pip install mbed-cli Download the Mbed-cli package and install it into the virtual environment

Here is what is looks like:

Once that is done you can run “which mbed” where you will find that the MBED-CLI is in your virtual environment path.  And when you run “mbed” you should see all of the options.

Download the GCC Compiler

In order to actually do something with the MBED-CLI you also need to have an ARM compiler toolchain installed e.g. GCC.  The easiest (best?) way to get this done is download it from this the ARM website here.

After you download the Mac OS X 64-bit Tarball file you will end up with a “…tar.bz2” file in your Downloads directory.  When you double click the file, the finder will unzip and untar the file into a folder with all of the stuff you need for the Mac.

I have a directory on my Mac called ~/proj where I hold all of my “project” stuff.  So after downloading and untaring the file, I move it to my project directory with “mv ~/download/gcc-arm-none-eabi-9-2019-q4-major ~/proj”

Configure the Compiler

The final step is to tell the MBED-CLI where your toolchain is located.  There are a bunch of slightly different variants for how to do this.  BUT I think that the best is to change the mbed global configuration by running:

  • mbed config –global GCC_ARM_PATH ~/proj/gcc-arm-none-eabi-9-2019-q4-major/bin

The “–global” flag will store that configuration variable in the file ~/.mbed/.mbed (notice a directory called .mbed and a file called .mbed)

It took me a while to figure out which directory you should put in the path because there are multiple bin directories in the “gcc-arm…” directory.

If you want to use one of the other toolchains mbed has configuration variables for those as well:

You can also configure these paths with environment variables, but I dont like that.

macOS Gatekeeper

On macOS there is a security infrastructure called Gatekeeper that will prevent you from running applications that Gatekeeper doesn’t know about.  This includes the GCC toolchain (which you just downloaded).  To make it so that you can run the toolchain there are a couple of things you COULD do, but I think that the best thing to do is tell Gatekeeper that the Terminal program is exempt from the Gatekeeper rules.

To do this type the following command into a terminal: “spctl developer-mode enable-terminal”

Then go to the System Preferences –> Security & Privacy –> Developer Tools and check that the “Terminal” is exempt from the Gatekeeper Rules.

You can read more here and here.


To test everything you have done, you should:

Command Comment
mbed import mbed-os-example-blinky Load the example project.  Notice that mbed also will install the Python requirements into your virtual environment.  It does this by running "pip install -r mbed-os/requirements.txt"
cd mbed-os-example-blinky
mbed config target CY8CKIT_062S2_43012 Setup the target (in my case the really cool P6 43012 devout)
mbed config toolchain GCC_ARM Set the toolchain to the one we setup in the previous step
mbed detect See if mbed can detect the development kit… it can

Here is what it looks like:

You can now run the compiler (with the -f option to program).  It should start up and barf out the compile messages.

Eventually it ends… then programs the development kit

The last thing to do is turn off the virtual environment

Which can later be turned back on with “source venv/bin/activate”