Skip to content

I2C disconnects BLE #58

Description

@thijses

Using the STM32WB55, using I2C (especially using it frequently/intensively) will disconnect BLE devices, and sometimes even crash the whole microcontroller. Presumably, this is caused by an overbearing HAL_LOCK or interrupt disable in the I2C libraries (twi.h refers back to stm32wbxx_hal_i2c.h). PRINT_IPCC_INFO does not print anything when it disconnects. Is there an immediately obvious way to solve/debug this? I was hoping to avoid getting into the low-level stuff with the STM platform, but i suspect i might need to in order to find this one.

Activity

  1. thijses commented on Jul 12, 2023

    @thijses
    Author

    sorry, i realized i should probably be a little more specific:
    when trying to transmit BLE packets and read/write I2C simultaneously, the whole microcontroller hangs for a few seconds and the BLE connection (to the central) fails. If using I2C without also transmitting BLE packets, the connection appears to survive.

  2. fpistm commented on Jul 12, 2023

    @fpistm
    Member

    Well BLE for WB using shared mem and IRQ. Lot of __disable_irq are used in the sharedmem.
    As I don't have your code and based on your inputs, it is not a good idea to perform "simultaneously" BLE action and I2C read as I2C is based on IT.

  3. thijses commented on Jul 12, 2023

    @thijses
    Author

    i know 'simultanious' is not really true on this kind of semi-single-core microcontroller, but how does one check whether the BLE packets have all finished transmitting? (I am using https://github.com/thijses/Arduino-HardwareBLESerial which is (a fork of) a library that just blasts serial data (for easy debugging) over 20-byte BLE packets. This library uses the (legacy(?)) characteristic.setValue(), which refers to writeValue(). Is there a function i can use to wait until all the data in the transmit buffer is successfully transmitted? (or am i fundamentally misunderstanding how the HCI connection to the coprocessor works?)

  4. fpistm commented on Jul 12, 2023

    @fpistm
    Member

    Could you share your full code. Core version, STM32duinoBLE version, STM32WB Copro Wireless Binary version. I gues your board is the Nucleo WB55?

  5. thijses commented on Jul 12, 2023

    @thijses
    Author

    yes, of course (sorry):
    Copro stack: stm32wb5x_BLE_HCILayer_fw.bin version 1.16.0
    platformIO details:
    PLATFORM: ST STM32 (15.4.1) > P-Nucleo WB55RG
    HARDWARE: STM32WB55RG 64MHz, 192KB RAM, 512KB Flash
    PACKAGES:

    • framework-arduinoststm32 @ 4.20200.221104 (2.2.0)
    • framework-cmsis @ 2.50700.210515 (5.7.0)
    • toolchain-gccarmnoneeabi @ 1.90201.191206 (9.2.1)

    i was using STM32duinoBLE version 1.2.3, but i just tested and 1.2.4 shows the same behaviour

    the whole code is excessively large for this question, and technically under NDA. But i'll scrap together some minimal code to reproduce the issue on my end (not that you could actually repeat the hardware without the I2C devices on my PCB).

    right now i have to go, but i'll be back in a few days to test some more (i just remembered BLE.debug() exists)

  6. fpistm commented on Jul 12, 2023

    @fpistm
    Member

    Pio uses an old version of the core and we do not support it. WB cube and the stack used here are not aligned.

  7. thijses commented on Jul 14, 2023

    @thijses
    Author

    first of all, thank you for your continued patience;

    • I'm now running the latest STM32 arduino framework, directly from https://github.com/stm32duino/Arduino_Core_STM32
      (P.S. pio is strange, they are indeed several releases behind, for reasons unbeknownst to me)
    • STM32duinoBLE is still on 1.2.4

    The issue still persists, but i've got some more hints, now that i've actually enabled BLE.debug(Serial):

    edit: turns out NDEBUG was not defined, BLE.debug() was still disabled. When i enable BLE.debug() as well, it crashes when it has to transmit anything demanding over BLE. I'll just stick to 1 debug mode at-a-time for now.

    When it crashes (during extended I2C tests, while it's also trying to print something to the bleSerial (so presumably some packets are still queued up for transmission), it hangs for several seconds, then it printed the following (unique) debug line:

    ble evt: 0x05 payload: 00 01 08 08
    mm evt released: 0x05 buffer addr: 0x20030030

    edit: after enabling BLE.debug() (instead of undefining NDEBUG), it spits out the following:

    HCI EVENT RX <- 04050400010808
    HCI COMMAND TX -> 010A200101
    HCI EVENT RX <- 0413050101080100
    HCI EVENT RX <- 0413050101080100
    HCI EVENT RX <- 0413050101080100
    HCI EVENT RX <- 0413050101080100
    HCI EVENT RX <- 040E04010A2000
    HCI ACLDATA TX -> 0201081B00170004001B0E006D70200920493243657272436F756E7465723A20

    I tried to find what evtcode 0x05 represents, but i think i may be a little out of my depth already. Is it possible that the I2C peripheral code uses similar event (software interrupt?) handlers, but that they overlap, and so the BLE event catcher accidentally caught some of the I2C events (or vice versa)? (truly a guess, not even remotely educated)

    on a completely unrelated note; the links in src/utility/STM32Cube_FW/README.md are broken, because there's 3 'v's instead of 1 (in multiple places). I noticed that in an earlier release (1.15.0) there were also 2 'v's instead of 1.

  8. thijses commented on Jul 17, 2023

    @thijses
    Author

    little update:
    i have made some small steps towards understanding the inner-workings of the STM32duinoBLE code. There's a few callbacks, buffers and abstraction layers to get through, but in HCI.cpp a lot of the important stuff is revealed.
    stuff like:

    #define EVT_DISCONN_COMPLETE 0x05
    #define EVT_NUM_COMP_PKTS    0x13
    

    which answers my questions about that the eventcodes mean, which is nice. Unfortunately, evtcode 0x05 is just a disconnection, which doesn't really help me identify why it disconnects. However, after following the path of the 0x13 evtcode, i found _pendingPkt.
    This handy variable allows me to wait for BLE packets to be 100% done transmitting before doing I2C interactions (to avoid interrupt overlap).

    However, this did NOT solve my problem :( , it seems that simply the act of doing ~100 I2C read/writes in rapid succession (during a time when the HCI is quiet) causes the BLE to die. I'm not sure whether the act of sending another BLE packet after the I2C stuff is what triggers the disconnect, or if that's just how the disconnect is discovered. Either way, there must be some deeper issue than just competing interrupts.

  9. fpistm commented on Jul 17, 2023

    @fpistm
    Member

    on a completely unrelated note; the links in src/utility/STM32Cube_FW/README.md are broken, because there's 3 'v's instead of 1 (in multiple places). I noticed that in an earlier release (1.15.0) there were also 2 'v's instead of 1.

    Thanks, missed that, I' fix it and updated the script which update it automatically: stm32duino/Arduino_Core_STM32@2e75489

    About your issue I have no clue and will not have time soon to try to reproduce nor debug.
    As stated, my first thought was an issue with IRQ which block BLE and probably disconnect it as it considered not maintained or something similar.

  10. thijses commented on Jul 17, 2023

    @thijses
    Author

    absolutely understandable, and no problem.
    I'm going to continue digging for the true cause of the issue (which, may well be hardware after all). If i find something definitive, i'll let you know.

  11. fpistm commented on Mar 28, 2025

    @fpistm
    Member

    Hi @thijses
    Withotu code to reproduce, it's hard to help. Always think it is linked to irq management.
    Could you test with new STM32duinoBLE version, please?

  12. thijses commented on Mar 28, 2025

    @thijses
    Author

    i'll try to do some quick testing next week (probably wednesday)

  13. thijses commented on Apr 2, 2025

    @thijses
    Author

    short answer; yes, the issue appears to persist.
    But i'm tempted to just blame my code at this point.
    My whole code is bulky, technically confidential (and not very well-written, so) i'm not posting it here.
    The snippit of code where the faillure happens is not huge though;
    Similar to the LedControl.ino example, i open a simple connection:

    BLEDevice central = BLE.central();
    if (central) {
      while (central.connected()) {
        checkForCommands(); // check if the user has input any commands in the serial terminal
        if (switchCharacteristic.written()) { // if the remote device wrote to the characteristic, use the received value to control the LED:
          bool newLEDstatus = switchCharacteristic.value() != 0; // any value other than 0
          digitalWrite(debug_LED_green, newLEDstatus ? debug_LED_ACTIVE : !debug_LED_ACTIVE); // update LED state
        } // if-statement
      } // while-loop
    } // if-statement
    

    connection works fine, LED toggles quickly and reliably, untill checkForCommands() starts doing a whole bunch of blocking I2C read/writes.
    Replacing the I2C function with delay(1000); does not kill the connection, so i don't think it's just a blocking function that kills BLE.
    Similarly, doing only a few (<10) read/writes consistantly makes BLE slow down (packets take 1~2 seconds to arrive if sent during/shortly-after I2C stuff), and occaisionally kills BLE (connection timeout on phone side, MCU side sometimes recognises disconnect).
    The I2C code is also needlessly long, but it boils down to just:

    for(uint16_t i=0; i<packetLossTestCount; i++) {
      Wire.beginTransmission(slaveAddress);
      Wire.write(registerToRead);
      Wire.endTransmission();
      Wire.requestFrom(slaveAddress, bytesToRead);
      for(uint8_t i=0; i<bytesToRead; i++) { readBuff[i] = Wire.read(); }
    } // for-loop
    

    using an unmodified, bog-standard #include <Wire.h> lib from stm32duino/Arduino_Core_STM32, initialized to 100kHz (before BLE connection was made)
    The versions of stuff i'm using are:

    • STM32duinoBLE 1.3.7 (according to library.properties)
    • Arduino Code STM32 2.10.1 (i think)

    (i am blissfully ignorant, i just let platformIO pull the latest packages like:

    platform = ststm32
    platform_packages = framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32 ; pio package is out of date. This one includes required build script
    lib_deps =  https://github.com/stm32duino/STM32duinoBLE ; for BLE
    board = nucleo_wb55rg_p
    framework = arduino
    build_flags = -D NDEBUG ; disables extra (BLE) debug
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions