PHY update problems?

Hi

I am using the nRF54L15 DK and build a thread continueing monitor the data rate in 1 Hz, if it is lower to 800kbps I want to change to 1M; while above 800kbps I want to change to 2M. My code is:

int desired_phy = (avg_rate > 800000.0f) ? 2 : 1;

            if (desired_phy != last_phy) {
                struct bt_conn_le_phy_param *phy = 
                    (desired_phy == 2) ? &phy_2m : &phy_1m;
                int phy_err = bt_conn_le_phy_update(default_conn, phy);
                if (phy_err) {
                    LOG_WRN("PHY update failed (%d)", phy_err);
                } else {
                    last_phy = desired_phy;
                    LOG_INF("Switched to %dM PHY", desired_phy);
                }
            }

However, the error shows:

 [00:00:44.038,989] <wrn> bt_hci_core: opcode 0x2032 status 0x3a 
00> [00:00:44.039,003] <wrn> central_uart: PHY update failed (-5)
00> [00:00:44.039,009] <inf> central_uart: RXRX  = -18

Could you give me some advice?

Parents
  • Hi,

    0x3A is "Controller Busy", which indicates the BLE Controller is busy. How often are you attempting to change PHY? I suggest that you wait at least for a few seconds. I also suggest that you let the connection stabilize before you start to gather throughput statistics.

    You could also consider to not switch back and forth on the same value, but instead add some hysteresis to the system. (That is, for instance change to 1M if the rate drops below 700 and change to 2M if the rate goes above 900.)

    In any case, selecting PHY this way might or might not be a good idea. I think a better approach would be to use RSSI as an indicator of the link quality, and select PHY based on that. You could potentially also take packet loss rate into account. Regardless of method, make sure not to change PHY too often, and perform the measurements on a stable link (to not include in measurements the downtime for changing PHY or other parameters.)

    Regards,
    Terje

  • Hi

    Thank you for your reply! I have tried to update PHY and wait for 5 seconds, it still cannot work. I have set up a new thread and my code is:

    void modulate_tx_power(void *p1, void *p2, void *p3)
    {
    	int8_t txp_get = 0;
        uint8_t idx = 0;
        int8_t rssi = 0xFF;
        static float rate[5] = {0}; 
        static uint8_t history_index = 0;
        static float avg_rate = 0;
        static bool last_send_successful = true;  // 新增:记录上一次 bt_nus_client_send 是否成功
    	static int last_phy = 2;  // 1 = 1M, 2 = 2M
    
    
    	while (1) {
    		
    		uint32_t now_ms = k_uptime_get_32();
            uint32_t dt_ms  = now_ms - g_last_rate_calc_time_ms;
    
            /* 每隔至少1秒计算一次数据速率 */
            if (dt_ms >= 1000) {
                uint32_t new_bytes = g_rx_bytes_count;
                float dt_sec = (float)dt_ms / 1000.0f;
                float rate_bytes_per_sec = ((float)new_bytes) / dt_sec;
                g_data_rate_bps = rate_bytes_per_sec * 8.0f;
    
                LOG_INF("Data Rate: %.2f bps (%.2f bytes/s)",
                        (double)g_data_rate_bps, (double)rate_bytes_per_sec);
    
                /* 重置计数器 */
                g_rx_bytes_count = 0;
                g_last_rate_calc_time_ms = now_ms;
            }
    
    
    
    
    		if (!default_conn) {
    			printk("Set Tx power level to %d\n", 8);
    			set_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_SCAN,
    				    //  0, 20);//永远开大到20
    					0, TXpower);
    			printk("Get Tx power level -> ");
    			get_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_SCAN,0, &txp_get);
    			printk("TXP = %d\n", txp_get);
    		} else {
    			
    		
    		
    
    		
    			idx = 0;
    			
    
    		
    
    				
    				read_conn_rssi(default_conn_handle, &rssi);
    
    
    
    
    			 /* 将最新的 g_data_rate_bps 存入滤波窗口 */
    			 rate[history_index] = g_data_rate_bps;  // 如有需要,可考虑修改为 float 类型
    			 history_index = (history_index + 1) % 5;
     
    			 /* 计算窗内平均值 */
    			 avg_rate = 0;
    			 for (int i = 0; i < 5; i++) {
    				 avg_rate += rate[i];
    			 }
    			 avg_rate /= 5.0f;
    
    			 LOG_INF("avg_rate  = %f\n",avg_rate);
    
    
    
    			int desired_phy = (avg_rate > 800000.0f) ? 2 : 1;
    			LOG_INF("desired_phy = %d", desired_phy);
    
                if (desired_phy != last_phy) {
                    struct bt_conn_le_phy_param *phy = 
                        (desired_phy == 2) ? &phy_2m : &phy_1m;
                    int phy_err = bt_conn_le_phy_update(default_conn, phy);
    				                // k_sleep(K_SECONDS(5));
    
                    if (phy_err) {
                        LOG_WRN("PHY update failed (%d)", phy_err);
                    } else {
                        last_phy = desired_phy;
                        LOG_INF("Switched to %dM PHY", desired_phy);
                    }
                }
    
    		
    			
    			LOG_INF("RXRX  = %d\n",rssi);
    			
    		}
    		k_sleep(K_MSEC(1000));
    	}
    	
    }

    Could you give me some advice?

