一.测试的平台
本篇文章主要介绍将52840作为接收器,使用的工程为nRF5_SDK_15.2.0_9412b96\examples\ble_central\ble_app_uart_c\pca10056。
整个测试平台如下:
环境:win10,64位,MDK集成开发环境.
SDK:nRF5_SDK_15.2
协议栈:s132_nrf52_6.1_softdevice.hex.
USB参考工程: nRF5_SDK_15.2.0_9412b96\examples\peripheral\usbd_cdc_acm\pca10056.
硬件平台:pca10056开发板.
二.Application移植
1.USBD移植
(1)添加相关C文件
将app_usbd.c、app_usbd_core.c、app_usbd_serial_num.c、app_usbd_string_desc.c、app_usbd_cdc_acm.c、nrf_drv_usbd.c添加到工程中。
(2)添加头文件
(3)加入usb相关代码
在main.c中加入下面代码
①头文件和宏定义
#include "nrf.h"
#include "nrf_drv_usbd.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_power.h"
#include "app_usbd_core.h"
#include "app_usbd.h"
#include "app_usbd_string_desc.h"
#include "app_usbd_cdc_acm.h"
#include "app_usbd_serial_num.h"
#define LED_USB_RESUME (BSP_BOARD_LED_0)
#define LED_CDC_ACM_OPEN (BSP_BOARD_LED_1)
#define LED_CDC_ACM_RX (BSP_BOARD_LED_2)
#define LED_CDC_ACM_TX (BSP_BOARD_LED_3)
#define BTN_CDC_DATA_SEND 0
#define BTN_CDC_NOTIFY_SEND 1
#define BTN_CDC_DATA_KEY_RELEASE (bsp_event_t)(BSP_EVENT_KEY_LAST + 1)
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION true
#endif
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_cdc_acm_user_event_t event);
#define CDC_ACM_COMM_INTERFACE 0
#define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
#define CDC_ACM_DATA_INTERFACE 1
#define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
#define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
//APP_TIMER_DEF(m_blink_cdc);
#define LED_BLINK_INTERVAL 800
#define LED_CDC_ACM_CONN (BSP_BOARD_LED_2)
/**
* @brief CDC_ACM class instance
* */
APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm,
cdc_acm_user_ev_handler,
CDC_ACM_COMM_INTERFACE,
CDC_ACM_DATA_INTERFACE,
CDC_ACM_COMM_EPIN,
CDC_ACM_DATA_EPIN,
CDC_ACM_DATA_EPOUT,
APP_USBD_CDC_COMM_PROTOCOL_AT_V250
);
#define READ_SIZE 1
static char m_rx_buffer[READ_SIZE];
static char m_tx_buffer[NRF_DRV_USBD_EPSIZE];
②添加usb事件处理程序
static bool m_usb_connected = false;
static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_cdc_acm_user_event_t event)
{
app_usbd_cdc_acm_t const * p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
switch (event)
{
case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
{
//bsp_board_led_on(LED_CDC_ACM_OPEN);
/*Setup first transfer*/
ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
m_rx_buffer,
READ_SIZE);
UNUSED_VARIABLE(ret);
//ret = app_timer_stop(m_blink_cdc);
break;
}
case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
if (m_usb_connected)
{
// ret_code_t ret = app_timer_start(m_blink_cdc,
// APP_TIMER_TICKS(LED_BLINK_INTERVAL),
// (void *) LED_CDC_ACM_CONN);
//APP_ERROR_CHECK(ret);
}
//bsp_board_led_off(LED_CDC_ACM_OPEN);
break;
case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
//bsp_board_led_invert(LED_CDC_ACM_TX);
break;
case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
{
ret_code_t ret;
NRF_LOG_INFO("Bytes waiting: %d", app_usbd_cdc_acm_bytes_stored(p_cdc_acm));
do
{
/*Get amount of data transfered*/
size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
NRF_LOG_INFO("RX: size: %lu char: %c", size, m_rx_buffer[0]);
/* Fetch data until internal buffer is empty */
ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
m_rx_buffer,
READ_SIZE);
} while (ret == NRF_SUCCESS);
//bsp_board_led_invert(LED_CDC_ACM_RX);
break;
}
default:
break;
}
}
static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
switch (event)
{
case APP_USBD_EVT_DRV_SUSPEND:
//bsp_board_led_off(LED_USB_RESUME);
break;
case APP_USBD_EVT_DRV_RESUME:
//bsp_board_led_on(LED_USB_RESUME);
break;
case APP_USBD_EVT_STARTED:
break;
case APP_USBD_EVT_STOPPED:
app_usbd_disable();
//bsp_board_leds_off();
break;
case APP_USBD_EVT_POWER_DETECTED:
NRF_LOG_INFO("USB power detected");
if (!nrf_drv_usbd_is_enabled())
{
app_usbd_enable();
}
break;
case APP_USBD_EVT_POWER_REMOVED:
NRF_LOG_INFO("USB power removed");
//ret_code_t err_code = app_timer_stop(m_blink_cdc);
//bsp_board_led_off(LED_CDC_ACM_CONN);
m_usb_connected = false;
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
{
NRF_LOG_INFO("USB ready");
//ret_code_t err_code = app_timer_start(m_blink_cdc,
// APP_TIMER_TICKS(LED_BLINK_INTERVAL),
// (void *) LED_CDC_ACM_CONN);
m_usb_connected = true;
app_usbd_start();
}
break;
default:
break;
}
}
③在mian函数中添加初始化函数
et_code_t ret;
static const app_usbd_config_t usbd_config = {
.ev_state_proc = usbd_user_ev_handler
};
app_usbd_serial_num_generate();
ret = nrf_drv_clock_init();
ret = app_usbd_init(&usbd_config);
app_usbd_class_inst_t const * class_cdc_acm =app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
ret = app_usbd_class_append(class_cdc_acm);
// Initialize.
nrf_drv_clock_lfclk_request(NULL);
ret = app_usbd_power_events_enable();
while(1)
{
while (app_usbd_event_queue_process())
{
/* Nothing to do */
}
}
(4)修改sdk_config.h
使能电源控制
#ifndef NRFX_POWER_ENABLED
#define NRFX_POWER_ENABLED 1
#endif
#ifndef POWER_ENABLED
#define POWER_ENABLED 1
#endif
使能USB
#ifndef USBD_ENABLED
#define USBD_ENABLED 1
#endif
#ifndef APP_USBD_ENABLED
#define APP_USBD_ENABLED 1
#endif
#ifndef APP_USBD_VID
#define APP_USBD_VID 0x1915
#endif
#ifndef APP_USBD_PID
#define APP_USBD_PID 0x521A
#endif
#ifndef APP_USBD_STRING_SERIAL_EXTERN
#define APP_USBD_STRING_SERIAL_EXTERN 1
#endif
#ifndef APP_USBD_STRING_SERIAL
#define APP_USBD_STRING_SERIAL g_extern_serial_number
#endif
#ifndef APP_USBD_CDC_ACM_ENABLED
#define APP_USBD_CDC_ACM_ENABLED 1
#endif
(5)写指令
app_usbd_cdc_acm_write(&m_app_cdc_acm, p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
2.移植扫描程序
/**@brief Function for searching a given addr in the advertisement packets.
*
* @details Use this function to parse received advertising data and to find a given
* addr in them.
*
* @param[in] p_adv_report advertising data to parse.
* @param[in] p_addr name to search.
* @return true if the given name was found, false otherwise.
*/
static bool find_peer_addr(const ble_gap_evt_adv_report_t * p_adv_report,
const ble_gap_addr_t * p_addr)
{
if (p_addr->addr_type == p_adv_report->peer_addr.addr_type)
{
if (memcmp(p_addr->addr, p_adv_report->peer_addr.addr,
sizeof(p_adv_report->peer_addr.addr)) == 0)
{
return true;
}
}
return false;
}
static bool find_adv_name(const ble_gap_evt_adv_report_t * p_adv_report,const char * name_to_find)
{
uint32_t err_code;
uint8_array_t adv_data;
uint8_array_t dev_name;
adv_data.p_data = (uint8_t *)p_adv_report->data;
adv_data.size = p_adv_report->dlen;
err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,&adv_data,&dev_name);
if(err_code == NRF_SUCCESS)
{
if(memcmp(name_to_find,dev_name.p_data,dev_name.size)==0)
{
return true;
}
}
return false;
}
static bool find_adv_uuid(const ble_gap_evt_adv_report_t * p_adv_report,const uint16_t uuid_to_find)
{
uint32_t err_code;
uint8_array_t adv_data;
uint8_array_t type_data;
adv_data.p_data = (uint8_t *)p_adv_report->data;
adv_data.size = p_adv_report->dlen;
err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,&adv_data,&type_data);
if(err_code != NRF_SUCCESS)
{
err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,&adv_data,&type_data);
if(err_code != NRF_SUCCESS)
{
return false;
}
}
for(uint32_t u_index = 0;u_index < (type_data.size/sizeof(uint16_t));u_index++)
{
ble_uuid_t extraced_uuid;
//UUID16_EXTRACT(&extraced_uuid,&type_data.p_data[u_index * sizeof(uint16_t)]);
sd_ble_uuid_decode( UUID16_SIZE, &type_data.p_data[u_index * UUID16_SIZE], &extraced_uuid);
if (err_code == NRF_SUCCESS)
{
if (extraced_uuid.uuid == uuid_to_find)
{
return true;
}
}
}
return false;
}
/**@brief Function for handling the advertising report BLE event.
*
* @param[in] p_adv_report Advertising report from the SoftDevice.
*/
static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{
ret_code_t err_code;
bool do_connect = false;
if (is_connect_per_addr && find_peer_addr(p_adv_report, &m_target_periph_addr))
{
//NRF_LOG_INFO("Address match, send connect_request.");
do_connect = true;
}
else if (find_adv_name(p_adv_report,m_target_periph_name))
{
//NRF_LOG_INFO("Name match, send connect_request.");
do_connect = true;
printf("connect\n");
}
else if (find_adv_uuid(p_adv_report,m_nus_uuid.uuid))
{
//NRF_LOG_INFO("UUID match, send connect_request.");
do_connect = true;
}
if (do_connect)
{
// Stop scanning.
(void) sd_ble_gap_scan_stop();
//m_scan_params.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL;
// Initiate connection.
err_code = sd_ble_gap_connect(&p_adv_report->peer_addr,
&m_scan_params,
&m_connection_param);
//m_whitelist_disabled = false;
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Connection Request Failed, reason %d.", err_code);
}
}
else
{
err_code = sd_ble_gap_scan_start(&m_scan_params);
APP_ERROR_CHECK(err_code);
}
}
/**@brief Reads an advertising report and checks if a uuid is present in the service list.
*
* @details The function is able to search for 16-bit, 32-bit and 128-bit service uuids.
* To see the format of a advertisement packet, see
* https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm
*
* @param[in] p_target_uuid The uuid to search fir
* @param[in] p_adv_report Pointer to the advertisement report.
*
* @retval true if the UUID is present in the advertisement report. Otherwise false
*/
static bool is_uuid_present(const ble_uuid_t *p_target_uuid,
const ble_gap_evt_adv_report_t *p_adv_report)
{
uint32_t err_code;
uint32_t index = 0;
uint8_t *p_data = (uint8_t *)p_adv_report->data;
ble_uuid_t extracted_uuid;
while (index < p_adv_report->dlen)
{
uint8_t field_length = p_data[index];
uint8_t field_type = p_data[index+1];
if ( (field_type == BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE)
|| (field_type == BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE)
)
{
for (uint32_t u_index = 0; u_index < (field_length/UUID16_SIZE); u_index++)
{
err_code = sd_ble_uuid_decode( UUID16_SIZE,
&p_data[u_index * UUID16_SIZE + index + 2],
&extracted_uuid);
if (err_code == NRF_SUCCESS)
{
//printf("16extracted_uuid:%d\n",extracted_uuid.uuid);
//printf("extracted_uuid:%d\n",extracted_uuid.type);
#if 1
if ((extracted_uuid.uuid == p_target_uuid->uuid)
&& (extracted_uuid.type == p_target_uuid->type))
{
return true;
}
#else
if ((extracted_uuid.uuid == 0xfef5)
&& (extracted_uuid.type == 0x01))
{
return true;
}
#endif
}
}
}
else if ( (field_type == BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE)
|| (field_type == BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE)
)
{
for (uint32_t u_index = 0; u_index < (field_length/UUID32_SIZE); u_index++)
{
err_code = sd_ble_uuid_decode(UUID16_SIZE,
&p_data[u_index * UUID32_SIZE + index + 2],
&extracted_uuid);
if (err_code == NRF_SUCCESS)
{
printf("32extracted_uuid:%d\n",extracted_uuid.uuid);
printf("extracted_uuid:%d\n",extracted_uuid.type);
if ((extracted_uuid.uuid == p_target_uuid->uuid)
&& (extracted_uuid.type == p_target_uuid->type))
{
return true;
}
}
}
}
else if ( (field_type == BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE)
|| (field_type == BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE)
)
{
err_code = sd_ble_uuid_decode(UUID128_SIZE,
&p_data[index + 2],
&extracted_uuid);
if (err_code == NRF_SUCCESS)
{
printf("128extracted_uuid:%d\n",extracted_uuid.uuid);
printf("extracted_uuid:%d\n",extracted_uuid.type);
if ((extracted_uuid.uuid == p_target_uuid->uuid)
&& (extracted_uuid.type == p_target_uuid->type))
{
return true;
}
}
}
index += field_length + 1;
}
return false;
}
3.修改扫描服务UUID
根据设备的服务UUID,修改NUS_BASE_UUID,默认数值为
{{0xfb,0x34,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0XF0,0XFF,0x00,0x00}}
三.驱动安装
nRF5_SDK_15.2.0_9412b96\examples\usb_drivers