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


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

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

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

    #define TIMER_INTERVAL        APP_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, "
    ");// 此处打印信息
    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
    ");// 此处打印信息
     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
    ");// 此处打印信息
    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个字节要快一点了。

     先写到这里吧,如果有什么写的不对的,欢迎大家指正,后面还需要测试稳定性,距离,功耗,还好实际上也不需要用到8K的传输速率,还需要深入的学习BLE,加油!

  • 相关阅读:
    如何将asp.net MVC2项目升级为MVC3项目(微软官方自动升级工具:ASP.NET MVC 3 Application Upgrader )
    扩展Html Helper类,ASP.NET MVC框架提供了一个帮助我们构造Html元素的类:TagBuilder
    详解ASP.NET MVC2项目升级到MVC 3 RC
    NHibernate学习
    ASP.MVCNOTE
    MVC问题反馈页面代码
    Silverlightnote
    jqGrid
    必须掌握的八个DOS命令
    分页且带条件的存储过程
  • 原文地址:https://www.cnblogs.com/jiangjiu/p/10063556.html
Copyright © 2020-2023  润新知