Reply
  • Hi

    Thank you for your reply! I have tried to update PHY and wait for 5 seconds, it still cannot work. I have set up a new thread and my code is:

    void modulate_tx_power(void *p1, void *p2, void *p3)
    {
    	int8_t txp_get = 0;
        uint8_t idx = 0;
        int8_t rssi = 0xFF;
        static float rate[5] = {0}; 
        static uint8_t history_index = 0;
        static float avg_rate = 0;
        static bool last_send_successful = true;  // 新增:记录上一次 bt_nus_client_send 是否成功
    	static int last_phy = 2;  // 1 = 1M, 2 = 2M
    
    
    	while (1) {
    		
    		uint32_t now_ms = k_uptime_get_32();
            uint32_t dt_ms  = now_ms - g_last_rate_calc_time_ms;
    
            /* 每隔至少1秒计算一次数据速率 */
            if (dt_ms >= 1000) {
                uint32_t new_bytes = g_rx_bytes_count;
                float dt_sec = (float)dt_ms / 1000.0f;
                float rate_bytes_per_sec = ((float)new_bytes) / dt_sec;
                g_data_rate_bps = rate_bytes_per_sec * 8.0f;
    
                LOG_INF("Data Rate: %.2f bps (%.2f bytes/s)",
                        (double)g_data_rate_bps, (double)rate_bytes_per_sec);
    
                /* 重置计数器 */
                g_rx_bytes_count = 0;
                g_last_rate_calc_time_ms = now_ms;
            }
    
    
    
    
    		if (!default_conn) {
    			printk("Set Tx power level to %d\n", 8);
    			set_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_SCAN,
    				    //  0, 20);//永远开大到20
    					0, TXpower);
    			printk("Get Tx power level -> ");
    			get_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_SCAN,0, &txp_get);
    			printk("TXP = %d\n", txp_get);
    		} else {
    			
    		
    		
    
    		
    			idx = 0;
    			
    
    		
    
    				
    				read_conn_rssi(default_conn_handle, &rssi);
    
    
    
    
    			 /* 将最新的 g_data_rate_bps 存入滤波窗口 */
    			 rate[history_index] = g_data_rate_bps;  // 如有需要,可考虑修改为 float 类型
    			 history_index = (history_index + 1) % 5;
     
    			 /* 计算窗内平均值 */
    			 avg_rate = 0;
    			 for (int i = 0; i < 5; i++) {
    				 avg_rate += rate[i];
    			 }
    			 avg_rate /= 5.0f;
    
    			 LOG_INF("avg_rate  = %f\n",avg_rate);
    
    
    
    			int desired_phy = (avg_rate > 800000.0f) ? 2 : 1;
    			LOG_INF("desired_phy = %d", desired_phy);
    
                if (desired_phy != last_phy) {
                    struct bt_conn_le_phy_param *phy = 
                        (desired_phy == 2) ? &phy_2m : &phy_1m;
                    int phy_err = bt_conn_le_phy_update(default_conn, phy);
    				                // k_sleep(K_SECONDS(5));
    
                    if (phy_err) {
                        LOG_WRN("PHY update failed (%d)", phy_err);
                    } else {
                        last_phy = desired_phy;
                        LOG_INF("Switched to %dM PHY", desired_phy);
                    }
                }
    
    		
    			
    			LOG_INF("RXRX  = %d\n",rssi);
    			
    		}
    		k_sleep(K_MSEC(1000));
    	}
    	
    }

    Could you give me some advice?

Children
No Data
Related