Page 1 of 1

Demystify external flash MMU and Cache

Posted: Thu Jun 18, 2020 4:01 pm
by ursescuionut1
Hi,

I am currently reading through the ESP32 Reference Manual on the External Memory section. So, here is stated that ESP32 can access external SPI flash and SPI SRAM as external memory. Also the table of Address mapping (External memory) is shown. The next part is saying that 'When a CPU accesses external memory through the Cache and MMU, the cache will map the CPU’s address to an
external physical memory address (in the external memory’s address space), according to the MMU settings. Due
to this address mapping, the ESP32 can address up to 16 MB External Flash and 8 MB External SRAM.'.

Looking in the MMU section from the Reference Manual I found that there is a Cache MMU, that can map pages of flash from the physical address space into virtual memory address space for each PID and CPU CORE source.

So, in order to use the SPI flash I need to populate Cache MMU entries or can I bypass the MMU and use the raw physical address space ?

Now looking through code, I find two API's that I can't really comprehend, so there it is:

- spi_flash_map(): maps a region of physical flash addresses into instruction space or data space of the CPU.
- cache_flash_mmu_set(): which is used in the bootloader code

What's the difference between those two ? Is spi_flash_map not using the Cache ? Looked in the Cache section and found that I can use the SRAM0 as cache for external memory, can I use the external memory without cache, why the External Memory MMU is called Cache MMU ?

It's really confusing, I would appreciate if someone could explain to me a little about how things actually works :D. Maybe you can point me where I can read about it.

Thanks

Re: Demystify external flash MMU and Cache

Posted: Fri Jun 19, 2020 12:59 pm
by ESP_Sprite
In the ESP32, memory accesses to external memory always go via the cache, so the cache MMU is indeed the unit you need to tweak to handle this. Not sure about the API, but ESP-IDF has higher-level APIs to easily handle most of the standard use cases; if what you want to do is not covered by them, we'd love to hear what you're trying to do.

Re: Demystify external flash MMU and Cache

Posted: Thu Jun 25, 2020 4:53 pm
by Olof Astrand
The cache_flash_mmu_set function is documented in the cache.h header file.
Because of ... reasons, the rom function cache_flash_mmu_set_rom almost does the trick, but also allow the other core to run around and possibly fetch instructions from the flash when no flash is mappped. That could cause problems and espressif decided that the following code will do a better job.

Code: Select all

/**
  * @brief Set Flash-Cache mmu mapping.
  *        Please do not call this function in your SDK application.
  *
  * @param  int cpu_no : CPU number, 0 for PRO cpu, 1 for APP cpu.
  *
  * @param  int pod : process identifier. Range 0~7.
  *
  * @param  unsigned int vaddr : virtual address in CPU address space.
  *                              Can be IRam0, IRam1, IRom0 and DRom0 memory address.
  *                              Should be aligned by psize.
  *
  * @param  unsigned int paddr : physical address in Flash.
  *                              Should be aligned by psize.
  *
  * @param  int psize : page size of flash, in kilobytes. Should be 64 here.
  *
  * @param  int num : pages to be set.
  *
  * @return unsigned int: error status
  *                   0 : mmu set success
  *                   1 : vaddr or paddr is not aligned
  *                   2 : pid error
  *                   3 : psize error
  *                   4 : mmu table to be written is out of range
  *                   5 : vaddr is out of range
  */
static inline unsigned int IRAM_ATTR cache_flash_mmu_set(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr,  int psize, int num)
{
    extern unsigned int cache_flash_mmu_set_rom(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr,  int psize, int num);

    unsigned int ret;

    DPORT_STALL_OTHER_CPU_START();
    ret = cache_flash_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num);
    DPORT_STALL_OTHER_CPU_END();

    return ret;
}
If you get into the details of the cache_flash_mmu_set_rom() functions you will find something similar to this,
mmu_table = 3ff10000;
if (cpu_no != PRO) {
mmu_table = 0x3ff12000;
}
And a loop that maps the flash to the desired virtual address (which must be correctly set by the caller).
Also note that the MMU only maps in chunks of 64KB (0x10000) psize=64 . When data is read at an MMU-mapped address that is not available in the cache, the hardware will fetch this data (with a slight delay) but the software developer can consider the MMU mapped data as any other read only memory, available at the 64KB aligned vaddr.
You can read more about this in chapter 7.3.2.2 External Memory in the TRM.

However, the thing to pay most attention to is, Please do not call this function in your SDK application.
Unless you are writing your own bootloader you should use spi_flash_mmap() and esp_partition_mmap().

Here is the documentation that you are looking for:
https://docs.espressif.com/projects/esp ... flash.html
:geek: