cancel
Showing results for 
Search instead for 
Did you mean: 

How to run a BLE P2P Server simultaneously with USB CDC on STM32WB part 2

B.Montanari
ST Employee

How to run a Bluetooth® Low Energy P2P Server simultaneously with USB CDC on STM32WB part 2

Welcome back! If you have not seen the part 1 yet, please use the link to get the hardware settings in place before moving to the code, and now that you have, LET’S CODE!

We use the following files to implement our code:
  • app_ble.c
  • p2p_server_app.c
  • app_conf.h
  • app_entry.c
  • main. c
In STM32_WPAN > app > app_ble.c file, around line 750 between USER CODE “BEGIN” and “END” RADIO_ACTIVITY_EVENT insert the following code:
#if (RADIO_ACTIVITY_EVENT != 0)
        case ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE:

          /* USER CODE BEGIN RADIO_ACTIVITY_EVENT*/
		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);
          /* USER CODE END RADIO_ACTIVITY_EVENT*/

          break; /* ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE */
#endif /* RADIO_ACTIVITY_EVENT != 0 */
The Radio Activity Event is triggered after every Radio RF Activity finishes. The lines above will make the LD2 (Green LED) blink every 5ms every time this happens.
For the next step, still in STM32_WPAN > app, open the p2p_server_app.c file and add the following code, to set the Blue LED on every time you give this command through the phone.
 
    case P2PS_STM_WRITE_EVT:
/* USER CODE BEGIN P2PS_STM_WRITE_EVT */
if (pNotification -> DataTransfered.pPayload[1] == 0x01)
{
	HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
}

else 
{
	HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
}
/* USER CODE END P2PS_STM_WRITE_EVT */
      break;
Now, still in p2p_server_app.c, add the following function and its prototype:
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
static void P2PS_Send_Notification(void);
/* USER CODE END PFP */

/* USER CODE BEGIN FD */
static void P2PS_Send_Notification(void)
{
	/* Update P2P_NOTIFU characteristic */
	P2PS_STM_App_Update_Char(P2P_NOTIFY_CHAR_UUID, 0X00);
	
	return;
}
/* USER CODE END FD */
Now, going to Core > Inc > app_conf.h, between /* USER CODE BEGIN/END CFG_Task_ Id_With_HCI_Cmd_t */, we will create a task that will send a message over Bluetooth to the phone informing when the User Button is pressed.
/**< Add in that list all tasks that may send a ACI/HCI command */
typedef enum
{
  CFG_TASK_ADV_CANCEL_ID,
#if (L2CAP_REQUEST_NEW_CONN_PARAM != 0 )
  CFG_TASK_CONN_UPDATE_REG_ID,
#endif
  CFG_TASK_HCI_ASYNCH_EVT_ID,

  /* USER CODE BEGIN CFG_Task_Id_With_HCI_Cmd_t */

  CFG_TASK_SW1_BUTTON_PUSHED_ID,		/**< ADD THIS LINE */

  /* USER CODE END CFG_Task_Id_With_HCI_Cmd_t */

  CFG_LAST_TASK_ID_WITH_HCICMD,		/**< Shall be LAST in the list */
} CFG_Task_Id_With_HCI_Cmd_t;
Back to the p2p_server_app.c file, add the code bellow in the “P2PS_APP_Init function” to register the Send notification task ID:
void P2PS_APP_Init(void)
{
/* USER CODE BEGIN P2PS_APP_Init */
	UTIL_SEQ_RegTask(1<<CFG_TASK_SW1_BUTTON_PUSHED_ID, UTIL_SEQ_RFU, P2PS_Send_Notification);
/* USER CODE END P2PS_APP_Init */
  return;
}
Now, on Core > Src > app_entry.c, add the Interrupt Callback to execute the task when the user button is pressed.
/* USER CODE BEGIN FD */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	switch (GPIO_Pin)
	{
	case BUTTON_SW1_Pin:
		UTIL_SEQ_SetTask(1<<CFG_TASK_SW1_BUTTON_PUSHED_ID, CFG_SCH_PRIO_0);
		break;
	default:
		break;
	}
	
	return;
}
/* USER CODE END FD */
Now, to let the Bluetooth® Low Energy code work along with the USB code, we perform a simple workaround by taking HSEM5, thereby preventing CPU2 from getting it along with its ability to control the CLK48 clock.
To perform this, we create a function that locks the HSEM5, enable the HSI48 as the USB clock, and configure the clock recovery system for automatic recalibration when used with USB.
Going to Core > Src > main.c, add the Function Prototype:
/* USER CODE BEGIN PFP */
void PeriphUsbClock_Config(void);
/* USER CODE END PFP */
Also, in the same file, add the function, you can locate yourself using the USER CODE BEGIN 4 comment:
/* USER CODE BEGIN 4 */

void PeriphUsbClock_Config(void)
{
#if (CFG_USB_INTERFACE_ENABLE != 0)
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };
	RCC_CRSInitTypeDef RCC_CRSInitStruct = { 0 };

