Core2, BLE, serial monitoring stops after power-cycle



  • I have some example BLE code for collecting data from a BLE temperature probe that I'm using with a Core2 (Visual Studio + PlatformIO). All of this BLE code works for my testing purposes. If I restart/reboot the unit, it works perfectly fine, but if I power-cycle the Core2 the serial connection no longer works. In that PlatformIO no longer shows the serial output. That said, the unit boots-up perfectly fine and carries on with it's scanning and printing data to the screen. Just no serial monitoring?

    When this happens, if I just unplug and re-plug in the serial/usb cable, then restart the serial monitoring (in PlatformIO), everything is fine. I've tried on two different Core2 units and the both do the same thing. It appears that there is something in this code that's causing it?

    Can anyone help with this? Any ideas on whether this is a coding issue or a possibly module issue causing the serial to fail? I really can't see what could be causing this?

    #include <Arduino.h>
    #include <M5Core2.h>
    
    */
    
    /**
     * A BLE client example that is rich in capabilities.
     * There is a lot new capabilities implemented.
     * author unknown
     * updated by chegewara
     */
    
    #include "BLEDevice.h"
    //#include "BLEScan.h"
    
    // The remote service we wish to connect to.
    static BLEUUID serviceUUID("a75cc7fc-c956-488f-ac2a-2dbc08b63a04");
    // The characteristic of the remote service we are interested in.
    static BLEUUID charUUID("7edda774-045e-4bbf-909b-45d1991a2876");
    
    static boolean doConnect = false;
    static boolean connected = false;
    static boolean doScan = false;
    static BLERemoteCharacteristic *pRemoteCharacteristic;
    static BLEAdvertisedDevice *myDevice;
    
    static void notifyCallback(
        BLERemoteCharacteristic *pBLERemoteCharacteristic,
        uint8_t *pData,
        size_t length,
        bool isNotify)
    {
        Serial.print("Notify callback for characteristic ");
        Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
        Serial.print(" of data length ");
        Serial.println(length);
        /*
         * meat_raw, ambient_raw, offset, whatever = struct.unpack('<hhhh', value)
        meat = meat_raw / 16
        # 6,33 ist ein anhand mehrerer Wertepaare üer Excel ermittelter Faktor, k.A. wo dieser herkommt....
        ambient = (meat_raw + max(0, (ambient_raw - offset)) * 6.33) / 16
    
         */
        int meat_raw = ((pData[1] << 8) + (pData[0]));
        float temp_int = float(meat_raw) / 16;
        int ambient_raw = ((pData[3] << 8) + (pData[2]));
        int offset = ((pData[5] << 8) + (pData[4]));
        float ambient = float(meat_raw + max(0, (ambient_raw - offset)) * 6.33) / 16;
    
        M5.Lcd.clearDisplay();
        M5.Lcd.setCursor(0, 10);
        M5.Lcd.print("temp int: ");
        M5.Lcd.println(temp_int);
        M5.Lcd.print("ambient int: ");
        M5.Lcd.println(ambient);
    
        Serial.print("data: ");
        Serial.println((char *)pData);
        Serial.print("temp int: ");
        Serial.println(temp_int);
        Serial.print("ambient: ");
        Serial.println(ambient);
    }
    
    class MyClientCallback : public BLEClientCallbacks
    {
        void onConnect(BLEClient *pclient)
        {
        }
    
        void onDisconnect(BLEClient *pclient)
        {
            connected = false;
            Serial.println("onDisconnect");
        }
    };
    
    bool connectToServer()
    {
        Serial.print("Forming a connection to ");
        Serial.println(myDevice->getAddress().toString().c_str());
    
        BLEClient *pClient = BLEDevice::createClient();
        Serial.println(" - Created client");
    
        pClient->setClientCallbacks(new MyClientCallback());
    
        // Connect to the remove BLE Server.
        pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
        Serial.println(" - Connected to server");
    
        // Obtain a reference to the service we are after in the remote BLE server.
        BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
        if (pRemoteService == nullptr)
        {
            Serial.print("Failed to find our service UUID: ");
            Serial.println(serviceUUID.toString().c_str());
            pClient->disconnect();
            return false;
        }
        Serial.println(" - Found our service");
    
        // Obtain a reference to the characteristic in the service of the remote BLE server.
        pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
        if (pRemoteCharacteristic == nullptr)
        {
            Serial.print("Failed to find our characteristic UUID: ");
            Serial.println(charUUID.toString().c_str());
            pClient->disconnect();
            return false;
        }
        Serial.println(" - Found our characteristic");
    
        // Read the value of the characteristic.
        if (pRemoteCharacteristic->canRead())
        {
            std::string value = pRemoteCharacteristic->readValue();
            Serial.print("The characteristic value was: ");
            Serial.println(value.c_str());
        }
    
        if (pRemoteCharacteristic->canNotify())
            pRemoteCharacteristic->registerForNotify(notifyCallback);
    
        connected = true;
        return true;
    }
    /**
     * Scan for BLE servers and find the first one that advertises the service we are looking for.
     */
    class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
    {
        /**
         * Called for each advertising BLE server.
         */
        void onResult(BLEAdvertisedDevice advertisedDevice)
        {
            Serial.print("BLE Advertised Device found: ");
            Serial.println(advertisedDevice.toString().c_str());
    
            // We have found a device, let us now see if it contains the service we are looking for.
            if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID))
            {
    
                BLEDevice::getScan()->stop();
                myDevice = new BLEAdvertisedDevice(advertisedDevice);
                doConnect = true;
                doScan = true;
    
            } // Found our server
        }     // onResult
    };        // MyAdvertisedDeviceCallbacks
    
    void setup()
    {
    
        /*
        
        It seems we have a M5Core2 problem. All of this BLE code works, but if I power off the unit and then on again, the serial connection no longer works.
        If I restart/reboot the unit, it works perfectly fine... The unit boots-up perfectly fine and carries on with it's scanning and printing of data. In that
        PlatformIO no longer shows the serial output.
    
        When this happens, if I just unplug and re-plug in again the serial/usb cable, then restart the serial monitoring, everything is fine.
    
        I've tried on two different Core2 units and the both do the same thing. It appears that there is something in this code that's causing it?
     
        */
    
        //                      kMBusModeOutput, powered by USB or Battery
        //                      kMBusModeInput, powered by outside input
        M5.begin(true, true, true, true, kMBusModeOutput);
        // M5.begin(true,true,true,true,kMBusModeInput);
    
        M5.Axp.SetLed(true); // Lets just turn this on so we know we're up and running
        M5.Lcd.println("Boot(ing)");
    
        // Loop while no serial: yet this never reports their is a problem?
        while (!Serial)
        {
            M5.Lcd.clearDisplay();
            M5.Lcd.setCursor(0, 0);
            M5.Lcd.println("No serial");
            Serial.begin(115200);
            delay(1000);
        }
    
        Serial.println("Starting Arduino BLE Client application...");
        BLEDevice::init("");
    
        // Retrieve a Scanner and set the callback we want to use to be informed when we
        // have detected a new device.  Specify that we want active scanning and start the
        // scan to run for 5 seconds.
        BLEScan *pBLEScan = BLEDevice::getScan();
        pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
        pBLEScan->setInterval(1349);
        pBLEScan->setWindow(449);
        pBLEScan->setActiveScan(true);
        pBLEScan->start(5, false);
    } // End of setup.
    
    // This is the Arduino main loop function.
    void loop()
    {
        // If the flag "doConnect" is true then we have scanned for and found the desired
        // BLE Server with which we wish to connect.  Now we connect to it.  Once we are
        // connected we set the connected flag to be true.
        if (doConnect == true)
        {
            if (connectToServer())
            {
                Serial.println("We are now connected to the BLE Server.");
            }
            else
            {
                Serial.println("We have failed to connect to the server; there is nothin more we will do.");
            }
            doConnect = false;
        }
    
        // If we are connected to a peer BLE Server, update the characteristic each time we are reached
        // with the current time since boot.
        if (connected)
        {
            String newValue = "Time since boot: " + String(millis() / 1000);
            Serial.println("Setting new characteristic value to \"" + newValue + "\"");
    
            // Set the characteristic's value to be the array of bytes that is actually a string.
            pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
        }
        else if (doScan)
        {
            BLEDevice::getScan()->start(0); // this is just sample to start scan after disconnect, most likely there is better way to do it in arduino
        }
    
        delay(1000); // Delay a second between loops.
    } // End of loop
    '''


  • Hello @Minxster

    calling Serial.begin(115200); multiple times has been known to lead to strange results. Maybe that is your issue?

    BTW: calling M5.begin() already sets up Serial for you.

    Thanks
    Felix



  • Hi Felix (@felmue) the !Serial check never actually re-tries to re-start the console thank-fully. I only left the code in to try and keep it vanilla for the original/source.

    That said I have just now taken it out to be 110% sure it's not causing an issue. But sadly this has made no change to the problem. I think I'll have to run through the code line by line to try and find which command actually causes the failure. I'll report back when i find it.



  • From what you have said it looks like the issue is with the PC side.
    If so this is normal and you need to restart the PC connection every time the terminal is dropped by the core.
    I get this behaviour with VS Thonny, Arduino and many more programs.



  • @ajb2k3 it's defiantly code related. I can upload other code and have no issues with powering the unit off/on and the USB serial connection keeps on working. It's just this particular set of code that stops it working.

    I actually went through the whole of setup() and put in an infinite loop after each line of code, starting from the end and worked my way all the way back. And the problem still occurs even if setup() runs no actual code, just the infinite loop. This lead me to showing it was either something in all the static declarations or from the #include. I've not had chance to go back to it today to slowly remove more bits out.

    If you actually upload this code, as is, to a Core2 device, you'll see it for yourself. I'll report back when I've stripped back even more code.



  • Hello @Minxster
    Not sure if it is necessary to put Serial.begin(9600) for this set of code/device. You can try adding it. Or you can check if you're missing any definitions.



  • @labixiaoxin8888 thanks for the idea. The M5.begin () automatically starts serial.begin. I have the whole loop to capture if serial has not started and indeed it never fires off.

    When I compile the core and upload it, the unit + code + serial.print all work perfectly fine. It's only when I power off and on again, that I find that the serial connect has stopped and will not start without manually removing the cable.

    As we know, powering off the unit (core2) doesn't actually fully turn it off since the serial is still running normally. This is why it seems like a software issues. As I mentioned in a previous post, I ran through trying to find at which line this problem occurred. But I went all the way through to the first line of setup(), without finding the issue. This means the only thing left is a problem with the initial declarations.

    In fact I'll bodge some code on this issue just now and see what I can find. I honestly thought it would have been something obvious, when I first posted this.



  • Well, that didn't take too long to work how much of a muppet I am! It turns out, there's nothing wrong. If I'm powering the Core2 off and on, the USB connection does not re-start properly. No matter what code/sketch I upload.

    I think is coming down to a driver/PC issue! I should really have looked at this problem using a completely different computer!

    Needless to say, it's not specific to this code (above), but a problem elsewhere! DOH!