Ошибка Low memory available, stability problems may occur.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Здравствуйте.

Использую Arduino UNO

Задача такова - писать на SD карту показания температуры, влажности, освещения.

На данный момент подключил только SD карту и модуль часов DS3231 считываю время и температуру с часов и пишу все это в файл.

Пока тестировал только работу с SD картой все было нормально. Но как только подключил библиотеку часов то памяти SRAM 2KB (ATmega328) сразу стало не хватать. при компиляции выдается предупреждение:

Sketch uses 22 038 bytes (68%) of program storage space. Maximum is 32 256 bytes.
Global variables use 1 718 bytes (83%) of dynamic memory, leaving 330 bytes for local variables. Maximum is 2 048 bytes.
Low memory available, stability problems may occur.

В итоге при создании очередного файла программа зависает.

То есть я правильно понимаю что Arduino UNO не потянет несколько устройств таких как SD карта, часы DS3231, датчик влажности DHT22 и сетевую карту Ethernet ENC28J60?

Или можно поковырять библиотеки уменьшив их размер исключением не востребованных функций, вернее глобальных переменных?

Или есть еще какие либо варианты решения проблемы?

Вот код:

// подключаем библиотеку карты
#include <SdFat.h>
// подключим библиотеку часов
#include <Wire.h>
#include <DS3231.h>

// CS у нас будет на 8 пине
#define SDCSpin 8
// Установим интервал опроса датчиков
#define IntervalDataReadMS 2000
// опередели максимальный размер одного файла в 1 килобайт (1 000 байт)
#define MaxSizeDataFile 1000

// Файл у нас будет состоять из наименования и номера файла. будет обрезаться по размеру чтобы не был слишком большим.
char fileName[13] = "DATA0000.CSV";
//------------------------------------------------------------------------------
// Объявим сам объект SD карты
SdFat sd;
// Объект файл для создания лог файла
SdFile file;
// часы
DS3231 clock;
// структура для хранения даты и времения
RTCDateTime dt;



//------------------------------------------------------------------------------
void setup() {
  // Инициализируем serial
  Serial.begin(9600);
  delay(1000);

  // инициализируем часы
  clock.begin();

  // Инициализируем SD карту
  if (InitSDCard()) {
    // ищем поседний лог файл который был создан чтобы записать в него дату и событие перезагрузки
    InitLogFile();
  }
}
//------------------------------------------------------------------------------
// void setup()

//------------------------------------------------------------------------------
void loop() {
  // пишем в файл
  if (file.open(fileName, FILE_WRITE)) {
    Serial.println("Write data");
    // первая колонка это время
    dt = clock.getDateTime();
    file.print(clock.dateFormat("Y-m-d H:i:s", dt));
    file.print("\t");
    // вторая колонка это температура с часов
    clock.forceConversion();
    file.print(clock.readTemperature());
    file.println();
    file.close();
    int fram = freeRam(); 
    Serial.print("RAM free - ");
    Serial.println(fram);

  }
  else {
    sd.errorHalt("ERR open file 1");
  }

  // проверяем не закончился ли у нас файл
  ControlLogFile();
  delay(200);
}
//------------------------------------------------------------------------------
// void loop()


//------------------------------------------------------------------------------
// Функция инициализации карты памяти
// В случае неудачной инициализации возвращает false и отсанавливает SD
// В случае удачной инициализации возвращает true
bool InitSDCard() {
  // инициализируем SD карту для того чтобы проверить установлена она или нет
  if (!sd.begin(SDCSpin, SPI_FULL_SPEED)) {
    // SPI_HALF_SPEED половина скорости SPI интерфейса если не работает полная скорость SPI_FULL_SPEED
    Serial.println("Не удалась инициализация на полной скорости");
    if (!sd.begin(SDCSpin, SPI_HALF_SPEED)) {
      // не получилось запустить и на половине пишем ошибку и останавливаем SD
      Serial.println("Не удалась инициализация на половине скорости");
      sd.initErrorHalt();
      Serial.println("SD карта не инициализирована!!!");
      return false;
    }
  }
  return true;
}
// bool InitSDCard()
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// функция работы с созданием и контролем размера файла.
void InitLogFile() {
  if (!sd.exists(fileName)) {
    // файла с начальным именем "DATA0000.CSV" не существует. Создаем его
    if (file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) {
      Serial.print("Create file  - ");
      Serial.println(fileName);
    }
    else {
      sd.errorHalt("ERR open file");
    }
    // закрываем файл
    file.close();
  }
  else {
    // файл существует
    Serial.print("Old file have - ");
    Serial.println(fileName);
    // проверим размер файла и если он больше необходимого то создадим новый
    ControlLogFile();
  }
}
// void InitLogFile()
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// функция работы с созданием и контролем размера файла.
void ControlLogFile() {
  uint32_t myFileSize;
  // файл существует
  while (sd.exists(fileName)) {
    // открываем файл на чтение и смотрим размер
    if (file.open(fileName, FILE_READ)) {
      myFileSize = file.fileSize();
      file.close();
      // пишем информацию о файле
      Serial.print("File - ");
      Serial.print(fileName);
      Serial.print("\t size - ");
      Serial.println(myFileSize);
      // если размер найденного файла больше допустимого проверяем есть ли следующий
      if (myFileSize >= MaxSizeDataFile) {
        // извлекаем счетчик
        String currentCounter = (fileName);
        currentCounter = currentCounter.substring(4, 8);
        int fileCount = currentCounter.toInt();
        // добавляем 1
        fileCount++;
        // добавляем нули впереди
        String myStr = String(fileCount);
        int sizeStr = myStr.length();
        while (sizeStr < 4) {
          myStr = "0" + myStr;
          sizeStr++;
        }
        // собираем имя файла
        String strFileName = "DATA" + myStr + ".CSV";
        // переводим строку в char
        strFileName.toCharArray(fileName, sizeof(fileName));
                Serial.print("Char count - ");
                Serial.print(currentCounter);
                Serial.print("\t");
                Serial.print("Int count - ");
                Serial.print(fileCount);
                Serial.print("\t");
                Serial.print("Str count - ");
                Serial.print(myStr);
                Serial.println();

      }
      else
      {
        // размер файла меньше допустимого пишем в него
        Serial.println("Write to file");
        break;
      }
    }
    else {
      sd.errorHalt("ERR open file");
    }
  }
}
// void ControlLogFile()
//------------------------------------------------------------------------------

int freeRam()
{
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

 

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Дежа вю...

А где в коде библиотека для ENC28J60, или памяти не хватает уже на этом этапе? Расковырять библиотеки можно. Можно так-же почитать это http://arduino.cc/en/Reference/PROGMEM и попробовать применить.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Gippopotam пишет:

Дежа вю...

А где в коде библиотека для ENC28J60, или памяти не хватает уже на этом этапе? Расковырять библиотеки можно. Можно так-же почитать это http://arduino.cc/en/Reference/PROGMEM и попробовать применить.

 

До ENC28J60 дело не дошло, подключил только SD карту и SD3231 и место в SRAM кончилось.

PROGMEM мне особо не поможет потому как у меня осталась только одна глобальная переменная и та небольшая. Так что вижу только один путь решения для Arduino UNO это убрать из используемых библиотек неиспользуемый функционал :-)

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Andrey12 пишет:

Gippopotam пишет:

Дежа вю...

А где в коде библиотека для ENC28J60, или памяти не хватает уже на этом этапе? Расковырять библиотеки можно. Можно так-же почитать это http://arduino.cc/en/Reference/PROGMEM и попробовать применить.

 

До ENC28J60 дело не дошло, подключил только SD карту и SD3231 и место в SRAM кончилось.

PROGMEM мне особо не поможет потому как у меня осталась только одна глобальная переменная и та небольшая. Так что вижу только один путь решения для Arduino UNO это убрать из используемых библиотек неиспользуемый функционал :-)

Все-таки дежа-вю...

http://arduino.ru/forum/programmirovanie/sd-card-initsializiruetsya-no-rabotaet-esli-sketch-menee-24k

 

А дело не в простых глобальных переменных, а в глобальных объектах (пардон за терминологию)

// Объявим сам объект SD карты
018	SdFat sd;
019	// Объект файл для создания лог файла
020	SdFile file;
021	// часы
022	DS3231 clock;
023	// структура для хранения даты и времения
024	RTCDateTime dt;

Вот как минимум - в этих

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Попробуйте стандартную библиотеку

#include <SD.h>

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Gippopotam пишет:

А дело не в простых глобальных переменных, а в глобальных объектах (пардон за терминологию)

// Объявим сам объект SD карты
018	SdFat sd;
019	// Объект файл для создания лог файла
020	SdFile file;
021	// часы
022	DS3231 clock;
023	// структура для хранения даты и времения
024	RTCDateTime dt;

Вот как минимум - в этих

но вроде как написано что PROGMEM используется для типов переменных:

prog_char      - a signed char (1 byte) -127 to 128
prog_uchar     - an unsigned char (1 byte) 0 to 255
prog_int16_t   - a signed int (2 bytes) -32,767 to 32,768
prog_uint16_t  - an unsigned int (2 bytes) 0 to 65,535
prog_int32_t   - a signed long (4 bytes) -2,147,483,648 to * 2,147,483,647.
prog_uint32_t  - an unsigned long (4 bytes) 0 to 4,294,967,295

Поэтому для объектов он не применим. Или я неправильно понял?

 

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Gippopotam пишет:

Попробуйте стандартную библиотеку

#include <SD.h>

Пробовал, результат тот же.

И стандартная читает карты только до 4ГБ, сделална на основе SdFat.h более ранней версии.

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Andrey12 пишет:

Gippopotam пишет:

А дело не в простых глобальных переменных, а в глобальных объектах (пардон за терминологию)

// Объявим сам объект SD карты
018	SdFat sd;
019	// Объект файл для создания лог файла
020	SdFile file;
021	// часы
022	DS3231 clock;
023	// структура для хранения даты и времения
024	RTCDateTime dt;

Вот как минимум - в этих

но вроде как написано что PROGMEM используется для типов переменных:

prog_char      - a signed char (1 byte) -127 to 128
prog_uchar     - an unsigned char (1 byte) 0 to 255
prog_int16_t   - a signed int (2 bytes) -32,767 to 32,768
prog_uint16_t  - an unsigned int (2 bytes) 0 to 65,535
prog_int32_t   - a signed long (4 bytes) -2,147,483,648 to * 2,147,483,647.
prog_uint32_t  - an unsigned long (4 bytes) 0 to 4,294,967,295

Поэтому для объектов он не применим. Или я неправильно понял?

 

Это я предложил, если вы решитесь переделывать библиотеки...