"Несмотря на отмеченные недостатки, диссертация отвечает ..., а диссертант заслуживает ..."


Решил я приобщиться к модным трендам и купить себе (для побаловаться) платку на ESP32, тем более и повод выдался неординарный - на сайте одной из российских фирм, торгующих Arduino, обнаружился модуль ESP32 lolin32 OLED по цене ниже, чем на Aliexpress.
Примечание на полях (Пнп): не знаю, будет ли это рекламой, но вот ссылка на модуль https://iarduino.ru/shop/boards/wemos-esp32-oled.html, а фирму вы узнаете сами. Не то, чтобы мне было очень жалко 1200-990=210 рублей, но возможность получить платку сразу, без ожидания посылки дорогого стоит. Кстати, если заказывать доставку до пункта выдачи вне МКАД, то даже получается чуть дороже, чем доставка из КНР, хотя и быстрее - всего 3 рабочих дня. Но можно съездить в "столицу нашей Родины город-герой Москва" и получить заказ на следующий день, что я и сделал. Не очень понятно, зачем я это все совершил в пятницу, потому что в выходные с платой возится так и не начал, но охота пуще неволи.

Тем не менее, на следующей неделе приступил к освоению платы. Для начала включил плату в USB порт - экран засветился и появилась надпись, заявляющая о любви к ESP - начало неплохое. Нужно установить среду разработки программ, и я решил поступить, как нормальный самодельщик, тем более что мне это рекомендовали на сайте фирмы продавца - скачать Arduino. Читатели, испытывающие непреодолимое отвращение к этому термину, могут далее себя не мучить, все остальные могут нажать на транспарант ниже.

Итак, скачиваем IDE по ссылке, устанавливаем ... и все устанавливается, ставятся необходимые драйвера и все готово к работе - 5+ балов. Далее, в соответствии с той же инструкцией (снабженной картинками), устанавливаю дополнительный пакет для ESP32, настраиваю IDE на работу с моей платой и опять все получается – 5 баллов, но без плюса, поскольку конкретную плату нужно выбирать руками, а могла бы и определиться сама в момент подключения.

Берем из инструкции на сайте текст скетча - пришлось воспользоваться Ctrl-C/Ctrl-V (5-), запускаем компиляцию, получаем сообщение об отсутствии библиотек. Опять же по инструкции скачиваем библиотеки из репозитория на Github и устанавливаем. Все бы хорошо, но остается сообщение об отсутствии другой библиотеки, приходится смотреть текст «руками», находить нужную библиотеку и скачивать еще и ее, так что 5-.

Подключаю плату, прошиваю скетч и все заработало - на экран выведена новая картинка с названием фирмы - продавца товара. Есть маленькое замечание - прошивка не всегда проходит, но если нажать на кнопку "BOOT" во время попыток старта загрузки, то все получается гарантировано. Пытаюсь сделать по инструкции - предварительно перевести плату в режим загрузки. Нажатие кнопки "EN" (да, так тут называют кнопку сброса, видимо, надпись "RESET" не умещалась на шелкографии, хотя "RST" вполне могла бы, но кто может понять ход мысли китайцев) при нажатой кнопке "BOOT" действительно переводит плату в режим ожидания прошивки, но все равно не гарантирует результата, так что 4+, не больше.

Пнп: сразу сам отмечу действительно недостаток среды разработки "из коробки" - инкрементальную компиляцию так и не завезли, несмотря на наличие уже скомпилированного проекта, перед каждой загрузкой он собирается заново. Наверное, где то в глубинах меню настроек (а может, и в текстовых конфигурационных файлах) есть соответствующие флажки, но мне лениво их искать. В конце концов, для человека, который когда-то ждал результатов исполнения программы до следующего дня, подождать 25 секунд - не так уж и много, так что 4.

Пнп: еще недостаток - видимо, как следствие предыдущей особенности, часть файлов, реализующие операции на самом низком, близком к аппаратуре уровне, представлены не в исходниках, а в скомпилированном виде. Для обычного пользователя разницы никакой, а вот для исследователя глубин, которым я себя читаю, это представляет определенные неудобства, так что опять 4-. Но, с другой стороны, Инет пока никто не отменил, хотя на Гитхабе и забанили мой логин, зарегистрированный с mail.ru, но логин с gmail.com все еще работает, так что все не безнадежно.

В заключение вводной части: несмотря на отдельные отмеченные недостатки, не могу не порадоваться за будущих пользователей указанной платы под данной средой - менее, чем за полчаса получить с нуля работающую систему - совсем и совсем неплохо. Пнп: еще раз напомню, что я предложил всем ненавистникам Arduino не читать дальше ката, так что не стоит рассказывать в комментариях, насколько она плоха и насколько IDE ххх лучше всех остальных ("то вечный спор славян между собою"), тем более, что пост совсем не об этом и данная среда программирования используется просто как инструмент для дальнейших исследований - хоть и небезупречный, но вполне рабочий.

Ну а теперь собственно к исследованию платы, мы же не просто так ее запускали.
Для начала определим тактовую частоту - есть встроенная функция, которая ее возвращает, но мы же не будем доверять посторонним. Находим счетчик циклов (я бы сказал, тактов), считываем счетчик при помощи функции
long cpu_hal_get_cycle_count(void),
делаем задержку, выводим прошедшие микросекунды и выводим изменение счетчика, делим второе на первое и получаем чуть больше 240. Пнп: не забываем убедиться, что заказанная задержка приблизительно равна реально прошедшему времени.

Смотрим документацию на кристалл и видим обещанную частоту до 240 МГц, что хорошо согласовано с измерениями. Отметим, что мы всегда при такой методике будем получать значение, чуть большее, чем реальная частота, потому что счетчик тактов инкрементируется "по взрослому", а счетчик микросекунд (о нем позже) имеет пределитель, поэтому его значение всегда будет меньше (и лишь иногда равно) реально прошедшему времени.

Немного забежим и погрузимся глубже, нажимаем F12 на функции чтения и в файле cpu_hal.h видим #define cpu_hal_get_cycle_count() cpu_ll_get_cycle_count(), нажимаем F12 еще раз и в файле cpu_ll.h находим исходник:

static inline uint32_t IRAM_ATTR cpu_ll_get_cycle_count(void) { 
  uint32_t result; 
  RSR(CCOUNT, result); 
  return result; 
};

Пнп: я позволил себе изменить стиль и поставить египетские скобки.

Нажимаем F12 еще раз и облом - "no definition found for CCOUNT", странно как то, ведь программа скомпилировалась, но обычный поиск находит в файле specreg.h определение:
#define CCOUNT 234.
Такая же ситуация и с определением RSR в файле xt_instr_masros.h
#define RSR(reg, at) asm volatile ("rsr %0, %1" : "=r" (at) : "i" (reg))
Все, мы достигли дна в исходниках и ниже лежит уже только описание на архитектуру собственно ядра. Пнп: хотя остаются вопросы к именам и расположению файлов (что не так важно при правильно настроенной среде программирования), и особенно к неявному преобразованию типа результата функции, выглядит данный фрагмент не так плохо.

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

uint32_t start=cpu_hal_get_cycle_count();
uint32_t stop=cpu_hal_get_cycle_count();
Serial.print(stop-start);

Пнп: ни фига себе, я внутренне был готов к 5-6, а тут так быстро, видимо результат прячется в регистр и там и остается до вывода.
Небольшие исследования показывают, что среда разработки в принципе поддерживает поиск по проекту ("в принципе у нас все есть, хотя не всегда, не везде и в недостаточном количестве") и в конце цепочки мы видим RSR(CCOUNT, result), так что, скорее всего, мы имеем дело не с чтением из памяти, а со специальной командой, что косвенно подтверждается значение CCOUNT (243). Пнп: да, надо бы посмотреть код на ассемблере, но как его сделать в данной среде программирования, я не знаю, так что будем судить по косвенным данным. Кроме того, можно пользоваться любимым сайтом godbolt.com для просмотра ассемблерного кода.

Для проверки добавляем в код еще 1 строку RSR(CCOUNT, stop) ( да, я знаю, что это нехорошо, но не смог удержаться) и видим, что время исполнения увеличилось на 1 такт, а размер кода вырос на 4 байта. Повторяем процесс несколько раз и убеждаемся, что команда занимает 4 байта и выполняется за 1 такт ядра, откуда предполагаю, что у меня в распоряжении камень с RISC-V ядром, которому свойственны 2 или 4 байтные команды, поскольку в Tenselica команды занимают 2 или 3 байта, хотя это неточно.

Далее нахожу в описании команд (Tensilica) команду RSR (Read Special Register) и убеждаюсь, что занимает она одно слово (3 байта) и номер регистра закодирован напрямую в команде, хорошее подтверждение выдвинутых предположений, хотя вопрос с видом ядром провисает. Сразу же пробую команду записи в данный регистр и получаю 0 тактов исполнения, все правильно, ведь мы теперь отнимаем 1 из результата.

Поскольку весьма маловероятно, чтобы программа состояла только из операций доступа к специальным регистрам, исследуем другие команды, начиная с простейших. Для начала вставляем между чтениями регистра счетчика инкремент целого числа и видим, что время исполнения 0 тактов. В общем то, ожидаемо, поскольку, если в компиляторе включена оптимизация (хотя бы -О1), а результат вычисления далее не используется, то фрагмент кода с инкрементированием будет просто выкинут из исполняемого кода.

Применяю любимый прием (нет, не делаю переменную volatilte, это плохое решение) - завожу глобальную переменную, перед операцией читаю ее в инкрементируемую переменную, после операции возвращаю в нее результат. Такой подход не позволяет компилятору с ать никаких предположений о содержании нашей переменной и заставляет работать с ней "по честному". Результат не заставил себя ждать - время исполнения инкремента локального объекта (скорее всего, размещенного в регистре) составляет 1 такт, что вполне ожидаемо.

uint32_t tmp;
tmp=global;
uint32_t start=cpu_hal_get_cycle_count();
tmp++;
uint32_t stop=cpu_hal_get_cycle_count();
global=tmp;
Serial.print(stop-start-1);

Пнп: почему квалификатор volatile не лучшее решение - компилятор несколько по-разному работает с такими переменными и с обычными. Например, для Tensilica дополнительно вставляется барьер памяти memw перед считыванием переменной (и это можно понять), а также перед записью результата (а вот это понять сложнее), что несомненно усложняет измерения времени исполнения.

Пробуем работу с оперативной памятью, для чего делаем локальную переменную статической (static), инкрементируем ее (расположенную в памяти, а не в регистре) и видим ... 490 тактов.
WTF???
Результат очевидно абсурдный, поэтому не верим своим глазам и повторяем фрагмент кода еще раз, получая ожидаемые 4 такта.
Пнп: вообще то я по опыту общения с ARM ожидал 3 команды и три такта - косвенное чтение со смещением относительно указателя сегмента данных в рабочий регистр, собственно инкремент (прибавление 1), косвенная запись в память. Но, наверное, сегмент данных нагружен (хотя странно) и добавляется формирование исполнительного адреса в промежуточном регистре. Могло быть и больше четырех тактов в случае загрузки сложной константы или если доступ в память длительный, но ожидалось именно 3. Чисто теоретически могло быть и меньше, для этого конвейер и предназначен, но это маловероятно, только при строго определенном обрамлении тестируемой последовательности команд.

Так, от сердца отлегло, я еще кое-что понимаю в микроконтроллерах, но откуда взялся первый результат 490 (а он никуда не делся). Повторяю в тексте программы несколько раз тестовый фрагмент (да, я так умею) и убеждаюсь, что время исполнения одной и той же команды меняется от 4 до 490 тактов, причем последовательность остается неизменной при каждом перезапуске системы (нажатие кнопки "EN").

Становится ясно, что иногда кто-то, помимо моего кода, вмешивается в процесс исполнения и запускает некий длительный процесс, время исполнения которого прибавляется к времени исполнения собственно команды. Будем искать.

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

Вторая гипотеза - некий процесс работает в прерывании, например, шедулер. Вроде как маловероятно, чтобы что-то постороннее прилинковалось к моему коду, но чем черт не шутит. Пнп: хотя кто знает - пустой скетч занимает 239к байт памяти программ, так что туда много чего можно запихать. Проверить легко - защищаю процесс исполнения команды запрещением прерываний и не помогает. Значит, это вообще не прерывания. Пнп: есть еще вариант, что команда cli() прерывания на самом деле не запрещает, но это уже слишком много сомнительных допущений.

Третья группа гипотез - причина внешняя по отношению к ядру, исполняющему код.
Вспоминаю, что в кристалле имеется 2 основных ядра плюс еще одно вспомогательное и они делят общую память.
Гипотеза 3.1 - возможно, что второе ядро или ядро низкого потребления имеет свой собственный процесс, который захватывает общую память данных для каких-то целей и блокирует доступ к ней моей программы. Вроде, похоже, потому что команда чтения специального регистра всегда выполняется правильно (а вот это было заблуждение...). Привлекательность гипотезе добавляет тот факт, что тест, вынесенный в бесконечный цикл, исполняется без лишних задержек, значит, начиная с какого-то момента времени этот другой процесс завершается (о как я заблуждался...). Внимательное чтение документации гипотезу не подтверждает - второе ядро надо запускать явным образом, да и чтобы ядро пониженного потребления заработало, надо постараться, а я этого не делал.

Тогда гипотеза 3.2 - по каким-то причинам срабатывает валидация кэша данных и блокирует обращение к памяти. Ну как то странно, что она перестает срабатывать, начиная с некоего времени. Еще более странно, что кэш промах одного слова вызывает такую задержку, хотя, что мы знаем о механизме кэширования и размере страницы в данном конкретном случае. Но очень сомнительно, я бы такой кэш делать точно не стал и вряд ли в Espressif работают настолько странные люди.

Пнп: степень моего недоумения можно проиллюстрировать тем фактом, что я обратился за помощью к ChatGPT. Он сделал все предыдущие предположения - прерывания, блокировка другим процессом, кэш промах и добавил еще парочку - изменение частоты и переключение режимов потребления, но все не подходит.

И тут родилась гипотеза 3.3 - кэш памяти программы. Что, если программа на самом деле исполняется не из IRAM (куда переписывается из внешнего FLASH при старте), а из некоего кэша в памяти, в который время от времени подкачивается код. Эта гипотеза объясняет, почему через какое то время задержки прекращаются, но с треском разбивается о факт, что операции работы с регистром задержкам не подвержены.

Ну что же, "если факты противоречат теории, то тем хуже для фактов". Для проверки составляю программу с множеством чтений счетчика и на 11 последовательных чтениях подряд наблюдаю резкое увеличение задержки исполнения до 399. Значит, заключение о связи задержки с обращением к памяти данных было частным и ошибочным и главное возражение против гипотезы 3.3 снято.

Читаю еще раз внимательно документацию и обнаруживаю, что программа действительно исполняется из IRAM (еще и из IROM), но туда вовсе не загружается при старте. Вместо этого настраивается механизм MРU, при обращении к непрочитанному фрагменту кода возбуждается аппаратное прерывание, которое подкачивает соответствующий фрагмент (страницу) кода из FLASH в IRAM.

Многое становится понятнее. Во-первых, для возникновения задержки внутри измеряемого кода должна располагаться граница страницы, а это гораздо проще обеспечить, когда исследуемый фрагмент имеет длину 4 команды, а не одну. Вот почему я раньше этого эффекта не наблюдал, просто (не) повезло. Во-вторых, становится понятно, почему после определенного времени работы программы задержка исчезает - весь код оказывается подкачанным в оперативку и исключения перестают происходить.

Проверяется гипотеза очень просто - делается функция с атрибутом IRAM_ATTR, в нее выносятся измерения и, вуаля, задержка полностью пропала с первого раза и больше не появляется.

