Today, I am going to start the BLE part of this series of blogs. To do that I am going to configure my GATT database, include the BLE libraries, then launch the stack and start advertising so I can connect to the kit from my phone. If that sounds daunting... it's really not. The ModusToolbox software and tools make it all very simple. Just follow the instructions and you'll be a BLE wizard faster than it takes a UK politician to jump off the Brexit bandwagon.

Start by downloading the template I created yesterday (attached) and following the instructions at the end of that blog to create a new project. Your project should look like this.

ModusToolbox IDE project files

Double-click on the "design.modus" file to open the Device Configurator. You can also click on the "Configure Device" button in the Quick Panel - your choice. In the peripherals tab check the box labeled "Bluetooth Low energy (BLE)" then look to the right-hand panel and press "Launch Bluetooth Configurator". The tool will pop up a dialog asking you to accept the change you just made and, once you accept, will gray out the device Configurator and launch the BLE Configurator (it is not safe to allow edits in both tools at the same time).

Launching the ModusToolbox BLE Configurator

This GUI has a set of tabs and we are going to use the first three. The L2CAP and Link Layer settings are not necessary for the simple, straightforward applications we are going to write. In the General tab you will see that the default GAP role is "Peripheral". That is what we want because we are going to build a peripheral device that acts as a GATT server to a phone (called the central in BLE parlance). We do not need any edits here, and we'll cover GATT tomorrow, so move onto the GAP Settings tab.

ModusToolbox BLE Configurator - General tab

GAP stands for Generic Access Profile. It controls how your device appears to the outside world and determines how two devices can (or can't) interact. In the general section choose a silicon-generated address (it will be unique to your kit) and give it a name (I almost always call my devices "bunty"... it's a long story so, not today).

ModusToolbox BLE Configurator - GAP Settings tab

In this application we are going to advertise our name to the world and invite connections. Advertising is when the device periodically emits a single, small packet (maximum of 31 bytes) so that a listening central can detect it and make a connection. Switch to the Advertisement Packet and check "Enable Local Name". Notice how your device name gets added to the packet on the right of the window. The packet contains two items - 2 bytes of required flags (which just tell the central "I'm connectable")  and, now, your device name. If you make the name too long the packet will get too big and the tool will tell you off!

ModusToolbox BLE Configurator - GAP Settings tab

Advertising infrequently is one way that BLE conserves power because the peripheral radio is off most of the time. You can set some rules for how long and how often to advertise in the Advertisement Settings section but the defaults will be OK for us. That's all we need to do right now. Save the edits by pressing the big blue button (if you are under 600 years old, that's a floppy disk... my Mom told me about them) and switch back to the ModusToolbox IDE.

Now we need to add a wee bit of middleware for the BLE. Click on the cunningly-named "Select Middleware" button in the Quick Panel. In the dialog that pops up, select two items:

  • BLE Base
  • BLE single-core mode, controller and host on CM4 only, soft FP prebuilt library

ModusToolbox Middleware SelectorThe Base is the low-level stack (including that L2CAP and Link Layer stuff we are pretending does not exist). That second one is quite a mouthful but it's just the upper layer of the stack that will be calling the event handlers we are going to write over the next few days. Press OK and the middleware gets added to your project in the "psoc6sw-1.1" folder. All we need now is some application code.Add these include files so the compiler finds the generated source files from the BLE Configurator tool and the libraries we added.

 

#include "cy_ble_gatt.h"
#include "cycfg_ble.h"

 

In main(), add this initialization code after the button ISR setup. What does it do?

  • Installs the BLE interrupt handler with a very high priority (note that the handler is from the middleware, not your code)
  • Registers your stack event handler for stack events (we will add more tomorrow)
  • Initializes and enables the BLE hardware
  • Calls the event processing function in a forever loop (this is a little lkazt because I really should go to sleep and wait for interrupts.... shhhhhh, don't tell)

 

const cy_stc_sysint_t ble_intr_config = { bless_interrupt_IRQn, ISR_PRIORITY_HIGH };
Cy_SysInt_Init( &ble_intr_config, Cy_BLE_BlessIsrHandler );
NVIC_EnableIRQ(  ble_intr_config.intrSrc );
Cy_BLE_RegisterEventCallback( stack_handler );

/* Initialize and start BLE */
Cy_BLE_Init( &cy_ble_config );
Cy_BLE_Enable();
__enable_irq();

for( ; ; )
{
    Cy_BLE_ProcessEvents();
}

 

When BLE is operating the stack generates events that can be handled (or ignored) in the event handlers that you set up. The handlers are (indirectly) called from the Cy_BLE_ProcessEvents() function. Our handler will deal with connection and disconnection events. This is the last bit of code we need to write today.

 

void stack_handler( uint32_t event, void* eventParam )
{
    switch( event )
    {
        case CY_BLE_EVT_STACK_ON:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Stack on\r\n" );
            Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );
        break;

 

        case CY_BLE_EVT_GATT_CONNECT_IND:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Connected\r\n" );
        break;

 

        case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED:
            Cy_SCB_UART_PutString( KIT_UART_HW, "Disconnected\r\n" );
            Cy_BLE_GAPP_StartAdvertisement( CY_BLE_ADVERTISING_FAST, CY_BLE_PERIPHERAL_CONFIGURATION_0_INDEX );
        break;

 

        default:
            /* Ignore the event */
        break;
    }
}

 

Looking at the code you can see that there are three interesting events and we are printing out messages to the terminal for each one.

  • CY_BLE_EVT_STACK_ON means the stack is up and running so we turn on advertising (in fast mode) for configuration 0. You may have noticed that we made changes in the BLE Configurator for "Peripheral Configuration 0" - BLE peripherals can support multiple configurations, but we are not going that deep today.
  • CY_BLE_EVT_GATT_CONNECT_IND means a connection from a central has occurred.
  • CY_BLE_EVT_GAP_DEVICE_DISCONNECTED means... wait for it... the phone disconnected and so we re-start advertising. if we forget that part then the device will not allow another connection (until you press reset).

OK, let's run this. pres the "BLE_proj Program (KitProg3)" button and watch the compiler work it;s magic, and program the kit.

Install CySmart on your phone. It is in the App store and Google Play. Open it and refresh the screen to see your device name. EXCITING!!!

CySmart showing BLE connections

Press on the name and it will connect and show you... not very much, just "No services"! Of course not, we have not enabled any functionality yet. That's for tomorrow, when I will show you how to get the peripheral to respond to alert message from your phone.

      CySmart connected to a peripheral with no services enabled

I attached the template and also a copy of the C file (main.c) as a zip file to this blog.