CY8CKIT-021: Example 10 — The iOS App

Now that we have completely tested PRoC and PSoC4200M firmware the next step is to build an iOS App called Example 10.  The Xcode project is available in the Xcode directory in the project directory at github.com/iotexpert/cy8ckit-021/

Ill try to build this App to be as simple as possible.   Here is what the (single) screen looks like in three different state (nothing pressed, button0 pressed, led0 on):

IMG_0027     IMG_0028    IMG_0029

This App is built up with four files

  1. ViewController.swift: an object which controls the screen (button clicks)
  2. BluetoothNeighborhood.swift: an object which controls the Bluetooth in the phone and represents the CY8CKIT021 board (the Model)
  3. globals.swift: Defines the NSNotifications that can be sent
  4. Main.storyboard: The screen layout

The code will do the following:

  1. When the ViewController (VC) starts it will instantiate a BluetoothNeighborhood (BN) object
  2. VC: Tell the BN to start the bluetooth central in the phone
  3. BN: Scan for BLE Peripherals that are advertising the CY8CKIT-021 Service UUID
  4. BN: When it hears the peripheral with the correct UUID then connect
  5. BN: Read the state of the button0 and led0 then send an NSNotification
  6. BN: Turn on the notify for button0 (to cause the PRoC to send an NSNotification when there are changes)
  7. VC: update the screen when it gets the NSNotification from (5)
  8. VC: If the LED0 switch on the screen is switched then tell the BN to write to the PRoC
  9. BN: If the button0 is changed then send an NSNotification to the VC
  10. VC: If there is an NSNotification (9) of a button0 change then update the screen
  11. VC: If the bootloader button is pressed tell the BN to write the bootloader characteristic
  12. BN: If there is a disconnect event then send an NSNotification to the VC to disable the GUI elements and start scanning again (step 3)

ViewController.swift

The viewDidLoad method runs when the Apps starts and loads the first screen.  This method

  1. Initializes the BluetoothNeighborhood object
  2. Tell it to start the bluetooth scanning
  3. Disables the UI buttons
  4. Then registers with the NSNotificationCenter that it wants to hear the 4 possible messages that the model can send
    1. Connect: enable the buttons
    2. Disconnect: disable the buttons
    3. UpdateLED: reflect the current state of the LED on the screen
    4. UpdateButton: reflect the current state of the button on the screen

 

//
//  ViewController.swift
//  Example10
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
//  This file contains the viewcontroller for the single view application.
//  Basically when it loads you startup and connect to the bleboard
//  then display the state of things... or let the user flip the switch
//
 
import UIKit
 
class ViewController: UIViewController {
 
var bleLand : BlueToothNeighborhood!
 
override func viewDidLoad() {
super.viewDidLoad()
 
// bleLand-BlueToothNeighborhood is the model.  It is capable of finding
// a CY8CKIT021 and connecting to it. It can also read/write etc
bleLand = BlueToothNeighborhood()
bleLand.startUpCentralManager()
 
// start with the switch disabled.  it will turn on once there is a connection
led0switch.userInteractionEnabled = false
bootLoaderButton.userInteractionEnabled = false
 
 
// The global structure CY8CKITNotifications defines the different notificateions
// that can come from the bleLand model.  Basically a connection/disconnection or
// and update of the Led0 or Button0 State
 
// If you get a complete connection then turn on the buttons to start working
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.ConnectionComplete, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
self.led0switch.userInteractionEnabled = true
self.bootLoaderButton.userInteractionEnabled = true
}
 
// if you get disconnected then turn off the buttons
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.DisconnectedDevice, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
self.led0switch.userInteractionEnabled = false
self.bootLoaderButton.userInteractionEnabled = false
}
 
// The we got feedback from the model about the state of the button0
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdatedButton0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.button0.selected = self.bleLand.button0State }
 
// The we got feedback from the model about the state of the led0
NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdateLed0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.updateLed0() }
 
}

The GUI part of the code just acts when the button/switch is pressed to send messages to the model.  These methods are linked to the GUI elements on the main.storyboard

    // This function grabs the current button0 state from the model and sets the button
// to indicate it is either being pressed or not
func updateButton0()
{
self.button0.selected = self.bleLand.button0State
}
 
// This functiong rabs the current led0 state from the model and then flips the 
// switch the right way
func updateLed0()
{
led0switch.on = bleLand.led0State
}
 
@IBOutlet weak var button0: UIButton!
@IBOutlet weak var led0switch: UISwitch!
 
// When the user flips the switch you need to write the updated value to the model
@IBAction func led0SwitchAction(sender: UISwitch) {
 
bleLand.writeLed0Characteristic(sender.on)
}
 
// If the user presses the bootload button then send the bootload command
// this will cause and immediate BLE disconnect... etc
@IBOutlet weak var bootLoaderButton: UIButton!
@IBAction func startBootLoader(sender: AnyObject) {
bleLand.startBootloader()
}

BluetoothNeighborhood

This file contains all of the code that interacts with the CY8CKIT021 board.  The first block of code defines a structure with a list of the UUIDs that we need to search for.  These are defined in the Bluetooth Component Customizer from the PRoC firmware.

// BlueToothNeighborhood.swift
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This file contains the model for the CY8CKIT021 board with 1 LED0 and 1 Button 0
//
 
import CoreBluetooth
 
 
// This structure conatains the UUIDS for the services and characteristics on the board
// it MUST match what you defined in the creator BLE Configuration Wizard
private struct BLEParameters {
static let CY8CKIT021Service = CBUUID(string: "00000000-0000-1000-8000-00805F9B3400")
static let bootloadCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3401")
static let ledCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3402")
static let buttonCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3404")
 
}

The next block of code

// The model for the board
// The BlueToothNeighborhood has BOTH the board model and the Bluetooth model.  This
// makes the code slightly simpler to explain but is a bit weird architectururally
class BlueToothNeighborhood: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate  {
 
private var centralManager : CBCentralManager!
private var CY8CKIT021Board : CBPeripheral?
private var CY8CKIT021Service : CBService!
private var led0Characteristic : CBCharacteristic!
private var button0Characteristic : CBCharacteristic!
private var bootloadCharacteristic : CBCharacteristic!
 
// This function is called by the main view controller to get things going
func startUpCentralManager() {
centralManager = CBCentralManager(delegate: self, queue: nil)
}
 
// This is the bluetooth delegate function
@objc func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state) {
case .PoweredOff: break
case .PoweredOn:
print("Bluetooth is on - Starting scan")
// start scanning for a device that we can talk to
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
case .Resetting: break
case .Unauthorized: break
case .Unknown:break
case .Unsupported:break
}
}
 
// This delegate function is called by the bluetooth when it finds a device
// that matches our UUID that we told it when we started the scan
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
// if you already are connected to a device ignore this one
if CY8CKIT021Board == nil {
print("Found a new Periphal advertising CY8CKIT021 Service")
CY8CKIT021Board = peripheral
centralManager.stopScan()
centralManager.connectPeripheral(CY8CKIT021Board!, options: nil)
}
}
 
// This delegate is called when a device connection is complete
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("Connection complete \(CY8CKIT021Board) \(peripheral)")
CY8CKIT021Board!.delegate = self
CY8CKIT021Board!.discoverServices(nil)
}
 
// This delegate is called after the service discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print("discovered services")
for service in peripheral.services! {
print("Found service \(service)")
if service.UUID == BLEParameters.CY8CKIT021Service {
CY8CKIT021Service = service // as! CBService
}
}
CY8CKIT021Board!.discoverCharacteristics(nil, forService: CY8CKIT021Service)
}
 
 
// This delegate is called when the characteristic discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
for characteristic in service.characteristics!
{
 
print("Found characteristic \(characteristic)")
switch characteristic.UUID {
case BLEParameters.buttonCharactersticUUID: button0Characteristic = characteristic
case BLEParameters.ledCharactersticUUID: led0Characteristic = characteristic
case BLEParameters.bootloadCharactersticUUID: bootloadCharacteristic = characteristic
default: break
}
}
 
// You have a complete connection... so find out the current state of the LED0
// and Button.. then notify the viewcontroller that things are rolling
 
// read the led0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(led0Characteristic)
 
// read the button0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(button0Characteristic)
 
CY8CKIT021Board!.setNotifyValue(true, forCharacteristic: button0Characteristic)
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.ConnectionComplete, object: nil)
}
 
// disconnected device - start scanning again
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("Disconnected \(peripheral)")
CY8CKIT021Board = nil
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.DisconnectedDevice, object: nil)
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
}

The last block of code is responsible for interacting with the board

