Malloc, куча, стек

Когда-то вся тусовка сидела на сайте марсоход ну и на электроникс. А не актуальны, скорее всего, из за цены. Для более менее нормального проекта нужен чип, цена которого может быть сопоставима с десятком тех же стм. Есть у меня самые бюджетные epm3064 и epm240. В первую влезет пара тройка регистров типа 595, не больше. Во вторую уже десятка два-три аналогичных. Дальше цена уже заставляет задуматься, а так ли оно тебе надо.

ща появились китайские, они подешевле. Танг Нано на 9К ячеек стоит примерно 1.5 тыс с доставкой. А 9к это совсем иной разговор, чем менее чем 200 у epm240.
Правда у Нано другая проблема - выходов маловато

Глянул, интересные платки. А как с освояемостью ихнего по? Не сильно вырвиглазное, как обычно любят китайцы?

В этом наверное главное преимущество плисов - работа с параллельными линиями данных. Если мало, то плохо.

мне не с чем сравнивать.
У них есть плагин к ВС Коду, есть гайд по установке и с пол-дюжины учебных проектов. Особых проблем в прохождении учебного курса у меня не возникло. Другой вопрос, что будет, когда захочешь сойти с протоптанной тропинки… Народ пишет на форумах, что софт кривоват…
Еще из плюсов - к плате не нужен дорогой программатор.

ну а если захочется схемой наваять, как в квартусе, есть там такое?

хер его знает, я года два назад(или больше) пробовал, когда они только вышли… ща уже забыл все
Вот тут их основные гайды, посмотрите сами

Ага, глянул, есть у них по GOWIN, по сути тот же квартус. Надо будет прикупить на попробовать.

Да, нет, такое же там мышление. Принципиально там всё также - та же самая процедурная парадигма – последовательность действий, повторы и ветвления. Т.е. программа описывает последовательность действий, которую нужно выполнить для получения результата – всё точно так же.

Другое мышление нужно для программирования на принципиально иных языках (непроцедурных), скажем логических (пролог, планнер, попплер, QA-4 и т.п.) или функциональных (например - хаскел, лисп, рефал и т.п.). Там действительно сам процесс программирования другой. Там не описывают последовательность действий для получения результата, там просто описывается исходное состояние и свойства желаемого результата, но никак не поясняется, каким способом результат должен быть получен. Улавливаете разницу?

Также принципиально другое программирование используется для некоторых экзотических процессоров (например, ZISC (Zero Instruction Set Computer)). Но тут понятно, коль скоро у процессора вообще нет никакой системы команд, традиционное программирование в виде выписывания последовательности команд здесь не канает от слова совсем.

А между Си и программой в машинных командах принципиальной разницы нет никакой.

Так я и не о программе говорил…
Ладно, не суть.

Угу.

Вот пример реализации мигания светодиодом (Blink) на ассемблере Xtensa для классического ESP32.

Код написан в виде ассемблерной вставки для C/C++, которую можно легко запустить в Arduino IDE или ESP-IDF. Мы будем использовать GPIO 2 (встроенный светодиод на большинстве плат разработки).

Код программы

void setup() {
  // Настраиваем GPIO 2 на вывод через стандартную функцию
  pinMode(2, OUTPUT);
}

void loop() {
  __asm__ __volatile__ (
    ".equ GPIO_OUT_REG,   0x3FF44004 \n\t" // Адрес регистра вывода GPIO 0-31
    ".equ LED_PIN_MASK,   0x00000004 \n\t" // Маска для GPIO 2 (1 << 2 = 4)
    ".equ DELAY_CYCLES,   24000000   \n\t" // ~24 млн тактов (около 0.15 сек при 160МГц)

    // --- 1. ВКЛЮЧАЕМ СВЕТОДИОД ---
    "movi  a2, GPIO_OUT_REG         \n\t" // Загружаем адрес регистра в a2
    "l32i  a3, a2, 0                \n\t" // Читаем текущее состояние GPIO в a3
    "movi  a4, LED_PIN_MASK         \n\t" // Загружаем маску пина в a4
    "or    a3, a3, a4               \n\t" // Устанавливаем 2-й бит в 1 (включаем)
    "s32i  a3, a2, 0                \n\t" // Записываем обратно в регистр

    // --- 2. ЗАДЕРЖКА ---
    "movi  a5, DELAY_CYCLES         \n\t" // Загружаем счетчик циклов в a5
    "1:                             \n\t" // Метка начала цикла задержки
    "addi  a5, a5, -1               \n\t" // Уменьшаем счетчик на 1
    "bnez  a5, 1b                   \n\t" // Если a5 != 0, прыгаем назад на метку 1 (backward)

    // --- 3. ВЫКЛЮЧАЕМ СВЕТОДИОД ---
    "l32i  a3, a2, 0                \n\t" // Снова читаем состояние GPIO в a3
    "neg   a4, a4                   \n\t" // Инвертируем маску (было 0..0100, стало 1..1011)
    "and   a3, a3, a4               \n\t" // Сбрасываем 2-й бит в 0 (выключаем)
    "s32i  a3, a2, 0                \n\t" // Записываем обратно в регистр

    // --- 4. ЗАДЕРЖКА ---
    "movi  a5, DELAY_CYCLES         \n\t" // Снова инициализируем счетчик
    "2:                             \n\t" // Метка второго цикла задержки
    "addi  a5, a5, -1               \n\t" // Уменьшаем счетчик
    "bnez  a5, 2b                   \n\t" // Если a5 != 0, прыгаем назад на метку 2
    
    : // Выходных параметров нет
    : // Входных параметров нет
    : "a2", "a3", "a4", "a5" // Перечисляем измененные регистры (clobber list)
  );
}

Как это работает:

  • l32i (Load 32-bit Instant): Считывает 32-битное значение из памяти (из регистра состояния GPIO) в регистр процессора Xtensa.
  • s32i (Store 32-bit Instant): Записывает измененное 32-битное значение обратно в регистр управления портами, физически меняя уровень напряжения на пине.
  • bnez (Branch if Not Equal to Zero): Переход, если значение в регистре не равно нулю. Используется для создания циклов задержки.
  • Clobber list ("a2", "a3"...): Важная деталь ассемблерной вставки. Мы сообщаем компилятору GCC, какие регистры процессор задействовал внутри вставки, чтобы он не хранил там свои важные переменные С++.

Как проверить код:

  1. Подключите ESP32 к ПК.
  2. Вставьте этот код в Arduino IDE.
  3. Убедитесь, что в меню Инструменты → Плата выбран классический ESP32 Dev Module (не C3, S3 и т.д.).
  4. Прошейте контроллер — встроенный синий светодиод начнет мигать.

Если хотите, мы можем оптимизировать код через специальные регистры GPIO_OUT_W1TS_REG (установка бита) и GPIO_OUT_W1TC_REG (сброс бита) — это позволит избежать операции чтения l32i и сделает переключение мгновенным. Показать этот вариант?

естественно, какая принципиальная разница c:

C30100

)))

о, а можешь у него спросить как таким способом включить подтяжку для пина на вход? Было бы полезно.

Я не передаст - сложно зайти и спрость у гугла? Там кнопка есть - режим ИИ.

не шарю

Чтобы включить внутреннюю подтяжку к высокому уровню (Pull-Up) для GPIO 2, нам нужно изменить конфигурацию регистра IO_MUX_GPIO2_REG.

В классическом ESP32 за подтяжку к питанию в регистре IO_MUX отвечает 12-й бит (MCU_SEL_PULLUP). Если объединить его с настройками силы тока и цифровой функции, вместо значения 0xA0 в регистр конфигурации пина нужно записать значение 0x10A0.

Вот обновленный код функции setup с включенной аппаратной подтяжкой:

void setup() {
  __asm__ __volatile__ (
    ".equ GPIO_ENABLE_REG,  0x3FF44020 \n\t" // Регистр направления GPIO 0-31
    ".equ IO_MUX_GPIO2_REG, 0x3FF49040 \n\t" // Регистр конфигурации пина GPIO 2
    ".equ LED_PIN_MASK,     0x00000004 \n\t" // Маска для GPIO 2 (1 << 2 = 4)
    
    // 0x10A0 включает: 
    // - Функция GPIO (выбор режима периферии)
    // - Сила тока драйвера (10мА)
    // - Бит 12 (0x1000) -> Внутренняя подтяжка к VCC (Pull-Up)
    ".equ FUN_DRV_PULLUP,   0x000010A0 \n\t" 

    // --- 1. НАСТРОЙКА НА ВЫВОД (ENABLE) ---
    "movi  a2, GPIO_ENABLE_REG      \n\t" // Загружаем адрес регистра enable
    "l32i  a3, a2, 0                \n\t" // Читаем текущее состояние
    "movi  a4, LED_PIN_MASK         \n\t" // Загружаем маску пина
    "or    a3, a3, a4               \n\t" // Устанавливаем 2-й бит в 1 (разрешаем вывод)
    "s32i  a3, a2, 0                \n\t" // Записываем обратно

    // --- 2. НАСТРОЙКА ФУНКЦИИ ПИНА И ПОДТЯЖКИ В IO_MUX ---
    "movi  a2, IO_MUX_GPIO2_REG     \n\t" // Адрес регистра конфигурации для GPIO2
    "movi  a3, FUN_DRV_PULLUP       \n\t" // Константа с включенным битом Pull-Up
    "s32i  a3, a2, 0                \n\t" // Записываем настройки в IO_MUX
    
    : // Выходных параметров нет
    : // Входных параметров нет
    : "a2", "a3", "a4" // Разрушаемые регистры
  );
}

void loop() {
  __asm__ __volatile__ (
    ".equ GPIO_OUT_REG,   0x3FF44004 \n\t" 
    ".equ LED_PIN_MASK,   0x00000004 \n\t" 
    ".equ DELAY_CYCLES,   24000000   \n\t" 

    // --- 1. ВКЛЮЧАЕМ СВЕТОДИОД ---
    "movi  a2, GPIO_OUT_REG         \n\t" 
    "l32i  a3, a2, 0                \n\t" 
    "movi  a4, LED_PIN_MASK         \n\t" 
    "or    a3, a3, a4               \n\t" 
    "s32i  a3, a2, 0                \n\t" 

    // --- 2. ЗАДЕРЖКА ---
    "movi  a5, DELAY_CYCLES         \n\t" 
    "1:                             \n\t" 
    "addi  a5, a5, -1               \n\t" 
    "bnez  a5, 1b                   \n\t" 

    // --- 3. ВЫКЛЮЧАЕМ СВЕТОДИОД ---
    "l32i  a3, a2, 0                \n\t" 
    "neg   a4, a4                   \n\t" 
    "and   a3, a3, a4               \n\t" 
    "s32i  a3, a2, 0                \n\t" 

    // --- 4. ЗАДЕРЖКА ---
    "movi  a5, DELAY_CYCLES         \n\t" 
    "2:                             \n\t" 
    "addi  a5, a5, -1               \n\t" 
    "bnez  a5, 2b                   \n\t" 
    
    : 
    : 
    : "a2", "a3", "a4", "a5" 
  );
}

Как это работает на уровне железа:

Когда вы подаете на пин низкий уровень (выключаете светодиод), вывод принудительно прижимается к «земле» (GND). Когда вы подаете высокий уровень (или если пин случайно перейдет в режим входа), встроенный резистор номиналом около 30–80 кОм внутри чипа ESP32 будет стабильно подтягивать этот пин к шине питания 3.3V, защищая линию от электромагнитных наводок и ложных срабатываний.

Если вы хотите использовать этот пин не как выход для мигания, а как вход для чтения кнопки с подтяжкой, мне переписать код loop на опрос состояния пина вместо мигания?

спасибо

и что, эти регистры не доступны из С/С++ ? И если доступны - к чему это все?

Это я попросил. Надеялся что разложив на асм, найдется некий неведомый регистр, который умеет включать подтяжку на всех пинах одновременно. Не сработало, нет волшебного регистра.

Это к спору, что на ассемблере тяжело писать. Писать просто, но много.

От архитектуры зависит.