IOT

Create BLE Project using STM32 Microcontroller & BlueIO

We’ll learn how to make a BLE project with an STM32 microcontroller and BlueIO in this tutorial. The project is a basic demonstration of how to quickly configure a STM32Cube as a USB CDC Host capable of connecting with the BleuIO Dongle.

The STM32 will recognize a BleuIO Dongle connected to the Nucleo board’s USB connection. The BleuIO Dongle will then accept one of three UART inputs and transmit one of three preprogrammed commands according to the input. The following commands are used in this example:

  • ATI(Dongle Information)
  • AT+ADVSTART(Starts Advertising)
  • AT+ADVSTOP(Stops Advertising)

We used an STM32 Nucleo-144 development board with an STM32H743ZI microcontroller, which is an ARM® Cortex®-M7 MCU 32-Bit Embedded Evaluation Board. We’ll develop a demo BLE project with the same STM32 Microcontroller and BlueIO in this example.

If you want to utilize a different arrangement, make sure it supports USB Host, and keep in mind that the GPIO setup may be different, requiring changes to the.ioc file.

About the Code

You can get the project here: https://github.com/smart-sensor-devices-ab/stm32_bleuio_example

This project-based on a new STM32 project with these changes in the .ioc file. The ‘USB_OTG_FS’-mode is set to Host-Only under ‘Connectivity,’ and all global interrupts are enabled in the NVIC Settings.

The ‘USB_HOST’-‘Class for FS IP’ is set to ‘Communication Host Class (Virtual Port Com)’ under ‘Middleware’.

The USBH_UserProcess  function in ‘usb host.c’ (located under ‘USB HOST’ -> ‘App’ folder) was added to ensure that the host would identify when the bootloader was complete and the BleuIO firmware was executing.

static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
{
/* USER CODE BEGIN CALL_BACK_1 */
switch(id)
{
case HOST_USER_SELECT_CONFIGURATION:
break;

case HOST_USER_DISCONNECTION:
Appli_state = APPLICATION_DISCONNECT;
isBleuIOReady = false;

// Turn on Red LED, turn off Green and Yellow LED
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);
break;

case HOST_USER_CLASS_ACTIVE:
Appli_state = APPLICATION_READY;
// Check if BleuIO firmware is running
// (idProduct:0x6001 = bootloader, idProduct:0x6002 = bleuio fw)
if(phost->device.DevDesc.idProduct == 0x6002)
{
isBleuIOReady = true;
// Sends message to uart that BleuIO is connected and ready
HAL_UART_Transmit(&huart3, (uint8_t*)BLEUIO_READY, strlen(BLEUIO_READY), HAL_MAX_DELAY);

// Turn on Green LED, turn off Yellow and Red LED
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);

// Start receiving from usb
USBH_CDC_Receive(&hUsbHostFS, CDC_RX_Buffer, RX_BUFF_SIZE);
}
break;

case HOST_USER_CONNECTION:
Appli_state = APPLICATION_START;
isBleuIOReady = false;
// Turn on Yellow LED, turn off Green and Red LED
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);
break;

default:
break;
}
/* USER CODE END CALL_BACK_1 */
}

About the Code

The Nucleo board’s Green, Red, and Yellow LEDs are also programmed to change colour according on the connection state.

  • Red = Disconnnected
  • Yellow = Connecting
  • Green = Connected

An external variable bool is BleuIOReady is also set so the status of the dongle is accessible from the main.c section.

The USBH_CDC_Receive function is called after the BleuIO dongle is confirmed to be connected in order to begin receiving data from the USB CDC. Additionally, the USBH_CDC_ReceiveCallback must be implemented.

/**
* @brief Simple function that takes a string and transmit it to the dongle
* @retval None
*/
void writeToDongle(uint8_t * cmd)
{
USBH_CDC_Transmit(&hUsbHostFS, cmd, strlen((char *)cmd));
}

