{"id":5055,"date":"2019-08-01T01:12:06","date_gmt":"2019-08-01T08:12:06","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=5055"},"modified":"2019-10-08T12:56:26","modified_gmt":"2019-10-08T19:56:26","slug":"creating-a-bluetooth-le-central-with-stm32wb","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/stm32wb\/central\/","title":{"rendered":"Creating a Bluetooth LE Central with STM32WB"},"content":{"rendered":"<p>This tutorial shows how to create a basic Bluetooth LE Central (a device that enumerates and communicates to Bluetooth LE peripherals) using the STM32WB platform and VisualGDB.<\/p>\n<p>We will show the functions involved in enumerating the peripherals and obtaining various information from them. If you are not familiar with the Bluetooth LE concepts, follow our <a href=\"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/stm32wb\">Bluetooth LE Peripheral tutorial<\/a> to get started.<\/p>\n<p>Before you begin, ensure you have an STM32WB Nucleo kit (including the Nucleo board and the USB dongle) and install VisualGDB 5.4 or later.<\/p>\n<ol>\n<li>First we will create a Bluetooth LE peripheral project for the USB dongle included with the STM32WB-Nucleo kit. Start Visual Studio and open the VisualGDB Embedded Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/01-newprj-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5057\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/01-newprj-2.png\" alt=\"\" width=\"1024\" height=\"710\" \/><\/a><\/li>\n<li>Select the name and location for your project and press &#8220;Create&#8221; to launch the VisualGDB&#8217;s wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/02-prjname-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5058\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/02-prjname-1.png\" alt=\"\" width=\"1024\" height=\"710\" \/><\/a><\/li>\n<li>On the first page of the wizard select &#8220;<strong>Create a new project -&gt; Embedded binary -&gt; MSBuild<\/strong>&#8220;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/03-msbuild.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5059\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/03-msbuild.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>On the next page select the device you are targeting. The STM32WB-Nucleo USB Dongle uses the STM32WB55CGU6 device, so we select it in the list:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/04-device-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5060\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/04-device-2.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>In this tutorial the dongle will be running a Bluetooth LE Peripheral project (server) and the STM32WB-Nucleo board will run the Central project (client). Hence, select <strong>BLE_p2pServer\u00a0<\/strong> under <strong>STM32CubeMX Samples<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/05-server-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5066\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/05-server-1.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Unlike the Nucleo board itself, the USB dongle does not contain an embedded ST-Link debugger, hence you will not be able to debug it with VisualGDB. Select &#8220;Debug Methods -&gt; Built-in GDB Simulator&#8221; as a debug method (note that as of July 2019, the GDB simulator does not support STM32 devices):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/06-sim.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5062\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/06-sim.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Press &#8220;Finish&#8221; to create the project. As we will be using the STM32Programmer tool to upload the built project into the USB dongle, we recommend changing the target extension to <strong>.elf<\/strong> so that the tool can detect the file type automatically:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/07-elf.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5063\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/07-elf.png\" alt=\"\" width=\"1265\" height=\"821\" \/><\/a><\/li>\n<li>Build the project by pressing Ctrl-Shift-B:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/08-build.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5064\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/08-build.png\" alt=\"\" width=\"1265\" height=\"821\" \/><\/a><\/li>\n<li>Before you upload the built project into the dongle, you need to program the wireless stack binary (<strong>stm32wb5x_BLE_Stack_fw.bin) <\/strong>into it. Download and run our <a href=\"https:\/\/visualgdb.com\/tools\/STM32WBUpdater\/\">Wireless Stack Updater tool<\/a> to upload the wireless stack automatically. Once the stack is uploaded, leave the USB dongle in the bootloader mode: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/dongle.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5067\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/dongle.jpg\" alt=\"\" width=\"600\" height=\"248\" \/><\/a><\/li>\n<li>Install the <a href=\"https:\/\/www.st.com\/en\/development-tools\/stm32cubeprog.html\">STM32CubeProg<\/a> tool from ST and run the following command line:\n<pre class=\"\">STM32_Programmer_CLI.exe -c port=usb1 -d &lt;full path to PeripheralProject.elf&gt;<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/09-program.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5065\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/09-program.png\" alt=\"\" width=\"979\" height=\"693\" \/><\/a><\/li>\n<li>Once the dongle is programmed, move the SW2 switch back to the default position and replug the dongle. Observe how the green LED begins blinking:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/dongle-blinking.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5069\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/dongle-blinking.jpg\" alt=\"\" width=\"796\" height=\"375\" \/><\/a><\/li>\n<li>You can use the <a href=\"https:\/\/www.microsoft.com\/en-us\/p\/bluetooth-le-explorer\/9n0ztkf1qd98\">Bluetooth LE Explorer<\/a> app to verify that the dongle is advertising itself as a Bluetooth LE peripheral:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/10-explorer.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5070\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/10-explorer.png\" alt=\"\" width=\"1019\" height=\"490\" \/><\/a><\/li>\n<li>Click on the device to view services and characteristics provided by it:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/11-chars.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5071\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/11-chars.png\" alt=\"\" width=\"1019\" height=\"655\" \/><\/a><\/li>\n<li>You can read more about the STM32WB API used to register services and characteristics on the device side in our <a href=\"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/stm32wb\/peripheral\">STM32WB Peripheral Tutorial<\/a>. This tutorial will instead focus on the API for accessing those characteristics from a Bluetooth LE Central project. Select File-&gt;New-&gt;Project again, pick the VisualGDB Embedded Project Wizard and specify the location for the central project: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/12-central.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5072\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/12-central.png\" alt=\"\" width=\"1024\" height=\"710\" \/><\/a><\/li>\n<li>As the project will run on the Nucleo board itself, select the STM32WB55RG device that is present on the board:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/13-rg.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5073\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/13-rg.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>On the sample page select the <strong>BLE_p2pClient<\/strong> sample:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/14-client.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5074\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/14-client.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Plug in your Nucleo board via USB and let VisualGDB detect the ST-Link debug settings. Then press Finish to create the project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/15-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5075\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/15-debug.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>If you haven&#8217;t done this previously, program the <strong>stm32wb5x_BLE_Stack_fw.bin<\/strong> stack into the Nucleo board using our <a href=\"https:\/\/visualgdb.com\/tools\/STM32WBUpdater\/\">Wireless Stack Updater tool<\/a>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/08-update.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5019\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/08-update.png\" alt=\"\" width=\"586\" height=\"606\" \/><\/a><\/li>\n<li>Press F5 to build the Bluetooth LE Central project and begin debugging it:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/16-start.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5077\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/16-start.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a><\/li>\n<li>Once the project begins running on the Nucleo board, the green LED (LED2) will turn on:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/led_button-1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5079\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/led_button-1.jpg\" alt=\"\" width=\"700\" height=\"639\" \/><\/a><\/li>\n<li>Replug the USB dongle into the USB port and confirm that its green LED begins blinking, indicating that the Bluetooth LE advertisement is in progress. Then press the leftmost button (SW1) on the Nucleo board. The blue LED will turn on indicating the the scan is in progress:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/scan-1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5081\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/scan-1.jpg\" alt=\"\" width=\"700\" height=\"616\" \/><\/a>Once the scan is complete, the green LED on both Nucleo board and the USB dongle will begin blinking. Now you can press the button on the dongle to control the LED on the Nucleo board and the SW1 button on the Nucleo to control the LED on the dongle.<\/li>\n<li>Now we will go through the STM32 functions involved in discovering and communicating with the BLE Peripheral running on the USB dongle. Set a breakpoint inside the <strong>HAL_GPIO_EXTI_Callback()<\/strong> function in app_entry.c and restart the program via the button in the GDB Session window. Then press the SW1 button again. Once the breakpoint triggers, step through the <strong>HAL_GPIO_EXTI_Callback()<\/strong> function and into <strong>APP_BLE_Key_Button1_Action()<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/17-action.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5082\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/17-action.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a><\/li>\n<li>Note that the handler for the SW1 button does not immediately start calling the Bluetooth LE API. Instead, it enables the <strong>CFG_TASK_START_SCAN_ID<\/strong> task. You can use the &#8220;Find all references&#8221; function to find out that the task is implemented in the <strong>Scan_Request()<\/strong> function. STM32WB devices use the task scheduler to minimize power usage. Most of the time the CPU will be in the low power mode, only waking up to process a certain event. When the event arrives, the event handler typically wakes up a task that will do further processing. Tasks are created via the <strong>SCH_RegTask()<\/strong> function and are woken up by calling <strong>SCH_SetTask()<\/strong>. Set a breakpoint in <strong>Scan_Request()<\/strong> and continue the program to let the breakpoint trigger:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/18-scan.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5083\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/18-scan.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a><\/li>\n<li>The logic inside Scan_Request() is very simple &#8211; it calls <strong>aci_gap_start_general_discovery_proc()<\/strong> and immediately returns, letting the device go into the lower power mode until the Bluetooth LE logic receives some advertisement packets from BLE peripherals. Locate the line assigning 0x01 to the <strong>BleApplicationContext.DeviceServerFound<\/strong> field in <strong>app_ble.c<\/strong>, set a breakpoint there and wait for it to trigger:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/19-adv.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5084\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/19-adv.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a>The breakpoint will trigger once the <strong>SVCCTL_App_Notification()<\/strong> function gets called with an event type of <strong>EVT_LE_META_EVENT<\/strong> and sub-event of <strong>EVT_LE_ADVERTISING_REPORT<\/strong>. The logic in <strong>SVCCTL_App_Notification() <\/strong>checks that the advertisement packet contains the <strong>CFG_DEV_ID_P2P_SERVER1<\/strong> value,\u00a0 remembers the BLE Peripheral address and sets the <strong>DeviceServerFound<\/strong> field.<\/li>\n<li>Use the &#8220;Find References&#8221; command to locate the code that checks the <strong>DeviceServerFound <\/strong>field later, set a breakpoint there and let it trigger<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/20-scandone.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5085\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/20-scandone.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a>This code is located in the <strong>SVCCTL_App_Notification()<\/strong> function and gets invoked when the Bluetooth LE stack sends the <strong>EVT_VENDOR<\/strong> event with the <strong>EVT_BLUE_GAP_PROCEDURE_COMPLETE <\/strong>subevent.<\/li>\n<li>The code in <strong>SVCCTL_App_Notification()<\/strong> wakes up the <strong>Connect_Request()<\/strong> task and then the following events take place:\n<ol>\n<li><strong>Connect_Request() <\/strong>calls <strong>aci_gap_create_connection()<\/strong> to establish a connection to the peripheral.<\/li>\n<li>When the connection is created, the BLE stack sends the <strong>EVT_LE_META_EVENT<\/strong>\/<strong>EVT_LE_CONN_COMPLETE<\/strong> event to<br \/>\n<strong>SVCCTL_App_Notification()<\/strong>.<\/li>\n<li>The handler for the <strong>EVT_LE_CONN_COMPLETE <\/strong>event calls <strong>aci_gatt_disc_all_primary_services()<\/strong> to enumerate all services of the peripheral.<\/li>\n<li>Once the services are enumerated, the BLE stack sends the <strong>EVT_BLUE_GATT_PROCEDURE_COMPLETE<\/strong> event to the <strong>Event_Handler()<\/strong> callback in <strong>p2p_client_app.c<\/strong>.<\/li>\n<li>The <strong>EVT_BLUE_GATT_PROCEDURE_COMPLETE<\/strong> handler wakes up the <strong>Update_Service()<\/strong> task.<\/li>\n<li>The <strong>Update_Service()<\/strong> task together with <strong>Event_Handler()<\/strong> implement a basic state machine. Each time a related Bluetooth LE event arrives, <strong>Event_Handler()<\/strong> updates the internal state in the <strong>aP2PClientContext[index].state<\/strong> field and wakes up <strong>Update_Service() <\/strong>that starts the next Bluetooth LE request. In this example, the following requests take place:<strong><br \/>\n<\/strong><\/p>\n<ol>\n<li><strong>aci_gatt_disc_all_char_of_service()<\/strong> is called to discover all characteristics of the discovered service.<\/li>\n<li><strong>aci_gatt_disc_all_char_desc()<\/strong> is called to get the descriptors of the <strong>P2P_NOTIFY_CHAR_UUID<\/strong> characteristic.<\/li>\n<li><strong>aci_gatt_write_char_desc()<\/strong> is called to subscribe to change notifications from the characteristic by writing to its CCCD descriptor.<\/li>\n<\/ol>\n<\/li>\n<li>When the button on the USB dongle is pressed and it reports a change in the characteristic value, <strong>Gatt_Notification()<\/strong> is invoked on the Nucleo board to toggle the LED.<\/li>\n<\/ol>\n<p>You can find the code responsible for the LED toggling by setting a breakpoint in <strong>Gatt_Notification()<\/strong> and pressing the button on the USB dongle:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/21-led.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-5087\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2019\/07\/21-led.png\" alt=\"\" width=\"1232\" height=\"802\" \/><\/a><\/li>\n<\/ol>\n<p>You can change the logic of the Bluetooth LE Central used in this example by adding more states to the state machine implemented in<strong> Update_Service()<\/strong> and <strong>Event_Handler(). <\/strong>I.e. initiate new Bluetooth LE operations from <strong>Update_Service()<\/strong> and update the state in the <strong>Event_Handler()<\/strong>. This will minimize the power consumption by the STM32WB device, as it will automatically enter the low power state as soon as it is done handling an event.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to create a basic Bluetooth LE Central (a device that enumerates and communicates to Bluetooth LE<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18],"tags":[96,56,61,184],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/5055"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=5055"}],"version-history":[{"count":4,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/5055\/revisions"}],"predecessor-version":[{"id":5088,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/5055\/revisions\/5088"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=5055"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=5055"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=5055"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}