-
Notifications
You must be signed in to change notification settings - Fork 58
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
<ProvideServicesAdvertisement flags= services=<BoundServiceList: UUID(0x1818), UUID(0x1826)> comp>
found a CyclingPowerService advertisement
<ProvideServicesAdvertisement flags= services=<BoundServiceList: UUID(0x1818), UUID(0x1826)> 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)