Ошибка StoreProhibited при попытке чтения файла в PROGMEM
Я пытаюсь прочитать файл с micro SD на плате ESP32-cam и загрузить его на FTP-сервер, но когда я пытаюсь прочитать данные из открытого файла в unsigned char, это дает мне следующую ошибку:
Guru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x4008c674 PS : 0x00060030 A0 : 0x800ed1c7 A1 : 0x3ffb1e20
A2 : 0x00000000 A3 : 0x3ffd7c78 A4 : 0x00000080 A5 : 0x00000000
A6 : 0x474e5089 A7 : 0x0a1a0a0d A8 : 0x00000000 A9 : 0x3ffb1df0
A10 : 0x00000080 A11 : 0x3ffb66e4 A12 : 0x3ffd7c78 A13 : 0x00000080
A14 : 0x00002494 A15 : 0xff000000 SAR : 0x00000018 EXCCAUSE: 0x0000001d
EXCVADDR: 0x00000000 LBEG : 0x4008c670 LEND : 0x4008c68c LCOUNT : 0x00000007
ELF file SHA256: 0000000000000000
Backtrace: 0x4008c674:0x3ffb1e20 0x400ed1c4:0x3ffb1e30 0x400ed245:0x3ffb1e60 0x400d06e7:0x3ffb1e80 0x400d084f:0x3ffb1f20 0x400d2b5a:0x3ffb1fb0 0x4008efde:0x3ffb1fd0
Rebooting...
Код выглядит следующим образом:
// Wi-Fi и FTP - клиент Lib
#include <WiFi.h>
#include <WiFiClient.h>
#include "ESP32_FTPClient.h"
// MicroSD
#include "driver/sdmmc_host.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "esp_vfs_fat.h"
// Учетные данные FTP-сервера
char ftp_server[] = "192.168.1.50";
char ftp_user[] = "username";
char ftp_pass[] = "password";
// wi-Fi доступ
const char* ssid = "ssid";
const char* password = "psk";
// файл для чтения и загрузки
FILE *fileUpload = NULL;
// ftp client object
ESP32_FTPClient ftp (ftp_server, ftp_user, ftp_pass);
// micro sd initialization
static esp_err_t init_sdcard()
{
esp_err_t ret = ESP_FAIL;
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 10,
};
sdmmc_card_t *card;
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
}
void FTP_upload( void );
void FTP_upload()
{
// initialize file name
char fileName[100];
sprintf(fileName, "/sdcard/img.png");
fileUpload = fopen(fileName, "r+");
// notify reading of the file
Serial.print("Reading file: ");
Serial.println(fileName);
if (fileUpload == NULL)
{
Serial.println("Cannot open file");
return;
}
// получить размер файла
fseek(fileUpload, 0, SEEK_END);
long int size = ftell(fileUpload);
fclose(fileUpload);
// печать размера файла в серийный порт
Serial.print("File size: ");
Serial.println(size);
// Чтение данных в массив unsigned char fileUpload = fopen(fileName, "r+");
unsigned char * in PROGMEM = (unsigned char *) malloc(size);
// отображение выделенной памяти
Serial.print("Allocated memory: ");
Serial.println(sizeof(in));
// read file to allocated memory
int bytes_read = fread(in, sizeof(unsigned char), size, fileUpload); // <------- THIS ROW RISES THE ERROR
// close file
fclose(fileUpload);
// Открыть FTP-соединение
Serial.println("Starting FTP upload...");
ftp.OpenConnection();
//Создать файл и записать в него данные изображения;
ftp.InitFile("Type I");
// изменить удаленный каталог
ftp.ChangeWorkDir("/Shared/");
// имя удаленного файла
String strNome = "img.png";
// преобразовать строку в char
const char *f_name = strNome.c_str();
// создайте новый файл с заданным именем внутри удаленного каталога
ftp.NewFile( f_name );
// write data read above from local file to remote file
ftp.WriteData(in, sizeof(in));
// close remote file
ftp.CloseFile();
// notify completed upload
Serial.println("File uploaded successfully");
// wait
delay(100);
}
void setup() {
// begin serial communication
Serial.begin(115200);
// initialize micro sd
esp_err_t errSD = init_sdcard();
if (errSD != ESP_OK) {
Serial.printf("Не удается инициализировать SD. Код ошибки: 0x%x", errSD);
return;
}
// начать подключение Wi-Fi
WiFi.begin(ssid, password);
// wait for the connection to be estabilished
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// уведомить об успешном соединении
Serial.println("");
Serial.println("WiFi connected");
// показать назначенный IP-адрес
Serial.print("IP: ");
Serial.println(WiFi.localIP());
// вызов процедуры загрузки по FTP
FTP_upload();
}
void loop() {
// пусто
}
Как я могу это решить? Спасибо
@user2959923, 👍1
Обсуждение1 ответ
Решив, я немного изменил метод.
В цикле я читаю часть файла и записываю его в открытый удаленный файл FTP, а затем закрываю оба в конце цикла
// открыть FTP-соединение
ftp.OpenConnection();
// открыть локальный файл
FileUpload = fopen("/sdcard/img.png", "r+");
// инициализировать тип файла
ftp.InitFile("Тип I");
// изменить удаленный каталог
ftp.ChangeWorkDir("/Shared/");
// определение имени удаленного файла
String strName = "img.png";
// преобразовать в char
const char *f_name = strName.c_str();
// создать удаленный файл с заданным именем
ftp.NewFile( f_name );
// read all file in a loop
unsigned char buff[64];
while(!feof(FileUpload)){
// чтение части файла
fread(buff, sizeof(char), sizeof(buff), FileUpload);
// запишите эту часть в удаленный файл
ftp.WriteData(buff, sizeof(buff));
}
// закройте как локальный, так и удаленный файл
fclose(FileUpload);
ftp.CloseFile();
Было бы хорошо получить более конкретное объяснение причины. Одна вещь, которую вы сделали, - это отошли от " malloc ()", что является хорошей идеей. В процессе, похоже, вы исправили утечку памяти, которая была вызвана отсутствием соответствующего вызова " free(). Вы также избавились от
ftp.WriteData(в, sizeof(в));`, который записывал только первые 4 четырех байта того, на что указывает "в", потому что "размер (в)" - это размер указателя, а не размер выделенного блока., @timemage
Для того, что остается, существует вероятность сбоя "fopen", которую вам, вероятно, следует проверить, прежде чем пытаться использовать "Загрузка файлов". Когда дело доходит до "феофа" и "фреда", важно знать, что "феоф" не говорит вам, когда вы находитесь в конце файла. Он сообщает вам, когда вы пытались прочитать **после** конца файла. Поэтому, чтобы исправить цикл, вам нужно сначала попробовать "fread", а затем проверить, не произошло ли это из-за условия EOF, а затем либо разорвать цикл, либо записать данные., @timemage
@timemage Причина этого решения заключается в том, что строка "fread(in, sizeof(символ без знака), размер, загрузка файла);" пытается прочитать элементы "size" ("размер" - это полный размер файла) и пытается поместить эти элементы в символ "in", но символ " in "имеет только 4 байта, независимо от функции "malloc"., @user2959923
Если вы когда-нибудь появитесь на freenode, я бы рассказал, что я об этом думаю. Для этого я просто скажу, что, по-моему, вам, возможно, нужно будет еще немного посмотреть на него., @timemage
- Задержка звука I2S с SD-карты на усилитель MAX98357A
- ESP32 в Arduino-IDE с FS.h и SPIFFS
- Программаторы для этой платы отсутствуют - Программирование ESP32 Cam с помощью Ardunio IDE
- Установка значения float до двух знаков после запятой
- ESP32-CAM первый: 0x8 TG1WDT_SYS_RESET загрузочный цикл
- esp32 Stack canary watchpoint срабатывает
- Проверка размера во флэш-памяти Esp32
- Ошибка Cast from 'char*' to 'uint8_t {aka unsigned char}' loses precision [-fpermissive]
Эта строка для меня не имеет смысла:
символ без знака * в программе = (символ без знака *) malloc(размер);
Либо это в ПРОГМЕ, либо в куче. Это не может быть и тем, и другим. [Я не думаю, что это ваша проблема, так как PROGMEM не существует в ESP32 ASFAIK], @PMFХех, это все, что нам нужно:
progmalloc()
. Или это " malloc_P ()"?=) Я не проверял ESP32, но обычно ядра без AVR имеют фиктивные " F ()", " PSTR ()", "PROGMEM", "pgm_read_ что угодно" и т. Д., Которые просто помещают вещи в единственное адресное пространство, которое у них есть. Таким образом, существует своего рода понятие их наличия в том смысле, что они не вызывают ошибок для непризнанных идентификаторов., @timemage@timemage Это именно то, что я думаю, да. В приведенной выше программе это может ничего не делать, но это просто неправильно. Данные должны быть считаны в обычную оперативную память., @PMF
@PMF, ах, это имеет смысл. Раньше я читал это по-другому., @timemage
@PMF да, извините, это была ошибка, которую я действительно пропустил. Однако удаление PROGMEM ничего не изменило. @timemage что ты имеешь в виду? Я успешно использовал "malloc" в другом коде, поэтому я могу подтвердить, что он распознается ядром ESP32., @user2959923
Является ли
sizeof(символ без знака)
= 1? Если бы это было не так, это объяснило бы катастрофу., @PMF@PMF, для
char
, независимо от того, как указана (или не указана) знаковость,sizeof
всегда будет давать1
. Это своего рода определение в стандарте. В принципе, как указано, sizeof возвращает количество символов, необходимых для представления чего-либо, где "символ" становится синонимом "байта", независимо от того, являются ли байты октетами или нет., @timemage@timemage Спасибо за объяснение. Я больше не был в этом уверен. Я в основном программист на C#, где
sizeof(char)
- это просто _not_ 1, потому что строки по определению являются юникодом., @PMF