ESP32 представляет собой двухъядерную систему с двумя процессорами Xtensa LX6 гарвардской архитектуры. Вся встроенная память, внешняя память и периферийные устройства расположены на шине данных и шине команд этих процессоров.
За некоторыми незначительными исключениями, отображение адресов двух процессоров симметрично, что означает, что они используют одни и те же адреса для доступа к одной и той же памяти.
Некоторые периферийные устройства также напрямую (через DMA-Direct Memory Access) могут обращаться к встроенной памяти.
разбивается на разделы и может использоваться с различными назначениями:
Внешняя память может быть использовано контроллером, как доступное адресное пространство, вместо встроенной памяти. В этом случае часть встроенной памяти становится кэшем для внешней памяти.
Внутреннее ПЗУ разделено на две части: Internal ROM0 (384 КБ) и Internal ROM1 (64 КБ).
Внутренняя оперативная память разделена на три части: Internal SRAM0 (192 КБ), Internal SRAM1 (128 КБ) и Internal SRAM2 (200 Кбайт).
RTC FAST Memory (8 КБ) может использоваться для хранения данных, к ней обращается основной процессор во время загрузки RTC из режима глубокого сна.
RTC SLOW Memory (8 КБ) доступна только сопроцессору ULP в режиме глубокого сна. Сопроцессор ULP (ultra-low-power processor - процессор со сверхнизким потреблением) остаётся в работе в режиме пониженного энергопотреблении Deep Sleep. В данном режиме основные два ядра контроллера не работают.
Объем внутреннего ПЗУ0 составляет 384 КБ. Доступ к нему осуществляется обоими процессорами через диапазон адресов 0x4000_0000 - 0x4005_FFFF, который находится на шине команд.
Диапазон адресов первых 32 КБ ПЗУ0 (0x4000_0000 - 0x4000_7FFF) может быть переназначен для доступа к части внутренней памяти SRAM1, которая обычно находится в диапазоне памяти 0x400B_0000 - 0x400B_7FFF.
При переназначении 32-килобайтная SRAM-память больше не может быть доступна с диапазоном адресов 0x400B_0000 - 0x400B_7FFF, но она все еще может быть доступна через шину данных 0x3FFE_8000 - 0x3FFE_FFFF.
Это можно сделать для каждого процессора: установка бита 0 в регистре DPORT_PRO_BOOT_REMAP_CTRL_REG или DPORT_APP_BOOT_REMAP_CTRL_REG приведет к переназначению SRAM для PRO_CPU и APP_CPU соответственно.
Емкость внутреннего ПЗУ1 составляет 64 КБ. Оно может быть прочитано любым процессором в диапазоне адресов 0x3FF9_0000 - 0x3FF9_FFFF шины данных.
Емкость внутренней памяти SRAM0 составляет 192 КБ. Аппаратное обеспечение может быть настроено таким образом, чтобы использовать первые 64 КБ для кэширования доступа к внешней памяти. Когда они не используются в качестве кэша, первые 64 КБАЙТ могут быть считаны и записаны любым процессором по адресам 0x4007_0000 - 0x4007_FFFF шины команд.
Оставшиеся 128 КБАЙТ всегда могут быть считаны и записаны любым процессором по адресам 0x4008_0000 - 0x4009_FFFF шины команд.
Емкость внутренней памяти SRAM1 составляет 128 КБАЙТ. Любой центральный процессор может считывать и записывать данные из этой памяти по адресам 0x3FFE_0000 - 0x3FFF_FFFF шины данных, а также по адресам 0x400A_0000 - 0x400B_FFFF шины команд.
Доступ к диапазону адресов по шине команд осуществляется в обратном порядке (по словам) по сравнению с доступом по шине данных.
То есть, адреса:
0x3FFE_0000 и 0x400B_FFFC обращаются к одному и тому же слову
0x3FFE_0004 и 0x400B_FFF8 используют одно и то же слово
0x3FFE_0008 и 0x400B_FFF4 используют одно и то же слово
……
0x3FFF_FFF4 и 0x400A_0008 обращаются к одному и тому же слову
0x3FFF_FFF8 и 0x400A_0004 используют одно и то же слово
0x3FFF_FFFC и 0x400A_0000 используют одно и то же слово
Как шина данных, так и шина команд центрального процессора по-прежнему имеют начальный порядок байтов, поэтому порядок байтов отдельных слов в адресных пространствах не меняется на противоположный.
Например, адреса:
0x3FFE_0000 обращается к младшему значащему байту в слове, к которому обращается 0x400B_FFFC;
0x3FFE_0001 обращается ко второму по старшинству байту в слове, к которому обращается 0x400B_FFFC;
0x3FFE_0002 обращается ко второму по старшинству байту в слове, к которому обращается 0x400B_FFFC;
0x3FFE_0003 обращается к старшему значащему байту в слове, к которому обращается 0x400B_FFFC.
0x3FFE_0004 обращается к младшему значащему байту в слове, к которому обращается 0x400B_FFF8;
0x3FFE_0005 обращается ко второму по старшинству байту в слове, к которому обращается 0x400B_FFF8;
0x3FFE_0006 обращается ко второму по старшинству байту в слове, к которому обращается 0x400B_FFF8;
0x3FFE_0007 обращается к старшему значащему байту в слове, к которому обращается 0x400B_FFF8.
Часть этой памяти может быть переназначена в адресное пространство ROM0.
Емкость внутренней памяти SRAM2 составляет 200 КБАЙТ. Она может считываться и записываться любым процессором по адресам 0x3FFA_E000 - 0x3FFD_FFFF на шине данных.
RTC FAST Memory составляет 8 КБ оперативной памяти SRAM. Он может быть прочитан и записан PRO_CPU только в диапазоне адресов 0x3FF8_0000-0x3FF8_1FFF на шине данных или в диапазоне адресов 0x400C_0000 - 0x400C_1FFF на шине команд. В отличие от большинства других областей памяти, быстрая память RTC недоступна для APP_CPU.
Два диапазона адресов PRO_CPU обращаются к быстрой памяти RTC в одинаковом порядке, например, адреса 0x3FF8_0000 и 0x400C_0000 используют одно и то же слово. В APP_CPU эти диапазоны адресов не предоставляют доступ к оперативной памяти RTC или к любой другой ячейке памяти.
RTC SLOW Memory - это 8 КБ SRAM, которые могут считываться и записываться любым процессором с диапазоном адресов 0x5000_0000 - 0x5000_1FFF. Этот диапазон адресов совместно используется как шиной данных, так и шиной команд.
ESP32 может использовать SPI flash и SPI SRAM в качестве внешней памяти. Когда центральный процессор обращается к внешней памяти через кэш, то адрес в кэше сопоставляется с адресом внешней физической памяти в соответствии с настройками MMU (устройство управления памятью, которое выполняет трансляцию адресов памяти между физическими и виртуальными адресами, благодаря этому процессор может обращаться к физической памяти через виртуальные адреса).
Благодаря такому сопоставлению адресов ESP32 может адресовать до 16 МБ внешней флэш-памяти и 8 МБ внешней SRAM.
Каждый из двух процессоров в ESP32 имеет 32 КБ кэш-памяти с размером блока в 32 байта для доступа к внешнему хранилищу. PRO CPU использует бит PRO_CACHE_ENABLE в регистре DPORT_PRO_CACHE_CTRL_REG для включения кэширования, в то время как APP CPU использует бит APP_CACHE_ENABLE в регистре DPORT_APP_CACHE_CTRL_REG для включения той же функции.
ESP32 использует несколько вариантов подключения к кэшу процессора PRO CPU и APP CPU.
Биты CACHE_MUX_MODE в регистре DPORT_CACHE_MUX_MODE_REG ставят в соответствие пулы кэша: POOL0 или POOL1 во внутреннем SRAM0 нулевому или первому процессору для использования в качестве кэш-памяти.
Когда и PRO CPU, и APP CPU используют функцию кэширования, POOL0 и POOL1 во внутренней памяти SRAM0 будут использоваться одновременно в качестве кэш-памяти, в то время как они также могут использоваться и шиной команд.
Как видно, когда бит CACHE_MUX_MODE равен 1 или 2, PRO CPU и APP CPU не могут одновременно включить функцию кэширования.
Когда функция кэширования включена, POOL0 или POOL1 могут использоваться в качестве кэш-памяти для External Memory и поэтому соответствующее пространство адресов не может использоваться шиной команд.
Кэш ESP32 поддерживает функцию очистки. Но стоит отметить, что при использовании функции Flush данные, записанные в кэш, будут удалены, а не перезаписаны во внешнюю SRAM.
Для того, чтобы включить функцию Flush, следует сначала очистить бит x_CACHE_FLUSH_ENA в регистре DPORT_x_CACHE_CTRL_REG, а затем установить этот бит равным 1. После этого системное оборудование установит бит x_CACHE_FLUSH_DONE равным 1, где x может быть ”PRO” или ”APP”, указывая на то, что операция очистки кэша завершена.
DMA в ESP32 - это контроллер прямого доступа к памяти (Direct Memory Access). Он позволяет некоторым периферийным устройствам (UART, SPI, I2C, Ethernet и другим) работать с ОЗУ напрямую, то есть без участия процессора. Это помогает разгрузить процессор и ускорить процесс обмена данными между памятью и периферией, поэтому в ряде случаев грамотное использование DMA позволяет существенно увеличить скорость работы программы.
DMA использует ту же адресацию, что и шина данных центрального процессора: для чтения и записи во внутреннюю SRAM1 0x3FFE_0000 - 0x3FFF_FFFF, для чтения и записи во внутреннюю SRAM2 0x3FFA_E000 - 0x3FFD_FFFF.
В микроконтроллерах ESP32 прямой доступ к памяти имеют 13 периферийных устройств:
UARTx - инструменты последовательной связи для обмена данными между двумя устройствами по протоколу UART (Universal Asynchronous Receiver-Transmitter).
В отличие от SPI или I2C, которые являются синхронными, UART является асинхронным, то есть он не использует тактовый сигнал для синхронизации передачи данных между устройствами. Однако оба устройства должны согласовывать скорость передачи данных (baud).
В UART-коммуникации данные передаются последовательно, побитно, с заранее определённой скоростью (битами в секунду). Для передачи данных используется одна линия (TX), а для приёма — другая (RX).
UART-порты позволяют обмениваться данными с другими устройствами, такими как другие микроконтроллеры, компьютер, датчики, GPS или Bluetooth-модули, некоторые типы дисплеев и другие.
SPIx. SPI (последовательный периферийный интерфейс) - это протокол шины, который позволяет ESP32 взаимодействовать с периферийными устройствами или интегральными схемами, соответствующими протоколу SPI.
В рамках протокола одно устройство (обычно ESP32) действует как «ведущий» шины, а все остальные устройства — как «ведомые». Это означает, что одновременно происходит связь между ведущим и одним отдельным подчиненным. Подчиненные устройства не общаются друг с другом.
Назначение шины состоит в том, что можно подключить несколько устройств к ESP32 (ведущему устройству), используя минимум проводов.
I2Sx. I2S - это синхронный последовательный протокол связи, используемый для передачи цифровых аудиоданных между устройствами. Он предназначен для связи между микрофонами, аудиосенсорами, цифровыми и аналоговыми преобразователями и другими аудиоперифериями.
Протокол I2S использует три основные линии:
ESP32 содержит две I2S-периферии, которые можно настроить для ввода и вывода данных по протоколу I2S.
SDIO Slave - «ведомое» устройство, подключённое к шине SDIO. Чип ESP32 оснащён встроенным интерфейсом SD-карт, который соответствует стандартному протоколу SDIO Card Specification Version 2.0. Он позволяет хост-контроллеру получать доступ к SoC с помощью интерфейса и протокола шины SDIO.
Контроллер «ведомого» устройства (SDIO/SPI slave controller) поддерживает SDIO SPI, однобитный и четырёхбитный режимы обмена данными при тактовых частотах 0–50 МГц. Обмен данными между «ведущим» и «ведомым» устройствами реализуется по стандартному протоколу SDIO V2.0.
SDMMC - это специальная аппаратная шина, которая используется на платах ESP32 и ESP32-S3 для работы с SD-картами. Она позволяет использовать 1, 4 или 8 контактов данных, а также 2 дополнительных контакта связи и 2 контакта питания.
Скорость работы SDMMC в 1-битном режиме примерно в два раза выше, чем в режиме SPI, а в 4-битном режиме примерно в три раза выше, чем в режиме SPI.
EMAC - это интерфейс Ethernet MAC, который обеспечивает канальный уровень передачи данных (аббревиатура от англ. Media Access Control). Он отвечает за управление и подключение физической среды физического уровня.
ESP32 оснащен 41 периферийным устройством. В следующих таблицах подробно описаны периферийные устройства и соответствующие им диапазоны адресов. Доступ к почти всем периферийным модулям может осуществляться любым процессором по одному и тому же адресу, за единственным исключением - это PID-контроллер.
Замечание:
Для детального знакомства с контроллером Esp32 в меню инструментов IDE Arduino изменим настройки подменю общих параметров платы:
Partition Scheme: "Huge APP (3MB No OTA/1MB SPIFFS)"
Core Debug Level: "Verbose"
В скетч просто включим вывод результатов некоторых системных методов по заголовочному файлу “Esp.h”, который штатно включен в IDE Arduino для ESP32.
/** Arduino-Esp32-CAM *** ControllerMemory.ino ***
*
* Показать информацию по встроенной и внешней памяти,
* и сведения о системе контроллера ESP32
*
* v1.0, 20.10.2024 Автор: Труфанов В.Е.
* Copyright © 2024 tve Дата создания: 20.10.2024
*
**/
/*
Esp.h - ESP31B-specific APIs
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
*/
char buffer[60]; // буфер сообщения
void setup()
{
Serial.begin(115200);
Serial.println("");
// Получаем полный размер кучи в памяти
printf("Общий размер ВСТРОЕННОЙ памяти: %u\n", ESP.getHeapSize());
// Количество доступной кучи в памяти
printf("Оставшаяся доступная память в куче: %u\n", ESP.getFreeHeap());
// Самый низкий уровень свободной кучи с момента загрузки
printf("Минимальная свободная с загрузки: %u\n", ESP.getMinFreeHeap());
// Размер самого большого блока кучи, который может быть выделен.
printf("Самый большой блок для выделения: %u\n", ESP.getMaxAllocHeap());
// Размер текущего скетча в виде беззнакового 32-битного целого числа
printf("Размер текущего скетча: %u\n", ESP.getSketchSize());
Serial.println("");
// Размер флэш-чипа в байтах. Этот параметр может быть меньше фактического размера.
printf("Флэш-чип: SPI Flash File Storage %u\n", ESP.getFlashChipSize());
// Размер общей кучи SPI PSRAM
printf("Общий размер SPI PSRAM: %u\n", ESP.getPsramSize());
// Количество свободной PSRAM
printf("Количество свободной PSRAM: %d\n", ESP.getFreePsram());
// Минимальный размер свободной памяти в SPI RAM
printf("Минимум свободной SPI PSRAM: %d\n", ESP.getMinFreePsram());
// Размер самого большого блока PSRAM, который может быть выделен
printf("Самый большой блок для выделения: %d\n", ESP.getMaxAllocPsram());
// Размер свободного пространства для скетча в виде 32-битного целого
printf("Cвободное пространство для скетча: %u\n", ESP.getFreeSketchSpace());
Serial.println("");
// Модель ЧИПа
sprintf(buffer,
"Модель контроллера: (%s)\n", ESP.getChipModel());
Serial.print(buffer);
// Номер ревизии чипа
printf("Номер версии чипа: %d\n", ESP.getChipRevision());
// Количество процессорных ядер в микроконтроллере
printf("Количество процессорных ядер: %d\n", ESP.getChipCores());
// Частота процессора в МГц в виде беззнакового 8-битного целого числа
printf("Частота процессора в МГц: %d\n", ESP.getCpuFreqMHz());
// getFlashChipSpeed
printf("getFlashChipSpeed: %u\n", ESP.getFlashChipSpeed());
Serial.println("");
// version of ESP-IDF
sprintf(buffer,
"Версия ESP-IDF: (%s)\n", ESP.getSdkVersion());
Serial.print(buffer);
// version of this core
sprintf(buffer,
"Версия ESP32 в IDE Arduino: (%s)\n", ESP.getCoreVersion());
Serial.print(buffer);
Serial.println("");
}
void loop() {}
// *************************************************** ControllerMemory.ino ***
В ходе выполнения скетча будут выведены данные, которые заказаны в программе и отладочные сведения до и после работы приложения.
И та, и другая информация хорошо согласованы:
=========== Before Setup Start ===========
Chip Info:
------------------------------------------
Model : ESP32
Package : D0WD-Q5
Revision : 1.00
Cores : 2
CPU Frequency : 240 MHz
XTAL Frequency : 40 MHz
Features Bitfield : 0x00000032
Embedded Flash : No
Embedded PSRAM : No
2.4GHz WiFi : Yes
Classic BT : Yes
BT Low Energy : Yes
IEEE 802.15.4 : No
------------------------------------------
INTERNAL Memory Info:
------------------------------------------
Total Size : 380556 B ( 371.6 KB)
Free Bytes : 350268 B ( 342.1 KB)
Allocated Bytes : 23172 B ( 22.6 KB)
Minimum Free Bytes: 344756 B ( 336.7 KB)
Largest Free Block: 118772 B ( 116.0 KB)
------------------------------------------
SPIRAM Memory Info:
------------------------------------------
Total Size : 4194304 B (4096.0 KB)
Free Bytes : 4192124 B (4093.9 KB)
Allocated Bytes : 0 B ( 0.0 KB)
Minimum Free Bytes: 4192124 B (4093.9 KB)
Largest Free Block: 4128756 B (4032.0 KB)
Bus Mode : QSPI
------------------------------------------
Flash Info:
------------------------------------------
Chip Size : 4194304 B (4 MB)
Block Size : 65536 B ( 64.0 KB)
Sector Size : 4096 B ( 4.0 KB)
Page Size : 256 B ( 0.2 KB)
Bus Speed : 80 MHz
Bus Mode : QIO
------------------------------------------
Partitions Info:
------------------------------------------
nvs : addr: 0x00009000, size: 20.0 KB, type: DATA NVS
otadata : addr: 0x0000E000, size: 8.0 KB, type: DATA OTA
app0 : addr: 0x00010000, size: 3072.0 KB, type: APP OTA_0
spiffs : addr: 0x00310000, size: 896.0 KB, type: DATA SPIFFS
coredump : addr: 0x003F0000, size: 64.0 KB, type: DATA COREDUMP
------------------------------------------
Software Info:
------------------------------------------
Compile Date/Time : Nov 20 2024 13:43:51
Compile Host OS : windows
ESP-IDF Version : v5.1.4-972-g632e0c2a9f-dirty
Arduino Version : 3.0.6
------------------------------------------
Board Info:
------------------------------------------
Arduino Board : ESP32_DEV
Arduino Variant : esp32
Arduino FQBN : esp32:esp32:esp32cam:CPUFreq=240, FlashMode=qio,
PartitionScheme=huge_app, FlashFreq=80,
DebugLevel=verbose, EraseFlash=none
============ Before Setup End ============
[ 1196][V][esp32-hal-uart.c:408] UART0 baud(115200) Mode(800001c) rxPin(3) txPin(1)
[ 1205][V][esp32-hal-uart.c:497] UART0 not installed. Starting installation
[ 1216][V][esp32-hal-uart.c:560] UART0 initialization done.
Общий размер ВСТРОЕННОЙ памяти: 380556
Оставшаяся доступная память в куче: 348372
Минимальная свободная с загрузки: 342860
Самый большой блок для выделения: 118772
Размер текущего скетча: 304528
Флэш-чип: SPI Flash File Storage 4194304
Общий размер SPI PSRAM: 4194304
Количество свободной PSRAM: 4192124
Минимум свободной SPI PSRAM: 4192124
Самый большой блок для выделения: 4128756
Cвободное пространство для скетча: 3145728
Модель контроллера: (ESP32-D0WD)
Номер версии чипа: 100
Количество процессорных ядер: 2
Частота процессора в МГц: 240
getFlashChipSpeed: 80000000
Версия ESP-IDF: (v5.1.4-972-g632e0c2a9f-dirty)
Версия ESP32 в IDE Arduino: (3.0.6)
=========== After Setup Start ============
INTERNAL Memory Info:
------------------------------------------
Total Size : 380556 B ( 371.6 KB)
Free Bytes : 348272 B ( 340.1 KB)
Allocated Bytes : 24896 B ( 24.3 KB)
Minimum Free Bytes: 342572 B ( 334.5 KB)
Largest Free Block: 118772 B ( 116.0 KB)
------------------------------------------
SPIRAM Memory Info:
------------------------------------------
Total Size : 4194304 B (4096.0 KB)
Free Bytes : 4192124 B (4093.9 KB)
Allocated Bytes : 0 B ( 0.0 KB)
Minimum Free Bytes: 4192124 B (4093.9 KB)
Largest Free Block: 4128756 B (4032.0 KB)
------------------------------------------
GPIO Info:
------------------------------------------
GPIO : BUS_TYPE[bus/unit][chan]
--------------------------------------
1 : UART_TX[0]
3 : UART_RX[0]
============ After Setup End =============