Add initial SPI RAM support. This adds support for an ESP-PSRAM32 chip connected to the default flash pins and GPIO 16 and 17. The RAM is mapped to address 0x3F800000, but otherwise ignored by esp-idf as of yet.

This commit is contained in:
Jeroen Domburg 2017-07-20 16:26:35 +08:00
parent 518edac42f
commit 34372a091c
22 changed files with 1412 additions and 198 deletions

View File

@ -8,6 +8,7 @@
LINKER_SCRIPTS := \
esp32.bootloader.ld \
$(IDF_PATH)/components/esp32/ld/esp32.rom.ld \
$(IDF_PATH)/components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld \
$(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \
esp32.bootloader.rom.ld

View File

@ -27,9 +27,103 @@ config MEMMAP_SMP
The ESP32 contains two cores. If you plan to only use one, you can disable this item
to save some memory. (ToDo: Make this automatically depend on unicore support)
config SPIRAM_SUPPORT
bool "Support for external, SPI-connected RAM"
default "n"
help
This enables support for an external SPI RAM chip, connected in parallel with the
main SPI flash chip.
menu "SPI RAM config"
depends on SPIRAM_SUPPORT
config SPIRAM_BOOT_INIT
bool "Initialize SPI RAM when booting the ESP32"
default "y"
help
If this is enabled, the SPI RAM will be enabled during initial boot. Unless you
have specific requirements, you'll want to leave this enabled so memory allocated
during boot-up can also be placed in SPI RAM.
choice SPIRAM_USE
prompt "SPI RAM access method"
default SPIRAM_USE_MEMMAP
help
The SPI RAM can be accessed in multiple methods: by just having it available as an unmanaged
memory region in the ESP32 memory map, by integrating it in the ESP32s heap as 'special' memory
needing heap_caps_malloc to allocate, or by fully integrating it making malloc() also able to
return SPI RAM pointers.
config SPIRAM_USE_MEMMAP
bool "Integrate RAM into ESP32 memory map"
config SPIRAM_USE_CAPS_ALLOC
bool "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPISRAM)"
depends on TO_BE_DONE
config SPIRAM_USE_MALLOC
bool "Make RAM allocatable using malloc as well"
depends on TO_BE_DONE
endchoice
choice SPIRAM_TYPE
prompt "Type of SPI RAM chip in use"
default SPIRAM_TYPE_ESPPSRAM32
config SPIRAM_TYPE_ESPPSRAM32
bool "ESP-PSRAM32 or IS25WP032"
endchoice
config SPIRAM_SIZE
int
default 4194304 if SPIRAM_TYPE_ESPPSRAM32
default 0
choice SPIRAM_SPEED
prompt "Set RAM clock speed"
default SPIRAM_CACHE_SPEED_40M
help
Select the speed for the SPI RAM chip.
If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now:
1. Flash SPI running at 40Mhz and RAM SPI running at 40Mhz
2. Flash SPI running at 80Mhz and RAM SPI running at 40Mhz
3. Flash SPI running at 80Mhz and RAM SPI running at 80Mhz
Note: If the third mode(80Mhz+80Mhz) is enabled, the VSPI port will be occupied by the system.
Application code should never touch VSPI hardware in this case. The option to select
80MHz will only be visible if the flash SPI speed is also 80MHz. (ESPTOOLPY_FLASHFREQ_80M is true)
config SPIRAM_SPEED_40M
bool "40MHz clock speed"
config SPIRAM_SPEED_80M
depends on ESPTOOLPY_FLASHFREQ_80M
bool "80MHz clock speed"
endchoice
config SPIRAM_MEMTEST
bool "Run memory test on SPI RAM initialization"
default "y"
help
Runs a rudimentary memory test on initialization. Aborts when memory test fails. Disable this for
slightly faster startop.
config SPIRAM_CACHE_WORKAROUND
bool "Enable workaround for bug in SPI RAM cache for Rev1 ESP32s"
depends on SPIRAM_USE_MEMMAP || SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC
default "y"
help
Revision 1 of the ESP32 has a bug that can cause a write to PSRAM not to take place in some situations
when the cache line needs to be fetched from external RAM and an interrupt occurs. This enables a
fix in the compiler that makes sure the specific code that is vulnerable to this will not be emitted.
This will also not use any bits of newlib that are located in ROM, opting for a version that is compiled
with the workaround and located in flash instead.
endmenu
config MEMMAP_TRACEMEM
bool
default "n"
bool
default "n"
config MEMMAP_TRACEMEM_TWOBANKS
bool
@ -104,16 +198,6 @@ config ESP32_CORE_DUMP_LOG_LEVEL
help
Config core dump module logging level (0-5).
# Not implemented and/or needs new silicon rev to work
config MEMMAP_SPISRAM
bool "Use external SPI SRAM chip as main memory"
depends on ESP32_NEEDS_NEW_SILICON_REV
default "n"
help
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the
main memory map. Enable this if you have this hardware and want to use it in the same
way as on-chip RAM.
choice NUMBER_OF_UNIVERSAL_MAC_ADDRESS
bool "Number of universally administered (by IEEE) MAC address"
default FOUR_UNIVERSAL_MAC_ADDRESS

View File

@ -30,3 +30,14 @@ all: phy_init_data
flash: phy_init_data
endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
# Enable psram cache bug workaround in compiler if selected
ifdef CONFIG_SPIRAM_CACHE_WORKAROUND
CFLAGS+=-mfix-esp32-psram-cache-issue
CXXFLAGS+=-mfix-esp32-psram-cache-issue
#Filter out the standard libstdc++ linkage. The component.mk will add a specific
#cache-workaround-enabled version.
LDFLAGS:=$(filter-out -lstdc++,$(LDFLAGS))
endif

View File

@ -7,8 +7,17 @@ ifndef CONFIG_NO_BLOBS
LIBS := core rtc net80211 pp wpa smartconfig coexist wps wpa2 phy
endif
#Linker scripts used to link the final application.
#Warning: These linker scripts are only used when the normal app is compiled; the bootloader
#specifies its own scripts.
LINKER_SCRIPTS += esp32.common.ld esp32.rom.ld esp32.peripherals.ld
#SPI-RAM incompatible functions can be used in when the SPI RAM
#workaround is not enabled.
ifndef CONFIG_SPIRAM_CACHE_WORKAROUND
LINKER_SCRIPTS += esp32.rom.spiram_incompatible_fns.ld
endif
ifeq ("$(CONFIG_NEWLIB_NANO_FORMAT)","y")
LINKER_SCRIPTS += esp32.rom.nanofmt.ld
endif
@ -28,6 +37,11 @@ COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libhal.a \
-u ld_include_panic_highint_hdl \
$(addprefix -T ,$(LINKER_SCRIPTS))
#The cache workaround also needs a c++ standard library recompiled with the workaround.
ifdef CONFIG_SPIRAM_CACHE_WORKAROUND
COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/libstdcc++-cache-workaround.a
endif
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
COMPONENT_SUBMODULES += lib

View File

@ -63,6 +63,7 @@
#include "esp_core_dump.h"
#include "esp_app_trace.h"
#include "esp_efuse.h"
#include "esp_spiram.h"
#include "esp_clk.h"
#include "esp_timer.h"
#include "trax.h"
@ -147,6 +148,13 @@ void IRAM_ATTR call_start_cpu0()
memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
}
#if CONFIG_SPIRAM_BOOT_INIT
if (esp_spiram_init() != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to init external RAM!");
abort();
}
#endif
ESP_EARLY_LOGI(TAG, "Pro cpu up.");
#if !CONFIG_FREERTOS_UNICORE
@ -175,11 +183,23 @@ void IRAM_ATTR call_start_cpu0()
DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
#endif
#if CONFIG_SPIRAM_MEMTEST
bool ext_ram_ok=esp_spiram_test();
if (!ext_ram_ok) {
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
abort();
}
#endif
/* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted.
If the heap allocator is initialized first, it will put free memory linked list items into
memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory,
corrupting those linked lists. Initializing the allocator *after* the app cpu has booted
works around this problem. */
works around this problem.
With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the
app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may
fail initializing it properly. */
heap_caps_init();
ESP_EARLY_LOGI(TAG, "Pro cpu start user code");

View File

@ -0,0 +1,61 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_SPIRAM_H
#define __ESP_SPIRAM_H
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
*
* @return ESP_OK on success
*/
esp_err_t esp_spiram_init();
/**
* @brief Memory test for SPI RAM. Should be called after SPI RAM is initialized and
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in SPI RAM.
*
* @return true on success, false on failed memory test
*/
bool esp_spiram_test();
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size();
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI
* RAM cache.
*
* This is meant for use from within the SPI flash code.
*/
void esp_spiram_writeback_cache();
#endif

View File

