• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Рекомендации по программированию (перевод статьи)

Юрий Ботов

Moderator
Команда форума
Оригинал: Guidelines for writing code for the ESP8266 – Daniel Casner
Перевод несколько вольный, но без полной отсебятины. Оригинальный текст под спойлерами. Просьба к асам - просмотреть на предмет смысловых ошибок и некорректностей перевода.

Guidelines for writing code for the ESP8266
Рекомендации по написанию кода для ESP8266

Espressif’s ESP8266 WiFi SoC is an increasingly popular chip for Internet of Things projects, both hobby and professional, because it combines a capable MCU with a WiFi radio in a single chip for an amazingly low cost. It’s received a lot of attention in many blogs but I wanted to give a little bit more technical depth on the MCU architecture and my best practices for programming it. There are some idiosyncrasies which have to be taken into account when programming to get the most out of the SoC.
ESP8266 WiFi SoC от Espressif - безумно популярный чип для проектов IoT, и любительских и профессиональных, потому что объединяет MCU и WiFi в дешевой одно-кристальной схеме. Это обсуждалось во многих блогах, но я хотел дать немного больше технической информации о архитектуре MCU и моих принципов его успешного программирования. Есть некоторые особенности, которые нужно учитывать, программируя, чтобы получить все возможное от SoC.

Chip Architecture
Архитектура чипа
см. Фотографию в оригинале статьи

Code Memory
Память команд

The ESP8266 has on die program ROM which includes some library code and a first stage boot loader. All the rest of the code must be stored in external SPI flash. 32kb of code can be loaded into dedicated code RAM. The rest of the code is fetched over SPI and cached in additional 32kb of RAM. Cached code can be fast as long as there isn’t too much churn. The ICACHE_FLASH_ATTR decorator is used to locate code in the SPI flash memory instead of the core 32kb of RAM.
У ESP8266 есть ROM в которой хранятся немного библиотечного кода и начальный загрузчик. Весь остальной код хранится на внешней SPI flash. 32kb кода могут быть постоянно загружены в RAM. Оставшийся код загружается при необходимости через SPI и кэшируется в добавочных 32kb RAM. Кэшированный код работает быстро, если не подгружать его слишком часто. Признак ICACHE_FLASH_ATTR используется для размещения кода в кэше вне основного 32kb ядра.

Processor Architecture
Архитектура процессора

The SoC uses a Tensilica Xtensa lx106 MCU which is a 32bit processor with 16 bit instructions but is not ARM. It is Harvard architecture which most significantly means that instruction memory and data memory are completely separate.
В "системе на чипе" используется ядро Tensilica Xtensa lx106 MCU представляющее собой 32bit процессор с командами длиной 16 bit [от переводчика: правильнее сказать 24 и 16 бит] но это не ARM. Тут Гарвардская архитектура с полностью разделенными памятью команд и данных.

Peripherals
Периферия

All of the MCU peripherals (UART, I2S, Radio, etc.) seem to have been developed custom by Espressif and are a bit idiosyncratic so they take some time to get used to.
Вся периферия (UART, I2S, Radio, etc.) была сделана Espressif и она несколько специфична и на нее придется потратить некоторое время
One of the most significant speed limitations is that all register reads / writes are surprisingly slow so they should be kept to a minimum.
Одно из основных ограничений скорости это то что любые чтения/запись регистров неожиданно медленны поэтому обращения к ним лучше свести к минимуму
DMA: So far the only peripheral which has any kind of DMA which has been figured out is the I2S peripheral. With some clever tricks, I2S can also be used for SPI.
DMA: На данный момент имеется информация о поддержке DMA только одним периферийным устройством - I2S. С использованием некоторых хитрых приемов можно использовать его для SPI.

Programming Best Practices
Правильное программирование

Code structure
Структура кода

All application code must be in either a task or a timer
- Каждый блок кода должен быть либо Задачей RTOS либо вызываться по таймеру;
All tasks and timers should complete in less than 2ms and must complete in less than 500ms or the watchdog timer will reset the MCU.
- Желательно чтобы каждый блок кода выполнялся менее чем за 2ms, и он не в коем случае не должен выполняться более чем 500ms, поскольку при этом watchdog перезагрузит процессор;
Reoccurring timers should not be scheduled more often than every 5ms.
- Не вызывайте блок кода по таймеру чаще чем каждые 5 ms ;
There are 3 user task levels: 0, 1, 2.
All level 2 tasks queued run before any queued level 1 tasks and so on.
Task level 2 is reserved for HAL functions
- Имеется три уровня приоритета для задач операционной системы: 0,1,2. Все задачи 2-го уровня будут выполнены до того как выполнятся задачи 1-го уровня, и только после выполнения всех задач 1-го уровня начнут выполняться задачи 0-го уровня. Уровень 2 - зарезервирован за системными (HAL) функциями;
Timers which are due are higher priority than tasks.
- Вызов по таймеру имеет больший приоритет чем задачи операционной системы;
Tasks and timers do not preempt each other. A new task or timer cannot start until the running task / timer has ended.
- Задачи и обработчики таймеров не вытесняют друг друга. Новая задача или обработчик не будут запущены пока не завершится текущ(ая/ий);
Interrupts must not be locked out for more than 10μs at a time or WiFi will crash.
No ISR can run for more than 10μs.
This is likely the cause of the mysterious lmac.c ### / mac ### errors which many people have encountered. They happen when the MCU can’t service radio interrupts fast enough.
- Прерывания не должны выполняться или блокировать процессор более чем на 10μs иначе WiFi поведет себя непредсказуемо. Если не выполнять этого требования вы получите "мистические" ошибки "lmac.c ### / mac ### ", которые означают что прерывания обрабатываются недостаточно быстро;
Register reading and writing is surprisingly slow, cache where possible, etc.
- Запись и чтение регистров периферийных устройств неожиданно медленны. Везде где возможно(и необходимо) кэшируйте значения регистров в памяти.

Performance and Memory
Производительность и память

Application code should have the ICACHE_FLASH_ATTR decorator unless it is executed very often.
- Любой блок кода не вызывающийся слишком часто должен иметь признак ICACHE_FLASH_ATTR;
All interrupt handlers must not have the ICACHE_FLASH_ATTR decorator and any code which executes very often should not have the decorator.
- Все обработчики прерываний и любые блоки кода вызываемые из них не должны иметь признака ICACHE_FLASH_ATTR;
The Espressif is not especially fast and fetching code is relatively slow, however, it has a relatively large amount of RAM so when making computation/code-size/RAM use trade offs, generally take the path that uses more RAM.
- Espressif не слишком быстр, и загрузка кода происходит относительно медленно, но памяти в нем достаточно, поэтому если есть такая возможность, выбирайте решения где меньше кода и больше данных;
Heep (malloc and free) is available but should be used sparingly and cautiously.
- "Куча" доступна через malloc/free однако пользоваться ей нужно экономно и осторожно.

Code size:
Размер кода

Since the Espressif uses external SPI flash, there is effectively unlimited code memory.
- Учитывая что Espressif использует внешнюю SPI flash допустимый размер кода получается практически неограниченным (зависит только от размера этой SPI flash);

However, loading code from SPI flash is relatively slow and there is a limited code cache in local chip RAM. Hence inner loops and code which executes often should be kept relatively small to reduce cache thrashing.
- Однако загрузка кода из SPI flash относительно медленная и в локальной RAM есть весьма ограниченная область используемая как кэш кода. Поэтому внутренние циклы и код, который выполняется часто, должны быть относительно небольшими, чтобы уменьшить частоту загрузки кода в кэш.
 
Сверху Снизу