AnyCloud Bluetooth Advertising Scanner (Part 10)

Summary

We have finally reached the end of the AnyCloud Bluetooth Advertising Scanner.  In this article I will add the ability to sort the database.  In addition I will add the ability to purge a device.  And finally, truly finally, a bit of commentary.

Story

I originally built this program to help me learn about the AnyCloud Bluetooth SDK.  Well, originally I built this functionality to try to find and talk to a specific device (in an upcoming series).  The problem is that there are so many devices at my house that are blasting out so much data it is hard to see what I am looking for.  What I realized would help is add the ability to sort the devices from newest to oldest.  In addition I noticed that occasionally my database would fill up… and it would be nice to purge out old entries.  So that is what we are going to do.

There are

Article Topic
AnyCloud Bluetooth Advertising Scanner (Part 1) Introduction to AnyCloud Bluetooth Advertising
AnyCloud Bluetooth Advertising Scanner (Part 2) Creating an AnyCloud Bluetooth project
AnyCloud Bluetooth Advertising Scanner (Part 3) Adding Observing functionality to the project
AnyCloud Bluetooth Utilities Library A set of APIs for enhancement of the AnyCloud Library
AnyCloud Bluetooth Advertising Scanner (Part 4) Adding a command line to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 5) Adding a history database to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 6) Decoding advertising packets
AnyCloud Bluetooth Advertising Scanner (Part 7) Adding recording commands to the command line
AnyCloud Bluetooth Advertising Scanner (Part 8) Adding filtering to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 9) Improve the print and add packet age
AnyCloud Bluetooth Advertising Scanner (Part 10) Sort the database

All of the code can be found at git@github.com:iotexpert/AnyCloudBLEScanner.git and https://github.com/iotexpert/AnyCloudBLEScanner.git

There are git tags in place starting at part 5 so that you can look at just that version of the code.  "git tag" to list the tags.  And "git checkout part6" to look at the part 6 version of the code.

You can also create a new project with this is a template if you have the IoT Expert Manifest Files installed

Fix the Database Data Structure

You might remember that the database was built as an array of structures.  This mean that any moving around of the data would be a require a replacement of the whole structure.

static adb_adv_t adb_database[ADB_MAX_SIZE];

To fix this problem I moved the database to a an array of pointers.

static adb_adv_t *adb_database[ADB_MAX_SIZE];

To support this, when I see a new device I malloc a block of memory to hold the actual structure.

    // If it is NOT found && you have room
    if(entry == -1)
    {
        adb_database[adb_db_count] = malloc(sizeof(adb_adv_t));

Then I had to fix all of the references to the structure.  And there were a bunch (actually 43 of them).  But the replacement was pretty simple

adb_database[…].xxx is replaced by adb_database[…]-> …. here are the three different cases

case 1: adb_database[adb_db_count].

case 2: adb_database[entry].

case 1: adb_database[i].

That was actually way less painful that I thought it was going to be.  Probably what would actually be best is a library of these data structures with an API that would not have changed when the key changed, but that I suppose, is for another day.

Add Two New Commands

Now I add the sort and purge commands to my command list.

typedef enum {
    ADB_ADD,
    ADB_PRINT_RAW,
    ADB_PRINT_DECODE,
    ADB_WATCH,
    ADB_ERASE,
    ADB_RECORD,
    ADB_FILTER,
    ADB_SORT,
    ADB_PURGE,
} adb_cmd_t;

Create the Sort Functionality

To sort, I will use the c-standard library function qsort.  It requires a function that compares two entries a/b and returns

  1. a negative number of a<b
  2. 0 if a=b
  3. a positive number if a>b

Here is the function.  Hey Hassane you like those pointers?

static int adb_sort_cmpfunc(const void * a, const void * b) 
{
    adb_adv_t *p1 = *((adb_adv_t **)a);
    adb_adv_t *p2 = *((adb_adv_t **)b);
        
    return p2->lastSeen - p1->lastSeen;
}

The sort is actually really simple now.  Just a call to sort (then I decided to print out the table)

                case ADB_SORT:
                    qsort(adb_database, adb_db_count, sizeof(adb_adv_t *), adb_sort_cmpfunc);
                    adb_db_print(ADB_PRINT_METHOD_BYTES,true,-1);
                break;

Now instead of this….

I get this…

Create the Purge Functionality

The purge function needs to do two things

  1. Free all of the memory from an entry
  2. Move the pointers so that the “purged” entry is gone.

First I erase all of the data in the linked list with the adb_eraseEntry function.

Then I free the head of the list

Then I free the actual structure

Then I move all of the pointers to squeeze the able.

static void adb_purgeEntry(int entry)
{

    adb_eraseEntry(entry);
    free(adb_database[entry]->list);
    free(adb_database[entry]->result);
    free(adb_database[entry]);
    adb_db_count -= 1;
    for(int i=entry;i<adb_db_count;i++)
    {
        adb_database[i] = adb_database[i+1];
    }
}

And you need to add the actual command.

                case ADB_PURGE:
                    if((int)msg.data0<0 || (int)msg.data0>=adb_db_count)
                    {
                        printf("Purge error %d\n",(int)msg.data0);
                        break;
                    }   
                    adb_purgeEntry((int)msg.data0);
                break;

The End & Commentary

I would like to add and maybe will one day:

  1. A connect function with a GATT browser
  2. A smarter way to deal with the fact that device change addresses

Finally a couple of comments about this

  1. You might notice that I don’t check very many possible errors.  I do this in the interest of simpler to read code.  This is a tradeoff that I make for “teaching” code.  I hope that you understand that if you want to do something like this in a real product that you need to be much more careful.
  2. I don’t have unit testing.  This falls into the same category as the error checking.  Really this is a bad idea as code without unit testing is obsolete the second it comes out of your fingers.  But, it is easier to read.
  3. I don’t have many comments.  This is something that my colleagues bitch about all of the time with me.  And I know that it must be a personality defect.
  4. I use malloc/free all over the place.  This is a religious war.  You can make a static allocation scheme, but it would be really complicated in this case.  I personally think that the tradeoff of using a battle worn and tested malloc/free is totally worthwhile against the complexity of custom static memory allocation schemes.

AnyCloud Bluetooth Advertising Scanner (Part 3)

Summary

In this article I discuss BLE “Observing” and add that functionality to my PSoC 6 – CYW43xxx AnyCloud BLE Adverting Scanner project.

Story

In part1 of this series I discussed the pieces parts required to get the AnyCloud Bluetooth Stack operating using the AnyCloud SDK running on a PSoC 6 with a CY43xxx combo.  Then in part 2 I built a project with those parts and started up the Bluetooth Host stack.  The project didn’t really do anything, actually nothing, so it wasn’t very interesting, but it was going.  In this article I will discuss BLE advertising scanning, how to configure it in the AnyCloud project and finally how to add it to the project.

There are

Article Topic
AnyCloud Bluetooth Advertising Scanner (Part 1) Introduction to AnyCloud Bluetooth Advertising
AnyCloud Bluetooth Advertising Scanner (Part 2) Creating an AnyCloud Bluetooth project
AnyCloud Bluetooth Advertising Scanner (Part 3) Adding Observing functionality to the project
AnyCloud Bluetooth Utilities Library A set of APIs for enhancement of the AnyCloud Library
AnyCloud Bluetooth Advertising Scanner (Part 4) Adding a command line to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 5) Adding a history database to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 6) Decoding advertising packets
AnyCloud Bluetooth Advertising Scanner (Part 7) Adding recording commands to the command line
AnyCloud Bluetooth Advertising Scanner (Part 8) Adding filtering to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 9) Improve the print and add packet age
AnyCloud Bluetooth Advertising Scanner (Part 10) Sort the database

All of the code can be found at git@github.com:iotexpert/AnyCloudBLEScanner.git and https://github.com/iotexpert/AnyCloudBLEScanner.git

There are git tags in place starting at part 5 so that you can look at just that version of the code.  "git tag" to list the tags.  And "git checkout part6" to look at the part 6 version of the code.

You can also create a new project with this is a template if you have the IoT Expert Manifest Files installed

Explain BLE Advertising – Scanner/Observer

You might recall that there are four roles that a BLE device can perform

  • Peripheral – low power devices that broadcast advertisements, then accept a single connection
  • Central – devices like cell phones that connect to peripherals.  They may run multiple connections at a time.
  • Broadcaster – a nonconnectable peripheral that sends out advertisements
  • Observer – A central-like device that listens for broadcasters (or advertising peripherals)

And you might remember that advertisements are short, up to 31-byte, packets of data that give information which can be used for one or more of:

  • advertising the availability to connect
  • advertising services
  • advertising the name
  • advertising vendor specific information
  • advertising beacon data (like temperature or …)
  • advertising location

And, if you forgot, BLE operates on 40 channels.  But to save power in peripherals, all of the advertising happens on channel 37, 38 and 39.  Specifically a peripheral or broadcaster will send out the advertising data on channel 37, then 38 then 39, then wait… then do it again.  But why one channel at a time?  Because BLE radio’s can be tuned to transmit and receive on only one channel at a time (a power saving and complexity reducing feature)

Inside of the Central/Observer it will listen on channel 37 for a “window” amount of time.  Then it will do nothing for an interval-window amount of time.  Then it will do that same thing on channel 28 then 39.  But why only one channel at a time?  Same reason as above, it saves power and simplifies the design.  Why not have the window and the interval be the same?  Once again, it saves power.

Here is a picture:

But, what happens if you are not listening when the advertiser advertises?  You missed it.  Tough shit.  It turns out that setting the scan window and interval will greatly impact the probability that you hear advertisements.  And, you are more likely to hear advertisements because they are sent on three channels.  But it seems like it will never work.  Will it? … yes, of course, or they wouldn’t have done it that way 🙂

BLE Advertising – The Advertiser Peripheral or Broadcaster

So what exactly is inside of an advertising packet?  Volume 6 part B Section 2.3 of the bluetooth core spec describes the advertising protocol data unit (PDU)

But what is inside of the header?

This leaves us with what is inside of the “payload”.  The answer is that the ADV_IND Payload Data Unit (PDU) contains an address of 6-bytes plus up to 31 bytes of data.

The AdvA field shall contain the advertiser’s public or random device address as indicated by TxAdd.

The actual AdvData field is further broken up into “AD Structures” like this:

And what is the “AD Type”, well it is a one byte of one of the following:

And then where do you find the assigned numbers for the field types?  In the “Assigned Numbers and GAP“.  Here is a clip from the spec.

And conveniently enough we enumerated them for you inside of the SDK header file wiced_bt_ble.h

