Bluetooth HM10 with STM32 | BLE | UART | STM32F103c8T6 (Arm Cortex M3)

Bluetooth HM10 module:

  • Bluetooth 4.0 
  • Bluetooth Low Energy (BLE)
  • UART interface
  • Data rate: 24 Mbps
  • Distance: 100 m 
  • Operating Voltage - 3.3 V 
  • 2.4 GHz communication range

Schematic:


Apart from RX, TX, VCC, Gnd pins, there is an LED (PIO1),  Switch(PIO0), USB pins and I/O or ADC pins available

Steps:

1. Configure using AT commands through Serial Terminal via PC / via Program

List of AT commands can be found in the link

- If AT+ command? is sent, you will receive a response with current setting for the command

(sometimes it might work without question mark)

- To set a parameter for a command, send AT+ command[parameter]

A) Set-up each device:

When ON, change mode to respond to AT commands for configurations: AT+IMME1  

         - Default baud rate is set as 9600, use command: AT+BAUD[P1] to change it.

          Note: The P1 number might vary

          - Can set module name: AT+NAME[P1] (max length - 12) (if required, use AT+SHOW1)

         - Can set UUID: AT+UUID[0x0001 to 0xFFFE]
         Note: Find module MAC address using: AT+ADDR? or AT+LADDR?

         Enable notifications: AT+NOTI1 

- Set role: for Slave - AT+ROLE0, for Master - AT+ROLE1

B) In Slave device (Peripheral role)

- Set Advertising interval: AT+ADVI [in ms] 

         - Can also set advertising type: AT+ADTY [0/1/2/3] 

        - Change the mode to work state after completing configuration: AT+START 

        - if required, For changes / commands to apply, restart: AT+RESET  

         Note: In some devices, if advertising didn't start, set flag: AT+FLAG[0 to FF] (any value) 

After restart, the slave will advertise, so the master can find it.  

C.1) In Master device (Central role) (or)

         - Start a device discovery scan: AT+DISC?
         responses: OK+DIS [string/address/index][start/end/MAC address] - list of available devices

        - If you need to connect to specific address: AT+CO [P0][P1]
or
        - Can connect using discovery index or MAC address: AT+CON [N index/MAC address]
        Connection status can be received in response to these connect commands

Note: After AT+CON or AT+CONNL commands, the master will change to work mode automatically

To disconnect from remote device use command: AT, if notification is enabled then you receive: OK+LOST response

2. Send / Receive data through Serial Terminal via PC / via Program

Work Modes:

        2.a - Transmit mode: Configuration through AT commands should be done before sending data via UART

        2.b - Remote mode: Configuration can be done through AT commands via remote options

        2.c - PIO mode: PIO (pins) can be controlled through AT commands like: AT+AFTC[P1], AT+BEFC[P1]

        By default, AT+MODE? is 0 - Transmission mode

Demo:

Configure Slave Bluetooth device using serial terminal: realterm

Connection: TX -> RX, RX -> TX, 3.3V -> VCC, Gnd -> Gnd

CP2102 USB to UART Serial converter -> HM10 Bluetooth module



PC - Device Manager
Realterm Serial Terminal:




Note: use command AT+HELP to see available commands


Use command AT+RESET and the start work mode using AT+START

Note: AT+TYPE is 0 - no pin required while connecting, default is 000000
use AT+PIN / AT+PASS to see the password

Bluetooth with STM32 (UART) as Slave and Phone with Bluetooth as Master:

Send data from STM32 UART -> Slave Bluetooth -> Phone Bluetooth (Master)

Connection: TX -> RX(PA10), RX -> TX(PA9), VCC -> 3.3V, Gnd -> Gnd

HM10 Bluetooth module -> STM32 UART



- In Phone Bluetooth it may show the device but it wont be able to connect to this BLE device. So use an app to connect to BLE device (nRF connect)

- open nRF connect app, click connect on your BLE name -> click on your UUID -> 3 dot -> Read character, to read the value you send from serial terminal or from STM32 UART program

Program:

/* STM32 - USART - Asynchronous mode
   LSB first
   Baud Rate = 9600, SysClk = 72 MHz
   Start bit - 8 data bits - 1 Stop bit
*/

#include "stm32f10x.h"
#define baud_9600 0x1D4C              // for SysClk = 72 MHz

void RCC_config(void);


void RCC_config() // RCC clock configuration
{
  RCC -> CR |= RCC_CR_HSEON;                               // HSE ON
  RCC -> CFGR |= (RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);    // Setting PLL - HSE * 9
  RCC -> CFGR |= RCC_CFGR_SW_1;                            // SysClk = PLLCLK
  RCC -> CR |= RCC_CR_PLLON;                                              
  // Turn ON PLL after above PLL configurations, making SysClk = HSE * 9 = 8 * 9 = 72 MHz
  RCC -> CFGR |= RCC_CFGR_PPRE1_DIV2;                      
  // APB1 = AHB / 2 = 72 / 2 = 36 MHz (max)
}

int main()
{
  RCC_config();
 
  /* USART1 configuration */
  RCC -> APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;            // Enable UART and Port A clock
  GPIOA -> CRH |= (GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_1);
  // PA9- CNF: 10, MODE: 10; PA10- CNF: 10, MODE: 00
  GPIOA -> CRH &= ((~GPIO_CRH_CNF9_0) & (~GPIO_CRH_CNF10_0));             // Clear default reset value
  USART1 -> BRR = baud_9600;                                              // Baud Rate = 9600
  USART1 -> CR1 |= USART_CR1_TE;                                          // Sending a Idle line
  /* This should clear TXE and TC flag */
  USART1 -> CR1 |= USART_CR1_UE;                                          // Enable USART, M = 0 - 8data bits
  /* USART1 -> CR2 : STOP = 0 -> Indicating 1 stop bit */
 
  USART1 -> DR = 'A';                                                      // Sending data

  while(1)
  {
    /*//static int i;
while(1)
{
  USART1 -> DR = 'A';
  //for(i = 0; i < 1000000; i ++);
while((USART1 -> SR & USART_SR_TC) == 0);
}*/
  }
  return 0;
}

Instead of single character, send a string

  static char s[19] = "STM32 with BLE\r\n";
static int i;

  while(1){
    for(i = 0; s[i]; i ++)
    {
      USART1 -> DR = s[i];
      while((USART1 -> SR & USART_SR_TC) == 0);
    }
  }

We can also send AT commands through program before sending data

static char at[20];
static int baud = 4;
static int i = 0;

sprintf(at,"AT+BAUD%d\r\n",baud);

while(1){
    for(; at[i]; i ++)
    {
      USART1 -> DR = at[i];
      while((USART1 -> SR & USART_SR_TC) == 0);
    }
  }

Reference: link

For getting started with STM32, click here

For UART in STM32, see this post

For RTOS in STM32, see this post

For I2C driver program in ATMega328P, see this post

Comments