Mouser PSoC 6 WiFi/BT MBED: L1 Developer Resources

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

This is an index of links to all of the PSoC 6 MCU, CYW4343W & Mbed OS learning resources.  You can click the links to go the website or see screen captures of the resources.

  1. Mbed OS Overview (screen capture only)
  2. Mbed OS Landing Page
  3. Mbed Studio
  4. CY8CPROTO-062-4343W
  5. ModusToolbox Software Environment
  6. PSoC 6 Product Page
  7. WiFi + Bluetooth Combo Product Page
  8. PSoC 6 Documentation
  9. PSoC 6 Community
  10. Wireless Combo Community
  11. CY8CKIT-062-BT-WiFi Development Kit Product Page
  12. CY8CKIT-062-BT-WiFi Development Kit Guide
  13. PSoC 6 Datasheet
  14. CYW4343W Datasheet
  15. PSoC 6 Technical Reference Manuals
  16. PSoC 6 Application Notes
  17. WiFi + Bluetooth Combo Application Notes
  18. PSoC 6 Code Examples
  19. Video Tutorials
  20. PSoC 6 Knowledge Base
  21. Peripheral Driver Library Documentation (Doxygen – screen capture only)
  22. IoT Expert Website

Mbed OS Overview

Mbed OS Landing Page

The link to the Arm Mbed landing page can be found here.

Mbed Studio

The link to Mbed Studio can be found here.

CY8CPROTO-062-4343W Landing Page

The link to the PSoC 6 WiFi-BT Prototyping Kit (CY8CPROTO-062-4343W) can be found here.

ModusToolbox Software Environment

The link to the ModusToolbox Software Environment landing page can be found here.

PSoC 6 Product Page

You can find the PSoC 6 Product landing page for PSoC 6 here

WiFi + Bluetooth Combo Page

You can find the landing page for all Cypress WiFi + Bluetooth combo radios here.

PSoC 6 Documentation

On the PSoC 6 Product Landing page there is a documentation tab that has links to all of the current documentation.

PSoC 6 Community

Cypress has an active development community and forum.  It can be found here.

Wireless WiFi + Bluetooth Combo Community

The forum on the Cypress Developer Community for WiFi + Bluetooth combo radios can be found here.

CY8CKIT-062-WiFi-BT Development Kit Web Page

Every Cypress development kit has a web page that contains all of the information about it, including links to the documentation and store.  The CY8CKIT-062-WiFi-BT kit page is here.

CY8CKIT-062-WiFi-BT Development Kit Guide

You can find the development kit guide here.

PSoC 6 Datasheet

The PSoC 6 Datasheet is available on Cypress.com here.

CYW4343W Datasheet

The CYW4343W datasheet can be found here.

PSoC 6 Technical Reference Manual

Each of the PSoC 6 devices has a lengthy discussion of the Technical Resources.  These documents can be found here

PSoC 6 Application Notes

You can get them all on our website. Here is a link to the filtered list of PSoC 6 Application Notes.

The best application note is always the “Getting Started”.  In this case it is AN210781 “Getting Started with PSoC 6 MCU with Bluetooth Low Energy (BLE) Connectivity”

WiFi + Bluetooth Combo Application Notes

Here is a link to all of the WiFI Bluetooth Combo Application Notes.

Video Tutorials

Cypress has made a bunch of videos that take you step by step through an introduction to PSoC 6.  You can find them on the Cypress training website.

PSoC 6 Knowledge Base

The Cypress technical support team writes “Knowledge Base” articles when there are repeated issues reported by customers.  You can find them here.

Peripheral Driver Library Documentation (Doxygen)

All of the APIs in the PDL are documented in a Doxygen generated HTML document.  You can get there from

  • Help -> Peripheral Driver Library (this link is live only when you have a PSoC 6 project open)
  • Right click on a component -> Open PDL Documentation

Mouser PSoC 6 WiFi/BT MBED: L2 The Blinking Thread

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

Here we are again. The blinking LED.  I always start with a basic Blinking LED project just to make sure that everything is working.  What is everything?  The whole tool flow, from the editor, to the programmer, to the chip to the SDK.  The only thing that will be a little different than usual is that I will run the blinking LED in a thread by itself. This is useful for looking at the development kit and knowing that the RTOS is still running and the blinking LED thread is at least OK even if the rest of your program is trashed.

In each of the following lessons I will add on a new block (or two) into the architecture.  The blocks colored “green” will be the ones that are done in that lesson.  In future lessons the blocks that are blue will be from the previous lessons.

For all of these projects I will be using the Mbed Studio program to create, edit, build and program the development board.

To implement the blinking LED thread I will:

  1. Make a new Mbed OS Program from the blank template
  2. Create & code “blinkThread.h”
  3. Create & code “blinkThread.cpp”
  4. Update main.cpp
  5. Give a Tour of Targets
  6. Compile and Program

Make a new Mbed OS Program from the blank template

Start Mbed Studio.  Then run “File->New Program…”

Mbed Studio will then give you the ability to start with a template project.  To get started use “empty Mbed OS program”.  For each of the projects I will give it a name that corresponds to the lesson number, in this case “mouser-mbed-02”.  When you have all that selected click “Add Program”.

This will create a brand new project for you with Mbed OS setup and a blank main.cpp.

Create & code “blinkThread.h”

In each of the following lessons I will be creating different threads to perform the different pieces of system functionality.  I will put each thread in a separate set of files with the name “functionThread.h” and “functionThread.cpp”.  As I am sure everyone knows, the “dot h” file is supposed to be the public interface to the “dot cpp” file.  In other words that file has all of the functions, objects and variables that other files are allowed to access.

To create a file you “right click” on the project and select “New File”

And then give the file a name.  In this case it will be “blinkThread.h”.

This file will have the guards, to keep it from being included more than once, and just the function prototype for the thread.  In all of the coming lessons I will name the thread “functionThread”.  In this case the function is “blink” so the thread is called “blinkThread”

#ifndef BLINK_THREAD_H
#define BLINK_THREAD_H

void blinkThread();

#endif

Create & code “blinkThread.cpp”

Now I am ready to write the actual function which acts as the blinking LED thread.  Right click on the project and select “New File”

Then give it the name “blinkThread.cpp”.  Just like the “dot h” files, the “dot cpp” files will be named “functionThread.cpp”.  In this case the function is blink so the file will be called “blinkThread.cpp”.

This is a really simple thread.  It wants to talk to the LED on the board.  All Mbed OS development boards are required to have at least one LED and that LED must be named “LED1”.  In reality the LED1 is just a map to the PSoC pin name of “P1_1” (this happens in the BSP/Target – more on this later).

By creating an object of type “DigitalOut” with an initializer argument of “LED1” I will have access to writing 1’s and 0’s to that pin.  Notice that I give the object definition the keyword “static” to limits its scope to this file.

The next thing that I need is the actual function which serves as the thread.  Notice that it is an infinite loop, which just does the following:

1. Inverts led1 by reading the pin, inverting it with the “!”, and then writing it back to the pin.

2. Doing a delay of 500 ms using the Mbed OS library function “sleep_for”.  For those of you who aren’t CPP people the “ThisThread::” just tells the compiler that the sleep_for function is in the namespace “ThisThread”.

#include "mbed.h"
#include "blinkThread.h"


static DigitalOut led1(LED1);

void blinkThread()
{
 
    while (true) 
    {
        led1 = !led1;
        ThisThread::sleep_for(500);
    }
}

Update main.cpp

In each of the following lessons, each time I create a new file, I will be making the same basic change to main.cpp.  Specifically I will startup the thread when the main function starts.  To do this:

  1. Include the new “functionThread.h” (in this case “blinkThread.h”).
  2. Declare an object to hold the new thread (in this case “blinkThreadHandle”).
  3. Start the thread by calling the start method with a function pointer to the actual thread function (in this case “blinkThread”).
#include "mbed.h"
#include "blinkThread.h"

Thread blinkThreadHandle;

int main()
{

    printf("Started System\n");

    blinkThreadHandle.start(blinkThread);
}

Targets Tour

Mbed OS abstracts all information about a development board into a set of files called the Target. These files reside in the mbed-os/targets directory.  This files are classically called the board support package (BSP).  This including information about which chip, startup code, libraries, and peripherals exist on the board.

In order to build a project you need to tell Mbed OS which target you are using.  This can be done in the Mbed CLI with  “mbed config target CY8CPROTO_062_4343W” or by selecting the correct target in the Mbed Studio IDE.

You should look in the following directories/files:

  1. mbed-os
  2. targets directory
  3. targets.json
  4. TARGET_Cypress directory
  5. One directory per Target

Compile and Program

There are several things that you should notice on the panel to the left of your code.

  1. The active program (this is a drop down menu with each project in your workspace).
  2. Which “target”.  When you plug in the development kit, Mbed Studio will recognize that you have attached a target that it recognizes.
  3. The “hammer” button runs the Build process.
  4. The “play” button runs a “Build” then programs the development kit.

Press the “Play” button to Compile and Program.  And with any luck you should have a blinking LED.

Notice that it compiles a bunch of different files… actually all of the files in mbed-os.  This will take a while on a PC, but is much faster on a Mac or Linux.  This full compile step only needs to happen the first time for a project – each subsequent time will only compile your changes.

Mouser PSoC 6 WiFi/BT MBED: L3 Display Thread

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

In this lesson we will add an output capability to our project.  But what output device?  I am going old school with a serial terminal using VT100 graphics commands.

Here is the update to the architecture.  Notice the new green boxes.

  1. A new thread (called Display Thread)
  2. The Serial terminal
  3. An RTC (the one built into the PSoC 6)
  4. An RTOS Queue called “Display Command Queue”
  5. A function called displaySendUpdateTime (to tell the display to show the time)

The way this will work is a new thread called “displayThread” will be created.  I will have an RTOS queue associated with it.  Tasks that want to display something will push a message into the queue.  The display thread will wait around until some other task pushes a message into the queue.  When another task pushes a message, the displayThread will process the message and “do the needful”.

To implement this I will:

  1. Import from GitHub lesson02
  2. Discuss VT100 Commands
  3. Create & code displayThread.h
  4. Create & code displayThread.cpp
  5. Create & code mbed_app.json
  6. Update blinkThread.cpp
  7. Update main.cpp
  8. Build, Program and Test

Import from GitHub Lesson 02

Mbed Studio can start a new project by “importing” an old project and giving it a new name.  This is a super convenient way for me to build each project for this class on the base of the previous one.  To make this easier for you I save each of these lesson projects on GitHub so you can start from there.

In Mbed Studio use “File->Import Program…”

Give it the path to my github site for the project you want to start from:

https://github.com/iotexpert/mouser-mbed-02.git

And then give it the new name you want for the new project – in this case mouser-mbed-03

After clicking “Add program” you should have a new program called “mouser-mbed-03” and it should be set as the active program.

At this point you could press the play button and get exactly the same behavior as the previous lesson 02.

VT100 Commands

Back in the dark ages when I started programming, most work was done on a “main frame” of some kind or the other.  The two that I used were the PDP-11 and the Prime.  To access these systems you typically used a “Dumb Terminal” attached to the mainframe via a long serial cable.  One of the most used terminals was the VT100 made by Digital Equipment Corporation (DEC).

These terminals could output a fixed width font in about 80 columns and 24 rows.  Basically, the mainframe sent ASCII characters and the terminal would display them.

An interesting feature that was put into these terminals was the ability to take commands and move the cursor around to screen, or clear it, or draw a line or ….

What does that have to do with today?  Simple, the VT100 command set is still used by almost all serial programs on your PC (Putty, etc).  And I am going to use these commands to create a graphical user interface for the thermostat that looks like this:

  • Line 1 will be the current temperature
  • Line 2 will be the setPoint of the thermostat
  • Line 3 will be the time
  • Line 4 will be the status of the system (Heat, Cool or Off)

To use the VT100 commands you just use printf to send them to the serial terminal.  The commands I will use are:

Command ESC Sequence printf
Home ESC [ H printf("\033[H");
Clear Screen ESC [ J printf("\033[2J");
Turn Cursor Off ESC [ ? 25l printf("\033[?25l");
Goto column & row ESC [ column ; row H printf("\033[%d;%dH%s",y,x,buffer);

Add displayThread.h

As in lesson 02 I will create a new thread.  This time the header file will be called “displayThread.h”  Right click and select “New File”

Give it the name “displayThread.h”

This file will:

  1. Guard against multiple include
  2. Provide the function prototype of the thread
  3. Provide four functions to tell the displayThread to write onto the four different lines of the GUI
#ifndef DISPLAY_THREAD_H
#define DISPLAY_THREAD_H

void displayThread();


void displaySendUpdateTemp(float temperature);
void displaySendUpdateTime();
void displaySendUpdateSetPoint(float setPoint);
void displaySendUpdateMode(float mode);

#endif

Add displayThread.cpp

From now on I will just show the file creation.  In this case “displayThread.cpp”

The first part of the file is to specify the queue.  To do this I create a new type called msg_t which will be inserted into the queue (actually a pointer to the msg_t).  The message structure will have two members the “command_t” and a generic floating point variable called “value”.

The Queue and Memory pool will only be accessible inside of this file.  The queue will hold up to 16 “msg_t”.  The MemoryPool is just an easy  way to do memory allocation.

#include "mbed.h"
#include "displayThread.h"

typedef enum {
    CMD_temperature,
    CMD_setPoint,
    CMD_time,
    CMD_mode,
} command_t;


typedef struct {
    command_t cmd;
    float    value;
} msg_t;


static Queue<msg_t, 16> queue;
static MemoryPool<msg_t, 16> mpool;

In order to insert msg_t into the queue I create one function per msg_t that:

  • allocates a new message
  • sets the command
  • sets the value
  • puts the message in the queue

Notice if something goes wrong, I just ignore the problem.  In a real system you would probably want to do something else.

These four functions will actually run inside of the thread that calls them, but they will insert messages into the queue that the displayThread is processing.  This queue mechanism is a safe way for processes to talk to each other.

// Function called by other threads to queue a temperature change onto the display
void displaySendUpdateTemp(float temperature)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_temperature;
        message->value = temperature;
        queue.put(message);
    }
}

// Function called by other threads to queue display to update time
void displaySendUpdateTime()
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_time;
        message->value = 0;
        queue.put(message);
    }
}

// Function called by other threads to queue a setPoint change onto the display
void displaySendUpdateSetPoint(float setPoint)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPoint;
        message->value = setPoint;
        queue.put(message);
    }
}

// Function called by other threads to queue a setPoint change onto the display
void displaySendUpdateMode(float mode)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_mode;
        message->value = mode;
        queue.put(message);
    }
}

The function displayAtXY creates a string with the VT100 Goto command plus the string that was send.

static void displayAtXY(int x, int y,char *buffer)
{
    // row column
    printf("3[%d;%dH%s",y,x,buffer);
    fflush(stdout);
}

The actual display thread:

  • Clears the screen and turns the cursor off
  • Goes into an infinite loop waiting for messages to be put into the queue
  • When a new message comes in, look at the command
  • sprintf to create the display message
  • print it using the displayAtXY function
void displayThread()
{
    char buffer[128];

    printf("3[2J3[H"); // Clear Screen and go Home
    printf("3[?25l"); // Turn the cursor off
    fflush(stdout);

    while(1)
    {
        osEvent evt = queue.get();
        if (evt.status == osEventMessage) {
            msg_t *message = (msg_t*)evt.value.p;
            switch(message->cmd)
            {
                case CMD_temperature:
                    sprintf(buffer,"Temperature = %2.1fF",message->value);
                    displayAtXY(1, 1, buffer);
                break;
                case CMD_setPoint:
                    sprintf(buffer,"Set Point = %2.1fF",message->value);
                    displayAtXY(1, 2, buffer);
                break;
                case CMD_time:
                    time_t rawtime;
                    struct tm * timeinfo;
                    time (&rawtime);
                    rawtime = rawtime - (5*60*60); // UTC - 4hours ... serious hack which only works in winter
                    timeinfo = localtime (&rawtime);
                    strftime (buffer,sizeof(buffer),"%r",timeinfo);
                    displayAtXY(1,3, buffer);
                break;
                case CMD_mode:
                    if(message->value == 0.0)
                        sprintf(buffer,"Mode = Off ");
                    else if (message->value < 0.0)
                        sprintf(buffer,"Mode = Heat");
                    else
                        sprintf(buffer,"Mode = Cool");
                    displayAtXY(1, 4, buffer);
                break;

            }
            mpool.free(message);

        }
    }
}

Here is the whole file displayThread.cpp (to make a copy/paste easier):

#include "mbed.h"
#include "displayThread.h"

typedef enum {
    CMD_temperature,
    CMD_setPoint,
    CMD_time,
    CMD_mode,
} command_t;


typedef struct {
    command_t cmd;
    float    value;
} msg_t;


static Queue<msg_t, 32> queue;
static MemoryPool<msg_t, 16> mpool;

// Function called by other threads to queue a temperature change onto the display
void displaySendUpdateTemp(float temperature)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_temperature;
        message->value = temperature;
        queue.put(message);
    }
}

// Function called by other threads to queue display to update time
void displaySendUpdateTime()
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_time;
        message->value = 0;
        queue.put(message);
    }
}

// Function called by other threads to queue a setPoint change onto the display
void displaySendUpdateSetPoint(float setPoint)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPoint;
        message->value = setPoint;
        queue.put(message);
    }
}

// Function called by other threads to queue a setPoint change onto the display
void displaySendUpdateMode(float mode)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_mode;
        message->value = mode;
        queue.put(message);
    }
}

static void displayAtXY(int x, int y,char *buffer)
{
    // row column
    printf("3[%d;%dH%s",y,x,buffer);
    fflush(stdout);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////

void displayThread()
{
    char buffer[128];

    printf("3[2J3[H"); // Clear Screen and go Home
    printf("3[?25l"); // Turn the cursor off
    fflush(stdout);

    while(1)
    {
        osEvent evt = queue.get();
        if (evt.status == osEventMessage) {
            msg_t *message = (msg_t*)evt.value.p;
            switch(message->cmd)
            {
                case CMD_temperature:
                    sprintf(buffer,"Temperature = %2.1fF",message->value);
                    displayAtXY(1, 1, buffer);
                break;
                case CMD_setPoint:
                    sprintf(buffer,"Set Point = %2.1fF",message->value);
                    displayAtXY(1, 2, buffer);
                break;
                case CMD_time:
                    time_t rawtime;
                    struct tm * timeinfo;
                    time (&rawtime);
                    rawtime = rawtime - (5*60*60); // UTC - 4hours ... serious hack which only works in winter
                    timeinfo = localtime (&rawtime);
                    strftime (buffer,sizeof(buffer),"%r",timeinfo);
                    displayAtXY(1,3, buffer);
                break;
                case CMD_mode:
                    if(message->value == 0.0)
                        sprintf(buffer,"Mode = Off ");
                    else if (message->value < 0.0)
                        sprintf(buffer,"Mode = Heat");
                    else
                        sprintf(buffer,"Mode = Cool");
                    displayAtXY(1, 4, buffer);
                break;

            }
            mpool.free(message);

        }
    }
}

Create mbed_app.json

By default the serial terminal on Mbed OS is 9600 baud or approximately the same speed as back in VT100 days.  Fortunately you can change that by setting up a global configuration.  To do this you need to create a file called “mbed_app.json”.

In that file, I tell the system that I want 115200 baud for all targets.

{
    "target_overrides": {
        "*": {
            "platform.stdio-baud-rate": 115200
        }
    }
}

Update blinkThread.cpp

In order to test the new displayThread, I will fix up the blinkThread to temporarily send the four messages.

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"

static DigitalOut led1(LED1);

void blinkThread()
{
 
    while (true) 
    {
        led1 = !led1;
        displaySendUpdateTime();
        displaySendUpdateTemp(69.2);
        displaySendUpdateSetPoint(23.5);
        displaySendUpdateMode(-1.0);
        ThisThread::sleep_for(500);
    }
}

Update main.cpp

The last step is to update main to start the new displayThread.

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"

Thread blinkThreadHandle;
Thread displayThreadHandle;

int main()
{

    printf("Started System\n");

    blinkThreadHandle.start(blinkThread);
    displayThreadHandle.start(displayThread);

}

Build, Program and Test

Now press the play button.

One nice thing in Mbed Studio is a built-in serial port viewer.  You can use it by clicking “View -> Serial Monitor”

Change the baud rate to 115200 and you should see something like this:

Mouser PSoC 6 WiFi/BT MBED: L4 Temperature Thread

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

In Lesson 04 I will add temperature sensing to the system.

The new thread called “temperatureThread” acts as the actual guts of the thermostat.  It reads the temperature sensor, keeps track of the setPoint of the system and turns on and off Heat and Cooling.  Notice that it doesn’t know anything about displaying information,  it just uses the functions calls we created for the displayThread.

To implement this I will:

  1. Explain Thermistors
  2. Import lesson03
  3. Create and code temperatureThread.h
  4. Create and code temperatureThread.cpp
  5. Fix blinkThread.cpp
  6. Update main.cpp
  7. Build, Program and Test

Thermistor

On the wing of the CY8CPROTO-062-4343W there is a thermistor that you can use to measure temperature.   What is a thermistor?  It is simply a resistor that changes resistance in a known way based on temperature.

If you know the resistance you can calculate the temperature using the Steinhart-Hart equation.  Here is the Thermistor Wikipedia article.

When you look at the schematic for the development kit you can see how the circuit is attached to the PSoC.

Basically, a known 10K resistor in series with the thermistor with a measurement point between them.  To calculate the resistance of the thermistor you use Ohms low, V=IR.  Or even better R=V/I.

To use this circuit you need to assign a voltage to the THERM_VDD, use a DigialOut to drive 3.3v to that signal and a DigialOut to drive ground to the THERM_GND.

Then use the ADC to find the voltage for THERM_OUT

To do the calculation, first the Thermistor voltage is THERM_VDD-THERM_OUT.

Then you need to get the current.  To do this you calculate the current through the reference resistor I=V/R or I=(THERM_OUT/10K).  This will be the same current as the Thermistor.

Now you can calculate the thermistor resistance.

Here is a picture of the thermistor on the board.

Here is the code that implements the thermistor measurement.

static DigitalOut thermVDD(P10_3,1);
static DigitalOut thermGND(P10_0,0);
static AnalogIn thermOut(P10_1);

static void readTemp()
{
    float refVoltage = thermOut.read() * 2.4; // Range of ADC 0->2*Vref
    float refCurrent = refVoltage  / 10000.0; // 10k Reference Resistor
    float thermVoltage = 3.3 - refVoltage;    // Assume supply voltage is 3.3v
    float thermResistance = thermVoltage / refCurrent; 
    float logrT = (float32_t)log((float64_t)thermResistance);

    /* Calculate temperature from the resistance of thermistor using Steinhart-Hart Equation */
    float stEqn = (float32_t)((0.0009032679) + ((0.000248772) * logrT) + 
                             ((2.041094E-07) * pow((float64)logrT, (float32)3)));

    float temperatureC = (float32_t)(((1.0 / stEqn) - 273.15)  + 0.5);
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}

Import Lesson 03

To build the project, start by importing Lesson 03:

https://github.com/iotexpert/mouser-mbed-03.git

Give it a new name of “mouser-mbed-04”:

Create and code temperatureThread.h

As before we want a thread for the temperature system called “temperatureThread.h”.  Create the “dot h”:

This file will just declare the thread and interface functions.

#ifndef TEMPERATURE_H
#define TEMPERATURE_H

void temperatureThread();

void tempSendUpdateSetpointF(float setPoint);
void tempSendDeltaSetpointF(float delta);


#endif

Create and code temperatureThread.cpp

Now we need the actual thread.  Make the new file “temperatureThread.cpp”

This thread will have two state variables.  One for temperatureF and one for the setPoint of the thermostat.

This thread will also have a queue just like the displayThread.  This queue will be used to let other parts of the system change the setPoint. One command to make a “delta” change  e.g. “go up 1 degree” and one command to make an absolute change e.g “set to 78 degrees”

#include "mbed.h"
#include "temperatureThread.h"
#include "displayThread.h"

static float temperatureF;
static float setPoint = 75.0;

static void readTemp();

typedef enum {
    CMD_setPointDelta,
    CMD_setPoint,

} command_t;


typedef struct {
    command_t cmd;
    float    value;   /* AD result of measured voltage */
} msg_t;

As before to make things easier for the other parts of the system to send messages to the queue, I create functions to send the two commands.

void tempSendDeltaSetpointF(float delta)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPointDelta;
        message->value = delta;
        queue.put(message);
    }
}

void tempSendUpdateSetpointF(float setPoint)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPoint;
        message->value = setPoint;
        queue.put(message);
    }
}

Now you need the function to read the temperature and update the state variable temperatureF

static DigitalOut thermVDD(P10_3,1);
static DigitalOut thermGND(P10_0,0);
static AnalogIn thermOut(P10_1);

static void readTemp()
{
    float refVoltage = thermOut.read() * 2.4; // Range of ADC 0->2*Vref
    float refCurrent = refVoltage  / 10000.0; // 10k Reference Resistor
    float thermVoltage = 3.3 - refVoltage;    // Assume supply voltage is 3.3v
    float thermResistance = thermVoltage / refCurrent; 
    float logrT = (float32_t)log((float64_t)thermResistance);

    /* Calculate temperature from the resistance of thermistor using Steinhart-Hart Equation */
    float stEqn = (float32_t)((0.0009032679) + ((0.000248772) * logrT) + 
                             ((2.041094E-07) * pow((float64)logrT, (float32)3)));

    float temperatureC = (float32_t)(((1.0 / stEqn) - 273.15)  + 0.5);
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}

The temperatureThread listens for messages to be put into the queue.  It then processes them by either increment/decrement of the setPoint or by setting an absolute setPoint.

Also, the queue wait will timeout every 200ms and when that happens it will read the temperature and update the display.

It will also send the cool, heat or off based on a +- 0.5 degree difference from the setPoint.  In other words:

  • temperatureF > setPoint + 0.5 = cool
  • temperatureF < setPoint -0.5 = heat
  • Otherwise OFF
void temperatureThread()
{

    char buffer[128];
    displaySendUpdateTemp(temperatureF);
    displaySendUpdateSetPoint(setPoint);
    
    while(1)
    {
        osEvent evt = queue.get(200);
        if (evt.status == osEventMessage) {
            msg_t *message = (msg_t*)evt.value.p;
            switch(message->cmd)
            {
                case CMD_setPointDelta:
                    setPoint += message->value;
                    displaySendSetPoint(setPoint);
                break;
                case CMD_setPoint:
                    setPoint = message->value;
                    displaySendUpdateSetPoint(setPoint);
                break;

            }
            mpool.free(message);

        }
        else
        {
            readTemp();

            // Control the HVAC system with +- 0.5 degree of Hystersis
            if(temperatureF < setPoint - 0.5)
                displaySendUpdateMode(-1.0);
            else if (temperatureF > setPoint + 0.5)
                displaySendUpdateMode(1.0);
            else
                displaySendUpdateMode(0.0);

            displaySendUpdateTemp(temperatureF); 
        }
    }

}

The whole file (to make the copy/paste easier):

#include "mbed.h"
#include "temperatureThread.h"
#include "displayThread.h"

static float temperatureF;
static float setPoint = 75.0;

static void readTemp();

typedef enum {
    CMD_setPointDelta,
    CMD_setPoint,

} command_t;


typedef struct {
    command_t cmd;
    float    value;   /* AD result of measured voltage */
} msg_t;


static Queue<msg_t, 32> queue;
static MemoryPool<msg_t, 16> mpool;

void tempSendDeltaSetpointF(float delta)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPointDelta;
        message->value = delta;
        queue.put(message);
    }
}

void tempSendUpdateSetpointF(float setPoint)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPoint;
        message->value = setPoint;
        queue.put(message);
    }
}

void temperatureThread()
{

    char buffer[128];
    displaySendUpdateTemp(temperatureF);
    displaySendUpdateSetPoint(setPoint);
    
    while(1)
    {
        osEvent evt = queue.get(200);
        if (evt.status == osEventMessage) {
            msg_t *message = (msg_t*)evt.value.p;
            switch(message->cmd)
            {
                case CMD_setPointDelta:
                    setPoint += message->value;
                    displaySendUpdateSetPoint(setPoint);
                break;
                case CMD_setPoint:
                    setPoint = message->value;
                    displaySendUpdateSetPoint(setPoint);
                break;

            }
            mpool.free(message);

        }
        else
        {
            readTemp();

            // Control the HVAC system with +- 0.5 degree of Hystersis
            if(temperatureF < setPoint - 0.5)
                displaySendUpdateMode(-1.0);
            else if (temperatureF > setPoint + 0.5)
                displaySendUpdateMode(1.0);
            else
                displaySendUpdateMode(0.0);

            displaySendUpdateTemp(temperatureF); 
        }
    }

}


static DigitalOut thermVDD(P10_3,1);
static DigitalOut thermGND(P10_0,0);
static AnalogIn thermOut(P10_1);

static void readTemp()
{
    float refVoltage = thermOut.read() * 2.4; // Range of ADC 0->2*Vref
    float refCurrent = refVoltage  / 10000.0; // 10k Reference Resistor
    float thermVoltage = 3.3 - refVoltage;    // Assume supply voltage is 3.3v
    float thermResistance = thermVoltage / refCurrent; 
    float logrT = (float32_t)log((float64_t)thermResistance);

    /* Calculate temperature from the resistance of thermistor using Steinhart-Hart Equation */
    float stEqn = (float32_t)((0.0009032679) + ((0.000248772) * logrT) + 
                             ((2.041094E-07) * pow((float64)logrT, (float32)3)));

    float temperatureC = (float32_t)(((1.0 / stEqn) - 273.15)  + 0.5);
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}

Fix blinkThread.cpp

Now edit the blinkThread.cpp to remove the test code from Lesson 03:

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"

static DigitalOut led1(LED1);

void blinkThread()
{
 
    while (true) 
    {
        led1 = !led1;
        displaySendUpdateTime();
        ThisThread::sleep_for(500);

    }
}

Update main.cpp

Then update main.cpp to start the new temperatureThread:

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"
#include "temperatureThread.h"

Thread blinkThreadHandle;
Thread displayThreadHandle;
Thread temperatureThreadHandle;

int main()
{

    printf("Started System\n");

    blinkThreadHandle.start(blinkThread);
    displayThreadHandle.start(displayThread);
    temperatureThreadHandle.start(temperatureThread);

}

Build, Program and Test

When you program the development kit you should be able to change the temperature by putting your finger on the thermistor:

And your terminal should look something like this:

Mouser PSoC 6 WiFi/BT MBED: L6 WiFi & NTP Thread

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

I don’t know about you guys, but it annoys me every time I see that the clock isn’t set.  In this lesson we will start the IoT-ifying of this system by attaching it to WiFi and getting the network time.

Inside of the PSoC is a RealTime clock that is driven by the crystal oscillator on the board.  However, “What time is it?”  turns out to be a pretty simple question to answer if you are attached to the network.  You find out using an NTP server.  This lesson will attach to WiFi, and then every 5 minutes go get the UTC time from an NTP server.

To implement this I will

  1. Import lesson05
  2. Add the NTP Server Library
  3. Create & Code ntpThread.h
  4. Create & Code ntpThread.cpp
  5. Update main.cpp
  6. Build, Program and Test

Import lesson05

First import the Lesson 05 to create a new project.

https://github.com/iotexpert/mouser-mbed-05.git

Add the NTP Server Library

For this lesson I will use a library that knows how to talk to an NTP server using a TCP socket.  To get this library click on the libraries tab and press “+”

Now provide the path to the library.

https://github.com/ARMmbed/ntp-client

Use the master branch:

Create & Code ntpThread.h

As always I am going to run the NTP Client in a thread.  This thread will be called “ntpThread”:

There is nothing to this but the function definition:

#ifndef NTP_THREAD_H
#define NTP_THREAD_H
void ntpThread();

#endif

Create & Code ntpThread.cpp

Next create the actual thread code:

This code will need to include the ntp-client library.  Then I do something semi-evil by making an external reference to the WiFiInterface which will be declared in main.cpp.

Finally I will poll the NTP server every 5 minutes.  Notice that if the thing fails it tries again in 10 seconds.  When I get the time I write it into the RTC using the standard-C set_time function.  This function was connected by Cypress to the RTC hardware in the PSoC 6.

#include "mbed.h"
#include "ntp-client/NTPClient.h"

extern WiFiInterface *wifi;


void ntpThread()
{
    NTPClient ntpclient(wifi);
 
    uint32_t sleepTime = 1000 * 60 * 5 ; // 5 minutes
    while(1)
    {

        if(wifi->get_connection_status() == NSAPI_STATUS_GLOBAL_UP)
        {
            time_t timestamp = ntpclient.get_timestamp();
            if (timestamp < 0) {
                sleepTime = 1000 * 10 ; // 10 seconds
            } 
            else 
            {
                set_time(timestamp);
                sleepTime = 1000 * 60 * 5 ; // 5 minutes

            }
        }
        ThisThread::sleep_for(sleepTime); // Goto the NTP server every 5 minutes
    }
}

Update main.cpp

Now I need to update main.cpp.  This time is a little bit different since I need to setup a connection to the WiFi network.  I start by getting a pointer to the WiFi in the system and then connecting before I start all of the threads.

Notice that I hard-coded the SSID and Password.  I also try again until I have a WiFi connection.

The rest of main.cpp is normal.

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"
#include "temperatureThread.h"
#include "capsenseThread.h"
#include "ntpThread.h"

Thread blinkThreadHandle;
Thread displayThreadHandle;
Thread temperatureThreadHandle;
Thread capsenseThreadHandle;
Thread ntpThreadHandle;

WiFiInterface *wifi;

int main()
{

    printf("Started System\n");

    int ret;
    wifi = WiFiInterface::get_default_instance();

    do {
            ret = wifi->connect("CYFI_IOT_EXT", "cypresswicedwifi101", NSAPI_SECURITY_WPA_WPA2);
            if (ret != 0) {
            ThisThread::sleep_for(2000); // If for some reason it doesnt work wait 2s and try again
            }
    } while(ret !=0);


    ntpThreadHandle.start(ntpThread);
    blinkThreadHandle.start(blinkThread);
    displayThreadHandle.start(displayThread);
    temperatureThreadHandle.start(temperatureThread);
    capsenseThreadHandle.start(capsenseThread);
    
}

Build, Program and Test

Now when I program this version, after 10 seconds or so, my time is updated… how cool is that?

Mouser PSoC 6 WiFi/BT MBED: L5 CapSense Thread

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

In Lesson 05 we will add a CapSense GUI to enable the user to change the setPoint of the thermostat.

Specifically I will create a new Thread called “CapSense Thread” which will read the state of the CapSense Buttons and send messages to the temperatureThread.

To implement this I will:

  1. Import Lesson 04
  2. Add the Cypress CapSense library
  3. Run the CapsSense configurator
  4. Create and code capsenseThread.h
  5. Create and code capsenseThread.cpp
  6. Update main.cpp
  7. Build, Program and Test

Import Lesson 04

First import Lesson 04 and call your new project “mouser-mbed-05”

https://github.com/iotexpert/mouser-mbed-04.git

Add the Cypress CapSense library

In order to use the CapSense library you will need to import it from the Cypress GitHub site.  To do this we will use the Mbed Studio Library manager.  Click on the “Libraries” tab. Then press the “+” button to add a new library.

Give the Library manager the URL to the Cypress CapSense library:

https://github.com/cypresssemiconductorco/capsense.git

Specify that you want your library to point to the master branch.

Once that is done your library screen should look something like this.  When I took this screen shot I noticed that I was on the old version of mbed-os so I pressed the update button.

Now both libraries are at the latest version.

Run the CapSense Configurator

First, lets run the CapSense configurator to look at the CapSense configuration.  You can find it in ModusToolbox/tools_2.0/capsense_configurator. Then use file>open to open the Target’s CapSense configuration file from targets/TARGET_Cypress/TARGET_PSOC6/TARGET_CY8PROTO_062_4343w/COMPONENT_BSP_DESIGN_MODUS/design.cycapsense.

Here is the advanced tab:

The BSP/Target as delivered inside of Mbed OS does not have the generated source code required to run CapSense.  I could press save in the CapSense configurator GUI, but this would modify my version of Mbed OS.  I would rather add these files to the make project.  In order to get this code into my project I run the CapSense Configurator from the command line and tell to save the files locally.

  • /Applications/ModusToolbox/tools_2.0/capsense-configurator/capsense-configurator-cli -c mbed-os/targets/TARGET_Cypress/TARGET_PSOC6/TARGET_CY8CKIT_062_WIFI_BT/COMPONENT_BSP_DESIGN_MODUS/design.cycapsense -o `pwd` -g

Here is what the output looks like:

Create and Code capsenseThread.h

As with all of the other lessons, I want a new thread called “capsenseThread”  Start by making the “dot h”

This will only have the capsenseThread function.

#ifndef CAPSENSE_THREAD_H
#define CAPSENSE_THREAD_H

void capsenseThread(void);

#endif

Create and code capsenseThread.cpp

Now make the cpp file.

The Cypress CapSense system is a combination of hardware and firmware.  It works by:

  1. Initializing the Hardware
  2. Initializing the Interrupt
  3. Initializing the callback
  4. Starting a scan (run the hardware block)
  5. Processing the raw data when the scan is done and send a message
  6. Starting another Scan

I got the basis for this code by using the CapSense example project that Cypress has posted on GitHub. You can find that code example at:

github.com/cypresssemiconductorco/mtb-example-psoc6-capsense-buttons-slider

Initializing the Hardware

    /* Configure AMUX bus for CapSense */
    init_cycfg_routing();
    /* Configure PERI clocks for CapSense */
    Cy_SysClk_PeriphAssignDivider(PCLK_CSD_CLOCK, CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphDisableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphSetDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM, 0u);
    Cy_SysClk_PeriphEnableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    

    /* Initialize the CSD HW block to the default state. */
    Cy_CapSense_Init(&cy_capsense_context);

Initializing the Interrupt

This sets up the CapSense interrupt to work with the hardware block

    const cy_stc_sysint_t CapSense_ISR_cfg =
    {
        .intrSrc = CYBSP_CSD_IRQ,
        .intrPriority = 4u
    };
    /* Initialize CapSense interrupt */
    Cy_SysInt_Init(&CapSense_ISR_cfg, &CapSense_InterruptHandler);
    NVIC_ClearPendingIRQ(CapSense_ISR_cfg.intrSrc);
    NVIC_EnableIRQ(CapSense_ISR_cfg.intrSrc);

Initializing the callback

The callback is used to set the semaphore when the scan is done.

    /* Initialize the CapSense firmware modules. */
    Cy_CapSense_Enable(&cy_capsense_context);
    Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E, CapSenseEndOfScanCallback, &cy_capsense_context);

Starting a scan (run the hardware block)

    Cy_CapSense_ScanAllWidgets(&cy_capsense_context);  // Launch the initial scan   

Processing Raw Data when the scan completes, and Send Message

        if (CY_CAPSENSE_NOT_BUSY == Cy_CapSense_IsBusy(&cy_capsense_context))
        {
            Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);
            uint32_t currBtn0Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON0_WDGT_ID, CY_CAPSENSE_BUTTON0_SNS0_ID, &cy_capsense_context);        
            uint32_t currBtn1Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON1_WDGT_ID, CY_CAPSENSE_BUTTON1_SNS0_ID, &cy_capsense_context);       

            if(currBtn0Status != prevBtn0Status && currBtn0Status==1 )
            {
                tempSendDeltaSetpointF(-0.1);
            }
            prevBtn0Status = currBtn0Status;
    
            if(currBtn1Status != prevBtn1Status && currBtn1Status == 1)
            {
                tempSendDeltaSetpointF(0.1);
            } 
            prevBtn1Status = currBtn1Status;

             
        } 

Starting another Scan

Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

Here is the whole file:

#include "mbed.h"
#include "cy_pdl.h"
#include "cycfg_capsense.h"
#include "cycfg.h"
#include "temperatureThread.h"

static Semaphore capsense_sem;


/*****************************************************************************
* Function Name: CapSense_InterruptHandler()
******************************************************************************
* Summary:
*  Wrapper function for handling interrupts from CSD block.
*
*****************************************************************************/
static void CapSense_InterruptHandler(void)
{
    Cy_CapSense_InterruptHandler(CYBSP_CSD_HW, &cy_capsense_context);
}


/*****************************************************************************
* Function Name: CapSenseEndOfScanCallback()
******************************************************************************
* Summary:
*  This function releases a semaphore to indicate end of a CapSense scan.
*
* Parameters:
*  cy_stc_active_scan_sns_t* : pointer to active sensor details.
*
*****************************************************************************/
static void CapSenseEndOfScanCallback(cy_stc_active_scan_sns_t * ptrActiveScan)
{
    capsense_sem.release();
}


void capsenseThread(void)
{

    /* Configure AMUX bus for CapSense */
    init_cycfg_routing();
    /* Configure PERI clocks for CapSense */
    Cy_SysClk_PeriphAssignDivider(PCLK_CSD_CLOCK, CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphDisableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    Cy_SysClk_PeriphSetDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM, 0u);
    Cy_SysClk_PeriphEnableDivider(CYBSP_CSD_CLK_DIV_HW, CYBSP_CSD_CLK_DIV_NUM);
    

    /* Initialize the CSD HW block to the default state. */
    Cy_CapSense_Init(&cy_capsense_context);

    const cy_stc_sysint_t CapSense_ISR_cfg =
    {
        .intrSrc = CYBSP_CSD_IRQ,
        .intrPriority = 4u
    };
    /* Initialize CapSense interrupt */
    Cy_SysInt_Init(&CapSense_ISR_cfg, &CapSense_InterruptHandler);
    NVIC_ClearPendingIRQ(CapSense_ISR_cfg.intrSrc);
    NVIC_EnableIRQ(CapSense_ISR_cfg.intrSrc);

    /* Initialize the CapSense firmware modules. */
    Cy_CapSense_Enable(&cy_capsense_context);
    Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E, CapSenseEndOfScanCallback, &cy_capsense_context);

    Cy_CapSense_ScanAllWidgets(&cy_capsense_context);  // Launch the initial scan   
    
    uint32_t prevBtn0Status = 0u; 
    uint32_t prevBtn1Status = 0u;
     
    while(1)
    {

        capsense_sem.acquire();
        if (CY_CAPSENSE_NOT_BUSY == Cy_CapSense_IsBusy(&cy_capsense_context))
        {
            Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);
            uint32_t currBtn0Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON0_WDGT_ID, CY_CAPSENSE_BUTTON0_SNS0_ID, &cy_capsense_context);        
            uint32_t currBtn1Status = Cy_CapSense_IsSensorActive(CY_CAPSENSE_BUTTON1_WDGT_ID, CY_CAPSENSE_BUTTON1_SNS0_ID, &cy_capsense_context);       

            if(currBtn0Status != prevBtn0Status && currBtn0Status==1 )
            {
                tempSendDeltaSetpointF(-0.1);
            }
            prevBtn0Status = currBtn0Status;
    
            if(currBtn1Status != prevBtn1Status && currBtn1Status == 1)
            {
                tempSendDeltaSetpointF(0.1);
            } 
            prevBtn1Status = currBtn1Status;

            Cy_CapSense_ScanAllWidgets(&cy_capsense_context);  
        } 

    }
}

Update main.cpp

Inside of the main.cpp I will make the usual changes to turn on the CapSense thread.

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"
#include "temperatureThread.h"
#include "capsenseThread.h"

Thread blinkThreadHandle;
Thread displayThreadHandle;
Thread temperatureThreadHandle;
Thread capsenseThreadHandle;

int main()
{

    printf("Started System\n");

    blinkThreadHandle.start(blinkThread);
    displayThreadHandle.start(displayThread);
    temperatureThreadHandle.start(temperatureThread);
    capsenseThreadHandle.start(capsenseThread);

}

Build, Program and Test

When I build, program and test I can see that by pressing the two CapSense Buttons I can raise and lower the setPoint.

Mouser PSoC 6 WiFi/BT MBED: L7 The CY8CKIT-062-WiFi-BT

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

This weekend as I was getting ready for the workshop, my son, Nicholas, was making fun of me for my user interface.  To fix this I decided to show how you could move platforms.  Specifically to the CY8CKIT-062-WiFi-BT which you can buy from mouser.com

You could literally just change the target and things would work… almost.  The one exception is that this development kit doesn’t have a thermistor.  So, I soldered a different kind of temperature sensor, called a TMP36, onto the kit which means I have to make a few small code updates to the temperatureThread.

In addition to changing to the TMP36 I will also use the TFT as a display for the system, so I need to modify the displayThread.

One of the major points that I wanted to make with this lesson is that if you design your code correctly, a change like this isn’t very hard.

To implement this I will:

  1. Provide a TMP36 Temperature Sensor Tutorial
  2. Modify the CY8CKIT-028-TFT
  3. Import Lesson06
  4. Update temperatureThread.cpp
  5. Build, Program and Test
  6. Add Segger emWin Library
  7. Add IoTExpert CY8CKIT-028-TFT configuration
  8. Update mbed_app.json to include driver
  9. Update displayThread.cpp
  10. Build, Program and Test

TMP36 Temperature Sensor

The TMP36 is a single wire temperature sensor that gives you a voltage that is directly proportional to the temperature.  Specifically, it is 10mV per degree C.

The Analog Devices TMP36 that I am using I bought here from mouser.com.  It looks like a little 3-wire transistor looking thing.

Here is a snapshot from the data sheet of the temperature voltage response

Yes I know that I am a digital guy, but for just three wires, signal, ground and power, it sure looks like there is a lot going on in the package.

The data sheet (which is actually really interesting)  gives you the parameters to make the linear equation for temperature

To calculate the temperature you just calculate:

T = (degree C/10mV) * V – 50 degree C

Here is the function to read the temperature:

static AnalogIn tmp36(A5);
static void readTemp()
{
    float volts;
    
    volts = tmp36.read() * 2.4;
    float temperatureC = 1/.01 * volts - 50.0;
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}

Modify the CY8CKIT-028-TFT

Start this process by attaching the TMP36.  On the back of the CY8CKIT-028-TFT I solder three wires onto the temperature sensor.  One to 3.3v, one to ground and one to A5.  Here is the picture of my ugly ugly solder job.  Yes, that is duct-tape holding it onto the back of the shield.  And yes that is a prototype sticker.

I also remove the PDM microphone which is also attached to A5 (I’m not sure that it would cause a problem… but better safe than sorry)

Import Lesson06

Now, fix the code.  As always, start by importing the previous lesson.

https://github.com/iotexpert/mouser-mbed-06.git

Update temperatureThread.cpp

In order to switch between the thermistor and the TMP36 I create two #defines based on the target that is currently active.  This is cool because the Mbed OS creates these #defines automatically.

#ifdef TARGET_CY8CPROTO_062_4343W
#define THERMISTOR
#endif

#ifdef TARGET_CY8CKIT_062_WIFI_BT
#define TMP36
#endif

There are a bunch of ways that could have been done, including with the Mbed configuration system which you control with the mbed_app.json.  But this was expedient.

Next, I create the code to measure the temperature using the AnalogIn object. Notice that it is connected to the Arduino A5 pin. Also notice that when the TMP36 is active I have a different readTemp function so I don’t need to change anything else to get the temperature.

#ifdef TMP36
static AnalogIn tmp36(A5);
static void readTemp()
{
    float volts;
    
    volts = tmp36.read() * 2.4;
    float temperatureC = 1/.01 * volts - 50.0; // from the data sheet
    temperatureF = (temperatureC * 9.0/5.0) + 32; // conver to F
}
#endif

Then I update the thermistor readTemp function with the THERMISTOR #define

#ifdef THERMISTOR
static DigitalOut thermVDD(P10_3,1);
static DigitalOut thermGND(P10_0,0);
static AnalogIn thermOut(P10_1);

static void readTemp()
{
    float refVoltage = thermOut.read() * 2.4; // Range of ADC 0->2*Vref
    float refCurrent = refVoltage  / 10000.0; // 10k Reference Resistor
    float thermVoltage = 3.3 - refVoltage;    // Assume supply voltage is 3.3v
    float thermResistance = thermVoltage / refCurrent; 
    float logrT = (float32_t)log((float64_t)thermResistance);

    /* Calculate temperature from the resistance of thermistor using Steinhart-Hart Equation */
    float stEqn = (float32_t)((0.0009032679) + ((0.000248772) * logrT) + 
                             ((2.041094E-07) * pow((float64)logrT, (float32)3)));

    float temperatureC = (float32_t)(((1.0 / stEqn) - 273.15)  + 0.5);
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}
#endif

Here is the whole file:

#include "mbed.h"
#include "temperatureThread.h"
#include "displayThread.h"


#ifdef TARGET_CY8CPROTO_062_4343W
#define THERMISTOR
#endif

#ifdef TARGET_CY8CKIT_062_WIFI_BT
#define TMP36
#endif


static float temperatureF;
static float setPoint = 75.0;

static void readTemp();

typedef enum {
    CMD_setPointDelta,
    CMD_setPoint,

} command_t;


typedef struct {
    command_t cmd;
    float    value;   /* AD result of measured voltage */
} msg_t;


static Queue<msg_t, 32> queue;
static MemoryPool<msg_t, 16> mpool;

void tempSendDeltaSetpointF(float delta)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPointDelta;
        message->value = delta;
        queue.put(message);
    }
}

void tempSendUpdateCurrentSetPointF(float setPoint)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_setPoint;
        message->value = setPoint;
        queue.put(message);
    }
}

void temperatureThread()
{

    char buffer[128];
    displaySendUpdateTemp(temperatureF);
    displaySendUpdateSetPoint(setPoint);
    
    while(1)
    {
        osEvent evt = queue.get(200);
        if (evt.status == osEventMessage) {
            msg_t *message = (msg_t*)evt.value.p;
            switch(message->cmd)
            {
                case CMD_setPointDelta:
                    setPoint += message->value;
                    displaySendUpdateSetPoint(setPoint);
                break;
                case CMD_setPoint:
                    setPoint = message->value;
                    displaySendUpdateSetPoint(setPoint);
                break;

            }
            mpool.free(message);

        }
        else
        {
            readTemp();

            // Control the HVAC system with +- 0.5 degree of Hystersis
            if(temperatureF < setPoint - 0.5)
                displaySendUpdateMode(-1.0);
            else if (temperatureF > setPoint + 0.5)
                displaySendUpdateMode(1.0);
            else
                displaySendUpdateMode(0.0);

            displaySendUpdateTemp(temperatureF);
        
        }
    }

}


#ifdef THERMISTOR
static DigitalOut thermVDD(P10_3,1);
static DigitalOut thermGND(P10_0,0);
static AnalogIn thermOut(P10_1);

static void readTemp()
{
    float refVoltage = thermOut.read() * 2.4; // Range of ADC 0->2*Vref
    float refCurrent = refVoltage  / 10000.0; // 10k Reference Resistor
    float thermVoltage = 3.3 - refVoltage;    // Assume supply voltage is 3.3v
    float thermResistance = thermVoltage / refCurrent; 
    float logrT = (float32_t)log((float64_t)thermResistance);

    /* Calculate temperature from the resistance of thermistor using Steinhart-Hart Equation */
    float stEqn = (float32_t)((0.0009032679) + ((0.000248772) * logrT) + 
                             ((2.041094E-07) * pow((float64)logrT, (float32)3)));

    float temperatureC = (float32_t)(((1.0 / stEqn) - 273.15)  + 0.5);
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}
#endif

#ifdef TMP36
static AnalogIn tmp36(A5);
static void readTemp()
{
    float volts;
    
    volts = tmp36.read() * 2.4;
    float temperatureC = 1/.01 * volts - 50.0;
    temperatureF = (temperatureC * 9.0/5.0) + 32;
}
#endif

Build, Program and Test

With that little update I can now build, program and test. Notice that my display is still working… and I can change the temperature by holding the TMP36 between my fingers.

Add Segger emWin Library

But, I haven’t really addressed Nicholas’ complaint, the GUI.  To do this I am going to use the Segger emWin library to control the TFT display.  Go to the library manager and add the library.

https://github.com/cypresssemiconductorco/emwin.git

Use the master branch:

Add IoTExpert CY8CKIT-028-TFT configuration

The emWin library doesn’t know anything about how the TFT is attached.  So, I created a driver library which you can use for all of the Cypress development kits.

https://github.com/iotexpert/mbed-os-emwin-st7789v.git

Use the master branch:

Now your libraries should look like this.

Update mbed_app.json to include emWin Driver

In order to use this driver you need to tell Mbed OS to add the correct archive file.  To do this update mbed_app.json

{
    "target_overrides": {
        "*": {
            "target.components_add": ["EMWIN_OSNTS"],
            "platform.stdio-baud-rate": 115200
        }
    }
}

Update displayThread.cpp

Finally update the displayThread.  Start by adding the include for the Segger library.

#ifdef TARGET_CY8CKIT_062_WIFI_BT
#include "GUI.h"
#endif

Then update the displayAtXY function to also print on the display.  By doing it here I don’t have to change anything else in the code because this is the only function that draws on the screen.

static void displayAtXY(int x, int y,char *buffer)
{
    #ifdef TARGET_CY8CKIT_062_WIFI_BT
    GUI_SetTextAlign(GUI_TA_LEFT);
    GUI_DispStringAt(buffer,(x-1)*8,(y-1)*16); // 8x16 font
    #endif
    // row column
    printf("3[%d;%dH%s",y,x,buffer);
    fflush(stdout);
}

Update the main thread to initialize the display when the thread starts.