/** Advertisement data types */
enum wiced_bt_ble_advert_type_e {
BTM_BLE_ADVERT_TYPE_FLAG                        = 0x01,                 /**< Advertisement flags */
BTM_BLE_ADVERT_TYPE_16SRV_PARTIAL               = 0x02,                 /**< List of supported services - 16 bit UUIDs (partial) */
BTM_BLE_ADVERT_TYPE_16SRV_COMPLETE              = 0x03,                 /**< List of supported services - 16 bit UUIDs (complete) */
BTM_BLE_ADVERT_TYPE_32SRV_PARTIAL               = 0x04,                 /**< List of supported services - 32 bit UUIDs (partial) */
BTM_BLE_ADVERT_TYPE_32SRV_COMPLETE              = 0x05,                 /**< List of supported services - 32 bit UUIDs (complete) */
BTM_BLE_ADVERT_TYPE_128SRV_PARTIAL              = 0x06,                 /**< List of supported services - 128 bit UUIDs (partial) */
BTM_BLE_ADVERT_TYPE_128SRV_COMPLETE             = 0x07,                 /**< List of supported services - 128 bit UUIDs (complete) */
BTM_BLE_ADVERT_TYPE_NAME_SHORT                  = 0x08,                 /**< Short name */
BTM_BLE_ADVERT_TYPE_NAME_COMPLETE               = 0x09,                 /**< Complete name */
BTM_BLE_ADVERT_TYPE_TX_POWER                    = 0x0A,                 /**< TX Power level  */
BTM_BLE_ADVERT_TYPE_DEV_CLASS                   = 0x0D,                 /**< Device Class */
BTM_BLE_ADVERT_TYPE_SIMPLE_PAIRING_HASH_C       = 0x0E,                 /**< Simple Pairing Hash C */
BTM_BLE_ADVERT_TYPE_SIMPLE_PAIRING_RAND_C       = 0x0F,                 /**< Simple Pairing Randomizer R */
BTM_BLE_ADVERT_TYPE_SM_TK                       = 0x10,                 /**< Security manager TK value */
BTM_BLE_ADVERT_TYPE_SM_OOB_FLAG                 = 0x11,                 /**< Security manager Out-of-Band data */
BTM_BLE_ADVERT_TYPE_INTERVAL_RANGE              = 0x12,                 /**< Slave connection interval range */
BTM_BLE_ADVERT_TYPE_SOLICITATION_SRV_UUID       = 0x14,                 /**< List of solicitated services - 16 bit UUIDs */
BTM_BLE_ADVERT_TYPE_128SOLICITATION_SRV_UUID    = 0x15,                 /**< List of solicitated services - 128 bit UUIDs */
BTM_BLE_ADVERT_TYPE_SERVICE_DATA                = 0x16,                 /**< Service data - 16 bit UUID */
BTM_BLE_ADVERT_TYPE_PUBLIC_TARGET               = 0x17,                 /**< Public target address */
BTM_BLE_ADVERT_TYPE_RANDOM_TARGET               = 0x18,                 /**< Random target address */
BTM_BLE_ADVERT_TYPE_APPEARANCE                  = 0x19,                 /**< Appearance */
BTM_BLE_ADVERT_TYPE_ADVERT_INTERVAL             = 0x1a,                 /**< Advertising interval */
BTM_BLE_ADVERT_TYPE_LE_BD_ADDR                  = 0x1b,                 /**< LE device bluetooth address */
BTM_BLE_ADVERT_TYPE_LE_ROLE                     = 0x1c,                 /**< LE role */
BTM_BLE_ADVERT_TYPE_256SIMPLE_PAIRING_HASH      = 0x1d,                 /**< Simple Pairing Hash C-256 */
BTM_BLE_ADVERT_TYPE_256SIMPLE_PAIRING_RAND      = 0x1e,                 /**< Simple Pairing Randomizer R-256 */
BTM_BLE_ADVERT_TYPE_32SOLICITATION_SRV_UUID     = 0x1f,                 /**< List of solicitated services - 32 bit UUIDs */
BTM_BLE_ADVERT_TYPE_32SERVICE_DATA              = 0x20,                 /**< Service data - 32 bit UUID */
BTM_BLE_ADVERT_TYPE_128SERVICE_DATA             = 0x21,                 /**< Service data - 128 bit UUID */
BTM_BLE_ADVERT_TYPE_CONN_CONFIRM_VAL            = 0x22,                 /**< LE Secure Connections Confirmation Value */
BTM_BLE_ADVERT_TYPE_CONN_RAND_VAL               = 0x23,                 /**< LE Secure Connections Random Value */
BTM_BLE_ADVERT_TYPE_URI                         = 0x24,                 /**< URI */
BTM_BLE_ADVERT_TYPE_INDOOR_POS                  = 0x25,                 /**< Indoor Positioning */
BTM_BLE_ADVERT_TYPE_TRANS_DISCOVER_DATA         = 0x26,                 /**< Transport Discovery Data */
BTM_BLE_ADVERT_TYPE_SUPPORTED_FEATURES          = 0x27,                 /**< LE Supported Features */
BTM_BLE_ADVERT_TYPE_UPDATE_CH_MAP_IND           = 0x28,                 /**< Channel Map Update Indication */
BTM_BLE_ADVERT_TYPE_PB_ADV                      = 0x29,                 /**< PB-ADV */
BTM_BLE_ADVERT_TYPE_MESH_MSG                    = 0x2A,                 /**< Mesh Message */
BTM_BLE_ADVERT_TYPE_MESH_BEACON                 = 0x2B,                 /**< Mesh Beacon */
BTM_BLE_ADVERT_TYPE_PSRI                        = 0x2E,                 /**< Generic Audio Provate Set Random Identifier */
BTM_BLE_ADVERT_TYPE_3D_INFO_DATA                = 0x3D,                 /**< 3D Information Data */
BTM_BLE_ADVERT_TYPE_MANUFACTURER                = 0xFF                  /**< Manufacturer data */
};

How does scanning work in the AnyCloud Bluetooth Stack?

To turn on observing/scanning you need to call the function:

wiced_bt_dev_status_t wiced_bt_ble_observe (wiced_bool_t start, uint8_t duration, wiced_bt_ble_scan_result_cback_t *p_scan_result_cback);

Which will cause the host stack to tell the controller to start scanning for advertising packets.  It will set the scan window and scan interval the low duty scan settings from the bluetooth configuration structure… which we setup with the Bluetooth configurator.

 .low_duty_scan_interval          = CY_BT_LOW_DUTY_SCAN_INTERVAL,                              /**< Low duty scan interval */
.low_duty_scan_window            = CY_BT_LOW_DUTY_SCAN_WINDOW,                                /**< Low duty scan window */
.low_duty_scan_duration          = CY_BT_LOW_DUTY_SCAN_DURATION,                              /**< Low duty scan duration in seconds (0 for infinite) */

When the controller hears an advertising packet, it will send the HCI advertising report to the Bluetooth host stack, which with then call you back.  Specifically it will call you back by calling the p_scan_result_cback” function.

You provide the callback function which has the prototype:

typedef void (wiced_bt_ble_scan_result_cback_t) (wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data);

which contains two parameters, p_scan_result which is a structure that has the mac address and some thing data plus the p_adv_data which has the raw bytes of the advertising packet.

Add Observing to our Project

OK.  Lets add this to our project by creating a callback function like this:

Lines 5-9: Just prints out the raw bytes of the MAC address of the remote device, the one advertising

To print out the raw advertising data you need to remember that it is formatted as

  1. A length (of all of the data of the field)
  2. A type
  3. The rest of the data

When you find a field of length of 0 you know that you have reached the end of the data

On Lines 13-20: I print out one field at a time and the raw data

//
void obv_callback(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{
// Print the MAC Address
printf("MAC: ");
for(int i=0;i<6;i++)
{
printf("%02X:",p_scan_result->remote_bd_addr[i]);
}
// Print the RAW Data of the ADV Packet
printf(" Data: ");
int i=0;
while(p_adv_data[i])
{
for(int j=0;j<p_adv_data[i];j++)
{
printf("%02X ",p_adv_data[i+1+j]);
}
i = i + p_adv_data[i]+1;
}
printf("\n");
}

Then update the management callback to start the scanner after the stack is successfully started

    switch (event)
{
case BTM_ENABLED_EVT:
if (WICED_BT_SUCCESS == p_event_data->enabled.status)
{
printf("Started BT Stack Succesfully\n");
wiced_bt_ble_observe(WICED_TRUE,0,obv_callback);
}

Program and Test

Now when I run the program data comes blasting out of the screen because there are a boatload of ble devices in my house

AnyCloud> Unhandled Bluetooth Management Event: 0x16
Started BT Stack Succesfully
MAC: 76:99:58:E8:8B:1F:Data: 01 1A 0A 0C FF 4C 00 10 06 13 1A 54 F7 5A 7A 
MAC: 9E:7B:EF:0B:74:20:Data: 01 06 16 F7 FD 01 0C C2 81 CE 0C 74 58 77 19 C8 E3 84 A3 42 50 98 00 00 00 00 03 
MAC: 6F:11:7C:FF:02:13:Data: 01 1A 0A 05 FF 4C 00 10 06 03 1E BA 24 58 3D 
MAC: 3F:64:BE:4E:29:0C:Data: 01 04 FF 00 4C 02 15 26 86 F3 9C BA DA 46 58 85 4A A6 2E 7E 5E 8B 8D 00 01 00 00 C9 
MAC: 47:4B:F1:53:2C:84:Data: 01 06 FF 4C 00 10 05 08 18 79 1E C2 
MAC: C8:69:CD:18:BC:E6:Data: 01 1A 0A 0C FF 4C 00 10 05 0C 14 17 BF E9 
MAC: 27:F6:6F:1E:7A:78:Data: 01 1A FF 4C 00 09 06 03 12 C0 A8 20 0D 
MAC: 6F:AE:84:F6:6A:9F:Data: 01 06 FF 4C 00 10 05 08 18 79 1E C2 
MAC: 3F:64:BE:4E:29:0C:Data: 01 04 FF 00 4C 02 15 26 86 F3 9C BA DA 46 58 85 4A A6 2E 7E 5E 8B 8D 00 01 00 00 C9 
MAC: 41:EE:B4:9C:5C:5F:Data: 01 1A 0A 07 FF 4C 00 10 06 33 1A 49 59 46 B4 
MAC: 9E:7B:EF:0B:74:20:Data: 01 06 16 F7 FD 01 0C C2 81 CE 0C 74 58 77 19 C8 E3 84 A3 42 50 98 00 00 00 00 03 
MAC: C8:EB:ED:C8:AC:1C:Data: 01 0A 03 66 66 19 D0 07 FF EE 03 1C AC C8 ED EB C8 
MAC: 76:99:58:E8:8B:1F:Data: 01 1A 0A 0C FF 4C 00 10 06 13 1A 54 F7 5A 7A

In the next article Ill add some more smarts to manage the data to be easier to look at.

For your information here is all of the file bluetoothManager.c

#include <stdio.h>
#include <stdlib.h>
#include "cybsp.h"
#include "FreeRTOS.h"
#include "bluetoothManager.h"
#include "wiced_bt_stack.h"
#include "wiced_bt_dev.h"
#include "wiced_bt_trace.h"
//
void obv_callback(wiced_bt_ble_scan_results_t *p_scan_result, uint8_t *p_adv_data)
{
// Print the MAC Address
printf("MAC: ");
for(int i=0;i<6;i++)
{
printf("%02X:",p_scan_result->remote_bd_addr[i]);
}
// Print the RAW Data of the ADV Packet
printf(" Data: ");
int i=0;
while(p_adv_data[i])
{
for(int j=0;j<p_adv_data[i];j++)
{
printf("%02X ",p_adv_data[i+1+j]);
}
i = i + p_adv_data[i]+1;
}
printf("\n");
}
/**************************************************************************************************
* Function Name: app_bt_management_callback()
***************************************************************************************************
* Summary:
*   This is a Bluetooth stack event handler function to receive management events from
*   the BLE stack and process as per the application.
*
* Parameters:
*   wiced_bt_management_evt_t event             : BLE event code of one byte length
*   wiced_bt_management_evt_data_t *p_event_data: Pointer to BLE management event structures
*
* Return:
*  wiced_result_t: Error code from WICED_RESULT_LIST or BT_RESULT_LIST
*
*************************************************************************************************/
wiced_result_t app_bt_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
wiced_result_t result = WICED_BT_SUCCESS;
switch (event)
{
case BTM_ENABLED_EVT:
if (WICED_BT_SUCCESS == p_event_data->enabled.status)
{
printf("Started BT Stack Succesfully\n");
wiced_bt_ble_observe(WICED_TRUE,0,obv_callback);
}
else
{
printf("Error enabling BTM_ENABLED_EVENT\n");
}
break;
default:
printf("Unhandled Bluetooth Management Event: 0x%x\n", event);
break;
}
return result;
}

 

AnyCloud Bluetooth Advertising Scanner (Part 2)

Summary

The second article in a series discussing the creation of a PSoC 6 + CYW43xxx Advertising Scanner using the AnyCloud SDK.  This article will use the learning from Part 1 to create a template project that starts the BLE stack.

Story

In the previous article I discussed the structure of the Cypress/Infineon Bluetooth Stack and its integration into AnyCloud.  A bunch of “theory”, well I say BS to that.  Let’s build something.

There are

Article Topic
AnyCloud Bluetooth Advertising Scanner (Part 1) Introduction to AnyCloud Bluetooth Advertising
AnyCloud Bluetooth Advertising Scanner (Part 2) Creating an AnyCloud Bluetooth project
AnyCloud Bluetooth Advertising Scanner (Part 3) Adding Observing functionality to the project
AnyCloud Bluetooth Utilities Library A set of APIs for enhancement of the AnyCloud Library
AnyCloud Bluetooth Advertising Scanner (Part 4) Adding a command line to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 5) Adding a history database to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 6) Decoding advertising packets
AnyCloud Bluetooth Advertising Scanner (Part 7) Adding recording commands to the command line
AnyCloud Bluetooth Advertising Scanner (Part 8) Adding filtering to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 9) Improve the print and add packet age
AnyCloud Bluetooth Advertising Scanner (Part 10) Sort the database

All of the code can be found at git@github.com:iotexpert/AnyCloudBLEScanner.git and https://github.com/iotexpert/AnyCloudBLEScanner.git

There are git tags in place starting at part 5 so that you can look at just that version of the code.  "git tag" to list the tags.  And "git checkout part6" to look at the part 6 version of the code.

You can also create a new project with this is a template if you have the IoT Expert Manifest Files installed

Recall from Part 1 that you need three things to startup the Bluetooth Stack

  • The Hardware Configuration Structure that matches : cybt_platform_config_t
  • The Bluetooth Stack Configuration Structure that matches : wiced_bt_cfg_settings_t
  • The Bluetooth Management Callback that matches : typedef wiced_result_t (wiced_bt_management_cback_t) (wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data);

Then you need to call

  • The hardware initialization function : cybt_platform_config_init
  • The stack initialization function : wiced_bt_stack_init

Ok let’s do this!

Basic Project

You can do all of these steps from the Eclipse IDE for ModusToolbox.  Or you can do it from the individual programs and the command line.  I like Visual Studio code, so this article will be done completely from the command line and individual configurators.

Run the new project creator from the start menu.  Start by creating a project for the development kit that you have, in my case the one currently plugged into my computer is the CY8CKIT-062S2-43012, so that is what I pick.  But, this project will work with any of the WiFI/BT combo chips attached to PSoC 6.

In previous articles I discussed the template that I use to get things going with FreeRTOS.  I won’t discuss that here, but I want FreeRTOS and the NTShell, so pick the IoT Expert FreeRTOS NTShell Template.

After about a minute you should have a project.  I always like to build the project to make sure that everything is working before I get too far down the road of modifying anything.  Run “make -j build”

arh (master) AnyCloudBLEScanner $ make -j build
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 205 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 503 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 193 file(s)
Compiling app file lowPower.c
Compiling app file main.c
Compiling app file usrcmd.c
Compiling ext file startup_psoc6_02_cm4.S
..... a bunch of lines deleted
Compiling ext file psoc6_01_cm0p_sleep.c
Compiling ext file psoc6_02_cm0p_sleep.c
Compiling ext file psoc6_03_cm0p_sleep.c
Compiling ext file psoc6_04_cm0p_sleep.c
Compiling ext file cy_retarget_io.c
Linking output file MTBShellTemplate.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  54876      | 
| .ARM.exidx           |  0x1000f65c   |  8          | 
| .copy.table          |  0x1000f664   |  24         | 
| .zero.table          |  0x1000f67c   |  8          | 
| .data                |  0x080022e0   |  1688       | 
| .cy_sharedmem        |  0x08002978   |  8          | 
| .noinit              |  0x08002980   |  148        | 
| .bss                 |  0x08002a14   |  2136       | 
| .heap                |  0x08003270   |  1029520    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           64812      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    

Then to be sure it is working, program the development kit.

arh (master) AnyCloudBLEScanner $ make program
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 205 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 503 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 193 file(s)
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  54876      | 
| .ARM.exidx           |  0x1000f65c   |  8          | 
| .copy.table          |  0x1000f664   |  24         | 
| .zero.table          |  0x1000f67c   |  8          | 
| .data                |  0x080022e0   |  1688       | 
| .cy_sharedmem        |  0x08002978   |  8          | 
| .noinit              |  0x08002980   |  148        | 
| .bss                 |  0x08002a14   |  2136       | 
| .heap                |  0x08003270   |  1029520    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           64812      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    
Programming target device... 
Open On-Chip Debugger 0.10.0+dev-4.1.0.1058 (2020-08-11-03:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 2000 kHz
adapter srst delay: 25
adapter srst pulse_width: 25
** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable
cortex_m reset_config sysresetreq
cortex_m reset_config sysresetreq
Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 14672 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 : KitProg3: FW version: 1.14.514
Info : KitProg3: Pipelined transfers disabled, please update the firmware
Info : VTarget = 3.215 V
Info : kitprog3: acquiring the device...
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x6ba02477
Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints
***************************************
** Silicon: 0xE453, Family: 0x102, Rev.: 0x12 (A1)
** Detected Device: CY8C624ABZI-S2D44
** Detected Main Flash size, kb: 2048
** Flash Boot version: 3.1.0.378
** Chip Protection: NORMAL
***************************************
Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for psoc6.cpu.cm0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for psoc6.cpu.cm4 on 3334
Info : Listening on port 3334 for gdb connections
Info : SWD DPIDR 0x6ba02477
Info : kitprog3: acquiring the device...
psoc6.cpu.cm0 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...
psoc6.cpu.cm4 halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800
** Programming Started **
auto erase enabled
Info : Flash write discontinued at 0x1000179c, next section at 0x10002000
Info : Padding image section 0 at 0x1000179c with 100 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
Info : Padding image section 1 at 0x1000fd24 with 220 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
wrote 62976 bytes from file /Users/arh/mtw/AnyCloudBLEScanner/build/CY8CKIT-062S2-43012/Debug/MTBShellTemplate.hex in 2.069358s (29.719 KiB/s)
** Programming Finished **
** Verify Started **
verified 62656 bytes in 0.122208s (500.683 KiB/s)
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x6ba02477
shutdown command invoked
Info : psoc6.dap: powering down debug domain...
arh (master) AnyCloudBLEScanner $

When that is done, open up a terminal window and you should have a functioning base project.  Notice that I ran “help” and “tasks” from the command shell.

Now that we have a basic project working, add the Bluetooth libraries.  Run the library manager by typing “make modlibs”.  Then select “bluetooth-freertos” and the library manager will automatically select the other libraries you need.  Press Update then Close.

Next, run the bluetooth configurator by running “make config_bt”  This tool will help you make the bluetooth stack configuration structure.  When the configurator starts, press “New”

Then select our device (the PSoC 6 and the Combo chip)

Click on the “GAP Settings”.  Then press the Plus and add “Observer configuration”

Then setup the scan settings (more detail on these numbers in the next article)

  • Low duty scan window (ms) = 60
  • Low duty scan interval (ms) = 60
  • Low duty scan timeout = deselected (meaning no timeout)

Then save your configuration file.  Notice that I called it “btconfig”

When you are done you will have a directory called “GeneratedSource” inside of your project with the needed files.

The next step is to fix up the Makefile.  I like changing the name of the “App”.

# Name of application (used to derive name of final linked file).
APPNAME=AnyCloudBLEScanner

Then you need the “FREERTOS WICED_BLE” components.

# Enable optional code that is ordinarily disabled by default.
#
# Available components depend on the specific targeted hardware and firmware
# in use. In general, if you have
#
#    COMPONENTS=foo bar
#
# ... then code in directories named COMPONENT_foo and COMPONENT_bar will be
# added to the build
#
COMPONENTS=FREERTOS WICED_BLE

If you run make vscode it will update the workspace with all of the stuff needed for Visual Studio Code to be able to find all of the files.

arh (master) AnyCloudBLEScanner $ make vscode
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 230 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 22 .a file(s)
-> Found 561 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Generating IDE files =
==============================================================================
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
echo "The existing MTBShellTemplate.code-workspace file has been saved to .vscode/backup";
The existing MTBShellTemplate.code-workspace file has been saved to .vscode/backup
The existing c_cpp_properties.json file has been saved to .vscode/backup
The existing launch.json file has been saved to .vscode/backup
Modifying existing settings.json file. Check against the backup copy in .vscode/backup
The existing tasks.json file has been saved to .vscode/backup
Generated Visual Studio Code files: c_cpp_properties.json launch.json openocd.tcl settings.json tasks.json
J-Link users, please see the comments at the top of the launch.json
file about setting the location of the gdb-server.
Instructions:
1. Review the modustoolbox.toolsPath property in .vscode/settings.json
2. Open VSCode
3. Install "C/C++" and "Cortex-Debug" extensions
4. File->Open Folder (Welcome page->Start->Open folder)
5. Select the app root directory and open
6. Builds: Terminal->Run Task
7. Debugging: "Bug icon" on the left-hand pane
arh (master) AnyCloudBLEScanner $

Inside of Visual Studio Code, create a new file called “bt_platform_cfg_settings.h” and add:

#include "cybt_platform_config.h"
#include "cybsp.h"
#include "wiced_bt_stack.h"
extern const cybt_platform_config_t bt_platform_cfg_settings;

Inside of Visual Studio Code, create a new file called “bt_platform_cfg_settings.c” and add:

#include "cybt_platform_config.h"
#include "cybsp.h"
#include "wiced_bt_stack.h"
const cybt_platform_config_t bt_platform_cfg_settings =
{
.hci_config =
{
.hci_transport = CYBT_HCI_UART,
.hci =
{
.hci_uart =
{
.uart_tx_pin = CYBSP_BT_UART_TX,
.uart_rx_pin = CYBSP_BT_UART_RX,
.uart_rts_pin = CYBSP_BT_UART_RTS,
.uart_cts_pin = CYBSP_BT_UART_CTS,
.baud_rate_for_fw_download = 115200,
.baud_rate_for_feature     = 115200,
.data_bits = 8,
.stop_bits = 1,
.parity = CYHAL_UART_PARITY_NONE,
.flow_control = WICED_TRUE
}
}
},
.controller_config =
{
.bt_power_pin      = CYBSP_BT_POWER,
.sleep_mode =
{
#if (bt_0_power_0_ENABLED == 1) /* BT Power control is enabled in the LPA */
#if (CYCFG_BT_LP_ENABLED == 1) /* Low power is enabled in the LPA, use the LPA configuration */
.sleep_mode_enabled = true,
.device_wakeup_pin = CYCFG_BT_DEV_WAKE_GPIO,
.host_wakeup_pin = CYCFG_BT_HOST_WAKE_GPIO,
.device_wake_polarity = CYCFG_BT_DEV_WAKE_POLARITY,
.host_wake_polarity = CYCFG_BT_HOST_WAKE_IRQ_EVENT
#else /* Low power is disabled in the LPA, disable low power */
.sleep_mode_enabled = false
#endif
#else /* BT Power control is disabled in the LPA – default to BSP low power configuration */
.sleep_mode_enabled = true,
.device_wakeup_pin = CYBSP_BT_DEVICE_WAKE,
.host_wakeup_pin = CYBSP_BT_HOST_WAKE,
.device_wake_polarity = CYBT_WAKE_ACTIVE_LOW,
.host_wake_polarity = CYBT_WAKE_ACTIVE_LOW
#endif
}
},
.task_mem_pool_size    = 2048
};

Inside of Visual Studio Code, create bluetoothManager.h.  Remember this is the Bluetooth Stack Management Callback

#pragma once
#include "wiced_bt_stack.h"
#include "wiced_bt_dev.h"
wiced_result_t app_bt_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data);

Inside of Visual Studio code, create bluetoothManager.c.  This function does a whole lotta nothin… except saying that things got started.

#include <stdio.h>
#include <stdlib.h>
#include "cybsp.h"
#include "FreeRTOS.h"
#include "bluetoothManager.h"
#include "wiced_bt_stack.h"
#include "wiced_bt_dev.h"
#include "wiced_bt_trace.h"
/**************************************************************************************************
* Function Name: app_bt_management_callback()
***************************************************************************************************
* Summary:
*   This is a Bluetooth stack event handler function to receive management events from
*   the BLE stack and process as per the application.
*
* Parameters:
*   wiced_bt_management_evt_t event             : BLE event code of one byte length
*   wiced_bt_management_evt_data_t *p_event_data: Pointer to BLE management event structures
*
* Return:
*  wiced_result_t: Error code from WICED_RESULT_LIST or BT_RESULT_LIST
*
*************************************************************************************************/
wiced_result_t app_bt_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
wiced_result_t result = WICED_BT_SUCCESS;
switch (event)
{
case BTM_ENABLED_EVT:
if (WICED_BT_SUCCESS == p_event_data->enabled.status)
{
printf("Started BT Stack Succesfully\n");
}
else
{
printf("Error enabling BTM_ENABLED_EVENT\n");
}
break;
default:
printf("Unhandled Bluetooth Management Event: 0x%x\n", event);
break;
}
return result;
}

Next, update main.c with the required includes.

#include "bluetoothManager.h"
#include "cycfg_bt_settings.h"
#include "bt_platform_cfg_settings.h"

Then update main.c to start the stack

    cybt_platform_config_init(&bt_platform_cfg_settings);
wiced_bt_stack_init (app_bt_management_callback, &wiced_bt_cfg_settings);

Now build and program it, remember “make -j build” and “make program”.  Look, we have a functioning stack with the two bluetooth thread running.

In the next article Ill finally get around to building the Bluetooth Scanner.

AnyCloud Bluetooth Advertising Scanner (Part 1)

Summary

The first of several articles discussing the use of the AnyCloud BLE Stack to build advertising scanner/observers.

Story

A few summers ago while I was writing the WICED Bluetooth Academy book, I created a WICED based BLE advertising scanner.  Actually, I created a framework for the scanner and the remarkable summer intern I had finished the work.  That project has been sitting in the source code repository for the Bluetooth class, mostly only shown to face-to-face students.  This scanner is built using some of the original code combined with the new AnyCloud Bluetooth SDK.  It will act sort-of-like LightBlue or one of the other Bluetooth advertising scanners you might run on your phone, but with a serial console.

Sometime in the last few months we released the Bluetooth SDK for AnyCloud (things have been crazy and I have lost track of time)  This SDK has all of the stuff needed to add Bluetooth to your AnyCloud project using one of the Cypress Bluetooth/WiFi combo chips.  I had not had a chance to try it out, so I decided to build a Bluetooth project and then port the scanning code.

There are

Article Topic
AnyCloud Bluetooth Advertising Scanner (Part 1) Introduction to AnyCloud Bluetooth Advertising
AnyCloud Bluetooth Advertising Scanner (Part 2) Creating an AnyCloud Bluetooth project
AnyCloud Bluetooth Advertising Scanner (Part 3) Adding Observing functionality to the project
AnyCloud Bluetooth Utilities Library A set of APIs for enhancement of the AnyCloud Library
AnyCloud Bluetooth Advertising Scanner (Part 4) Adding a command line to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 5) Adding a history database to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 6) Decoding advertising packets
AnyCloud Bluetooth Advertising Scanner (Part 7) Adding recording commands to the command line
AnyCloud Bluetooth Advertising Scanner (Part 8) Adding filtering to the scanner
AnyCloud Bluetooth Advertising Scanner (Part 9) Improve the print and add packet age
AnyCloud Bluetooth Advertising Scanner (Part 10) Sort the database

All of the code can be found at git@github.com:iotexpert/AnyCloudBLEScanner.git and https://github.com/iotexpert/AnyCloudBLEScanner.git

There are git tags in place starting at part 5 so that you can look at just that version of the code.  "git tag" to list the tags.  And "git checkout part6" to look at the part 6 version of the code.

You can also create a new project with this is a template if you have the IoT Expert Manifest Files installed

Bluetooth Application Architecture

Bluetooth applications are divided into these four pieces

  1. You user application which responds to events and sends messages from/to the Bluetooth host stack
  2. A Bluetooth Host Stack
  3. A Bluetooth Controller Stack
  4. The Bluetooth Radio

These four pieces can be divided into multiple chips, as few as one or as many as four.  However, for this article, the project will be built to run on a PSoC 6 + CYW43012 WiFi/Bluetooth Combo chip.  Specifically:

  1. My scanner application running on the PSoC 6
  2. The Bluetooth Host Stack running on the PSoC 6
  3. The BlueTooth Controller Firmware running on the CYW43012
  4. A Bluetooth Radio on the CYW43012

But how do they talk?  Simple, there is:

  1. A UART Host Controller Interface (HCI) between the two chips
  2. A GPIO to serve as a deep sleep wakeup from the 43012 –> PSoC 6
  3. A GPIO to serve as the bluetooth controller wakeup from the PSoC 6 –> 43012
  4. A GPIO to turn on the Bluetooth regulator from the PSoC 6 –> 43012

Here is the block diagram from the CY8CKIT-062S2-43012 Kit Guide.  Notice that signals labeled UART and Control going between the PSoC 6 and the CYW43012.

And when you read more deeply into the schematic you can see the signals labeled

  • BT_UART_TXD/RXD/CTS/RTS
  • BT_HOST_WAKE
  • BT_DEV_WAKE
  • BT_REG_ON

How to Start the AnyCloud Bluetooth Stack

To actually start the AnyCloud Bluetooth stack you will call two functions

  1. cybt_platform_config_init – that will setup the hardware interface to the CYW43012
  2. wiced_bt_stack_init that will:
    1. Start a task to manage the Host Controller Interface
    2. Download the controller firmware to the CYW43012
    3. Start a task to manage the host stack
    4. Initialize both the host and the controller
    5. Call you back when that is all done

Here is an example from main.

    cybt_platform_config_init(&bt_platform_cfg_settings);
wiced_bt_stack_init (app_bt_management_callback, &wiced_bt_cfg_settings);

When you look at these two function calls, you will find that you need to provide three things:

  1. A platform hardware configuration structure called bt_platform_cfg_settings
  2. The Bluetooth stack configuration settings structure called wiced_bt_cfg_settings
  3. A management callback called app_bt_management_callback

bt_platform_cfg_settings

The purpose of the hardware configuration structure is to define the UART + parameters and the wakeup GPIOs.  Specifically, the hardware configuration structure defines the configuration of the host controller interface (hci)

  1. The HCI transport scheme (in this case UART)
  2. The pins of the UART
  3. Baud Rate
  4. Data Bits
  5. Stop Bits
  6. Parity
  7. Flow Control

And the controller low power behavior (in the .controller_config member)

This is a fairly standard configuration and I think that we should help you by providing this structure somewhere in the BSP.  But for now, you need to provide it (in an upcoming article I’ll update the IoT Expert Bluetooth Library to provide it).  Here is the specific structure that I will be using.

const cybt_platform_config_t bt_platform_cfg_settings =
{
.hci_config =
{
.hci_transport = CYBT_HCI_UART,
.hci =
{
.hci_uart =
{
.uart_tx_pin = CYBSP_BT_UART_TX,
.uart_rx_pin = CYBSP_BT_UART_RX,
.uart_rts_pin = CYBSP_BT_UART_RTS,
.uart_cts_pin = CYBSP_BT_UART_CTS,
.baud_rate_for_fw_download = 115200,
.baud_rate_for_feature     = 115200,
.data_bits = 8,
.stop_bits = 1,
.parity = CYHAL_UART_PARITY_NONE,
.flow_control = WICED_TRUE
}
}
},
.controller_config =
{
.bt_power_pin      = CYBSP_BT_POWER,
.sleep_mode =
{
#if (bt_0_power_0_ENABLED == 1) /* BT Power control is enabled in the LPA */
#if (CYCFG_BT_LP_ENABLED == 1) /* Low power is enabled in the LPA, use the LPA configuration */
.sleep_mode_enabled = true,
.device_wakeup_pin = CYCFG_BT_DEV_WAKE_GPIO,
.host_wakeup_pin = CYCFG_BT_HOST_WAKE_GPIO,
.device_wake_polarity = CYCFG_BT_DEV_WAKE_POLARITY,
.host_wake_polarity = CYCFG_BT_HOST_WAKE_IRQ_EVENT
#else /* Low power is disabled in the LPA, disable low power */
.sleep_mode_enabled = false
#endif
#else /* BT Power control is disabled in the LPA – default to BSP low power configuration */
.sleep_mode_enabled = true,
.device_wakeup_pin = CYBSP_BT_DEVICE_WAKE,
.host_wakeup_pin = CYBSP_BT_HOST_WAKE,
.device_wake_polarity = CYBT_WAKE_ACTIVE_LOW,
.host_wake_polarity = CYBT_WAKE_ACTIVE_LOW
#endif
}
},
.task_mem_pool_size    = 2048
};

wiced_bt_cfg_settings

The Cypress WICED Bluetooth Stack has a boatload of configuration settings.  When you call the stack start function you need to provide all of those settings in a structure of type “wiced_bt_cfg_settings_t” which is actually a structure of structures.  There are several basic ways to set these settings

  • Start from scratch and build you own settings
  • Copy from an example project
  • Use the Bluetooth Configurator to generate the structure

For the purposes of THIS project I started by copying the structure from on of the example projects and then modifying the three numbers that were relevant to me.  Specifically

  • max_simultanous_link – which I changed to 0 because this is simply a Bluetooth Observer
  • low_duty_scan_interval – how long in the window to listen for advertising packets
  • low_duty_scan_window – how wide the window of listening should be
const wiced_bt_cfg_settings_t wiced_bt_cfg_settings =
{
.device_name                         = (uint8_t *)BT_LOCAL_NAME,                                   /**< Local device name (NULL terminated) */
.device_class                        = {0x00, 0x00, 0x00},                                         /**< Local device class */
.security_requirement_mask           = BTM_SEC_NONE,                                               /**< Security requirements mask (BTM_SEC_NONE, or combinination of BTM_SEC_IN_AUTHENTICATE, BTM_SEC_OUT_AUTHENTICATE, BTM_SEC_ENCRYPT (see #wiced_bt_sec_level_e)) */
.max_simultaneous_links              = 0,                                                          /**< Maximum number simultaneous links to different devices */
.ble_scan_cfg =                                                 /* BLE scan settings  */
{
.scan_mode                       = BTM_BLE_SCAN_MODE_PASSIVE,                                  /**< BLE scan mode (BTM_BLE_SCAN_MODE_PASSIVE, BTM_BLE_SCAN_MODE_ACTIVE, or BTM_BLE_SCAN_MODE_NONE) */
/* Advertisement scan configuration */
.high_duty_scan_interval         = WICED_BT_CFG_DEFAULT_HIGH_DUTY_SCAN_INTERVAL,               /**< High duty scan interval */
.high_duty_scan_window           = WICED_BT_CFG_DEFAULT_HIGH_DUTY_SCAN_WINDOW,                 /**< High duty scan window */
.high_duty_scan_duration         = 0,                                                          /**< High duty scan duration in seconds (0 for infinite) */
.low_duty_scan_interval          = 96,                                                         /**< Low duty scan interval  */
.low_duty_scan_window            = 96,                                                         /**< Low duty scan window */
.low_duty_scan_duration          = 0,                                                          /**< Low duty scan duration in seconds (0 for infinite) */
/* Connection scan configuration */
.high_duty_conn_scan_interval    = WICED_BT_CFG_DEFAULT_HIGH_DUTY_CONN_SCAN_INTERVAL,          /**< High duty cycle connection scan interval */
.high_duty_conn_scan_window      = WICED_BT_CFG_DEFAULT_HIGH_DUTY_CONN_SCAN_WINDOW,            /**< High duty cycle connection scan window */
.high_duty_conn_duration         = 0,                                                         /**< High duty cycle connection duration in seconds (0 for infinite) */
.low_duty_conn_scan_interval     = WICED_BT_CFG_DEFAULT_LOW_DUTY_CONN_SCAN_INTERVAL,           /**< Low duty cycle connection scan interval */
.low_duty_conn_scan_window       = WICED_BT_CFG_DEFAULT_LOW_DUTY_CONN_SCAN_WINDOW,             /**< Low duty cycle connection scan window */
.low_duty_conn_duration          = 0,                                                         /**< Low duty cycle connection duration in seconds (0 for infinite) */
/* Connection configuration */
.conn_min_interval               = WICED_BT_CFG_DEFAULT_CONN_MIN_INTERVAL,                     /**< Minimum connection interval */
.conn_max_interval               = WICED_BT_CFG_DEFAULT_CONN_MAX_INTERVAL,                     /**< Maximum connection interval */
.conn_latency                    = WICED_BT_CFG_DEFAULT_CONN_LATENCY,                          /**< Connection latency */
.conn_supervision_timeout        = WICED_BT_CFG_DEFAULT_CONN_SUPERVISION_TIMEOUT,              /**< Connection link supervision timeout */
},
.default_ble_power_level            = 12                                                           /**< Default LE power level, Refer lm_TxPwrTable table for the power range */
};

app_bt_management_callback

The last thing that you need to provide is a management callback.  This function is called by the Bluetooth Stack when a “management event” occurs.  There is a big-long-list of enumerated events of type wiced_bt_management_event_t.  The events include things like the the stack started “BTM_ENABLED_EVENT”.  Each event may have data associated with the event which is passed to you in a pointer to wiced_bt_management_event_data_t.

You typically deal with these events with a giant switch statement like this:

wiced_result_t app_bt_management_callback(wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data)
{
wiced_result_t result = WICED_BT_SUCCESS;
switch (event)
{
case BTM_ENABLED_EVT:
if (WICED_BT_SUCCESS == p_event_data->enabled.status)
{
printf("Stack Started Successfully\n");
}
break;
default:
printf("Unhandled Bluetooth Management Event: 0x%x %s\n", event, btutil_getBTEventName(event));
break;
}
return result;
}

Tasks

The Bluetooth stack on the PSoC6 is operated with two tasks.  Specifically, when you call the wiced_bt_stack_init it will startup:

  1. CYBT_HCI_Task – a task that sends and receives HCI packets going to the Radio chip
  2. CY_BT_Task – a task that manages the Bluetooth Host Stack

Here is print of the task list from my project:

AnyCloud> tasks
Name          State Priority   Stack  Num
------------------------------------------
nt shell        X       0       236     5
IDLE            R       0       115     6
blink           B       0       98      4
CYBT_BT_Task    B       4       1371    2
sleep_task      B       6       217     1
CYBT_HCI_Task   B       5       950     3
Tmr Svc         B       6       76      7
‘B’ – Blocked
‘R’ – Ready
‘D’ – Deleted (waiting clean up)
‘S’ – Suspended, or Blocked without a timeout
Stack = bytes free at highwater

 

Now with the background in place, in the next article I will discuss Bluetooth advertising and how to build the observer project.

Update Project to ModusToolbox 2.2

Summary

This article walks you through the steps that I took to convert a ModusToolbox 2.1 project using the “dot lib” flow into a Modus Toolbox 2.2 project using the “mtb” flow.

Story

I have been working on way way to many different things and not finishing nearly enough things.  Oh well.  One of the projects that I have been working on is an implementation of a Bluetooth Observer to process iBeacon packets from a Tilt Hydrometer (more on that in a future article).  This project was started in Modus Toolbox 2.1.  It will continue to work perfectly in ModusToolbox 2.2 as it is 100% backwards compatible, but, I want to use some of the new features of 2.2.

As I discussed in a previous article, there are now two library systems in Modus Toolbox.

  • The “mtb” flow – which allows for “shared libraries”
  • The “dot lib” flow – which has all libraries embedded into the project.

If you want to convert your Modus Toolbox 2.1 project Modus Toolbox 2.2 you can follow a process like this:

  1. Backup the project into Git
  2. Create a template Modus Toolbox 2.2 project (so I have a “clean” copy of the Makefile and “mtb” files)
  3. Fix the Makefile
  4. Examine and Update the library dependencies
  5. Test

Backup Everything

Before you torch your perfectly good project you should back it up.  I typically use Git.  Actually I always use Git.  As I wrote this article I realized that I should have tagged the version before I started the updates.  To figure out which commit that was I ran a “git log” and then I scrolled through my new commits until I found the last one before the conversion to 2.2.  Which requires me to admit that when I left the project a couple of weeks ago there were two files which I hadn’t checked.  So I blindly checked them in and then told the truth in my comment.

commit c256b822b2c956b17ec6cb35868e171d71dda0fe (HEAD, tag: mtb2.1)
Author: iotexpert <engineer@iotexpert.com>
Date:   Sat Oct 10 06:47:40 2020 -0400
updates which I have no idea what they are

Now that I have the right commit, I tagged with with a “mtb 2.1” tag.

arh (master) TiltHydrometer $ git tag -a "mtb2.1" c256b822b2c956b17ec6cb35868e171d71dda0fe

Now I can go back to my 2.1 project by running “git checkout mtb2.1”

Create a Template Project

In order to use the new flow you need to do two things.

  1. Fix the Makefile
  2. Change the “dot lib” files to “mtb” files

I never can remember the secret incantation to put in either place.  So, I create a blank project called “Simple22” to allow me to steal the bits that I want.

Makefile

In Modus Toolbox 2.2 we added two new variables to the Makefile which allow you to specify the location of the shared library.  First, here is the relevant section of the original 2.1 Makefile

################################################################################
# Paths
################################################################################
# Relative path to the project directory (default is the Makefile's directory).
#
# This controls where automatic source code discovery looks for code.
CY_APP_PATH=
# Relative path to the "base" library. It provides the core makefile build
# infrastructure.
CY_BASELIB_PATH=libs/psoc6make
# Absolute path to the compiler's "bin" directory.
#
# The default depends on the selected TOOLCHAIN (GCC_ARM uses the ModusToolbox
# IDE provided compiler by default).
CY_COMPILER_PATH=

And the new 2.2 Makefile where you can see the two new variables

  • CY_GETLIBS_SHARED_PATH=../
  • CY_GETLIBS_SHARED_NAME=mtb_shared
################################################################################
# Paths
################################################################################
# Relative path to the project directory (default is the Makefile's directory).
#
# This controls where automatic source code discovery looks for code.
CY_APP_PATH=
# Relative path to the shared repo location.
#
# All .mtb files have the format, <URI>#<COMMIT>#<LOCATION>. If the <LOCATION> field 
# begins with $$ASSET_REPO$$, then the repo is deposited in the path specified by 
# the CY_GETLIBS_SHARED_PATH variable. The default location is one directory level 
# above the current app directory.
# This is used with CY_GETLIBS_SHARED_NAME variable, which specifies the directory name.
CY_GETLIBS_SHARED_PATH=../
# Directory name of the shared repo location.
#
CY_GETLIBS_SHARED_NAME=mtb_shared

Dependencies & Libraries

The next thing to do is look at what libraries are in my original project.  To do this run the Library manager via “make modlibs”

All of these libraries are added to the project by creating “dot Libs” in the “deps” directory.  Specifically as I worked on the original project I added the libraries using the library manager, which created a dot lib for each library.  Here is a look at the original “deps” directory.

arh (master) TiltHydrometer $ ls deps
CY8CKIT-028-TFT.lib		abstraction-rtos.lib		display-tft-st7789v.lib		middleware-ntshell.lib		sensor-motion-bmi160.lib
TARGET_CY8CKIT-062S2-43012.lib	audio-codec-ak4954a.lib		emwin.lib			retarget-io.lib
TARGET_CY8CPROTO-062-4343W.lib	bluetooth-freertos.lib		freertos.lib			sensor-light.lib

When I did an “update” in Modus Toolbox 2.1 it ran “make depend” which brought in the libraries specified by the the “dot libs” into the “libs” directory.  Here it is a listing of the lib directory.

arh (master) TiltHydrometer $ ls libs
TARGET_CY8CKIT-062S2-43012	btstack.mtb			core-lib.mtb			mtb-hal-cat1.mtb		psoc6make
TARGET_CY8CPROTO-062-4343W	capsense			core-make.mtb			mtb-pdl-cat1.mtb		psoc6pdl
abstraction-rtos		capsense.mtb			display-tft-st7789v		mtb.mk				recipe-make-cat1a.mtb
abstraction-rtos.mtb		clib-support			emwin				psoc6cm0p			retarget-io
bluetooth-freertos		clib-support.mtb		freertos			psoc6cm0p.mtb
btstack				core-lib			middleware-ntshell		psoc6hal
arh (master) TiltHydrometer $

