Arduino becomes unresponsive after sometime of operation

Hello everyone, I am using arduino to control a Bluetooth device to keep it alive to avoid low power operation after long time of inactivity, this because I need to use them for automated testing.
My problem is that they work well, but sometimes after long time operation suddenly they stop responding, and I just can get them back by rebooting plugging out and in the USB cable.
Here is my code, hope somebody can let me know what is the issue.

/*
HW control firmware for the Ford AV-SDM board needed to enable AVDXP CT testing.
Serial port based control of power supply and hw keys is implemented in that firmware.
Author: Juan Pablo Villa, Igor Rupcic, Tim-Gerrit Bittner, Rahman, Md Mahfuzur
Date: 02.08.2021
*/
#include <MemoryFree.h>

class ArduinoUno {
public:
long baudrate = 115200;
bool keepBluetoothAlive = false;
int hwNXPPin = 7; //Uno pin as Hw control pin for DC Power Switch control of the Display
int hwNormalModePin = 6; //Uno pin as Hw control pin for Normal-Mode jumper
int hwSDMPwrPin = 5; //Uno pin as Hw control pin for DC Power Switch control of the AV-DXP
int hwBluetooth = 4; //Uno pin as Hw control pin for NXP-Mode jumper
int hwBootloader = 8; //Uno pin as Hw control pin for the bootloader control
int bluetoothController = 9;
int hwRelayNXP_MODE = 10;
int hwRelayAV_DXP_NORMAL_MODE = 11;
int hwRelayAV_DXP_PWR = 12;
int hwRelayAV_BLUETOOTH = 13;

    String pieces[5] = {"", "", "", "", ""};

    ArduinoUno() {
    }

    void arduinoSetup() {
        //Define inputs and outputs
        pinMode(hwBluetooth, OUTPUT);
        pinMode(hwSDMPwrPin, OUTPUT);
        pinMode(hwNormalModePin, OUTPUT);
        pinMode(hwNXPPin, OUTPUT);
        pinMode(hwBootloader, OUTPUT);

        pinMode(bluetoothController, INPUT);
        pinMode(hwRelayNXP_MODE, INPUT);
        pinMode(hwRelayAV_DXP_NORMAL_MODE, INPUT);
        pinMode(hwRelayAV_DXP_PWR, INPUT);
        pinMode(hwRelayAV_BLUETOOTH, INPUT);
        // using low level input HW devices
        digitalWrite(hwBootloader,HIGH);
        digitalWrite(hwNXPPin, LOW);
        digitalWrite(hwSDMPwrPin, LOW);
        digitalWrite(hwBluetooth, LOW);
        digitalWrite(hwNormalModePin, LOW);
        // Start up serial connection
        Serial.begin(baudrate); // baud rate
        Serial.flush();
    }

    void inputCommandParser(String input) { // Helpert function filtering out command logic so that relevant data can be used.
        int openingBracket, closingBracket;
        openingBracket = input.indexOf('(') + 1;
        closingBracket = input.indexOf(')');
        pieces[1] = input.substring(openingBracket, closingBracket);
        pieces[0] = input.substring(0, openingBracket - 1);           
    }

    String readSerial() {
        // Read serial input until carriage return
        pieces[0] = "";
        pieces[1] = "";
        pieces[2] = "";
        pieces[3] = "";
        pieces[4] = "";

        String input = Serial.readStringUntil('\r');
        input.toUpperCase();

        return input;
    }

    void processCommand(String command){
        int counter = 2;
        int lastIndex = 0;
        for (int i = 0; i < command.length(); i++) {
            // Loop through each character and check if it's a comma
            if (command.substring(i, i + 1) == ",") {
                // Grab the piece from the last index up to the current position and store it
                pieces[counter] = command.substring(lastIndex, i);
                // Update the last position and add 1, so it starts from the next character
                lastIndex = i + 1;
                // Increase the position in the array that we store into
                counter++;
            }
            // If we're at the end of the string (no more commas to stop us)
            if (i == command.length() - 1) {
                // Grab the last part of the string from the lastIndex to the end
                pieces[counter] = command.substring(lastIndex, i + 1);
            }
        }
    }

    //Function for setting digital outputs to high and low
    String setPin(int pinNumber, String command, int timeDelay) {
        command.trim();
        if (command == "UP") {
            digitalWrite(pinNumber, LOW); // off
            return "OK";
        } else if (command == "DWN") {
            digitalWrite(pinNumber, HIGH); // on
            return "OK";
        } else if (command == "SELECT") {
            digitalWrite(pinNumber, HIGH);
            delay(timeDelay);
            digitalWrite(pinNumber, LOW);
            return "OK";
        } else {
            return "ERROR";
        }
    }
    //Function for setting digital outputs to high and low with defualt value of 1000 ms.
    String setPin(int pinNumber, String command ) {
        return setPin(pinNumber, command, 1000);
    }

    //helper function for wrong commands
    void raiseError(String command) {
        Serial.println("Wrong command: " + command + ";Type 'help' for supported commands.");
    }

    void selfKill() {
        delete this;
    }

    void executeSetPinCommand(String command, String input){
        String result;
        processCommand(command);
        if (pieces[2] == "NXP_MODE") {
            pieces[2] = String(hwNXPPin);
        } else if (pieces[2] == "AV_DXP_PWR") {
            pieces[2] = String(hwSDMPwrPin);
        } else if (pieces[2] == "BLUETOOTH") {
            pieces[2] = String(hwBluetooth);
        } else if (pieces[2] == "AV_DXP_NORMAL_MODE") {
            pieces[2] = String(hwNormalModePin);
        } else if (pieces[2] == "NONE") {
            digitalWrite(hwNXPPin, LOW);
            digitalWrite(hwSDMPwrPin, LOW);
            digitalWrite(hwBluetooth, LOW);
            digitalWrite(hwNormalModePin, LOW);
            Serial.println("OK");
            return;
        }
        // check for valid command
        if (pieces[2].toInt() == 0 ) {
            raiseError(input);
            return;
        };
        // check for delay  3rd argument
        if (pieces[4] == "") {
            result = setPin(pieces[2].toInt(), pieces[3]);
        } else {
            result = setPin(pieces[2].toInt(), pieces[3], pieces[4].toInt());
        }
        // Setpin error handling
        if (result == "ERROR") {
            raiseError(input);
        } else {
            Serial.println(result);
        }
    }

    void executeStatusRelayCommand(String command, String input){
        String result;
        processCommand(command);
        // read status of the relay
        if (pieces[2] == "NXP_MODE") {
            pieces[2] = String(hwRelayNXP_MODE);
        } else if (pieces[2] == "AV_DXP_PWR") {
            pieces[2] = String(hwRelayAV_DXP_PWR);
        } else if (pieces[2] == "BLUETOOTH") {
            pieces[2] = String(hwRelayAV_BLUETOOTH);
        } else if (pieces[0] == "AV_DXP_NORMAL_MODE") {
            pieces[2] = String(hwRelayAV_DXP_NORMAL_MODE);
        }
        // check for valid command
        if (pieces[2].toInt() == 0 ) {
            raiseError(input);
            return;
        };
        String statusRelay = String(digitalRead(pieces[2].toInt()));
        result = "STATUS_RELAY: "+statusRelay;
        Serial.println(result);
    }

    void executeBootloaderCommand(String command, String input){
        processCommand(command);
        if (pieces[2] == "ON") {
            digitalWrite(hwBootloader, LOW);
            Serial.println("OK");
        }
        else if (pieces[2] == "OFF") {
            digitalWrite(hwBootloader, HIGH);
            Serial.println("OK");
        }
        else {
            raiseError(input);
            return;
        }
    }

    void executeBluetoothActivation(String command, String input){
        processCommand(command);
        if(pieces[2] == "ON"){
            keepBluetoothAlive = true;
            Serial.println("OK");
        }
        else if (pieces[2] == "OFF") {
            switchBluetooth(false);
            keepBluetoothAlive = false;
            Serial.println("OK");
        }
        else {
            raiseError(input);
            return;
        }
    }

    void switchBluetooth(bool ON){ // true means ON and false means OFF
        int bluetoothActive = digitalRead(bluetoothController);
        if(ON){
            if(bluetoothActive == LOW){
                String result = setPin(hwBluetooth, "SELECT", 3000);
            }
        } else {
            if(bluetoothActive == HIGH){
                String result = setPin(hwBluetooth, "SELECT", 3000);
            }
        }
    }

    void keepingBluetoothAlive(){
        if(keepBluetoothAlive){
            switchBluetooth(true);
        }
    }

    void executeHelpCommand(){
        Serial.println("Command                       Description: [Info]: Use serial tool showing more than one line e.g.Arduino Serial Monitor.");
        Serial.println("SETPIN([PIN],DWN)             Holds down the PIN button.Valid PIN: NXP_MODE,AV_DXP_PWR,AV_DISP_PWR,AV_DXP_NORMAL_MODE,NONE");
        Serial.println("SETPIN([PIN],UP)              Releases PIN button.");
        Serial.println("SETPIN([PIN],SELECT,[TIME])   Press PIN button for one sec.[default] or by defined [TIME] in ms ");
        Serial.println("Important:                    Commands above will always return OK, else it will raise and error.");
        Serial.println("                              FAILURE: If HW is damaged e.g. LED defect.");
    }

    void arduinoLoop() {
        String input = readSerial();
        if (input != ""){
            inputCommandParser(input);

            if (pieces[0] == "SETPIN"){
                executeSetPinCommand(pieces[1], input);
            } else if (pieces[0] == "STATUSRELAY") {
                executeStatusRelayCommand(pieces[1], input);
            } else if (pieces[0] == "BOOTLOADER") {
                executeBootloaderCommand(pieces[1], input);
            } else if (pieces[0] == "BLUETOOTH"){
                executeBluetoothActivation(pieces[1], input);
            } else if (pieces[0] == "HELP" || pieces[0] == "H") {
                executeHelpCommand();
            } else {
                raiseError(input);
            }
        }
        Serial.flush();
        keepingBluetoothAlive();
    }

};

ArduinoUno arduino;
int firstIteration = true;
int avgFreeMemory;

void setup(){
arduino.arduinoSetup();
}
void loop() {
arduino.arduinoLoop();
if(firstIteration){
avgFreeMemory = getFreeMemory();
firstIteration = false;
} else if(getFreeMemory() < avgFreeMemory / 2){ // check if there are leak in memory, if so, kill the object and reinstate it
bool keepBluetoothAlive = arduino.keepBluetoothAlive; // keep the old variables alive before destroying the object
arduino.selfKill();
ArduinoUno arduino;
arduino.keepBluetoothAlive = keepBluetoothAlive;
}
}

Hello, do yourself a favour and please read How to get the best out of this forum and modify your post accordingly (including code tags and necessary documentation for your ask).

Please edit your post to add code tags.

Use of String objects can lead to program crashes on AVR based Arduinos, so you should avoid using them. They are never necessary.

However, expect someone to come along shortly and tell you how wonderful his String library is.

@jpvilla1990, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with your project. See About the Installation & Troubleshooting category.

Hello
I´ve made a low level flight about your "sketch" and I think the usage of the datatype string will/could caused problems.

"Arduino becomes unresponsive after sometime of operation"

Even without opening the discussion thread, from this frequent topic heading we pretty much know someone is attempting to use the form of "String"s with the capital "S". :roll_eyes:

Just waiting for the "String Champion" - forget who it is just now - to pop in and explain that it actually can be made to work if you follow the right rules. :+1:

Mostly it is easier simply not to use "String"s.

2 Likes

Interesting, may I ask what is the issue with the object String in arduino enviroments?

Problems with Strings

Now I have to put on a clean shirt.

image

a7

1 Like

@drmpf will give you a different opinion.

Equipped with the right knowledge you can decide what’s your best way forward

——-

please edit your post, select the code part and press the </> icon in the tool bar to mark it as code. It’s barely readable as it stands. (also make sure you indented the code in the IDE before copying, that’s done by pressing ctrlT on a PC or cmdT on a Mac)

I believe he tried. For some reason, contributors quite frequently seem to manage to mark up only half of their code, leaving this sort of mangled mess. I'm not sure what has happened. :worried:

Or is it the forum software doing that?

To put on a clean shirt? :grinning:

If you want some practical help with this, private msg me or email www.pfod.com.au via support. I have a number of tools and libraries for solving these types of problems.

No, it's the forum software. Certain number of spaces at the beginning of a line in the code will result in the forum software marking it as code.

I tried using your library on an old project that had to be rebooted every few hours because of the liberal use of Strings, but I determined that it was more work than simply using c-strings in the first place.

1 Like

Greetings, I thanks all for the given advices, in general I tried to refactor all the code to use only chararrays instead of using the String Class, saddly still sometimes the device become unresponsive after a while, I am not sure if maybe the usb port of the computer is the problem, but anyways here is my new code to see if somebody has any suggestion.

/*
  HW control firmware for the Ford AV-SDM board needed to enable AVDXP CT testing.
  Serial port based control of power supply and hw keys is implemented in that firmware.
  Author: Juan Pablo Villa, Igor Rupcic, Tim-Gerrit Bittner, Rahman, Md Mahfuzur
  Date: 02.08.2021
*/

class ArduinoUno {
    public:
        long baudrate = 115200;
        bool keepBluetoothAlive = false;
        int bluetoothActivationTime = 3000;
        int hwNXPPin = 7; //Uno pin as Hw control pin for DC Power Switch control of the Display
        int hwNormalModePin = 6; //Uno pin as Hw control pin for Normal-Mode jumper
        int hwSDMPwrPin = 5; //Uno pin as Hw control pin for DC Power Switch control of the AV-DXP
        int hwBluetooth = 4; //Uno pin as Hw control pin for NXP-Mode jumper
        int hwBootloader = 8; //Uno pin as Hw control pin for the bootloader control
        int bluetoothController = 9;

        long lengthInput = 100;
        char input [100];
        long indexParameters [3];

        ArduinoUno() {
        }

        void arduinoSetup() {
            //Define inputs and outputs
            pinMode(hwBluetooth, OUTPUT);
            pinMode(hwSDMPwrPin, OUTPUT);
            pinMode(hwNormalModePin, OUTPUT);
            pinMode(hwNXPPin, OUTPUT);
            pinMode(hwBootloader, OUTPUT);

            pinMode(bluetoothController, INPUT);
            // using low level input HW devices
            digitalWrite(hwBootloader,HIGH);
            digitalWrite(hwNXPPin, LOW);
            digitalWrite(hwSDMPwrPin, LOW);
            digitalWrite(hwBluetooth, LOW);
            digitalWrite(hwNormalModePin, LOW);
            // Start up serial connection
            Serial.begin(baudrate); // baud rate
            Serial.flush();
        }

        void cleanInput(){
            for(int i = 0; i < lengthInput; i++){
                    input[i] = '\n';
                }
        }

        bool incomingData(){
            if(Serial.available() > 0){
                return true;
            } else {
                return false;
            }
        }

        int getBufferSize(){
            return Serial.available();
        }

        char processInputChar(){
            // Reads input erasing spaces, converting lowcase to uppercase and processing input
            char incoming = Serial.read();
            // Trimm spaces
            while(incoming == ' '){
                incoming = Serial.read();
            }
            //Converts to Capital
            if(incoming >=97 && incoming <= 122){
                incoming = incoming - 32;
            // Converts open parenthesis into commas
            } else if(incoming == '('){
                incoming = ',';
            // Reads close parenthesis as end of the command
            } else if(incoming == ')'){
                incoming = '\n';
            }

            return incoming;
        }

        void printCharArray(char array[]){
            int i = 0;
            while (true){
                Serial.print(array[i]);
                if(array[i] == '\n'){
                    break;
                }else{
                    i++;
                }
            }
        }

        bool readSerial() {
            // Read serial input until carriage return

            if(incomingData()){
                cleanInput();
                delay(1000); //TODO: get bytes until \r
                int bufferSize = getBufferSize();
                for (int i = 0; i < bufferSize; i++){
                    input[i] = processInputChar();
                }
                input[bufferSize] = '\n';
                return true;
            }else{
                return false;
            }
        }

        long getLengthCharArray(char array[]){
            long size = 0;
            while(array[size] >= 48 && array[size] <= 125){
                size++;
            }
            return size;
        }

        // Process to compare if a bytearray is equal to the first separated word in the input
        bool commandCompare(char compared[]){
            bool allTrue = true;
            long length = getLengthCharArray(compared);
            int i = 0;
            for (i = 0; i < length; i++){
                if(input[i] == '\n' || input[i] == ','){
                    break;
                }
                if(input[i] != compared[i]){
                    allTrue = false;
                }
            }
            if(input[length] != '\n' && input[length] != ','){
                allTrue = false;
            }else if(i == 0){
                allTrue = false;
            }
            return allTrue;
        }

        // Method to compare one of the input parameters with a chararray
        bool parameterCompare(char compared[], long parameter){
            bool allTrue = true;
            long length = getLengthCharArray(compared);
            long index = indexParameters[parameter];
            int i = 0;
            for (i = 0; i < length; i++){
                if(input[index] == '\n' || input[index] == ','){
                    break;
                }
                if(input[index] != compared[i]){
                    allTrue = false;
                }
                index++;
            }
            if(input[index] != '\n' && input[index] != ','){
                allTrue = false;
            }else if(i == 0){
                allTrue = false;
            }
            return allTrue;
        }

        // Method that assigns the index of the parameters according to the position of the commas
        void processCommand(){
            long numberParameters = 0;
            indexParameters[0] = 0;
            indexParameters[1] = 0;
            indexParameters[2] = 0;
            for (int i = 0; i < lengthInput; i++){
                if(input[i] == ','){
                    indexParameters[numberParameters] = i + 1;
                    numberParameters++;
                }
                if(input[i] == '\n'){
                    break;
                }
            }
        }

        int processTimeDelayParameter(){
            int timeDelay = 0;
            int index = indexParameters[2] + 1;
            int length = lengthInput - index;
            int multiplier = 1;
            int countDecimals = 0;
            for (index; index < length; index++){
                if(input[index] == '\n'){
                    break;
                }
                countDecimals++;
                multiplier = multiplier * 10;
            }
            countDecimals++;
            index = indexParameters[2];
            length = index + countDecimals;
            for (index; index < length; index++){
                int number = input[index] - '0';
                timeDelay = timeDelay + (number * multiplier);
                multiplier = multiplier / 10;
            }
            Serial.println(timeDelay);
            return timeDelay;
        }

        //Function for setting digital outputs to high and low
        bool setPin(int pinNumber, int timeDelay) {
            if (parameterCompare("UP",1)) {
                digitalWrite(pinNumber, LOW); // off
                return true;
            } else if (parameterCompare("DWN",1)){
                digitalWrite(pinNumber, HIGH); // on
                return true;
            } else if (parameterCompare("SELECT",1)){
                digitalWrite(pinNumber, HIGH);
                delay(timeDelay);
                digitalWrite(pinNumber, LOW);
                return true;
            } else {
                return false;
            }
        }
        //Function for setting digital outputs to high and low with defualt value of 1000 ms.
        bool setPin(int pinNumber) {
            return setPin(pinNumber, 1000);
        }

        //helper function for wrong commands
        void raiseError() {
            Serial.print("Wrong command: ");
            for (int i = 0; i < lengthInput; i++){
                Serial.print(input[i]);
                if(input[i] == '\n'){
                    break;
                }
            }
            Serial.print(";Type 'help' for supported commands.\n");
        }

        void selfKill() {
            delete this;
        }

        // Method to set a pin uppon input command
        void executeSetPinCommand(){
            int pin = 0;
            bool result;
            if (parameterCompare("NXP_MODE", 0)) {
                pin = hwNXPPin;
            } else if (parameterCompare("AV_DXP_PWR", 0)) {
                pin = hwSDMPwrPin;
            } else if (parameterCompare("BLUETOOTH", 0)) {
                pin = hwBluetooth;
            } else if (parameterCompare("AV_DXP_NORMAL_MODE", 0)) {
                pin = hwNormalModePin;
            } else if (parameterCompare("NONE", 0)) {
                digitalWrite(hwNXPPin, LOW);
                digitalWrite(hwSDMPwrPin, LOW);
                digitalWrite(hwBluetooth, LOW);
                digitalWrite(hwNormalModePin, LOW);
                Serial.println("OK");
                return;
            }
            // check for valid command
            if (pin == 0 ) {
                raiseError();
                return;
            };
            // check for delay  3rd argument
            if (indexParameters[2] == 0) {
                result = setPin(pin);
            } else {
                int timeDelay = processTimeDelayParameter();
                result = setPin(pin, timeDelay);
            }
            // Setpin error handling
            if (result == false) {
                raiseError();
            } else {
                Serial.println("OK");
            }
        }

        // Method to set bootloader on or off
        void executeBootloaderCommand(){
            if (parameterCompare("ON", 0)) {
                digitalWrite(hwBootloader, LOW);
                Serial.println("OK");
            } else if (parameterCompare("OFF", 0)) {
                digitalWrite(hwBootloader, HIGH);
                Serial.println("OK");
            }
            else {
                raiseError();
            }
        }

        // Method to keep the bluetooth active or inactive
        void executeBluetoothActivation(){
            if(parameterCompare("ON", 0)){
                keepBluetoothAlive = true;
                Serial.println("OK");
            }
            else if (parameterCompare("OFF", 0)){
                switchBluetooth(false);
                keepBluetoothAlive = false;
                Serial.println("OK");
            }
            else {
                raiseError();
            }
        }

        void switchBluetooth(bool ON){ // true means ON and false means OFF
            int bluetoothActive = digitalRead(bluetoothController);
            if(ON){
                if(bluetoothActive == LOW){
                    digitalWrite(hwBluetooth, HIGH);
                    delay(bluetoothActivationTime);
                    digitalWrite(hwBluetooth, LOW);
                }
            } else {
                if(bluetoothActive == HIGH){
                    digitalWrite(hwBluetooth, HIGH);
                    delay(bluetoothActivationTime);
                    digitalWrite(hwBluetooth, LOW);
                }
            }
        }

        // Method that checks if the bluetooth must be kept alive
        void keepingBluetoothAlive(){
            if(keepBluetoothAlive){
                delay(1000);
                switchBluetooth(true);
            }
        }

        // Method to execute the help command
        void executeHelpCommand(){
            Serial.println("Command                       Description: [Info]: Use serial tool showing more than one line e.g.Arduino Serial Monitor.");
            Serial.println("SETPIN([PIN],DWN)             Holds down the PIN button.Valid PIN: NXP_MODE,AV_DXP_PWR,AV_DISP_PWR,AV_DXP_NORMAL_MODE,NONE");
            Serial.println("SETPIN([PIN],UP)              Releases PIN button.");
            Serial.println("SETPIN([PIN],SELECT,[TIME])   Press PIN button for one sec.[default] or by defined [TIME] in ms ");
            Serial.println("Important:                    Commands above will always return OK, else it will raise and error.");
            Serial.println("                              FAILURE: If HW is damaged e.g. LED defect.");
        }

        void arduinoLoop() {
            bool serialReady = readSerial();
            if (serialReady){
                processCommand();

                if (commandCompare("SETPIN")){
                    executeSetPinCommand();
                } else if (commandCompare("BOOTLOADER")){
                    executeBootloaderCommand();
                } else if (commandCompare("BLUETOOTH")){
                    executeBluetoothActivation();
                } else if (commandCompare("HELP") ||commandCompare("H")){
                    executeHelpCommand();
                } else {
                    raiseError();
                }
            }
            Serial.flush();
            keepingBluetoothAlive();
        }
};

ArduinoUno arduino;

void setup(){
    arduino.arduinoSetup();
}
void loop() {
    arduino.arduinoLoop();
}

Still no code tags…

Bye

Please edit your post, select all code and click the </> button; next save your post.

Besides Strings, another thing that can cause the symptom is writing or reading from beyond the bounds of an array. Examine all array operations to confirm that that is not happening.