This is tutorial is not intended to be a guide for learning C language or about the Nordic SDK platform. It’s primary target is to provide developers a concise guide about integrating peripheral modules and features into active applications.
If you are a beginner, I would recommend you look into an nRF52 Project Setup guide like this one.
Another easy way to get started with coding, without bothering with all basic stuff like files and driver inclusion, check out this Code Generation Tool
nrf52 Code Generator: https://vicara.co/nrf52-code-generator
In nRF52 devices, the BLE data is received and parsed as an UART transceiver port. Thus, to enable BLE communication, we will need to use a NUS (Nordic UART Service) module.
In the following section, I will provide a guide as it has been tested in the nRF52832 Dev Kit. However, the same structure will remain common across all nRF52 devices.
Include the SPI Driver files. This file should be titled, ble_nus.cUpdate sdk_config.h File
#include "ble_nus.h"Connection Status Check Variablebool is_ble_connected;
static uint16_t check_nus_rx_data_available(void); // -> Returns an uint16 with the number of bytes of data available in the RX bufferstatic void get_nus_data(uint8_t *buf, uint16_t len); // -> len number of received bytes copied to bufstatic void send_nus_data(uint8_t *buf, uint16_t size); // -> Sends an array of uint8/* ************* API Functions ************** */
staticuint16_tcheck_nus_rx_data_available(void)
{
return nus_buffer.head;
}
//VCE: Function to get data from NUS RX buffer
staticvoidget_nus_data(uint8_t *buf, uint16_t len)
{
if(len < NUS_BUFFER_LENGTH)
{
memcpy(buf, nus_buffer.buffer, len);
memset(nus_buffer.buffer, 0, NUS_BUFFER_LENGTH);
}
}
staticvoidsend_nus_data(uint8_t *buf, uint16_t size)
{
ble_nus_data_send(&m_nus, buf, &size, m_conn_handle);
}
#define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service (vendor specific). */
BLE_NUS_DEF (m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT);
staticuint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
#define NUS_BUFFER_LENGTH 512
BUFFER(nus, NUS_BUFFER_LENGTH);
/**@brief Function for handling the data from the Nordic UART Service.
*
* @details This function will process the data received from the Nordic UART BLE Service and send
* it to the UART module.
*
* @param[in] p_evt Nordic UART Service event.
*//**@snippet [Handling the data received over BLE] */
staticvoidnus_data_handler(ble_nus_evt_t * p_evt)
{
if (p_evt->type == BLE_NUS_EVT_RX_DATA)
{
uint32_t err_code;
NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
if(NUS_BUFFER_LENGTH - nus_buffer.head >= p_evt->params.rx_data.length)
{
memcpy(&nus_buffer.buffer[nus_buffer.head], p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
nus_buffer.head += p_evt->params.rx_data.length;
}
elseif(NUS_BUFFER_LENGTH > p_evt->params.rx_data.length)
{
memset(nus_buffer.buffer, 0, NUS_BUFFER_LENGTH);
memcpy(nus_buffer.buffer, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
nus_buffer.head = p_evt->params.rx_data.length;
}
}
}
/**@brief Function for initializing services that will be used by the application.
*/
staticvoidservices_init(void)
{
ret_code_t err_code;
nrf_ble_qwr_init_t qwr_init = {0};
// Initialize Queued Write Module.
qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
// VCE: Initialize NUS.
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
}
Note: The existing gatt_init function needs to be replaced with the below one. gatt_evt_handler also needs to be added
/**@brief Function for handling events from the GATT library. */
voidgatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_tconst * p_evt)
{
if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
{
m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
}
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph);
}
/**@brief Function for initializing the GATT module.
*/
staticvoidgatt_init(void)
{
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
APP_ERROR_CHECK(err_code);
}
services_init();
With the above steps anyone can easily get started with BLE.
There is another easier method to initialize and auto-generate code for nRF52. This tool, will handle all library additions and code generations for a variety of peripherals like SPI, I2C, UART etc.
Link: https://vicara.co/nrf52-code-generator