micropython / micropython-esp32

Old port of MicroPython to the ESP32 -- new port is at https://github.com/micropython/micropython
MIT License
680 stars 219 forks source link

Bluetooth support #222

Closed MrSurly closed 5 years ago

MrSurly commented 7 years ago

I've abandoned my PR for Bluetooth support because the IDF has changed so much, large portions of the code no longer work or are irrelevant. Modifying the old code would be more work than just starting anew, copying snippets from the old codebase as necessary.

Having said that, I've created a dev-bluetooth-2 branch, with the goal if just getting network.Bluetooth() working. That is, simply initializing the BT subsystem, and nothing else.

While it does compile, it crashes (gibberish to console, WDT a few seconds later) when calling esp_bt_controller_init().

I'm hoping for some guidance from others that know the IDF & MicroPython better than I do. If @projectgus, @igrr, @dpgeorge or anyone else has any hints, it'd be much appreciated. The IDF hash is 2c95a77cf93781f296883d5dbafcdc18e4389656, which currently is the hash used by MicroPython ESP32.

Thanks.

MrSurly commented 7 years ago

@dpgeorge Oh, also, this would be a good time to work on a HAL layer for BT in general, as was discussed.

MrSurly commented 7 years ago

Okay, I've looked at this a bit further. There doesn't appear that there's enough heap to support Bluetooth on the ESP-WROOM-32 alongside MicroPython. Perhaps one of the other ESP modules that have psRAM support will work.

nickzoic commented 7 years ago

That's a shame.

What makes BLE so heap-intensive compared to, say, WLAN?

MrSurly commented 7 years ago

What makes BLE so heap-intensive compared to, say, WLAN?

Well, right off the bat, it takes 64K from the heap for the BT stack. This is in the linker script for the IDF. That doesn't include all the bss items that eat up the heap.

I added this line:

ESP_LOGI(TAG, "Free RAM for user task: %d", xPortGetFreeHeapSize());

at line 373 of esp32/cpu_start.c in the IDF, before the call to vTaskStartScheduler();

examples/system/deepsleep: 178388 examples/bluetooth/gatt_client: 73420 Current MP: 7232 (with 96K MP heap) = 105536 Current MP: 80444 (with 6K MP heap)

Those last two lines don't make any sense to me. If I use a 96K MP heap, then there's a report 7232b free. If I use a 6K MP heap (-90K), then the free ram only jumps to 80444. Shouldn't it jump to 99392 (96K + 7232)?

  178388            Baseline
- 104968            Bluetooth
-  72852            MicroPython (with MP heap size of 0)
=    568            Free
nickzoic commented 7 years ago

That does seem a bit arbitrary. Is that this bit in components/soc/esp32/soc_memory_layout.c you're referring to?

#if CONFIG_BT_ENABLED
    { 0x3ffb0000, 0x3ffc0000 }, //Reserve BT hardware shared memory & BT data region

I wonder if the BT hardware controller can be asked to use just a smidge less memory ... there's code in components/bt/bt.c which sets up a mapping of available memory regions, perhaps this can be tweaked a little. Also perhaps if you're only interested in BLE then CLASSIC_BT can be disabled or whatever.

I'll follow up with Espressif ...

MrSurly commented 7 years ago

That does seem a bit arbitrary. Is that this bit in components/soc/esp32/soc_memory_layout.c you're referring to?

That may very well be part of it, but I was thinking of CONFIG_BT_RESERVE_DRAM

From sdkconfig.h

#define CONFIG_BT_RESERVE_DRAM 0x10000

This is used in components/esp32/ld/esp32.ld

projectgus commented 7 years ago

Well, right off the bat, it takes 64K from the heap for the BT stack

I'll follow up with Espressif ...

Hi folks,

As you've mentioned, the ROM-resident part of the Bluetooth hardware controller reserves a region of memory for static memory - buffers, etc. The region is compiled into the ROM code which is why it's blocked out as an absolute range in the linker script.

In IDF v2.1 you could use menuconfig to reduce the size of this region if you were not using BT Classic (ie BLE-only).

In IDF v3.0, in an effort to make this more flexible, you can release the Bluetooth controller memory at runtime. See esp_bt_controller_mem_release(): https://esp-idf.readthedocs.io/en/latest/api-reference/bluetooth/controller_vhci.html#_CPPv229esp_bt_controller_mem_release13esp_bt_mode_t

It's possible to either release the BT-Classic-only memory at runtime (approx 30KB of the 64KB), or to release the entire 64KB. It's not possible to release memory which is currently used by the Bluetooth controller. Releasing BT controller memory is permanent, the only way to claim it back (ie to re-enable those BT modes) is to restart.

Regarding memory for the MicroPython heap, there are two other (potential) issues which spring to mind here:

Those last two lines don't make any sense to me. If I use a 96K MP heap, then there's a report 7232b free. If I use a 6K MP heap (-90K), then the free ram only jumps to 80444. Shouldn't it jump to 99392 (96K + 7232)?

That seems odd to me. You may get some more clues by calling heap_caps_print_heap_info(MALLOC_CAP_8BIT): https://esp-idf.readthedocs.io/en/latest/api-reference/system/mem_alloc.html#_CPPv225heap_caps_print_heap_info8uint32_t

dpgeorge commented 7 years ago

Thanks @projectgus for the info. It looks like we can make progress here in a few ways: disable classic BT so less RAM is needed overall, and have some way to completely disable BT from within Python so that a user can reclaim memory if they don't need BLE. Also, it may be better to allocate the MP heap dynamically (at runtime) to get around any static allocation issues.

bmeisels commented 7 years ago

@MrSurly I tried the newest commit on the branch and keep crashing. Does the current commit work for you?

MrSurly commented 6 years ago

@MrSurly I tried the newest commit on the branch and keep crashing. Does the current commit work for you?

No, that's the point of this post.

nickzoic commented 6 years ago

G'day @bmeisels

Sadly the BT support in MicroPython/ESP32 is still very much a work in progress and we've hit a number of problems getting it implemented ... see the comments in this issue for details. I'm hoping we'll get there eventually but it'll require more work to get something usable ...

bmeisels commented 6 years ago

@nickzoic @MrSurly I understand that this feature is far from production. I must have skipped over the part in the original post mentioning it doesn't run.

The previous attempt (dev-bluetooth) worked when I tested it. What has changed in dev-bluetooth-2 which is causing increased use of memory? Is this caused by the updated idf or by changes to the implementation of the Bluetooth micropython module?

I would like to help with debugging and trying to get this working.

MrSurly commented 6 years ago

MP has been updated to a relatively new version of the IDF -- as I stated above, perhaps too many static allocations in the .BSS segment? But that's just a guess. dev-bluetooth-2 doesn't even really have any code to speak of; just turning on BT in sdkconfig is enough to eat up all the RAM.

I still want to make BLE work in MP (would make my life much easier -- I have projects I've re-written from Python to C++), but my bandwidth is severely limited right now.

aykevl commented 6 years ago

I've tried this branch but it doesn't seem to work at all. The error:

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4324
load:0x40078000,len:0
load:0x40078000,len:10992
entry 0x4007a6c4
I (426) cpu_start: Pro cpu up.
I (426) cpu_start: Single core mode
I (426) heap_init: Initializing. RAM available for dynamic allocation:
I (429) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (435) heap_init: At 3FFDC360 len 00003CA0 (15 KiB): DRAM
I (442) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (448) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (454) heap_init: At 40092CE8 len 0000D318 (52 KiB): IRAM
I (461) cpu_start: Pro cpu start user code
I (31) cpu_start: Starting scheduler on PRO CPU.
abort() was called at PC 0x400824c6 on core 0

Backtrace: 0x4008a5f3:0x3ffe3bc0 0x4008a61f:0x3ffe3be0 0x400824c6:0x3ffe3c00 0x400825a7:0x3ffe3c30 0x4007a63f:0x3ffe3c70 0x4007a7d2:0x3ffe3e70 0x40007c31:0x3ffe3eb0 0x4000073d:0x3ffe3f20

Rebooting...
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
Guru Meditation Error of type IllegalInstruction occurred on core  0. Exception was unhandled.
[...many more of these lines until the WDT kicks in...]

It may be caused by a faulty toolchain/SDK setup, see #237.

Note that this error occurs even before I get to a REPL.


With self-built toolchain (not the one from Espressif) the error is a bit different, without the Guru Meditation Error. Apparently it calls abort() from within start_cpu0_default due to lack of memory:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4348
load:0x40078000,len:0
load:0x40078000,len:10992
entry 0x4007a6c4
I (426) cpu_start: Pro cpu up.
I (426) cpu_start: Single core mode
I (426) heap_init: Initializing. RAM available for dynamic allocation:
I (429) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (436) heap_init: At 3FFDC370 len 00003C90 (15 KiB): DRAM
I (442) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (448) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (454) heap_init: At 40092CE8 len 0000D318 (52 KiB): IRAM
I (461) cpu_start: Pro cpu start user code
I (31) cpu_start: Starting scheduler on PRO CPU.
abort() was called at PC 0x400824c6 on core 0

Backtrace: 0x4008a5f3:0x3ffe3bc0 0x4008a61f:0x3ffe3be0 0x400824c6:0x3ffe3c00 0x400825a7:0x3ffe3c30 0x4007a63f:0x3ffe3c70 0x4007a7d2:0x3ffe3e70 0x40007c31:0x3ffe3eb0 0x4000073d:0x3ffe3f20

Rebooting...
 0 0L�?�@3

I'm pretty sure it's this line in ESP-IDF calling abort().

MrSurly commented 6 years ago

I've tried this branch but it doesn't seem to work at all.

Correct. Have you read through the comments posted here?

aykevl commented 6 years ago

Correct. Have you read through the comments posted here?

Yes. My interpretation was that it stopped working with any call to the bluetooth subsystem (from Python), but in my case it doesn't even get to a REPL - it crashes on boot.

aykevl commented 6 years ago

I managed to save 33.8kB of RAM, by disabling LAN, see https://github.com/MrSurly/micropython-esp32/pull/17. This way I was able to enter the REPL and enable the BT stack without problems (I think):

MicroPython v1.9.2-452-g2b3b1a7a9-dirty on 2017-12-10; ESP32 module with ESP32
Type "help()" for more information.
>>> import network
>>> bt = network.Bluetooth()
enter network_bt_make_new
before network_bt_init
past queue initializations
before esp_bt_controller_init
I (404027) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
after esp_bt_controller_init
before esp_bt_controller_enable
W (405197) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
I (405357) phy: phy_version: 362.0, 61e8d92, Sep  8 2017, 18:48:11, 0, 2
before esp_bluedroid_init
E (405367) BT: config_parse returned with err code: 2

before esp_bluedroid_enable
before esp_ble_gap_register_callback
after network_bt_init
>>> 
aykevl commented 6 years ago

I managed to enable advertisement, showing that it really is working :D The device is visible from my phone (using nRF Connect). I added advertisement support with this commit: https://github.com/aykevl/micropython-esp32/commit/2f8dd92ce7d43dcb73fb89ce484b5223885285c4

It is also possible to enable GATTS and GATTC. They are enabled, although GATTC logs an error during initialization (E (96244) BT: btc_gattc_call_handler()). Advertisement still works, though.

You can find such chunks of memory by using this method - but sadly it doesn't differentiate between .data and .rodata (the latter doesn't take up RAM).

MrSurly commented 6 years ago

@aykevl It's a start. If it's possible to move forward w/ BLE, then the real issue to hammer out is the API

nickzoic commented 6 years ago

If it's possible to enable Ethernet at runtime only if it's used, I'm definitely all for that ... I thought we already were doing that? Anyway, I agree that BT will probably have a more enthusiastic following than Ethernet and if the only way to do this is a compile-time flag I'm happy to do that too.Might just mean we need multiple pre-built builds.

------Nick

MrSurly commented 6 years ago

If it's possible to enable Ethernet at runtime only if it's used, I'm definitely all for that ... I thought we already were doing that?

We're calling "init" at runtime. But just compiling it in reserves .BSS.

aykevl commented 6 years ago

I plan to look into enabling Ethernet at runtime, unless someone else picks it up. Note that it not only helps Bluetooth, but would probably make it possible to enlarge the MP heap to 128kB (from 96kB) - a significant improvement.

EDIT: if anyone wants to take a look, the buffers are defined here: https://github.com/espressif/esp-idf/blob/master/components/ethernet/emac_main.c#L63

YanMinge commented 6 years ago

@MrSurly , do you solve the problem, I also port the latest esp-idf one month ago, and when i call esp_bt_controller_init, it will cause crash. I have no idea for it.

MrSurly commented 6 years ago

@YanMinge Development has moved here: https://github.com/MrSurly/micropython/tree/dev-bluetooth-esp32

I have not had much time to work on it.

pvanallen commented 6 years ago

Is there any update on the BLE progress in ESP32 MicroPython?

MrSurly commented 6 years ago

No, not from my end. MP development (for me) often involves having to solve a specific need. If/when I have another project that absolutely has to have BLE, I'll revisit this.

aykevl commented 6 years ago

Over at the nrf port (https://github.com/tralamazza/micropython) we're thinking about working on it soonish (CC @glennrub).

The idea is to define a common API for both ports so most of the implementation can be shared between ports. This is a bit more work initially but should make it possible to use the same NUS console (REPL over BLE) on both ports, for example.

averri commented 6 years ago

Have you tried the new boards with 4 Mb of PSRAM or more?

Refs.:

aykevl commented 6 years ago

I don't think available RAM is a blocking issue, we just have to be a little bit more careful in how we allocate it. For example, the current configuration (last time I looked) was that it allocates about 90kB in .bss, which may give problems. But there is a large area of heap which is unused, where the MicroPython heap should probably be put instead (solving most of these RAM issues). It would even increase the available RAM to ~110kB.

averri commented 6 years ago

@aykevl, thanks for that information. That's great because once the issue is resolved, we can use the standard ESP32 boards with no PSRAM.

heltucosta commented 6 years ago

Hey, been looking forward to use BLE with esp32 and micropython and would love to help in any way if possible. Are there any updates on the progress?

aykevl commented 6 years ago

The latest info is here: https://github.com/micropython/micropython/issues/3809#issuecomment-407469624

This fork of MicroPython has long since been merged upstream.

dpgeorge commented 5 years ago

BLE support for esp32 is being implemented upstream via the following PR: micropython/micropython#5051