Доброго всем дня. Есть прототип 10-ти канального измерителя температуры (esp32s3, запись на SD карту).
- Диапазон измерений от 0.0 до 300.0, дискретность 0.1С
- Измерения происходят 1 раз в 3 секунды
- Один блок измерений выполняется в течении 40 минут (это максимум, меньше может быть, больше нет). Т.е. получается в одном блоке 800 измерений
- Всего может быть максимум 10 блоков. После каждого цикла измерений блок может быть стерт и запись начнется заново в блок №1, а может каждый следующий цикл измерений начать записывать в N+1 блок, после записи 10-го блока, следующая запись будет производиться в блок №1.
- Измерения температуры выполняются по всем десяти каналам, если отсутствует какой-то из температурных датчиков, то по данному каналу выдается значение -99.9 (чтобы потом можно отсортировать и исключить данный канал)
- После каждого измерения все данные температуры собираются в строку char имеющую формат (№ измерения,t1,t2…t10) (т.е. максимальная длина строки 64 байта, пусть будет 65).
Таким образом минимальный размер данных может составлять 65 байт, максимальный = 10x800x65=520000 байт
В процессе измерений запись данных производится на SD карту (допустим 2Gb).
В день планируется выполнять 2 цикла измерений. Если записывать построчно, то в день максимально будет выполнятся 1600 циклов записи на SD карту. Интернет пишет, что у SD карты число циклов стирания-записи (P/E cycles) составляет порядка 1000-5000. Конечно хочется надеяться, что запись будет производится равномерно по всем ячейкам.
Т.е. для карты 2Gb этот ресурс составит (при учете ежедневного использования):
минимум: (2048000байт x 1000циклов)/(2x800x65) = 19692 дней (53 года)
максимум: (2048000x5000/(2x800x65) = 98461 дней (250 лет)
Что-то мне не верится в такой ресурс карты и видится, что правильней было бы записывать данные не построчно, а объединять данные в блоки (к примеру по поминутно) и потом записывать разово.
Тут возникает конфликт интересов:
- Нужно выделить памяти, чтобы хранить такой массив данных (65байт x 20блоков/минута)=1300 байт. Наверное не много в рамках ESP32S3. Документация говорит, что у ESP32S3 520 КБ встроенной SRAM, при этом по факту в зависимости от используемых компонентов и вызываемых им процедур, остается что-то около 200-250Кб, что все равно много.
- Цена возможной потери данных за время измерения (выключилось питание и стало все плохо), когда измеренные данные записались в массив, но не успели записаться на sd карту (в моем случаем я готов пожертвовать минутой данных).
- Думал еще время записи большого блока на SD карту займет много времени и сдвинет по времени измерение температуры (но потом проверил, оно ничтожно мало по отношению к 3 секундам между измерения, поэтому это можно в расчет не брать)
Очень хотелось бы услышать мнение в рамках данной задачи и используемого железа - как правильно выбрать размер массива поl данные с учетом ресурса SD карты. Различных логгеров много кто делал. А может реально ресурс карты такой и есть, и плановая замена карты раз в 5 лет, точно перекрывает риск ее порчи и можно спокойно писать построчно.
Прилагаю немного утрированные скетч, без описания функций, не относящихся к записи данных на карту
#include <FS.h>
#include <SD_MMC.h>
//SPI FOR LTC2984 PIN GPIO CONFIGURATION
#define ADC_MISO_PIN 13 // 13
#define ADC_MOSI_PIN 11 // 11
#define ADC_CLK_PIN 12 // 12
#define ADC_INT1_PIN 35 // 35
#define BUTTON_PRESS 8 // GPIO8
//BUTTON FOR MEASURE CONFIG
int LastState = LOW;
int CurState;
boolean messure_flag = false;
float ch_res[11] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
char tmp2[70] = "%d,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f\n";
unsigned int num_mes;
#define MSC_CLK_PIN 39 //39
#define MSC_CMD_PIN 38 //38
#define MSC_D0_PIN 37 //37
bool onebit = true; // true for 1-bit. 1-bit will ignore the d1-d3 pins. d3 not used in 1-line SD mode, but card's D3 pin must have a 10k pullup
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PRESS, INPUT_PULLUP);
Serial.println("Mounting SDcard");
SD_MMC.setPins(MSC_CLK_PIN, MSC_CMD_PIN, MSC_D0_PIN);
if (!SD_MMC.begin("/sdcard", onebit)) {
Serial.println("Mount Failed");
return;
}
else
{
Serial.println("Mount Complete");
}
num_mes = 0;
removeDir(SD_MMC, "/B1");
createDir(SD_MMC, "/B1");
writeFile(SD_MMC, "/B1/result.txt", "num,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10\n");
}
void loop() {
if (messure_flag)
{
num_mes++;
measure_channel(Ch1, TEMPERATURE);
measure_channel(Ch2, TEMPERATURE);
measure_channel(Ch3, TEMPERATURE);
measure_channel(Ch4, TEMPERATURE);
measure_channel(Ch5, TEMPERATURE);
measure_channel(Ch6, TEMPERATURE);
measure_channel(Ch7, TEMPERATURE);
measure_channel(Ch8, TEMPERATURE);
measure_channel(Ch9, TEMPERATURE);
measure_channel(Ch10, TEMPERATURE);
char tmp[70] = "";
sprintf(tmp, tmp2, num_mes, ch_res[1], ch_res[2], ch_res[3], ch_res[4], ch_res[5], ch_res[6], ch_res[7], ch_res[8], ch_res[9], ch_res[10]);
appendFile(SD_MMC, "/B1/result.txt", tmp);
delay(100);
if (num_mes>799) {messure_flag = false;}
}
int CurState = digitalRead(BUTTON_PRESS);
if (LastState == HIGH && CurState == LOW)
{
messure_flag = true;
}
LastState = CurState;
}