Единственное, что смущает - частота возникновения исключений, документация в данной части ясностью не отличается и нам остается путь эксперимента. Копируем фрагмент с 4х байтовыми командами, добиваемся получения исключения в обоих фрагментах путем вариации количества команд внутри измерения, далее уменьшаем второй фрагмент до исчезновения исключения, затем удаляем весь второй фрагмент и смотрим на изменение размера кода. Код уменьшился на 60 байт, так что, скорее всего, размер страницы подкачки составляет 64 байта. Тогда пересылка одного байта программы из FLASH в IROM занимает
(488/64= 64*7+40=64*6+104) семь либо шесть тактов, а остальное - накладные расходы на адресацию FLASН и коррекцию таблиц MPU.

Если загрузка проводится в немаскируемом прерывании в программном режиме, то 6 – не так и много с учетом 4-битового аппаратного доступа к FLASH, но если работает специальный аппаратный узел, то это многовато. В любом случае изменять что-либо внутри микросхемы я не имею ни желания, ни возможности (интересно, что важнее) и остаюсь с единственной рекомендацией (и она совпадает с рекомендацией производителя микросхемы) - критичные по времени исполнения фрагменты кода должны снабжаться атрибутом IRAM_ATTR, все остальные методы не дают твердых гарантий (а мягких нам и не надо, они не гарантии вовсе).

Пнп: дальнейшие странствия по описанию микросхемы и исходным кодам привели к обнаружению регистра, задающего частоту обращения к Flash памяти и она равна 80 МГц. Тогда на собственно считывание двух ниблов, формирующих 1 байт, уйдет 3*2=6 тактов и это вполне согласуется с предположением о 6 тактах на пересылку байта + 104 (вход в прерывание, настройка доступа к памяти, коррекция таблицы защиты, выход из прерывания).

Почему именно такой размер страницы подкачки - в принципе понятно, большую страницу долго грузить, меньшую придется грузить чаще. Документация намекает, что это параметр (размер страницы MPU) можно менять от 64 до 2048, но вряд ли стоит это делать без детального анализа. В любом случае, если Ваша программа может уместиться в оперативной памяти кода, рано или поздно она туда будет подгружена и станет работать без лишних задержек, за исключением самого первого выполнения цикла, когда Вам ничего не гарантируется. Да и в дальнейшем возможны сюрпризы, ведь мы толком не знаем, как работает механизм вытеснения страниц кода, поэтому единственная гарантия быстрого выполнения кода - уже упомянутый атрибут.

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

  1. Очень интересно, хочу продолжения "автор, пиши еще"

  2. Неплохо, почитаю, если будет продолжение.

  3. Интересные факты тривиальны, а нетривиальные неинтересны, ну напиши, если хочешь.

  4. Совершенно неинтересно, "автор, выпей яду"