@ -4,7 +4,6 @@ Generated for ROM with MD5sum:
ab8282ae908fe9e7a63fb2a4ac2df013 ../../rom_image/prorom.elf
*/
PROVIDE ( abort = 0x4000bba4 );
PROVIDE ( abs = 0x40056340 );
PROVIDE ( __absvdi2 = 0x4006387c );
PROVIDE ( __absvsi2 = 0x40063868 );
PROVIDE ( Add2SelfBigHex256 = 0x40015b7c );
@ -21,15 +20,8 @@ PROVIDE ( aes_128_cbc_encrypt = 0x4005cc18 );
PROVIDE ( aes_unwrap = 0x4005ccf0 );
PROVIDE ( app_gpio_arg = 0x3ffe003c );
PROVIDE ( app_gpio_handler = 0x3ffe0040 );
PROVIDE ( __ascii_wctomb = 0x40058ef0 );
PROVIDE ( asctime = 0x40059588 );
PROVIDE ( asctime_r = 0x40000ec8 );
PROVIDE ( __ashldi3 = 0x4000c818 );
PROVIDE ( __ashrdi3 = 0x4000c830 );
PROVIDE ( atoi = 0x400566c4 );
PROVIDE ( _atoi_r = 0x400566d4 );
PROVIDE ( atol = 0x400566ec );
PROVIDE ( _atol_r = 0x400566fc );
PROVIDE ( base64_decode = 0x4005ced8 );
PROVIDE ( base64_encode = 0x4005cdbc );
PROVIDE ( BasePoint_x_256 = 0x3ff97488 );
@ -49,7 +41,6 @@ PROVIDE ( btdm_r_modules_func_p_get = 0x4005427c );
PROVIDE ( btdm_r_modules_func_p_set = 0x40054270 );
PROVIDE ( btdm_r_plf_func_p_set = 0x40054288 );
PROVIDE ( bt_util_buf_env = 0x3ffb8bd4 );
PROVIDE ( bzero = 0x4000c1f4 );
PROVIDE ( cache_flash_mmu_set_rom = 0x400095e0 );
PROVIDE ( Cache_Flush_rom = 0x40009a14 );
PROVIDE ( Cache_Read_Disable_rom = 0x40009ab8 );
@ -60,10 +51,7 @@ PROVIDE ( cache_sram_mmu_set_rom = 0x400097f4 );
PROVIDE ( calc_rtc_memory_crc = 0x40008170 );
PROVIDE ( calloc = 0x4000bee4 );
PROVIDE ( _calloc_r = 0x4000bbf8 );
PROVIDE ( _cleanup = 0x40001df8 );
PROVIDE ( _cleanup_r = 0x40001d48 );
PROVIDE ( __clear_cache = 0x40063860 );
PROVIDE ( close = 0x40001778 );
PROVIDE ( _close_r = 0x4000bd3c );
PROVIDE ( __clrsbdi2 = 0x40064a38 );
PROVIDE ( __clrsbsi2 = 0x40064a20 );
@ -79,9 +67,6 @@ PROVIDE ( crc32_be = 0x4005d024 );
PROVIDE ( crc32_le = 0x4005cfec );
PROVIDE ( crc8_be = 0x4005d114 );
PROVIDE ( crc8_le = 0x4005d0e0 );
PROVIDE ( creat = 0x40000e8c );
PROVIDE ( ctime = 0x400595b0 );
PROVIDE ( ctime_r = 0x400595c4 );
PROVIDE ( _ctype_ = 0x3ff96354 );
PROVIDE ( __ctype_ptr__ = 0x3ff96350 );
PROVIDE ( __ctzdi2 = 0x4000ca64 );
@ -118,7 +103,6 @@ PROVIDE ( dh_group2_generator = 0x3ff9ada2 );
PROVIDE ( dh_group2_prime = 0x3ff9ad22 );
PROVIDE ( dh_group5_generator = 0x3ff9ad21 );
PROVIDE ( dh_group5_prime = 0x3ff9ac61 );
PROVIDE ( div = 0x40056348 );
PROVIDE ( __divdc3 = 0x40064460 );
PROVIDE ( __divdf3 = 0x40002954 );
PROVIDE ( __divdi3 = 0x4000ca84 );
@ -126,14 +110,10 @@ PROVIDE ( __divsc3 = 0x40064200 );
PROVIDE ( __divsf3 = 0x4000234c );
PROVIDE ( __divsi3 = 0x4000c7b8 );
PROVIDE ( g_rom_spiflash_dummy_len_plus = 0x3ffae290 );
PROVIDE ( __dummy_lock = 0x4000c728 );
PROVIDE ( __dummy_lock_try = 0x4000c730 );
PROVIDE ( ecc_env = 0x3ffb8d60 );
PROVIDE ( ecc_Jacobian_InfinityPoint256 = 0x3ff972e8 );
PROVIDE ( em_buf_env = 0x3ffb8d74 );
PROVIDE ( environ = 0x3ffae0b4 );
PROVIDE ( __env_lock = 0x40001fd4 );
PROVIDE ( __env_unlock = 0x40001fe0 );
PROVIDE ( __eqdf2 = 0x400636a8 );
PROVIDE ( __eqsf2 = 0x40063374 );
PROVIDE ( esp_crc8 = 0x4005d144 );
@ -143,13 +123,8 @@ PROVIDE ( ets_startup_callback = 0x3ffe0404 );
PROVIDE ( exc_cause_table = 0x3ff991d0 );
PROVIDE ( _exit_r = 0x4000bd28 );
PROVIDE ( __extendsfdf2 = 0x40002c34 );
PROVIDE ( fclose = 0x400020ac );
PROVIDE ( _fclose_r = 0x40001fec );
PROVIDE ( fflush = 0x40059394 );
PROVIDE ( _fflush_r = 0x40059320 );
PROVIDE ( __ffsdi2 = 0x4000ca2c );
PROVIDE ( __ffssi2 = 0x4000c804 );
PROVIDE ( _findenv_r = 0x40001f44 );
PROVIDE ( __fixdfdi = 0x40002ac4 );
PROVIDE ( __fixdfsi = 0x40002a78 );
PROVIDE ( __fixsfdi = 0x4000244c );
@ -165,31 +140,19 @@ PROVIDE ( __floatundidf = 0x4000c978 );
PROVIDE ( __floatundisf = 0x4000c8b0 );
PROVIDE ( __floatunsidf = 0x4000c938 );
PROVIDE ( __floatunsisf = 0x4000c864 );
PROVIDE ( __fp_lock_all = 0x40001f1c );
PROVIDE ( __fp_unlock_all = 0x40001f30 );
PROVIDE ( fputwc = 0x40058ea8 );
PROVIDE ( __fputwc = 0x40058da0 );
PROVIDE ( _fputwc_r = 0x40058e4c );
PROVIDE ( free = 0x4000beb8 );
PROVIDE ( _free_r = 0x4000bbcc );
PROVIDE ( _fstat_r = 0x4000bccc );
PROVIDE ( _fwalk = 0x4000c738 );
PROVIDE ( _fwalk_reent = 0x4000c770 );
PROVIDE ( __gcc_bcmp = 0x40064a70 );
PROVIDE ( __gedf2 = 0x40063768 );
PROVIDE ( __gesf2 = 0x4006340c );
PROVIDE ( __get_current_time_locale = 0x40001834 );
PROVIDE ( _getenv_r = 0x40001fbc );
PROVIDE ( _getpid_r = 0x4000bcfc );
PROVIDE ( __getreent = 0x4000be8c );
PROVIDE ( _gettimeofday_r = 0x4000bc58 );
PROVIDE ( __gettzinfo = 0x40001fcc );
PROVIDE ( GF_Jacobian_Point_Addition256 = 0x400163a4 );
PROVIDE ( GF_Jacobian_Point_Double256 = 0x40016260 );
PROVIDE ( GF_Point_Jacobian_To_Affine256 = 0x40016b0c );
PROVIDE ( _global_impure_ptr = 0x3ffae0b0 );
PROVIDE ( gmtime = 0x40059848 );
PROVIDE ( gmtime_r = 0x40059868 );
PROVIDE ( g_phyFuns_instance = 0x3ffae0c4 );
PROVIDE ( g_rom_flashchip = 0x3ffae270 );
PROVIDE ( __gtdf2 = 0x400636dc );
@ -216,26 +179,10 @@ PROVIDE ( hmac_sha1 = 0x40060acc );
PROVIDE ( hmac_sha1_vector = 0x400609e4 );
PROVIDE ( hmac_sha256 = 0x40060d58 );
PROVIDE ( hmac_sha256_vector = 0x40060c84 );
PROVIDE ( isalnum = 0x40000f04 );
PROVIDE ( isalpha = 0x40000f18 );
PROVIDE ( isascii = 0x4000c20c );
PROVIDE ( _isatty_r = 0x40000ea0 );
PROVIDE ( isblank = 0x40000f2c );
PROVIDE ( iscntrl = 0x40000f50 );
PROVIDE ( isdigit = 0x40000f64 );
PROVIDE ( isgraph = 0x40000f94 );
PROVIDE ( islower = 0x40000f78 );
PROVIDE ( isprint = 0x40000fa8 );
PROVIDE ( ispunct = 0x40000fc0 );
PROVIDE ( isspace = 0x40000fd4 );
PROVIDE ( isupper = 0x40000fe8 );
PROVIDE ( itoa = 0x400566b4 );
PROVIDE ( __itoa = 0x40056678 );
PROVIDE ( jd_decomp = 0x400613e8 );
PROVIDE ( jd_prepare = 0x40060fa8 );
PROVIDE ( ke_env = 0x3ffb93cc );
PROVIDE ( _kill_r = 0x4000bd10 );
PROVIDE ( labs = 0x40056370 );
PROVIDE ( lb_default_handler = 0x3ff982b8 );
PROVIDE ( lb_default_state_tab_p_get = 0x4001c198 );
PROVIDE ( lb_env = 0x3ffb9424 );
@ -251,7 +198,6 @@ PROVIDE ( ld_acl_br_types = 0x3ff98a36 );
PROVIDE ( ld_acl_edr_sizes = 0x3ff98a14 );
PROVIDE ( ld_acl_edr_types = 0x3ff98a22 );
PROVIDE ( ld_env = 0x3ffb9510 );
PROVIDE ( ldiv = 0x40056378 );
PROVIDE ( ld_pcm_settings_dft = 0x3ff98a0c );
PROVIDE ( ld_sched_params = 0x3ffb96c0 );
PROVIDE ( ld_sync_train_channels = 0x3ff98a3c );
@ -292,25 +238,14 @@ PROVIDE ( lm_n_page_tab = 0x3ff990e8 );
PROVIDE ( lmp_desc_tab = 0x3ff96e6c );
PROVIDE ( lmp_ext_desc_tab = 0x3ff96d9c );
PROVIDE ( lm_state = 0x3ffb9a1c );
PROVIDE ( __locale_charset = 0x40059540 );
PROVIDE ( __locale_cjk_lang = 0x40059558 );
PROVIDE ( localeconv = 0x4005957c );
PROVIDE ( _localeconv_r = 0x40059560 );
PROVIDE ( __locale_mb_cur_max = 0x40059548 );
PROVIDE ( __locale_msgcharset = 0x40059550 );
PROVIDE ( localtime = 0x400595dc );
PROVIDE ( localtime_r = 0x400595fc );
PROVIDE ( _lock_acquire = 0x4000be14 );
PROVIDE ( _lock_acquire_recursive = 0x4000be28 );
PROVIDE ( _lock_close = 0x4000bdec );
PROVIDE ( _lock_close_recursive = 0x4000be00 );
PROVIDE ( _lock_init = 0x4000bdc4 );
PROVIDE ( _lock_init_recursive = 0x4000bdd8 );
PROVIDE ( _lock_release = 0x4000be64 );
PROVIDE ( _lock_release_recursive = 0x4000be78 );
PROVIDE ( _lock_try_acquire = 0x4000be3c );
PROVIDE ( _lock_try_acquire_recursive = 0x4000be50 );
PROVIDE ( longjmp = 0x400562cc );
PROVIDE ( _lseek_r = 0x4000bd8c );
PROVIDE ( __lshrdi3 = 0x4000c84c );
PROVIDE ( __ltdf2 = 0x40063790 );
@ -323,14 +258,6 @@ PROVIDE ( MD5Final = 0x4005db1c );
PROVIDE ( MD5Init = 0x4005da7c );
PROVIDE ( MD5Update = 0x4005da9c );
PROVIDE ( md5_vector = 0x4005db80 );
PROVIDE ( memccpy = 0x4000c220 );
PROVIDE ( memchr = 0x4000c244 );
PROVIDE ( memcmp = 0x4000c260 );
PROVIDE ( memcpy = 0x4000c2c8 );
PROVIDE ( memmove = 0x4000c3c0 );
PROVIDE ( memrchr = 0x4000c400 );
PROVIDE ( memset = 0x4000c44c );
PROVIDE ( mktime = 0x4005a5e8 );
PROVIDE ( mmu_init = 0x400095a4 );
PROVIDE ( __moddi3 = 0x4000cd4c );
PROVIDE ( __modsi3 = 0x4000c7c0 );
@ -360,7 +287,6 @@ PROVIDE ( __nesf2 = 0x40063374 );
PROVIDE ( notEqual256 = 0x40015b04 );
PROVIDE ( __nsau_data = 0x3ff96544 );
PROVIDE ( one_bits = 0x3ff971f8 );
PROVIDE ( open = 0x4000178c );
PROVIDE ( _open_r = 0x4000bd54 );
PROVIDE ( __paritysi2 = 0x40002f3c );
PROVIDE ( pbkdf2_sha1 = 0x40060ba4 );
@ -372,10 +298,6 @@ PROVIDE ( __powidf2 = 0x400638d4 );
PROVIDE ( __powisf2 = 0x4006389c );
PROVIDE ( _Pri_4_HandlerAddress = 0x3ffe0648 );
PROVIDE ( _Pri_5_HandlerAddress = 0x3ffe064c );
PROVIDE ( qsort = 0x40056424 );
PROVIDE ( _raise_r = 0x4000bc70 );
PROVIDE ( rand = 0x40001058 );
PROVIDE ( rand_r = 0x400010d4 );
PROVIDE ( r_btdm_option_data = 0x3ffae6e0 );
PROVIDE ( r_bt_util_buf_acl_rx_alloc = 0x40010218 );
PROVIDE ( r_bt_util_buf_acl_rx_free = 0x40010234 );
@ -419,7 +341,6 @@ PROVIDE ( r_E22 = 0x400109b4 );
PROVIDE ( r_E3 = 0x40010a58 );
PROVIDE ( r_ea_alarm_clear = 0x40015ab4 );
PROVIDE ( r_ea_alarm_set = 0x40015a10 );
PROVIDE ( read = 0x400017dc );
PROVIDE ( _read_r = 0x4000bda8 );
PROVIDE ( r_ea_elt_cancel = 0x400150d0 );
PROVIDE ( r_ea_elt_create = 0x40015264 );
@ -1440,24 +1361,10 @@ PROVIDE ( rwip_priority = 0x3ff99159 );
PROVIDE ( rwip_rf = 0x3ffbdb28 );
PROVIDE ( rwip_rf_p_get = 0x400558f4 );
PROVIDE ( r_XorKey = 0x400112c0 );
PROVIDE ( sbrk = 0x400017f4 );
PROVIDE ( _sbrk_r = 0x4000bce4 );
PROVIDE ( __sccl = 0x4000c498 );
PROVIDE ( __sclose = 0x400011b8 );
PROVIDE ( __seofread = 0x40001148 );
PROVIDE ( setjmp = 0x40056268 );
PROVIDE ( setlocale = 0x40059568 );
PROVIDE ( _setlocale_r = 0x4005950c );
PROVIDE ( __sf_fake_stderr = 0x3ff96458 );
PROVIDE ( __sf_fake_stdin = 0x3ff96498 );
PROVIDE ( __sf_fake_stdout = 0x3ff96478 );
PROVIDE ( __sflush_r = 0x400591e0 );
PROVIDE ( __sfmoreglue = 0x40001dc8 );
PROVIDE ( __sfp = 0x40001e90 );
PROVIDE ( __sfp_lock_acquire = 0x40001e08 );
PROVIDE ( __sfp_lock_release = 0x40001e14 );
PROVIDE ( __sfputs_r = 0x40057790 );
PROVIDE ( __sfvwrite_r = 0x4005893c );
PROVIDE ( sha1_prf = 0x40060ae8 );
PROVIDE ( sha1_vector = 0x40060b64 );
PROVIDE ( sha256_prf = 0x40060d70 );
@ -1466,9 +1373,6 @@ PROVIDE ( sha_blk_bits = 0x3ff99290 );
PROVIDE ( sha_blk_bits_bytes = 0x3ff99288 );
PROVIDE ( sha_blk_hash_bytes = 0x3ff9928c );
PROVIDE ( sig_matrix = 0x3ffae293 );
PROVIDE ( __sinit = 0x40001e38 );
PROVIDE ( __sinit_lock_acquire = 0x40001e20 );
PROVIDE ( __sinit_lock_release = 0x40001e2c );
PROVIDE ( sip_after_tx_complete = 0x4000b358 );
PROVIDE ( sip_alloc_to_host_evt = 0x4000ab9c );
PROVIDE ( sip_get_ptr = 0x4000b34c );
@ -1494,15 +1398,7 @@ PROVIDE ( slc_reattach = 0x4000b62c );
PROVIDE ( slc_send_to_host_chain = 0x4000b6a0 );
PROVIDE ( slc_set_host_io_max_window = 0x4000b89c );
PROVIDE ( slc_to_host_chain_recycle = 0x4000b758 );
PROVIDE ( __smakebuf_r = 0x40059108 );
PROVIDE ( specialModP256 = 0x4001600c );
PROVIDE ( srand = 0x40001004 );
PROVIDE ( __sread = 0x40001118 );
PROVIDE ( __srefill_r = 0x400593d4 );
PROVIDE ( __sseek = 0x40001184 );
PROVIDE ( __ssprint_r = 0x40056ff8 );
PROVIDE ( __ssputs_r = 0x40056f2c );
PROVIDE ( __ssrefill_r = 0x40057fec );
PROVIDE ( __stack = 0x3ffe3f20 );
PROVIDE ( __stack_app = 0x3ffe7e30 );
PROVIDE ( _stack_sentry = 0x3ffe1320 );
@ -1511,41 +1407,7 @@ PROVIDE ( _start = 0x40000704 );
PROVIDE ( start_tb_console = 0x4005a980 );
PROVIDE ( _stat_r = 0x4000bcb4 );
PROVIDE ( _stext = 0x40000560 );
PROVIDE ( strcasecmp = 0x400011cc );
PROVIDE ( strcasestr = 0x40001210 );
PROVIDE ( strcat = 0x4000c518 );
PROVIDE ( strchr = 0x4000c53c );
PROVIDE ( strcmp = 0x40001274 );
PROVIDE ( strcoll = 0x40001398 );
PROVIDE ( strcpy = 0x400013ac );
PROVIDE ( strcspn = 0x4000c558 );
PROVIDE ( strdup = 0x4000143c );
PROVIDE ( _strdup_r = 0x40001450 );
PROVIDE ( strftime = 0x40059ab4 );
PROVIDE ( strlcat = 0x40001470 );
PROVIDE ( strlcpy = 0x4000c584 );
PROVIDE ( strlen = 0x400014c0 );
PROVIDE ( strlwr = 0x40001524 );
PROVIDE ( strncasecmp = 0x40001550 );
PROVIDE ( strncat = 0x4000c5c4 );
PROVIDE ( strncmp = 0x4000c5f4 );
PROVIDE ( strncpy = 0x400015d4 );
PROVIDE ( strndup = 0x400016b0 );
PROVIDE ( _strndup_r = 0x400016c4 );
PROVIDE ( strnlen = 0x4000c628 );
PROVIDE ( strrchr = 0x40001708 );
PROVIDE ( strsep = 0x40001734 );
PROVIDE ( strspn = 0x4000c648 );
PROVIDE ( strstr = 0x4000c674 );
PROVIDE ( __strtok_r = 0x4000c6a8 );
PROVIDE ( strtok_r = 0x4000c70c );
PROVIDE ( strtol = 0x4005681c );
PROVIDE ( _strtol_r = 0x40056714 );
PROVIDE ( strtoul = 0x4005692c );
PROVIDE ( _strtoul_r = 0x40056834 );
PROVIDE ( strupr = 0x4000174c );
PROVIDE ( __subdf3 = 0x400026e4 );
PROVIDE ( __submore = 0x40058f3c );
PROVIDE ( __subsf3 = 0x400021d0 );
PROVIDE ( SubtractBigHex256 = 0x40015bcc );
PROVIDE ( SubtractBigHexMod256 = 0x40015e8c );
@ -1554,15 +1416,9 @@ PROVIDE ( SubtractFromSelfBigHex256 = 0x40015c20 );
PROVIDE ( SubtractFromSelfBigHexSign256 = 0x40015dc8 );
PROVIDE ( __subvdi3 = 0x40002d20 );
PROVIDE ( __subvsi3 = 0x40002cf8 );
PROVIDE ( _sungetc_r = 0x40057f6c );
PROVIDE ( __swbuf = 0x40058cb4 );
PROVIDE ( __swbuf_r = 0x40058bec );
PROVIDE ( __swrite = 0x40001150 );
PROVIDE ( __swsetup_r = 0x40058cc8 );
PROVIDE ( sw_to_hw = 0x3ffb8d40 );
PROVIDE ( syscall_table_ptr_app = 0x3ffae020 );
PROVIDE ( syscall_table_ptr_pro = 0x3ffae024 );
PROVIDE ( _system_r = 0x4000bc10 );
PROVIDE ( tdefl_compress = 0x400600bc );
PROVIDE ( tdefl_compress_buffer = 0x400607f4 );
PROVIDE ( tdefl_compress_mem_to_mem = 0x40060900 );
@ -1572,24 +1428,13 @@ PROVIDE ( tdefl_get_prev_return_status = 0x400608d0 );
PROVIDE ( tdefl_init = 0x40060810 );
PROVIDE ( tdefl_write_image_to_png_file_in_memory = 0x4006091c );
PROVIDE ( tdefl_write_image_to_png_file_in_memory_ex = 0x40060910 );
PROVIDE ( time = 0x40001844 );
PROVIDE ( __time_load_locale = 0x4000183c );
PROVIDE ( times = 0x40001808 );
PROVIDE ( _times_r = 0x4000bc40 );
PROVIDE ( _timezone = 0x3ffae0a0 );
PROVIDE ( tinfl_decompress = 0x4005ef30 );
PROVIDE ( tinfl_decompress_mem_to_callback = 0x40060090 );
PROVIDE ( tinfl_decompress_mem_to_mem = 0x40060050 );
PROVIDE ( toascii = 0x4000c720 );
PROVIDE ( tolower = 0x40001868 );
PROVIDE ( toupper = 0x40001884 );
PROVIDE ( __truncdfsf2 = 0x40002b90 );
PROVIDE ( __tzcalc_limits = 0x400018a0 );
PROVIDE ( __tz_lock = 0x40001a04 );
PROVIDE ( _tzname = 0x3ffae030 );
PROVIDE ( tzset = 0x40001a1c );
PROVIDE ( _tzset_r = 0x40001a28 );
PROVIDE ( __tz_unlock = 0x40001a10 );
PROVIDE ( UartDev = 0x3ffe019c );
PROVIDE ( __ucmpdi2 = 0x40063840 );
PROVIDE ( __udivdi3 = 0x4000cff8 );
@ -1599,20 +1444,12 @@ PROVIDE ( __udiv_w_sdiv = 0x40064aa8 );
PROVIDE ( __umoddi3 = 0x4000d280 );
PROVIDE ( __umodsi3 = 0x4000c7d0 );
PROVIDE ( __umulsidi3 = 0x4000c7d8 );
PROVIDE ( ungetc = 0x400590f4 );
PROVIDE ( _ungetc_r = 0x40058fa0 );
PROVIDE ( _unlink_r = 0x4000bc84 );
PROVIDE ( __unorddf2 = 0x400637f4 );
PROVIDE ( __unordsf2 = 0x40063478 );
PROVIDE ( user_code_start = 0x3ffe0400 );
PROVIDE ( utoa = 0x40056258 );
PROVIDE ( __utoa = 0x400561f0 );
PROVIDE ( veryBigHexP256 = 0x3ff9736c );
PROVIDE ( wcrtomb = 0x40058920 );
PROVIDE ( _wcrtomb_r = 0x400588d8 );
PROVIDE ( __wctomb = 0x3ff96540 );
PROVIDE ( _wctomb_r = 0x40058f14 );
PROVIDE ( write = 0x4000181c );
PROVIDE ( _write_r = 0x4000bd70 );
PROVIDE ( xthal_bcopy = 0x4000c098 );
PROVIDE ( xthal_copy123 = 0x4000c124 );

View File

@ -0,0 +1,167 @@
/*
If the spiram compiler workaround is active, these functions from ROM cannot be used. If the workaround is not
active (e.g. because the system does not use SPI RAM) then these functions are okay to use.
*/
PROVIDE ( abs = 0x40056340 );
PROVIDE ( __ascii_wctomb = 0x40058ef0 );
PROVIDE ( asctime = 0x40059588 );
PROVIDE ( asctime_r = 0x40000ec8 );
PROVIDE ( atoi = 0x400566c4 );
PROVIDE ( _atoi_r = 0x400566d4 );
PROVIDE ( atol = 0x400566ec );
PROVIDE ( _atol_r = 0x400566fc );
PROVIDE ( bzero = 0x4000c1f4 );
PROVIDE ( _cleanup = 0x40001df8 );
PROVIDE ( _cleanup_r = 0x40001d48 );
PROVIDE ( close = 0x40001778 );
PROVIDE ( creat = 0x40000e8c );
PROVIDE ( ctime = 0x400595b0 );
PROVIDE ( ctime_r = 0x400595c4 );
PROVIDE ( div = 0x40056348 );
PROVIDE ( __dummy_lock = 0x4000c728 );
PROVIDE ( __dummy_lock_try = 0x4000c730 );
PROVIDE ( __env_lock = 0x40001fd4 );
PROVIDE ( __env_unlock = 0x40001fe0 );
PROVIDE ( fclose = 0x400020ac );
PROVIDE ( _fclose_r = 0x40001fec );
PROVIDE ( fflush = 0x40059394 );
PROVIDE ( _fflush_r = 0x40059320 );
PROVIDE ( _findenv_r = 0x40001f44 );
PROVIDE ( __fp_lock_all = 0x40001f1c );
PROVIDE ( __fp_unlock_all = 0x40001f30 );
PROVIDE ( fputwc = 0x40058ea8 );
PROVIDE ( __fputwc = 0x40058da0 );
PROVIDE ( _fputwc_r = 0x40058e4c );
PROVIDE ( _fwalk = 0x4000c738 );
PROVIDE ( _fwalk_reent = 0x4000c770 );
PROVIDE ( __get_current_time_locale = 0x40001834 );
PROVIDE ( _getenv_r = 0x40001fbc );
PROVIDE ( __gettzinfo = 0x40001fcc );
PROVIDE ( gmtime = 0x40059848 );
PROVIDE ( gmtime_r = 0x40059868 );
PROVIDE ( isalnum = 0x40000f04 );
PROVIDE ( isalpha = 0x40000f18 );
PROVIDE ( isascii = 0x4000c20c );
PROVIDE ( _isatty_r = 0x40000ea0 );
PROVIDE ( isblank = 0x40000f2c );
PROVIDE ( iscntrl = 0x40000f50 );
PROVIDE ( isdigit = 0x40000f64 );
PROVIDE ( isgraph = 0x40000f94 );
PROVIDE ( islower = 0x40000f78 );
PROVIDE ( isprint = 0x40000fa8 );
PROVIDE ( ispunct = 0x40000fc0 );
PROVIDE ( isspace = 0x40000fd4 );
PROVIDE ( isupper = 0x40000fe8 );
PROVIDE ( itoa = 0x400566b4 );
PROVIDE ( __itoa = 0x40056678 );
PROVIDE ( labs = 0x40056370 );
PROVIDE ( ldiv = 0x40056378 );
PROVIDE ( __locale_charset = 0x40059540 );
PROVIDE ( __locale_cjk_lang = 0x40059558 );
PROVIDE ( localeconv = 0x4005957c );
PROVIDE ( _localeconv_r = 0x40059560 );
PROVIDE ( __locale_mb_cur_max = 0x40059548 );
PROVIDE ( __locale_msgcharset = 0x40059550 );
PROVIDE ( localtime = 0x400595dc );
PROVIDE ( localtime_r = 0x400595fc );
PROVIDE ( _lock_acquire = 0x4000be14 );
PROVIDE ( _lock_release = 0x4000be64 );
PROVIDE ( longjmp = 0x400562cc );
PROVIDE ( memccpy = 0x4000c220 );
PROVIDE ( memchr = 0x4000c244 );
PROVIDE ( memcmp = 0x4000c260 );
PROVIDE ( memcpy = 0x4000c2c8 );
PROVIDE ( memmove = 0x4000c3c0 );
PROVIDE ( memrchr = 0x4000c400 );
PROVIDE ( memset = 0x4000c44c );
PROVIDE ( mktime = 0x4005a5e8 );
PROVIDE ( open = 0x4000178c );
PROVIDE ( qsort = 0x40056424 );
PROVIDE ( _raise_r = 0x4000bc70 );
PROVIDE ( rand = 0x40001058 );
PROVIDE ( rand_r = 0x400010d4 );
PROVIDE ( read = 0x400017dc );
PROVIDE ( sbrk = 0x400017f4 );
PROVIDE ( __sccl = 0x4000c498 );
PROVIDE ( __sclose = 0x400011b8 );
PROVIDE ( __seofread = 0x40001148 );
PROVIDE ( setjmp = 0x40056268 );
PROVIDE ( setlocale = 0x40059568 );
PROVIDE ( _setlocale_r = 0x4005950c );
PROVIDE ( __sflush_r = 0x400591e0 );
PROVIDE ( __sfmoreglue = 0x40001dc8 );
PROVIDE ( __sfp = 0x40001e90 );
PROVIDE ( __sfp_lock_acquire = 0x40001e08 );
PROVIDE ( __sfp_lock_release = 0x40001e14 );
PROVIDE ( __sfputs_r = 0x40057790 );
PROVIDE ( __sfvwrite_r = 0x4005893c );
PROVIDE ( __sinit = 0x40001e38 );
PROVIDE ( __sinit_lock_acquire = 0x40001e20 );
PROVIDE ( __sinit_lock_release = 0x40001e2c );
PROVIDE ( __smakebuf_r = 0x40059108 );
PROVIDE ( srand = 0x40001004 );
PROVIDE ( __sread = 0x40001118 );
PROVIDE ( __srefill_r = 0x400593d4 );
PROVIDE ( __sseek = 0x40001184 );
PROVIDE ( __ssprint_r = 0x40056ff8 );
PROVIDE ( __ssputs_r = 0x40056f2c );
PROVIDE ( __ssrefill_r = 0x40057fec );
PROVIDE ( strcasecmp = 0x400011cc );
PROVIDE ( strcasestr = 0x40001210 );
PROVIDE ( strcat = 0x4000c518 );
PROVIDE ( strchr = 0x4000c53c );
PROVIDE ( strcmp = 0x40001274 );
PROVIDE ( strcoll = 0x40001398 );
PROVIDE ( strcpy = 0x400013ac );
PROVIDE ( strcspn = 0x4000c558 );
PROVIDE ( strdup = 0x4000143c );
PROVIDE ( _strdup_r = 0x40001450 );
PROVIDE ( strftime = 0x40059ab4 );
PROVIDE ( strlcat = 0x40001470 );
PROVIDE ( strlcpy = 0x4000c584 );
PROVIDE ( strlen = 0x400014c0 );
PROVIDE ( strlwr = 0x40001524 );
PROVIDE ( strncasecmp = 0x40001550 );
PROVIDE ( strncat = 0x4000c5c4 );
PROVIDE ( strncmp = 0x4000c5f4 );
PROVIDE ( strncpy = 0x400015d4 );
PROVIDE ( strndup = 0x400016b0 );
PROVIDE ( _strndup_r = 0x400016c4 );
PROVIDE ( strnlen = 0x4000c628 );
PROVIDE ( strrchr = 0x40001708 );
PROVIDE ( strsep = 0x40001734 );
PROVIDE ( strspn = 0x4000c648 );
PROVIDE ( strstr = 0x4000c674 );
PROVIDE ( __strtok_r = 0x4000c6a8 );
PROVIDE ( strtok_r = 0x4000c70c );
PROVIDE ( strtol = 0x4005681c );
PROVIDE ( _strtol_r = 0x40056714 );
PROVIDE ( strtoul = 0x4005692c );
PROVIDE ( _strtoul_r = 0x40056834 );
PROVIDE ( strupr = 0x4000174c );
PROVIDE ( __submore = 0x40058f3c );
PROVIDE ( _sungetc_r = 0x40057f6c );
PROVIDE ( __swbuf = 0x40058cb4 );
PROVIDE ( __swbuf_r = 0x40058bec );
PROVIDE ( __swrite = 0x40001150 );
PROVIDE ( __swsetup_r = 0x40058cc8 );
PROVIDE ( _system_r = 0x4000bc10 );
PROVIDE ( time = 0x40001844 );
PROVIDE ( __time_load_locale = 0x4000183c );
PROVIDE ( times = 0x40001808 );
PROVIDE ( toascii = 0x4000c720 );
PROVIDE ( tolower = 0x40001868 );
PROVIDE ( toupper = 0x40001884 );
PROVIDE ( __tzcalc_limits = 0x400018a0 );
PROVIDE ( __tz_lock = 0x40001a04 );
PROVIDE ( tzset = 0x40001a1c );
PROVIDE ( _tzset_r = 0x40001a28 );
PROVIDE ( __tz_unlock = 0x40001a10 );
PROVIDE ( ungetc = 0x400590f4 );
PROVIDE ( _ungetc_r = 0x40058fa0 );
PROVIDE ( utoa = 0x40056258 );
PROVIDE ( __utoa = 0x400561f0 );
PROVIDE ( wcrtomb = 0x40058920 );
PROVIDE ( _wcrtomb_r = 0x400588d8 );
PROVIDE ( _wctomb_r = 0x40058f14 );
PROVIDE ( write = 0x4000181c );

Binary file not shown.

184
components/esp32/spiram.c Normal file
View File

@ -0,0 +1,184 @@
/*
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*/
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "spiram_psram.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "soc/soc.h"
#include "soc/dport_reg.h"
#include "rom/cache.h"
#if CONFIG_FREERTOS_UNICORE
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#else
#if CONFIG_MEMMAP_SPIRAM_CACHE_EVENODD
#define PSRAM_MODE PSRAM_VADDR_MODE_EVENODD
#else
#define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH
#endif
#endif
#if CONFIG_SPIRAM_SUPPORT
static const char* TAG = "spiram";
#if CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define PSRAM_SPEED PSRAM_CACHE_F40M_S40M
#elif CONFIG_SPIRAM_SPEED_40M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S40M
#elif CONFIG_SPIRAM_SPEED_80M && CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define PSRAM_SPEED PSRAM_CACHE_F80M_S80M
#else
#error "FLASH speed can only be equal to or higher than SRAM speed while SRAM is enabled!"
#endif
static bool spiram_inited=false;
/*
Simple RAM test. Writes a word every 32 bytes. Takes about a second to complete for 4MiB. Returns
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
*/
bool esp_spiram_test()
{
volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
size_t p;
size_t s=CONFIG_SPIRAM_SIZE;
int errct=0;
int initial_err=-1;
for (p=0; p<(s/sizeof(int)); p+=8) {
spiram[p]=p^0xAAAAAAAA;
}
for (p=0; p<(s/sizeof(int)); p+=8) {
if (spiram[p]!=(p^0xAAAAAAAA)) {
errct++;
if (errct==1) initial_err=p*4;
}
}
if (errct) {
ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s/32, initial_err+SOC_EXTRAM_DATA_LOW);
return false;
} else {
ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
return true;
}
}
esp_err_t esp_spiram_init()
{
//Enable external RAM in MMU
cache_sram_mmu_set( 0, 0, SOC_EXTRAM_DATA_LOW, 0, 32, 128 );
//Flush and enable icache for APP CPU
#if !CONFIG_FREERTOS_UNICORE
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1);
cache_sram_mmu_set( 1, 0, SOC_EXTRAM_DATA_LOW, 0, 32, 128 );
#endif
esp_err_t r;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != ESP_OK) {
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
return r;
}
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_F40M_S40M ? "flash 40m sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_F80M_S40M ? "flash 80m sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_F80M_S80M ? "flash 80m sram 80m" : "ERROR");
ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", \
(PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)": \
(PSRAM_MODE==PSRAM_VADDR_MODE_LOWHIGH)?"low/high (2-core)": \
(PSRAM_MODE==PSRAM_VADDR_MODE_NORMAL)?"normal (1-core)":"ERROR");
spiram_inited=true;
return ESP_OK;
}
size_t esp_spiram_get_size()
{
return CONFIG_SPIRAM_SIZE;
}
/*
Before flushing the cache, if psram is enabled as a memory-mapped thing, we need to write back the data in the cache to the psram first,
otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this.
*/
void IRAM_ATTR esp_spiram_writeback_cache()
{
int x;
volatile int i=0;
volatile uint8_t *psram=(volatile uint8_t*)SOC_EXTRAM_DATA_LOW;
int cache_was_disabled=0;
if (!spiram_inited) return;
//We need cache enabled for this to work. Re-enable it if needed; make sure we
//disable it again on exit as well.
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<0);
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
}
#endif
#if CONFIG_FREERTOS_UNICORE
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
}
#else
/*
Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
we ever support external RAM chips of 2M or smaller, this may need adjusting.
*/
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
i+=psram[x+(1024*1024*2)+(1024*64)]; //address picked to also clear cache of app cpu in low/high mode
}
#endif
if (cache_was_disabled&(1<<0)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) ;
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
}
#ifndef CONFIG_FREERTOS_UNICORE
if (cache_was_disabled&(1<<1)) {
while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1);
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
}
#endif
}
#endif

View File

@ -1,19 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SPI_RAM_H
#define SPI_RAM_H
void enable_spi_sram();
#endif

View File

@ -0,0 +1,638 @@
/*
Driver bits for PSRAM chips (at the moment only the ESP-PSRAM32 chip).
*/
// Copyright 2013-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "string.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "spiram_psram.h"
#include "rom/ets_sys.h"
#include "rom/spi_flash.h"
#include "rom/gpio.h"
#include "rom/cache.h"
#include "soc/io_mux_reg.h"
#include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#if CONFIG_SPIRAM_SUPPORT
//Commands for PSRAM chip
#define PSRAM_READ 0x03
#define PSRAM_FAST_READ 0x0B
#define PSRAM_FAST_READ_DUMMY 0x3
#define PSRAM_FAST_READ_QUAD 0xEB
#define PSRAM_WRITE 0x02
#define PSRAM_QUAD_WRITE 0x38
#define PSRAM_ENTER_QMODE 0x35
#define PSRAM_EXIT_QMODE 0xF5
#define PSRAM_RESET_EN 0x66
#define PSRAM_RESET 0x99
#define PSRAM_SET_BURST_LEN 0xC0
#define PSRAM_DEVICE_ID 0x9F
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
#define PSRAM_MFG_ID_M 0xff
#define PSRAM_MFG_ID_S 8
#define PSRAM_MFG_ID_V 0x5d
#endif
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
// currently support are 1.8V parts.
// WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines
// hardcode the flash pins as well, making this code incompatible with either a setup
// that has the flash on non-standard pins or ESP32s with built-in flash.
#define FLASH_CLK_IO 6 //Psram clock is a delayed version of this in 40MHz mode
#define FLASH_CS_IO 11
#define PSRAM_CLK_IO 17
#define PSRAM_CS_IO 16
#define PSRAM_SPIQ_IO 7
#define PSRAM_SPID_IO 8
#define PSRAM_SPIWP_IO 10
#define PSRAM_SPIHD_IO 9
#define PSRAM_IO_MATRIX_DUMMY_40M 1
#define PSRAM_IO_MATRIX_DUMMY_80M 2
#if CONFIG_FLASHMODE_QIO
#define SPI_CACHE_DUMMY SPI0_R_QIO_DUMMY_CYCLELEN //qio 3
#elif CONFIG_FLASHMODE_QOUT
#define SPI_CACHE_DUMMY SPI0_R_FAST_DUMMY_CYCLELEN //qout 7
#elif CONFIG_FLASHMODE_DIO
#define SPI_CACHE_DUMMY SPI0_R_DIO_DUMMY_CYCLELEN //dio 3
#elif CONFIG_FLASHMODE_DOUT
#define SPI_CACHE_DUMMY SPI0_R_FAST_DUMMY_CYCLELEN //dout 7
#endif
typedef enum {
PSRAM_SPI_1 = 0x1,
PSRAM_SPI_2,
PSRAM_SPI_3,
PSRAM_SPI_MAX ,
} psram_spi_num_t;
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
//For now, we only use F40M + S40M, and we don't have to go through gpio matrix
#define ENABLE_GPIO_MATRIX_SPI 1
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
static int extra_dummy = 0;
typedef enum {
PSRAM_CMD_QPI,
PSRAM_CMD_SPI,
} psram_cmd_mode_t;
typedef struct {
uint16_t cmd; /*!< Command value */
uint16_t cmdBitLen; /*!< Command byte length*/
uint32_t *addr; /*!< Point to address value*/
uint16_t addrBitLen; /*!< Address byte length*/
uint32_t *txData; /*!< Point to send data buffer*/
uint16_t txDataBitLen; /*!< Send data byte length.*/
uint32_t *rxData; /*!< Point to recevie data buffer*/
uint16_t rxDataBitLen; /*!< Recevie Data byte length.*/
uint32_t dummyBitLen;
} psram_cmd_t;
static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode);
static void psram_clear_spi_fifo(psram_spi_num_t spi_num)
{
int i;
for (i = 0; i < 16; i++) {
WRITE_PERI_REG(SPI_W0_REG(spi_num)+i*4, 0);
}
}
//set basic SPI write mode
static void psram_set_basic_write_mode(psram_spi_num_t spi_num)
{
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_QIO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_DIO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_QUAD);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_DUAL);
}
//set QPI write mode
static void psram_set_qio_write_mode(psram_spi_num_t spi_num)
{
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_QIO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_DIO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_QUAD);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_FWRITE_DUAL);
}
//set QPI read mode
static void psram_set_qio_read_mode(psram_spi_num_t spi_num)
{
SET_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_QIO);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_QUAD);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_DUAL);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_DIO);
}
//set SPI read mode
static void psram_set_basic_read_mode(psram_spi_num_t spi_num)
{
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_QIO);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_QUAD);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_DUAL);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_FREAD_DIO);
}
//start sending cmd/addr and optionally, receiving data
static void IRAM_ATTR psram_cmd_recv_start(psram_spi_num_t spi_num, uint32_t* pRxData, uint16_t rxByteLen,
psram_cmd_mode_t cmd_mode)
{
//get cs1
CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS1_DIS_M);
SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS0_DIS_M);
uint32_t mode_backup = (READ_PERI_REG(SPI_USER_REG(spi_num)) >> SPI_FWRITE_DUAL_S) & 0xf;
uint32_t rd_mode_backup = READ_PERI_REG(SPI_CTRL_REG(spi_num)) & (SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M | SPI_FREAD_QUAD_M | SPI_FREAD_QIO_M);
if (cmd_mode == PSRAM_CMD_SPI) {
psram_set_basic_write_mode(spi_num);
psram_set_basic_read_mode(spi_num);
} else if (cmd_mode == PSRAM_CMD_QPI) {
psram_set_qio_write_mode(spi_num);
psram_set_qio_read_mode(spi_num);
}
//Wait for SPI0 to idle
while ( READ_PERI_REG(SPI_EXT2_REG(0)) != 0);
DPORT_SET_PERI_REG_MASK(DPORT_HOST_INF_SEL_REG, 1 << 14);
// Start send data
SET_PERI_REG_MASK(SPI_CMD_REG(spi_num), SPI_USR);
while ((READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR));
DPORT_CLEAR_PERI_REG_MASK(DPORT_HOST_INF_SEL_REG, 1 << 14);
//recover spi mode
SET_PERI_REG_BITS(SPI_USER_REG(spi_num), (pRxData?SPI_FWRITE_DUAL_M:0xf), mode_backup, SPI_FWRITE_DUAL_S);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), (SPI_FREAD_DIO_M|SPI_FREAD_DUAL_M|SPI_FREAD_QUAD_M|SPI_FREAD_QIO_M));
SET_PERI_REG_MASK(SPI_CTRL_REG(spi_num), rd_mode_backup);
//return cs to cs0
SET_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS1_DIS_M);
CLEAR_PERI_REG_MASK(SPI_PIN_REG(PSRAM_SPI_1), SPI_CS0_DIS_M);
if (pRxData) {
int idx = 0;
// Read data out
do {
*pRxData++ = READ_PERI_REG(SPI_W0_REG(spi_num) + (idx << 2));
} while (++idx < ((rxByteLen / 4) + ((rxByteLen % 4) ? 1 : 0)));
}
}
static uint32_t backup_usr[3];
static uint32_t backup_usr1[3];
static uint32_t backup_usr2[3];
//setup spi command/addr/data/dummy in user mode
static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
{
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
backup_usr[spi_num]=READ_PERI_REG(SPI_USER_REG(spi_num));
backup_usr1[spi_num]=READ_PERI_REG(SPI_USER1_REG(spi_num));
backup_usr2[spi_num]=READ_PERI_REG(SPI_USER2_REG(spi_num));
// Set command by user.
if (pInData->cmdBitLen != 0) {
// Max command length 16 bits.
SET_PERI_REG_BITS(SPI_USER2_REG(spi_num), SPI_USR_COMMAND_BITLEN, pInData->cmdBitLen - 1,
SPI_USR_COMMAND_BITLEN_S);
// Enable command
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_COMMAND);
// Load command,bit15-0 is cmd value.
SET_PERI_REG_BITS(SPI_USER2_REG(spi_num), SPI_USR_COMMAND_VALUE, pInData->cmd, SPI_USR_COMMAND_VALUE_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2_REG(spi_num), SPI_USR_COMMAND_BITLEN, 0, SPI_USR_COMMAND_BITLEN_S);
}
// Set Address by user.
if (pInData->addrBitLen != 0) {
SET_PERI_REG_BITS(SPI_USER1_REG(spi_num), SPI_USR_ADDR_BITLEN, (pInData->addrBitLen - 1), SPI_USR_ADDR_BITLEN_S);
// Enable address
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_ADDR);
// Set address
WRITE_PERI_REG(SPI_ADDR_REG(spi_num), *pInData->addr);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1_REG(spi_num), SPI_USR_ADDR_BITLEN, 0, SPI_USR_ADDR_BITLEN_S);
}
// Set data by user.
uint32_t* p_tx_val = pInData->txData;
if (pInData->txDataBitLen != 0) {
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MOSI);
// Load send buffer
int len = (pInData->txDataBitLen + 31) / 32;
if (p_tx_val != NULL) {
memcpy((void*)SPI_W0_REG(spi_num), p_tx_val, len * 4);
}
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spi_num), SPI_USR_MOSI_DBITLEN, (pInData->txDataBitLen - 1),
SPI_USR_MOSI_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MOSI);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spi_num), SPI_USR_MOSI_DBITLEN, 0, SPI_USR_MOSI_DBITLEN_S);
}
// Set rx data by user.
if (pInData->rxDataBitLen != 0) {
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MISO);
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spi_num), SPI_USR_MISO_DBITLEN, (pInData->rxDataBitLen - 1),
SPI_USR_MISO_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spi_num), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
}
if (pInData->dummyBitLen != 0) {
SET_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_DUMMY); // dummy en
SET_PERI_REG_BITS(SPI_USER1_REG(PSRAM_SPI_1), SPI_USR_DUMMY_CYCLELEN_V, pInData->dummyBitLen - 1,
SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_DUMMY); // dummy en
SET_PERI_REG_BITS(SPI_USER1_REG(PSRAM_SPI_1), SPI_USR_DUMMY_CYCLELEN_V, 0, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
}
return 0;
}
void psram_cmd_end(int spi_num) {
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
WRITE_PERI_REG(SPI_USER2_REG(spi_num), backup_usr2[spi_num]);
}
//exit QPI mode(set back to SPI mode)
static void psram_disable_qio_mode(psram_spi_num_t spi_num)
{
psram_cmd_t ps_cmd;
uint32_t cmd_exit_qpi;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
cmd_exit_qpi = PSRAM_EXIT_QMODE;
ps_cmd.txDataBitLen = 8;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
ps_cmd.txDataBitLen = 16;
break;
}
ps_cmd.txData = &cmd_exit_qpi;
ps_cmd.cmd = 0;
ps_cmd.cmdBitLen = 0;
ps_cmd.addr = 0;
ps_cmd.addrBitLen = 0;
ps_cmd.rxData = NULL;
ps_cmd.rxDataBitLen = 0;
ps_cmd.dummyBitLen = 0;
psram_cmd_config(spi_num, &ps_cmd);
psram_cmd_recv_start(spi_num, NULL, 0, PSRAM_CMD_QPI);
psram_cmd_end(spi_num);
}
//read psram id
static void psram_read_id(uint32_t* dev_id)
{
psram_spi_num_t spi_num = PSRAM_SPI_1;
psram_disable_qio_mode(spi_num);
uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0;
uint32_t dummy_bits = 0;
psram_cmd_t ps_cmd;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
dummy_bits = 0 + extra_dummy;
ps_cmd.cmdBitLen = 0;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
dummy_bits = 0 + extra_dummy;
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
break;
}
ps_cmd.cmd = 0;
ps_cmd.addr = &addr;
ps_cmd.addrBitLen = 4 * 8;
ps_cmd.txDataBitLen = 0;
ps_cmd.txData = NULL;
ps_cmd.rxDataBitLen = 4 * 8;
ps_cmd.rxData = dev_id;
ps_cmd.dummyBitLen = dummy_bits;
psram_cmd_config(spi_num, &ps_cmd);
psram_clear_spi_fifo(spi_num);
psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
psram_cmd_end(spi_num);
}
//enter QPI mode
static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
{
psram_cmd_t ps_cmd;
uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
ps_cmd.cmdBitLen = 0;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
ps_cmd.cmdBitLen = 2;
break;
}
ps_cmd.cmd = 0;
ps_cmd.addr = &addr;
ps_cmd.addrBitLen = 8;
ps_cmd.txData = NULL;
ps_cmd.txDataBitLen = 0;
ps_cmd.rxData = NULL;
ps_cmd.rxDataBitLen = 0;
ps_cmd.dummyBitLen = 0;
psram_cmd_config(spi_num, &ps_cmd);
psram_cmd_recv_start(spi_num, NULL, 0, PSRAM_CMD_SPI);
psram_cmd_end(spi_num);
return ESP_OK;
}
//spi param init for psram
void IRAM_ATTR psram_spi_init(psram_spi_num_t spi_num, psram_cache_mode_t mode)
{
uint8_t i, k;
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spi_num), SPI_TRANS_DONE << 5);
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_CS_SETUP);
// SPI_CPOL & SPI_CPHA
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spi_num), SPI_CK_IDLE_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_CK_OUT_EDGE);
// SPI bit order
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_WR_BIT_ORDER);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spi_num), SPI_RD_BIT_ORDER);
// SPI bit order
CLEAR_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_DOUTDIN);
// May be not must to do.
WRITE_PERI_REG(SPI_USER1_REG(spi_num), 0);
// SPI mode type
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spi_num), SPI_SLAVE_MODE);
// Set SPI speed for non-80M mode. (80M mode uses APB clock directly.)
if (mode!=PSRAM_CACHE_F80M_S80M) {
i = 1; //Pre-divider
k = 2; //Main divider. Divide by 2 so we get 40MHz
//clear bit 31, set SPI clock div
CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spi_num), SPI_CLK_EQU_SYSCLK);
WRITE_PERI_REG(SPI_CLOCK_REG(spi_num),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | //50% duty cycle
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S));
}
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
memset((void*)SPI_W0_REG(spi_num), 0, 16 * 4);
}
static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
{
gpio_matrix_out(FLASH_CLK_IO, SPICLK_OUT_IDX, 0, 0);
gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
gpio_matrix_in(PSRAM_SPIQ_IO, SPIQ_IN_IDX, 0);
gpio_matrix_out(PSRAM_SPID_IO, SPID_OUT_IDX, 0, 0);
gpio_matrix_in(PSRAM_SPID_IO, SPID_IN_IDX, 0);
gpio_matrix_out(PSRAM_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
gpio_matrix_in(PSRAM_SPIWP_IO, SPIWP_IN_IDX, 0);
gpio_matrix_out(PSRAM_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
gpio_matrix_in(PSRAM_SPIHD_IO, SPIHD_IN_IDX, 0);
switch (mode) {
case PSRAM_CACHE_F80M_S40M:
extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
g_rom_spiflash_dummy_len_plus[1] = PSRAM_IO_MATRIX_DUMMY_40M;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, SPI_CACHE_DUMMY + PSRAM_IO_MATRIX_DUMMY_80M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
break;
case PSRAM_CACHE_F80M_S80M:
extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
g_rom_spiflash_dummy_len_plus[1] = PSRAM_IO_MATRIX_DUMMY_80M;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, SPI_CACHE_DUMMY + PSRAM_IO_MATRIX_DUMMY_80M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
break;
case PSRAM_CACHE_F40M_S40M:
extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
g_rom_spiflash_dummy_len_plus[1] = PSRAM_IO_MATRIX_DUMMY_40M;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, SPI_CACHE_DUMMY + PSRAM_IO_MATRIX_DUMMY_40M, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
break;
default:
break;
}
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_USR_DUMMY); // dummy en
//select pin function gpio
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 2);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2);
}
//psram gpio init , different working frequency we have different solutions
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
{
/* note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
Application code should never touch VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves*/
if (mode == PSRAM_CACHE_F80M_S80M) {
bool r=spicommon_periph_claim(VSPI_HOST);
if (!r) {
return ESP_ERR_INVALID_STATE;
}
}
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
s_psram_mode = mode;
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
WRITE_PERI_REG(SPI_EXT3_REG(0), 0x1);
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_PREP_HOLD_M);
switch (mode) {
case PSRAM_CACHE_F80M_S80M:
psram_spi_init(PSRAM_SPI_1, mode);
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, BIT(PSRAM_CS_IO)); //DPORT_SPI_CLK_EN
break;
}
}
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
psram_spi_init(PSRAM_SPI_1, mode);
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
/* We need to delay CLK to the PSRAM with respect to the clock signal as output by the SPI peripheral.
We do this by routing it signal to signal 224/225, which are used as a loopback; the extra run through
the GPIO matrix causes the delay. We use GPIO20 (which is not in any package but has pad logic in
silicon) as a temporary pad for this. So the signal path is:
GPIO6(SPI CLK) --> signal224(in then out) --> internal GPIO20 --> signal225(in then out) --> GPIO17(PSRAM CLK)
*/
gpio_matrix_in(FLASH_CLK_IO, SIG_IN_FUNC224_IDX, 0);
gpio_matrix_out(20, SIG_IN_FUNC224_IDX, 0, 0);
gpio_matrix_in(20, SIG_IN_FUNC225_IDX, 0);
gpio_matrix_out(PSRAM_CLK_IO, SIG_IN_FUNC225_IDX, 0, 0);
break;
}
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_SETUP_M);
#if ENABLE_GPIO_MATRIX_SPI
psram_gpio_config(mode);
#endif
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], 2);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], 2);
uint32_t id;
psram_read_id(&id);
if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
return ESP_FAIL;
}
psram_enable_qio_mode(PSRAM_SPI_1);
psram_cache_init(mode, vaddrmode);
return ESP_OK;
}
//register initialization for sram cache params and r/w commands
static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psram_vaddr_mode_t vaddrmode)
{
CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M);
SET_PERI_REG_BITS(SPI_CLOCK_REG(0), SPI_CLKDIV_PRE_V, 0, SPI_CLKDIV_PRE_S);
SET_PERI_REG_BITS(SPI_CLOCK_REG(0), SPI_CLKCNT_N, 1, SPI_CLKCNT_N_S);
SET_PERI_REG_BITS(SPI_CLOCK_REG(0), SPI_CLKCNT_H, 0, SPI_CLKCNT_H_S);
SET_PERI_REG_BITS(SPI_CLOCK_REG(0), SPI_CLKCNT_L, 1, SPI_CLKCNT_L_S);
switch (psram_cache_mode) {
case PSRAM_CACHE_F80M_S80M:
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40;
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
case PSRAM_CACHE_F80M_S40M:
SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
case PSRAM_CACHE_F40M_S40M:
default:
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
}
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_ADDR_BITLEN_V, 23, SPI_SRAM_ADDR_BITLEN_S); //write address for cache command.
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command
CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command
//config sram cache r/w command
switch (psram_cache_mode) {
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
break;
case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
case PSRAM_CACHE_F40M_S40M:
default:
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8),
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
break;
}
DPORT_CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_HL|DPORT_PRO_DRAM_SPLIT);
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_HL|DPORT_APP_DRAM_SPLIT);
if (vaddrmode == PSRAM_VADDR_MODE_LOWHIGH) {
DPORT_SET_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_HL);
DPORT_SET_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_HL);
} else if (vaddrmode == PSRAM_VADDR_MODE_EVENODD) {
DPORT_SET_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_DRAM_SPLIT);
DPORT_SET_PERI_REG_MASK(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_DRAM_SPLIT);
}
DPORT_CLEAR_PERI_REG_MASK(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DRAM1|DPORT_PRO_CACHE_MASK_OPSDRAM); //use Dram1 to visit ext sram.
//cache page mode : 1 -->16k 4 -->2k 0-->32k,(accord with the settings in cache_sram_mmu_set)
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CMMU_SRAM_PAGE_MODE, 0, DPORT_PRO_CMMU_SRAM_PAGE_MODE_S);
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1|DPORT_APP_CACHE_MASK_OPSDRAM); //use Dram1 to visit ext sram.
//cache page mode : 1 -->16k 4 -->2k 0-->32k,(accord with the settings in cache_sram_mmu_set)
DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CMMU_SRAM_PAGE_MODE, 0, DPORT_APP_CMMU_SRAM_PAGE_MODE_S);
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
}
#endif // CONFIG_SPIRAM_SUPPORT

View File

@ -0,0 +1,55 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _PSRAM_H
#define _PSRAM_H
#include "soc/spi_reg.h"
#include "esp_err.h"
#include "sdkconfig.h"
typedef enum {
PSRAM_CACHE_F80M_S40M = 0,
PSRAM_CACHE_F40M_S40M,
PSRAM_CACHE_F80M_S80M,
PSRAM_CACHE_MAX,
} psram_cache_mode_t;
/*
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
Important is that NORMAL works with the app CPU cache disabled, but gives huge cache coherency
issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
issues but cannot be used when the app CPU cache is disabled.
*/
typedef enum {
PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
} psram_vaddr_mode_t;
/**
* @brief psram cache enable function
*
* Esp-idf uses this to initialize cache for psram, mapping it into the main memory
* address space.
*
* @param mode SPI mode to access psram in
* @param vaddrmode Mode the psram cache works in.
* @return ESP_OK on success, ESP_ERR_INVALID_STATE when VSPI peripheral is needed but cannot be claimed.
*/
esp_err_t psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode);
#endif

View File

@ -0,0 +1,141 @@
/*
This code tests the interaction between PSRAM and SPI flash routines.
*/
#include <esp_types.h>
#include <stdio.h>
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "unity.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rom/ets_sys.h"
#include "esp_heap_caps.h"
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "test_utils.h"
#if CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MEMMAP
#define TSTSZ (16*1024)
volatile static int res[2], err[2];
void tstMem(void *arg) {
volatile unsigned char *mem=(volatile unsigned char*)arg;
int p=0;
while(1) {
for (int i=0; i<TSTSZ; i++) {
mem[i]=(i^p);
}
for (int i=0; i<TSTSZ; i++) {
if (mem[i]!=((i^p)&0xff)) {
printf("Core %d mem err! Got %x espected %x at addr %p\n", xPortGetCoreID(), mem[i], (i^p)&0xff, &mem[i]);
err[xPortGetCoreID()]++;
}
}
p++;
res[xPortGetCoreID()]++;
}
}
TEST_CASE("Spiram cache flush on mmap", "[spiram][ignore]")
{
void *mem[2];
res[0]=0; res[1]=0;
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
#else
mem[0]=(void*)0x3f800000;
mem[1]=(void*)0x3f800000+TSTSZ;
#endif
TaskHandle_t th[2];
err[0]=0; err[1]=0;
printf("Creating tasks\n");
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
const esp_partition_t* part = get_test_data_partition();
for (int l=0; l<10; l++) {
for (int p=0; p<4096*1024; p+=65536) {
const void *out;
spi_flash_mmap_handle_t h;
spi_flash_mmap(p, 65536, SPI_FLASH_MMAP_DATA, &out, &h);
spi_flash_munmap(h);
}
printf("%d/10\n", l);
}
printf("Checked memory %d and %d times. Errors: %d and %d\n", res[0], res[1], err[0], err[1]);
vTaskDelete(th[0]);
vTaskDelete(th[1]);
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
free(mem[0]);
free(mem[1]);
#endif
TEST_ASSERT(err[0]==0);
TEST_ASSERT(err[1]==0);
}
#define CYCLES 1024
TEST_CASE("Spiram cache flush on write/read", "[spiram][ignore]")
{
void *mem[2];
res[0]=0; res[1]=0;
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
mem[0]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
mem[1]=pvPortMallocCaps(TSTSZ, MALLOC_CAP_SPIRAM);
#else
mem[0]=(void*)0x3f800000;
mem[1]=(void*)0x3f800000+TSTSZ;
#endif
TaskHandle_t th[2];
const esp_partition_t* part = get_test_data_partition();
assert(part!=NULL);
printf("Erasing sector...\n");
esp_partition_erase_range(part, 0, 64*1024);
printf("Erased.\n");
printf("Creating tasks\n");
xTaskCreatePinnedToCore(tstMem , "tskone" , 2048, mem[0], 3, &th[0], 0);
xTaskCreatePinnedToCore(tstMem , "tsktwo" , 2048, mem[1], 3, &th[1], 1);
char buf[512];
const void *out;
spi_flash_mmap_handle_t handle;
esp_partition_mmap(part, 0, 512, SPI_FLASH_MMAP_DATA, &out, &handle);
for (int i=0; i<CYCLES; i++) {
printf("%d/%d\n", i, CYCLES);
esp_partition_write(part, 0, buf, 512);
esp_partition_read(part, 0, buf, 512);
vTaskDelay(1);
}
spi_flash_munmap(handle);
printf("Checked memory %d and %d times.\n", res[0], res[1]);
vTaskDelete(th[0]);
vTaskDelete(th[1]);
#if CONFIG_SPIRAM_USE_CAPS_ALLOC
free(mem[0]);
free(mem[1]);
#endif
}
#endif //CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MEMMAP

View File

@ -1,5 +1,12 @@
ifdef CONFIG_NEWLIB_NANO_FORMAT
ifeq ("$(CONFIG_SPIRAM_CACHE_WORKAROUND)","y")
LIBC_PATH := $(COMPONENT_PATH)/lib/libc-psram-workaround.a
LIBM_PATH := $(COMPONENT_PATH)/lib/libm-psram-workaround.a
else
ifeq ("$(CONFIG_NEWLIB_NANO_FORMAT)","y")
LIBC_PATH := $(COMPONENT_PATH)/lib/libc_nano.a
else
LIBC_PATH := $(COMPONENT_PATH)/lib/libc.a
@ -7,7 +14,9 @@ endif
LIBM_PATH := $(COMPONENT_PATH)/lib/libm.a
COMPONENT_ADD_LDFLAGS += $(LIBC_PATH) $(LIBM_PATH)
endif
COMPONENT_ADD_LDFLAGS := $(LIBC_PATH) $(LIBM_PATH) -lnewlib
COMPONENT_ADD_LINKER_DEPS := $(LIBC_PATH) $(LIBM_PATH)

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
components/soc/component.mk Executable file → Normal file
View File

View File

@ -67,6 +67,9 @@
#define SOC_RTC_IRAM_HIGH 0x400C2000
#define SOC_RTC_DATA_LOW 0x50000000
#define SOC_RTC_DATA_HIGH 0x50002000
#define SOC_EXTRAM_DATA_LOW 0x3F800000
#define SOC_EXTRAM_DATA_HIGH 0x3FC00000
#define DR_REG_DPORT_BASE 0x3ff00000
#define DR_REG_AES_BASE 0x3ff01000
@ -119,7 +122,7 @@
#define DR_REG_UART2_BASE 0x3ff6E000
#define DR_REG_PWM2_BASE 0x3ff6F000
#define DR_REG_PWM3_BASE 0x3ff70000
#define PERIPHS_SPI_ENCRYPT_BASEADDR DR_REG_SPI_ENCRYPT_BASE
#define PERIPHS_SPI_ENCRYPT_BASEADDR DR_REG_SPI_ENCRYPT_BASE
//Registers Operation {{
#define ETS_UNCACHED_ADDR(addr) (addr)

View File

@ -31,6 +31,7 @@
#include "esp_flash_encrypt.h"
#include "esp_log.h"
#include "cache_utils.h"
#include "esp_spiram.h"
#ifndef NDEBUG
// Enable built-in checks in queue.h in debug builds
@ -225,6 +226,9 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flas
entire cache.
*/
if (!did_flush && need_flush) {
#if CONFIG_SPIRAM_SUPPORT
esp_spiram_writeback_cache();
#endif
Cache_Flush(0);
Cache_Flush(1);
}
@ -330,6 +334,9 @@ static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t leng
tricky because mmaped memory can be used on un-pinned
cores, or the pointer passed between CPUs.
*/
#if CONFIG_SPIRAM_SUPPORT
esp_spiram_writeback_cache();
#endif
Cache_Flush(0);
#ifndef CONFIG_FREERTOS_UNICORE
Cache_Flush(1);

View File

@ -118,6 +118,7 @@ CONFIG_BT_RESERVE_DRAM=0
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_MEMMAP_SMP=y
# CONFIG_SPIRAM_SUPPORT is not set
# CONFIG_MEMMAP_TRACEMEM is not set
# CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set
# CONFIG_ESP32_TRAX is not set