/* This prevents the CPU2 to disable the HSI48 oscillator when
 * It does not use anymore the RNG IP */
 
LL_HSEM_1StepLock( HSEM, 5 );


/* Enables the HSI48 Clock Source */

LL_RCC_HSI48_Enable();

while(!LL_RCC_HSI48_IsReady());

/* Select HSI48 as USB clock source */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);



/* Configure the clock recovery system (CRS)**********************************/

/* Enable CRS Clock */
__HAL_RCC_CRS_CLK_ENABLE();

/* Default Synchro Signal division factor (not divided) */
RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;

/* Set the SYNCSRC[1:0] bits according to CRS_Source value */
RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;

/* HSI48 is synchronized with USB SOF at 1KHz rate */
RCC_CRSInitStruct.ReloadValue = RCC_CRS_RELOADVALUE_DEFAULT;
RCC_CRSInitStruct.ErrorLimitValue = RCC_CRS_ERRORLIMIT_DEFAULT;
RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;

/* Set the TRIM[5:0] to the default value*/
RCC_CRSInitStruct.HSI48CalibrationValue = RCC_CRS_HSI48CALIBRATION_DEFAULT;

/* Start automatic synchronization */
HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);

#endif

	return;
}

/* USER CODE END 4 */
Remember to enable the USB interface by setting the CFG_USB_INTERFACE_ENABLE to 1 on Core > Inc > app_conf.h, around line 465, as follows:
 
/******************************************************************************
 * USB interface
 ******************************************************************************/

/**
 * Enable/Disable USB interface
 */
#define CFG_USB_INTERFACE_ENABLE    1
Please note that each time you regenerate code, it is necessary to enable again the USB peripheral.
To test and verify that everything is working as expected, the STBLESensor app can be used and easily connected to the board.
Build the code, check errors and warnings, and run it:
556.png
The Green LED must blink, advertising that it is ready to connect.
558.png
Open the Bluetooth® Low Energy sensor app and you already can see the board available to connection.
561.png
Clicking on the image changes the LED status and you can see that the Blue LED switched on.
Pressing the user button SW1, the message “Button pressed” will appear in the app.
563.png
With the user USB connected properly, we can see that a virtual COM Port is opened without any problems:
565.png
Well done!
With this setup, the USB CDC class works just fine alongside with the Bluetooth® Low Energy Peer to peer Server!
 
Comments
SFry.2
Associate

You also need to add a call to PeriphUsbClock_Config

to main.c

MSing.1713
Associate II

Greetings,

Thanks for this post.  I witnessed this issue and started to debug.  It was clear that starting the stack was disabling the clock.  I tried just reenabling it after starting the stack which, of course, did nothing.  As I'm not using Cube libraries, the crux is that I had to lock HSEM channel 5, a one-line change.

But, to be clear, the thanks is really for posting something that was easily findable with a search on "USB BLE simultaneous stm32wb".

Cheers

baydı.1
Associate III

Hello Mr. Montarani, 

           Thanks for great tutorial. My question is may seems unrelated.   I am trying to do BLE camera module. And I am using the EXTI and DMA to taking data from camera. My BLE code and Camera code working fine when I run them in different project. However when I try to implement camera code to sequencer, sequencer somehow does not work propoerly.  Here is my EXTI callback function that is used for sycronization with camera and taking data to write memory. 

void APP_BLE_RISING_FV_Action(void){
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
}

void APP_BLE_FALLING_FV_Action(void){
HAL_NVIC_DisableIRQ(EXTI2_IRQn);
HAL_NVIC_DisableIRQ(EXTI3_IRQn);
}

void APP_BLE_RISING_LV_Action(void){
DMA_Enable();
if(hsyncCount<240)
{
hsyncCount++;
}
else {

// uart_flag =1;
hsyncCount=0;
HAL_NVIC_DisableIRQ(EXTI0_IRQn);
HAL_NVIC_DisableIRQ(EXTI1_IRQn);
HAL_NVIC_DisableIRQ(EXTI2_IRQn);
HAL_NVIC_DisableIRQ(EXTI3_IRQn);
frame_complete=0;
UTIL_SEQ_SetTask(1<<CFG_TASK_SEND_DATA, CFG_SCH_PRIO_0);

}
}

void APP_BLE_FALLING_LV_Action(void){
DMA_Disable();
}

 

After running this part once, I cannot add new task or run task in sequenecer. Indeed, until

" UTIL_SEQ_SetTask(1<<CFG_TASK_SEND_DATA, CFG_SCH_PRIO_0);" line everthing working fine. Do you have any

idea what I am missing?

Lep
Senior

@baydı.1 Have you solved this problem? I added the UTIL_SEQ_SetTask function to HAL_GPIO_EXTI_Callback, and my program also crashed. I also tried various methods, but still no solution...

Thanks and regards.

Version history
Last update:
‎2023-05-22 02:20 AM
Updated by: