【瑞萨BLE/WIFI模块测评】5、DA14531蓝牙模块数据接收
开发套件中的DA14531模块,实现蓝牙串口数据的透传,DA14531模块连接到开发板的PMOD2接口上,串口发送的数据,由DA14531模块通过蓝牙GATT服务发送蓝牙接收端,比如瑞萨推出的SmartBond App。
# 1、硬件连接
查看开发板和DA14531模块的原理图,
!(//m.qjumbo.com/forum/data/attachment/forum/202610/07/153800m39al038ev9lhy3h.png)
|DA14531模块引脚|MCU引脚|
|----|----|
|RXD|P411|
|TXD|P410|
|CONNECT|P414|
|LPR|P609|
使用DA14531模块时,需要将LPR引脚设置为GPIO Output高电平,将模块退出低功耗模式。
!(//m.qjumbo.com/forum/data/attachment/forum/202610/07/153811zo7uyf7yzprps7pp.png)
AT指令通过串口传输到DA14531模块,串口的配置参数如下
!(//m.qjumbo.com/forum/data/attachment/forum/202610/07/153817gcgjszqqb7csrbz7.png)
保存并生成配置代码。
# 2、模块驱动代码
定义BLE模块传输相关的宏定义、数据结构体以及变量和函数声明如下。
```c
#include "hal_data.h"
#include <stdbool.h>
#include <stdint.h>
#define BLE_IDENTITY_RESULT_AT (1UL << 0)
#define BLE_IDENTITY_RESULT_VERSION(1UL << 1)
#define BLE_IDENTITY_RESULT_NAME (1UL << 2)
#define BLE_IDENTITY_RESULT_MAC (1UL << 3)
#define BLE_IDENTITY_RESULT_ALL (BLE_IDENTITY_RESULT_AT | \
BLE_IDENTITY_RESULT_VERSION | \
BLE_IDENTITY_RESULT_NAME | \
BLE_IDENTITY_RESULT_MAC)
#define BLE_IDENTITY_RESPONSE_SIZE (64U)
typedef enum e_ble_transport_mode
{
BLE_TRANSPORT_MODE_BOOT = 0,
BLE_TRANSPORT_MODE_AT,
BLE_TRANSPORT_MODE_TRANSPARENT,
} ble_transport_mode_t;
/* Driver state and counters intended for debugger inspection. */
extern volatile ble_transport_mode_t g_ble_mode;
extern volatile bool g_ble_connected;
extern volatile uint32_t g_ble_connection_change_count;
extern volatile uart_event_t g_ble_last_uart_event;
extern volatile uint32_t g_ble_uart_error_flags;
extern volatile fsp_err_t g_ble_last_error;
extern volatile uint32_t g_ble_rx_total;
extern volatile uint32_t g_ble_tx_total;
extern volatile uint32_t g_ble_rx_overflow_count;
extern volatile uint32_t g_ble_tx_overflow_count;
extern volatile uint32_t g_ble_at_timeout_count;
extern volatile uint32_t g_ble_command_success_mask;
extern volatile char g_ble_at_response;
extern volatile char g_ble_version_response;
extern volatile char g_ble_name_response;
extern volatile char g_ble_mac_response;
extern volatile uint32_t g_ble_at_response_length;
extern volatile uint32_t g_ble_version_response_length;
extern volatile uint32_t g_ble_name_response_length;
extern volatile uint32_t g_ble_mac_response_length;
fsp_err_t ble_transport_init(void);
void ble_transport_poll(void);
bool ble_transport_is_connected(void);
uint32_tble_transport_read(uint8_t * p_destination, uint32_t destination_size);
uint32_tble_transport_write(uint8_t const * p_source, uint32_t length);
uint32_tble_transport_rx_available(void);
bool ble_get_byte(uint8_t *b); /* 从BLE缓存区读取1字节 */
```
BLE模块的驱动代码如下
```c
#include "ble_transport.h"
#define BLE_RING_BUFFER_SIZE (256U)
#define BLE_RING_BUFFER_MASK (BLE_RING_BUFFER_SIZE - 1U)
#define BLE_UART_TX_CHUNK_SIZE (64U)
#define BLE_AT_RX_BUFFER_SIZE (128U)
#define BLE_MODULE_BOOT_DELAY_MS (1000U)
#define BLE_AT_RESPONSE_TIMEOUT_MS(1000U)
#define BLE_AT_RESPONSE_QUIET_MS (30U)
#define BLE_UART_TX_TIMEOUT_MS (500U)
#if (0U != (BLE_RING_BUFFER_SIZE & BLE_RING_BUFFER_MASK))
#error "BLE_RING_BUFFER_SIZE must be a power of two."
#endif
volatile ble_transport_mode_t g_ble_mode = BLE_TRANSPORT_MODE_BOOT;
volatile bool g_ble_connected = false;
volatile uint32_t g_ble_connection_change_count = 0U;
volatile uart_event_t g_ble_last_uart_event = (uart_event_t) 0U;
volatile uint32_t g_ble_uart_error_flags = 0U;
volatile fsp_err_t g_ble_last_error = FSP_SUCCESS;
volatile uint32_t g_ble_rx_total = 0U;
volatile uint32_t g_ble_tx_total = 0U;
volatile uint32_t g_ble_rx_overflow_count = 0U;
volatile uint32_t g_ble_tx_overflow_count = 0U;
volatile uint32_t g_ble_at_timeout_count = 0U;
volatile uint32_t g_ble_command_success_mask = 0U;
volatile char g_ble_at_response = {0};
volatile char g_ble_version_response = {0};
volatile char g_ble_name_response = {0};
volatile char g_ble_mac_response = {0};
volatile uint32_t g_ble_at_response_length = 0U;
volatile uint32_t g_ble_version_response_length = 0U;
volatile uint32_t g_ble_name_response_length = 0U;
volatile uint32_t g_ble_mac_response_length = 0U;
static volatile uint8_tg_rx_ring;
static volatile uint32_t g_rx_head = 0U;
static volatile uint32_t g_rx_tail = 0U;
static volatile uint8_tg_tx_ring;
static volatile uint32_t g_tx_head = 0U;
static volatile uint32_t g_tx_tail = 0U;
static volatile uint8_tg_at_rx_buffer;
static volatile uint32_t g_at_rx_length = 0U;
static volatile bool g_uart_tx_complete = false;
static volatile bool g_uart_tx_busy = false;
static volatile uint32_t g_uart_tx_active_length = 0U;
static uint8_t g_uart_tx_chunk;
static uint8_t const g_at_test_command[] = "AT?\r\n";
static uint8_t const g_at_version_command[] = "AT+VER?\r\n";
static uint8_t const g_at_name_command[] = "AT+NAME?\r\n";
static uint8_t const g_at_mac_command[] = "AT+MAC?\r\n";
static void ble_rx_ring_push(uint8_t data)
{
uint32_t const head = g_rx_head;
uint32_t const next = (head + 1U) & BLE_RING_BUFFER_MASK;
if (next != g_rx_tail)
{
g_rx_ring = data;
g_rx_head = next;
g_ble_rx_total++;
}
else
{
g_ble_rx_overflow_count++;
}
}
static void ble_at_rx_clear(void)
{
g_at_rx_length = 0U;
g_at_rx_buffer = 0U;
}
void ble_uart_callback(uart_callback_args_t * p_args)
{
if (NULL == p_args)
{
return;
}
g_ble_last_uart_event = p_args->event;
if (UART_EVENT_RX_CHAR == p_args->event)
{
uint8_t const data = (uint8_t) p_args->data;
if (BLE_TRANSPORT_MODE_AT == g_ble_mode)
{
uint32_t const index = g_at_rx_length;
if (index < (BLE_AT_RX_BUFFER_SIZE - 1U))
{
g_at_rx_buffer = data;
g_at_rx_length = index + 1U;
g_at_rx_buffer = 0U;
}
else
{
g_ble_rx_overflow_count++;
}
}
else if (BLE_TRANSPORT_MODE_TRANSPARENT == g_ble_mode)
{
ble_rx_ring_push(data);
}
else
{
/* Ignore bytes received before the driver has selected a mode. */
}
}
else if (UART_EVENT_TX_COMPLETE == p_args->event)
{
g_uart_tx_complete = true;
if ((BLE_TRANSPORT_MODE_TRANSPARENT == g_ble_mode) && g_uart_tx_busy)
{
g_ble_tx_total += g_uart_tx_active_length;
g_uart_tx_active_length= 0U;
g_uart_tx_busy = false;
}
}
else if ((UART_EVENT_ERR_PARITY == p_args->event) ||
(UART_EVENT_ERR_FRAMING == p_args->event) ||
(UART_EVENT_ERR_OVERFLOW == p_args->event) ||
(UART_EVENT_BREAK_DETECT == p_args->event))
{
g_ble_uart_error_flags |= (uint32_t) p_args->event;
}
else
{
/* No action is required for the remaining UART events. */
}
}
static bool ble_at_wait_for_response(void)
{
uint32_t last_length = 0U;
uint32_t quiet_ms = 0U;
for (uint32_t elapsed_ms = 0U; elapsed_ms < BLE_AT_RESPONSE_TIMEOUT_MS; elapsed_ms++)
{
uint32_t const current_length = g_at_rx_length;
if (current_length != last_length)
{
last_length = current_length;
quiet_ms = 0U;
}
else if (current_length > 0U)
{
quiet_ms++;
if (quiet_ms >= BLE_AT_RESPONSE_QUIET_MS)
{
return true;
}
}
else
{
/* Still waiting for the first response byte. */
}
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
}
return (g_at_rx_length > 0U);
}
static uint32_t ble_at_copy_response(volatile char * p_destination, uint32_t destination_size)
{
uint32_t length = g_at_rx_length;
if (length >= destination_size)
{
length = destination_size - 1U;
}
for (uint32_t i = 0U; i < length; i++)
{
p_destination = (char) g_at_rx_buffer;
}
p_destination = '\0';
return length;
}
static bool ble_at_execute(uint8_t const * p_command,
uint32_t command_length,
volatile char * p_response,
uint32_t response_size,
volatile uint32_t * p_response_length,
uint32_t result_bit)
{
ble_at_rx_clear();
g_uart_tx_complete = false;
fsp_err_t const err = R_SCI_UART_Write(&g_uart0_ctrl, p_command, command_length);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
*p_response_length = 0U;
p_response = '\0';
return false;
}
for (uint32_t elapsed_ms = 0U;
(elapsed_ms < BLE_UART_TX_TIMEOUT_MS) && !g_uart_tx_complete;
elapsed_ms++)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
}
if (!g_uart_tx_complete)
{
g_ble_last_error = FSP_ERR_TIMEOUT;
g_ble_at_timeout_count++;
*p_response_length = 0U;
p_response = '\0';
return false;
}
bool const response_received = ble_at_wait_for_response();
*p_response_length = ble_at_copy_response(p_response, response_size);
if (response_received)
{
g_ble_command_success_mask |= result_bit;
}
else
{
g_ble_at_timeout_count++;
}
R_BSP_SoftwareDelay(50U, BSP_DELAY_UNITS_MILLISECONDS);
return response_received;
}
static void ble_transport_update_connection(void)
{
bsp_io_level_t level = BSP_IO_LEVEL_LOW;
fsp_err_t const err = R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_14, &level);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
return;
}
bool const connected = (BSP_IO_LEVEL_HIGH == level);
if (connected != g_ble_connected)
{
g_ble_connected = connected;
g_ble_connection_change_count++;
if (!connected)
{
/* Do not transmit stale application data after the next connection. */
g_tx_tail = g_tx_head;
}
}
}
fsp_err_t ble_transport_init(void)
{
fsp_err_t err;
g_ble_mode = BLE_TRANSPORT_MODE_BOOT;
g_ble_connected = false;
g_ble_connection_change_count = 0U;
g_ble_last_error = FSP_SUCCESS;
g_ble_uart_error_flags = 0U;
g_ble_rx_total = 0U;
g_ble_tx_total = 0U;
g_ble_rx_overflow_count = 0U;
g_ble_tx_overflow_count = 0U;
g_ble_at_timeout_count = 0U;
g_ble_command_success_mask = 0U;
g_rx_head = 0U;
g_rx_tail = 0U;
g_tx_head = 0U;
g_tx_tail = 0U;
g_uart_tx_busy = false;
g_uart_tx_active_length = 0U;
/* PMOD2 pin 9: DA14531 LPR. A high level enables the module UART. */
err = R_IOPORT_PinCfg(&g_ioport_ctrl,
BSP_IO_PORT_06_PIN_09,
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
return err;
}
/* PMOD2 pin 7: DA14531 CONNECT. The module drives it high while BLE is connected. */
err = R_IOPORT_PinCfg(&g_ioport_ctrl,
BSP_IO_PORT_04_PIN_14,
IOPORT_CFG_PORT_DIRECTION_INPUT);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
return err;
}
err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
return err;
}
g_ble_mode = BLE_TRANSPORT_MODE_AT;
R_BSP_SoftwareDelay(BLE_MODULE_BOOT_DELAY_MS, BSP_DELAY_UNITS_MILLISECONDS);
/* Discard the optional boot banner and read the module identity. */
ble_at_rx_clear();
(void) ble_at_execute(g_at_test_command,
(uint32_t) (sizeof(g_at_test_command) - 1U),
g_ble_at_response,
BLE_IDENTITY_RESPONSE_SIZE,
&g_ble_at_response_length,
BLE_IDENTITY_RESULT_AT);
(void) ble_at_execute(g_at_version_command,
(uint32_t) (sizeof(g_at_version_command) - 1U),
g_ble_version_response,
BLE_IDENTITY_RESPONSE_SIZE,
&g_ble_version_response_length,
BLE_IDENTITY_RESULT_VERSION);
(void) ble_at_execute(g_at_name_command,
(uint32_t) (sizeof(g_at_name_command) - 1U),
g_ble_name_response,
BLE_IDENTITY_RESPONSE_SIZE,
&g_ble_name_response_length,
BLE_IDENTITY_RESULT_NAME);
(void) ble_at_execute(g_at_mac_command,
(uint32_t) (sizeof(g_at_mac_command) - 1U),
g_ble_mac_response,
BLE_IDENTITY_RESPONSE_SIZE,
&g_ble_mac_response_length,
BLE_IDENTITY_RESULT_MAC);
g_rx_head= 0U;
g_rx_tail= 0U;
g_ble_mode = BLE_TRANSPORT_MODE_TRANSPARENT;
ble_transport_update_connection();
return FSP_SUCCESS;
}
uint32_t ble_transport_rx_available(void)
{
return (g_rx_head - g_rx_tail) & BLE_RING_BUFFER_MASK;
}
uint32_t ble_transport_read(uint8_t * p_destination, uint32_t destination_size)
{
if ((NULL == p_destination) || (0U == destination_size))
{
return 0U;
}
uint32_t count = 0U;
while ((count < destination_size) && (g_rx_tail != g_rx_head))
{
uint32_t const tail = g_rx_tail;
p_destination = g_rx_ring;
g_rx_tail = (tail + 1U) & BLE_RING_BUFFER_MASK;
count++;
}
return count;
}
static inline bool ble_buffer_get(uint8_t *b) {
if (g_rx_head == g_rx_tail) return false; /* empty */
*b = g_rx_ring;
g_rx_tail = (g_rx_tail + 1) & BLE_RING_BUFFER_MASK;
return true;
}
bool ble_get_byte(uint8_t *b) /* 从g_rx_ring取1字节 */
{
return ble_buffer_get(b);
}
uint32_t ble_transport_write(uint8_t const * p_source, uint32_t length)
{
if ((NULL == p_source) || (0U == length) || !g_ble_connected)
{
return 0U;
}
uint32_t queued = 0U;
while (queued < length)
{
uint32_t const head = g_tx_head;
uint32_t const next = (head + 1U) & BLE_RING_BUFFER_MASK;
if (next == g_tx_tail)
{
break;
}
g_tx_ring = p_source;
g_tx_head = next;
queued++;
}
g_ble_tx_overflow_count += length - queued;
return queued;
}
static void ble_transport_start_next_tx(void)
{
if (g_uart_tx_busy || !g_ble_connected || (g_tx_tail == g_tx_head))
{
return;
}
uint32_t length = 0U;
while ((length < BLE_UART_TX_CHUNK_SIZE) && (g_tx_tail != g_tx_head))
{
uint32_t const tail = g_tx_tail;
g_uart_tx_chunk = g_tx_ring;
g_tx_tail = (tail + 1U) & BLE_RING_BUFFER_MASK;
length++;
}
g_uart_tx_active_length = length;
g_uart_tx_complete = false;
g_uart_tx_busy = true;
fsp_err_t const err = R_SCI_UART_Write(&g_uart0_ctrl, g_uart_tx_chunk, length);
if (FSP_SUCCESS != err)
{
g_ble_last_error = err;
g_ble_tx_overflow_count += length;
g_uart_tx_active_length= 0U;
g_uart_tx_busy = false;
}
}
void ble_transport_poll(void)
{
ble_transport_update_connection();
ble_transport_start_next_tx();
}
bool ble_transport_is_connected(void)
{
return g_ble_connected;
}
```
# 3、DA14531模块数据Echo
以下代码实现接收DA14531模块的初始化,通过检测Connect引脚的状态判断模块是否与手机APP连接,接收来自DA14531的数据并将接收的数据发送给手机APP显示。
```c
#include "hal_data.h"
#include "ble_transport.h"
#include <stdbool.h>
#include "common_utils.h"
/*
* RAECO4M2 V2.0 + DA14531 application bring-up.
*
* LED1: P405, active high.
* BLE UART: SCI0, P411/TXD0, P410/RXD0, 115200 8N1.
* BLE LPR: P609, output high.
* BLE CONNECT: P414, input; high while a phone is connected.
*
* The application echoes every byte received from the phone back through the
* DA14531. Enable notifications for CodeLess Outbound Command in SmartBond.
*/
typedef enum e_diagnostic_reason
{
DIAGNOSTIC_REASON_NONE = 0,
DIAGNOSTIC_REASON_LED_PIN_CFG = 1,
DIAGNOSTIC_REASON_CPU_EXCEPTION = 2,
DIAGNOSTIC_REASON_BLE_INIT = 3,
} diagnostic_reason_t;
#define APP_ECHO_BUFFER_SIZE (64U)
#define APP_LED_BLINK_MS (500U)
volatile diagnostic_reason_t g_diagnostic_reason = DIAGNOSTIC_REASON_NONE;
volatile fsp_err_t g_diagnostic_error= FSP_SUCCESS;
volatile uint32_t g_fault_exception = 0U;
volatile uint32_t g_fault_cfsr = 0U;
volatile uint32_t g_fault_hfsr = 0U;
volatile uint32_t g_fault_dfsr = 0U;
volatile uint32_t g_fault_mmfar = 0U;
volatile uint32_t g_fault_bfar = 0U;
/* Application state intended for debugger inspection. */
volatile bool g_app_ble_identity_ok = false;
volatile bool g_app_ble_connected = false;
volatile uint8_tg_app_last_rx_data = {0U};
volatile uint32_t g_app_last_rx_length = 0U;
volatile uint32_t g_app_rx_message_count = 0U;
volatile uint32_t g_app_echo_queued_total = 0U;
volatile uint32_t g_app_echo_dropped_total = 0U;
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SecureFault_Handler(void);
static void diagnostic_stop(diagnostic_reason_t reason, fsp_err_t error)
{
g_diagnostic_reason = reason;
g_diagnostic_error= error;
if (0U != (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk))
{
__BKPT(0);
}
while (1)
{
__NOP();
}
}
static void cpu_exception_stop(void)
{
g_fault_exception = SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk;
g_fault_cfsr = SCB->CFSR;
g_fault_hfsr = SCB->HFSR;
g_fault_dfsr = SCB->DFSR;
g_fault_mmfar = SCB->MMFAR;
g_fault_bfar = SCB->BFAR;
diagnostic_stop(DIAGNOSTIC_REASON_CPU_EXCEPTION, FSP_ERR_ASSERTION);
}
void HardFault_Handler(void)
{
cpu_exception_stop();
}
void MemManage_Handler(void)
{
cpu_exception_stop();
}
void BusFault_Handler(void)
{
cpu_exception_stop();
}
void UsageFault_Handler(void)
{
cpu_exception_stop();
}
void SecureFault_Handler(void)
{
cpu_exception_stop();
}
void hal_entry(void)
{
fsp_err_t err;
uint8_t echo_buffer;
bool led_level = false;
uint32_tled_elapsed_ms = 0U;
/* IOPORT is opened by R_BSP_WarmStart() before main() is called. */
err = R_IOPORT_PinCfg(&g_ioport_ctrl,
BSP_IO_PORT_04_PIN_05,
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_LOW);
if (FSP_SUCCESS != err)
{
diagnostic_stop(DIAGNOSTIC_REASON_LED_PIN_CFG, err);
}
err = ble_transport_init();
if (FSP_SUCCESS != err)
{
diagnostic_stop(DIAGNOSTIC_REASON_BLE_INIT, err);
}
g_app_ble_identity_ok = (BLE_IDENTITY_RESULT_ALL == g_ble_command_success_mask);
while (1)
{
ble_transport_poll();
g_app_ble_connected = ble_transport_is_connected();
uint32_t const received = ble_transport_read(echo_buffer, sizeof(echo_buffer));
if (received > 0U)
{
for (uint32_t i = 0U; i < received; i++)
{
g_app_last_rx_data = echo_buffer;
}
g_app_last_rx_data = 0U;
g_app_last_rx_length = received;
g_app_rx_message_count++;
uint32_t const queued = ble_transport_write(echo_buffer, received);
g_app_echo_queued_total+= queued;
g_app_echo_dropped_total += received - queued;
}
if (g_app_ble_connected)
{
led_level = true;
led_elapsed_ms = 0U;
}
else
{
led_elapsed_ms++;
if (led_elapsed_ms >= APP_LED_BLINK_MS)
{
led_elapsed_ms = 0U;
led_level = !led_level;
}
}
(void) R_IOPORT_PinWrite(&g_ioport_ctrl,
BSP_IO_PORT_04_PIN_05,
led_level ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
}
}
```
在手机上运行SmartConfig软件,通过其中的Codeless Inbound GATT发送数据,在Codeless Outbound GATT接收数据,通过发送和接收的数据对比,确认程序功能实现正常。
!(//m.qjumbo.com/forum/data/attachment/forum/202610/07/153846qkkzgiupzgpgiduq.png)
页:
[1]