ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock

Pattern Agents are running a crowd funding effort for TSoC … here

Summary

In the previous post I told you that I immediately blew away the factory firmware on the TSoC4L board.  I’m like that sometimes :-).  In this post I am going to take you through the entire process of getting and reprogramming the factory firmware, then finding and debugging a PSoC4 clock problem.  The rest of this post is:

  1. Getting the correct firmware back on the TSoC4L Board
  2. Running into a bug in the beta version of the firmware
  3. Using the debugger to find the bug
  4. Explaining the functionality of Low Frequency Clocks and the Watch Dog Timer
  5. The Pattern Agents bug fix

Factory Firmware

Getting things going again starts with “git”ing the firmware.  This can be done by “git clone git@github.com:PatternAgents/TSOC_PSoC4L.git”.  Once you have the repo cloned you will find a bunch of good stuff including:

  1. datasheets: All the datasheets
  2. documentation: The PatternAgents documentation (quick start)
  3. drivers: The windows USB <-> UART drivers
  4. eagleUp: JPG renderings of the PCB
  5. firmware: The PSoC Creator Project
  6. hardware: gerbers, boms etc
  7. images: renderings of the board, photos of the board etc
  8. revisions: old revisions of the Eagle project files
  9. The Eagle PCB Project including schematic and layout

TSoC4 L Files from GitHub

When you open the PSoC Creator Workspace you will find two projects

  1. A USB Bootloader – called “USBFS_Bootloader”
  2. The TSoC RSVP Firmware – called “rspvsis_4l_typ”

The system is supposed to

  1. Start the USB HID bootloader (so you could get new firmware).  Wait for 10 seconds for a bootloader host to start then if it doesnt … then start
  2. The RSVP Firmware

When you plug in the board you will see the TSoC4L enumerate as “Cypress ThingSoc Bootloader”.  Then, after 10 seconds, you should see it reboot, then enumerate as “Cypress USB UART”.  But, this was not happening for me.  Why?  I wasn’t sure.  The first thing that I did was add a blinking LED circuit that looked like this:

Blinking LED

But the LED was not blinking.  That meant that the firmware was not even getting to main i.e. it was hanging BEFORE main in the PSoC boot code.  But where and why?

Using the Debugger to Find the Bug

How do you figure out where the system is stuck if you can’t even use the “blinking LED” or “printf” debug?  Simple.  Use the debugger.  Start by programming the PSoC with your firmware.  Then click “Debug->Attach to running target”.

Starting the PSoC Debugger

The debugger will start.  Then you will be able to press the “Pause” button. which will take you to a screen that looks like this:

PSoC4 Clock Busy Wait Loop

The chip is stuck on line 234.  What does line 234 do?  That is a busy wait loop.  It is waiting for the Watch Dog Control Register to clear.  To explain that, I will need to take you through the PSoC4 Low Frequency Clocks.  First you should notice that the file we are in is named “cyfitter_cfg.c”.  What is this file?  If you look at the top, this is what PSoC Creator says.

This means that the “cyfitter_cfg.c” file is synthesized by PSoC Creator when you do a build based on what you configured when you setup your project.  This file contains a bunch of the startup code including the code that gets the clock systems going.  Line 234 is inside of a function called “ClockSetup”.  All of this code is called BEFORE you get to main().

The PSoC4 Clock(s)

To explain why we are stuck there you first need to double click on the “Clocks” tab in the Design Wide Resources.  When you do that it will take you to this screen which contains a bunch of information about the clocking system in the PSoC.

PSoC4 Clock Setup

In the screen above, you can see that there are three Timers in the Watch Dog Timer system (WDT) that are clocked (i.e. have a Source Clock of) by the Low Frequency Clock (LFCLK).  The LFCLK has its source as the Watch Crystal Oscillator (WCO).  If you double click the WCO line it will take you to a screen that is much easier to see what is going on, specifically the “Configure System Clocks” screen:

PSoC4 Clock - Low Frequency

In the screen above you can see that the LFCLK has two choices of oscillator sources, the “ILO” or the “WCO”.  ILO stands for Internal Low Speed Oscillator.  The ILO is a fairly inaccurate (+- 60%) RC oscillator that is built inside of the chip.   It is designed to be very low power which is why it is so inaccurate.  If you need a more accurate oscillator, then you should use an external oscillator, specifically a Watch Crystal Oscillator or WCO.  A WCO is a 32.768KHz crystal oscillator.  These watch crystal oscillators give you very precise clocks that can be used to drive real time clocks accurately.

The next thing to see is there are three Watch Dog Timers (WDT) numbered 0-2.  These times are driven by the “LFCLK”.  Here is a picture from the PSoC Technical Reference Manual.


PSoC4 Clock - WDT Block Diagram

So what is the “CYREG_WDT_CONTROL”?  You can find that by looking in the PSoC4 Registers TRM.

PSoC4 Clock WDT Control Register

The busy wait loop is waiting for bits 19,11,3 to be cleared.  Those bits are “WDT_RESETx”  They become 0 when the three WDT timers are cleared which happens “several LFCLK cycles” after the reset.  As a reminder, here is that block of code:

This still leaves us with the question, “What is the problem?”.  If you look on the back of the ThingSoC4L board you will see there is no Crystal populated on this board. (the blank footprint on the right side of the back).  The WCO is an optional feature from Pattern Agents.  If you need the more accurate timing, you need to solder on your own Crystal.

Backside of ThingSoC4L PCB

If there is no WCO crystal, then the WDT timer reset will never happen because LFCLK isn’t doing anything.  And, the busy wait loop will never end.  Mystery solved.

The Pattern Agents Bug Fix

To fix the startup problem, the Pattern Agents guys changed the clock configuration to

  1. Turn off the WDTs
  2. Use the ILO as the source of the LFCLK

PSoC4 Clock - Low Frequency Setup

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

ThingSoC: TSoC PSoC4L Development Kit from PatternAgents

Pattern Agents are running a crowd funding effort for ThingSoC TSoC4L … help them here

Summary

Last week I got a box in the mail from my friend Tom Moxon in Oregon.  He runs a company called Pattern Agents.  I was excited when I saw the box because I love new development kits.  I was even more happy when I opened the box and found a ThingSoC PSoC4L kit.

Tom sent me three boards

  1. A ThingSoC PSoC4L
  2. A MiniProg Adaptor
  3. A ThingSoC I2C Hub

ThingSoC PSoC 4L Packaging

ThingSoC PSoC4L

The ThingSoC complies to a new open source stackable footprint called the ThingSoC Open Source Socket.  This ThingSoC board is driven by a PSoC4L.  The PSoC4L is the largest and most capable of the PSoC4 family.  This chip “completed” the high end of the PSoC4 family by adding more IOs, more Flash, more RAM and a USB controller.  The PSoC4L serves as the base MCU in the stack as well as providing a bridge to the PC via a USB <–> UART Connection.  The board also has a connection for a 3.7V LiPo battery to power the system.  In the picture below you can see the base board (on the left) with the programmer attachment (on the right).  The programmer attachment lets you attach a MiniProg-3 or a Uart Bridge or an ISSP connection (like a MiniProg-1).

thingsoc 4200l

Here is a picture of the backs of the boards.  On the back of the ThingSoC PSoC4L board you can see a place to solder a Cypress NVSRAM as well as a footprint for a Watch Crystal.

The backs of the ThingSoC PSoC4L

The Blinking LED

The first thing I did with the board (and no, reading the instructions wasn’t the first thing) was program the chip to blink the LED.  Obviously with a PSoC the best thing to do was make a schematic with a PWM driving the USER LED pin:

I used the default clock of 12MHZ, then I used the PWM pre divider to get the frequency down to something that I could see.

Lastly, I wrote a tiny bit of firmware to get things going.  Notice that I use the CySysPmSleep to put the CPU to sleep.  It never wakes up from this sleep (because there are no interrupt sources to wake it up).  But, if it did, it would go right back to sleep because of the loop.

After programming the board, the LED started right up.  That is good as it means everything makes sense.

When I programmed the Blinking LED project I overwrote Tom’s default firmware which is called “RISC”.  In the next post Ill talk more about the architecture of the ThingSoC PSoC4L.

You can find all of the projects in the TSoC Series at my GitHub ThingSoC repository git@github.com:iotexpert/ThingSoC.git

Index Description
ThingSoc: TSoC PSoC4L Development Kit from PatternAgents Introduction to ThingSoC
ThingSoC PSoC4L: Using & Debugging the PSoC4 Clock Debugging a beta firmware problem
ThingSoC: The TSoC GROVEY I2CHUB : I2C Hub/Switch Evaluating the ThingSoC I2C Hub
ThingSoC: Multiple I2C Displays Using the I2CHUB and U8X8 Library A project using ThingSoC I2C Hub & 4 OLED Displays

Electronica 2016 – CY8CKIT-145 User Interface

I finally made it to Munich late yesterday afternoon… then I proceeded to turn my hotel room into an electronics lab as I frantically worked to finish everything for tomorrow.  Earlier this year I wrote a whole series of posts about the PSoC4000S & CY8CKIT-145 after the Embedded World show.  We finally have volume production on the development kit and will be giving them out at the show this week.  So, I decided to use the -145 as part of the user interface for my Electronica project.  The devkit functions as the block labeled “PSoC Capsense”.  The wire between the “PSoC Capsense” and the “WICED WiFi” will be I2C (the green and red wire from the picture below)

electronica-wiced

The -145 devkit has the PSoC4000S silicon on it which has the new mutual capacitance capsense block.  On the devkit, there are three mutual cap buttons and one slider.  Here is a picture of the devkit connected to the WICED WiFi board that I am going to use:

img_3318

I want to make as simple of a PSoC Creator project as I can possibly do as I want to be able to easily do it live.  Here it is:

screen-shot-2016-11-07-at-10-12-23-am

The CapSense block is configured with three mutual cap buttons and 1 self-cap slider:

screen-shot-2016-11-07-at-10-13-54-am

On this development board, the three mutual cap buttons share the same transmit line, so you need to configure the component that way. The screen shot below shows the configuration of the “Button1_Tx” which is set to share the “Button0_Tx”.  You need to make the same setting for “Button2_Tx”.

screen-shot-2016-11-07-at-10-15-34-am

The next step is to assign all of the pins to the proper locations:

screen-shot-2016-11-07-at-10-18-10-am

Finally the smallest amount of firmware that I could think up to hold it all together.

Line 3-6: define a structure that the WICED board will be able to read.  It will represent the position of two of the Servo motors.  The CY_PACKED provides the compiler appropriate key words to make the bytes be right next to each other in the RAM, i.e. not word aligned..

Line 8: initializes both positions to 50%.

Lines 12-17 get the components going

Line 22: Checks to make sure that the CapSense block is not scanning before it reads the results

Line 24: Tells the CapSense block to process the results from the previous scan

Lines 25-31: Looks at the three buttons, sets the LEDs and sets pos1 to be either 25%, 50% or 75%

Line 33: Reads the position of the slider and assigns it to “pos0”

Lines 34-35: Gets the scanning going again

screen-shot-2016-11-07-at-10-21-02-am

To test the system I first used the bridge control panel.  First, connect to the kitprog2.  Then I setup a read from the I2C address (0x08) which is the address of my board.  I then click repeat which runs the read command over and over again.  In the picture below you can see that I tested the three position of the button (25,50 and 75 which are also known as 0x19, 0x32 and 0x4B).  Then I tested the slider by touching it about in the middle (0x3A)

screen-shot-2016-11-07-at-10-31-52-am

The next thing to do was make sure that the WICED devkit could read my I2C slave, so I wrote some WICED firmware to read the I2C registers every 500ms:

screen-shot-2016-11-07-at-10-55-08-am

But, occasionally I  was getting a “read failed”:

screen-shot-2016-11-07-at-10-58-48-am

Last night in my sleep deprived state I was struggling like crazy to figure it out.  This morning after some sleep I realized that the WICED board that I have must not like getting its I2C clock stretched.  So, I changed the priority of the I2C interrupt on the PSoC and that fixed the problem:

screen-shot-2016-11-07-at-10-28-03-am

Keep watching here for more updates on the project.

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: &amp;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: &amp;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(&amp;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(&amp;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(&amp;tempHandle,0,&amp;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 &amp; local initiated 
{
CyBle_GattsNotification(cyBle_connHandle,&amp;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(&amp;notifyFlags,0,sizeof(notifyFlags));
break;       
 
case CYBLE_EVT_GAP_DEVICE_CONNECTED:           
PWM_Stop();
updateGattDB(&amp;BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
updateGattDB(&amp;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-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_BOOTLOAD_CHAR_HANDLE)
{
if(wrReqParam-&gt;handleValPair.value.val[0]) Bootloadable_Load();
 
}
#endif
 
// LED0
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CHAR_HANDLE)
{
BLEIOT_updateLed0(wrReqParam-&gt;handleValPair.value.val[0]);
updateGattDB(wrReqParam-&gt;handleValPair.value.val,1,notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_PEER_INITIATED);
}
 
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CCCD_DESC_HANDLE)
{
notifyFlags.led0 = wrReqParam-&gt;handleValPair.value.val[0];
CyBle_GattsWriteRsp(cyBle_connHandle);
}
 
// BUTTON 0
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_BUTTON0_CCCD_DESC_HANDLE)
{
notifyFlags.button0 = wrReqParam-&gt;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 *)&amp;BLEIOT_local);
 
CyBle_Start(BleCallBack);
 
for(;;)
{
 
#ifndef BootLoadable__DISABLED
// if they write into the BLEIOT_local.bootload (from EzI2C)
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BOOTLOAD || BLEIOT_local.bootload)
{
// enter the bootloader
Bootloadable_Load();
}
 
#endif
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0)
{
BLEIOT_updateLed0(BLEIOT_remote.led0);
updateGattDB(&amp;BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BUTTON0)
{
BLEIOT_updateButton0(BLEIOT_remote.button0);
updateGattDB(&amp;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

PSoC4000s & The SmartIO – Part 5

This is my last post on the SmartIO.  This time, I am going to describe how to use the SmartIO to trigger an interrupt.  For this project I will start from the “SmartIOCountUp” project.  That project is a 3-bit counter.  I thought that I would choose one of the states (000) and trigger an interrupt when that state is hit, then toggle the P25 user led.  I will keep data4, and gpio 3,6,7 exactly the same.  I will use gpio 2 to trigger the interrupt, which can be accomplished by setting it up as an output.  Here is the SmartIO configuration:

smart-io-config

The next step is to use LUT2 to look for the “000” state and to create a rising edge.  The other states will be 0.

lut-p22

After making the modification to the SmartIO the next step is to fix the schematic.  To do this I add a pin for P22, its configuration is on the next screen.  In addition I move the P25 (aka the BlueLED on the master board) to pin by itself.

interrupt-schematic

To configure the P22 pin.  There is a trick that is required to make the pin be both an output, so that it can be connected to the SmartIO LUT as well as an Input, so that it can be connected to the Port 2 interrupt.

pin-config

After setting up the pin to be both an Input and an Output you need to configure the pin to have an interrupt on the rising edge.

int-pin

Then I assign the pins.

interrput-pin-assignment

The last step is to make the firmware.

  • Lines 4-9 create an interrupt service routine
  • Line 18 registers the interrupt service routine to be called with the Port2 interrupt is triggered
  • The rest is the same as before

int-mainc

When I run this, I see the Blue LED toggle each time it gets to state 000 (which is all three LEDs on as they are active low).

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “SmartIOInterrupt”.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt

PSoC4000s & The SmartIO – Part 4

In the previous post I built a 3-bit counter that is clocked by the PWM.  In this example I will show you how to make the same design work with an external clock.  It seems like it would be cool to use the CapSense Button to provide the clock.  I will start by copying SmartIOCountUp to a new project called SmartIOCountUpExtClock.

First, I delete the clock and PWM.  Then add a new digital output pin (P20) that I can toggle from the CapSense handler and a digital Input pin (P21) to clock the SmartIO.  I add a wire between them on the female header on the board.

The next step is to modify the SmartIO.  I change data4 and data5 to bypass.  Then make gpio1 an input and then set the Clock to gpio1.  Here is what the new SmartIO configuration looks like:

smart-io-config

And the schematic.

smart-io-schematic

Assign the pins.

smart-io-dwr

I need to update the main.c write the CapSense button to P20 to be a clock source for the SmartIO

mainc

After I program the board, I can “clock” my statemachine with CapSense Button2.  Cool.  Obviously this example is a bit contrived in that I am running a wire on the outside of the chip, but you could imagine that you might have a “real” example that uses an onboard clock source.

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “SmartIOCountUpExtClock”.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt

PSoC4000s & The SmartIO – Part 3

For this post, I wanted to build a simple state machine inside of the SmartIO.  So I decided to build a 3-bit counter.  On the CY8CKIT145 board, port 2 is mostly connected to LEDs.  When you look at the picture below you can see that the LEDs on the left side of the board are easiest to see, so I decided to use them to indicate the state of the counter.  You can see from my notes that I was originally considering using LED9,11,10 which are the three LEDs on the CapSense buttons board.  I also considered using LED5,6,8 which are on the right side of the slider board, but I ruled all of that out because they were hard to see.

IMG_2737

To build this project you start by creating the schematic.  In this case I copied the design from the previous post called “145MutualCap” which had 3 CapSense buttons and 3 LEDs (LED10,11,9).  I then added:

  • A 5 KHz Clock to drive the PWM
  • A PWM to divide down the clock to a speed that I could see and provide a clock for the counter
  • A Smart IO
  • 4 Output Pins to drive LEDs (P27, P26, P25, P23)

counter-schematic-1

Next I configured the PWM with a 50% duty cycle and a Period of 10000.  This results in a 0.5Hz clock:

smartiopwm

Then I configure the SmartIO.

  • Setup “data4” as an input to the Smart IO.  Data 4 is the line out 0 of the TCPWM0
  • Setup “data5” as an input to the Smart IO.  Then configure it to be the “clock” for the smart IO. Data 5 is the Line_N of TCPWM0.  Originally I wanted to be able to have the clock drive LED5 as well, but this can create a timing hazard in the Smart IO and is not allowed (which is why I mirror data 4 onto the output P25.
  • Setup GPIO 7,6,5, and 3 as outputs (these outputs are connected to P27, P26, P23 which are the LEDs on the slider board.  GPIO5 is connected to P25 that is the user LED on the main board

smartioconfig

Then I configure LUTs 6, 3, 7 to implement the state table of a counter

state

lut6

lut3

lut7

I want to be able to see the clock (the PWM input data4) ticking so I create a transparent LUT (000 = 0 and 111 = 1) for LUT5 which is attached to P25 which is the LED on the main board.

lut5

After this is done I need to assign the Pins.

smartiopinassignment

Followed by the very simple firmware which is copied from the previous design.  The only new code is line 9 to turn on the PWM.

main

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “SmartIOCountUp”.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt

PSoC4000s & The SmartIO – Part 2

In the previous posts I introduced you to the Smart IO.  I also went through the instructions to create CapSense Buttons using the new Mutual-cap CSX mode of the PSoC4000S.  In this post I am going to use the three CapSense buttons on the CY8CKIT-145 as inputs to the Smart IO.  I want to create a simple logic function P25 = !XOR(P24,P26,P27).  This will cause the LED that is attached P25 to light up when there is an odd number of 1’s on P24,P26,P27.  The equation is slightly strange because the LED is wired as active low (it lights up when there is a 0 written to it)

To make this work I soldered an 8 pin female header to Port 2 of my development kit.  I then wired:

  • P20 <–> P24
  • P21 <–> P26
  • P22 <–> P27

You can see all of that in the picture below.

IMG_2744

The next step is to create the schematic for this design.  I started from the Mutual Capacitance project that I talked about in the previous post.  It has three LEDs and the Capsense Buttons.  I then add

  • Three digital output pins (P20,P21,P22) to drive the three inputs to the SmartIO
  • Three digital input pins (P24,P26, P27) to use as inputs to the SmartIO
  • One digital output pin (P25) to drive the LED
  • The Smart IO block

3xorschematic

The next step is to configure the SmartIO.  I setup P24,P26,P27 as “inputs” and setup P25 as an “output”

smartio-config

Then I configure the LUT to match the logic equation: P25 = !XOR(P24,P26,P27)

LUT5

Lastly I assign the pins to the correct physical pins on the chip.

dwr

Then I create the firmware by copying the main.c from the earlier CapSense example.  I then add the small amount of code to glue it all together:

  • Line 7: start the SmartIO
  • Lines 27-29: Write to P20,P21,P22 based on the state of the input buttons.

3xormainc

You can find this PSoC Creator workspace on github in the directory called “SmartIO”.  This project is called “3Xor”.

In the next post I will show you how to make a state machine using the Smart IO.

Index Description
PSoC4000s & The SmartIO – Part 1 An introduction to the SmartIO and first project
PSoC4000s & CSX Mutual CapSense Buttons Part 1 Using mutual capacitance
PSoC4000s & CSX Mutual CapSense Buttons Part 2 Using the CapSense tuner
PSoC4000s & The SmartIO – Part 2 A 3 input XOR logic gate
PSoC4000s & The SmartIO – Part 3 A 3 bit up counter state machine
PSoC4000s & The SmartIO – Part 4 Using an external clock with the Smart IO
PSoC4000s & The SmartIO – Part 5 Triggering an interrupt