How to save more RAM?

How to save more RAM memory from Bluetooth + Wi-Fi?

My additional memory requirement is 100KB, either in-heap memory or global memory. And both Bluetooth and Wi-Fi are enabled at the same time.

I’m using the 8720DN, a module with only 512KB of RAM
When I enable Bluetooth, Wi-Fi, and MQTT+TLS tasks, the heap memory of FreeRTOS is only 30KB.

How to optimize and save more memory space?
For example, by disabling or stopping some unnecessary functions of Bluetooth and Wi-Fi, can more RAM be freed up?

Hi @White_Jason,

Can I check is this for Standard SDK or Arduino SDK?

Could you show your code that you wish to optimise?

Thank you.

I want to save 100KB to do the some new Tasks to improve the IoT UE.

  1. Connection Management, include auto reconnect/change connection channel.
  2. Save data into Flash due to the offline, bad network env.
  3. Micro Gateway/Edge that can parse the data according to the download config.
  4. Execute some micro rule engine script by above gateway parse engine.
  5. Auto timer script with above engine.
  6. Micro web service in AP/STA mode, that can let the user config the wifi ssid/password, and provide some pages to let the user view the device’s telemetry and attribute, without Bluetooth APP and MQTT Server side webpage.

here bellow attached is my code copied from Ameba Arduino examples with FreeRTOS task creation.
I found the memory usage like bellow:

  1. Bletooth with Ble.Init(), 150KB, global static + rtos heap;
  2. WiFi + MQTT, 200KB
  3. TLS, 50~60KB

Can you give me the main memory usage details?

#include "Ds1302.h"

Ds1302 rtc(PA14, PA12, PA13);
TaskHandle_t mqttTaskHandle = NULL;

  

#include "BLEDevice.h"
#define UART_SERVICE_UUID      "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX   "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define STRING_BUF_SIZE 100

BLEService UartService(UART_SERVICE_UUID);
BLECharacteristic Rx(CHARACTERISTIC_UUID_RX);
BLECharacteristic Tx(CHARACTERISTIC_UUID_TX);
BLEAdvertData advdata;
BLEAdvertData scndata;
bool notify = false;

void readCB (BLECharacteristic* chr, uint8_t connID) {
    Serial.print("Characteristic ");
    Serial.print(chr->getUUID().str());
    Serial.print(" read by connection ");
    Serial.println(connID);
}

void writeCB (BLECharacteristic* chr, uint8_t connID) {
    Serial.print("Characteristic ");
    Serial.print(chr->getUUID().str());
    Serial.print(" write by connection ");
    Serial.println(connID);
    if (chr->getDataLen() > 0) {
        Serial.print("Received string: ");
        Serial.print(chr->readString());
        Serial.println();
    }
}

void notifCB(BLECharacteristic* chr, uint8_t connID, uint16_t cccd) {
    if (cccd & GATT_CLIENT_CHAR_CONFIG_NOTIFY) {
        //printf("Notifications enabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        Serial.print("Notifications enabled on Characteristic");
        notify = true;
    } else {
        //printf("Notifications disabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        Serial.print("Notifications disabled on Characteristic");
        notify = false;
    }
    Serial.print(chr->getUUID().str());
    Serial.print(" for connection");
    Serial.println(connID);
}

void connectBluetooth(){

  advdata.addFlags(); //GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED
  //advdata.addData((const uint8_t*)"020106080948554C4B4D414E12FFFFFF20208011F6C4487F4E0244DD010000", sizeof("020106080948554C4B4D414E12FFFFFF20208011F6C4487F4E0244DD010000"));
  advdata.addCompleteName("BrandName");
  scndata.addCompleteServices(BLEUUID(UART_SERVICE_UUID));

  Rx.setWriteProperty(true);
  Rx.setWritePermissions(GATT_PERM_WRITE);
  Rx.setWriteCallback(writeCB);
  Rx.setBufferLen(STRING_BUF_SIZE);
  Tx.setReadProperty(true);
  Tx.setReadPermissions(GATT_PERM_READ);
  Tx.setReadCallback(readCB);
  Tx.setNotifyProperty(true);
  Tx.setCCCDCallback(notifCB);
  Tx.setBufferLen(STRING_BUF_SIZE);

  UartService.addCharacteristic(Rx);
  UartService.addCharacteristic(Tx);

  BLE.init();
  //BLE.setDeviceName("Brand");
  //BLE.configAdvert()->stopAdv();
  BLE.configAdvert()->setAdvData(advdata);
  BLE.configAdvert()->setScanRspData(scndata);
  BLE.setDeviceName("BrandName222222");
  //BLE.configAdvert()->startAdv();
  BLE.configServer(1);
  BLE.addService(UartService);
  BLE.beginPeripheral();
}

#include <WiFi.h>

char ssid[] = "Office_NETGEAR";
char password[] = "1234567890";
TaskHandle_t TaskHandle_WiFiConnect;
void wifi_connect_task(void *pvParameters){
    Serial.println("WiFi Connect Task Started");
    WiFi.begin(ssid, password);
    for (int i = 0; i < 30; ++i) { // 30 attempts, ~3-10 seconds
        if (WiFi.status() == WL_CONNECTED) {
            Serial.println("Connected to WiFi!");
            break;
        }
        vTaskDelay(pdMS_TO_TICKS(1000)); // Wait for 1 second
    }
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("Failed to connect to WiFi. Please check your settings.");
    }
    vTaskDelete(NULL); // Delete this task if it's no longer needed
}

void asyncConnectWiFi(){
    Serial.println("asyncConnectWiFi 1111111111111");
    xTaskCreate(
        wifi_connect_task,          /* Task function */
        "WiFi Connect",            /* Name of task */
        2048,                      /* Stack size */
        NULL,                      /* Task input parameter */
        1,                         /* Priority of the task */
        &TaskHandle_WiFiConnect);  /* Task handle */
    Serial.println("asyncConnectWiFi 22222222222222");
}

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  //rtc.init(); 
  asyncConnectWiFi();
  asyncConnectBluetooth();
  //createHugeArray();
}

const int array_length1 = 10 * 1024;
unsigned char myArray1[array_length1]; 

void createHugeArray() {
    int array_length = 1 * 1024; 
    unsigned char* myArray = (unsigned char*)pvPortMalloc(array_length); 
    if (myArray != NULL) {
        vTaskDelay(pdMS_TO_TICKS(100));
        Serial.print("First address: ");
        Serial.println((unsigned long)&myArray[0], HEX); 
        vTaskDelay(pdMS_TO_TICKS(50)); 
        Serial.print("Final address: ");
        Serial.println((unsigned long)&myArray[array_length - 1], HEX); 

        Serial.print("First address: ");
        Serial.println((unsigned long)&myArray1[0], HEX); 

        Serial.print("Final address: ");
        Serial.println((unsigned long)&myArray1[array_length1 - 1], HEX); 

        vPortFree(myArray); 
    } else {
        vTaskDelay(pdMS_TO_TICKS(50)); 
        Serial.println("Memory allocation failed!");
    }
}

void loop() {
  //printTime();
  serial1Update();
  //check_wifi(); // Check WiFi connection status
  print_task(); // Monitor and log task status
  if (WiFi.status() != WL_CONNECTED && mqttTaskHandle != NULL) {
    Serial.println("Network is down, stopping MQTT task.");
    vTaskDelete(mqttTaskHandle);
    mqttTaskHandle = NULL;
  } else if (WiFi.status() == WL_CONNECTED && mqttTaskHandle == NULL) {
    Serial.println("Network is up, starting MQTT task.");
    xTaskCreate(connect_mqtt_task, "MQTT Task", 2048, NULL, 1, &mqttTaskHandle);
  }
  if (BLE.connected(0)) { // Assuming 0 is the connection ID for the BLE connection
    asyncSendBluetoothData(); // Send data over Bluetooth if connected
  }
  //if (mqttClient.connected()) {
  //  asyncSendMQTTData(); // Send data over MQTT if connected
 // }
  delay(100); // Delay to prevent flooding; adjust as necessary

}

void serial1Update(){
  if (Serial1.available()) {
    byte inByte = Serial1.read();
    Serial.println(inByte);
  }
  delay(100);
}

void printTime(){
  Ds1302::DateTime now;
  rtc.getDateTime(&now);
  Serial.print("Current Date/Time: ");
  Serial.print(now.year); Serial.print("-");
  Serial.print(now.month); Serial.print("-");
  Serial.print(now.day); Serial.print(" ");
  Serial.print(now.hour); Serial.print(":");
  Serial.print(now.minute); Serial.print(":");
  Serial.println(now.second);

  delay(1000);
}


void asyncSendBluetoothData(){}
void asyncSendMQTTData(){}

void check_wifi(){
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("connected wifi 44444444444444");
        Serial.print("IP Address: ");
        Serial.println(WiFi.localIP()); // Print the IP address
        delay(1000); // Example: Check every 10 seconds instead of as fast as possible
    } else {
        Serial.println("not connected the wifi 33333333333333333333");
        //WiFi.begin(ssid, password); // Attempt to reconnect
        delay(1000); // Wait a bit before the next check
    }
}

void print_task() {
    Serial.println("===== Task Monitor =====");

    // Total and used heap memory
    uint32_t totalHeap = configTOTAL_HEAP_SIZE;
    uint32_t usedHeap = totalHeap - xPortGetFreeHeapSize();
    uint32_t freeHeap = xPortGetFreeHeapSize();

    Serial.print("Total Heap Size: ");
    Serial.println(totalHeap);
    Serial.print("Used Heap Size: ");
    Serial.println(usedHeap);
    Serial.print("Free Heap Size: ");
    Serial.println(freeHeap);
    displayFreeRam();
    // Task Info
    UBaseType_t uxArraySize = uxTaskGetNumberOfTasks();
    TaskStatus_t *pxTaskStatusArray;
    volatile UBaseType_t uxArraySizeRequired;

    // Allocate array to hold the task info
    pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));

    if (pxTaskStatusArray != NULL) {
        // Generate raw status information about each task
        uxArraySizeRequired = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, NULL);

        Serial.println("Tasks Info:");
        for (int i = 0; i < uxArraySizeRequired; i++) {
            Serial.print("Task ");
            Serial.print(i + 1);
            Serial.print(" [Name: ");
            Serial.print(pxTaskStatusArray[i].pcTaskName);
            Serial.print(", ID: ");
            Serial.print((unsigned long)pxTaskStatusArray[i].xTaskNumber);
            Serial.print(", State: ");
            Serial.print(pxTaskStatusArray[i].eCurrentState);
            Serial.print(", Stack High Water Mark: ");
            Serial.print(pxTaskStatusArray[i].usStackHighWaterMark);
            Serial.println("]");
        }

        // Free the allocated array
        vPortFree(pxTaskStatusArray);
    } else {
        Serial.println("Failed to allocate memory for task info.");
    }
    Serial.println("=========================");
    delay(5000);
}
extern "C" char* sbrk(int incr);

int freeRam() {
  char stackDummy = 0;
  return &stackDummy - reinterpret_cast<char*>(sbrk(0));
}

void displayFreeRam() {
  Serial.print(F("- SRAM left: "));
  Serial.println(freeRam());
}

void bluetooth_connect_task(void *pvParameters) {
    connectBluetooth(); // Call your existing function to set up the BLE service and start advertising
    vTaskDelete(NULL); // Delete this task if it's no longer needed
}

TaskHandle_t TaskHandle_BluetoothConnect;
void asyncConnectBluetooth() {
    xTaskCreate(
        bluetooth_connect_task,   /* Task function */
        "Bluetooth Connect",      /* Name of task */
        2048,                     /* Stack size */
        NULL,                     /* Task input parameter */
        1,                        /* Priority of the task */
        &TaskHandle_BluetoothConnect); /* Task handle */
}


#include <WiFiSSLClient.h>
#include <PubSubClient.h>
//WiFiClient wifiClient;
WiFiSSLClient wifiClient;
PubSubClient mqttClient(wifiClient);
char* rootCABuff =\
"-----BEGIN CERTIFICATE-----\n"\
//........
"MrY=\n"\
"-----END CERTIFICATE-----\n";

char* httpsRootCABuff = "-----BEGIN CERTIFICATE-----\n" \
//..........
"-----END CERTIFICATE-----\n";

char mqttServer[] = "iot.xxxxxxxxxxx.com";
int mqttPort = 8883;
char clientId[]       = "new ID";
char clientUser[]     = "YYYYYYYYYYYYYYYY";
char clientPass[]     = "";
char publishTopic[]   = "v1/devices/me/telemetry";
char publishPayload[] = "hello world";
char subscribeTopic[] = "v1/devices/me/rpc/request/+";
char subscribeTopic1[] = "Upgrade1";
char gwConnectTopic[] = "v1/gateway/connect";
char gwDisConnectTopic[] = "v1/gateway/disconnect";
char gwAttributeTopic[] = "v1/gateway/attributes";
char gwAttributeRequest[] = "v1/gateway/attributes/request";
char gwAttributeResponse[] = "v1/gateway/attributes/response";
char gwTelemetryTopic[] = "v1/gateway/telemetry";
char gwRPCTopic[] = "v1/gateway/rpc";
char gwClaimTopic[] = "v1/gateway/claim";






void connect_mqtt_task(void *pvParameters) {
    wifiClient.setRootCA((unsigned char*)rootCABuff);
    mqttClient.setServer(mqttServer, mqttPort);

    for (;;) {
        if (!mqttClient.connected()) {
            Serial.println("Attempting MQTT connection...");
            if (mqttClient.connect(clientId, clientUser, clientPass)) {
                Serial.print("Connected to MQTT broker: ");
                Serial.println(mqttServer);
                // Subscribe to topics
                mqttClient.subscribe(subscribeTopic);
                
                mqttClient.subscribe(subscribeTopic1);
            } else {
                Serial.print("MQTT connection failed, rc=");
                Serial.println(mqttClient.state());
                // Wait 5 seconds before retrying
                vTaskDelay(pdMS_TO_TICKS(5000));
                continue;
            }
        }else{
          const int temperature = random(35,42);
          String payload = "{\"temperature\":" + String(temperature) + "}";
          mqttClient.publish(publishTopic, payload.c_str());
          Serial.println(payload);
          vTaskDelay(1000);
        }

        // MQTT client loop processing
        mqttClient.loop();
        vTaskDelay(pdMS_TO_TICKS(10));
    }

    // Clean up and delete task if we ever break out of the loop
    vTaskDelete(NULL);
}
TaskHandle_t TaskHandle_ConnectToMqtt;
void asyncInitMQTTClient(){
    Serial.println("asyncInitMQTTClient 1111111111111");
    xTaskCreate(
        connect_mqtt_task,          /* Task function */
        "mqtt",            /* Name of task */
        2048,                      /* Stack size */
        NULL,                      /* Task input parameter */
        1,                         /* Priority of the task */
        &TaskHandle_ConnectToMqtt);  /* Task handle */
    Serial.println("asyncInitMQTTClient 22222222222222");
}

Hi @White_Jason,

Can you test out 2 things?

  1. In FreeRTOSConfig.h, try to increase the configTOTAL_HEAP_SIZE.

  2. Can you increase the stacksize from your existing ino from 2048 to something larger?
    image

Let me know if it does not work, I’ll try to see if I can help you.