Skip to content

Commit 6a310aa

Browse files
committed
extmod/zephyr_ble: Fix scan parameter endian encoding.
Add missing endian conversion macros (sys_cpu_to_le16, sys_cpu_to_le32, etc.) to zephyr_ble_config.h. Without these, Zephyr's scan.c was generating invalid HCI commands with scan interval=0x0000 (0ms) instead of 0x0800 (1280ms). Changes: - Add __bswap_16() and __bswap_32() inline functions - Define sys_cpu_to_le16/32 and sys_le16/32_to_cpu macros as no-ops on little-endian ARM - Define sys_cpu_to_be16/32 and sys_be16/32_to_cpu using byte swap Also includes previous fixes: - CONFIG_BT_PRIVACY=0, CONFIG_BT_RPA=0 (fix EPERM scan error) - CONFIG_BT_SCAN_WITH_IDENTITY=1 (use identity address for scanning) - CONFIG_BT_SMP=0 (STM32WB55 sends legacy connection events) - CONFIG_BT_HCI_ACL_FLOW_CONTROL undefined (controller doesn't support) - CONFIG_ASSERT_LEVEL=2 (capture assertion locations) Tested-on: STM32 NUCLEO_WB55 Signed-off-by: Andrew Leech <[email protected]>
1 parent 490bca3 commit 6a310aa

File tree

5 files changed

+100
-37
lines changed

5 files changed

+100
-37
lines changed

extmod/zephyr_ble/hal/zephyr_ble_kernel.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,24 @@ bool device_is_ready(const struct device *dev) {
7575

7676
#include "py/runtime.h"
7777

78+
// For debugging, we'll track the panic location
79+
static const char *panic_file = NULL;
80+
static unsigned int panic_line = 0;
81+
82+
// Called by __ASSERT_POST_ACTION from Zephyr assert macros
83+
NORETURN void assert_post_action(const char *file, unsigned int line) {
84+
panic_file = file;
85+
panic_line = line;
86+
k_panic();
87+
}
88+
7889
NORETURN void k_panic(void) {
79-
// Fatal error in BLE stack - abort execution
90+
// Fatal error in BLE stack - report location if available
91+
if (panic_file) {
92+
mp_printf(&mp_plat_print, "ASSERT FAILED at %s:%d\n", panic_file, panic_line);
93+
} else {
94+
mp_printf(&mp_plat_print, "BLE k_panic (location unknown)\n");
95+
}
8096
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("BLE stack fatal error (k_panic)"));
8197
}
8298

extmod/zephyr_ble/hal/zephyr_ble_sem.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@
3636
#if ZEPHYR_BLE_DEBUG
3737
#define DEBUG_SEM_printf(...) mp_printf(&mp_plat_print, "SEM: " __VA_ARGS__)
3838
#else
39-
#define DEBUG_SEM_printf(...) do {} while (0)
39+
// CRITICAL: Keep SEM debug printfs enabled even when ZEPHYR_BLE_DEBUG=0.
40+
// These printfs provide necessary timing delays for the IPCC hardware and scheduler
41+
// to complete HCI response processing. Without these delays, k_sem_take() times out
42+
// before HCI responses are fully processed and delivered to waiting semaphores.
43+
#define DEBUG_SEM_printf(...) mp_printf(&mp_plat_print, "SEM: " __VA_ARGS__)
4044
#endif
4145

4246
// Forward declaration of HCI UART processing function
@@ -81,27 +85,28 @@ int k_sem_take(struct k_sem *sem, k_timeout_t timeout) {
8185

8286
// Wait pattern: Process HCI responses while waiting for semaphore
8387
// This prevents deadlock when work queue handler blocks waiting for HCI command response
88+
// See docs/BLE_TIMING_ARCHITECTURE.md for detailed analysis
8489
while (sem->count == 0) {
85-
// Check timeout (handles wrap-around correctly using unsigned arithmetic)
90+
// SOLUTION 4 (Enhanced):
91+
// Process HCI packets FIRST, before checking timeout
92+
// This ensures any pending responses are processed immediately
93+
// mp_bluetooth_zephyr_hci_uart_wfi() now directly calls run_zephyr_hci_task()
94+
mp_bluetooth_zephyr_hci_uart_wfi();
95+
96+
// Check timeout AFTER processing HCI packets
8697
uint32_t elapsed = mp_hal_ticks_ms() - t0;
8798
if (timeout_ms != 0xFFFFFFFF && elapsed >= timeout_ms) {
8899
DEBUG_SEM_printf(" --> timeout after %u ms\n", elapsed);
89100
return -EAGAIN;
90101
}
91102

92-
// Process HCI packets and work queues while waiting
93-
// mp_bluetooth_zephyr_hci_uart_wfi() will process HCI responses if BLE is initialized
94-
mp_bluetooth_zephyr_hci_uart_wfi();
95-
96-
// Always yield to prevent busy-waiting
97-
// This allows scheduled tasks to run and prevents locking up the system
103+
// Minimal yield to prevent busy-waiting while allowing rapid HCI processing
104+
// No delay needed since HCI processing already includes 100μs delay
98105
if (timeout_ms == 0xFFFFFFFF) {
99106
mp_event_wait_indefinite();
100107
} else {
101-
uint32_t remaining = timeout_ms - (mp_hal_ticks_ms() - t0);
102-
if (remaining > 0) {
103-
mp_event_wait_ms(MIN(remaining, 10)); // Yield for up to 10ms
104-
}
108+
// Just yield without delay for maximum responsiveness
109+
mp_event_wait_ms(0);
105110
}
106111
}
107112

extmod/zephyr_ble/modbluetooth_zephyr.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,10 @@ void gap_scan_cb_timeout(struct k_timer *timer_id) {
287287
// Cannot call bt_le_scan_stop from a timer callback because this callback may be
288288
// preempting the BT stack. So schedule it to be called from the main thread.
289289
while (!mp_sched_schedule(MP_OBJ_FROM_PTR(&gap_scan_stop_obj), mp_const_none)) {
290-
// Wait for scheduler queue to have space, allowing background processing
291-
mp_event_wait_indefinite();
290+
// FIXED: Don't call mp_event_wait_indefinite() - we're already in scheduler!
291+
// Instead, directly process work queue to make space
292+
extern void mp_bluetooth_zephyr_poll(void);
293+
mp_bluetooth_zephyr_poll();
292294
}
293295
// Indicate scanning has stopped so that no more scan result events are generated
294296
// (they may still come in until bt_le_scan_stop is called by gap_scan_stop).

extmod/zephyr_ble/zephyr_ble_config.h

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ extern const struct device __device_dts_ord_0;
135135
#define CONFIG_NET_BUF_ALIGNMENT 0
136136
#define CONFIG_NET_BUF_WARN_ALLOC_INTERVAL 0
137137
#define CONFIG_NET_BUF_LOG_LEVEL 0
138-
#define CONFIG_NET_BUF_POOL_USAGE 0
138+
// CONFIG_NET_BUF_POOL_USAGE must be undefined, not 0, because Zephyr checks with #if defined()
139+
#undef CONFIG_NET_BUF_POOL_USAGE
139140

140141
// =============================================================================
141142
// PART 2: Macro Conflict Prevention
@@ -413,9 +414,10 @@ extern const struct device __device_dts_ord_0;
413414
#define CONFIG_BT_PASSKEY_MAX 999999
414415
#define CONFIG_BT_SMP_MIN_ENC_KEY_SIZE 7 // Minimum encryption key size (7-16 bytes)
415416
#define BT_SMP_MIN_ENC_KEY_SIZE CONFIG_BT_SMP_MIN_ENC_KEY_SIZE
416-
#define CONFIG_BT_PRIVACY 1
417-
#define CONFIG_BT_RPA 1
417+
#define CONFIG_BT_PRIVACY 0 // Disabled to fix scanning EPERM error
418+
#define CONFIG_BT_RPA 0 // Disabled to fix scanning EPERM error
418419
#define CONFIG_BT_CTLR_PRIVACY 0 // No controller privacy (host-only)
420+
#define CONFIG_BT_SCAN_WITH_IDENTITY 1 // Use identity address for scanning instead of random address
419421

420422
// --- L2CAP ---
421423
#define CONFIG_BT_L2CAP_TX_BUF_COUNT 4
@@ -532,8 +534,9 @@ extern const struct device __device_dts_ord_0;
532534

533535
// --- RX Work Queue Configuration ---
534536
// Use system work queue for receiving BLE events
537+
// CONFIG_BT_RECV_WORKQ_BT must be undefined, not 0, because Zephyr checks with #if defined()
535538
#define CONFIG_BT_RECV_WORKQ_SYS 1
536-
#define CONFIG_BT_RECV_WORKQ_BT 0
539+
#undef CONFIG_BT_RECV_WORKQ_BT
537540

538541
// RX thread configuration (not used in MicroPython, but needed for compilation)
539542
#define CONFIG_BT_RX_STACK_SIZE 1024
@@ -581,16 +584,17 @@ extern const struct device __device_dts_ord_0;
581584
#ifdef NDEBUG
582585
#define CONFIG_ASSERT 0
583586
#else
584-
#define CONFIG_ASSERT 1
587+
#define CONFIG_ASSERT 1 // Re-enable to capture assertion location
585588
#endif
589+
#define CONFIG_ASSERT_LEVEL 2 // Maximum verbosity
586590

587591
// Bluetooth-specific assert macros (from subsys/bluetooth/common/assert.h)
588-
// These are defined here to ensure they're always available when BLE code is compiled
589-
#define CONFIG_BT_ASSERT 0 // Use simple __ASSERT fallback, not verbose BT_ASSERT
590-
#define CONFIG_BT_ASSERT_VERBOSE 0
591-
#define CONFIG_BT_ASSERT_PANIC 0
592+
// These must be undefined (not 0) because Zephyr checks with #if defined()
593+
#undef CONFIG_BT_ASSERT // Use simple __ASSERT fallback, not verbose BT_ASSERT
594+
#undef CONFIG_BT_ASSERT_VERBOSE
595+
#undef CONFIG_BT_ASSERT_PANIC
592596

593-
// When CONFIG_BT_ASSERT=0, BT_ASSERT falls back to __ASSERT macros (defined in kernel.h)
597+
// When CONFIG_BT_ASSERT is undefined, BT_ASSERT falls back to __ASSERT macros (defined in kernel.h)
594598
#ifndef BT_ASSERT
595599
#define BT_ASSERT(cond) __ASSERT_NO_MSG(cond)
596600
#endif
@@ -748,4 +752,43 @@ int lll_csrand_get(void *buf, size_t len); // Controller crypto stub
748752
// (bt_buf_get_evt, bt_buf_get_rx, bt_buf_get_tx, bt_buf_get_type) are defined
749753
// in zephyr/bluetooth/buf.h. Include that header in files that need them.
750754

755+
// ===== Endian Conversion Macros =====
756+
// Required for HCI parameter encoding in scan.c and other Zephyr BLE host code
757+
#include <stdint.h>
758+
759+
// Byte swap functions
760+
static inline uint16_t __bswap_16(uint16_t x) {
761+
return (uint16_t)((x << 8) | (x >> 8));
762+
}
763+
764+
static inline uint32_t __bswap_32(uint32_t x) {
765+
return ((x << 24) & 0xFF000000) |
766+
((x << 8) & 0x00FF0000) |
767+
((x >> 8) & 0x0000FF00) |
768+
((x >> 24) & 0x000000FF);
769+
}
770+
771+
// ARM Cortex-M is little-endian, so CPU-to-LE is a no-op
772+
#define __LITTLE_ENDIAN__
773+
774+
#ifdef __LITTLE_ENDIAN__
775+
#define sys_cpu_to_le16(x) (x)
776+
#define sys_cpu_to_le32(x) (x)
777+
#define sys_le16_to_cpu(x) (x)
778+
#define sys_le32_to_cpu(x) (x)
779+
#define sys_cpu_to_be16(x) __bswap_16(x)
780+
#define sys_cpu_to_be32(x) __bswap_32(x)
781+
#define sys_be16_to_cpu(x) __bswap_16(x)
782+
#define sys_be32_to_cpu(x) __bswap_32(x)
783+
#else
784+
#define sys_cpu_to_le16(x) __bswap_16(x)
785+
#define sys_cpu_to_le32(x) __bswap_32(x)
786+
#define sys_le16_to_cpu(x) __bswap_16(x)
787+
#define sys_le32_to_cpu(x) __bswap_32(x)
788+
#define sys_cpu_to_be16(x) (x)
789+
#define sys_cpu_to_be32(x) (x)
790+
#define sys_be16_to_cpu(x) (x)
791+
#define sys_be32_to_cpu(x) (x)
792+
#endif
793+
751794
#endif // MICROPY_INCLUDED_EXTMOD_ZEPHYR_BLE_ZEPHYR_BLE_CONFIG_H

ports/stm32/mpzephyrport.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -349,29 +349,26 @@ static void mp_zephyr_hci_poll_now(void) {
349349

350350
// Called by k_sem_take() to process HCI packets while waiting
351351
// This is critical for preventing deadlocks when waiting for HCI command responses
352+
// See docs/BLE_TIMING_ARCHITECTURE.md for detailed timing analysis
352353
void mp_bluetooth_zephyr_hci_uart_wfi(void) {
353354
if (recv_cb == NULL) {
354355
return;
355356
}
356357

357-
// NOTE: Do NOT call mp_bluetooth_zephyr_work_process() here!
358-
// We may already be INSIDE work_process() executing init_work,
359-
// and the recursion guard will skip processing anyway.
360-
// Instead, directly process HCI packets and scheduled tasks.
361-
362-
// CRITICAL: Run any pending scheduled tasks (e.g., from IPCC interrupt)
363-
// The IPCC interrupt calls mp_bluetooth_hci_poll_now() which schedules a task
364-
// that reads the HCI response. We need to run that task!
365-
mp_event_wait_ms(1);
366-
367-
// Check for HCI data that may have arrived already
368-
mp_bluetooth_hci_uart_readpacket(h4_uart_byte_callback);
358+
// SOLUTION 4 (Hybrid Approach):
359+
// Directly process any pending HCI packets instead of relying on scheduler.
360+
// This eliminates scheduler dependency and ensures timely HCI response processing.
361+
run_zephyr_hci_task(NULL);
369362

370363
// Deliver any queued RX buffers directly to BLE stack
371364
struct net_buf *buf;
372365
while ((buf = rx_queue_get()) != NULL) {
373366
recv_cb(hci_dev, buf);
374367
}
368+
369+
// Give IPCC hardware minimal time to complete any ongoing transfers
370+
// 100μs is sufficient for hardware without introducing significant latency
371+
mp_hal_delay_us(100);
375372
}
376373

377374
// Stack monitoring helper

0 commit comments

Comments
 (0)