// start the bootloader...this will cause an immediate disconnect by the board
func startBootloader()
{
var val: UInt8 = 1 // it doesnt matter the value... any write will cause the bootloader to start
let ns = NSData(bytes: &val, length: sizeof(UInt8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: bootloadCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
 
// a helper function to write the the device
func writeLed0Characteristic(state: Bool)
{
var val : Int8
if(state)
{
val = 1
}
else
{
val = 0
}
let ns = NSData(bytes: &val, length: sizeof(Int8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: led0Characteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
// this is the model of the board
var button0State : Bool = false 
var led0State : Bool = false // assume that it is off
 
// This delegate function is called when an updated value is received from the Bluetooth Stack
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
if characteristic == button0Characteristic {
var out: UInt8 = 0
characteristic.value!.getBytes(&out, length:sizeof(UInt8))
if(out == 0)
{
button0State = false
}
else
{
button0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdatedButton0, object: nil)
}
 
if characteristic == led0Characteristic {
var out: NSInteger = 0
characteristic.value!.getBytes(&out, length:sizeof(UInt8))
if(out == 0)
{
led0State = false
}
else
{
led0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdateLed0, object: nil)
}
}

In the next post Ill show you how to build the Android App.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: The PRoC BLE Firmware

In the next few posts I am going to show how to build a very simple BLE project for the shield, debug it using CySmart, make an iOS app, and finally make an Android app.  I am going to try to only put in the bare minimum of feature that will enable you to see the whole project work from end to end.  This next series of posts will use

  • LED0: which can be turned on/off from the from the Android and iOS App
  • Button0: which will be displayed as on/off on the Android and iOS App
  • Bootload: you will be able to trigger the bootloader from the baseboard or by writing into the BLE Bootload characteristic
  • The blue LED attached to the PRoC will blink when advertising and be solid when connected

All of this firmware is available as Example10a (for the PRoC) and Example10b for the PSoC4200m in the firmware directory on github.com/iotexpert/CY8CKIT-021

Example 10a: The PRoC Firmware

The schematic for this project has two pages.  The first page has everything except for the bootloadble.

Screen Shot 2016-05-30 at 10.11.35 AM

The second page of the schematic has the bootloadable.  This allows me to “disable” that page if I am not using the Bootloader

Screen Shot 2016-05-30 at 10.14.59 AM

The BLE component has the “CY8CKIT021” service with three characteristics one for LED0, Button and Bootload,  The Button has a notify CCCD setup.  All three are uint8s.

Screen Shot 2016-05-30 at 10.11.56 AM

This program is broken up into three functions

  • updateGattDB: A helper function that can take data as a void* and write it into the correct place in the GattDB.  For example when the app changes the LED0 Characteristic you need to write that update into the GattDB.  This function is generic which will support the same logic on a bunch of different characteristic (for instance when I put in all of the other characteristics LED0/1, Button0/1, Pot, …)
  • BleCallBack: This function  processes the BLE Events
    • Stack on or disconnect: start advertising and start blinking
    • Write of characterstic from Central: store the written value into the GattDB and do something
    • Connect: update the GattDB and turn on the LED
  • main: This function is very simple and forms the main loop of the program.
    • Start the components
    • If there is a remote from the 4200M side then update the GattDB

First, the updateGattDB helper function.

// updateGattDB() -  
//
// Arguments: 
//  uint8* val  - a pointer to the bytes that need to be writted into the GATTDB
//  int size - the number of bytes that need to be written into the GATTDB
//  uint8 notify - if the NOTIFY is on then send a notification
//  CYBLE_GATT_DB_ATTR_HANDLE_T handle - a handle to the entry in the gatt table
//  uint8 flags - a request 
//   
// This is a helper function that will update the GATT database with a value.  It update the field of
// the "CYBLE_GATT_DB_ATTR_HANDLE_T"
 
void updateGattDB(uint8 *val,int size,uint8 notify, CYBLE_GATT_DB_ATTR_HANDLE_T handle,uint8 flags)
{
 
// this little block of code doesnt make me happy... 
switch(CyBle_GetState())
{
case CYBLE_STATE_ADVERTISING:
return;
case CYBLE_STATE_DISCONNECTED:
return;
case CYBLE_STATE_STOPPED:
return;
case CYBLE_STATE_CONNECTED:
break;
case CYBLE_STATE_INITIALIZING:
return;
}
//update the GATT Database
CYBLE_GATTS_HANDLE_VALUE_NTF_T 	tempHandle;
tempHandle.attrHandle = handle;
tempHandle.value.val = val;
tempHandle.value.len = size;
CYBLE_GATT_ERR_CODE_T ret = CyBle_GattsWriteAttributeValue(&tempHandle,0,&cyBle_connHandle,flags);
if(ret != CYBLE_GATT_ERR_NONE) // this is really not a good place to be.
{
return;
 
CYASSERT(0);
while(1);
}
// if peer initiated then write response.
if(flags == CYBLE_GATT_DB_PEER_INITIATED)
CyBle_GattsWriteRsp(cyBle_connHandle);
else if(notify) // If notify & local initiated 
{
CyBle_GattsNotification(cyBle_connHandle,&tempHandle);
}    
}

The next block of code is the BleCallback.  One cool thing that PSoC Creator does is give you the ability to #ifndef to remove code when a schematic page is disabled.  In the code below when I have “disabled” the Bootloadable schematic page it will remove that block of code from my firmware.

/***************************************************************
* Function to handle the BLE stack
**************************************************************/
void BleCallBack(uint32 event, void* eventParam)
{
CYBLE_GATTS_WRITE_REQ_PARAM_T *wrReqParam;
switch(event)
{
/* if there is a disconnect or the stack just turned on from a reset then start the advertising and turn on the LED blinking */
case CYBLE_EVT_STACK_ON:
case CYBLE_EVT_GAP_DEVICE_DISCONNECTED:
CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST);
PWM_Start();
memset(&notifyFlags,0,sizeof(notifyFlags));
break;       
 
case CYBLE_EVT_GAP_DEVICE_CONNECTED:           
PWM_Stop();
updateGattDB(&BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
updateGattDB(&BLEIOT_local.button0,sizeof(BLEIOT_local.button0),notifyFlags.button0,CYBLE_CY8CKIT021_BUTTON0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
break;
 
case CYBLE_EVT_GATTS_WRITE_REQ:
wrReqParam = (CYBLE_GATTS_WRITE_REQ_PARAM_T *) eventParam;
// Bootload
#ifndef BootLoadable__DISABLED
if(wrReqParam->handleValPair.attrHandle == CYBLE_CY8CKIT021_BOOTLOAD_CHAR_HANDLE)
{
if(wrReqParam->handleValPair.value.val[0]) Bootloadable_Load();
 
}
#endif
 
// LED0
if(wrReqParam->handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CHAR_HANDLE)
{
BLEIOT_updateLed0(wrReqParam->handleValPair.value.val[0]);
updateGattDB(wrReqParam->handleValPair.value.val,1,notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_PEER_INITIATED);
}
 
if(wrReqParam->handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CCCD_DESC_HANDLE)
{
notifyFlags.led0 = wrReqParam->handleValPair.value.val[0];
CyBle_GattsWriteRsp(cyBle_connHandle);
}
 
// BUTTON 0
if(wrReqParam->handleValPair.attrHandle == CYBLE_CY8CKIT021_BUTTON0_CCCD_DESC_HANDLE)
{
notifyFlags.button0 = wrReqParam->handleValPair.value.val[0];
CyBle_GattsWriteRsp(cyBle_connHandle);
}
break;  
 
default:
break;
}
}

Finally the last block of code is the main loop

int main()
{
CyGlobalIntEnable;
BLEIOT_Start();
 
EZI2C_Start();
EZI2C_EzI2CSetBuffer1(sizeof(BLEIOT_local),1,(uint8 *)&BLEIOT_local);
 
CyBle_Start(BleCallBack);
 
for(;;)
{
 
#ifndef BootLoadable__DISABLED
// if they write into the BLEIOT_local.bootload (from EzI2C)
if(BLEIOT_getDirtyFlags() & BLEIOT_FLAG_BOOTLOAD || BLEIOT_local.bootload)
{
// enter the bootloader
Bootloadable_Load();
}
 
#endif
 
if(BLEIOT_getDirtyFlags() & BLEIOT_FLAG_LED0)
{
BLEIOT_updateLed0(BLEIOT_remote.led0);
updateGattDB(&BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
}
 
if(BLEIOT_getDirtyFlags() & BLEIOT_FLAG_BUTTON0)
{
BLEIOT_updateButton0(BLEIOT_remote.button0);
updateGattDB(&BLEIOT_local.button0,sizeof(BLEIOT_local.button0),notifyFlags.button0,CYBLE_CY8CKIT021_BUTTON0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
}
 
CyBle_ProcessEvents();
CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);
}
}

PSoC FIRMWARE

To make this project work I built the simplest firmware that I can think of for the PSoC4200M.  The schematic has only the BLEIOT, CapSense and the LED.

Screen Shot 2016-05-30 at 11.11.51 AM

The firmware just

  • Starts the components
  • If the capsense is not busy then it updates the Button0 state if it has changed then rescans
  • If the PRoC side writes the LED0 then it updates the state.
// Project: Example10b - PSoC
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project demonstrates the simplest connection to the PRoC and BLE
// It updates the LED0 based on writes from the PRoC side
// It sends out updates to the PRoC based on button processes
#include <project.h>
 
int main()
{
CyGlobalIntEnable;
 
BLEIOT_Start();
CapSense_Start();
CapSense_InitializeEnabledBaselines();
CapSense_ScanEnabledWidgets();
 
for(;;)
{
if(!CapSense_IsBusy())
{
uint8 b0=CapSense_CheckIsWidgetActive(CapSense_BUTTON0__BTN);
if(b0 != BLEIOT_local.button0) // if the state has changed then send an update
BLEIOT_updateButton0(b0);
CapSense_UpdateEnabledBaselines();
CapSense_ScanEnabledWidgets();
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0)  // if the PRoC side send an update, write it
{
BLEIOT_updateLed0(BLEIOT_remote.led0);
led0_Write(!BLEIOT_local.led0); // the led is active low
}
}
}
</project.h>

 

Debugging using CySmart

After I created all of the code and bootloaded it into the PRoC I used CySmart to debug it.  Once the board is reset I can see the blinking blue LED that is connected to the PRoC.   When I start CySmart I can see the “C021” board (that is the name I gave the device in the Gap settings:

Screenshot_20160530-112449

When I connect to the device and explore the Gatt Database I can see the three characteristics (Boatload, LED0 and Button0).  You can recognize them from the UUIDs that I configured in the component.

Screenshot_20160530-112358

When I write a 1 into the LED0 characteristic the Green LED0 lights up.

Screenshot_20160530-112421

When I turn on notification for the Button0 characteristic and then touch the button I can see it turn back and forth from 0/1

Screenshot_20160530-112435

Now that everything seems to be working Ill move onto the iPhone App in the next post.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: Using the BLEIOT Component

Now that we have a component built up, I will build up a test to demonstrate its functionality.  The test will do the following

On the PSoC side it will:

  • Read the Capsense Button0.  If it is pressed it will send a “boatload” command to the PRoC
  • Read the Capsense Button1.  Each time it is pressed it will toggle the PRoC blue LED by sending alternating On/Off
  • Read the remote LED0 update and turn on/off the LED0 based on the remote command

On the PRoC side it will:

  • Alternate sending a 1/0 every 500ms to the “led0” on the PSoC side
  • If the Capsense Button 0 is changed from the PSoC side it will turn the Blue LED On/Off
  • If it get a Bootload it will enter the bootloader

These projects are available as Example9 in the CY8CKIT-021 workspace that is in the firmware directory on github at github.com/iotexpert/CY8CKIT-021

PSoC

After creating a new schematic for PSoC 4200m, the next thing that I do is make a dependency to the components in the BLEInterface project.  This gives me access to the BLEIOT component.

Screen Shot 2016-05-28 at 11.56.18 AM

When I go to the component catalog I see the “IOT” and in that tab I find the  IOT Tab with the BLEIOT component.

Screen Shot 2016-05-28 at 12.02.55 PM

Now I add components for CapSense and the LED to get the final schematic.

Screen Shot 2016-05-28 at 12.09.56 PM

Now assign the Pins in the cydwr.

Screen Shot 2016-05-28 at 12.10.57 PM

And finally the code:

// Project: Example9b-PSoC-BLEIOT-Test
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project demonstrates using the BLEIOT component
// If the other side writes the LED then update it
// If the user presses button 0 then send an bootload command
// If the user presses button 1 then send an update to the button
 
#include <project.h>
 
int main()
{
CyGlobalIntEnable; 
CapSense_Start();
CapSense_InitializeEnabledBaselines();
CapSense_ScanEnabledWidgets();
 
BLEIOT_Start();
 
for(;;)
{
if(!CapSense_IsBusy())
{
uint8 b0 = CapSense_CheckIsWidgetActive(CapSense_BUTTON0__BTN);
uint8 b1 = CapSense_CheckIsWidgetActive(CapSense_BUTTON1__BTN);
 
if(b0)
BLEIOT_updateBootload(1); // send the bootload command
 
if(b1 != BLEIOT_local.button1) // if the button state has changed send it
BLEIOT_updateButton1(b1);
 
CapSense_UpdateEnabledBaselines();
CapSense_ScanEnabledWidgets();
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0) // other side wrote LED0, update state
{
BLEIOT_updateLed0(BLEIOT_local.led0); // update local state
led0_Write(!BLEIOT_remote.led0); // the LED is active low
}
}
}
</project.h>

PRoC

Unfortunately it is prohibited to create custom components for PRoC BLE devices.  So, the first thing that I do after creating the project is to copy over BLEIOT_BLEIOT.c and BLEIOT_BLEIOT.h from the generated source directory of the PSoC project.  Yes I understand that this is a bit of a lame thing to do, but there it is:

cd Example9a-ProC-BLEIOT-Test.cydsn/
cp ../Example9b-PSoC-BLEIOT-Test.cydsn/Generated_Source/PSoC4/BLEIOT_BLEIOT.* .

One you have the files in the correct directory you need to add them to the project by right clicking on the “header files” in the workspace explorer and “add existing” then adding the BLEIOT_BLEIOT.h.  You also should do the same with “source files” and BLEIOT_BLEIOT.c

Finally you need to add #include “BLEIOT_BLEIOT.h” to the top of BLEIOT_BLEIOT.c

After that I finish the schematic.  First, add a UART Component to the schematic and call it BLEIOT_UART (so that it will match the code that was generated in the other project).  Then add the bootloadable and the blue LED pin.  Don’t forget to configure the Bootloadable to link to the bootloader just like Example 8.  Also you need to configure the UART to have a 32 byte software buffer.

Screen Shot 2016-05-28 at 12.40.14 PM

Then assign the pins:

Screen Shot 2016-05-28 at 12.41.51 PM

Finally the main.c

// Project: Example9b-PRoC-BLEIOT-Test
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project should be bootloaded into the PRoC.  It demonstrates using the BLEIOT
// component.
//
// Using the systick, send an update to led0 every 500ms
// If the other side writes to Bootload... then start the bootloader
// If the other side writes to the button1... then display that on the blue led
#include <project.h>
#include "BLEIOT_BLEIOT.h"
 
int countMs =0;
 
// This is the ISR for the systick
void sendLedUpdate()
{
if(countMs++&lt;500) // count 500ms
return;
countMs = 0;
BLEIOT_updateLed0(!BLEIOT_local.led0);
}
 
int main()
{
 
CyGlobalIntEnable; 
CyDelay(100);
BLEIOT_Start();
 
CySysTickStart(); // start the systick and register our call back
CySysTickSetCallback(0,sendLedUpdate);
 
for(;;)
{
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BOOTLOAD)
Bootloadable_Load();
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BUTTON1)
{
BLEIOT_updateButton1(BLEIOT_remote.button1);
blue_Write(!BLEIOT_local.button1);
}
}
}
</project.h>

 

As always these projects are available in the firmware directory at http://github.com/iotexpert/CY8CKIT-021

In the next post Ill show you the BLE Firmware.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: The BLEIOT Component

The PRoC (on the shield) and the baseboard share two pairs of lines that are connected to the Serial Communication Blocks (SCBs) on the chips.  One of the pairs is also connected to the standard I2C Arduino bridge pins and in fact this is how you bootloaded the PRoC in the previous example.  When I started thinking about the problem of making the PRoC on the shield talk to the baseboard I knew that I wanted either side to be able to initiate communication and I did not want either side to poll.  This fact eliminated the master/slave scheme of I2C or SPI.  OK.  UART it is.

The next thing that I knew that I wanted was one set of firmware that would work exactly the same on both side.  This lead me to build a component called BLEIOT.  This component has the following features

  1. It transmits its local status every 20 ms
  2. It is triggered by the Systick
  3. It uses UART to transmit and receive
  4. It has a “Update” API which will update the local and remote state
  5. It has dirtyFlags which are a bit mask of what was written from the other side and is different than the current local status
  6. The component works the same on both sides
  7. It has a data structure that represents all of the peripherals on the shield (LEDs, Thermistor, CapSense Buttons etc)

The system works by having a “local” copy of the state and a last known “remote” copy of the state.  There is a C-Structure that represents each of the system variables (LED, CapSense, …).  The way it works is:

  1. When something changes in your system you use the “Update” API.
  2. The update API changes the local state and the “Write Flags” which is just a bit mask of all of the local variables
  3. Every 20ms the component sends the local table to the remote side (assuming something has been written)
  4. The remote side then looks at each variable that has been “written” and compares it against the local copy.  If they are different then it marks the “dirtyFlags” with the corresponding bitmask
  5. On either side you can monitor the “dirtyFlags”.  If the dirtyFlag for a variable is set then you know that the other  side changed it and you can do something.
  6. When you run the “Update” API if you write your local copy to be the same as the remote copy then you will clear the dirtyFlag.

This project is available as BLEInterface in the CY8CKIT-021 workspace that is in the firmware directory on github at github.com/iotexpert/CY8CKIT-021

Here is a picture of the architecture:

bleiot1

An example:

  1. Everything starts in sync
  2. The PSoC turns on an LED with Pin_Write()
  3. The PSoC calls the BLEIOT_updateLed API
  4. That BLEIOT_updateLed API updates the local state table
  5. That BLEIOT_updateLed API marks the “writeFlag” corresponding to the LED
  6. The PSoC systick triggers the BLEIOT component to send the local table to the PRoC via UART
  7. The PRoC UART receives the table and calls the BLEIOT_receive API
  8. The PRoC BLEIOT component looks at the “Write Flags” and notices that the LED was written, so it marks the dirtyFlag corresponding to the LED
  9. The PRoC  main loop notices the dirtyFlag and turns on the LED using Pin_Write
  10. The PRoC then runs the BLEIOT_updateLed function which updates the local state and clears the dirtyFlag
  11. The PRoC systick calls the BLEIOT_send which sends the local state table to the PSoC
  12. The PSoC calls the BLEIOT_receive
  13. The PSoC BLEIOT_receive notices that the LED was written but that its remote state now matches its local state so it doesn’t do anything

Building the Component

In order to make a component this component I need

  1. A symbol for the component
  2. A schematic (with the UART)
  3. The BLEIOT.h (which is the public interface to the component)
  4. The BLEIOT.c (which hold the functions that makeup the component)

To make the component I start by adding a “library project” to my workspace called BleInterface.  You do this from the new project dialog.

Then I click on the components tab of the BleInterface project.  This is a bit of a trick as it seems like the library is “empty” but it isn’t.

Screen Shot 2016-05-27 at 1.49.08 PM

The next step is to create a symbol by right clicking the library and saying “add component item” and choosing Symbol Wizard.  If you are doing this make sure that you give the component a good name (or at least something better than “component01”

Screen Shot 2016-05-27 at 1.54.36 PM

This component does not have any visible terminals so just accept the defaults.

In the next step I create a schematic to hold the UART component.  When you add the component item for the schematic you need to configure the architecture to target the PSoC4 family in order to have access to place the SCB UART.  After you have placed the UART component you will automatically get “buried” pins which you can assign for that component.

Now that I have a schematic and a symbol, the last steps are to add the .h and .c

The .h contains the public interface to the component.

Screen Shot 2016-05-27 at 2.46.10 PM

This section defines the public interface.  On update function per system state.

Screen Shot 2016-05-27 at 3.36.00 PM

The bit masks for the dirtyFlags and updatedFlags

Screen Shot 2016-05-27 at 2.46.48 PM

The definition of the table of variables.

Screen Shot 2016-05-27 at 2.47.15 PM

The last thing that you need is “BLEIOT.c”

Screen Shot 2016-05-28 at 8.31.24 AM

The update function is a generic function that will “update” the local table with the current value of one of the local status (LED0, CapSense …).  This function is called by the various helper function (updateLed0, updateBootload, updateCapsense,…)

Screen Shot 2016-05-28 at 8.32.08 AM

Screen Shot 2016-05-28 at 8.37.10 AM

Screen Shot 2016-05-28 at 8.37.35 AM

This function sends the data to the other side when it gets a turn from the systick interrupt

Screen Shot 2016-05-28 at 8.37.50 AM

In the next post Ill show you an example project of the BLEIOT.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: Bootloading the PRoC

Now that I have shown you how to make all of the basic functions of the devkit work, I really want to make this shield into an IOT Device.  In order to do this I need to:

  1. Get the bootloading to work (so I can put firmware into the PRoC)
  2. Have a scheme to communicate between between the PRoC and the Baseboard (the subject of the next posts)
  3. Have BLE Firmware (the subject of the next posts)

Bootloading the PRoC

When the India team sent me the shield, the EZ-USB PRoC came preprogrammed with a bootloader project.  They also sent me the bootloader project that is programmed into the device.  That project, called “I2C_Bootloader”, is in the workspace that you can find in the firmware directory at github.com/iotexpert/CY8CKIT-021.  In order to make your own firmware application for that PRoC you need to make a reference to the bootloader project in the bootloadable component.

When I first plugged in the board I thought that I was going to have a seizure as the blue LED is blinking like crazy.  That has got to go!  To get firmware into the PRoC you either need to solder a header onto the board so that you can use a miniprog-3 (which I also did) and/or you can bootload the firmware.  The I2C Pins on the PRoC are connected to the KitProg I2C pins on the baseboard.

Bootloading is the process of transferring a hex file image via a serial connection (I2C in this case) into the chip, then flashing it into the memory in the right place.  I wrote in detail about this process in this post “The Creek: PSoC4 Bootloader + Firmware”.    Here is a picture of the architecture:

bootloading

First ill explain the bootloader project.  This project will:

  • Wait for 100ms, and if the Pin_BL_Select is held low it will start the bootloader otherwise it will start application.  This was done so that you could signal the PRoC from the board that it was plugged into to start the boot loading process via a GPIO.
  • If there is no application firmware or the application firmware is invalid then it will start the bootloader
  • The bootloader will listen to the I2C on address 0x0B and load in firmware when it gets a request
  • The application is yours to write.

The schematic is simply a blank SCB I2C component to service the Bootloader, a GPIO pin, a blinking LED using the PWM and the Bootloader component.

Screen Shot 2016-05-26 at 7.31.10 AM

Here is the configuration of the I2C component — just 400KBS and slave address 0x0B:

Screen Shot 2016-05-26 at 9.40.45 AM

Here is the configuration of the Bootloader:

Screen Shot 2016-05-26 at 9.40.27 AM

And finally the main.c

Line 23-49 are run if the digital input pin is held low when the chip is booted… indicating that you want the bootloader to start.  You use this to get the PRoC back into the bootloader mode if you have already programmed firmware into it that does something else.

Line 25-32 is a loop that goes for 100ms and makes sure that the line is held down the whole time.  If it is NOT held down then it break out of the loop and start the application (By falling out of the loop)

Line 34-42: if the pin was held down the whole time, then configure the the bootloader component to start

Line 54:  Start the bootloader component.  The component is configured to start the application immediately upon startup.  If line 36 is run, then it will start the boot loading process.  (this was a bit confusing to me when I first looked at this program)

Screen Shot 2016-05-26 at 7.35.47 AM

A Bootloadable Application

Now that you understand the bootloader application, Ill build a simple simple bootloadable (just a program that can be loaded by the bootloader).  My application will do only two things.

  1. It will blink the LED at 1HZ
  2. If will have an EzI2C component.  If there is something other than “0” written to address 0 it will launch the bootloader (so you can restart the bootloader)

Screen Shot 2016-05-27 at 5.29.44 AM

Once the schematic is configured you need to configure the bootloadable component.  Basically you need to tell it where the bootloader hex file exists on your system.  This is required because the bootloader and the bootloadable need to come in pairs.

Screen Shot 2016-05-27 at 4.52.53 AM

The main.c is very straightforward.

Screen Shot 2016-05-27 at 5.27.11 AM

Once you have the project put together you will use the “build” menu to create the “.cyacd” file.  That is just the hex file in a format that can be read by the Bootloader host.  The Bootloader host know how to talk to a Cypress I2C bridge (either KitProg or MiniProg-3) and then send the CYACD file to the PRoC bootloader.

The process is

  1. Start the Bootloader host (from the windows start menu or by right clicking the bootloadable component)
  2. Find the .CYADC file for your project
  3. Select the KitProg and the correct I2C address (remember I set 0x0B which is also known as 11)
  4. Then click the “download” arrow

After each of those steps is done you will see the file being downloaded.  Then you will see you the Blue LED on the kit start blinking a 1hz.  Success!

Screen Shot 2016-05-27 at 5.26.58 AM

If you are ready to start the bootloader again you now have two options

  1. Hold down the PRoC Pin P04 for 100ms as the PRoC boots
  2. Attach the I2C bus and write a 1 to I2C address 0x0B.  The easiest way to do this is with the bridge control panel (see the picture below)

Screen Shot 2016-05-27 at 5.28.02 AM

Finally, On Cypress.com we have a ton of good Application Notes and data sheets to help you understand Bootloading.

AN73854 – PSoC® 3, PSoC 4, and PSoC 5LP Introduction to Bootloaders

The Booloader and Bootloadable Component Datasheet

AN86526 – PSoC® 4 I2C Bootloader

AN73503 – PSoC® USB HID Bootloader

AN60317 – PSoC® 3 and PSoC 5LP I2C Bootloader

AN68272 – PSoC® 3, PSoC 4, and PSoC 5LP UART Bootloader

Now that you know how the bootloader and bootloadable projects work Ill address the communication between the PSoC and the PRoC in the next post.

CY8CKIT-021: The Next 3 Example Projects

In the previous post I introduced 4 basic example projects.  In this post Ill finish up the examples with the Thermistor and two Capsense projects.

  • Example 5: A Thermistor
  • Example 6: 2 Capsense Buttons (using the V2.x component)
  • Example 7: 2 Capsense Buttons (using the new V3.x component + tuner)

Example 5: The Thermistor

A thermistor is a resistor that changes resistance with temperature in a known way.  You can use it in combination with a precision reference resistor to calculate temperature.  PSoC Creator provides a component for making this easy as the actual formula is crazy.  Here is the schematic.  R1 is the known reference resistor.  RT1 is the thermistor.  J6 is a selector that lets you select the analog input from the shield to either be the POT or the Thermistor.

Screen Shot 2016-05-25 at 7.07.26 AM

The schematic is simple.  Just an Analog to Digital Convertor and the LCD from the previous design plus the Thermistor.  Notice that the Thermistor symbol shows the configuration that you need on the schematic to make this work.

Screen Shot 2016-05-25 at 7.10.17 AM

In the Thermistor configuration window you get to select the size of the reference resistor (in this case it is 10K) and if you want to use a LUT or use an Equation.  If you choose LUT then PSoC Creator will pre-calculate a temperature versus resistance table and embed that into your program.  This will enable very fast calculation of temperature but will take more flash.

Screen Shot 2016-05-25 at 7.11.48 AM

The main.c just reads the voltage, calculates the resistance (using the API), calculates the temperature (using the API) and then displays it on the LCD.  The only problem with this whole setup is that it depends on knowing the exact VDDA voltage because you need to know the voltage across the reference resistor.  I use the handy PSoC Creator #define CYDEV_VDDA_MV to find out what the configured voltage.  The problem with this circuit is that the VDDA will vary and this will throw off the temperature calculation.  This could have been solved if we had used two differential measurements, but we were out of pins.

Screen Shot 2016-05-25 at 7.15.20 AM

Example 6: The CapSense Buttons using the 2.x Component

There are two CapSense buttons on this Development Kit.  I started with the old CapSense component because I know the APIs without looking at the examples.  We have now upgraded the component to support features in the new CapSense block (which I will show in the next example).  The V2.x schematic is simple with just the CapSense component plus the two LED pins.

Screen Shot 2016-05-25 at 7.23.14 AM

The CapSense component uses the default settings including SmartSense tuning.

Screen Shot 2016-05-25 at 7.23.40 AM

I add two buttons and use the default values.

Screen Shot 2016-05-25 at 7.23.51 AM

The code is also very simple.

Screen Shot 2016-05-25 at 7.27.01 AM

Example 7:  CapSense 3.0

In PSoC Creator 3.3 we released a new component to support features in the new CapSense block that was put into the new PSoC 4000S/4100S family.  Like the previous example, this project will light up the LEDs when the corresponding button is pressed. The addition in this example is the EZi2C to support the tuner (which is also new).

Screen Shot 2016-05-25 at 7.42.07 AM

In the EZI2C you need to change the defaults from 100kbps to 400 kbs and 8-bit subaddress to 16-bit subaddress.

Screen Shot 2016-05-25 at 7.42.20 AM

 

The first time I put this design together I noticed that the CapSense buttons were very sensitive.  Very means that you get a touch when your finger is 1mm or more from the surface of the button.  I thought that as long as I was going to manually tune some of the buttons that I will show the new tuner-which is really cool-in this example.

First configure two buttons and set the tuning to SmartSense (Hardware parameters only).

Screen Shot 2016-05-25 at 7.42.39 AM

The main.c is also very simple.

Screen Shot 2016-05-25 at 7.45.36 AM

The last step is to run the tuner.  The default finger threshold is 100.  To make the button less sensitive I increase the button touch to 500.  You can see in the picture below that Button 0 has about 1300 counts of signal when I am touching the button so 500 gives us plenty of room to not miss a touch.  You can see that just sitting there untouched that the signal is about 6850 counts and when there is a touch it is about 8150.

Screen Shot 2016-05-25 at 10.49.30 AM

Button 1 is more interesting.  I decided to run a signal-to-noise measurement on the button.  Here is the “acquire noise” graph.  You can see that just sitting there untouched, the signal is about 54170 and there is about 54 counts of noise.  That is quite a bit different than Button 0 which has a baseline of about 6850.  I don’t know why they are so different.

Screen Shot 2016-05-25 at 10.51.29 AM

When I run the signal acquisition I get this graph.  You can see that a “touch” is about 65500 which means that there is about 10000 counts of difference, so a threshold of 500 will also be stable, in fact it could be 5000 and work just fine.

Screen Shot 2016-05-25 at 10.52.12 AM

Here is the touch graph:

Screen Shot 2016-05-25 at 10.50.37 AM

In the next post I will talk about the BlueTooth Firmware.

Alan

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: The First 4 Example Projects

Recall from the last post that the CY8CKIT-021 has 6 different peripherals to attach to.  The first thing that I did with the board is build a simple example for each of the peripherals.  I built all of the projects on the PSoC4200M development board which is also known as CY8CKIT-044.  The pinout for the other kits will be different, but the PSoC projects will be the same, but with a different pin map.  Later in the week I’ll show projects for the FM0 and FM4 development kits.  All of these projects  are available at github.com/iotexpert/CY8CKIT-021 in the firmware directory and in a single workspace.

  • Example 1: 2 LEDs
  • Example 2: A buzzer
  • Example 3: A direct drive 7-segment LCD
  • Example 4: A potentiometer
  • Example 5: A thermistor
  • Example 6: 2 Capsense Buttons (using the V2.x component)
  • Example 7: 2 Capsense Buttons (using the new V3.x component + tuner)

Example 1: Two LEDs

This weekend I taught people at the Bay Area Maker Faire to program PSoC.  I told them that the first project that you always do is the blinking LED.  This simple project is perfect to show that the tools work etc.  So, that is what we will do here.  For this example I used a TCPWM to blink the two LEDs.  One LED is connected to the line output and the other one is connected to the line_n output.  This will cause the LEDs to alternate.  The only other slightly interesting thing that I do is put the CPU to sleep and just let the hardware do the blinking.

 

Screen Shot 2016-05-24 at 8.21.03 AM

Screen Shot 2016-05-24 at 8.23.44 AM

Screen Shot 2016-05-24 at 8.21.26 AM

Screen Shot 2016-05-24 at 8.21.43 AM

Example 2: A buzzer

To beep the buzzer I will use a 440hz tone that is generated by the TCPWM which divides an input clock of 440khz by 1000 to achieve the note “A” or “A4”.  To make the tone turn on and off I do my most hated thing, use the CyDelay to make a busy wait loop.  Basically, I turn on the PWM, wait for 500ms then turn it off, wait for 500ms and then go back to the start.

Screen Shot 2016-05-24 at 8.25.20 AM

Screen Shot 2016-05-24 at 8.25.33 AM

Screen Shot 2016-05-24 at 8.26.34 AM

Screen Shot 2016-05-24 at 8.25.53 AM

Example 3: Direct Drive 7 Segment LCD

A very cool feature of almost all of the PSoCs is their ability to drive “direct drive LCDs”.  This is a very low cost, low power way to add a display to your design.  This display we used on this board is a Lumex LCD-S401M16KR  that costs $0.73 from Mouser.  Internally, all LCDs are organized into rows and columns a.k.a Segments and Commons.  To enable a particular segment in the LCD you need to select the correct row and column.  Then to make a symbol on the screen you need to select the combination of segments for that number.  For example, from the picture below, to make a “7” on the left digit you would need to turn on C3/S1, C2/S1, and C1/S1.  This would be a serious pain in the ass, but conveniently, the PSoC Creator segment LCD component does this for you automatically.

Our Lumex display is organized into 8 Segments and 4 Commons.  This means that it takes 12 pins on the chip and can show 32 segments.  The segments are organized into 4 characters with 7 segments (28 total segments), a decimal point between each character (3 segments) and a colon. Here is a picture:

Screen Shot 2016-05-24 at 8.53.59 AM

First add the segment LCD component to your design and attach a clock

Screen Shot 2016-05-24 at 9.17.07 AM

Then make the top level configuration (4 commons and 8 segments)

Screen Shot 2016-05-24 at 9.17.15 AM

To configure the component display you need to first add a “7 segment” helper to your component by selecting it and then clicking the right arrow.  Then you click the “+” 4 times to add 4 digits to your design.  Then you need to drag and drop the each segment from the digits onto the correct location on the segment/common matrix in the “pixel mapping table”.  For example “Common 3 / Segment 1” or “C3/S1” is the top segment in the left digit (look at the picture above), it needs to go in the “Com3” column and the “Seg1” row.  There is a pattern and once you see it this will not take very long.

Screen Shot 2016-05-24 at 8.40.52 AM

The next step is to add the decimal points and colons to your project.  To do this add a “barograph and dial” helper.  Then click the “+” 4 times so that you have 4 segments.  As you add each one give it an appropriate name e.g. “colon” or “dp1”

Screen Shot 2016-05-24 at 8.41.05 AM

The last thing that you need to do is to assign the pins.

Screen Shot 2016-05-24 at 9.16.50 AM

The firmware is simple:

Screen Shot 2016-05-24 at 9.25.13 AM

Example 4: The Potentiometer

To test the potentiometer I will use the ADC to measure its output voltage and then display it on the LCD screen.

Screen Shot 2016-05-24 at 9.50.55 AM

Screen Shot 2016-05-24 at 9.51.39 AM

Screen Shot 2016-05-24 at 9.51.51 AM

Screen Shot 2016-05-24 at 9.52.11 AM

I am out of time… so in the next post Ill show examples 5,6,7

Alan

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board

In my job I spend a lot of time teaching people how to use Cypress Products.  One of the best students that I ever had was Paul Bentley the Cypress VP of Sales for Europe.  He came to Kentucky a few years ago to take my class.  He dove in with reckless abandon and did a amazing job learning how to actually program the PSoC (not just talk about it on powerpoint).  Recently, he was anointed with the responsibility to teach more of our Sales team to use PSoC at the Sales Technical Conference (STCON) which is going on this week.

For some time I have wanted a very simple, inexpensive board to help teach people how get going using our chips…. all of our chips both the FM products as well as the PSoC products.  The STCON afforded the perfect opportunity to build an education board.  I am very lucky to work with some really good people (in India and New Hampshire) who did the work of realizing the vision of a simple board and getting it made in short time.

Without further ado, here it is, the provisionally name CY8CKIT-021 PSoC and FM Starter Shield (shown connected to the CY8CKIT-044).

imageThe shield has an Arduino compatible footprint and has:

  • 2 CapSense Buttons
  • A Potentiometer
  • A Thermistor
  • 2 LEDs
  • A PRoC BLE Module
  • A Piezo-electric buzzer
  • A 7 Segment direct drive LCD

The PRoC is connected to the USB-I2C bridge on the programmer as well as the serial (I2C/UART) pins on the base board.  Here is the schematic:

Screen Shot 2016-05-23 at 6.53.13 AM

One of the cool things about this board is that it is generally compatible with a bunch of the Cypress products including:

  • CY8CKIT-042
  • CY8CKIT-042-BLE
  • CY8CKIT-044 (which is shown in the picture above)
  • CY8CKIT-046
  • S6E1B8
  • S6E1C3

Over the next several days I am going to show you example projects using the board.  I will culminate at the end of the week by IOTifying the board by writing BLE firmware for the PRoC, building an IOS app and an Android app to talk to the board.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit