Как объявить глобальные переменные в PSRAM

Перед использованием PSRAM надо выполнить psramInit()

Тогда каким образом объявить глобальные переменные? В void setup() они же не будут глобальными…

В примерах кода нашёл только это:

void setup() {
Serial.begin(115200);
//PSRAM Initialisation
if(psramInit()){
        Serial.println("\nThe PSRAM is correctly initialized");
}else{
        Serial.println("\nPSRAM does not work");
}

//Create an integer
int *var_int = (int *) ps_malloc(sizeof(int));
*var_int = 42;
}


Кто тебе запрещает указатель объявить глобально?
Выделишь ему память «уже по месту».

их объявляют в начале кода

Покажите пожалуйста как это сделать.

Бабос, как ты что-то смог написать не объявив сумму денех?))

=====================================================

Ну примерно как-то так:

int *var_int;

void setup() {
  Serial.begin(115200);
  //PSRAM Initialisation
  if (psramInit()) {
    Serial.println("\nThe PSRAM is correctly initialized");
  } else {
    Serial.println("\nPSRAM does not work");
    while(1);
  }

  var_int = (int *) ps_malloc(sizeof(int));
  *var_int = 42;
}

void loop () {

  Serial.print("Var_int = ");
  Serial.println((int)*var_int);
  *var_int = 56;
  delay(5000);
}

Не проверял. И не уверен на счет правильности 20 строки.

ну тут то можно помочь, даже если он код от ии скинул, а еще спать охота но нельзя, надо входить в другой режим, временно не до денег)))

О как, понятно почему бесплатно и бесполезно писал ))

Никак.

Подробнее

Глобальные переменные всегда идут в .data и .bss , т.е. DRAM.

Причина проста - память под глобальные переменные выделяется задолго до инициализации чего бы то ни было.

Это бутлоадер, который ничегошеньки не знает про PSRAM, пакостит.

Это он, негодяй, загружает бинарник ваш в DRAM и IRAM. Ну, не весь бинарник, а только .data, .bss, еще наверняка что-то.. .iram1.text.*, в частности.

Если вам нужны глобальные переменные гигантские (массивы, там, например), то вам к malloc(). Вернее, даже не так - вам к heap_caps_malloc(). Вот таким образом: heap_caps_malloc(…, MALLOC_CAP_SPIRAM)

Тогда гарантированно выделится память в PSRAM.

Если вы попытаетесь сделать просто malloc(), большого буфера, то он тоже будет выделен в SPIRAM. Ну а если махонький буфер - то как повезет. Скорее всего будет DRAM

ЗЫЖ

На самом деле, конечно можно разместить переменные где угодно.

Просто это нетривиальная задача.

Но в общих чертах:

  1. смотрите, что такое RTC_DATA_ATTR . Поиском по заголовочным файлам.
  2. разбираетесь, что такое секции, и как их обрабатывает линкер
  3. разбираетесь в синтаксисе linker файла, производите там соответствующие исправления (по образу и подобию)
  4. наконец-то пишете в своем коде, скажем, “int MY_PSRAM_VARIABLE var;“
  5. разбираетесь как устроен 2nd stage bootloader (исходный код и примеры в ESP-IDF)
  6. исправляете bootloader так, чтобы он инициализировал PSRAM, и загружал туда вашу секцию (скажем, .my_psram_data)
  7. PROFIT!!!

PPS: на несколько месяцев развлечение, плюс, даже не думай начинать без OpenOCD/JTAG - инфаркт будет

а вот интересно, может в свежих ядрах уже добавили использование PSRAM

В новых ставят какую-то 8-битную DDR память. 240мгц. Пишут, что по скорости близко к Octal SPI (который щас).

// ============================================================
// ЕДИНЫЙ СКЕТЧ ДЛЯ ДВУХ ПРОШИВОК
// Компилируем 1 раз, прошиваем 1 раз — работает как две программы
// ============================================================

#include <esp_partition.h>
#include <esp_ota_ops.h>

#define LED_PIN 2

// Таймер для первой прошивки (10 секунд до переключения)
#define SWITCH_DELAY_MS 10000

// Пин для кнопки возврата к первой прошивке (опционально)
#define RESET_PIN 0    // GPIO0 (кнопка BOOT на многих платах)

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(RESET_PIN, INPUT_PULLUP);
  
  // Определяем, с какого раздела мы запустились
  const esp_partition_t* running = esp_ota_get_running_partition();
  const char* running_partition = running->label;
  
  Serial.println("\n========================================");
  Serial.printf("Запущен раздел: %s\n", running_partition);
  Serial.println("========================================\n");
  
  // -----------------------------------------------------------------
  // ЛОГИКА ДЛЯ ПЕРВОЙ ПРОШИВКИ (раздел ota_0)
  // -----------------------------------------------------------------
  if (strcmp(running_partition, "ota_0") == 0) {
    Serial.println("Первая прошивка: мигаю LED 10 секунд...");
    
    // Мигаем LED 10 секунд
    for (int i = 0; i < 20; i++) {
      digitalWrite(LED_PIN, HIGH);
      delay(250);
      digitalWrite(LED_PIN, LOW);
      delay(250);
      
      if (i % 4 == 0 && i > 0) {
        Serial.printf("  прошло %d сек\n", i/2);
      }
    }
    
    Serial.println("\n10 секунд прошло! Переключаюсь на вторую прошивку...");
    
    // Находим раздел ota_1
    const esp_partition_t* target = esp_partition_find_first(
      ESP_PARTITION_TYPE_APP, 
      ESP_PARTITION_SUBTYPE_APP_OTA_1, 
      NULL
    );
    
    if (target == NULL) {
      Serial.println("ОШИБКА: раздел ota_1 не найден!");
      return;
    }
    
    // Устанавливаем ota_1 как загрузочный
    esp_err_t err = esp_ota_set_boot_partition(target);
    if (err != ESP_OK) {
      Serial.println("ОШИБКА: не удалось переключить раздел!");
      return;
    }
    
    Serial.println("OK! Перезагрузка через 1 секунду...");
    delay(1000);
    esp_restart();
  }
  
  // -----------------------------------------------------------------
  // ЛОГИКА ДЛЯ ВТОРОЙ ПРОШИВКИ (раздел ota_1)
  // -----------------------------------------------------------------
  else if (strcmp(running_partition, "ota_1") == 0) {
    Serial.println("Вторая прошивка: работаю постоянно!");
    Serial.println("(можно добавить логику возврата на первую прошивку)\n");
    
    // Бесконечное мигание
    while (true) {
      digitalWrite(LED_PIN, HIGH);
      Serial.println("LED включен");
      delay(1000);
      
      digitalWrite(LED_PIN, LOW);
      Serial.println("LED выключен");
      delay(1000);
      
      // Опционально: если нажата кнопка — возвращаемся к первой прошивке
      if (digitalRead(RESET_PIN) == LOW) {
        Serial.println("\nКнопка нажата! Возвращаюсь к первой прошивке...");
        
        const esp_partition_t* target = esp_partition_find_first(
          ESP_PARTITION_TYPE_APP, 
          ESP_PARTITION_SUBTYPE_APP_OTA_0, 
          NULL
        );
        
        if (target) {
          esp_ota_set_boot_partition(target);
          delay(500);
          esp_restart();
        }
      }
    }
  }
}

void loop() {
  // Для второй прошивки loop не нужен (уже в while)
  // Для первой сюда не доходит — перезагрузились раньше
  delay(1000);
}

вроде делал это как то, и забыл))) ради интереса решил сейчас попытаться загрузить это вывод такой

Запущен раздел: ota_0
========================================

Первая прошивка: мигаю LED 10 секунд...
  прошло 2 сек
  прошло 4 сек
  прошло 6 сек
  прошло 8 сек

10 секунд прошло! Переключаюсь на вторую прошивку...
E (10018) esp_image: image at 0x200000 has invalid magic byte (nothing flashed here?)
ОШИБКА: не удалось переключить раздел!

файл .csv по пути C:\Users\User\Desktop\FLProg\ideV8\portable\packages\esp32\hardware\esp32\2.0.17\tools\partitions был заменен на это

# Name,      Type, SubType, Offset,   Size,     Flags
nvs,         data, nvs,     0x9000,   0x4000,
otadata,     data, ota,     0xd000,   0x2000,
phy_init,    data, phy,     0xf000,   0x1000,
ota_0,       app,  ota_0,   0x10000,  0x1F0000,
ota_1,       app,  ota_1,   0x200000, 0x200000,

наверное надо как то код разместить еще и в ota_1 … может будет кому то интересно… держу в курсе, и продолжаю вести наблюдение!)))

это делается не так, размещаешь этот файлик в папке скетча и при выборе разметки выбираешь CUSTOM и будет тебе щастье!