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?

  • Hi,

    1. How does it not work this time?

    2. Does any of the updates succeed?

    3. What errors do you see and when?

    4. I see you have some log lines, what is the log output?

    5. I also see that you have some code to set TX power, which might also happen quite often. What code path is followed depends on the default_conn variable. Where is that variable set or changed, and if it is changed in a different context have you remembered to declare it volatile?

    Regards,
    Terje

Reply
  • Hi,

    1. How does it not work this time?

    2. Does any of the updates succeed?

    3. What errors do you see and when?

    4. I see you have some log lines, what is the log output?

    5. I also see that you have some code to set TX power, which might also happen quite often. What code path is followed depends on the default_conn variable. Where is that variable set or changed, and if it is changed in a different context have you remembered to declare it volatile?

    Regards,
    Terje

Children
No Data
Related