Комментарии (33)


  1. nikolz
    21.12.2023 14:54

    "на сайте одной из российских фирм, торгующих Arduino, обнаружился модуль ESP32 lolin32 OLED по цене ниже, чем на Aliexpress."

    Увы, такого не бывает на Али всегда дешевле:


    1. interm
      21.12.2023 14:54

      Вы ж стоимость доставки не показываете.

      А так да, почти за 745.


    1. GarryC Автор
      21.12.2023 14:54

      Я смотрел у другого продавца, там было ~1200р и решил, что и у остальных будет приблизительно так же. Значит плохо я умею искать на Али :(


  1. Moog_Prodigy
    21.12.2023 14:54

    ESP сами по себе довольно корявые внутри (не знаю как это обьяснить), поэтому приколов можно много накопать. Любят их за другое - цена и возможности. В узких кругах ходит шутка, что еррата на есп больше самого даташита. А вдруг не шутка?


    1. olartamonov
      21.12.2023 14:54

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

      Их уже три — ESP32, ESP32-S2 и ESP32-S3 (не считая ещё двух на ядре RISC V вместо Extensa LX — ESP32-C3 и ESP32-C6), и они существенно разные.

      Причём они не обязательно улучшаются: например, криптографический акселератор с каждым новым чипом — медленнее :)


  1. Jury_78
    21.12.2023 14:54

    Становится ясно, что иногда кто-то, помимо моего кода, вмешивается в процесс исполнения и запускает некий длительный процесс

    Там же установлена RTOS и WIFI, как я понимаю они тоже должны работать. Я правда только micropython использовал.


    1. jaha33
      21.12.2023 14:54

      Да, внутри freertos и просто куча всяких доп файлов "экосистемы". Плюс может сидеть wifi/ble, тут уже от библиотеки и чипа зависит.

      Если взять ESP IDF (почти чистый C код) и собрать проект мигания светодиодом, то на выходе бинарник будет весить под 120кб флеша и 60к озу :)


      1. VladimirFarshatov
        21.12.2023 14:54

        Ого.. не знал. Хотел тоже погонять но не задалось. А напрямую на асме её можно юзать?


        1. NutsUnderline
          21.12.2023 14:54

          можно но оооочень мало кому захочется: это потребует кучу времени для старта. но jtag прицепить можно, а значит будет гораздо лучше чем в старые добрые времена ПЗУ стираемых ультрафиолетом.


        1. olartamonov
          21.12.2023 14:54

          Практически нельзя. Документации нет, и даже ISA ядер Extensa — официально под NDA (хотя, говорят, в интернете найти можно всё).


          1. VladimirFarshatov
            21.12.2023 14:54

            Вот, меня эта сторона и интересовала: есть ли полноценная дока на архитектуру или там серо-черный ящик с сюрпризами?



            1. olartamonov
              21.12.2023 14:54

              Второе.

              SDK описана достаточно хорошо, но чуть в сторону — и вас ждут увлекательные приключения в серой зоне и «исходники как документация» в лучшем случае.

              К счастью, память обычно не проблема и имеющегося в SDK обычно хватает.


              1. VladimirFarshatov
                21.12.2023 14:54

                Как понял, Xtensa это собираемая система на кристалле из кубиков, но ещё на стадии проектирования кристалла. И, соответственно вопрос не столько в этой доке самой архитектуры, сколько чего конкретно напихано в процессор конкретной ESP-шки, и вот тут дока хромает:

                Типовая часть (общая) есть, понятна. А вот описания отдельных фич отсутствуют порой полностью. Так?


                1. olartamonov
                  21.12.2023 14:54

                  А вот описания отдельных фич отсутствуют порой полностью

                  Скажем так: детализированные описания отдельных фич. По сути, для многого на низком уровне есть лишь констатация присутствия фичи с очень, очень кратким описанием — без внутренних деталей.


                  1. LAutour
                    21.12.2023 14:54

                    Есть описание всех регистров перифирии в technical_reference_manual для работы на низком уровне.


                    1. olartamonov
                      21.12.2023 14:54

                      Там есть их перечисление. Из которого часто довольно трудно понять, что именно делает конкретный флаг и как он коррелирует с другими флагами.


          1. jcmvbkbc
            21.12.2023 14:54

            ISA ядер Extensa — официально под NDA

            Официальная документация на ISA доступна на сайте Cadence, без регистрации и смс: https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf


        1. Gryphon88
          21.12.2023 14:54

          маложрущий сопроцессор ULP по-другому и не получится :(


    1. VO_Obsidian
      21.12.2023 14:54

      WiFi как и второе ядро надо запускать явно, это точно не причина


  1. NutsUnderline
    21.12.2023 14:54

    автор сделал какой то бытрый и качественный скачек от ардуино да прилично все описал. Наверное он че то раньше умел :)

    я даже не знаю стоит ли повторять за автором рекомендуемая ардуино это надстройка над ESP IDF а она содержит кучу своего закрытого а так же процедуры из rom вызывает. в arduino 2 как то прикрутили отладку.. Но "правильная" отладка затруднена скуднейшей документацией по регистрам. она может nda но даташит и pm на esp очень .. лаконичный

    большая часть известных проектов что я смотрел обычно использует platformio. и обычно это тоже используется фрейворк ардуино , но вызывается он не ограниченной ide на java, а своеобразной утилитой командной строки с прикрученным web ide.

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

    в общем. если автор настоящий сварщик то надо либо нырять глубже в дизасм и jtag. Такие опыты есть: люди патчат вызовы rom на уровни бинарника. либо.. не пытаться сделать на этой микрухе больше чем можно: она и так неплохая - много всяких штуковин сделали, и такты не считали


    1. saga111a
      21.12.2023 14:54

      автор сделал какой то бытрый и качественный скачек от ардуино да прилично все описал

      В 2014 автор писал про DMA, он явно что-то умеет!


      1. rukhi7
        21.12.2023 14:54

        Действительно

        В 2014 автор писал про DMA

        https://habr.com/ru/articles/228531/

        и даже обещал продолжение про решение проблем с ДМА на отечественных МК (насколько я понял), я что-то продолжение не могу найти, интересно чем все закончилось.


        1. GarryC Автор
          21.12.2023 14:54

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


      1. NutsUnderline
        21.12.2023 14:54

        сферический DMA в вакууме? Был вот, например, хороший обзор всяких особенностей DMA в реализации от Milandr, .. а толку


    1. red_dragon
      21.12.2023 14:54

      А это на каком языке написано?


    1. RTFM13
      21.12.2023 14:54

      Я пришел к варианту vscode->platformio->esp-idf

      Проект platformio немного отличается от чистого esp-idf, но не сильно и эти отличия документированы. Еще одно время версия esp-idf в platformio заметно отставала от актуальной, но сей час такой проблемы нет.

      Фреймворк esp-idf немного косоват, но развивается и базовый функционал работает стабильно. Но в порядке вещей, например, такие вещи как нерабочие устаревшие примеры, которые даже не собираются на актуальном esp-idf.

      Документация в порядке убывания актуальности - примеры, комментарии в хидерах библиотек и собственно документация. Закрывает потребности от 50 до 100% от необходимого в зависимости от требуемого функционала.

      Периферия радует не только ассортиментом, но и гибкостью.

      Хотя если пользоваться обёрткой ардуино, то гибкости будет куда меньше, но и код будет проще - иногда одна комманда без параметров заменяет страницу исходного кода.

      Считать такты и писать на ассемблере на этот MCU не вижу ни малейшего смысла для 99,9% задач.


  1. 0x6b73ca
    21.12.2023 14:54

    Попробуйте mongoose os, проект заброшен но там очень много написано, намного больше возможностей чем с Arduino IDE


    1. GarryC Автор
      21.12.2023 14:54

      Ну я попробовал самое ходовое - Arduino и оно, в общем то, неплохо, даже для меня, а уж для нормального самодельщика так и просто хорошо.


    1. NutsUnderline
      21.12.2023 14:54

      поглядел. с одной стороны - там интересно, потому что в esp32 они залезли на уровне регистров, без  ESP IDF . С другой стороны эта универсальная вещь под несколько контроллеров, которая может все, что умеет каждый контроллер, но похоже не имеет заточки под возможности конкретных контроллеров - так что интересно что это за "много чего". как по мне - она поможет поглядеть-поучиться, но они за что то еще и деньги просят


  1. LAutour
    21.12.2023 14:54

    Есть маленькое замечание - прошивка не всегда проходит, но если нажать на кнопку "BOOT" во время попыток старта загрузки, то все получается гарантировано.

    Проблема самой платы. У меня есть две другие разновидности отладочныых плат на ESP32: одна входит в режим программирования без нажатия boot тоже 50 на 50, другая - всегда (чипы usb-uart разные).


    1. Winnie_The_Pooh
      21.12.2023 14:54

      Эта проблема решается напайкой дополнительного конденсатора между выводом EN и землей. Номинал - от 10 мкф и больше. Можно электролит, можно неполярный.


  1. jcmvbkbc
    21.12.2023 14:54

    Например, для Tensilica дополнительно вставляется барьер памяти memw перед считыванием переменной (и это можно понять), а также перед записью результата (а вот это понять сложнее)

    Это поведение можно отключить добавив опцию компилятора -mno-serialize-volatile

    Барьер перед записью в память гарантирует, что запись не будет переупорядочена с другими более ранними чтениями и записями. Вообще это поведение унаследовано из времён, когда о явных барьерах ещё не принято было задумываться и считалось, что volatile -- наше всё. Полагаю, что в некоторых культурах программирования это до сих пор верно. При компиляции ядра linux это поведение отключено и явные барьеры должны быть в правильных местах.