AnyCloud Bluetooth Advertising Scanner (Part 1)

Summary

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

Story

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

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

For this series of articles I will:

  1. Discuss an overview of Bluetooth Application Architecture (Part 1)
  2. Explain how to Start the AnyCloud Bluetooth Stack (Part 1) 
    1. Discuss the configuration structure: bt_platform_cfg_setting (Part 1)
    2. Discuss the configuration structure: wiced_bt_cfg_settings (Part 1)
    3. Discuss the Tasks created by the Bluetooth Stack (Part 1)
    4. Build the Basic Project (Part 2)
    5. Discuss BLE Advertising - Scanner/Observer (Part 3)
    6. Discuss BLE Advertising - Advertiser (Part 3)
    7. Add BLE Scanning Code to the project (Part 3)

    Bluetooth Application Architecture

    Bluetooth applications are divided into these four pieces

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

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

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

    But how do they talk?  Simple, there is:

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

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

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

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

    How to Start the AnyCloud Bluetooth Stack

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

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

    Here is an example from main.

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

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

    bt_platform_cfg_settings

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

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

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

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

    wiced_bt_cfg_settings

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

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

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

    • max_simultanous_link – which I changed to 0 because this is simply a Bluetooth Observer
    • low_duty_scan_interval – how long in the window to listen for advertising packets
    • low_duty_scan_window – how wide the window of listening should be

    app_bt_management_callback

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

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

    Tasks

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

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

    Here is print of the task list from my project:

     

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

    ModusToolbox 2.2 Template Project – FreeRTOS + NTShell

    Summary

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

    Story

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

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

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

    Here is what I am going to do:

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

    Create & Test a project from the IoT Expert FreeRTOS Template

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

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

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

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

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

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

    Add the NTShell Library & Examine New Library Structure

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

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

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

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

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

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

    Update the Project and Program

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

    Then I edit main.c to

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

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

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

    Add the Task List functionality

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

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

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

    Now build/program.

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

    Put the Template on GitHub

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

    Then on my current project:

    1. I blow away the git history (didnt really have to do that).
    2. Create a new git repo “git init .”
    3. Add a pointer to GitHub “git remote add….”
    4. Add all of the files “git add *”
    5. Add the .gitignore “git add .gitignore”
    6. Commit the changes “git commit…”
    7. Push it to GitHub “git push …”

    Update the Manifests

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

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

    Test the new Template

    Everything should be working so make a new project.

    Cool.  There is the new template.

    When I program it… everything is cool.

    And the project seems to be doing the needful.

    PSoC 6 SDK OneWire Bus (Part 5): Round out the OWB driver

    Summary

    This article shows the completion of the PSoC 6 SDK One Wire Bus library.  It shows the test apparatus for evaluating DS18B20 sensors.

    Story

    If you remember from the previous articles, I created the one wire bus library by looking at the function calls in the DS18B20 library and reverse engineering the function prototypes.  And, as I said in the earlier article, it would have been way better to just look at the David Antliff “OWB” library.  But that is not how it went down.  I wonder how much time in the world is wasted by programmer re-implementing code that already exists?

    After the first four articles, I had three functions which the DS18B20 library defined, but I had not yet implemented.

    I had not implemented them because I was not totally sure how they worked.  So, I decided to go back to GitHub and see what David had done originally.  When I got to the GitHub site, https://github.com/DavidAntliff/esp32-owb/blob/master/include/owb.h, there were actually quite a few functions in his owb library that I had not implemented.

    Here is the list:

    In this article I will create and/or copy the missing functions.  As I look through his implementation I also notice that we have some style differences that I will discuss.  In general I will say that his implementation is very good and any place that I did something different was just a matter of programming taste.

    I was originally planning on this article taking you linearly through how I did the changes, but in reality I jumped around while I was doing the changes, that approach won’t work.  Here is the list of what I did:

    1. Add Doxygen Function Headers
    2. Move Logging Function to Library
    3. Change Commands to Enumerated Type
    4. Change Const Bus Pointer
    5. Pack the Structures
    6. Pass Structures as Pointers
    7. Driver Functions
    8. Test the Search
    9. Test the Parastitic Power

    Doxygen Headers

    I like using documentation that has been generated with Doxygen.  Specifically I like that the documentation is written “at the point of attack”.  But I have never actually used or generated it using Doxygen.  To make the documentation you need to put comments into your c-header files in the right format.  Here is an example from owb.h

    In this case, David had done most of the work already and all I needed to do was copy/modify his headers in the few places where we had differences in the public interface to the library.  After that, I ran doxygen.  When I first did this I got an absolute boatload of warnings about places where I had not documented with comments.  If Hassane is reading he will say … “Really Alan didn’t write comments, imagine that”

    Now I have some documentation

    I will say that I wish I had a few days to really learn Doxygen as there are many many many options which I have no idea what they do.  Oh well.

    Fix the Logging Function

    David built the library on top of the ESP32 libraries.  This included calls to the ESP32 logging library “log.h/.c“.  All through his library he calls “ESP_LOG” like this.

    When I first looked at this I decided to just do this to make the error messages go away.  This is just a trick that will use the c-preprocessor to replace the function call to “ESP32_LOGE” with NOTHING

    After I sorted everything else out I went back to decide what to do.  My choices were

    1. Clone the Espressif library and “fix it”
    2. Implement the functions that David used in the OWB library
    3. Find another library

    I decided to use option 3 – a logging library that I found on GitHub called “log.c” (which is a very unfortunate name when you clone it).  It is really simple and works well.  Since the Tour de France is going as I write this article I will say “chappeau rxi”.  This library is written in C99 (just normal C) and has functions which can easily replace the ESP_LOG functions.  I add it to my project with “git clone git@github.com:rxi/log.c.git”

    This means that I just replace “ESP_LOGE” with “log_error”.  In reality rxi did something very nice by using a feature of the compiler to insert the file/line numbers.

    This only left me with the function

    Which I decided to do something cheap to solve.  The original code was:

    And I replaced the two uses with:

    and

    I know it isn’t beautiful what I did, but it works.

    Enumerated Command Type

    When I examined the original source code, the one-wire commands were defined using #defines.

    When I did the implementation originally I chose to make the #defines into an enumerated list.  I suppose that it doesn’t really matter.  But, by enumerating the values it lets the compiler help you in situations like a switch or a function call.

    Const Bus pointer

    Through out the original one wire bus library, the bus pointer is defined as const.  Like this:

    But, I wanted to use the OneWireBus structure to also store some context.  By context I mean variables (which can change) but hold state for the bus.  This included the semaphore that I used to fix the delay functions.

    ROM Code Structure Packed

    In the original library the ROMCode is a union that allows access to individual bytes, or the actual data.

    The problem is there is no guarantee that the compiler will pack the family, serial number and crc.  You should tell it to with the __PACKED macro.  I would say that I think that David got luck that there was not a bug.

    C-Programming: Passing Structures as Function Arguments

    In the original library David passed the rom_code structure as an argument on the stack.  But, because I started programming in the days before it was legal to pass a structure as a function argument when I did the implementation I passed a pointer.

    I wrote

    Which meant that he could write

    but I had to write

    In this case it doesn’t really matter as the structure is small.

    Driver Functions

    If you look at the original implementation the author has a “driver”

    Which is a structure with function pointers to talk to bus.

    Which meant that he did this:

    In my implementation I wrote functions for those things.

    I don’t really think that it helped abstract the hardware because he also did this.

    Perhaps a driver with function pointers would have made the original port easier if I had started there?  But if so, it would have required more adherence to the original  architecture.

    Test Search

    A nice thing that came with his library was an implementation of the search feature which allows multiple devices to be attached to the bus.  To test this I added two sensors.

    Then made a command in my console to run the test.

    Which worked perfectly.

    Parasitic Power

    I would like to test the functionality of the parasitic power.  Here is a schematic from the data sheet of how it work.  But I don’t have that transistor so that will be left for another day.

    What is Next?

    There are several things that I should do.

    1. Fix up the libraries to use the manifest files so they are available all of the time
    2. Fix up the libraries to use the dependency scheme
    3. Test the parasitic power
    4. Test the actual DS18B20 library (the original point of this whole thing)

    I have found myself in the middle of a bunch of other problems, so these things will need to happen another day.

    PSoC 6 Pins & the SPI Port

    Summary

    Recently, I have been helping a reader sort out some code that makes strings of WS2812 LEDs work.  Specifically, this code takes data from a frame buffer inside of the PSoC 6 and drives it out a SPI port via the MOSI pin. I have written about this a couple of times, but,  the new wrinkle in our code is that it allows you to use any combination of SPI port/pins on the chip.  Instead of using the configurators to setup the SPI to GPIO connection, I setup the connection using PDL to talk directly to the PSoC 6 configuration the registers.

    Perhaps it is obvious to everyone how a connection from a peripheral to a GPIO works, but I thought that I would write about it anyway.  In this article I am going to show you a bunch of the documentation for PSoC as well as the PDL source code which implements the documentation.  Specifically, I will show you the PSoC 6

    1. Architecture TRM
    2. Register TRM
    3. Datasheet
    4. PDL

    Architecture TRM

    In the picture below, which I copied from the PSoC 6 Architecture TRM, you can see how an individual GPIO works.  Starting  at the Pin of the chip you can see that there are three connections from/to the pin (look at the green box).

    • A set of switches to/from the Analog Mux Bus which enable CapSense or Analog peripherals to talk to the Pin
    • A connection from the pin to the Analog peripherals (some Analog peripherals can attach directly to a pin and not though the Analog Mux Bus
    • A connection to the High Speed I/O Matrix (HSIOM) – for the digital peripherals

    Notice that all of the signals coming into the green box from the top are DIGITAL.  All of the signals coming into the box from the bottom are Analog and the line coming into the middle of the box controls the behavior of the I/O.

    For my case the SPI is one of the “Fixed Function Digital Peripherals”.  In order to get it to connect to the pin I will beed to pick out the right signal in the multiplexer that is in the HSIOM Matrix box.

    When you scroll down a little bit further in the Architecture TRM, the next diagram is a more detailed description of the GPIO.  Notice that there are a bunch of configuration register bits which setup different parts of the I/O like slew rate, interrupts, drive mode etc.  Notice that the multiplexer that is connected to “out”
    and “out_en” has a bunch of different possible signals.  Including “GPIO_PRTx_OUT[OUTy]” which is a register bit which is can be used for “digital write”.  For instance GPIO_PRT0_OUT[2] would be P0_2.  The other interesting thing going on here is you can see that there are really three classes of signals attached to the mutiplexer

    • The digital output pin
    • Active signals – which work while the chip is not in deep sleep
    • Deep Sleep signals – which work while the chip is in deep sleep.

    On the output side you can see the two pullup and pulldown resistors, as well as the two transistors which pullup and pull down.  All of these can be configured to be connected… or not.

    And finally at the bottom of the I/O you can see the analog signals.

     

    If you look a little bit further down in the Architecture TRM you will find this table which describes how each of the actual pins on the multiplexer work.

    PSoC 6 Register TRM

    If you want to start to make specific configurations for specific pins you will need to look into the PSoC 6 Register TRM.  In that document you will find that the

    Register TRM

    Register TRM

    PSoC 6 Datasheet

    But what are all of the active and deep sleep signals?  Well if you look in the PSoC 6 data sheet you can find all of those connections.  For instance on P0.1 active signal 8 is the SCB 0 SPI Select signal 2.

    PSoC 6 PDL

    But really all of these register reads and writes are not really that fun.  So, Cypress provides other, less painful ways of getting things going.  Specifically,

    • void Cy_GPIO_SetHSIOM(GPIO_PRT_Type* base, uint32_t pinNum, en_hsiom_sel_t value)

    or

    • Cy_GPIO_Pin_Init(GPIO_PRT_Type *base, uint32_t pinNum, const cy_stc_gpio_pin_config_t *config)

    When you call both of these function you need to provide the value for the multipler either directly in the Cy_GPIO_SetHSIOM or indirectly in the Cy_GPIO_Pin_Init case where you provide it as a member of the cy_stc_gpio_pin_config_t *config structure called “hsiom”

    Depending on which package you have selected you will have a file like gpio_psoc6_01_124_bga.h which will have both the generic definitions for the HSIOM multiplexer select (like this)

    As well as the pin by pin definitions… like this for P0_2

    If you look at the Cy_GPIO_Pin_Init function you will see that on line 96 it sets the register which picks the correct pin mux.

    And finally the Cy_GPIO_SetHSIOM actually writes to the register.