Skip navigation
Home > All Places > ModusToolbox > Blog
1 2 3 Previous Next

ModusToolbox

33 posts

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.

 

project-creator-cli.exe

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...

super-manifest: https://github.com/cypresssemiconductorco/mtb-super-manifest/raw/v2.X/mtb-super-manifest.xml

Successfully acquired BSP/Application information from remote server.

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

mtb-example-psoc6-capsense-buttons-slider

mtb-example-psoc6-capsense-buttons-slider-freertos

mtb-example-psoc6-crypto-aes

mtb-example-psoc6-crypto-sha

mtb-example-psoc6-crypto-trng

mtb-example-psoc6-empty-app

mtb-example-psoc6-emulated-eeprom

mtb-example-psoc6-emwin-eink

mtb-example-psoc6-emwin-oled

mtb-example-psoc6-fault-handling

mtb-example-psoc6-gpio-interrupt

mtb-example-psoc6-hello-world

mtb-example-psoc6-i2c-master

mtb-example-psoc6-i2c-master-ezi2c-slave

mtb-example-psoc6-i2c-slave-callback

mtb-example-psoc6-i2s

mtb-example-psoc6-mcwdt

mtb-example-psoc6-pdm-pcm

mtb-example-psoc6-pdm-to-i2s

mtb-example-psoc6-qspi-readwrite

mtb-example-psoc6-qspi-readwrite-sfdp

mtb-example-psoc6-rtc-basics

mtb-example-psoc6-smartio-ramping-led

mtb-example-psoc6-spi-master

mtb-example-psoc6-spi-master-dma

mtb-example-psoc6-switching-power-modes

mtb-example-psoc6-tcpwm-square-wave

mtb-example-psoc6-uart-transmit-receive

mtb-example-psoc6-uart-transmit-receive-dma

mtb-example-psoc6-usb-hid

mtb-example-psoc6-wdt

 

Nice! This is a convenient way to see the examples without trawling around https://github.com/cypresssemiconductorco. 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...

super-manifest: https://github.com/cypresssemiconductorco/mtb-super-manifest/raw/v2.X/mtb-super-manifest.xml

Successfully acquired BSP/Application information from remote server.

 

 

==============================================================================

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

==============================================================================

Cloning https://github.com/cypresssemiconductorco/mtb-example-psoc6-tcpwm-square-wave 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 1.0.0.55

 

 

==============================================================================

= 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.

 

project-creator.exe

 

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).

project-creator-1.png

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

project-creator-2.png

Now pick your kit.

project-creator-3.png

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

project-creator-4.png

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.

Last time out we got hello world running on the PROTO-062-4343W kit. That was a lot of fun for me… because I have that kit! Actually, I have about 20 of them because they arrived too late for the training event last week. But most of you don’t have 20 kits so, today, I am going to show you how to re-target an application to another kit.

 

All ModusToolbox applications have a BSP. It is the thing that defines the PSoC device, the memory layout, the connection to the Wi-Fi device over SDIO, the CapSense buttons and sliders, the I2C and UART peripherals, and the mechanical buttons and LEDs. We give these things standard names, like CYBSP_USER_LED, so that applications using those names can run on just about any kit even if the physical pins connected to the LED are different. So, to re-target our application we only have to do two things; add a new BSP to the project and tell the build tools to use it instead of the original BSP. Some examples actually include more than one BSP, for convenience, so you can often skip the first step!

 

I’ve been writing about CY8CPROTO-063-BLE kit recently (github.com/cypresssemiconductorco/TARGET_CY8CPROTO-063-BLE) so let’s switch our program to that one. You can read about the BSP on the GitHub site or you can just get on with it and download the thing (as you can tell, I’m a type-first, read-later guy). Just jump into the libs folder and clone the BSP.

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ cd libs

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world/libs

$ git clone https://github.com/cypresssemiconductorco/TARGET_CY8CPROTO-063-BLE

Cloning into 'TARGET_CY8CPROTO-063-BLE'...

remote: Enumerating objects: 156, done.

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

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

Receiving objectsremote: Total 156 (delta 43), reused 153 (delta 43), pack-reused 0:   % (85/

Receiving objects: 100% (156/156), 391.77 KiB | 1.42 MiB/s, done.

Resolving deltas: 100% (43/43), done.

Checking out files: 100% (135/135), done.

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world/libs

$ ls -la

total 34

drwxr-xr-x 1 yfs 1049089  0 Nov 4 09:24 .

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:24 ..

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:12 capsense

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:12 core-lib

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:12 psoc6cm0p

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:13 psoc6hal

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:13 psoc6make

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:14 psoc6pdl

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:12 retarget-io

-rw-r--r-- 1 yfs 1049089 67 Nov  1 15:40 retarget-io.lib

drwxr-xr-x 1 yfs 1049089  0 Nov 1 16:12 TARGET_CY8CPROTO-062-4343W

-rw-r--r-- 1 yfs 1049089 82 Nov  1 15:40 TARGET_CY8CPROTO-062-4343W.lib

drwxr-xr-x 1 yfs 1049089  0 Nov 4 09:24 TARGET_CY8CPROTO-063-BLE

 

As you can see, you have added a new TARGET folder. Great, now let’s build for it. I can almost feel you gearing up for a stream of edit-this and move-that with a little bit of delete-the-other and a frustrating time. Not exactly, just add the name of the target to the build command.

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world/libs

$ cd ..

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ make build TARGET=CY8CPROTO-063-BLE

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

 

Initializing build: mtb-example-psoc6-hello-world Debug CY8CPROTO-063-BLE GCC_ARM

    Stale device files detected. Running device configurator to regenerate files...

 

Auto-discovery in progress...

-> Found 158 .c file(s)

-> Found 36 .S file(s)

-> Found 18 .s file(s)

-> Found 0 .cpp file(s)

-> Found 0 .o file(s)

-> Found 4 .a file(s)

-> Found 377 .h file(s)

-> Found 0 .hpp file(s)

-> Found 0 resource file(s)

Applying filters...

Auto-discovery complete

 

==============================================================================

= Building application =

==============================================================================

Building 142 file(s)

    Compiling app file startup_psoc6_01_cm4.S

    Compiling app file cy_syslib_gcc.S

    Compiling app file cycfg.c

    Compiling app file cycfg_clocks.c

    Compiling app file cycfg_peripherals.c

    Compiling app file cycfg_pins.c

    Compiling app file cycfg_routing.c

    Compiling app file cycfg_system.c

    Compiling app file cybsp.c

    Compiling app file system_psoc6_cm4.c

    Compiling app file cy_capsense_centroid.c

    Compiling app file cy_capsense_control.c

    Compiling app file cy_capsense_csd.c

    Compiling app file cy_capsense_csx.c

    Compiling app file cy_capsense_filter.c

    Compiling app file cy_capsense_processing.c

    Compiling app file cy_capsense_sensing.c

    Compiling app file cy_capsense_structure.c

    Compiling app file cy_capsense_tuner.c

    Compiling app file psoc6_01_cm0p_sleep.c

    Compiling app file psoc6_02_cm0p_sleep.c

    Compiling app file psoc6_03_cm0p_sleep.c

    Compiling app file cyhal_adc.c

    Compiling app file cyhal_analog_common.c

    Compiling app file cyhal_crc.c

    Compiling app file cyhal_crypto_common.c

    Compiling app file cyhal_dac.c

    Compiling app file cyhal_flash.c

    Compiling app file cyhal_gpio.c

    Compiling app file cyhal_hwmgr.c

    Compiling app file cyhal_i2c.c

    Compiling app file cyhal_interconnect.c

    Compiling app file cyhal_lptimer.c

    Compiling app file cyhal_not_implemented.c

    Compiling app file cyhal_pwm.c

    Compiling app file cyhal_qspi.c

    Compiling app file cyhal_rtc.c

    Compiling app file cyhal_scb_common.c

    Compiling app file cyhal_sdhc.c

    Compiling app file cyhal_spi.c

    Compiling app file cyhal_system.c

    Compiling app file cyhal_tcpwm_common.c

    Compiling app file cyhal_timer.c

    Compiling app file cyhal_trng.c

    Compiling app file cyhal_uart.c

    Compiling app file cyhal_udb_sdio.c

    Compiling app file cyhal_usb_dev.c

    Compiling app file cyhal_utils.c

    Compiling app file cyhal_wdt.c

    Compiling app file cyhal_psoc6_01_104_m_csp_ble.c

    Compiling app file cyhal_psoc6_01_104_m_csp_ble_usb.c

    Compiling app file cyhal_psoc6_01_116_bga_ble.c

    Compiling app file cyhal_psoc6_01_116_bga_usb.c

    Compiling app file cyhal_psoc6_01_124_bga.c

    Compiling app file cyhal_psoc6_01_124_bga_sip.c

    Compiling app file cyhal_psoc6_01_43_smt.c

    Compiling app file cyhal_psoc6_01_68_qfn_ble.c

    Compiling app file cyhal_psoc6_01_80_wlcsp.c

    Compiling app file cyhal_psoc6_02_100_wlcsp.c

    Compiling app file cyhal_psoc6_02_124_bga.c

    Compiling app file cyhal_psoc6_02_128_tqfp.c

    Compiling app file cyhal_psoc6_02_68_qfn.c

    Compiling app file cyhal_psoc6_03_100_tqfp.c

    Compiling app file cyhal_psoc6_03_49_wlcsp.c

    Compiling app file cyhal_psoc6_03_68_qfn.c

    Compiling app file cy_ble_clk.c

    Compiling app file cy_canfd.c

    Compiling app file cy_crypto.c

    Compiling app file cy_crypto_core_aes_v1.c

    Compiling app file cy_crypto_core_aes_v2.c

    Compiling app file cy_crypto_core_cmac_v1.c

    Compiling app file cy_crypto_core_cmac_v2.c

    Compiling app file cy_crypto_core_crc_v1.c

    Compiling app file cy_crypto_core_crc_v2.c

    Compiling app file cy_crypto_core_des_v1.c

    Compiling app file cy_crypto_core_des_v2.c

    Compiling app file cy_crypto_core_ecc_domain_params.c

    Compiling app file cy_crypto_core_ecc_ecdsa.c

    Compiling app file cy_crypto_core_ecc_key_gen.c

    Compiling app file cy_crypto_core_ecc_nist_p.c

    Compiling app file cy_crypto_core_hmac_v1.c

    Compiling app file cy_crypto_core_hmac_v2.c

    Compiling app file cy_crypto_core_hw.c

    Compiling app file cy_crypto_core_hw_v1.c

    Compiling app file cy_crypto_core_mem_v1.c

    Compiling app file cy_crypto_core_mem_v2.c

    Compiling app file cy_crypto_core_prng_v1.c

    Compiling app file cy_crypto_core_prng_v2.c

    Compiling app file cy_crypto_core_rsa.c

    Compiling app file cy_crypto_core_sha_v1.c

    Compiling app file cy_crypto_core_sha_v2.c

    Compiling app file cy_crypto_core_trng_v1.c

    Compiling app file cy_crypto_core_trng_v2.c

    Compiling app file cy_crypto_core_vu.c

    Compiling app file cy_crypto_server.c

    Compiling app file cy_csd.c

    Compiling app file cy_ctb.c

    Compiling app file cy_ctdac.c

    Compiling app file cy_device.c

    Compiling app file cy_dma.c

    Compiling app file cy_dmac.c

    Compiling app file cy_efuse.c

    Compiling app file cy_flash.c

    Compiling app file cy_gpio.c

    Compiling app file cy_i2s.c

    Compiling app file cy_ipc_drv.c

    Compiling app file cy_ipc_pipe.c

    Compiling app file cy_ipc_sema.c

    Compiling app file cy_lpcomp.c

    Compiling app file cy_lvd.c

    Compiling app file cy_mcwdt.c

    Compiling app file cy_pdm_pcm.c

    Compiling app file cy_profile.c

    Compiling app file cy_prot.c

    Compiling app file cy_rtc.c

    Compiling app file cy_sar.c

    Compiling app file cy_scb_common.c

    Compiling app file cy_scb_ezi2c.c

    Compiling app file cy_scb_i2c.c

    Compiling app file cy_scb_spi.c

    Compiling app file cy_scb_uart.c

    Compiling app file cy_sd_host.c

    Compiling app file cy_seglcd.c

    Compiling app file cy_smartio.c

    Compiling app file cy_smif.c

    Compiling app file cy_smif_memslot.c

    Compiling app file cy_sysanalog.c

    Compiling app file cy_sysclk.c

    Compiling app file cy_sysint.c

    Compiling app file cy_syslib.c

    Compiling app file cy_syspm.c

    Compiling app file cy_systick.c

    Compiling app file cy_tcpwm_counter.c

    Compiling app file cy_tcpwm_pwm.c

    Compiling app file cy_tcpwm_quaddec.c

    Compiling app file cy_trigmux.c

    Compiling app file cy_usbfs_dev_drv.c

    Compiling app file cy_usbfs_dev_drv_io.c

    Compiling app file cy_usbfs_dev_drv_io_dma.c

    Compiling app file cy_wdt.c

    Compiling app file cy_retarget_io.c

    Compiling app file main.c

    Linking output file mtb-example-psoc6-hello-world.elf

==============================================================================

= Build complete =

==============================================================================

 

Calculating memory consumption: CYBLE-416045-02 GCC_ARM -Og

 

   --------------------------------------------------

  | Section Name         |  Address |  Size     |

--------------------------------------------------

  | .cy_m0p_image        |  0x10000000 |  5328     |

  | .text                |  0x10002000 |  36180    |

  | .ARM.exidx           |  0x1000ad54 |  8        |

  | .copy.table          |  0x1000ad5c |  24       |

  | .zero.table          |  0x1000ad74 |  8        |

  | .data                |  0x0800228c |  1892     |

  | .cy_sharedmem        |  0x080029f0 |  12       |

  | .noinit              |  0x08002a00 |  148      |

  | .bss                 |  0x08002a94 |  976      |

  | .heap                |  0x08002e68 |  276888   |

--------------------------------------------------

 

  Total Internal Flash (Available) 1048576

  Total Internal Flash (Utilized)           46324

 

  Total Internal SRAM (Available) 292864

  Total Internal SRAM (Utilized) 279916

 

Now you can just run ”make qprogram” and hello world will run just the same way as it did on the original kit. That was cool, let’s do it again!

 

When you type as haphazardly as I do, that extra text at the end of the command is just asking for a typo. So I need a more permanent solution. It’s easy to do… just open the Makefile in a text editor, look for the line “TARGET=CY8CPROTO-062-4343W” and change the name of the board to CY8CPROTO-063-BLE, like this.

 

################################################################################

# Basic Configuration

################################################################################

 

# Target board/hardware

# TARGET=CY8CPROTO-062-4343W

TARGET=CY8CPROTO-063-BLE

 

Now you can build and program your kit in one step with the almost-impossible-to-mistype command “make program”. You’ll never guess how to go back to the other kit!

OK, that’s enough typing for me. Next time I’ll show off the new GUI tools we have created to automate all this make shenanigans.

Well, I did not get a visit from any of the VPs I was being rude about yesterday, so I can start showing you some of the ways to do cool projects with ModusToolbox. I usually dive straight into the IDE for things like this but I have lots of options with ModusToolbox so I will start with a simple command-line example instead. This will demonstrate the four fundamental steps involved in making a program.

  1. Clone a starter project from GitHub
  2. Pull down all the required libraries - startup code, board support, CapSense and so on
  3. Build
  4. Program

If you have installed ModusToolbox 2.0 already, then you can follow all these steps (only step 4 requires a kit). If you have not installed ModusToolbox… what the heck are you waiting for???

ModusToolbox includes a convenient "modus-shell", which is just a cygwin DLL with the path set up for the make and compiler executables. I start that by running cygwin.bat from the ModusToolbox\tools_2.0\modus-shell folder. That launches the shell in your home directory.

Clone a Project

All the ModusToolbox firmware is distributed as libraries in the cypresssemiconductorco repo on GitHub (yes, there are three consecutive 's' in there!). To get started you just have to clone an example from that site. As is traditional, I picked "hello world", and it takes just a few seconds to download.

yfs@YFS-T550 ~

$ mkdir MyFirstProject

 

yfs@YFS-T550 ~

$ cd MyFirstProject

 

yfs@YFS-T550 ~/MyFirstProject

$ git clone https://github.com/cypresssemiconductorco/mtb-example-psoc6-hello-world

Cloning into 'mtb-example-psoc6-hello-world'...

remote: Enumerating objects: 15, done.

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

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

remote: Total 15 (delta 0), reused 12 (delta 0), pack-reused 0

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

 

yfs@YFS-T550 ~/MyFirstProject

$ cd mtb-example-psoc6-hello-world

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ ls -la

total 64

drwxr-xr-x 1 yfs 1049089     0 Nov 1 15:40 .

drwxr-xr-x 1 yfs 1049089     0 Nov 1 15:40 ..

drwxr-xr-x 1 yfs 1049089     0 Nov 1 15:40 .git

drwxr-xr-x 1 yfs 1049089     0 Nov 1 15:40 images

drwxr-xr-x 1 yfs 1049089     0 Nov 1 15:40 libs

-rw-r--r-- 1 yfs 1049089 12443 Nov  1 15:40 LICENSE

-rw-r--r-- 1 yfs 1049089 10161 Nov  1 15:40 main.c

-rw-r--r-- 1 yfs 1049089  5207 Nov 1 15:40 Makefile

-rw-r--r-- 1 yfs 1049089 17480 Nov  1 15:40 README.md

 

What do you get? Well, there’s main.c and a Makefile, which is pretty much the whole application for “hello world”! Then there is README.md, which is a markdown file that tells you all about the application. You can read that file as plain text or open it in a markdown viewer. When you do that the document is nicely formatted and includes the pictures in the “images” folder. Then is also a LICENSE file, of course, and a “.git” folder, which contains all the clever stuff to support updating and pushing and pulling and cloning and tickling and tweaking and, oh you know, all that git stuff.

Pull in Libraries

The most interesting folder, though, is “libs”. Take a peak in there and you’ll see two files with the extension “.lib” (in this example). These files contain a hash of the GitHub repos and branch for all the extra firmware needed by the application. We use a make rule “getlibs” to pull in those libraries.

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ ls -la libs

total 6

drwxr-xr-x 1 yfs 1049089 0 Nov  1 15:40 .

drwxr-xr-x 1 yfs 1049089 0 Nov  1 15:40 ..

-rw-r--r-- 1 yfs 1049089 67 Nov 1 15:40 retarget-io.lib

-rw-r--r-- 1 yfs 1049089 82 Nov 1 15:40 TARGET_CY8CPROTO-062-4343W.lib

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ make getlibs

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

 

Initializing import: mtb-example-psoc6-hello-world

 

==============================================================================

= 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/MyFirstProject/mtb-example-psoc6-hello-world/libs/retarget-io.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W.lib

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

Found 8 file(s)

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/capsense.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/core-lib.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6cm0p.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6hal.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6make.lib

    Processing file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/libs/TARGET_CY8CPROTO-062-4343W/libs/psoc6pdl.lib

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

Found 8 file(s)

libs directory search complete.

 

==============================================================================

= Import complete =

==============================================================================

 

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ ls -la libs

total 46

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:13 .

drwxr-xr-x 1 yfs 1049089 0 Nov  1 15:40 ..

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:12 capsense

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:12 core-lib

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:12 psoc6cm0p

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:13 psoc6hal

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:13 psoc6make

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:14 psoc6pdl

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:12 retarget-io

-rw-r--r-- 1 yfs 1049089 67 Nov 1 15:40 retarget-io.lib

drwxr-xr-x 1 yfs 1049089 0 Nov  1 16:12 TARGET_CY8CPROTO-062-4343W

-rw-r--r-- 1 yfs 1049089 82 Nov 1 15:40 TARGET_CY8CPROTO-062-4343W.lib

 

When you look at the libs folder now you have all the Board and Chip support firmware in TARGET_CY8CPROTO-062-4343W and the retarget-io library to enable STDIO output to printf(). Note that the TARGET library, which is known as the BSP, automatically pulls in other libraries that it depends up; core-lib, psoc6hal, psoc6pdl and so on.

Build

So now we have used make to complete the application. The cool part is that we can also use make to update the library versions, or add more, or remove one that you no longer want. The next step is to see if it works… it’s really complicated. Not really, just type “make build”.

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ make build

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

 

Initializing build: mtb-example-psoc6-hello-world Debug CY8CPROTO-062-4343W GCC_ARM

 

Auto-discovery in progress...

-> Found 150 .c file(s)

-> Found 34 .S file(s)

-> Found 16 .s file(s)

-> Found 0 .cpp file(s)

-> Found 0 .o file(s)

-> Found 4 .a file(s)

-> Found 367 .h file(s)

-> Found 0 .hpp file(s)

-> Found 0 resource file(s)

Applying filters...

Auto-discovery complete

 

==============================================================================

= Building application =

==============================================================================

Building 144 file(s)

    Compiling app file startup_psoc6_02_cm4.S

    Compiling app file cy_syslib_gcc.S

    Compiling app file cycfg.c

    Compiling app file cycfg_capsense.c

    Compiling app file cycfg_clocks.c

    Compiling app file cycfg_peripherals.c

    Compiling app file cycfg_pins.c

    Compiling app file cycfg_qspi_memslot.c

    Compiling app file cycfg_routing.c

    Compiling app file cycfg_system.c

    Compiling app file cybsp.c

    Compiling app file system_psoc6_cm4.c

    Compiling app file cy_capsense_centroid.c

    Compiling app file cy_capsense_control.c

    Compiling app file cy_capsense_csd.c

    Compiling app file cy_capsense_csx.c

    Compiling app file cy_capsense_filter.c

    Compiling app file cy_capsense_processing.c

    Compiling app file cy_capsense_sensing.c

    Compiling app file cy_capsense_structure.c

    Compiling app file cy_capsense_tuner.c

    Compiling app file psoc6_01_cm0p_sleep.c

    Compiling app file psoc6_02_cm0p_sleep.c

    Compiling app file psoc6_03_cm0p_sleep.c

    Compiling app file cyhal_adc.c

    Compiling app file cyhal_analog_common.c

    Compiling app file cyhal_crc.c

    Compiling app file cyhal_crypto_common.c

    Compiling app file cyhal_dac.c

    Compiling app file cyhal_flash.c

    Compiling app file cyhal_gpio.c

    Compiling app file cyhal_hwmgr.c

    Compiling app file cyhal_i2c.c

    Compiling app file cyhal_interconnect.c

    Compiling app file cyhal_lptimer.c

    Compiling app file cyhal_not_implemented.c

    Compiling app file cyhal_pwm.c

    Compiling app file cyhal_qspi.c

    Compiling app file cyhal_rtc.c

    Compiling app file cyhal_scb_common.c

    Compiling app file cyhal_sdhc.c

    Compiling app file cyhal_spi.c

    Compiling app file cyhal_system.c

    Compiling app file cyhal_tcpwm_common.c

    Compiling app file cyhal_timer.c

    Compiling app file cyhal_trng.c

    Compiling app file cyhal_uart.c

    Compiling app file cyhal_udb_sdio.c

    Compiling app file cyhal_usb_dev.c

    Compiling app file cyhal_utils.c

    Compiling app file cyhal_wdt.c

    Compiling app file cyhal_psoc6_01_104_m_csp_ble.c

    Compiling app file cyhal_psoc6_01_104_m_csp_ble_usb.c

    Compiling app file cyhal_psoc6_01_116_bga_ble.c

    Compiling app file cyhal_psoc6_01_116_bga_usb.c

    Compiling app file cyhal_psoc6_01_124_bga.c

    Compiling app file cyhal_psoc6_01_124_bga_sip.c

    Compiling app file cyhal_psoc6_01_43_smt.c

    Compiling app file cyhal_psoc6_01_68_qfn_ble.c

    Compiling app file cyhal_psoc6_01_80_wlcsp.c

    Compiling app file cyhal_psoc6_02_100_wlcsp.c

    Compiling app file cyhal_psoc6_02_124_bga.c

    Compiling app file cyhal_psoc6_02_128_tqfp.c

    Compiling app file cyhal_psoc6_02_68_qfn.c

    Compiling app file cyhal_psoc6_03_100_tqfp.c

    Compiling app file cyhal_psoc6_03_49_wlcsp.c

    Compiling app file cyhal_psoc6_03_68_qfn.c

    Compiling app file cy_ble_clk.c

    Compiling app file cy_canfd.c

    Compiling app file cy_crypto.c

    Compiling app file cy_crypto_core_aes_v1.c

    Compiling app file cy_crypto_core_aes_v2.c

    Compiling app file cy_crypto_core_cmac_v1.c

    Compiling app file cy_crypto_core_cmac_v2.c

    Compiling app file cy_crypto_core_crc_v1.c

    Compiling app file cy_crypto_core_crc_v2.c

    Compiling app file cy_crypto_core_des_v1.c

    Compiling app file cy_crypto_core_des_v2.c

    Compiling app file cy_crypto_core_ecc_domain_params.c

    Compiling app file cy_crypto_core_ecc_ecdsa.c

    Compiling app file cy_crypto_core_ecc_key_gen.c

    Compiling app file cy_crypto_core_ecc_nist_p.c

    Compiling app file cy_crypto_core_hmac_v1.c

    Compiling app file cy_crypto_core_hmac_v2.c

    Compiling app file cy_crypto_core_hw.c

    Compiling app file cy_crypto_core_hw_v1.c

    Compiling app file cy_crypto_core_mem_v1.c

    Compiling app file cy_crypto_core_mem_v2.c

    Compiling app file cy_crypto_core_prng_v1.c

    Compiling app file cy_crypto_core_prng_v2.c

    Compiling app file cy_crypto_core_rsa.c

    Compiling app file cy_crypto_core_sha_v1.c

    Compiling app file cy_crypto_core_sha_v2.c

    Compiling app file cy_crypto_core_trng_v1.c

    Compiling app file cy_crypto_core_trng_v2.c

    Compiling app file cy_crypto_core_vu.c

    Compiling app file cy_crypto_server.c

    Compiling app file cy_csd.c

    Compiling app file cy_ctb.c

    Compiling app file cy_ctdac.c

    Compiling app file cy_device.c

    Compiling app file cy_dma.c

    Compiling app file cy_dmac.c

    Compiling app file cy_efuse.c

    Compiling app file cy_flash.c

    Compiling app file cy_gpio.c

    Compiling app file cy_i2s.c

    Compiling app file cy_ipc_drv.c

    Compiling app file cy_ipc_pipe.c

    Compiling app file cy_ipc_sema.c

    Compiling app file cy_lpcomp.c

    Compiling app file cy_lvd.c

    Compiling app file cy_mcwdt.c

    Compiling app file cy_pdm_pcm.c

    Compiling app file cy_profile.c

    Compiling app file cy_prot.c

    Compiling app file cy_rtc.c

    Compiling app file cy_sar.c

    Compiling app file cy_scb_common.c

    Compiling app file cy_scb_ezi2c.c

    Compiling app file cy_scb_i2c.c

    Compiling app file cy_scb_spi.c

    Compiling app file cy_scb_uart.c

    Compiling app file cy_sd_host.c

    Compiling app file cy_seglcd.c

    Compiling app file cy_smartio.c

    Compiling app file cy_smif.c

    Compiling app file cy_smif_memslot.c

    Compiling app file cy_sysanalog.c

    Compiling app file cy_sysclk.c

    Compiling app file cy_sysint.c

    Compiling app file cy_syslib.c

    Compiling app file cy_syspm.c

    Compiling app file cy_systick.c

    Compiling app file cy_tcpwm_counter.c

    Compiling app file cy_tcpwm_pwm.c

    Compiling app file cy_tcpwm_quaddec.c

    Compiling app file cy_trigmux.c

    Compiling app file cy_usbfs_dev_drv.c

    Compiling app file cy_usbfs_dev_drv_io.c

    Compiling app file cy_usbfs_dev_drv_io_dma.c

    Compiling app file cy_wdt.c

    Compiling app file cy_retarget_io.c

    Compiling app file main.c

    Linking output file mtb-example-psoc6-hello-world.elf

==============================================================================

= Build complete =

==============================================================================

 

Calculating memory consumption: CY8C624ABZI-D44 GCC_ARM -Og

 

--------------------------------------------------

  | Section Name         |  Address |  Size     |

--------------------------------------------------

  | .cy_m0p_image        |  0x10000000 |  5068     |

  | .text                |  0x10002000 |  37276    |

  | .ARM.exidx           |  0x1000b19c |  8        |

  | .copy.table          |  0x1000b1a4 |  24       |

  | .zero.table          |  0x1000b1bc |  8        |

  | .data                |  0x080022e0 |  1888     |

  | .cy_sharedmem        | 0x08002a40   |  8 |

  | .noinit              |  0x08002a48 |  148      |

  | .bss                 |  0x08002adc |  996      |

  | .heap                |  0x08002ec0 |  1030464  |

--------------------------------------------------

 

  Total Internal Flash (Available) 2097152

  Total Internal Flash (Utilized)           47412

 

  Total Internal SRAM (Available) 1046528

  Total Internal SRAM (Utilized) 1033504

 

Program

The last step is obviously to program the kit. Plug a CY8CPROTO-062-4343W kit into the USB port and give your computer a few moments to install the drivers for it. Then open a serial terminal like PuTTY or TeraTerm and set them up for the “KitProg3 USB-UART COMxx” port in the Windows Device Manager. The baud rate is 115200.

If you do not have that kit… don’t worry, next time I’ll show you how easy it is to switch applications onto different kits.

To program the kit just type “make program”. This will check that the build is up to date (and build again if necessary) and then download the program using the CMSIS-DAP protocol to the board. If you are super impatient, like me, then you can use “make qprogram” instead and that is quicker (hence the ‘q’) because it skips the build check.

yfs@YFS-T550 ~/MyFirstProject/mtb-example-psoc6-hello-world

$ make program

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

 

Initializing build: mtb-example-psoc6-hello-world Debug CY8CPROTO-062-4343W GCC_ARM

 

Auto-discovery in progress...

-> Found 150 .c file(s)

-> Found 34 .S file(s)

-> Found 16 .s file(s)

-> Found 0 .cpp file(s)

-> Found 0 .o file(s)

-> Found 4 .a file(s)

-> Found 367 .h file(s)

-> Found 0 .hpp file(s)

-> Found 0 resource file(s)

Applying filters...

Auto-discovery complete

 

==============================================================================

= Building application =

==============================================================================

Building 144 file(s)

==============================================================================

= Build complete =

==============================================================================

 

Calculating memory consumption: CY8C624ABZI-D44 GCC_ARM -Og

 

--------------------------------------------------

  | Section Name         |  Address |  Size     |

   --------------------------------------------------

  | .cy_m0p_image        |  0x10000000 |  5068     |

  | .text                |  0x10002000 |  37276    |

  | .ARM.exidx           |  0x1000b19c |  8        |

  | .copy.table          |  0x1000b1a4 |  24       |

  | .zero.table          |  0x1000b1bc |  8        |

  | .data                |  0x080022e0 |  1888     |

  | .cy_sharedmem        |  0x08002a40 |  8        |

  | .noinit              |  0x08002a48 |  148      |

  | .bss                 |  0x08002adc |  996      |

  | .heap                |  0x08002ec0 |  1030464  |

--------------------------------------------------

 

  Total Internal Flash (Available) 2097152

  Total Internal Flash (Utilized)           47412

 

  Total Internal SRAM (Available) 1046528

  Total Internal SRAM (Utilized) 1033504

 

Programming target device...

Open On-Chip Debugger 0.10.0+dev-2.2.0.249 (2019-09-10-10:57)

Licensed under GNU GPL v2

For bug reports, read

http://openocd.org/doc/doxygen/bugs.html

adapter speed: 1500 kHz

adapter speed: 1000 kHz

** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable

cortex_m reset_config sysresetreq

cortex_m reset_config vectreset

Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 6105 bytes)

Warn : SFlash programming allowed for regions: USER, TOC, KEY

Info : CMSIS-DAP: SWD  Supported

Info : CMSIS-DAP: FW Version = 2.0.0

Info : CMSIS-DAP: Interface Initialised (SWD)

Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1

Info : CMSIS-DAP: Interface ready

Info : VTarget = 3.332 V

Info : kitprog3: acquiring PSoC device...

Info : clock speed 1000 kHz

Info : SWD DPIDR 0x6ba02477

Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints

Info : psoc6.cpu.cm0: external reset detected

***************************************

** Silicon: 0xE402, Family: 0x102, Rev.: 0x11 (A0)

** Detected Device: CY8C624ABZI-S2D44A0

** Detected Main Flash size, kb: 2048

** Flash Boot version 3.1.0.45

** Chip Protection: NORMAL

***************************************

Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints

Info : psoc6.cpu.cm4: external reset detected

Info : Listening on port 3333 for gdb connections

Info : Listening on port 3334 for gdb connections

Warn : Only resetting the Cortex-M core, use a reset-init event handler to reset any peripherals or configure hardware srst support.

Info : kitprog3: acquiring PSoC device...

target halted due to debug-request, current mode: Thread

xPSR: 0x41000000 pc: 0x00000190 msp: 0x080ff800

** Device acquired successfully

** psoc6.cpu.cm4: Ran after reset and before halt...

target halted due to debug-request, current mode: Thread

xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800

** Programming Started **

auto erase enabled

Info : Flash write discontinued at 0x100013cc, next section at 0x10002000

Info : Padding image section 0 at 0x100013cc with 52 bytes (bank write end alignment)

[100%] [################################] [ Erasing     ]

[100%] [################################] [ Programming ]

Info : Padding image section 1 at 0x1000b92c with 212 bytes (bank write end alignment)

[100%] [################################] [ Erasing     ]

[100%] [################################] [ Programming ]

wrote 44544 bytes from file C:/Users/yfs/MyFirstProject/mtb-example-psoc6-hello-world/build/CY8CPROTO-062-4343W/Debug/mtb-example-psoc6-hello-world.hex in 5.370537s (8.100 KiB/s)

** Programming Finished **

** Verify Started **

verified 44280 bytes in 0.267027s (161.939 KiB/s)

** Verified OK **

** Resetting Target **

Warn : Only resetting the Cortex-M core, use a reset-init event handler to reset any peripherals or configure hardware srst support.

shutdown command invoked

 

You should see the red LED blinking at about 1Hz. That’s just way too slow for me and it drives me nuts - I always open main.c in an editor and speed that up! In the terminal emulator you should see this. You can turn the LED blinking on and off by pressing the Enter key.

My First ModusToolbox 2_0 Design PuTTY.png

 

Congratulations! If you followed along then you just created, built, and programmed your first ModusToolbox application.

Oh my stars, it has been a week since we released ModusToolbox 2.0! I thought I'd be getting some down time after the release but, as usual, things did not really go that way. Instead of taking a break we decided to give all the San Jose vice presidents a crash course in all things ModusToolbox. This was a group of sales guys, marketeers, and business unit managers, with not a single engineer among them... what could possibly go wrong?

Alan Hawse (who else!) was hosting the day but he missed his plane from Kentucky. We had no course materials. The kits we wanted to use for lab sessions arrived two days late. And, worst of all, we found that all VPs share one common skill - the ability to mess up software installations. It was a hectic day but, by the end of it all, these guys...

ModusToolbox training SJ.jpeg

... got our motley collection of non-programmers writing programs using every customer development flow that we could think of...

  • Mbed CLI
  • Mbed Online Compiler
  • Mbed Studio
  • ModusToolbox IDE
  • Visual Studio Code
  • And from the command-line

And we were not just building blinky. When you get a group of VPs at your mercy... it would be wrong not to torture them with a little C and C++ programming ("I wrote Pascal in college and waaa waaa waaa"). So we had them writing to TFT displays, connecting to Wi-Fi networks, polling NTP servers, and pulling all that together to create a PSoC-based alarm clock. In one day.

I think this is a testament to the design goal of ModusToolbox. We wanted to create a set of tools and libraries that are so flexible and interchangeable that we can support bare metal or RTOS-based applications; running in our own ecosystems or partner platforms like Mbed and Amazon FreeRTOS; using our IDE, a partner IDE, or no IDE at all; and building with the compiler of your choice. I think we crushed that objective, so 'Chapeau' to all the 226 engineers that have worked on the project!

Another good thing to come from that crazy day was that I now have a good set of starter projects and use cases that I can blog about and get everyone excited and up to speed with the new tools. Watch this space...

 

 

 

 

 

 

 

 

 

 

 

Over the weekend we released a major upgrade to ModusToolbox. The 2.0 software improves the development experience for PSoC 6 and Bluetooth SoC applications as well as being available in the Mbed OS and Amazon FreeRTOS ecosystems.

 

A big addition to all flows is the Cypress HAL (Hardware Abstraction Layer), which is a device-agnostic driver API. It simplifies the code you write for simple peripheral operation and, best of all, allows us to build middleware libraries that can be used in any flow you choose... from deeply embedded industrial control all the way across to wireless IoT applications. With a standardized HAL, all Cypress middleware - the good stuff like CapSense, MagSense and Bluetooth - will work the same way, and just as reliably, on all of our devices and in all your ecosystems. Our middleware roadmap for 2020 is really exciting!

 

ModusToolbox 2.0 also completes our commitment to distributing firmware through the web. ALL firmware libraries, including examples, are hosted on github so we can push out updates as soon as they are ready. It also means you can have a good old-fashioned rummage around the source code without downloading gigabytes of development tools.

 

Oh yeah! That reminds me... our firmware is now completely IDE-agnostic so you can use whatever tools you like. We obsessively test our firmware on the Arm, IAR and GNU compiler tool chains and our build recipes require no proprietary format conversion or mysterious merge utilities.

 

Interested? Of course you are! Now get over here and do some downloading.

Here's another interesting post from Matt Mielke, over at Digi-Key. It's actually two posts and, together, they describe how to set up the PSoC 6 PDM-PCM converter in the ModusToolbox Device Configurator.

The first article takes you through the PDM-PCM configuration process. I like how it breaks everything down into logical steps. It's well worth a read. Go on! Off you go. I'll still be here when you get back.

Oh, you're back already. I thought it was particularly interesting how Matt identifies, and provides a workaround, for an error in the Device Configurator. The PDM-PCM conversion requires a fast, accurate clock source and that comes from the PSoC External Crystal Oscillator (ECO). In ModusToolbox 1.1 the ECO frequency range is erroneously limited to between 4MHz and 33MHz. The error check exists to prevent users from inadvertently trying to generate frequencies that the ECO block cannot handle. Unfortunately, we got the upper limit wrong - it is too conservative. Matt's workaround is great but I wanted to let everyone know that we have already fixed the problem in our upcoming 2.0 release, which sets the upper limit at 35MHz.

Here is a pic of the configurator tool from the 1.1 release, showing the erroneous error check. You won't get that problem in our 2.0 software. Happy sampling!

Setting the ECO input frequency in ModusToolbox Device Configurator

It is time to take the final step in our week-long BLE adverture. Hopefully you have a working peripheral already. You should be able to send messages from your phone and have it send messages to you. OK, it's just a find me application and battery monitor right now, but those two things tell you a lot of what you need to know to make bigger, more interesting peripherals. Our last task is to make sure your device only talks to the right people. That process is called pairing and we shall control that with a passkey.

We shall start this job in familiar territory - the BLE Configurator. Switch the view to the GAP Settings and look at "Security configuration 0". Note that more complex peripherals can implement multiple configurations but we are only making one.

Change the Security level to "Authenticated pairing with encryption". The authentication means that the pairing requires a passkey. The IO Capability should be "Display" which means the peripheral has a way for presenting a passkey to the user. In our case that is the terminal and we will write a little code to print the key. Some peripherals do not have a display and so the authentication process has to done differently - for example, the passkey can be sent to, and displayed on, the phone instead and the a simple button can be used to accept the number on the peripheral. The last edit is for Binding, which should be set to "No Bond". In real-world applications you alnmost always bond, to the point that pairing and bonding are often considered to be synonyms. Strictly, bonding is just the storage of pairing information in non-volatile memory which enables bonded phones and devices to automatically recognize each other and connect without a passkey. We are not going to bond because it's a lot easy to learn about piring without the need to force your phone and peripheral to forget each other all the time. Let's get good at pairing first!

Setting up security in the ModusToolbox BLE Configurator

Saving the configurator edits, we need to add four events to our stack_handler() function.

  • CY_BLE_EVT_GAP_AUTH_REQ occurs when the phone asks to initiate pairing. The peripheral responds by sending back the authentication method(s) that it can support (in our case this means "display").
  • CY_BLE_EVT_GAP_PASSKEY_DISPLAY_REQUEST means the central wants the peripheral to display the passkey. The phone asks the user to enter the value (6-digit code with leading zeros).
  • CY_BLE_EVT_GAP_AUTH_COMPLETE means that the phone has sent the user's passkey and it matched the displayed value.
  • CY_BLE_EVT_GAP_AUTH_FAILED means the value entered was wrong, or the user waited too long, or some other reason for not allowing pairing.

Here is the code to handle those events. Just add it into the switch statement in stack_handler().

/* Include stdio.h at the top of main.c */

#include "stdio.h"

...

char passkey_str[50]; /* Put the string declaration at the top of stack_handler() */

...

case CY_BLE_EVT_GAP_AUTH_REQ:
    Cy_SCB_UART_PutString( KIT_UART_HW, "Authenticating\r\n" );
    /* Send the authentication settings set by the BLE Configurator - GAP Settings */
    Cy_BLE_GAPP_AuthReqReply( &cy_ble_config.authInfo[CY_BLE_SECURITY_CONFIGURATION_0_INDEX] );
break;

case CY_BLE_EVT_GAP_PASSKEY_DISPLAY_REQUEST:
    sprintf( passkey_str, "Passkey requested\tKey = %06ld\r\n", ( (cy_stc_ble_gap_auth_pk_info_t*)eventParam )->passkey );
    Cy_SCB_UART_PutString( KIT_UART_HW, passkey_str );
break;

case CY_BLE_EVT_GAP_AUTH_COMPLETE:
    Cy_SCB_UART_PutString( KIT_UART_HW, "Authentication complete\r\n" );
break;

case CY_BLE_EVT_GAP_AUTH_FAILED:
    Cy_SCB_UART_PutString( KIT_UART_HW, "Authentication fail\r\n" );
break;

As you can see, there is not a lot to it. The stack does the hard part of communicating with the phone and deciding whether to pair. The call to Cy_BLE_GAPP_AuthReqReply() takes an argument that is in the generated code from the BLE Configurator. The variable cy_ble_config is a big struct containing all the user selections from that tool. The authInfo member contains the information we just provided in an array of one element (CY_BLE_SECURITY_CONFIGURATION_0_INDEX is the only element in that array because we only have one configuration). So, sending that information up to the phone is all that is required to tell it to pop up a passkey request dialog.

CySmart prompting for a passkey

Of course, we have to print the passkey to give the user a chance to guess right! That happens in the CY_BLE_EVT_GAP_PASSKEY_DISPLAY_REQUEST event. The stack generates a random number and passes it into the event handler in the eventParam argument.

When you build and program the application, you should connect to it as normal. When you try to open the Battery service the CySmart app should automatically pop up the passkey request, as above. Note that the Android version of the app does this as soon as you connect but the iPhone version waits for you to do something that requires the peripheral to respond. On the iPhone, then, you can send an Immediate Alert before pairing and, while the phone says it was sent (it was) the peripheral ignores the message (and the LED does not light). Everything is working correctly in both cases, because you need to have completed pairing before either service will be honored by the peripheral.

Here is the terminal output for a session where I got the password wrong. There is no code to enable a re-try so you need to disconnect and reconnect on order to try again. When I got it right I could send and receive messages with the usual wild abandon! When you play with this, remember to include any leading zeros when entering the passkey - you must enter all 6 digits.

PSoC BLE Peripheral output

So that's the full set of BLE exercises. I hope you followed along and had some fun with it. We have a large array of examples of how to take this further and I have attached a template for you to recreate exactly what I have done here. To use the template download and unzip it, then open the New Application dialog, select the prototyping kit, then use the "Import..." button to open the modus.mk file in the BLE_proj folder.

Happy Blootoothing!!!

If you followed along with yesterday's blog, you should have a working BLE peripheral today. You should be able to send commands from your phone to the peripheral with wild abandon. It's good to be the King! Today we are going to turn things around and send messages from the peripheral to the phone.

Before we jump in, though, you may have noticed that the CySmart App has a tendency to remember a little too much about the connected peripheral. You program in a new application but the app keeps showing the old configuration. For example, you might have struggled to get the FindMe profile to appear when you connect. In today's example we are going to add another profile so it's a good time to give you a "clear your cache" tip. CySmart remembers the peripheral name and ID after a connection. As a result it thinks it knows that the device can do... but it has changed. To force it to refresh, go to your BLE settings on the phone and clear/delete the device. If the device is not there (exact behavior depends upon the phone and OS version) just give BLE the good old off-n-on treatment. On my phone I just swipe the wee green slider widget left, and then right again, and I am good to go.

OK, so let's add the Battery service to our phone. Things start out the same way as they did yesterday. Open the Configurator and add a "Battery" service in the "Server", alongside the Immediate Alert. Then click on the "Battery Level" characteristic and make a couple of edits. For value, write "100", which corresponds to a full battery (it is a percentage). The check the "Notify" box. That last edit is the cunning part...

ModusToolbox BLE Configurator setting up a Battery service

Save your changes and go back to editing main.c. The reason why this checkbox is important is that it enables the peripheral to update the phone without the phone expressly asking for the battery level. Woooo-hoooo! We are going to write a few lines of code that run when you press the button on the kit. That code will check that there is a connection, read the current battery level, decrement it, write the value back to the GATT database, and then tell the phone what happened.

Start by creating a global to hold the connection information. We need this because BLE supports multiple connections and it is important to only send messages to the right phone. When the transferred data is bit more important that the battery level, this becomes a big deal!

static cy_stc_ble_conn_handle_t conn_handle;

Next, we need to set the variable on a connection and clear it upon disconnect. Yes, you are right, I am being a little bit lazy by not maintaining an array of handles. But my application only supports one connection at a time. And I am really lazy person. So deal with it! Here's the code in stack_handler() - notice how the eventParam for the connection event is the handle itself.

  case CY_BLE_EVT_GATT_CONNECT_IND:
    Cy_SCB_UART_PutString( KIT_UART_HW, "Connected\r\n" );
    conn_handle = *(cy_stc_ble_conn_handle_t *)eventParam;
  break;

  case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED:
    Cy_SCB_UART_PutString( KIT_UART_HW, "Disconnected\r\n" );
    Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );
    alert( CY_BLE_NO_ALERT );
    conn_handle.attId = 0;
    conn_handle.bdHandle = 0;
  break;

Just like the Immediate Alert, we should have an attribute change handler. All mine does is print the state of the notification attribute.

void BAS_handler( uint32_t event, void* eventParam )
{
  Cy_SCB_UART_PutString( KIT_UART_HW, "Notification " );
  Cy_SCB_UART_PutString( KIT_UART_HW, ( CY_BLE_EVT_BASS_NOTIFICATION_ENABLED == event ) ? "on\r\n" : "off\r\n" );
}

 

Register the handler in the same way as before, in main().

 

  Cy_BLE_RegisterEventCallback( stack_handler );

  Cy_BLE_IAS_RegisterAttrCallback( IAS_handler );

  Cy_BLE_BAS_RegisterAttrCallback( BAS_handler );

 

One last thing before playtime. Update the button_isr() function to update the GATT and notify the phone.

  1. Check for a valid connection with Cy_BLE_GetConnectionState()
  2. Read the current battery level from GATT with Cy_BLE_BASS_GetCharacteristicValue() - note that the function takes a size and a pointer argument for the data to be read
  3. Simulate a depleting battery by decrementing the level (and wrap back to 100 should you press the button 100 times)
  4. Write the new level to the database
  5. Read the notify characteristic from GATT with Cy_BLE_BASS_SetCharacteristicValue()
  6. If it is set then push a message up to the phone with Cy_BLE_BASS_SendNotification()

Here is the code to do that. Add it after you clear the interrupt. It's a little daunting the first time but I think that the function names become obvious pretty quickly and you soon get the hang of the defines for the service index and characteristics.

 

  if( Cy_BLE_GetConnectionState( conn_handle ) == CY_BLE_CONN_STATE_CONNECTED )
  {
    uint8_t battery_level;
    uint8_t notify;

    /* Read the current battery level from GATT */
    Cy_BLE_BASS_GetCharacteristicValue( CY_BLE_BATTERY_SERVICE_INDEX, CY_BLE_BAS_BATTERY_LEVEL, sizeof( battery_level ), &battery_level );

    /* Decrement the level */
    battery_level--;
    if( battery_level == (uint8_t)(-1) )
      battery_level = 100;

    /* Write the new level back to GATT */
    Cy_BLE_BASS_SetCharacteristicValue( CY_BLE_BATTERY_SERVICE_INDEX, CY_BLE_BAS_BATTERY_LEVEL, sizeof( battery_level ), &battery_level );

    /* Is notification enabled? If yes, tell the central */
    Cy_BLE_BASS_GetCharacteristicDescriptor( conn_handle, CY_BLE_BATTERY_SERVICE_INDEX, CY_BLE_BAS_BATTERY_LEVEL, CY_BLE_BAS_BATTERY_LEVEL_CCCD, sizeof( notify ), &notify );

    if( notify )
      Cy_BLE_BASS_SendNotification( conn_handle, CY_BLE_BATTERY_SERVICE_INDEX, CY_BLE_BAS_BATTERY_LEVEL, sizeof( battery_level ), &battery_level );
  }

 

Done typing? Good, program that bad boy!

 

When you connect now, you should see a third profile - Battery Service. It shows a full battery (because we set the value to 100 in the Configurator). And there are two buttons - Read and Notify. If you press Read it looks like nothing happens because it is just reading the same value every time. Press the button on the kit and read again... it should come back with 99. Now press the notify button and repeatedly hit that kit button. Watch as the battery level steadily decreases... you can go all the way down to zero and wrap around if you wish. In fact I know you will. You cannot stop yourself!

CySmart Battery service

Well done - you have now created a peripheral device that can send and receive messages. Pretty cool no? But there is the slight problem that any Tom, Disk or Harry can make a connection. Tomorrow, I'll wrap up this series of blogs by adding a passkey to control the pairing of phone and device. As before, the updated main.c file is attached.

Did you get your kit to connect? Could you connect and reconnect? Was it cool? Are you ready to make your device actually DO SOMETHING? Good idea - let's go!

Well, hang on a second, before we add a FindMe profile to the device I have one final thought on connections... if you ever find that you cannot connect from CySmart until you reset the kit it is probably because you were not quick enough. The default length of time that the device will advertise rapidly is 30s. After that it advertises at a far slower rate for 150s until giving up entirely to save power. The expectation is that the device would implement a wakeup feature to restart advertising rather than just burning power advertising while nothing is listening. If this annoys you just go into the GAP Settings in the BLE Configurator and, in the Advertising settings section, increase the "Fast advertising timeout" value. The other solution to this problem is to be johnny on the spot and not wander off for a coffee and a donut every time you press the program button. Not judgin'. Just sayin'.

The FindMe profile is a Bluetooth SIG-defined application that is implemented by the Immediate Alert service. It's one of the simplest profiles and all it does is let a client send a single value to a GATT server. We are going to use it to light LEDs corresponding to the value sent from the central. Legal values are 0 (no alert), 1 (mild alert), and 2 (high alert). Did I mention that it is simple? All we need to do to make this work is to configure the GATT database with the service, write a handler for when an alert event happens (meaning you send a message from your phone), and a function to write messages and light LEDs, which we will call from the handler.

In the BLE Configurator, go to the GATT Settings tab. Notice that the GATT server already contains the mandatory Generic Access (GAP) , which contains the name you gave your device yesterday, and Generic Access services.

ModusToolbox BLE Configurator showing the GAP profile in the GATT database

Now let's add the service. You can do this in two ways - add the profile or just the service. For Find Me, which we are going to use, this is basically the same thing. But in more complex applications you might add an alert service to a different profile to increase it's functionality. The profile method is to select the "GATT" heading and click the green '+' button. From the menu choose "Find Me" and the "Find Me Target (GATT Server)". The easier way is to select "Server" instead of "GATT". Then choose "Immediate Alert" noting that the client or server choice is implicit. Do NOT choose the "Alert Notification" service. That is a far richer service, that you will be welcome to try once you have mastered the simple alert. Easy there, Tiger!!!

The service gets added to the GATT database and you can choose "No Alert" as the initial condition. It seems like a good idea to start the device in a nice relaxed state, doesn't it? Note that the service enables write but not read - it will not let the phone ask for the level.

ModusToolbox BLE Configurator showing the Find Me profile in the GATT database

Let's save those edits and write a little code in main.c. Let's start with a function to set the LEDs based on the alert level.

void alert( uint8_t level )
{
  Cy_SCB_UART_PutString( KIT_UART_HW, "Alert " );

  switch( level )
  {
    case CY_BLE_NO_ALERT: /* Both LEDs off */
      Cy_SCB_UART_PutString( KIT_UART_HW, "OFF\r\n" );
      Cy_GPIO_Set( KIT_LED1_PORT, KIT_LED1_PIN );
      Cy_GPIO_Set( KIT_LED2_PORT, KIT_LED2_PIN );
    break;

    case CY_BLE_MILD_ALERT: /* LED1 off, LED2 on */
      Cy_SCB_UART_PutString( KIT_UART_HW, "MILD\r\n" );
      Cy_GPIO_Set( KIT_LED1_PORT, KIT_LED1_PIN );
      Cy_GPIO_Clr( KIT_LED2_PORT, KIT_LED2_PIN );
    break;

    case CY_BLE_HIGH_ALERT: /* LED1 on, LED2 off */
      Cy_SCB_UART_PutString( KIT_UART_HW, "HIGH\r\n" );
      Cy_GPIO_Clr( KIT_LED1_PORT, KIT_LED1_PIN );
      Cy_GPIO_Set( KIT_LED2_PORT, KIT_LED2_PIN );
    break;

    default: /* Both LEDs on - should never occur */
      Cy_SCB_UART_PutString( KIT_UART_HW, "ERROR\r\n" );
      Cy_GPIO_Clr( KIT_LED1_PORT, KIT_LED1_PIN );
      Cy_GPIO_Clr( KIT_LED2_PORT, KIT_LED2_PIN );
    break;
  }
}

OK, now we need a handler. Here is the code for that. Note that, like stack_handler(), it takes an event and a parameter argument. Our code checks the event is a write to the alert characteristic so we do not do something silly if the phone is just reading the value (although we did not give it read access anyway - this is belt-and-braces safe programming). It then extracts the value into a local variable and calls the alert() function. Note that you do not need to write the value into the database - that has already been done for you by the stack.

void IAS_handler( uint32_t event, void* eventParam )
{
  uint8_t alertLevel;

  /* Alert Level Characteristic write event */
  if( event == CY_BLE_EVT_IASS_WRITE_CHAR_CMD )
  {
    /* Read the updated Alert Level value from the GATT database */
    Cy_BLE_IASS_GetCharacteristicValue( CY_BLE_IAS_ALERT_LEVEL, sizeof( alertLevel ), &alertLevel );

    alert( alertLevel );
  }
}

We are nearly done now. We have to register the handler with the stack - just like we did with stack_handler() - and that is done in main().

Cy_BLE_RegisterEventCallback( stack_handler );

Cy_BLE_IAS_RegisterAttrCallback( IAS_handler );

 

Finally, we should make sure that the alert does not out-live the connection. Call the alert() function on a disconnect event in stack_handler(), like this.

 

case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED:
   Cy_SCB_UART_PutString( KIT_UART_HW, "Disconnected\r\n" );
   Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );

   alert( CY_BLE_NO_ALERT );
break;

Program that into the device and connect via CySmart. Instead of "No Services" you will see the GATT database (which is a way to access all services) and the Find Me profile (which presents a profile-specific interface.

CySmart profiles

Swipe to the Find Me profile and use the button to change the alert level.

CySmart Find Me profile interface

It should change the state of the LEDs and print useful messages to the terminal. Notice how the alert gets set to OFF when I disconnected.

Terminal emulator output

I have attached the C code again (as a zip) to help you cut-and-paste into your own project. Next time, we'll add a battery service, which will send messages in the other direction.. letting the phone know that the state of the peripheral has changed.

Today, I am going to start the BLE part of this series of blogs. To do that I am going to configure my GATT database, include the BLE libraries, then launch the stack and start advertising so I can connect to the kit from my phone. If that sounds daunting... it's really not. The ModusToolbox software and tools make it all very simple. Just follow the instructions and you'll be a BLE wizard faster than it takes a UK politician to jump off the Brexit bandwagon.

Start by downloading the template I created yesterday (attached) and following the instructions at the end of that blog to create a new project. Your project should look like this.

ModusToolbox IDE project files

Double-click on the "design.modus" file to open the Device Configurator. You can also click on the "Configure Device" button in the Quick Panel - your choice. In the peripherals tab check the box labeled "Bluetooth Low energy (BLE)" then look to the right-hand panel and press "Launch Bluetooth Configurator". The tool will pop up a dialog asking you to accept the change you just made and, once you accept, will gray out the device Configurator and launch the BLE Configurator (it is not safe to allow edits in both tools at the same time).

Launching the ModusToolbox BLE Configurator

This GUI has a set of tabs and we are going to use the first three. The L2CAP and Link Layer settings are not necessary for the simple, straightforward applications we are going to write. In the General tab you will see that the default GAP role is "Peripheral". That is what we want because we are going to build a peripheral device that acts as a GATT server to a phone (called the central in BLE parlance). We do not need any edits here, and we'll cover GATT tomorrow, so move onto the GAP Settings tab.

ModusToolbox BLE Configurator - General tab

GAP stands for Generic Access Profile. It controls how your device appears to the outside world and determines how two devices can (or can't) interact. In the general section choose a silicon-generated address (it will be unique to your kit) and give it a name (I almost always call my devices "bunty"... it's a long story so, not today).

ModusToolbox BLE Configurator - GAP Settings tab

In this application we are going to advertise our name to the world and invite connections. Advertising is when the device periodically emits a single, small packet (maximum of 31 bytes) so that a listening central can detect it and make a connection. Switch to the Advertisement Packet and check "Enable Local Name". Notice how your device name gets added to the packet on the right of the window. The packet contains two items - 2 bytes of required flags (which just tell the central "I'm connectable")  and, now, your device name. If you make the name too long the packet will get too big and the tool will tell you off!

ModusToolbox BLE Configurator - GAP Settings tab

Advertising infrequently is one way that BLE conserves power because the peripheral radio is off most of the time. You can set some rules for how long and how often to advertise in the Advertisement Settings section but the defaults will be OK for us. That's all we need to do right now. Save the edits by pressing the big blue button (if you are under 600 years old, that's a floppy disk... my Mom told me about them) and switch back to the ModusToolbox IDE.

Now we need to add a wee bit of middleware for the BLE. Click on the cunningly-named "Select Middleware" button in the Quick Panel. In the dialog that pops up, select two items:

  • BLE Base
  • BLE single-core mode, controller and host on CM4 only, soft FP prebuilt library

ModusToolbox Middleware SelectorThe Base is the low-level stack (including that L2CAP and Link Layer stuff we are pretending does not exist). That second one is quite a mouthful but it's just the upper layer of the stack that will be calling the event handlers we are going to write over the next few days. Press OK and the middleware gets added to your project in the "psoc6sw-1.1" folder. All we need now is some application code.Add these include files so the compiler finds the generated source files from the BLE Configurator tool and the libraries we added.

 

#include "cy_ble_gatt.h"
#include "cycfg_ble.h"

 

In main(), add this initialization code after the button ISR setup. What does it do?

  • Installs the BLE interrupt handler with a very high priority (note that the handler is from the middleware, not your code)
  • Registers your stack event handler for stack events (we will add more tomorrow)
  • Initializes and enables the BLE hardware
  • Calls the event processing function in a forever loop (this is a little lkazt because I really should go to sleep and wait for interrupts.... shhhhhh, don't tell)

 

const cy_stc_sysint_t ble_intr_config = { bless_interrupt_IRQn, ISR_PRIORITY_HIGH };
Cy_SysInt_Init( &ble_intr_config, Cy_BLE_BlessIsrHandler );
NVIC_EnableIRQ(  ble_intr_config.intrSrc );
Cy_BLE_RegisterEventCallback( stack_handler );

/* Initialize and start BLE */
Cy_BLE_Init( &cy_ble_config );
Cy_BLE_Enable();
__enable_irq();

for( ; ; )
{
    Cy_BLE_ProcessEvents();
}

 

When BLE is operating the stack generates events that can be handled (or ignored) in the event handlers that you set up. The handlers are (indirectly) called from the Cy_BLE_ProcessEvents() function. Our handler will deal with connection and disconnection events. This is the last bit of code we need to write today.

 

void stack_handler( uint32_t event, void* eventParam )
{
    switch( event )
    {
        case CY_BLE_EVT_STACK_ON:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Stack on\r\n" );
            Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );
        break;

 

        case CY_BLE_EVT_GATT_CONNECT_IND:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Connected\r\n" );
        break;

 

        case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Disconnected\r\n" );
            Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );
        break;

 

        default:
            /* Ignore the event */
        break;
    }
}

 

Looking at the code you can see that there are three interesting events and we are printing out messages to the terminal for each one.

  • CY_BLE_EVT_STACK_ON means the stack is up and running so we turn on advertising (in fast mode) for configuration 0. You may have noticed that we made changes in the BLE Configurator for "Peripheral Configuration 0" - BLE peripherals can support multiple configurations, but we are not going that deep today.
  • CY_BLE_EVT_GATT_CONNECT_IND means a connection from a central has occurred.
  • CY_BLE_EVT_GAP_DEVICE_DISCONNECTED means... wait for it... the phone disconnected and so we re-start advertising. if we forget that part then the device will not allow another connection (until you press reset).

OK, let's run this. pres the "BLE_proj Program (KitProg3)" button and watch the compiler work it;s magic, and program the kit.

Install CySmart on your phone. It is in the App store and Google Play. Open it and refresh the screen to see your device name. EXCITING!!!

CySmart showing BLE connections

Press on the name and it will connect and show you... not very much, just "No services"! Of course not, we have not enabled any functionality yet. That's for tomorrow, when I will show you how to get the peripheral to respond to alert message from your phone.

      CySmart connected to a peripheral with no services enabled

I attached the template and also a copy of the C file (main.c) as a zip file to this blog.

I recently got volunteered to take some internal engineers through the process of creating a Bluetooth LE peripheral using ModusToolbox. I figured I should share the learning with you because it's been a while since I wrote about making PSoC do interesting things. Who knows, maybe I'll make another robot dog one day? Preferably one that does not run away or spin around like it's got rabies, and that I can control without getting off the couch. Priorities...

The goal was to empower our engineers to be able to make their own BLE designs and I hope it can do the same for you. Each step adds a little more understanding; from advertising and making connections, to sending alert messages from the phone, to receiving battery notifications from the device, and setting up rudimentary security (so engineers can't misbehave in class!!!). This is a hands-on, get up-and-running quick exercise, folks, and it's going to be up to you to take the next steps once I have covered the basics!

I decided to use a CY8CPROTO-063-PROTO kit because it is small and inexpensive, but any kit with a PSoC 63 MCU device would work without much modification (just use different pins). For example, there is the CY8CKIT-062-BLE, which is an Arduino form-factor alternative to the prototyping kit. Note, however, that the other "062" kits, such as CY8CKIT-062-WiFi-BT, use a PSoC 62 MCU, which does not have BLE on-chip. Those kits couple the PSoC MCU to a 43xxx connectivity device, which is supported by a different API.

On my kit, I used the two LEDs, the user button, and a UART to write across the KitProg3 bridge to my PC terminal emulator (TeraTerm or PuTTY). Knowing that I would create many projects during the development of this material I wanted to build a template so I would not have to keep re-creating the same setup. To do that I began with the "EmptyPSoC6App" project template, targeting the CY8CPROTO kit.

Repeating the configuration steps from previous blogs (Starter Templates for ModusToolbox and Customizing your PSoC configuration (buttons and LEDs)) I opened the Device Configurator and made the following edits.

  1. Enabled pin P6[3] with the alias "KIT_LED1" and drive mode "Strong Drive, Input buffer off".
  2. Repeated that task for P7[1] and called it "KIT_LED2".
  3. Enabled pin P0[4] to support the user button, calling it "KIT_BTN1", set to "Resistive Pull-Up, Input buffer on", and with an interrupt triggered of a "Falling Edge".
  4. Finally, I enabled SCB[5] to use the UART-1.0 personality, called it "KIT_UART", with a baud rate of 115200.

For the UART connections I chose "8-bit divider 0" and let the tool figure out the divider value to get the baud rate right (handy!). Lastly I chose P5[0] and P5[1] for the RX and TX pins.

Configuring the PSoC UART for 115200 baud, with P5[0] and P5[1] as RX and TX

The tool gave me a couple of "fix-it tickets" at this step - asking me to set the drive modes for those pins. Another handy feature of the Configurator is that it will make those changes for you by clicking on the wrench (aka "spanner") icons in the Notice List.

Fix-it tickets for the UART configuration - just click on the wrench to set up the drive modes for the UART pins

Once I had everything set up I saved it, switched back to the IDE, and wrote a little code to test things out. In main() I turned on the UART, installed the button ISR, and set one LED on and the other off.

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

  /* Turn on the UART */
  Cy_SCB_UART_Init( KIT_UART_HW, &KIT_UART_config, &KIT_UART_context );
  Cy_SCB_UART_Enable( KIT_UART_HW );
  Cy_SCB_UART_PutString( KIT_UART_HW, "\r\n\n*** Application Started ***\r\n" );

  /* Turn on the button interrupt */
  const cy_stc_sysint_t button_intr_config = { KIT_BTN1_IRQ, ISR_PRIORITY_LOW };
  Cy_SysInt_Init( &button_intr_config, button_isr );
  NVIC_EnableIRQ(  button_intr_config.intrSrc );

  /* Turn one LED on and one off */
  Cy_GPIO_Set( KIT_LED1_PORT, KIT_LED1_PIN );
  Cy_GPIO_Clr( KIT_LED2_PORT, KIT_LED2_PIN );

  __enable_irq();

  for(;;)
  {
  }

}

Then I added an ISR to do some fairly simple stuff when I press the button.

void button_isr( void )
{
  /* Clear the interrupt */
  Cy_GPIO_ClearInterrupt( KIT_BTN1_PORT, KIT_BTN1_PIN );
  NVIC_ClearPendingIRQ( KIT_BTN1_IRQ );

  /* Toggle both the LEDs */
  Cy_GPIO_Inv( KIT_LED1_PORT, KIT_LED1_PIN );
  Cy_GPIO_Inv( KIT_LED2_PORT, KIT_LED2_PIN );

  /* Print a friendly message */
  Cy_SCB_UART_PutString( KIT_UART_HW, "Button pressed\r\n" );
}

When I programmed the kit it behaved perfectly (after 15 bone-headed iterations that I'll not discuss!) - pressing the button swaps the LEDs and prints the nice message. I have a good start point for adding BLE!

Now I want to turn this project into a template. I created a new folder and copied across three files - design.modus, modus.mk, and main.c (in the Source folder). I edited modus.mk to make it more friendly as a template with these settings:

CY_EXAMPLE_NAME = BLE_proj

CY_EXAMPLE_DESCRIPTION = Useful start point for BLE designs on the CY8CPROTO-063-BLE kit.

CY_APP_CM4_SOURCE = \

Source/main.c

Finally, I trimmed back the main.c file to remove some of the test code from above. I did not want to have to delete it every time! Specifically, I removed the LED toggling and UART printing code from the ISR as well as the LED set/clr calls in main().

With this template, that I have attached to this blog (remember that you need to log in to get it), I am ready to dive into BLE development. Before then, here are instructions on creating projects with the template.

Unpack the attached files into your workspace folder (or anywhere convenient).

1. Click on New Application from the Quick Panel

Creating a new project in ModusToolbox IDE

2. Select CY8CPROTO-063-BLE as the target kit and press Next.

Selecting the target kit in ModusToolbox IDE

3. Click on Import.. then navigate to the template folder and choose modus.mk.

4. Check that the dialog updates with the template information and press Next.

Selecting a custom project template in ModusToolbox

5. Verify the selections in the final view and press Finish to create the project.

In my next blog I'll start our BLE adventure by launching the stack and advertising to my phone!

Our friend, Matt Mielke at Dig-Key, just wrote a really good blog about using CMSIS-DSP on PSoC 6. It is one of those really good articles that just gets on with the job of describing the subject without a load of unnecessary, showy-offy acronyms and buzzwords. I really liked it and recommend you give it a read. Unless you really like slow math in your programs. Ok, then... good luck with that.

I liked that it methodically explains what the library does and how it helps, uses the CMSIS-PACK plug-in that ships with ModusToolbox to install the library, then adds it to the project and sets the include path up. In case you have never seen it, here is an image showing the Pack Manager after the library has been installed - it is a great way to install libraries and keep them up to date.

CMSIS Pack Manager installing CMSIS-DSP in ModusToolbox

I only thought of one thing I would add to the article. Matt explains the difference between hardfp and softfp libraries, and points out that you cannot mix-and-match them. But I'd also add that you need to remember that when choosing other middleware for your application. Here is a picture of the ModusToolbox Middleware Selector... notice the CapSense and Segger emWin entries that list a Hard FP and Soft FP implementation... you need to make sure all those match your DSP library selection.

Hard and Soft FP libraries in ModusToolbox Middleware Selector

Did you finish reading it yet? Good, wasn't it?

MarkS_11

Mbed OS 5.13.1 released

Posted by MarkS_11 Jul 18, 2019

Arm announced a patch release of Mbed OS yesterday. It is version 5.13.1 and it adds a few interesting items for PSoC users. The big change is a new Wi-Fi Host Driver (WHD), which replaces the monolithic build of our WICED stack used in previous releases with a smaller footprint, more flexible driver that will save memory in your applications and make it easier to support your own target boards. There is also a USB peripheral driver, which extends the choices you have for wired connectivity, and a new Cypress HAL that complements the C++ Mbed peripheral driver interface with an efficient, Mbed-friendly set of drivers in the C language. Lovely!

One of the nice things about an online ecosystem like Mbed is that you do not need to go through a lengthy installation process to get the new software. Simply creating a new application in Mbed CLI ("mbed new my-super-new-application") will pull in the latest and greatest version of Mbed OS. You can then confirm the OS version by running "mbed ls". Here is the output from my Mbed CLI session where I create and build a new application.

yfs@YFS-T550 MINGW64 ~/mbed4

$ mbed new my-super-new-application

[mbed] Working path "C:\Users\yfs\mbed4" (directory)

[mbed] Program path "C:\Users\yfs\mbed4"

[mbed] Creating new program "my-super-new-application" (git)

[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at branch/tag "latest"

[mbed] Updating reference "mbed-os" -> "https://github.com/ARMmbed/mbed-os/#5941d1718339116cd12914238ec331c84da3..."

yfs@YFS-T550 MINGW64 ~/mbed4

$ cd my-super-new-application

yfs@YFS-T550 MINGW64 ~/mbed4/my-super-new-application (master)

$ mbed ls

[mbed] Working path "C:\Users\yfs\mbed4\my-super-new-application" (program)

my-super-new-application ( revision in the current branch)

`- mbed-os (#5941d1718339, tags: latest, mbed-os-5.13.1)

yfs@YFS-T550 MINGW64 ~/mbed4/my-super-new-application (master)

$ cp ../main.cpp .

yfs@YFS-T550 MINGW64 ~/mbed4/my-super-new-application (master)

$ mbed compile --target CY8CKIT_062_WIFI_BT --toolchain GCC_ARM

Building project my-super-new-application (CY8CKIT_062_WIFI_BT, GCC_ARM)

Scan: my-super-new-application

Compile [  0.1%]: mbed_tz_context.c

Compile [  0.2%]: MCR20Drv.c

Compile [  0.3%]: at24mac.cpp

Compile [  0.4%]: NanostackRfPhyAtmel.cpp

Compile [  0.5%]: NanostackRfPhyMcr20a.cpp

Compile [  0.6%]: rf_configuration.c

Compile [  0.7%]: fslittle_test.c

Compile [  0.8%]: main.cpp

<Lots of compilation - deleted!>

Compile [ 99.7%]: USBSerial.cpp

Compile [ 99.8%]: OperationListBase.cpp

Compile [ 99.9%]: PolledQueue.cpp

Compile [100.0%]: TaskBase.cpp

Link: my-super-new-application

Elf2Bin: my-super-new-application

Post-Build: my-super-new-application

| Module           |         .text |       .data |        .bss |

|------------------|---------------|-------------|-------------|

| [fill]           |       80(+80) |       9(+9) |     35(+35) |

| [lib]\c.a        | 16696(+16696) | 2472(+2472) |     89(+89) |

| [lib]\gcc.a      |   3168(+3168) |       0(+0) |       0(+0) |

| [lib]\misc       |     224(+224) |       4(+4) |     28(+28) |

| [misc]           |         0(+0) |       0(+0) |       0(+0) |

| main.o           |     192(+192) |       0(+0) |       4(+4) |

| mbed-os\drivers  |       74(+74) |       0(+0) |       0(+0) |

| mbed-os\features |     204(+204) |       0(+0) |     48(+48) |

| mbed-os\hal      |   1248(+1248) |       4(+4) |     67(+67) |

| mbed-os\platform |   2892(+2892) |   260(+260) |   220(+220) |

| mbed-os\rtos     |   6468(+6468) |   168(+168) | 5973(+5973) |

| mbed-os\targets  | 17578(+17578) |   107(+107) | 1236(+1236) |

| Subtotals        | 48824(+48824) | 3024(+3024) | 7700(+7700) |

Total Static RAM memory (data + bss): 10724(+10724) bytes

Total Flash memory (text + data): 51848(+51848) bytes

Image: .\BUILD\CY8CKIT_062_WIFI_BT\GCC_ARM\my-super-new-application.hex

[mbed] Working path "C:\Users\yfs\mbed4\my-super-new-application" (program)

 

Note that, after creating the application, I I just copy in a simple blinky application (main.cpp) to the my-super-new-application folder. Here is the code for that... isn't it super!?!

 

/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*/

#include "mbed.h"

DigitalOut led1(LED1);

#define SLEEP_TIME_MS 500

// main() runs in its own thread in the OS
int main()
{
    while( true )
    {
        // Blink LED and wait 0.5 seconds
        led1 = !led1;
        wait_ms( SLEEP_TIME_MS );
    }

}

MarkS_11

Task-Aware Debugging

Posted by MarkS_11 Jun 30, 2019

I was asked a question last week about multi-threaded debugging in ModusToolbox IDE. I knew there was a plug-in for that but I had never used it. So I gave it a shot and here's how you can enable task-aware debugging with the FreeRTOS kernel.

It turns out that you do not need to install the plug-in - it is already there - but you do need to enable it for OpenOCD. I did that in the file ModusToolbox_1.1\tools\openocd-2.1\scripts\target\psoc6_common.cfg. On line 228, make this addition:

${TARGET}.cm4 configure -rtos auto -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0

The "auto" is taken to mean FreeRTOS by the plug-in, but you can use "-rtos FreeRTOS" if you prefer to be explicit. Next you need to define a variable that the plug-in expects (but is no longer defined in FreeRTOS). I just created a global variable like this:

static volatile int uxTopUsedPriority;

Then, in main(), I use the variable to make sure it is not optimized out by the compiler.

uxTopUsedPriority = configMAX_PRIORITIES - 1;

All I needed now was a project to debug. I created one from the PioneerKitAppFreeRTOS template and made a copy of the "blinky" task (so my application would be slightly more interesting). When I run the debugger and hit a breakpoint in one of the blinky functions, the Quick Panel Debug tab looks like this, which make it really easy to figure out what tasks are in the application and which one I am debugging.

Task-Aware Debugging in ModusToolbox IDE

Now, there is one slight problem with this... it breaks debugging of non-FreeRTOS applications! Oopsy! The reason for this is that the "-rtos auto" causes the debugger to look for missing symbols when you are not using the RTOS. I fixed this by making copies of psoc6.cfg and psoc6_common.cfg (called psoc6_rtos.cfg and psoc6_common_rtos.cfg) in the target folder above. In the psoc6_rtos.cfg file I edited the last line as follows:

source [find target/psoc6_common_rtos.cfg]

In the original psoc6_common.cfg file I backed out the edit so that this file is returned to its original state. Now I have RTOS and non-RTOS config files and, by default, the launch configuration for your projects will use the non-RTOS setup. However, when I do want to enable multi-thread debugging, I just edit the Debug Configuration (Run menu) to use the new files instead. In the Debugger tab there is a filed for Config Options and I change the config file as follows:

-c "source [find target/psoc6.cfg]"

Here is an image of that change.

Enabling Task-aware Debugging in ModusToolbox IDE

 

I am really happy with this discovery. I can now enable task-aware debugging for a project in just a couple of minutes. I think it will become a standard practice for me. I hope you like it too! I attached my config files so you can just copy them into the target folder, rather than edit the installed IDE files (remember to log into cypress.com to access them).

MarkS_11

PWM Clock Sharing

Posted by MarkS_11 Jun 27, 2019

Did you finish your homework? Well, here's an answer anyway. A couple of days ago I used a pair of TCPWM blocks to toggle the brightness of an LED at 1Hz. In that project I used an 8-bit clock divider as the source for the LED-driving PWM and a 16-bit divider for the slower toggling Timer-Counter. It worked just fine but it felt a little decadent to use two clock dividers when I am using a PSoC, which has the on-chip flexibility to use one divider for both TCPWM blocks. How to do that?

Well, the easy part is changing the clock source selection in the Timer-Counter using the Device Configurator. Open the project in ModusToolbox IDE and open the Configurator. In the SWAP_CTR block change the Clock Signal to "8 bit Divider 2 clk", which is marked in the drop-down as "USED" as a reminder that another resource is using that source (obviously... this is why we are choosing it!).

Choosing a USED PSoC clock divider

Next, there is a little mathematics, which is the English word for math. The frequency of the TCPWM output is a function of the peripheral clock (CLK_PERI) frequency, the 8 but divider value, the TCPWM prescaler (which I hinted at last time) and the period of the TCPWM counter. In pseudo-math (note that it is OK to call it math when it's "pseudo" - just because I am a snob does not mean I am not really lazy as well) it looks like this.

CLK_PERI

LED frequency =  ----------------------------

divider * prescaler * period

Some of these are known (or the pseudo-math becomes "guessing"). The LED toggling frequency needs to be 1Hz. The CLK_PERI is set to 72MHz in the Platform tab of the Device Configurator and let's leave that alone. For the others, the divider is a 8-bit value, the period is 16-bit, and the prescaler is 1, 2, 4, 8, 16, 32, 164 or 128. The trick we have to perform is to divide and prescale CLK_PERI such that the TCPWM period gives us 1Hz, preferably with a nice round number. Here is the rearranged formula.

divider * prescaler * period = 72000000

The 16-bit TCPWM has a maximum period of 65535, which means the clock must be divided by at least 1098.6, which cannot be done in a 8-bit divider. So we need to use a prescaler value of at least 8. Beyond that there are gabillions of combinations that satisfy the equation. After a little trial and error, well mostly error, I figured out that a divider of 225 works really nicely because it creates a frequency of 320kHz. Precaling that by 32 gives me a TCPWM frequency of 10kHz and a period of 10000 gives me a 1Hz output. Et voila!

Dividing and prescaling the PSoC clock frequency

Here is the set up for the Timer-Counter, with the prescaler and period set as above.

Setting the PSoC Timer-Counter period and prescaler

Note that the LED_PWM just has to toggle fast enough not to flicker so I set the period to 1000 and the compare values to 500 and 50 for the 50% and 5% intensity values.

I had quite a lot of fun doing this project. I think it nicely illustrates how flexible PSoC is and how wretched my mathematics skills are. I've attached a template that you can use to replicate the design - to use it, open the New Application dialog and "Import..." the modus.mk file to create a copy of the project.

Importing the project template into ModusToolbox IDE

Note: you must be logged into cypress.com to see the attachment (PWM_Swap.zip).