adafruit / adafruit/Adafruit_CircuitPython_BLE

DeviceInfoService leads to out of memory on ESP32 8mb/no PSRAM

Open
#216 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
138
Forks
58
PR merge metrics
No merged PRs in 30d

Description

I've run into an out of memory error with the BLE library and while it is not a blocker for me (I can skip over it), it's weird so I thought I'd report it in case it could be of some use. I don't know how to debug circuitpython but if there is a way to increase the traceback module's "limit" param or turn on exception chaining in boot.py I can try it and report the results.

I've written a BLE parser class for the cycling power service and a simpletest that is a copy of ble_cycling_speed_and_cadence_simpletest.py but with my own service class substituted for CyclingSpeedAndCadenceService and a few prints of gc.mem_free() sprinkled about. It works fine on desktop linux. On an ESP32 8mb/no psram (product 5426) I get an out of memory error when doing `if DeviceInfoService in conn:`. I can only assume that there is something strange about my particular BLE device that causes something to go wrong after `_discover_remote` calls `self._bleio_connection.discover_remote_services`

I'm running the 9.2.8 bootloader with the circuitpython bundle cut on 8/7/2025

Here is the code output:

> Scanning...
> 78064
> services= comp>
> found a CyclingPowerService advertisement
> services= comp>
> found a CyclingPowerService advertisement
> Stopped scanning
> 69344
> Connected 1
> 69120
> Determining manufacturer
> Traceback (most recent call last):
> File "code.py", line 51, in
> File "adafruit_ble/__init__.py", line 88, in __contains__
> File "adafruit_ble/__init__.py", line 66, in _discover_remote
> MemoryError: Nimble out of memory
>

And here is the code:

```
# SPDX-FileCopyrightText: 2020 Dan Halbert for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
Read cycling speed and cadence data from a peripheral using the standard BLE
Cycling Speed and Cadence (CSC) Service.
"""

import time, gc

import adafruit_ble
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.standard.device_info import DeviceInfoService

from cycling_power_service import CyclingPowerService

# Initialize the BLE radio
ble = adafruit_ble.BLERadio()

while True:
print("Scanning...")
print(gc.mem_free())
# Save advertisements, indexed by address
advs = {}
for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5):
print(adv)
if CyclingPowerService in adv.services:
print("found a CyclingPowerService advertisement")
# Save advertisement. Overwrite duplicates from same address (device).
advs[adv.address] = adv

ble.stop_scan()
print("Stopped scanning")
print(gc.mem_free())
if not advs:
# Nothing found. Go back and keep looking.
continue

# Connect to all available CSC sensors.
cyc_connections = []
for adv in advs.values():
cyc_connections.append(ble.connect(adv))
print("Connected", len(cyc_connections))
print(gc.mem_free())

# Print out info about each sensors.
for conn in cyc_connections:
if conn.connected:
print("Determining manufacturer")
if DeviceInfoService in conn:
dis = conn[DeviceInfoService]
try:
manufacturer = dis.manufacturer
except AttributeError:
manufacturer = "(Manufacturer Not specified)"
print("Device:", manufacturer)
else:
print("No device information")

print("Waiting for data... (could be 10-20 seconds or more)")
# Get CSC Service from each sensor.
cyc_services = []
if len(cyc_connections) > 1:
print("Multiple trainers detected, this implementation just grabs the first one")
for conn in cyc_connections:
cyc_services.append(conn[CyclingPowerService])

# Read data from each sensor once a second.
# Stop if we lose connection to all sensors.
while True:
still_connected = False
for conn, svc in zip(cyc_connections, cyc_services):
if conn.connected:
still_connected = True
print(svc.get_cycling_power_measurement)
print(gc.mem_free())

if not still_connected:
break
time.sleep(1)
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with adafruit_ble/__init__.py, especially __contains__ and _discover_remote, and reproduce the reported DeviceInfoService lookup using the supplied code on an ESP32 8mb/no-PSRAM device. Compare memory usage around discover_remote_services; done means the lookup no longer raises MemoryError in this environment or the limitation is documented with a verified explanation.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.