2025年5月31日 星期六 乙巳(蛇)年 三月初四 设为首页 加入收藏
rss
您当前的位置:首页 > 电子 > 无线/电,信号与通信

nRF52832 改变ATT_MTU提高蓝牙数据发送速率(nRF5_SDK_14.2.0)

时间:03-25来源:作者:点击数:71

nRF52832 作为一个低功耗蓝牙芯片,其数据发送发送速率一直都偏低(高就不叫低功耗了^_^),作为初学者在网上找了很多资料,终于找到通过修改ATT_MTU来提升发送速率的方法,最快能达到8.2KB/s,现在就分享出来

首先我用的协议栈是 nRF5_SDK_14.2.0 ,将\examples\ble_peripheral中的 ble_app_template 作为模板,以此进行修改

废话不说,先上代码,首先是定义

  • #define TIMER_INTERVALAPP_TIMER_TICKS(29) //定时器时间间隔
  • 1 BLE_NUS_DEF(m_nus); //加入串口服务结构(修改)
  • 2 BLE_CMD_DEF(m_cmd); //加入命令服务结构
  • 3 APP_TIMER_DEF(m_timer1); //定时器1
  • 4
  • 5 uint8_t hr_data[250];
  • 6 uint8_t cmd_data; //接收的命令
  • 7 bool send_state = false; //发送状态,默认不发送
  • 8
  • 9 static uint16_t length = 244;

主函数基本没修改,主要初始化了一组数据用来测试发送,加入了调度器,因为使用的定时器定时进行发送,而蓝牙发送不好放在中断里进行,定时器中断就做一个接发送函数放入调度器的操作。定义了一个全局数组,用来存放发送的数据。

  • 1 int main(void)
  • 2 {
  • 3 bool erase_bonds;
  • 4
  • 5 // Initialize.
  • 6 log_init();
  • 7 timers_init();
  • 8 buttons_leds_init(&erase_bonds);
  • 9 ble_stack_init();
  • 10 gap_params_init();
  • 11 gatt_init();
  • 12 advertising_init();
  • 13 services_init();
  • 14 conn_params_init();
  • 15 peer_manager_init();
  • 16
  • 17 // Start execution.
  • 18 NRF_LOG_INFO("Template example started.");
  • 19
  • 20 advertising_start(erase_bonds);
  • 21
  • 22 for(uint8_t i=0;i<250;i++) hr_data[i]=i; //初始化数据包
  • 23 SEGGER_RTT_printf(0, "\n");// 此处打印信息
  • 24
  • 25 APP_SCHED_INIT(20, 2); //初始化调度器
  • 26
  • 27 // Enter main loop.
  • 28 for (;;)
  • 29 {
  • 30 app_sched_execute(); //调度
  • 31
  • 32 if (NRF_LOG_PROCESS() == false)
  • 33 {
  • 34 power_manage();
  • 35 }
  • 36 }
  • 37 }

先看定时器

  • 1 static void timers_init(void)
  • 2 {
  • 3 // Initialize timer module.
  • 4 uint32_t err_code = app_timer_init();
  • 5 APP_ERROR_CHECK(err_code);
  • 6
  • 7 err_code = app_timer_create(&m_timer1, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
  • 8 APP_ERROR_CHECK(err_code);
  • 9 }

定时器中断服务函数

  • 1 void timer_timeout_handler(void * p_context)
  • 2 {
  • 3 if ( send_state == true )
  • 4 {
  • 5 hr_data[0]++;
  • 6 if(hr_data[0]>255) hr_data[0]=0; //改变第一个字节
  • 7 app_sched_event_put(NULL, 0, ble_nus_send); // 加入调度
  • 8 }
  • 9 }

蓝牙发送函数

  • 1 void ble_nus_send(void)
  • 2 {
  • 3 uint32_t err_code;
  • 4 do
  • 5 {
  • 6 err_code = ble_nus_string_send(&m_nus, hr_data, &length);
  • 7 if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) )
  • 8 {
  • 9 APP_ERROR_CHECK(err_code);
  • 10 }
  • 11 } while (err_code == NRF_ERROR_BUSY);
  • 12 }

接下来是蓝牙服务,这里我使用了两个自定义的服务,因为之前测试发送同一个串口服务进行收发的话,在连续接收数据时候,发送的命令会被堵塞,所以索性改了两个服务,分别用来收发,不知道大家有碰到过这种情况没,有的话欢迎一起交流交流。

  • 1 static void services_init(void)
  • 2 {
  • 3 uint32_t err_code;
  • 4 ble_nus_init_t nus_init;
  • 5 ble_cmd_init_t cmd_init;
  • 6
  • 7 /* 初始化串口服务 */
  • 8 memset(&nus_init, 0, sizeof(nus_init));
  • 9 err_code = ble_nus_init(&m_nus, &nus_init);
  • 10 APP_ERROR_CHECK(err_code);
  • 11
  • 12 /* 初始化自定义命令服务 */
  • 13 memset(&cmd_init, 0, sizeof(cmd_init));
  • 14 cmd_init.data_handler = cmd_data_handler; //命令处理函数
  • 15 err_code = ble_cmd_init(&m_cmd, &cmd_init);
  • 16 APP_ERROR_CHECK(err_code);
  • 17 }

命令数据处理函数,定义了一个全局变量,用来指示发送状态,根据接收的命令修改状态,以及开关定时器。

  • 1 static void cmd_data_handler(ble_cmd_evt_t * p_evt)
  • 2 {
  • 3 ret_code_t err_code;
  • 4 SEGGER_RTT_printf(0, "Receive a command\n");// 此处打印信息
  • 5 cmd_data = p_evt->params.rx_data.p_data[0]; //接收1个字节作为命令
  • 6
  • 7 switch ( cmd_data )
  • 8 {
  • 9 case BLE_STOP_CMD :
  • 10 send_state = false; //停止发送
  • 11 err_code = app_timer_stop(m_timer1); //停止定时器
  • 12 APP_ERROR_CHECK(err_code);
  • 13 break;
  • 14 case BLE_SEND_CMD :
  • 15 send_state = true; //允许发送
  • 16 err_code = app_timer_start(m_timer1, TIMER_INTERVAL, NULL); //启动定时器
  • 17 APP_ERROR_CHECK(err_code);
  • 18 break;
  • 19 default:
  • 20 SEGGER_RTT_printf(0, "Invalid command\n");// 此处打印信息
  • 21 break;
  • 22 }
  • 23 }

整个程序的框架基本上就是这样,通过蓝牙接收的命令打开定时器,定时器中断将发送函数加入调度,主循环轮转到发送时进行数据发送

通过修改 length 改变发送包的大小

通过修改TIMER_INTERVAL修改定时器时间

两者配合改变数据发送速率。

到了这里,就得修改ATT_MTU了,不然244个字节根本发不了,打开sdk_config.h

  • 1 // <h> nRF_SoftDevice
  • 2
  • 3 //==========================================================
  • 4 // <e> NRF_SDH_BLE_ENABLED - nrf_sdh_ble - SoftDevice BLE event handler
  • 5 //==========================================================
  • 6 #ifndef NRF_SDH_BLE_ENABLED
  • 7 #define NRF_SDH_BLE_ENABLED 1
  • 8 #endif
  • 9 // <h> BLE Stack configuration - Stack configuration parameters
  • 10
  • 11 // <i> These values are not used directly by the SoftDevice handler but the application or other libraries might depend on them.
  • 12 // <i> Keep them up-to-date with the desired configuration.
  • 13 //==========================================================
  • 14 // <o> NRF_SDH_BLE_PERIPHERAL_LINK_COUNT - Maximum number of peripheral links.
  • 15 #ifndef NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
  • 16 #define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1
  • 17 #endif
  • 18
  • 19 // <o> NRF_SDH_BLE_CENTRAL_LINK_COUNT - Maximum number of central links.
  • 20 #ifndef NRF_SDH_BLE_CENTRAL_LINK_COUNT
  • 21 #define NRF_SDH_BLE_CENTRAL_LINK_COUNT 0
  • 22 #endif
  • 23
  • 24 // <o> NRF_SDH_BLE_TOTAL_LINK_COUNT - Maximum number of total concurrent connections using the default configuration.
  • 25 #ifndef NRF_SDH_BLE_TOTAL_LINK_COUNT
  • 26 #define NRF_SDH_BLE_TOTAL_LINK_COUNT 1
  • 27 #endif
  • 28
  • 29 // <o> NRF_SDH_BLE_GAP_EVENT_LENGTH - The time set aside for this connection on every connection interval in 1.25 ms units.
  • 30 #ifndef NRF_SDH_BLE_GAP_EVENT_LENGTH
  • 31 #define NRF_SDH_BLE_GAP_EVENT_LENGTH 8 //默认值3
  • 32 #endif
  • 33
  • 34 // <o> NRF_SDH_BLE_GATT_MAX_MTU_SIZE - Static maximum MTU size.
  • 35 #ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE
  • 36 #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247 //默认值23
  • 37 #endif
  • 38
  • 39 // <o> NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE - Attribute Table size in bytes. The size must be a multiple of 4.
  • 40 #ifndef NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE
  • 41 #define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1408
  • 42 #endif
  • 43
  • 44 // <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs.
  • 45 #ifndef NRF_SDH_BLE_VS_UUID_COUNT
  • 46 #define NRF_SDH_BLE_VS_UUID_COUNT 1 //默认为0
  • 47 #endif