Now take the dramatic step of:

  • rm deps/*
  • rm -rf libs

I decided that the easiest thing to do to create the “mtb” files was to run the library manager.  But, with nothing in the deps directory, the library manager doesn’t know what to do.

arh (master *) TiltHydrometer $ make modlibs
Tools Directory: /Applications/ModusToolbox/tools_2.2
/Applications/ModusToolbox/tools_2.2/make/startex.mk:380: *** Build support for the target device not found. Run "make getlibs" to ensure all required build and code dependencies are present..  Stop.
arh (master *) TiltHydrometer $ 

So, I copy the target file from the Simple22 project.

arh (master *) TiltHydrometer $ cp ../Simple22/deps/TARGET_CY8CKIT-062S2-43012.mtb deps
arh (master *) TiltHydrometer $ more deps/TARGET_CY8CKIT-062S2-43012.mtb 
https://github.com/cypresssemiconductorco/TARGET_CY8CKIT-062S2-43012#latest-v2.X#$$ASSET_REPO$$/TARGET_CY8CKIT-062S2-43012/latest-v2.X

I was sure that I would be able to run the library manager now.  But it gave me the bird.  At least it gave me the hint of running “make getlibs” first.  Which I do:

arh (master *) TiltHydrometer $ make modlibs
Tools Directory: /Applications/ModusToolbox/tools_2.2
/Applications/ModusToolbox/tools_2.2/make/startex.mk:380: *** Build support for the target device not found. Run "make getlibs" to ensure all required build and code dependencies are present..  Stop.
arh (master *) TiltHydrometer $ make getlibs
Tools Directory: /Applications/ModusToolbox/tools_2.2
==============================================================================
= Importing libraries =
==============================================================================
Git is git version 2.24.3 (Apple Git-128), found at /usr/bin/git
Resolving dependencies...
QNetworkReplyHttpImplPrivate::_q_startOperation was called more than once QUrl("https://github.com/iotexpert/mtb2-iotexpert-manifests/raw/master/iotexpert-super-manifest.xml")
/Users/arh/proj/TiltHydrometer/libs/capsense.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/core-lib.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/core-make.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/mtb-hal-cat1.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/mtb-pdl-cat1.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/psoc6cm0p.mtb was added or updated
/Users/arh/proj/TiltHydrometer/libs/recipe-make-cat1a.mtb was added or updated
Dependencies resolved.
Searching application directory (.mtb)...
Found 8 .mtb file(s)
Processing file "/Users/arh/proj/TiltHydrometer/deps/TARGET_CY8CKIT-062S2-43012.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/capsense.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/core-lib.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/core-make.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/mtb-hal-cat1.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/mtb-pdl-cat1.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/psoc6cm0p.mtb"
Processing file "/Users/arh/proj/TiltHydrometer/libs/recipe-make-cat1a.mtb"
Libraries processed.
Created file "/Users/arh/proj/TiltHydrometer/libs/mtb.mk".
==============================================================================
= Import complete =
==============================================================================
arh (master *) TiltHydrometer $ 

Now when I run “make modlibs” I can click on all of the libraries that I used in my project.

Once I click go.  It brings in all of the needed libraries.  Look at the “deps” directory now.  We are rocking.

arh (master *) TiltHydrometer $ ls deps
TARGET_CY8CKIT-062S2-43012.mtb	display-tft-st7789v.mtb		freertos.mtb			retarget-io.mtb
bluetooth-freertos.mtb		emwin.mtb			middleware-ntshell.mtb
arh (master *) TiltHydrometer $ cat deps/*
https://github.com/cypresssemiconductorco/TARGET_CY8CKIT-062S2-43012#latest-v2.X#$$ASSET_REPO$$/TARGET_CY8CKIT-062S2-43012/latest-v2.X
https://github.com/cypresssemiconductorco/bluetooth-freertos#latest-v1.X#$$ASSET_REPO$$/bluetooth-freertos/latest-v1.X
https://github.com/cypresssemiconductorco/display-tft-st7789v#latest-v1.X#$$ASSET_REPO$$/display-tft-st7789v/latest-v1.X
https://github.com/cypresssemiconductorco/emwin#latest-v5.X#$$ASSET_REPO$$/emwin/latest-v5.X
https://github.com/cypresssemiconductorco/freertos#latest-v10.X#$$ASSET_REPO$$/freertos/latest-v10.X
https://github.com/iotexpert/middleware-ntshell#latest-v2.X#$$ASSET_REPO$$/middleware-ntshell/latest-v2.X
https://github.com/cypresssemiconductorco/retarget-io#latest-v1.X#$$ASSET_REPO$$/retarget-io/latest-v1.X
arh (master *) TiltHydrometer $

And when I look in the shared library directory which is “../mtb_shared” you can see all of the source files.

arh (master *) TiltHydrometer $ ls ../mtb_shared/
TARGET_CY8CKIT-062S2-43012	capsense			display-tft-st7789v		mtb-hal-cat1			retarget-io
abstraction-rtos		clib-support			emwin				mtb-pdl-cat1
bluetooth-freertos		core-lib			freertos			psoc6cm0p
btstack				core-make			middleware-ntshell		recipe-make-cat1a

Build and Test

All the libraries are now fixed.  So run a “make -j build” and see what we have.

arh (master *) TiltHydrometer $ make -j build
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: mtb-example-psoc6-empty-app Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 237 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 38 .a file(s)
-> Found 665 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 218 file(s)
Compiling app file app_bt_cfg.c
Compiling app file bluetoothManager.c
Compiling app file capsenseManager.c
.... a bunch of compile messages deleted....
Compiling ext file cy_wdt.c
Compiling ext file psoc6_01_cm0p_sleep.c
Compiling ext file psoc6_02_cm0p_sleep.c
Compiling ext file psoc6_03_cm0p_sleep.c
Compiling ext file psoc6_04_cm0p_sleep.c
Compiling ext file cy_retarget_io.c
Linking output file mtb-example-psoc6-empty-app.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  322616     | 
| .ARM.exidx           |  0x10050c38   |  8          | 
| .copy.table          |  0x10050c40   |  24         | 
| .zero.table          |  0x10050c58   |  8          | 
| .data                |  0x080022e0   |  2544       | 
| .cy_sharedmem        |  0x08002cd0   |  8          | 
| .noinit              |  0x08002cd8   |  148        | 
| .bss                 |  0x08002d70   |  40048      | 
| .heap                |  0x0800c9e0   |  990752     | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           333408     
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    
arh (master *) TiltHydrometer $

A functioning project.  Sweet!

ModusToolbox 2.2 Template Project – FreeRTOS + NTShell

Summary

This article discusses the new library structure that was released with ModusToolbox 2.2.  I explain it by showing the creation of a template project that use FreeRTOS and NT Shell.

Story

I have often started projects from the IoT Expert FreeRTOS template project.   I realized the other day that almost always the first thing I do after creating the project is add the NT Shell library.  My friend Hassane has a personal mantra that if he is going to do the same job more than once he will always automate it.  I should have listened to him on this one because I have done it a bunch of times.

In Modus Toolbox 2.2 we have created a new library scheme which allows sharing of libraries between projects.  So this will also be a good example of how that works.

This will also give you another example of adding template projects to your own manifest.

Here is what I am going to do:

  1. Create a project from the IoT Expert FreeRTOS Template
  2. Add the NTShell Library & Examine New Library Structure
  3. Update the Project and Program
  4. Add the Task List functionality (a nice feature of FreeRTOS)
  5. Put the new template on GitHub
  6. Update the IoT Expert App Manifest
  7. Test the new Template

Create & Test a project from the IoT Expert FreeRTOS Template

I will start the whole process by creating  new project using my existing base template.  The kit that I happen to have on my desk right now is the CY8CKIT-062S2-43012.

Select the IoT Expert FreeRTOS Template and give it a name.  Notice that I add “NTShell” to the name (because that is what Im gonna add)

When you click create, Modus will do its magic and build you a complete project.

Today Im going to edit using Visual Studio Code.  Actually almost always I edit using Visual Studio Code.  You can do all of these tasks using Eclipse as well.  To turn my created project into a VSCODE project run “make vscode”

Before getting to far down the road I like to run a build to make sure everything is OK.  So “make -j build”

arh (master) IoT_Expert_FreeRTOS_NTShell_Template $ make -j build
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 195 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 491 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 183 file(s)
Compiling app file lowPower.c
Compiling app file main.c
Compiling ext file startup_psoc6_02_cm4.S
Compiling ext file cy_syslib_gcc.S
Compiling ext file cycfg.c
Compiling ext file cycfg_capsense.c
Compiling ext file cycfg_clocks.c
....a bunch of stuff deleted
Compiling ext file psoc6_04_cm0p_sleep.c
Compiling ext file cy_retarget_io.c
Linking output file MTBShellTemplate.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  30280      | 
| .ARM.exidx           |  0x10009648   |  8          | 
| .copy.table          |  0x10009650   |  24         | 
| .zero.table          |  0x10009668   |  8          | 
| .data                |  0x080022e0   |  1320       | 
| .cy_sharedmem        |  0x08002808   |  8          | 
| .noinit              |  0x08002810   |  148        | 
| .bss                 |  0x080028a4   |  1324       | 
| .heap                |  0x08002dd0   |  1030704    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           39848      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033504    
arh (master) IoT_Expert_FreeRTOS_NTShell_Template $

Then program it, just to make sure.  “make program”

arh (master) IoT_Expert_FreeRTOS_NTShell_Template $ make program
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 195 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 491 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 183 file(s)
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  30280      | 
| .ARM.exidx           |  0x10009648   |  8          | 
| .copy.table          |  0x10009650   |  24         | 
| .zero.table          |  0x10009668   |  8          | 
| .data                |  0x080022e0   |  1320       | 
| .cy_sharedmem        |  0x08002808   |  8          | 
| .noinit              |  0x08002810   |  148        | 
| .bss                 |  0x080028a4   |  1324       | 
| .heap                |  0x08002dd0   |  1030704    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           39848      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033504    
Programming target device... 
Open On-Chip Debugger 0.10.0+dev-4.1.0.1058 (2020-08-11-03:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 2000 kHz
adapter srst delay: 25
adapter srst pulse_width: 25
** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable
cortex_m reset_config sysresetreq
cortex_m reset_config sysresetreq
Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 14672 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 : KitProg3: FW version: 1.14.514
Info : KitProg3: Pipelined transfers disabled, please update the firmware
Info : VTarget = 3.221 V
Info : kitprog3: acquiring the device...
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x6ba02477
Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints
***************************************
** Silicon: 0xE453, Family: 0x102, Rev.: 0x12 (A1)
** Detected Device: CY8C624ABZI-S2D44
** Detected Main Flash size, kb: 2048
** Flash Boot version: 3.1.0.378
** Chip Protection: NORMAL
***************************************
Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for psoc6.cpu.cm0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for psoc6.cpu.cm4 on 3334
Info : Listening on port 3334 for gdb connections
Info : SWD DPIDR 0x6ba02477
Info : kitprog3: acquiring the device...
psoc6.cpu.cm0 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...
psoc6.cpu.cm4 halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800
** Programming Started **
auto erase enabled
Info : Flash write discontinued at 0x1000179c, next section at 0x10002000
Info : Padding image section 0 at 0x1000179c with 100 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
Info : Padding image section 1 at 0x10009ba0 with 96 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
wrote 37888 bytes from file /Users/arh/mtb22/IoT_Expert_FreeRTOS_NTShell_Template/build/CY8CKIT-062S2-43012/Debug/MTBShellTemplate.hex in 1.402638s (26.379 KiB/s)
** Programming Finished **
** Verify Started **
verified 37692 bytes in 0.080973s (454.579 KiB/s)
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x6ba02477
shutdown command invoked
Info : psoc6.dap: powering down debug domain...
Warn : Failed to power down Debug Domains
arh (master) IoT_Expert_FreeRTOS_NTShell_Template $

Add the NTShell Library & Examine New Library Structure

Everything is working and my basic project has FreeRTOS and a blinking LED.  Now let’s add the NT Shell Library.  To do this run the library manager by running “make modlibs” (or click on the button in Eclipse).  Select Libraries –> IoT Expert –> ntshell

When you press update, the library manager will do its thing again.

When I look in the “deps” directory, I see some new file types called “.mtb”.  These files tell your project where to find each of the libraries.  Notice that the middleware-ntshell.mtb points to “$$ASSET_REPO$$”.  Where is that?

If you have a aook at the Makefile it tell you that it is “../” and “mtb_shared”.

# Relative path to the shared repo location.
#
# All .mtb files have the format, <URI><COMMIT><LOCATION>. If the <LOCATION> field 
# begins with $$ASSET_REPO$$, then the repo is deposited in the path specified by 
# the CY_GETLIBS_SHARED_PATH variable. The default location is one directory level 
# above the current app directory.
# This is used with CY_GETLIBS_SHARED_NAME variable, which specifies the directory name.
CY_GETLIBS_SHARED_PATH=../
# Directory name of the shared repo location.
#
CY_GETLIBS_SHARED_NAME=mtb_shared

To start editing I will run Visual Studio Code by typing “code .”.  The first thing that happens is that it notices that this is a workspace instead of just a directory.

And when you look at the workspace you can see that it knows about both the example project as well as “mtb_shared”.  That is sweet.

Update the Project and Program

Now follow the instructions from the middlware-ntshell readme by copying “usrcmd.*” into my project.

arh (master) IoT_Expert_FreeRTOS_NTShell_Template $ cp ../mtb_shared/middleware-ntshell/latest-v2.X/template/psoc6sdk/usrcmd.* .

Then I edit main.c to

  1. #include “usrcmd.h” on line 8
  2. Start the shell task which is called “usrcmd_task” on line 39

Now buid/project by running “make -j program”

arh (master *) IoT_Expert_FreeRTOS_NTShell_Template $ make -j program
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 205 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 503 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 193 file(s)
Compiling app file main.c
Linking output file MTBShellTemplate.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  52780      | 
| .ARM.exidx           |  0x1000ee2c   |  8          | 
| .copy.table          |  0x1000ee34   |  24         | 
| .zero.table          |  0x1000ee4c   |  8          | 
| .data                |  0x080022e0   |  1688       | 
| .cy_sharedmem        |  0x08002978   |  8          | 
| .noinit              |  0x08002980   |  148        | 
| .bss                 |  0x08002a14   |  2136       | 
| .heap                |  0x08003270   |  1029520    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           62716      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    
Programming target device... 
Open On-Chip Debugger 0.10.0+dev-4.1.0.1058 (2020-08-11-03:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 2000 kHz
adapter srst delay: 25
adapter srst pulse_width: 25
** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable
cortex_m reset_config sysresetreq
cortex_m reset_config sysresetreq
Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 14672 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 : KitProg3: FW version: 1.14.514
Info : KitProg3: Pipelined transfers disabled, please update the firmware
Info : VTarget = 3.225 V
Info : kitprog3: acquiring the device...
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x6ba02477
Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints
***************************************
** Silicon: 0xE453, Family: 0x102, Rev.: 0x12 (A1)
** Detected Device: CY8C624ABZI-S2D44
** Detected Main Flash size, kb: 2048
** Flash Boot version: 3.1.0.378
** Chip Protection: NORMAL
***************************************
Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for psoc6.cpu.cm0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for psoc6.cpu.cm4 on 3334
Info : Listening on port 3334 for gdb connections
Info : SWD DPIDR 0x6ba02477
Info : kitprog3: acquiring the device...
psoc6.cpu.cm0 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...
psoc6.cpu.cm4 halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800
** Programming Started **
auto erase enabled
Info : Flash write discontinued at 0x1000179c, next section at 0x10002000
Info : Padding image section 0 at 0x1000179c with 100 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
Info : Padding image section 1 at 0x1000f4f4 with 268 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
wrote 60928 bytes from file /Users/arh/mtb22/IoT_Expert_FreeRTOS_NTShell_Template/build/CY8CKIT-062S2-43012/Debug/MTBShellTemplate.hex in 2.017097s (29.498 KiB/s)
** Programming Finished **
** Verify Started **
verified 60560 bytes in 0.119193s (496.175 KiB/s)
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x6ba02477
shutdown command invoked
Info : psoc6.dap: powering down debug domain...
arh (master *) IoT_Expert_FreeRTOS_NTShell_Template $

Now I have a functional shell.  Here is the serial console.

Add the Task List functionality

In the main.c above I started up the usrcmd_task with a stack size of config_MINIMAL_STACK_SIZE * 4.  Where did I get that?  Well the first couple of times I did this it crashed by running out of stack so I tried bigger and bigger numbers until it stopped crashing.  This is a kind of a pain in the ass.   If you know FreeRTOS there is a function called “vTaskList” which will give you stats about the tasks.

In order to use that function you need to turn it on.  Notice that I #ifdef and #if to see if it is turned on inside of usrcmd.c

#ifdef configUSE_TRACE_FACILITY
#if configUSE_STATS_FORMATTING_FUNCTIONS ==1
static int usrcmd_list(int argc, char **argv);
#endif
#endif

So let’s turn it on by editing “FreeRTOSConfig.h” and enabling the two required defines.

#define configUSE_TRACE_FACILITY					1
#define configUSE_STATS_FORMATTING_FUNCTIONS        1

Now build/program.

arh (master *) IoT_Expert_FreeRTOS_NTShell_Template $ make -j program
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 205 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 503 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 193 file(s)
Compiling app file lowPower.c
Compiling app file main.c
Compiling app file usrcmd.c
Compiling ext file croutine.c
Compiling ext file event_groups.c
Compiling ext file list.c
Compiling ext file heap_1.c
Compiling ext file heap_2.c
Compiling ext file heap_3.c
Compiling ext file heap_4.c
Compiling ext file heap_5.c
Compiling ext file port.c
Compiling ext file queue.c
Compiling ext file stream_buffer.c
Compiling ext file tasks.c
Compiling ext file timers.c
Compiling ext file psoc6_ntshell_port.c
Linking output file MTBShellTemplate.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  54876      | 
| .ARM.exidx           |  0x1000f65c   |  8          | 
| .copy.table          |  0x1000f664   |  24         | 
| .zero.table          |  0x1000f67c   |  8          | 
| .data                |  0x080022e0   |  1688       | 
| .cy_sharedmem        |  0x08002978   |  8          | 
| .noinit              |  0x08002980   |  148        | 
| .bss                 |  0x08002a14   |  2136       | 
| .heap                |  0x08003270   |  1029520    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           64812      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    
Programming target device... 
Open On-Chip Debugger 0.10.0+dev-4.1.0.1058 (2020-08-11-03:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 2000 kHz
adapter srst delay: 25
adapter srst pulse_width: 25
** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable
cortex_m reset_config sysresetreq
cortex_m reset_config sysresetreq
Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 14672 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 : KitProg3: FW version: 1.14.514
Info : KitProg3: Pipelined transfers disabled, please update the firmware
Info : VTarget = 3.220 V
Info : kitprog3: acquiring the device...
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x6ba02477
Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints
***************************************
** Silicon: 0xE453, Family: 0x102, Rev.: 0x12 (A1)
** Detected Device: CY8C624ABZI-S2D44
** Detected Main Flash size, kb: 2048
** Flash Boot version: 3.1.0.378
** Chip Protection: NORMAL
***************************************
Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for psoc6.cpu.cm0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for psoc6.cpu.cm4 on 3334
Info : Listening on port 3334 for gdb connections
Info : SWD DPIDR 0x6ba02477
Info : kitprog3: acquiring the device...
psoc6.cpu.cm0 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...
psoc6.cpu.cm4 halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800
** Programming Started **
auto erase enabled
Info : Flash write discontinued at 0x1000179c, next section at 0x10002000
Info : Padding image section 0 at 0x1000179c with 100 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
Info : Padding image section 1 at 0x1000fd24 with 220 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
wrote 62976 bytes from file /Users/arh/mtb22/IoT_Expert_FreeRTOS_NTShell_Template/build/CY8CKIT-062S2-43012/Debug/MTBShellTemplate.hex in 2.092903s (29.385 KiB/s)
** Programming Finished **
** Verify Started **
verified 62656 bytes in 0.123619s (494.968 KiB/s)
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x6ba02477
shutdown command invoked
Info : psoc6.dap: powering down debug domain...

When I run help you can see I have a new command called “tasks” which lists all of the tasks and their stack high water marks.

Put the Template on GitHub

I am happy with my new template.  So, I go to GitHub and create a new repository.

Then on my current project:

  1. I blow away the git history (didnt really have to do that).
  2. Create a new git repo “git init .”
  3. Add a pointer to GitHub “git remote add….”
  4. Add all of the files “git add *”
  5. Add the .gitignore “git add .gitignore”
  6. Commit the changes “git commit…”
  7. Push it to GitHub “git push …”
arh (master *) IoT_Expert_FreeRTOS_NTShell_Template $ rm -rf .git
arh IoT_Expert_FreeRTOS_NTShell_Template $ git init .
Initialized empty Git repository in /Users/arh/mtb22/IoT_Expert_FreeRTOS_NTShell_Template/.git/
arh (master #) IoT_Expert_FreeRTOS_NTShell_Template $ git remote add origin git@iotexpert.github.com:iotexpert/mtb2-freertos-ntshell-template.git
arh (master #) IoT_Expert_FreeRTOS_NTShell_Template $ git add * 
The following paths are ignored by one of your .gitignore files:
build
Use -f if you really want to add them.
arh (master #) IoT_Expert_FreeRTOS_NTShell_Template $ git add .gitignore
arh (master #) IoT_Expert_FreeRTOS_NTShell_Template $ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file:   .gitignore
new file:   FreeRTOSConfig.h
new file:   LICENSE
new file:   MTBShellTemplate.code-workspace
new file:   Makefile
new file:   README.md
new file:   deps/TARGET_CY8CKIT-062S2-43012.mtb
new file:   deps/freertos.mtb
new file:   deps/middleware-ntshell.mtb
new file:   deps/retarget-io.mtb
new file:   global.h
new file:   lowPower.c
new file:   main.c
new file:   openocd.tcl
new file:   usrcmd.c
new file:   usrcmd.h
Untracked files:
(use "git add <file>..." to include in what will be committed)
.vscode/
arh (master #) IoT_Expert_FreeRTOS_NTShell_Template $ git commit -m "Initial commit"
[master (root-commit) 26b5d3c] Initial commit
16 files changed, 994 insertions(+)
create mode 100644 .gitignore
create mode 100644 FreeRTOSConfig.h
create mode 100644 LICENSE
create mode 100644 MTBShellTemplate.code-workspace
create mode 100644 Makefile
create mode 100644 README.md
create mode 100644 deps/TARGET_CY8CKIT-062S2-43012.mtb
create mode 100644 deps/freertos.mtb
create mode 100644 deps/middleware-ntshell.mtb
create mode 100644 deps/retarget-io.mtb
create mode 100644 global.h
create mode 100644 lowPower.c
create mode 100644 main.c
create mode 100644 openocd.tcl
create mode 100644 usrcmd.c
create mode 100644 usrcmd.h
arh (master) IoT_Expert_FreeRTOS_NTShell_Template $ git push -u origin master
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 12 threads
Compressing objects: 100% (19/19), done.
Writing objects: 100% (19/19), 16.21 KiB | 5.40 MiB/s, done.
Total 19 (delta 0), reused 0 (delta 0)
To iotexpert.github.com:iotexpert/mtb2-freertos-ntshell-template.git
* [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
arh (master) IoT_Expert_FreeRTOS_NTShell_Template $

Update the Manifests

To get access to the new template I need to add it to the IoT Expert App Manifest.  I edit the xml file to have the new app

<apps>
<app>
<name>IoT Expert FreeRTOS Template</name>
<id>mtb2-freertos-template</id>
<uri>https://github.com/iotexpert/mtb2-freertos-template</uri>
<description>This template provide a starting point for FreeRTOS projects.  Including a starting blinking LED task</description>
<req_capabilities>psoc6</req_capabilities>
<versions>
<version>
<num>Latest 1.X release</num>
<commit>master</commit>
</version>
</versions>
</app>
<app>
<name>IoT Expert FreeRTOS NTShell Template</name>
<id>mtb2-freertos-ntshell-template</id>
<uri>https://github.com/iotexpert/mtb2-freertos-ntshell-template</uri>
<description>This template provide a starting point for FreeRTOS projects.  Including a starting blinking LED task and shell</description>
<req_capabilities>psoc6</req_capabilities>
<versions>
<version>
<num>Latest 1.X release</num>
<commit>master</commit>
</version>
</versions>
</app>
</apps>

Now I need to git add, git commit and git push it to GitHub.

arh (master) mtb2-iotexpert-manifests $ code .
arh (master) mtb2-iotexpert-manifests $ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified:   iotexpert-app-manifest.xml
no changes added to commit (use "git add" and/or "git commit -a")
arh (master *) mtb2-iotexpert-manifests $ git add iotexpert-app-manifest.xml
arh (master +) mtb2-iotexpert-manifests $ git commit -m "Updated with ntshell example"
[master 47a7bb1] Updated with ntshell example
1 file changed, 13 insertions(+)
arh (master) mtb2-iotexpert-manifests $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 554 bytes | 554.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To iotexpert.github.com:iotexpert/mtb2-iotexpert-manifests.git
28ed2d0..47a7bb1  master -> master

Test the new Template

Everything should be working so make a new project.

Cool.  There is the new template.

When I program it… everything is cool.

arh (master) TestNTS $ make -j program
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Prebuild operations complete
Commencing build operations...
Tools Directory: /Applications/ModusToolbox/tools_2.2
CY8CKIT-062S2-43012.mk: ../mtb_shared/TARGET_CY8CKIT-062S2-43012/latest-v2.X/CY8CKIT-062S2-43012.mk
Initializing build: MTBShellTemplate Debug CY8CKIT-062S2-43012 GCC_ARM
Auto-discovery in progress...
-> Found 205 .c file(s)
-> Found 46 .S file(s)
-> Found 23 .s file(s)
-> Found 0 .cpp file(s)
-> Found 0 .o file(s)
-> Found 6 .a file(s)
-> Found 503 .h file(s)
-> Found 0 .hpp file(s)
-> Found 0 resource file(s)
Applying filters...
Auto-discovery complete
Constructing build rules...
Build rules construction complete
==============================================================================
= Building application =
==============================================================================
Generating compilation database file...
-> ./build/compile_commands.json
Compilation database file generation complete
Building 193 file(s)
Compiling app file lowPower.c
Compiling app file main.c
Compiling app file usrcmd.c
Compiling ext file startup_psoc6_02_cm4.S
Compiling ext file cy_syslib_gcc.S
Compiling ext file cycfg.c
Compiling ext file cycfg_capsense.c
Compiling ext file cycfg_clocks.c
Compiling ext file cycfg_peripherals.c
Compiling ext file cycfg_pins.c
Compiling ext file cycfg_qspi_memslot.c
Compiling ext file cycfg_routing.c
Compiling ext file cycfg_system.c
Compiling ext file system_psoc6_cm4.c
Compiling ext file cybsp.c
Compiling ext file cy_capsense_centroid.c
Compiling ext file cy_capsense_control.c
Compiling ext file cy_capsense_csd.c
Compiling ext file cy_capsense_csx.c
Compiling ext file cy_capsense_filter.c
Compiling ext file cy_capsense_processing.c
Compiling ext file cy_capsense_selftest.c
Compiling ext file cy_capsense_sensing.c
Compiling ext file cy_capsense_structure.c
Compiling ext file cy_capsense_tuner.c
Compiling ext file croutine.c
Compiling ext file event_groups.c
Compiling ext file list.c
Compiling ext file heap_1.c
Compiling ext file heap_2.c
Compiling ext file heap_3.c
Compiling ext file heap_4.c
Compiling ext file heap_5.c
Compiling ext file port.c
Compiling ext file queue.c
Compiling ext file stream_buffer.c
Compiling ext file tasks.c
Compiling ext file timers.c
Compiling ext file ntlibc.c
Compiling ext file ntshell.c
Compiling ext file text_editor.c
Compiling ext file text_history.c
Compiling ext file vtrecv.c
Compiling ext file vtsend.c
Compiling ext file psoc6_ntshell_port.c
Compiling ext file ntopt.c
Compiling ext file ntstdio.c
Compiling ext file cyhal_adc.c
Compiling ext file cyhal_analog_common.c
Compiling ext file cyhal_clock.c
Compiling ext file cyhal_comp.c
Compiling ext file cyhal_comp_ctb.c
Compiling ext file cyhal_comp_lp.c
Compiling ext file cyhal_crc.c
Compiling ext file cyhal_crypto_common.c
Compiling ext file cyhal_dac.c
Compiling ext file cyhal_deprecated.c
Compiling ext file cyhal_dma.c
Compiling ext file cyhal_dma_dmac.c
Compiling ext file cyhal_dma_dw.c
Compiling ext file cyhal_ezi2c.c
Compiling ext file cyhal_flash.c
Compiling ext file cyhal_gpio.c
Compiling ext file cyhal_hwmgr.c
Compiling ext file cyhal_i2c.c
Compiling ext file cyhal_i2s.c
Compiling ext file cyhal_interconnect.c
Compiling ext file cyhal_lptimer.c
Compiling ext file cyhal_not_implemented.c
Compiling ext file cyhal_opamp.c
Compiling ext file cyhal_pdmpcm.c
Compiling ext file cyhal_pwm.c
Compiling ext file cyhal_qspi.c
Compiling ext file cyhal_rtc.c
Compiling ext file cyhal_scb_common.c
Compiling ext file cyhal_sdhc.c
Compiling ext file cyhal_spi.c
Compiling ext file cyhal_syspm.c
Compiling ext file cyhal_system.c
Compiling ext file cyhal_tcpwm_common.c
Compiling ext file cyhal_timer.c
Compiling ext file cyhal_trng.c
Compiling ext file cyhal_uart.c
Compiling ext file cyhal_udb_sdio.c
Compiling ext file cyhal_usb_dev.c
Compiling ext file cyhal_utils.c
Compiling ext file cyhal_wdt.c
Compiling ext file cyhal_psoc6_01_104_m_csp_ble.c
Compiling ext file cyhal_psoc6_01_104_m_csp_ble_usb.c
Compiling ext file cyhal_psoc6_01_116_bga_ble.c
Compiling ext file cyhal_psoc6_01_116_bga_usb.c
Compiling ext file cyhal_psoc6_01_124_bga.c
Compiling ext file cyhal_psoc6_01_124_bga_sip.c
Compiling ext file cyhal_psoc6_01_43_smt.c
Compiling ext file cyhal_psoc6_01_68_qfn_ble.c
Compiling ext file cyhal_psoc6_01_80_wlcsp.c
Compiling ext file cyhal_psoc6_02_100_wlcsp.c
Compiling ext file cyhal_psoc6_02_124_bga.c
Compiling ext file cyhal_psoc6_02_128_tqfp.c
Compiling ext file cyhal_psoc6_02_68_qfn.c
Compiling ext file cyhal_psoc6_03_100_tqfp.c
Compiling ext file cyhal_psoc6_03_49_wlcsp.c
Compiling ext file cyhal_psoc6_03_68_qfn.c
Compiling ext file cyhal_psoc6_04_64_tqfp.c
Compiling ext file cyhal_psoc6_04_68_qfn.c
Compiling ext file cyhal_psoc6_04_80_tqfp.c
Compiling ext file cyhal_triggers_psoc6_01.c
Compiling ext file cyhal_triggers_psoc6_02.c
Compiling ext file cyhal_triggers_psoc6_03.c
Compiling ext file cyhal_triggers_psoc6_04.c
Compiling ext file cy_ble_clk.c
Compiling ext file cy_canfd.c
Compiling ext file cy_crypto.c
Compiling ext file cy_crypto_core_aes_v1.c
Compiling ext file cy_crypto_core_aes_v2.c
Compiling ext file cy_crypto_core_cmac_v1.c
Compiling ext file cy_crypto_core_cmac_v2.c
Compiling ext file cy_crypto_core_crc_v1.c
Compiling ext file cy_crypto_core_crc_v2.c
Compiling ext file cy_crypto_core_des_v1.c
Compiling ext file cy_crypto_core_des_v2.c
Compiling ext file cy_crypto_core_ecc_domain_params.c
Compiling ext file cy_crypto_core_ecc_ecdsa.c
Compiling ext file cy_crypto_core_ecc_key_gen.c
Compiling ext file cy_crypto_core_ecc_nist_p.c
Compiling ext file cy_crypto_core_hmac_v1.c
Compiling ext file cy_crypto_core_hmac_v2.c
Compiling ext file cy_crypto_core_hw.c
Compiling ext file cy_crypto_core_hw_v1.c
Compiling ext file cy_crypto_core_mem_v1.c
Compiling ext file cy_crypto_core_mem_v2.c
Compiling ext file cy_crypto_core_prng_v1.c
Compiling ext file cy_crypto_core_prng_v2.c
Compiling ext file cy_crypto_core_rsa.c
Compiling ext file cy_crypto_core_sha_v1.c
Compiling ext file cy_crypto_core_sha_v2.c
Compiling ext file cy_crypto_core_trng_v1.c
Compiling ext file cy_crypto_core_trng_v2.c
Compiling ext file cy_crypto_core_vu.c
Compiling ext file cy_crypto_server.c
Compiling ext file cy_csd.c
Compiling ext file cy_ctb.c
Compiling ext file cy_ctdac.c
Compiling ext file cy_device.c
Compiling ext file cy_dma.c
Compiling ext file cy_dmac.c
Compiling ext file cy_efuse.c
Compiling ext file cy_flash.c
Compiling ext file cy_gpio.c
Compiling ext file cy_i2s.c
Compiling ext file cy_ipc_drv.c
Compiling ext file cy_ipc_pipe.c
Compiling ext file cy_ipc_sema.c
Compiling ext file cy_lpcomp.c
Compiling ext file cy_lvd.c
Compiling ext file cy_mcwdt.c
Compiling ext file cy_pdm_pcm.c
Compiling ext file cy_pra.c
Compiling ext file cy_pra_cfg.c
Compiling ext file cy_profile.c
Compiling ext file cy_prot.c
Compiling ext file cy_rtc.c
Compiling ext file cy_sar.c
Compiling ext file cy_scb_common.c
Compiling ext file cy_scb_ezi2c.c
Compiling ext file cy_scb_i2c.c
Compiling ext file cy_scb_spi.c
Compiling ext file cy_scb_uart.c
Compiling ext file cy_sd_host.c
Compiling ext file cy_seglcd.c
Compiling ext file cy_smartio.c
Compiling ext file cy_smif.c
Compiling ext file cy_smif_memslot.c
Compiling ext file cy_sysanalog.c
Compiling ext file cy_sysclk.c
Compiling ext file cy_sysint.c
Compiling ext file cy_syslib.c
Compiling ext file cy_syspm.c
Compiling ext file cy_systick.c
Compiling ext file cy_tcpwm_counter.c
Compiling ext file cy_tcpwm_pwm.c
Compiling ext file cy_tcpwm_quaddec.c
Compiling ext file cy_tcpwm_shiftreg.c
Compiling ext file cy_trigmux.c
Compiling ext file cy_usbfs_dev_drv.c
Compiling ext file cy_usbfs_dev_drv_io.c
Compiling ext file cy_usbfs_dev_drv_io_dma.c
Compiling ext file cy_wdt.c
Compiling ext file psoc6_01_cm0p_sleep.c
Compiling ext file psoc6_02_cm0p_sleep.c
Compiling ext file psoc6_03_cm0p_sleep.c
Compiling ext file psoc6_04_cm0p_sleep.c
Compiling ext file cy_retarget_io.c
Linking output file MTBShellTemplate.elf
==============================================================================
= Build complete =
==============================================================================
Calculating memory consumption: CY8C624ABZI-S2D44 GCC_ARM -Og
---------------------------------------------------- 
| Section Name         |  Address      |  Size       | 
---------------------------------------------------- 
| .cy_m0p_image        |  0x10000000   |  6044       | 
| .text                |  0x10002000   |  54876      | 
| .ARM.exidx           |  0x1000f65c   |  8          | 
| .copy.table          |  0x1000f664   |  24         | 
| .zero.table          |  0x1000f67c   |  8          | 
| .data                |  0x080022e0   |  1688       | 
| .cy_sharedmem        |  0x08002978   |  8          | 
| .noinit              |  0x08002980   |  148        | 
| .bss                 |  0x08002a14   |  2136       | 
| .heap                |  0x08003270   |  1029520    | 
---------------------------------------------------- 
Total Internal Flash (Available)          2097152    
Total Internal Flash (Utilized)           64812      
Total Internal SRAM (Available)           1046528    
Total Internal SRAM (Utilized with heap)  1033500    
Programming target device... 
Open On-Chip Debugger 0.10.0+dev-4.1.0.1058 (2020-08-11-03:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 2000 kHz
adapter srst delay: 25
adapter srst pulse_width: 25
** Auto-acquire enabled, use "set ENABLE_ACQUIRE 0" to disable
cortex_m reset_config sysresetreq
cortex_m reset_config sysresetreq
Info : Using CMSIS loader 'CY8C6xxA_SMIF' for bank 'psoc6_smif0_cm0' (footprint 14672 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 : KitProg3: FW version: 1.14.514
Info : KitProg3: Pipelined transfers disabled, please update the firmware
Info : VTarget = 3.221 V
Info : kitprog3: acquiring the device...
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x6ba02477
Info : psoc6.cpu.cm0: hardware has 4 breakpoints, 2 watchpoints
***************************************
** Silicon: 0xE453, Family: 0x102, Rev.: 0x12 (A1)
** Detected Device: CY8C624ABZI-S2D44
** Detected Main Flash size, kb: 2048
** Flash Boot version: 3.1.0.378
** Chip Protection: NORMAL
***************************************
Info : psoc6.cpu.cm4: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for psoc6.cpu.cm0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for psoc6.cpu.cm4 on 3334
Info : Listening on port 3334 for gdb connections
Info : SWD DPIDR 0x6ba02477
Info : kitprog3: acquiring the device...
psoc6.cpu.cm0 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...
psoc6.cpu.cm4 halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0000012a msp: 0x080ff800
** Programming Started **
auto erase enabled
Info : Flash write discontinued at 0x1000179c, next section at 0x10002000
Info : Padding image section 0 at 0x1000179c with 100 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
Info : Padding image section 1 at 0x1000fd24 with 220 bytes (bank write end alignment)
[100%] [################################] [ Erasing     ]
[100%] [################################] [ Programming ]
wrote 62976 bytes from file /Users/arh/mtb22/TestNTS/build/CY8CKIT-062S2-43012/Debug/MTBShellTemplate.hex in 2.082329s (29.534 KiB/s)
** Programming Finished **
** Verify Started **
verified 62656 bytes in 0.122516s (499.425 KiB/s)
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x6ba02477
shutdown command invoked
Info : psoc6.dap: powering down debug domain...
arh (master) TestNTS $

And the project seems to be doing the needful.

Modus Toolbox 2.1 Released

Summary

Yesterday, the Cypress software team released an update to Modus Toolbox, specifically to the “tools package”.  I am super excited about a bunch of the new features and I thought that I would should show you a few of the updates.  Specifically:

  1. The New Project Wizard
  2. Updated Directory Structure for Projects
  3. Visual Studio Code Integration
  4. Eclipse Integration
  5. Updates to the HAL

New Project Wizard

The first interesting thing about Modus Toolbox is that we designed it to be independent of IDE.  If you want to use Eclipse, OK.  If you want to use Visual Studio Code or IAR or MDK or … that is cool with us as well.  We did tons of work to make sure that our tools are completely independent of the operating system and the IDE.

You can still create your projects from inside of Eclipse from the Quick Panel.

The update in Modus Toolbox 2.1 is that the new project will launch an external project creation tool.

That will look like this:

However, if you want, you can totally ditch Eclipse and start the new project wizard from outside (via the Start menu or the Launchpad).  The new project creation wizard is a stand alone program that is written in C++ program and Qt that works on Mac, Windows, and Linux.  When you run the new project creation tool you will see this (at least on a Mac).  Look, it is exactly the same as the one you get from inside Eclipse (no surprise since it is exactly the same thing)

Notice that there is NO requirement that you run this tool from Eclipse.  On Windows you can find it from the Start menu and on Mac you can find it on the Launchpad (as project-creator).

First pick out a “Kit name” which will select the board support package for your project.  Ill Pick “CY8CKIT-062-WIFI-BT” (because that is what happens to be on my desk and press Next.

When the Project Creator starts it will go to the Cypress GitHub site and load in a file that will tell it all of the example projects and BSPs available.  This means that Cypress can release new BSPs and Example templates without you having to update your version of Modus Toolbox.

I give my example a name of “ExampleMTB21” then pick out the “Empty PSoC6 App” and press Create.


To create a project we basically “git clone” a bunch of different repositories.  So, in the output window, you will mostly see the output of Git doing its thing.

When it is all done you can press “Close”.  Now you can look in the file browser and you will see a complete project.

Updated Directory Structure

When you look at the files inside of a file browser you should notice two things.   First there is a directory called “deps” which has two files called “dot Libs”.  These two files contain URLs to the GitHub repositories for two of the BSPs.  In Modus Toolbox 2.0 we stored the dotLib files in the same directory with the actual libraries.  When you look in the Libs directory you will see the actual libraries which are required to build your project.  The Libs directory is now “Generated Source” which means you can blow it away and it can be re-generated with “make getlibs” (which will read the dotLibs from the Deps directory”

Command Line Interface

If you don’t like IDE’s you can now build and program this with our command line interface by running “make build”

And then you can program your board with “make program”

Visual Studio Code Integration

The command line stuff is cool, but I know that there are tons of people out there who like Visual Studio Code which we we now officially support.  To use it you can run “make vscode” and it will create the files required to use your project in Visual Studio Code.

When I look at the project I see that Modus Toolbox create a directory called “.vscode” which has all of the secret sauce to make Visual Studio Code work.

Now I can run “code .” (on my Mac) to start Visual Studio Code.  Or on a PC you can run Visual Studio Code from the Start and just open the directory.  Notice that when you run the “make vscode” we give you the instructions.  Inside of Visual Studio Code you will see the project.

You can press cmd-shift-b to build the project

Which will send all of the output to the Visual Studio Code console.

And you can then press F5 to start the programmer/debugger

Eclipse Integration

But if you are an Eclipse user where does this leave you?  Notice that you don’t have the Eclipse project files in your project anymore… AHHHHH???!?!?!   Relax.  We still love you.  To get your project back into Eclipse you just need to run “make eclipse” and we will recreate the Eclipse project for you.

If you want to add this to an existing workspace you can run “Import”

Then pick out your directory.

Press “Generate Launches for …” on the Quick Panel.  Then Press Build.

And now you have a fully functioning Modus Toolbox Project inside of your Eclipse workspace.

HAL Updates

Another one of my favorite things was a massive update to the documentation inside of the Hardware Abstraction Layer.  At this point most of the HAL drivers should have Code snippets to give you an example of what to do.

ModusToolbox 2.0 – Libraries an Example for emWin & Super Manifests

Summary

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

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

The Story

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

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

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

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

SSD1306 Driver

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

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

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

#ifndef SSD1306_DRIVER_H
#define SSD1306_DRIVER_H
#include "cyhal.h"
void SSD1306DriverInit(cyhal_i2c_t *obj,uint8_t oledAddress);
void          SSD1306_WriteCommandByte(unsigned char c);
void          SSD1306_WriteDataByte(unsigned char c);
void          SSD1306_WriteDataStream(unsigned char * pData, int NumBytes);
void          SSD1306_ReadDataStream(unsigned char * pData, int NumBytes);
#endif

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

#include "SSD1306Driver.h"
#include "GUI.h"
#include "cyhal.h"
#include "cybsp.h"
#include <stdlib.h>
/*********************************************************************
*
*       Defines: Configuration
*
**********************************************************************
Needs to be adapted to custom hardware.
*/
/* I2C port to communicate with the OLED display controller */
static cyhal_i2c_t *I2C=0;
/* I2C slave address, Command and Data byte prefixes for the display controller */
#define OLED_CONTROL_BYTE_CMD       (0x00)
#define OLED_CONTROL_BYTE_DATA      (0x40)
static uint8_t OLED_I2C_ADDRESS     =    (0x3C);
void SSD1306DriverInit(cyhal_i2c_t *obj,uint8_t oledAddress)
{
CY_ASSERT(obj);
I2C=obj;
if(oledAddress)
OLED_I2C_ADDRESS = oledAddress;
}

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

void SSD1306_WriteCommandByte(unsigned char c)
{
uint8_t buff[2];
/* The first byte of the buffer tells the display that the following byte
is a command */
buff[0] = OLED_CONTROL_BYTE_CMD;
buff[1] = (char)c;
/* Write the buffer to display controller */
cyhal_i2c_master_write(I2C, OLED_I2C_ADDRESS, buff, 2, 0, true);
}

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

void SSD1306_WriteDataByte(unsigned char c)
{
uint8_t buff[2];
/* First byte of the buffer tells the display controller that the following byte
is a data byte */
buff[0] = OLED_CONTROL_BYTE_DATA;
buff[1] = c;
/* Write the buffer to display controller */
cyhal_i2c_master_write(I2C, OLED_I2C_ADDRESS, buff, 2, 0, true);
}

emWin Configuration Files

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

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

GitHub

I checked in all of these files into GitHub at git@github.com:iotexpert/p6sdk-ssd1306-emwin-cyrtos-config.git  Now they can be used as a Modus Toolbox library.

Test Library

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

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

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

Now you have everything setup.  So click “Create”

And our software will do its thing.

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

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

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

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

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

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

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

COMPONENTS=EMWIN_OSNTS FREERTOS

Here is what it looks like in vscode

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

#include "cybsp.h"
#include "GUI.h"
#include "SSD1306Driver.h"
int main(void)
{
/* Set up the device based on configurator selections */
cybsp_init();
cyhal_i2c_t I2C;
/* Configuration to initialize the I2C block */
static cyhal_i2c_cfg_t i2c_config = {
.is_slave = false,
.frequencyhal_hz = 400000
};
cyhal_i2c_init(&I2C, CYBSP_I2C_SDA, CYBSP_I2C_SCL, NULL);
cyhal_i2c_configure(&I2C, &i2c_config);
SSD1306DriverInit(&I2C,0x3C);
GUI_Init();
GUI_SetColor(GUI_WHITE);
GUI_SetBkColor(GUI_BLACK);
GUI_SetFont(GUI_FONT_8_ASCII);
GUI_SetTextAlign(GUI_TA_CENTER);
GUI_DispStringAt("Hello World", GUI_GetScreenSizeX()/2,GUI_GetScreenSizeY()/2 - GUI_GetFontSizeY()/2);
}

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

After building you should have output like this:

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

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

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

OK.  Looks like the library works!

Updating the IoT Expert MTB2 Manifests

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

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

In words you need:

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

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

In my SuperManifest file I create references to the

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

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

<super-manifest>
<board-manifest-list>
</board-manifest-list>
<app-manifest-list>
<app-manifest>
<uri>https://github.com/iotexpert/mtb2-iotexpert-manifests/raw/master/iotexpert-app-manifest.xml</uri>
</app-manifest>
</app-manifest-list>
<board-manifest-list>
</board-manifest-list>
<middleware-manifest-list>
<middleware-manifest>
<uri>https://github.com/iotexpert/mtb2-iotexpert-manifests/raw/master/iotexpert-mw-manifest.xml</uri>
</middleware-manifest>
</middleware-manifest-list>
</super-manifest>

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

  • (The NTSHell) https://github.com/iotexpert/middleware-ntshell
  • (The SSD1306 Middleware in this article) https://github.com/iotexpert/p6sdk-ssd1306-emWin-cyrtos-config

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

<middleware>
<middleware>
<name>ntshell</name>
<id>ntshell</id>
<uri>https://github.com/iotexpert/middleware-ntshell</uri>
<desc>NT Shell</desc>
<category>iotexpert</category>
<req_capabilities>psoc6</req_capabilities>
<versions>
<version>
<num>Latest 1.X release</num>
<commit>master</commit>
<desc>Latest 1.X release</desc>
</version>
</versions>
</middleware>
<middleware>
<name>SSD1306-emwin-cyrtos-config</name>
<id>SSD1306-emwin-cyrtos-config</id>
<uri>https://github.com/iotexpert/p6sdk-ssd1306-emwin-cyrtos-config</uri>
<desc>SSD1306-emwin-cyrtos-config</desc>
<category>iotexpert</category>
<req_capabilities>psoc6</req_capabilities>
<versions>
<version>
<num>Latest 1.X release</num>
<commit>master</commit>
<desc>Latest 1.X release</desc>
</version>
</versions>
</middleware>
</middleware>

You can see that my GitHub repository contains

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

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

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