About esb_ptx_ble & esb_prx_ble.

Can I copy the ESB code from SDK v3.3.0-preview3 into SDK v2.9.0, and then get the functionality in esb_ptx_ble & esb_prx_ble?

 

Is there any way to achieve it quickly?

Parents
  • Hello,

    Not sure I understand what problem you are trying to solve here, there should be ESB example projects for the nRF52840 in both the nRF Connect SDK releases you are referring to.

    Can I copy the ESB code from SDK v3.3.0-preview3 into SDK v2.9.0, and then get the functionality in esb_ptx_ble & esb_prx_ble?

    There may be some api changes, but for most part I would expect it should be pretty straight forward possible yes.

    Kenneth

  • Hello,

    Using nRF Connect SDK v3.3.0, one device runs esb_ptx_ble and broadcasts 2 packets of data every 5-10ms, with 15 devices running esb_prx_ble,esb rx interval 7300ms,rx window 15ms, 30 seconds is a receiving cycle, and failure to receive a packet of data within the cycle is considered a failure; After running 15 devices for a few days, occasionally one device experiences dozens of consecutive cycles without receiving data. Why is that?

    CONFIG_CONN_INTERVAL_MIN=990  //ms
    CONFIG_CONN_INTERVAL_MAX=1010
    CONFIG_CONN_LATENCY=6

    Is it phase entanglement? Or is it another question? How can I solve it?
  • Hi Kenneth,

    Thanks!
    Yes, I can do that, but the key point is when to re-configure the radio, because TX devices only broadcasts data when a critical event occurs, so RX devices can only re-configure the radio when a error code occurs. Currently, I will reset MCU when an error code occurs.

    By the way, why does the ESB of nRF Connect SDK v3.3 no longer have the options of 125Kbits and 250Kbits?


    Leo Mo

  • Hi Leo,

    Kenneth is currently on PTO. I will follow up this case and get you an answer to the latest question, but I will need a little while to get up to speed here.

    I'll get back to you before the weekend.

    Kind regards,
    Andreas

  • Hello AHaug,

    Thanks!
    Another question is why sending 8 bytes, 16 bytes, and 32 bytes takes about the same amount of time? Is it time-consuming to prepare before sending? 


    config ESB_MPSL_TIMESLOT
        bool "ESB on MPSL Timeslot [EXPERIMENTAL]"
        select EXPERIMENTAL
        depends on MPSL
        depends on !ESB_NEVER_DISABLE_TX
        depends on !SOC_SERIES_NRF53
        help
          This option configures the ESB to use the MPSL Timeslot API as middleman in radio access.
          It allows multiple protocols to be used concurrently. Using the Timeslot API can increase
          number of retransmissions, reduce ESB packets delivery rate, and cause the delay of
          retransmissions to vary.

    config ESB_NEVER_DISABLE_TX
        select EXPERIMENTAL
        bool "Never disable radio transmission stage"
        help
          This option changes the radio behavior so that the
          transmitter remains IDLE between transmissions instead of being disabled.
          This is applicable only when the packet is not acknowledged. Otherwise,
          the radio emitter needs to be turned off to enable the radio receiver.
          This reduces delay between consecutive transmissions but consumes more energy.

    ESB_MPSL_TIMESLOT and ESB_NEVER_DISABLE_TX cannot be set to y at the same time.
    Is there any way to reduce the preparation time before launch.







    while (1) {
            
    	    err = esb_initialize();
    	    if (err) {
    		    LOG_ERR("ESB initialization failed, err %d", err);
    		    return 0;
    	    }
    
    
            tx_payload.length = 32;
            for (int i = 0; i < 3; i++) {
                   tx_count += !esb_write_payload(&tx_payload);
            }
            while (!esb_is_idle());
            k_sleep(K_MSEC(100));
            esb_disable();
            seq_num++;
            tx_payload.data[6] = seq_num & 0xFF;
            tx_payload.data[5] = (seq_num >> 8) & 0x7F;
            tx_count = 0;
    
            k_sleep(K_MSEC(1000));
        }

  • Hi Leo,

    Leo Mo said:
    Another question is why sending 8 bytes, 16 bytes, and 32 bytes takes about the same amount of time? Is it time-consuming to prepare before sending? 

    There is a payload discrepancy, it is just very small.

    Looking at your snippet, this stems from your code snippet mainly. As you can see in the image, the period where you do TX differs from the 3 images, but the sleep time in between each operation is so large compared to the Tx window that it is hard to notice. Measure this window instead of the pause to see the actual difference of the TX time.

     

    Roughly summarized what each cycle is

    1. A rise to a ~3 to 4 mA plateau that sits there for a while.
    2. Two short spikes up to ~16 mA (the actual radio TX).
    3. Back down to near zero.

    The payload is the only part of the transaction that scales with size.

    • On-air payload at 2 Mbit/s: 8 B ≈ 32 µs, 16 B ≈ 64 µs, 32 B ≈ 128 µs. Which is very small in the almost 2ms timescale of the selection view
    • Fixed per-packet cost that doesn't change with size: TX ramp-up (~40 µs fast, ~130 µs legacy), preamble + address + PCF + CRC (~35 to 45 µs on air), and with ACK enabled the turnaround to RX to catch the ack.

    The time between the packs you queue up is governed by esb_config.retransmit_delay, not by payload length. In the NCS samples that is typically ~600 µs. Three packets at that spacing is your largest contributor to on-air time, and it's identical whether each is 8 or 32 bytes.

    Is this test set up to do initialization every time before each pack? If this is not a test case, then the following might improve the time used for preparation in between each burst.

    • Move esb_initialize() out of the loop. Re-initializing every iteration reconfigures the radio and can force an HFCLK cold start. The initialization is the plateau you see in between each TX
    • Don't esb_disable() between bursts unless you need the radio released, since disabling can drop HFCLK and you re-pay the crystal ramp next time.

    Kind regards,
    Andreas

  • Hi,

    My device is battery powered and requires extremely low power consumption, so it will turn off RF. I changed the ts_dauration params. tx_rx_sequence of static void update_ts_duration_prams_for_tx (uint8_t payload_1ength), but it didn't have much effect, and the total time still hasn't changed. It seems that MPSL scheduling takes a lot of time.

    static void update_ts_duration_params_for_tx(uint8_t payload_length)
    {
    	const uint16_t margin = 100;
    	const uint16_t ramp_up =
    		esb_cfg.use_fast_ramp_up ? TX_FAST_RAMP_UP_TIME_US : TX_RAMP_UP_TIME_US;
    
    	ts_duration_params.tx_frame_duration = (ts_duration_params.frame_overhead + payload_length)
    					       << ts_duration_params.bitrate_shift;
    	// ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +
    	// 				    wait_for_ack_timeout_us +
    	// 				    ts_duration_params.max_frame_duration + margin;
    	ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration + margin;
    }
    


    1. ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                    margin;


    2. ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                wait_for_ack_timeout_us +

                                                ts_duration_params.max_frame_duration + margin;

    int main(void)
    {
    	int err;
    
        LOG_INF("Build date: %s, build time: %s", __DATE__, __TIME__);
    	// LOG_INF("Starting Enhanced ShockBurst prx with Peripheral LBS sample");
    
    	err = dk_leds_init();
    	if (err) {
    		LOG_ERR("LEDs init failed (err %d)", err);
    		return 0;
    	}
    
    	// err = dk_buttons_init(button_changed);
    	// if (err) {
    	// 	LOG_ERR("Cannot init buttons (err: %d)", err);
    	// }
    
    	// err = bt_enable(NULL);
    	// if (err) {
    	// 	LOG_ERR("Bluetooth init failed (err %d)", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("Bluetooth initialized");
    
    	// err = bt_lbs_init(&lbs_callbacks);
    	// if (err) {
    	// 	LOG_ERR("Failed to init LBS (err:%d)", err);
    	// 	return 0;
    	// }
    
    	// k_work_init(&adv_work, adv_work_handler);
    	// advertising_start();
    
    	// err = esb_initialize();
    	// if (err) {
    	// 	LOG_ERR("ESB initialization failed, err %d", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("ESB initialized");
    
    	// err = esb_write_payload(&tx_payload);
    	// if (err) {
    	// 	LOG_ERR("Write payload, err %d", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("Setting up for packet reception");
    
    	// err = esb_start_rx();
    	// if (err) {
    	// 	LOG_ERR("RX setup failed, err %d", err);
    	// 	return 0;
    	// }
    #if APP_ESB_RX_MODE
        LOG_INF("Starting RX mode");
        k_work_schedule(&rx_work, K_MSEC(1000 + sys_rand32_get() % 3000));
        while (1) {
            struct esb_payload rx_payload;
            k_msgq_get(&rx_msgq, &rx_payload, K_FOREVER);
            if (rx_payload.length) {
                // Process the received payload
                static uint8_t target_buf[3] = { 0x6e, 0x26, 0xb1 };
                if (memcmp(rx_payload.data, target_buf, sizeof(target_buf))) {
                    continue;
                }
                static uint32_t rx_count = 0, last_uptime = 0;
                static uint16_t last_seq_num = 0x8000, missed_count = 0, seq_count = 0;
                uint16_t new_seq_num = rx_payload.data[6] | (rx_payload.data[5] << 8);
                uint32_t uptime = k_uptime_seconds();
                rx_count++;
                if(new_seq_num  - last_seq_num > 1 && last_seq_num != 0x8000) {
                    missed_count += new_seq_num - last_seq_num - 1;
                    LOG_WRN("Missed %d packets, total missed %d", new_seq_num - last_seq_num - 1, missed_count);
                    LOG_HEXDUMP_WRN(rx_payload.data, rx_payload.length, "New packet data");
                }
                if(new_seq_num == last_seq_num || last_seq_num == 0x8000) {
                    seq_count++;
                } else {
                    seq_count = 1;
                }
    
                LOG_INF("T:%u, RX %u, seq 0x%04x, count %u, missed %u", uptime, rx_count, new_seq_num, seq_count, missed_count);
                last_seq_num = new_seq_num;
    
                // static bool last_led_state = false;
                // if (uptime - last_uptime > 2) {
                //     dk_set_led(DK_LED1, last_led_state);
                //     last_led_state = !last_led_state;
                //     last_uptime = uptime;
                // }
            }
        }
    #elif 1
        LOG_INF("Starting TX mode");
        k_sleep(K_MSEC(1000));
        tx_payload.noack = true;
        tx_payload.length = 8;
        uint32_t last_tx_time = k_uptime_get_32();
        int tx_count = 0;
        uint16_t seq_num = 0x8000;
        while (1) {
            
    	    err = esb_initialize();
    	    if (err) {
    		    LOG_ERR("ESB initialization failed, err %d", err);
    		    return 0;
    	    }
            // LOG_INF("ESB initialized");
            
            // last_tx_time = k_uptime_get_32();
            // while (last_tx_time + 30 > k_uptime_get_32()) {
    
            //     if(!esb_tx_full())
            //        tx_count += !esb_write_payload(&tx_payload);
            // }
    
            tx_payload.length = 8;
            for (int i = 0; i < 3; i++) {
                   tx_count += !esb_write_payload(&tx_payload);
            }
            while (!esb_is_idle());
            esb_disable();
            seq_num++;
            tx_payload.data[6] = seq_num & 0xFF;
            tx_payload.data[5] = (seq_num >> 8) & 0x7F;
            // LOG_INF("TX %d packets in 30ms, %d packet per ms", tx_count, tx_count / 30);
            tx_count = 0;
    
            k_sleep(K_MSEC(1000));
        }
    #else
        while (1) {
            k_sleep(K_FOREVER);
        }    
    #endif
        return 0;
    }
    


    ESB_TX_3_Packets_8_bytes_tx_rx_sequence: ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration + margin;

    ESB_TX_3_Packets_8_bytes: 

    ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                wait_for_ack_timeout_us +

                                                ts_duration_params.max_frame_duration + margin;

    ESB_TX_3_Packets_8_bytes_tx_rx_sequence.ppk2

    ESB_TX_3_Packets_8_bytes.ppk2



Reply
  • Hi,

    My device is battery powered and requires extremely low power consumption, so it will turn off RF. I changed the ts_dauration params. tx_rx_sequence of static void update_ts_duration_prams_for_tx (uint8_t payload_1ength), but it didn't have much effect, and the total time still hasn't changed. It seems that MPSL scheduling takes a lot of time.

    static void update_ts_duration_params_for_tx(uint8_t payload_length)
    {
    	const uint16_t margin = 100;
    	const uint16_t ramp_up =
    		esb_cfg.use_fast_ramp_up ? TX_FAST_RAMP_UP_TIME_US : TX_RAMP_UP_TIME_US;
    
    	ts_duration_params.tx_frame_duration = (ts_duration_params.frame_overhead + payload_length)
    					       << ts_duration_params.bitrate_shift;
    	// ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +
    	// 				    wait_for_ack_timeout_us +
    	// 				    ts_duration_params.max_frame_duration + margin;
    	ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration + margin;
    }
    


    1. ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                    margin;


    2. ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                wait_for_ack_timeout_us +

                                                ts_duration_params.max_frame_duration + margin;

    int main(void)
    {
    	int err;
    
        LOG_INF("Build date: %s, build time: %s", __DATE__, __TIME__);
    	// LOG_INF("Starting Enhanced ShockBurst prx with Peripheral LBS sample");
    
    	err = dk_leds_init();
    	if (err) {
    		LOG_ERR("LEDs init failed (err %d)", err);
    		return 0;
    	}
    
    	// err = dk_buttons_init(button_changed);
    	// if (err) {
    	// 	LOG_ERR("Cannot init buttons (err: %d)", err);
    	// }
    
    	// err = bt_enable(NULL);
    	// if (err) {
    	// 	LOG_ERR("Bluetooth init failed (err %d)", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("Bluetooth initialized");
    
    	// err = bt_lbs_init(&lbs_callbacks);
    	// if (err) {
    	// 	LOG_ERR("Failed to init LBS (err:%d)", err);
    	// 	return 0;
    	// }
    
    	// k_work_init(&adv_work, adv_work_handler);
    	// advertising_start();
    
    	// err = esb_initialize();
    	// if (err) {
    	// 	LOG_ERR("ESB initialization failed, err %d", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("ESB initialized");
    
    	// err = esb_write_payload(&tx_payload);
    	// if (err) {
    	// 	LOG_ERR("Write payload, err %d", err);
    	// 	return 0;
    	// }
    
    	// LOG_INF("Setting up for packet reception");
    
    	// err = esb_start_rx();
    	// if (err) {
    	// 	LOG_ERR("RX setup failed, err %d", err);
    	// 	return 0;
    	// }
    #if APP_ESB_RX_MODE
        LOG_INF("Starting RX mode");
        k_work_schedule(&rx_work, K_MSEC(1000 + sys_rand32_get() % 3000));
        while (1) {
            struct esb_payload rx_payload;
            k_msgq_get(&rx_msgq, &rx_payload, K_FOREVER);
            if (rx_payload.length) {
                // Process the received payload
                static uint8_t target_buf[3] = { 0x6e, 0x26, 0xb1 };
                if (memcmp(rx_payload.data, target_buf, sizeof(target_buf))) {
                    continue;
                }
                static uint32_t rx_count = 0, last_uptime = 0;
                static uint16_t last_seq_num = 0x8000, missed_count = 0, seq_count = 0;
                uint16_t new_seq_num = rx_payload.data[6] | (rx_payload.data[5] << 8);
                uint32_t uptime = k_uptime_seconds();
                rx_count++;
                if(new_seq_num  - last_seq_num > 1 && last_seq_num != 0x8000) {
                    missed_count += new_seq_num - last_seq_num - 1;
                    LOG_WRN("Missed %d packets, total missed %d", new_seq_num - last_seq_num - 1, missed_count);
                    LOG_HEXDUMP_WRN(rx_payload.data, rx_payload.length, "New packet data");
                }
                if(new_seq_num == last_seq_num || last_seq_num == 0x8000) {
                    seq_count++;
                } else {
                    seq_count = 1;
                }
    
                LOG_INF("T:%u, RX %u, seq 0x%04x, count %u, missed %u", uptime, rx_count, new_seq_num, seq_count, missed_count);
                last_seq_num = new_seq_num;
    
                // static bool last_led_state = false;
                // if (uptime - last_uptime > 2) {
                //     dk_set_led(DK_LED1, last_led_state);
                //     last_led_state = !last_led_state;
                //     last_uptime = uptime;
                // }
            }
        }
    #elif 1
        LOG_INF("Starting TX mode");
        k_sleep(K_MSEC(1000));
        tx_payload.noack = true;
        tx_payload.length = 8;
        uint32_t last_tx_time = k_uptime_get_32();
        int tx_count = 0;
        uint16_t seq_num = 0x8000;
        while (1) {
            
    	    err = esb_initialize();
    	    if (err) {
    		    LOG_ERR("ESB initialization failed, err %d", err);
    		    return 0;
    	    }
            // LOG_INF("ESB initialized");
            
            // last_tx_time = k_uptime_get_32();
            // while (last_tx_time + 30 > k_uptime_get_32()) {
    
            //     if(!esb_tx_full())
            //        tx_count += !esb_write_payload(&tx_payload);
            // }
    
            tx_payload.length = 8;
            for (int i = 0; i < 3; i++) {
                   tx_count += !esb_write_payload(&tx_payload);
            }
            while (!esb_is_idle());
            esb_disable();
            seq_num++;
            tx_payload.data[6] = seq_num & 0xFF;
            tx_payload.data[5] = (seq_num >> 8) & 0x7F;
            // LOG_INF("TX %d packets in 30ms, %d packet per ms", tx_count, tx_count / 30);
            tx_count = 0;
    
            k_sleep(K_MSEC(1000));
        }
    #else
        while (1) {
            k_sleep(K_FOREVER);
        }    
    #endif
        return 0;
    }
    


    ESB_TX_3_Packets_8_bytes_tx_rx_sequence: ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration + margin;

    ESB_TX_3_Packets_8_bytes: 

    ts_duration_params.tx_rx_sequence = ramp_up + ts_duration_params.tx_frame_duration +

                                                wait_for_ack_timeout_us +

                                                ts_duration_params.max_frame_duration + margin;

    ESB_TX_3_Packets_8_bytes_tx_rx_sequence.ppk2

    ESB_TX_3_Packets_8_bytes.ppk2



Children
No Data
Related