这里修改了3个地方,

NRF_SDH_BLE_GAP_EVENT_LENGTH 这个是每个间隔预留给连接的时间

NRF_SDH_BLE_GATT_MAX_MTU_SIZE 这个就是最大MTU了

NRF_SDH_BLE_VS_UUID_COUNT 这个因为我加了两个自定义服务,所以也要改成1

接下来通过修改 length 和 TIMER_INTERVAL 编译下载后来测试速率了

注意的是,因为修改过NRF_SDH_BLE_GATT_MAX_MTU_SIZE,所以RAM的地址会发生改变,打开sdk_config.h,修改

  • 1 //==========================================================
  • 2 // <e> NRF_LOG_ENABLED - Logging module for nRF5 SDK
  • 3 //==========================================================
  • 4 #ifndef NRF_LOG_ENABLED
  • 5 #define NRF_LOG_ENABLED 1
  • 6 #endif
  • 1 //==========================================================
  • 2 // <e> NRF_LOG_BACKEND_RTT_ENABLED - nrf_log_backend_rtt - Log RTT backend
  • 3 //==========================================================
  • 4 #ifndef NRF_LOG_BACKEND_RTT_ENABLED
  • 5 #define NRF_LOG_BACKEND_RTT_ENABLED 1
  • 6 #endif

这样就可以通过RTT打印的信息来调整RAM的地址和大小了

再次编译,下载,没问题后,在andorid手机上使用 ‘nRF Connect’ 进行调试

附上我的测试图片

数据显示

这里使用的就是每29ms发送一次,每次发送244字节,通过计算,(1000/29)*244 = 8413byte 约 8.2KB/s ,这是我目前测出的最大传输速率,但是不停稳定,超出一米的距离基本就会失去连接,另外连接间隔我也有修改

  • 1 #define MIN_CONN_INTERVAL MSEC_TO_UNITS(8, UNIT_1_25_MS)
  • 2 #define MAX_CONN_INTERVAL MSEC_TO_UNITS(12, UNIT_1_25_MS)
  • 3 #define SLAVE_LATENCY 0
  • 4 #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)

因为初次接触蓝牙,这方面不是太懂,可能写的不是太好,欢迎指正,或者有测出更高速率的朋友也可以一起交流下

对于改变MTU为什么会提高发送速率,我抓包分析了一下

从机接收到命令开始发数据

第一个包,可以看出数据只发送到0x13,也就是20个字节

第二个包,从0x14 发送到了0x2e, 也就是27个字节

第三个包,从0x2f 到0x49, 也是27个字节

也就是说,通过修改MTU后,每次发送从第二个包开始都可以达到每个包27个字节,这样一来自然就会比之前限定的每次只能发20个字节要快一点了。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门