This blog is to use Nordic nRF52840 as the BLE keyboard with multiple peripheral role. Those keyboard would connect to multiple mobile (BLE central) for demo.

I would use the HOGP Keyboard example on this blog.

HID over GATT Profile Specification (HOGP)

This profile requires the Generic Attribute Profile (GATT), the Battery Service, the Device Information Service, and the Scan Parameters Profile.

This specification can be used with Bluetooth Core Specification Version 4.0 or later.

Boot Host and HID Device Roles/Service Relationship
Report Host and HID Device Roles / Service Relationships

Nordic nRF5 SDK

The nRF5 SDK provides a rich developing environment for nRF5 Series devices by including a broad selection of drivers, libraries, examples for peripherals, SoftDevices, and proprietary radio protocols.

The SDK is delivered as a plain .zip-archive, which makes it easy to install as well as giving you the freedom to choose the IDE and compiler of your choice.

All code examples included in the SDK are tailored to compile for and run on Nordic Semiconductor’s nRF5 Development Kits.

To download the nRF5 SDK, go to www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF5-SDK.

HID Keyboard Application

All provided HID examples conform with USB HID usage tables, http://www.usb.org/developers/hidpage.

https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/ble_sdk_app_hids_keyboard.html

The HID Keyboard Application is an example that implements the HID over GATT profile for keyboard using the hardware delivered in the nRF5 Development Kit.

The application includes the three mandatory services needed for the HID over GATT profile:

How to create BLE Dual Peripheral role

  • Configure the multiple link inside the sdk_config.h

Initialize the BLE Stack

  • add the number link configuration during the ble_stack_init

Modify the RAM configuration if using the Segger Embedded Studio

  • direct modify the project file (ble_app_hids_keyboard_pca10056_s140.emProject)

GATT Server Table

Inside Multiple BLE Peripheral, it consists of the Battery services, Device Information Service and HID services.

Use the BLE Connection State module to get all the link status.

For example on the ble_evt_handler, it needs to store all the links status and do the advertising if need.

/**@brief Function for handling the Connected event.
 *
 * @param[in] p_gap_evt GAP event received from the BLE stack.
 */
static void on_connected(const ble_gap_evt_t * const p_gap_evt)
{
        ret_code_t err_code;
        uint32_t periph_link_cnt = ble_conn_state_peripheral_conn_count(); // Number of peripheral links.

        NRF_LOG_INFO("Connection with link 0x%x established.", p_gap_evt->conn_handle);

        // Assign connection handle to available instance of QWR module.
        for (uint32_t i = 0; i < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT; i++)
        {
                if (m_qwr[i].conn_handle == BLE_CONN_HANDLE_INVALID)
                {
                        err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr[i], p_gap_evt->conn_handle);
                        APP_ERROR_CHECK(err_code);
                        break;
                }
        }

        err_code = app_button_enable();
        APP_ERROR_CHECK(err_code);

        // Update LEDs
        bsp_board_led_on(CONNECTED_LED);
        if (periph_link_cnt == NRF_SDH_BLE_PERIPHERAL_LINK_COUNT)
        {
                bsp_board_led_off(ADVERTISING_LED);
        }
        else
        {
                // Continue advertising. More connections can be established because the maximum link count has not been reached.
                //advertising_start();
                advertising_start(false);
        }
}

/**@brief Function for handling the Disconnected event.
 *
 * @param[in] p_gap_evt GAP event received from the BLE stack.
 */
static void on_disconnected(ble_gap_evt_t const * const p_gap_evt)
{
        ret_code_t err_code;
        uint32_t periph_link_cnt = ble_conn_state_peripheral_conn_count(); // Number of peripheral links.

        NRF_LOG_INFO("Connection 0x%x has been disconnected. Reason: 0x%X",
                     p_gap_evt->conn_handle,
                     p_gap_evt->params.disconnected.reason);

        if (periph_link_cnt == 0)
        {
                bsp_board_led_off(CONNECTED_LED);
                err_code = app_button_disable();
                APP_ERROR_CHECK(err_code);
        }

        if (periph_link_cnt == (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT - 1))
        {

                NRF_LOG_INFO("on_disconnected peripheral link cnt = %d", periph_link_cnt);
                // Advertising is not running when all connections are taken, and must therefore be started.
                advertising_start(false);
        }
}

/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
        ret_code_t err_code;

        switch (p_ble_evt->header.evt_id)
        {
        case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected");
                // err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                // APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                // err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                // APP_ERROR_CHECK(err_code);

                on_connected(&p_ble_evt->evt.gap_evt);
                break;

        case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected");
                // Dequeue all keys without transmission.
                (void) buffer_dequeue(false, p_ble_evt->evt.gap_evt.conn_handle);

                on_disconnected(&p_ble_evt->evt.gap_evt);

                m_conn_handle = BLE_CONN_HANDLE_INVALID;

                // Reset m_caps_on variable. Upon reconnect, the HID host will re-send the Output
                // report containing the Caps lock state.
                m_caps_on = false;

                // disabling alert 3. signal - used for capslock ON
                // err_code = bsp_indication_set(BSP_INDICATE_ALERT_OFF);
                // APP_ERROR_CHECK(err_code);

                break; // BLE_GAP_EVT_DISCONNECTED

How to test with two difference Mobile phones

  • Bonding with Mobile through bluetooth setting menu
  • Press the button 1 or button 2 to send the keyboard data to mobile.

Here is the demo to use the nRF52840 DK to play as BLE multiple peripheral role x 4 and connect to 4 difference mobile phones.

Please leave the message to me if you would like to get such demo code.

Thanks for your interests on my blog. Since 2019, I have created this blog and shared the idea how to do some funny stuffs. I am very pleasure that I get quite a lot of positive feedback. I really hope that this blog helps your own embedded solution development. May I get support from you to keep it in order to maintain the wordpress host service? Your appreciation would be very helpful.


https://jimmywongiot.com/2021/05/26/asking-for-support/