2021-08-17 08:48 AM
Was anybody able to implement a custom BLE profile for the STM32WB55 using STM32CubeIDE v1.7 (or around) and the firmware package 1.11.1 (or around)? I would like to recreate and make publicly available this workshop. It is out-of-date.
2021-11-18 01:40 PM
I was able to recreate the project outlined in the MOOC STM32WB Workshop - 4 How to modify BLE Profile using STMCubeIDE v 1.7 and firmware STM32Cube_FW_WB_V1.12.1. But to do this I started with MOOC STM32WB Workshop - 3 How to add BLE functionality, which is now also out of date, and then modified that project to include a notification stream like that in Workshop - 4, while maintaining the push button notification and LED control of Workshop - 3. I'll paste in my lengthy notes below for the Workshop - 3 below, and for Workshop - 4 in a separate answer.
In terms of client apps, I could not get the ST apps (STBLESensor, STBLEProfiles) running on iOs to work with these two projects. The app LightBlue by PunchThrough seemed to work well for both.
Project BLE_BasicP2P, replicates the functionality outlined in Workshop for the P-Nucleo-WB55 board:
In STM32CubeMx (using 6.3.0):
1. Use Board selector to find: P-NUCLEO-WB55-Nucleo. Start project, accept "Set peripherals to defaults".
2. Configure board for BLE:
System Core > RCC > HSE > Crystal/Ceramic Resonator
(default), note this enables two pins RCC_OSC_IN, and RCC_OSCOUT
System Core > RCC > LSE > Crystal/Ceramic Resonator
(default), two pins RCC_OSC32_IN and _OUT
System Core > HSEM > check Activated
Connectivity > RF > Activate RF1
RF_RF1 pin enabled
Timers > RTC > Activate Clock Source
WakeUp > Internal WakeUp,
Wakeup >Configuration> NVIC Interrupt Table > RTC wakeup interrupt
Middleware > STM32_WPAN > check BLE
BLE Application Type : Server profile
Server Mode: Custom P2P Server Enabled (default)
Local Name: max chars = 7, default is P2PSRV1
3. Configure Clocks: Clock Configuration Tab
RTC Source Mux (top left of clock map): set to LSE
System Clock Mux (just below RTC): set to HSE_SYS (default),
both CPUs should have 32 MHz (HCLK1, HCLK2)
RFWKP Clock Mux (lower right corner): set to LSE
4. Project Manager
Project tab: Set or check project name, location, STM32CubeIDE,
check Generate Under Root.
This project uses Firmware Package: STM32Cube FW_WB V1.12.1
Advanced tab: Make sure STM32_WPAN is LAST in the list of Generated Function Calls (default).
5. Generate code, accept open project in IDE if working in standalone CubeMX.
6. Add HSE tuning, in Core/Src/stm32wbxx_hal_msp.c. See AN5042 for details on how to generate the underlying otp data.
#include "otp.h"
OTP_ID0_t * p_otp;
// Read HSE_Tuning from OTP
p_otp = (OTP_ID0_t *) OTP_Read(0);
if (p_otp){
LL_RCC_HSE_SetCapacitorTuning(p_otp->hse_tuning);
}
7. Add STM32_WPAN ISRs in Core/Src/STM32wbxx_it.c. in /*USER CODE BEGIN 1 (~line 245)
void IPCC_C1_RX_IRQHandler(void){
// This function handles IPCC RX occupied interrupt
HW_IPCC_Rx_Handler();
}
void IPCC_C1_TX_IRQHandler(void){
// This function handles IPCC TX free interrupt.
HW_IPCC_Tx_Handler();
}
8. Add a blinking led to mark radio activity event in STM32_WPAN/app_ble.c (~line 679) at /* USER CODE BEGIN RADIO_ACTIVITY_EVENT*/
// 5 ms green led after(?) every Radio Activity Event finishes
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
HAL_Delay(5);
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
9. Test build, debug, resume, run BLE phone app . At this point I could see the board on the phone app, could connect, and see default characteristics of the P2PServer: one read/write without response, one notify. Radio activity LED (LD2) on the Nucleo blinks slowly when disconnected, more rapidly when connected. If you don't connect within 60 sec, board goes into low power mode and you will have to reset the board. Note: LightBlue does not appear to update the primary service name until after you connect.
10. Turn red LED (LD3) on or off when GATT client writes 1 or 0, respectively, to P2P_WRITE characteristic. In STM32_WPAN/App/p2p_server_app.c P2PS_STM_App_Notification(), case P2PS_STM_WRITE_EVT, check data payload of notification. Note it seems like the payload structure has recently changed to not include the length (which is now DataTransfered.Length) so you can just dereference the pointer. At /* USER CODE BEGIN P2PS_STM_WRITE_EVT */ ~ line 85
if(*pNotification->DataTransfered.pPayload == 0x01) {
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}
else {
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}
11. Build and debug. Connect with LightBlue app and write 1 and then 0 and check for LD3 response.
12. When switch SW1 on Nucleo board is pressed, modify P2P_NOTIFY characteristic value, and send notification to client.
static void P2PS_Send_Notification(void);
and at /* USER CODE BEGIN FD */ ~line 149
static void P2PS_Send_Notification(void){
// Update P2P_NOTIFY characteristic
P2PS_STM_App_Update_Char(P2P_NOTIFY_CHAR_UUID, 0x00);
return;
}
UTIL_SEQ_RegTask(1 << CFG_TASK_SW1_BUTTON_PUSHED_ID, 0, P2PS_Send_Notification);
i. In Pinout tab / Pinout view, left click pin for PC4, select GPIO_EXT14, then right click on the pin and rename the pin to SW1
ii. System Core > GPIO > PC4 > GPIO mode > Ext interrupt: Falling edge detection. GPIO Pull-up/Pull-down > Pull-up
iii. System Core > NVIC > EXTI line4 interrupt (check box far to the right, often hidden) > enable
iv. generate code, open project in IDE
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
switch (GPIO_Pin){
case SW1_Pin:
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin); //optional blue led
UTIL_SEQ_SetTask(1<<CFG_TASK_SW1_BUTTON_PUSHED_ID, CFG_SCH_PRIO_0);
break;
default:
break;
}
return;
}
CFG_TASK_SW1_BUTTON_PUSHED_ID,
LL_EXTI_EnableIT_0_31(1<<4); // re-enable of exti line 4
2021-11-19 07:21 AM
BLE_CustomP2P project. The goal of this project was to begin with a copy of the above project and then add a custom notification characteristic that would push a sawtooth stream of 4 byte numbers from the Nucleo-STM32WB55 Nucleo board out to the client, recreating the functionality shown in the MOOC Workshop-4.
Duplicate and rename a project in the workspace
Add custom template. Using Mx (IDE or standalone version) modify the .ioc. In Pinout & Configuration > Middleware>STM32_WPAN >BLE Applications and Services
This brings up new tabs to be configured. A lot of confusion here. I thought I should be using AD_TYPE_MANUFACTURER_SPECIFIC_DATA element and that this would be 13 bytes with predefined fields as outlined in AN5289 section 7.3 and UM2496 section 1, but it seemed to be limited to 4 bytes. The UUID for P2P Service shown in AN5289 section 7.4.1 seems to be a nibble short:
00 00 FE 40 CC 7A 48 2A 98 4A 7F ED 5B 3E 58 F
So in the end I just used the UUID's from the MOOC Workshop #4 in the AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST and Characteristic1 UUID even though this is likely not correct.
BLE Advertising tab
Advertising configuration
Advertising Elements
BLE GATT tab
NumberStreamSvc tab
Characteristic1 properties
Build, Debug, Test previous functions in LightBlue: write to LD3 and SW1 notify. Note LightBlue doesn't seem to update Service Name until after connecting. The primary service name changes to NUMSTRM.
Create a structure for number stream data. Since in STM32_WPAN/App/custom_app.c, the user code section for private typedefs is below the Mx generated Custom_App_Context_t, I put the typedef in custom_app.h at /* USER CODE BEGIN ET */ ~line 49
typedef struct {
uint16_t Timestamp;
uint16_t Value;
} Numstrchar_Data_t;
Add Numstrchar_Data_t to Custom_App_Context_t in STM32_WPAN/App/custom_app.c at /* USER CODE BEGIN CUSTOM_APP_Context_t */ ~ line 41
Numstrchar_Data_t Numstr_Data;
Initialize Numstr_data. In STM32_WPAN/App/custom_app.c, Custom_APP_Init() at /* USER CODE BEGIN CUSTOM_APP_Init */ ~ line 166
Custom_App_Context.Numstr_Data.Timestamp = 0;
Custom_App_Context.Numstr_Data.Value = 0;
Implement number updates for number stream
#define NUM_CHANGE_STEP 10
#define NUM_CHANGE_PERIOD \
(0.1*1000*1000/CFG_TS_TICK_VAL)
#define NUM_VALUE_MAX 500
#define NUM_VALUE_MIN 10
uint16_t Change_Step;
Custom_App_Context.Change_Step = NUM_CHANGE_STEP;
static void Numstr_Modify_Number(void){
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin); //optional blue led
Custom_App_Context.Numstr_Data.Value += Custom_App_Context.Change_Step;
Custom_App_Context.Numstr_Data.Timestamp += NUM_CHANGE_STEP;
if (Custom_App_Context.Numstr_Data.Value > NUM_VALUE_MAX){
Custom_App_Context.Change_Step = -NUM_CHANGE_STEP;
}
else if (Custom_App_Context.Numstr_Data.Value < NUM_VALUE_MIN){
Custom_App_Context.Change_Step = NUM_CHANGE_STEP;
}
// Update the send buffer by bytes. LightBlue app seems to expect bigendian
UpdateCharData[0] = Custom_App_Context.Numstr_Data.Timestamp >> 8;
UpdateCharData[1] = Custom_App_Context.Numstr_Data.Timestamp & 0x00ff;
UpdateCharData[2] = Custom_App_Context.Numstr_Data.Value >> 8;
UpdateCharData[3] = Custom_App_Context.Numstr_Data.Value & 0x00ff;
Custom_Numstrchr_Update_Char();
}
static void Numstr_Modify_Number(void);
Create a task for triggering Numstr_Modify_Number. In Core/Inc/app_conf.h, /* USER CODE BEGIN CFG_Task_Id_With_HCI_Cmd_t */ ~ line 583 (I put this below CFG_TASK_SW1_BUTTON_PUSHED_ID, previously added for SW1 task)
CFG_TASK_NUMSTR_NOTIFY,
Register the task during app init. In STM32_WPAN/App/custom_app.c, in /* USER CODE BEGIN CUSTOM_APP_Init */ ~line 172
UTIL_SEQ_RegTask(1<<CFG_TASK_NUMSTR_NOTIFY, 0, Numstr_Modify_Number);
Set up a virtual timer to trigger send notification at 10Hz. All code goes in STM32_WPAN/App/custom_app.c
uint8_t Update_Timer_Id;
static void Numstr_Timer_Callback(void);
static void Numstr_Timer_Callback(void){
UTIL_SEQ_SetTask(1 << CFG_TASK_NUMSTR_NOTIFY, CFG_SCH_PRIO_0);
}
HW_TS_Create(CFG_TIM_PROC_ID_ISR, &Custom_App_Context.Update_Timer_Id, \
hw_ts_Repeated, Numstr_Timer_Callback);
Manage timer start. In STM32_WPAN/App/custom_app.c /* USER CODE BEGIN CUSTOM_STM_NUMSTRCHR_NOTIFY_ENABLED_EVT */ ~line 110
HW_TS_Start(Custom_App_Context.Update_Timer_Id, NUM_CHANGE_PERIOD);
Manage timer stop, in /* USER CODE BEGIN CUSTOM_STM_NUMSTRCHR_NOTIFY_DISABLED_EVT */ ~line 116
HW_TS_Stop(Custom_App_Context.Update_Timer_Id);
Build, debug. In LightBlue, test previous write and notify characteristics. In the new notify characteristic: Listen for Notifications. Blue LED (LD1) on Nucleo board flashes at about 5Hz (10Hz toggle). LightBlue app shows stream of 4-byte numbers. High 2 bytes are the timestamp which just steadily increments, low 2 bytes are the value, which swings between 0x000A and 0x01f4.
Hope that helps fill the void.