To receive input from Uart and a simple UART input handler, HAL_UART_RxCpltCallback is implemented in main.c.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
if(UartHandle == &huart3)
{
RX_value = (int)aRxBuffer[0];
uartStatus = UART_RX_NONE;

switch(RX_value)
{
case UART_RX_0:
{
uartStatus = UART_RX_0;
break;
}
case UART_RX_1:
{
uartStatus = UART_RX_1;
break;
}
case UART_RX_2:
{
uartStatus = UART_RX_2;
break;
}
default:
{
uartStatus = UART_RX_NONE;
break;
}
}
// Resets uart recieve interrupt mode
HAL_UART_Receive_IT(&huart3, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
}
}


/**
* @brief Simple uart input handler
* @retval None
*/
void handleUartInput(UARTCommandTypeDef cmd)
{
switch(cmd)
{
case UART_RX_0:
{
// 0
uart_buf_len = sprintf(uart_tx_buf, “\r\n(0 pressed)\r\n”);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
if(isBleuIOReady)
{
writeToDongle((uint8_t*)DONGLE_CMD_ATI);
} else
{
uart_buf_len = sprintf(uart_tx_buf, BLEUIO_NOT_READY_MSG);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
}
uartStatus = UART_RX_NONE;
break;
}
case UART_RX_1:
{
// 1
uart_buf_len = sprintf(uart_tx_buf, “\r\n(1 pressed)\r\n”);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
if(isBleuIOReady)
{
writeToDongle((uint8_t*)DONGLE_CMD_AT_ADVSTART);
} else
{
uart_buf_len = sprintf(uart_tx_buf, BLEUIO_NOT_READY_MSG);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
}
uartStatus = UART_RX_NONE;
break;
}
case UART_RX_2:
{
// 2
uart_buf_len = sprintf(uart_tx_buf, “\r\n(2 pressed)\r\n”);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
if(isBleuIOReady)
{
writeToDongle((uint8_t*)DONGLE_CMD_AT_ADVSTOP);
} else
{
uart_buf_len = sprintf(uart_tx_buf, BLEUIO_NOT_READY_MSG);
HAL_UART_Transmit(&huart3, (uint8_t *)uart_tx_buf, uart_buf_len, HAL_MAX_DELAY);
}
uartStatus = UART_RX_NONE;
break;
}
case UART_RX_NONE:
{
break;
}
default:
{
uartStatus = UART_RX_NONE;
break;
}
}
}

The handleUartInput() takes inputs 0 through 2 and maps them to specific Dongle commands. After that, the handler is inserted into the main loop.

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
// Simple handler for uart input
handleUartInput(uartStatus);
}
/* USER CODE END 3 */

Using the example project

For creating BLE Project using STM32 Microcontroller & BlueIO, we need the following list of hardware & software.

How to Setup the Project

Downloading the project from GitHub

Get the project from here: https://github.com/smart-sensor-devices-ab/stm32_bleuio_example

In your STM32CubeIDE workspace, either clone the project or download it as a zip file and unpack it.

Importing as an Existing Project

From STM32CubeIDE choose File>Import…

Then select  General>Existing Projects into Workspace then click ‘Next >’

Make sure you’ve chosen your workspace in ‘Select root directory:’

You should see “stm32_bleuio_example”,” tick it, and then click “Finish.”

/p>

Running the example

  • In STMCubeIDE click the hammer icon to build the project.
  • Open up the ‘STMicroelectronics STLink Virtual COM Port’ with a serial terminal emulation program like TeraTerm, Putty, or CoolTerm.Serial port Setup:
    Baudrate: 115200
    Data Bits: 8
    Parity: None
    Stop Bits: 1
    Flow Control: None
  • To flash and run it on your board, press the green play button in STMCubeIDE. The ‘Run Configuration’ window will appear the first time you click it. Simply leave it alone and click Run.
  • The BleuIO Dongle must be connected.
  • Wait until you see the message “[BleuIO Dongle Ready].”

– Press 0 to get device information:

 1 to start advertising:

2 to stop advertising:

The response from the Dongle will be printed to UART.

Conclusion

This is how you can make a Bluetooth Low Energy (BLE) project with an STM32 microcontroller and BlueIO. We MATHA ELECTRONICS will be back soon with more informative blogs.

Leave a Reply

Your email address will not be published.