void displayThread()
{
    char buffer[128];

    printf("3[2J3[H"); // Clear Screen and go Home
    printf("3[?25l"); // Turn the cursor off
    fflush(stdout);

    #ifdef TARGET_CY8CKIT_062_WIFI_BT
        GUI_Init();
        GUI_SetColor(GUI_WHITE);
        GUI_SetBkColor(GUI_BLACK);
        GUI_SetFont(GUI_FONT_8X16_1);
    #endif

Build, Program and Test

When you program, now you should have a TFT display.  Happy Nicholas?

Mouser PSoC 6 WiFi/BT MBED: L8 Amazon AWS MQTT Thread – Part1

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

In this lesson we will plumb in the ability to talk to the Amazon Web Services MQTT broker.  Specifically to publish messages from the broker to change the setPoint of the thermostat.

To implement this I will:

  1. Discuss MQTT
  2. Import Lesson 07
  3. Add the Cypress AWS IoT Middleware
  4. Add the Cypress Connectivity Utilities Library
  5. Create an AWS Policy, Thing, and Certificate
  6. Modify the keys to “C” format
  7. Create and Code awsThread.h
  8. Create and Code awsThread.cpp
  9. Update main.cpp
  10. Build, Program and Test

MQTT

There are five basic ideas that you need to understand when using MQTT.

  • (Message) Broker
  • Topic
  • Subscriber
  • Publisher
  • Messages

The Broker is a TCP/IP server sitting at the middle of an MQTT network.  It is responsible for receiving Messages from Publishers and forwarding them on to Subscribers.  A broker can run multiple simultaneous communication channels called Topics.

Topics are ad-hoc (application semantics) and are just a string of characters … like “setPoint” or “thing/setPoint”

Messages are just a string of bytes.  Typically formatted as JSON.  This is by convention and is not a requirement.

MQTT clients can be Publishers or Subscribers or both.

Import Lesson 07

Start by importing Lesson 07.

https://github.com/iotexpert/mouser-mbed-07.git


Add the Cypress AWS IoT Middleware

Cypress has built a library which will help you manage connections to AWS.  We call it the aws IoT middleware library.  Go to the library manager and add it:

  • https://github.com/cypresssemiconductorco/aws-iot.git

Use the master branch:

Add the Cypress Connectivity Utilities Library

The AWS IoT library needs to use another library of connectivity functions.  Add it:

  • https://github.com/cypresssemiconductorco/connectivity-utilities.git

Select the master branch:

Create an AWS Policy, Thing, and Certificate

In order to make a connection to AWS you need to have a policy attached to a certificate.  In addition it makes sense to have an AWS “Thing” to represent your system.

Start from the AWS Console and press “Secure->Policies”.  Then press “Create”

Give your policy a name.  Add all “iot:*” and all resource and “allow”.  Then press “Create”:

Once the policy is created you will see it in the catalog:

Create a new Thing by clicking “Manage -> Things”.  Then click “Create””

Press “Create a single thing”:

First give your thing a name (in this case mouser) then click “Next”:

Click “Create certificate”

You MUST DOWNLOAD these files now.  You will not be given another chance. Press activate:

Which will show the certificate as active.  Next press “attach a policy”:

Then pick the Mouser policy:

Now you have your new “Thing”.

Modify the keys to “C” Format

In order to make a connection to AWS you need a valid certificate, the private key that goes with the certificate and the CA certificate of AWS.    You just created these files in the previous step.

These keys come looking like this:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsRLypD2uhZNZgtfPAuX8M3ZFNYcBU/BHulG9CJrETKwmjXOV
j1l9U/Tlu3p/hGIFEhrkbqt1SGvPEj8x7U5kyCpJde1JojObW4m2S5T7WuXxd5JQ
Y+rqWkyrvwp/1HPFLRB3n3OopGaUcnEZwegsMznUcsi+kZwrUDkqBWFIQbEEKjW8
UzZxqmbmNSCsJQXHCv9OPrKdeisBnkQrpRkTz4uSG3yZI6jG7acx3UZkMcc6DvDo
bbz8PoBisZq4JcKthwpQdiV1RdS4aqCc0wq5Jv7DvhifqNcrOK3PT+zkck82jqIC
VDd58NkY6Y0URIyqjPCPPIltCbrAB/+u41rrtQIDAQABAoIBAQCQAhvprOxpX+u1
OLP35HjWlYI1xSU0Ub7T7bPx8oRg4sS711uz6JC/nfTUIwzf6iO7lLlgs/q/OkZ+
zXxaRZ47GAEEckWnL5dSu83Q7En7o/RcTVcp25xace5fgTdy3fBm9PSEbjih83cZ
F5heFecUhhyceVxa6YpkRQlCtNph6SwFfsY1BmfhHISHh4U7XYityUatdalQfOtL
Vf79TRIE/X1aX/H/xXYsqNQPCSGUzNj1BU5aHOM93B+hNg8q1t+Ze5w6Q/HkMBTb
5VPI8fabvaAV6WUrrWtEl8ErcokutYWNRadXH0ieCGiuI2uoK0qqgrBb2MwZwv81
ZtzCm3QlAoGBAOj5zlZtcWN5Mfb9PHonPSwFPE4pud2fZCJjO9btQWb6ELYwp9qW
2aRaoaQm9bA7pTwMaSRQYGC9eKPu8hu+cqPXJZ1gg1GrYP+IfJMChDAM0x7Faks4
B7ZDjfQlRGUJGAkqLQ4/4+k2y75KtZdnri5Z40myh4f0+PuiDDRwPcGjAoGBAMKS
2VuNefMvzqKW7g/drRLzChudUL96r2BWI8nkl7S9UChtKVgdqJcrNSiKXbTv0wLn
pWsnlOIxPVJAi1u5we045U+ZQadgIg4UqeIBVfRVKm4ZKrInSCT4uMriGDDJuvQl
NXBv9PIX8WCaPWpG2rcsOFsi0mNBcImVHMAhc2LHAoGBAIk6k8Ku5opMWhT9J0Fg
mZSzZMk5pMSZXXcv8pBv4gVRKMTYNhb4oixAQlQZqsBq8bJEMS51tb9l+4i8d5nF
/WrqkLp5ngBeLV13PMGvSsOu2jCW4jx6PXirpBL6XKYSzDihwjZRheLaJvrosLwF
E0E0K0A+y7xWnM5DrmK49nd3AoGAQdp70F24yZMDp8nXdu07F6/EWwZKfxQh6UQe
RsWkhtqQF66ikJ0xI0DPdBIolwWYcGJAfVzfKhMqQv1vbTMYrJZWHjOrod+KhyN9
P+3dzp1IiAzig3uCEmlP+fK95z1PljRFuvFZgNqTqnNpl9+1RMulo0rM1CUg1p/u
JCTuLZ8CgYEAwUsBplIARj4i+hhyVWC1WOR+I4AqgRAauCwliO9gvToJzjkQsc5q
RZxPbXLbm907wy6/7P/tKT20WhZ0b7szZsXchdeX20xSfAa4N0bJTZy3OiS0CYtF
3+Xw1Mlu3Gihr89X9QeSot0tH9m6QZky032aLW/8jbNT3Eb49niqQZA=
-----END RSA PRIVATE KEY-----

But you need them to look like this so that they can be read in by the Mbed TLS library.

// Private key
const char SSL_CLIENTKEY_PEM[] = \
"-----BEGIN RSA PRIVATE KEY-----\n"\
"MIIEpQIBAAKCAQEAsRLypD2uhZNZgtfPAuX8M3ZFNYcBU/BHulG9CJrETKwmjXOV\n"\
"j1l9U/Tlu3p/hGIFEhrkbqt1SGvPEj8x7U5kyCpJde1JojObW4m2S5T7WuXxd5JQ\n"\
"Y+rqWkyrvwp/1HPFLRB3n3OopGaUcnEZwegsMznUcsi+kZwrUDkqBWFIQbEEKjW8\n"\
"UzZxqmbmNSCsJQXHCv9OPrKdeisBnkQrpRkTz4uSG3yZI6jG7acx3UZkMcc6DvDo\n"\
"bbz8PoBisZq4JcKthwpQdiV1RdS4aqCc0wq5Jv7DvhifqNcrOK3PT+zkck82jqIC\n"\
"VDd58NkY6Y0URIyqjPCPPIltCbrAB/+u41rrtQIDAQABAoIBAQCQAhvprOxpX+u1\n"\
"OLP35HjWlYI1xSU0Ub7T7bPx8oRg4sS711uz6JC/nfTUIwzf6iO7lLlgs/q/OkZ+\n"\
"zXxaRZ47GAEEckWnL5dSu83Q7En7o/RcTVcp25xace5fgTdy3fBm9PSEbjih83cZ\n"\
"F5heFecUhhyceVxa6YpkRQlCtNph6SwFfsY1BmfhHISHh4U7XYityUatdalQfOtL\n"\
"Vf79TRIE/X1aX/H/xXYsqNQPCSGUzNj1BU5aHOM93B+hNg8q1t+Ze5w6Q/HkMBTb\n"\
"5VPI8fabvaAV6WUrrWtEl8ErcokutYWNRadXH0ieCGiuI2uoK0qqgrBb2MwZwv81\n"\
"ZtzCm3QlAoGBAOj5zlZtcWN5Mfb9PHonPSwFPE4pud2fZCJjO9btQWb6ELYwp9qW\n"\
"2aRaoaQm9bA7pTwMaSRQYGC9eKPu8hu+cqPXJZ1gg1GrYP+IfJMChDAM0x7Faks4\n"\
"B7ZDjfQlRGUJGAkqLQ4/4+k2y75KtZdnri5Z40myh4f0+PuiDDRwPcGjAoGBAMKS\n"\
"2VuNefMvzqKW7g/drRLzChudUL96r2BWI8nkl7S9UChtKVgdqJcrNSiKXbTv0wLn\n"\
"pWsnlOIxPVJAi1u5we045U+ZQadgIg4UqeIBVfRVKm4ZKrInSCT4uMriGDDJuvQl\n"\
"NXBv9PIX8WCaPWpG2rcsOFsi0mNBcImVHMAhc2LHAoGBAIk6k8Ku5opMWhT9J0Fg\n"\
"mZSzZMk5pMSZXXcv8pBv4gVRKMTYNhb4oixAQlQZqsBq8bJEMS51tb9l+4i8d5nF\n"\
"/WrqkLp5ngBeLV13PMGvSsOu2jCW4jx6PXirpBL6XKYSzDihwjZRheLaJvrosLwF\n"\
"E0E0K0A+y7xWnM5DrmK49nd3AoGAQdp70F24yZMDp8nXdu07F6/EWwZKfxQh6UQe\n"\
"RsWkhtqQF66ikJ0xI0DPdBIolwWYcGJAfVzfKhMqQv1vbTMYrJZWHjOrod+KhyN9\n"\
"P+3dzp1IiAzig3uCEmlP+fK95z1PljRFuvFZgNqTqnNpl9+1RMulo0rM1CUg1p/u\n"\
"JCTuLZ8CgYEAwUsBplIARj4i+hhyVWC1WOR+I4AqgRAauCwliO9gvToJzjkQsc5q\n"\
"RZxPbXLbm907wy6/7P/tKT20WhZ0b7szZsXchdeX20xSfAa4N0bJTZy3OiS0CYtF\n"\
"3+Xw1Mlu3Gihr89X9QeSot0tH9m6QZky032aLW/8jbNT3Eb49niqQZA=\n"\
"-----END RSA PRIVATE KEY-----";

There are a number of ways to change the format including manual editing.

For this lesson I put the keys into a file called “aws_config.h”  There are bunches of bad stories out there about people finding encryption keys on the internet (like these).  I am going to disable the keys as soon as this workshop is over, but you should be careful with yours.

Here is my aws_config.h

/* Change device certificate and device private key based on your account */
// certificate
const char SSL_CLIENTCERT_PEM[] =  \
"-----BEGIN CERTIFICATE-----\n\
MIIDWjCCAkKgAwIBAgIVAJ4u/gU7NxWiV2NwBRTFJk/mPPkvMA0GCSqGSIb3DQEB\n\
CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\n\
IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xOTA3MDMxMTM5\n\
MTZaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\n\
dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxEvKkPa6Fk1mC188C\n\
5fwzdkU1hwFT8Ee6Ub0ImsRMrCaNc5WPWX1T9OW7en+EYgUSGuRuq3VIa88SPzHt\n\
TmTIKkl17UmiM5tbibZLlPta5fF3klBj6upaTKu/Cn/Uc8UtEHefc6ikZpRycRnB\n\
6CwzOdRyyL6RnCtQOSoFYUhBsQQqNbxTNnGqZuY1IKwlBccK/04+sp16KwGeRCul\n\
GRPPi5IbfJkjqMbtpzHdRmQxxzoO8OhtvPw+gGKxmrglwq2HClB2JXVF1LhqoJzT\n\
Crkm/sO+GJ+o1ys4rc9P7ORyTzaOogJUN3nw2RjpjRREjKqM8I88iW0JusAH/67j\n\
Wuu1AgMBAAGjYDBeMB8GA1UdIwQYMBaAFIJyQZprW3SRNIXe+X22/uZ6sdO9MB0G\n\
A1UdDgQWBBT+al32O2+dH5qoClpyEWRRoMk6oTAMBgNVHRMBAf8EAjAAMA4GA1Ud\n\
DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAoRg4QETRC1rMKJytxthLuGDj\n\
WtB9Zow3TONnq1HZ4yMUQFQeflYCZ96khBuWu91cj2iZengikEJkl+6HGCL+9ZKA\n\
ybWPRyQNvJQ13ju/iQyl89ZIbYh5UGmGrk6G8ryyvPezVP8AxpB5usz9YxTTz/m6\n\
eQMs38zUK5Dv4297NBJ6Xxwoqb8ivJkHEmnkDxKeErd4Qb7Q9ukWYlo5ksjqib8F\n\
NYTv8fhcx4S3UFhbNB+z/iaGtJXk7WIzgGpSX/CiRtGcV776c94LdgIfIZ9DpLgi\n\
GWSrCjsCr6yNtc708vwC+0jKoBcrk3HdVII2N4ciNuzJaoGyuHi+YuiXnO8kbg==\n\
-----END CERTIFICATE-----";

// Private key
const char SSL_CLIENTKEY_PEM[] = \
"-----BEGIN RSA PRIVATE KEY-----\n"\
"MIIEpQIBAAKCAQEAsRLypD2uhZNZgtfPAuX8M3ZFNYcBU/BHulG9CJrETKwmjXOV\n"\
"j1l9U/Tlu3p/hGIFEhrkbqt1SGvPEj8x7U5kyCpJde1JojObW4m2S5T7WuXxd5JQ\n"\
"Y+rqWkyrvwp/1HPFLRB3n3OopGaUcnEZwegsMznUcsi+kZwrUDkqBWFIQbEEKjW8\n"\
"UzZxqmbmNSCsJQXHCv9OPrKdeisBnkQrpRkTz4uSG3yZI6jG7acx3UZkMcc6DvDo\n"\
"bbz8PoBisZq4JcKthwpQdiV1RdS4aqCc0wq5Jv7DvhifqNcrOK3PT+zkck82jqIC\n"\
"VDd58NkY6Y0URIyqjPCPPIltCbrAB/+u41rrtQIDAQABAoIBAQCQAhvprOxpX+u1\n"\
"OLP35HjWlYI1xSU0Ub7T7bPx8oRg4sS711uz6JC/nfTUIwzf6iO7lLlgs/q/OkZ+\n"\
"zXxaRZ47GAEEckWnL5dSu83Q7En7o/RcTVcp25xace5fgTdy3fBm9PSEbjih83cZ\n"\
"F5heFecUhhyceVxa6YpkRQlCtNph6SwFfsY1BmfhHISHh4U7XYityUatdalQfOtL\n"\
"Vf79TRIE/X1aX/H/xXYsqNQPCSGUzNj1BU5aHOM93B+hNg8q1t+Ze5w6Q/HkMBTb\n"\
"5VPI8fabvaAV6WUrrWtEl8ErcokutYWNRadXH0ieCGiuI2uoK0qqgrBb2MwZwv81\n"\
"ZtzCm3QlAoGBAOj5zlZtcWN5Mfb9PHonPSwFPE4pud2fZCJjO9btQWb6ELYwp9qW\n"\
"2aRaoaQm9bA7pTwMaSRQYGC9eKPu8hu+cqPXJZ1gg1GrYP+IfJMChDAM0x7Faks4\n"\
"B7ZDjfQlRGUJGAkqLQ4/4+k2y75KtZdnri5Z40myh4f0+PuiDDRwPcGjAoGBAMKS\n"\
"2VuNefMvzqKW7g/drRLzChudUL96r2BWI8nkl7S9UChtKVgdqJcrNSiKXbTv0wLn\n"\
"pWsnlOIxPVJAi1u5we045U+ZQadgIg4UqeIBVfRVKm4ZKrInSCT4uMriGDDJuvQl\n"\
"NXBv9PIX8WCaPWpG2rcsOFsi0mNBcImVHMAhc2LHAoGBAIk6k8Ku5opMWhT9J0Fg\n"\
"mZSzZMk5pMSZXXcv8pBv4gVRKMTYNhb4oixAQlQZqsBq8bJEMS51tb9l+4i8d5nF\n"\
"/WrqkLp5ngBeLV13PMGvSsOu2jCW4jx6PXirpBL6XKYSzDihwjZRheLaJvrosLwF\n"\
"E0E0K0A+y7xWnM5DrmK49nd3AoGAQdp70F24yZMDp8nXdu07F6/EWwZKfxQh6UQe\n"\
"RsWkhtqQF66ikJ0xI0DPdBIolwWYcGJAfVzfKhMqQv1vbTMYrJZWHjOrod+KhyN9\n"\
"P+3dzp1IiAzig3uCEmlP+fK95z1PljRFuvFZgNqTqnNpl9+1RMulo0rM1CUg1p/u\n"\
"JCTuLZ8CgYEAwUsBplIARj4i+hhyVWC1WOR+I4AqgRAauCwliO9gvToJzjkQsc5q\n"\
"RZxPbXLbm907wy6/7P/tKT20WhZ0b7szZsXchdeX20xSfAa4N0bJTZy3OiS0CYtF\n"\
"3+Xw1Mlu3Gihr89X9QeSot0tH9m6QZky032aLW/8jbNT3Eb49niqQZA=\n"\
"-----END RSA PRIVATE KEY-----";


const char SSL_CA_PEM[] = \
"-----BEGIN CERTIFICATE-----\n"\
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n"\
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n"\
"b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n"\
"MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n"\
"b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n"\
"ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n"\
"9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n"\
"IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n"\
"VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n"\
"93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n"\
"jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"\
"AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n"\
"A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n"\
"U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n"\
"N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n"\
"o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n"\
"5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n"\
"rqXRfboQnoZsG4q5WTP468SQvvG5\n"\
"-----END CERTIFICATE-----";

Create and Code awsThread.h

Now create a new header file for the awsThread:

This file just contains the thread function prototype.

#ifndef AWS_THREAD_H
#define AWS_THREAD_H

void awsThread(void);


#endif

Create and Code awsThread.cpp

Now create the awsThread.cpp file for the aws implementation:

The basis for this code is again taken from a code example that is provided by Cypress on GitHub. You can find that code example here:

github.com/cypresssemiconductorco/aws-iot

The awsThread starts with my evil extern.

Then I declare a function which is called when a message comes in from the MQTT broker.  I ASSUME that the message is an ASCII message formatted as %2.1f and I use sscanf to convert it to a float.  Many bugs have been made with this EXACT scheme.  It is expedient way to show people but it is a horrible habit.  I then send it to the temperature controller.

The main awsThread starts by initializing the AWS Client library, then connecting to AWS.  Lastly it subscribes to the setPoint topic.  Then it goes into an infinite loop calling the yield function which is responsible to listening to the aws MQTT socket and doing something with the data… specifically calling the callback.

#include "mbed.h"
#include "aws_client.h"
#include "aws_config.h"
#include "temperatureThread.h"

#define AWSIOT_ENDPOINT_ADDRESS             "a1c0l0bpd6pon3-ats.iot.us-east-2.amazonaws.com"


extern WiFiInterface *wifi;

static void messageArrived(aws_iot_message_t& md)
{
    float setPoint; 
    aws_message_t &message = md.message;
    sscanf((char*)message.payload,"%f",&setPoint);
    tempSendUpdateSetpointF(setPoint);
}

void awsThread(void)
{
    AWSIoTClient client;
    AWSIoTEndpoint* ep = NULL;

    /* Initialize AWS Client library */
    AWSIoTClient AWSClient(wifi, "thermostat" , SSL_CLIENTKEY_PEM, strlen(SSL_CLIENTKEY_PEM), SSL_CLIENTCERT_PEM, strlen(SSL_CLIENTCERT_PEM));

    aws_connect_params conn_params = { 0,0,NULL,NULL,NULL,NULL,NULL };
    ep = AWSClient.create_endpoint(AWS_TRANSPORT_MQTT_NATIVE, AWSIOT_ENDPOINT_ADDRESS, 8883, SSL_CA_PEM, strlen(SSL_CA_PEM));

    /* set MQTT connection parameters */
    conn_params.username = NULL;
    conn_params.password = NULL;
    conn_params.keep_alive = 60;
    conn_params.peer_cn = (uint8_t*) AWSIOT_ENDPOINT_ADDRESS;
    conn_params.client_id = (uint8_t*)"thermostat";

    /* connect to an AWS endpoint */
    AWSClient.connect (ep, conn_params);
 
    AWSClient.subscribe(ep, "setPoint", AWS_QOS_ATMOST_ONCE, messageArrived);
    while(1)
    {
        AWSClient.yield(1000);
    }
}

Update main.cpp

The last step is to start up the awsThread in main:

#include "mbed.h"
#include "blinkThread.h"
#include "displayThread.h"
#include "temperatureThread.h"
#include "capsenseThread.h"
#include "ntpThread.h"
#include "awsThread.h"

Thread blinkThreadHandle;
Thread displayThreadHandle;
Thread temperatureThreadHandle;
Thread capsenseThreadHandle;
Thread ntpThreadHandle;
Thread awsThreadHandle;

WiFiInterface *wifi;

int main()
{

    printf("Started System\n");

    int ret;
    wifi = WiFiInterface::get_default_instance();

    do {
            ret = wifi->connect("CYFI_IOT_EXT", "cypresswicedwifi101", NSAPI_SECURITY_WPA_WPA2);
            if (ret != 0) {
            ThisThread::sleep_for(2000); // If for some reason it doesnt work wait 2s and try again
            }
    } while(ret !=0);


    ntpThreadHandle.start(ntpThread);
    blinkThreadHandle.start(blinkThread);
    displayThreadHandle.start(displayThread);
    temperatureThreadHandle.start(temperatureThread);
    capsenseThreadHandle.start(capsenseThread);
    awsThreadHandle.start(awsThread);
    
}

Build, Program and Test

When you build and program the development kit.  You will be able to publish messages to the “setPoint” topic which will then change the setPoint on your system.  Remember that my parser is really not safe so just send %2.1f.

In the case below you can see that I publish 51.1:

Which changes the setPoint on my board.

 

Mouser PSoC 6 WiFi/BT MBED: L9 Amazon AWS MQTT Thread – Part2

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

Summary

In the last lesson we added an MQTT subscription that let’s the AWS servers control the setPoint.  In this lesson we will update the system to send out the current temperature every second – which I know is excessive.

To make the temperature publish changes I need to modify the awsThread to have a queue/command scheme just like the displayThread and the temperatureThread.  Then I will modify the temperatureThread to send out temperature changes to the awsThread which will take care of publishing changes.

To implement this I will:

  1. Import Lesson 08
  2. Modify awsThread.h
  3. Modify awsThread.cpp
  4. Modify temperatureThread.cpp
  5. Build, Program and Test

Import Lesson 09

Start by importing Lesson 08.

https://github.com/iotexpert/mouser-mbed-08.git

Modify awsThread.h

Add the function prototype for the other threads to queue temperature changes.

#ifndef AWS_THREAD_H
#define AWS_THREAD_H

void awsThread(void);
void awsSendUpdateTemperature(float temperature);

#endif

Modify awsThread.cpp

I will copy the scheme I built for the other threads.  There will be only one command, the one to send the temperature.

typedef enum {
    CMD_sendTemperature,
} command_t;

typedef struct {
    command_t cmd;
    float    value;   /* AD result of measured voltage */
} msg_t;


static Queue<msg_t, 32> queue;
static MemoryPool<msg_t, 16> mpool;

void awsSendUpdateTemperature(float temperature)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_sendTemperature;
        message->value = temperature;
        queue.put(message);
    }
}

Now I modify the main loop of the awsThread.  The AWSClient.yield function will time out every 1000ms which gives you the opportunity to do something.  That “something” is that I completely empty queue and then send the LAST update.

 bool doPublish=false;
    float currentTemp;
    while(1)
    {
        AWSClient.yield(1000);
        while(!queue.empty())
        {
            osEvent evt = queue.get(0);
            if (evt.status == osEventMessage) {
                msg_t *message = (msg_t*)evt.value.p;
                switch(message->cmd)
                {
                    case CMD_sendTemperature:
                        doPublish = true;
                        currentTemp = message->value;
                    break;

                }
                mpool.free(message);
            }
        }
        if(doPublish)
        {
            char buffer[128];
            sprintf(buffer,"%2.1f",currentTemp);
            AWSClient.publish(ep,"currentTemp", buffer, strlen(buffer),  publish_params);
        }
        doPublish = false;
    }

Here is the whole awsThread.cpp:

#include "mbed.h"
#include "aws_client.h"
#include "aws_config.h"
#include "temperatureThread.h"

#define AWSIOT_ENDPOINT_ADDRESS             "a1c0l0bpd6pon3-ats.iot.us-east-2.amazonaws.com"


extern WiFiInterface *wifi;

typedef enum {
    CMD_sendTemperature,
} command_t;

typedef struct {
    command_t cmd;
    float    value;   /* AD result of measured voltage */
} msg_t;


static Queue<msg_t, 32> queue;
static MemoryPool<msg_t, 16> mpool;

void awsSendUpdateTemperature(float temperature)
{
    msg_t *message = mpool.alloc();
    if(message)
    {
        message->cmd = CMD_sendTemperature;
        message->value = temperature;
        queue.put(message);
    }
}

void messageArrived(aws_iot_message_t& md)
{
    float setPoint; 
    aws_message_t &message = md.message;
    sscanf((char*)message.payload,"%f",&setPoint);
    tempSendUpdateSetpointF(setPoint);
}

void awsThread(void)
{
    AWSIoTClient client;
    AWSIoTEndpoint* ep = NULL;

    /* Initialize AWS Client library */
    AWSIoTClient AWSClient(wifi, "thermostat" , SSL_CLIENTKEY_PEM, strlen(SSL_CLIENTKEY_PEM), SSL_CLIENTCERT_PEM, strlen(SSL_CLIENTCERT_PEM));

    aws_connect_params conn_params = { 0,0,NULL,NULL,NULL,NULL,NULL };
    ep = AWSClient.create_endpoint(AWS_TRANSPORT_MQTT_NATIVE, AWSIOT_ENDPOINT_ADDRESS, 8883, SSL_CA_PEM, strlen(SSL_CA_PEM));

    /* set MQTT connection parameters */
    conn_params.username = NULL;
    conn_params.password = NULL;
    conn_params.keep_alive = 60;
    conn_params.peer_cn = (uint8_t*) AWSIOT_ENDPOINT_ADDRESS;
    conn_params.client_id = (uint8_t*)"thermostat";

    /* connect to an AWS endpoint */
    AWSClient.connect (ep, conn_params);
 
    AWSClient.subscribe(ep, "setPoint", AWS_QOS_ATMOST_ONCE, messageArrived);
    aws_publish_params publish_params = { AWS_QOS_ATMOST_ONCE };
    
    bool doPublish=false;
    float currentTemp;
    while(1)
    {
        AWSClient.yield(1000);
        while(!queue.empty())
        {
            osEvent evt = queue.get(0);
            if (evt.status == osEventMessage) {
                msg_t *message = (msg_t*)evt.value.p;
                switch(message->cmd)
                {
                    case CMD_sendTemperature:
                        doPublish = true;
                        currentTemp = message->value;
                    break;

                }
                mpool.free(message);
            }
        }
        if(doPublish)
        {
            char buffer[128];
            sprintf(buffer,"%2.1f",currentTemp);
            AWSClient.publish(ep,"currentTemp", buffer, strlen(buffer),  publish_params);
        }
        doPublish = false;
    }
}

Modify temperatureThread.cpp

In order to use the new functionality in the awsThread you need to modify the temperatureThread.

First add the #include “awsThread.h” (so that it has access to the awsThread public interface):

#include "mbed.h"
#include "temperatureThread.h"
#include "displayThread.h"
#include "awsThread.h"

Each time the temperature changes send the awsThread the update.

        {
            readTemp();

            // Control the HVAC system with +- 0.5 degree of Hystersis
            if(temperatureF < setPoint - 0.5)
                displaySendUpdateMode(-1.0);
            else if (temperatureF > setPoint + 0.5)
                displaySendUpdateMode(1.0);
            else
                displaySendUpdateMode(0.0);

            displaySendUpdateTemp(temperatureF);
            awsSendUpdateTemperature(temperatureF);
        }

Build, Program and Test

In order to test this I log into the AWS Test Console, and subscribe to the currentTemp topic.  Notice that temperatures keep coming!

 

Mouser PSoC 6 WiFi/BT MBED: L0 Introduction

Summary

Register for my Virtual Training Workshop – IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™ on December, 9 at 1:00PM Eastern Time!  I will be live-streaming a complete IoT Design using PSoC and WiFi – live for your entertainment … and hopefully education.

Hello everyone.  This is lesson 0 of a series of 10 lessons about creating an IoT application using the Cypress PSoC 6 MCU & WiFi radios.  For this class I will be building the solution using the Arm Mbed OS development platform.  This will include Mbed Studio and Mbed OS.  And I will be using the CY8CPROTO-062-4343W dev kit which you can purchase from Mouser.  As always I will be writing this code live … no powerpoint.  This is always an adventure and should make for good fun for everyone.

I am going to start by showing you the development kit and demonstrating how to use it.  Then we will build up a complete IoT application that acts like a IoT-ified thermostat by reading and controlling temperature, plus connecting to the internet.

I will attempt to go slowly enough for you to follow along, but if I go too fast, don’t worry you should be able to follow along with the instructions on this website.  I have attempted to put in screen shots and step-by-step instructions.

Today’s virtual workshop has this agenda table which will show also show up on every page.  The links will work to take you through the different lessons.

IoT Design with Cypress PSoC® 6 MCUs and Wi-Fi/Bluetooth using Arm® Mbed™

# Lesson GitHub Project
0 Introduction
1 Developer Resources
2 Your First Project & The Blinking Thread https://github.com/iotexpert/mouser-mbed-02.git
3 Display Thread https://github.com/iotexpert/mouser-mbed-03.git
4 Temperature Thread https://github.com/iotexpert/mouser-mbed-04.git
5 CapSense Thread https://github.com/iotexpert/mouser-mbed-05.git
6 WiFi & NTP Thread https://github.com/iotexpert/mouser-mbed-06.git
7 The CY8CKIT-062-WiFi-BT https://github.com/iotexpert/mouser-mbed-07.git 
8 Amazon AWS MQTT Thread - Part1 https://github.com/iotexpert/mouser-mbed-08.git
9 Amazon AWS MQTT Thread - Part2 https://github.com/iotexpert/mouser-mbed-09.git

You can “mbed import https://github.com/iotexpert/mouser-mbed-09.git“ to make a copy of the project in your workspace.

The final architecture of the thermostat looks like this.

 

You will need a few things for this class:

CY8CPROTO-062-4343W

This development kit (which you can buy from Mouser here) has a bunch of features which we will be using including:

  1. Programmer
  2. PSoC 6 MCU
  3. CYW4343W (WiFi Bluetooth combo chip)
  4. CapSense
  5. Thermistor
  6. LED

ModusToolbox 2.0

ModusToolbox 2.0 is the Cypress multi-platform development tool suite.  It includes several IDEs, Graphical Chip configurators, SDKs for Bluetooth, WiFi and PSoC 6 MCUs.

Mbed Studio

Arm Mbed Studio is an IDE for developing Mbed OS programs that target the Cypress PSoC 6 MCU.

Mbed Command Line Interface

The Mbed CLI is a command line interface for building and programming Mbed OS projects onto the PSoC 6 MCU.