1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
20 #include <freertos/FreeRTOS.h>
21 #include <freertos/task.h>
22 #include <freertos/semphr.h>
23 #include <rom/spi_flash.h>
24 #include <rom/cache.h>
26 #include <soc/dport_reg.h>
27 #include "sdkconfig.h"
30 #include "esp_spi_flash.h"
32 #include "cache_utils.h"
34 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
35 static const char* TAG = "spi_flash";
36 static spi_flash_counters_t s_flash_stats;
38 #define COUNTER_START() uint32_t ts_begin = xthal_get_ccount()
39 #define COUNTER_STOP(counter) \
41 s_flash_stats.counter.count++; \
42 s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \\
45 #define COUNTER_ADD_BYTES(counter, size) \
47 s_flash_stats.counter.bytes += size; \
51 #define COUNTER_START()
52 #define COUNTER_STOP(counter)
53 #define COUNTER_ADD_BYTES(counter, size)
55 #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
57 static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc);
61 spi_flash_init_lock();
62 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
63 spi_flash_reset_counters();
67 size_t spi_flash_get_chip_size()
69 return g_rom_flashchip.chip_size;
72 SpiFlashOpResult IRAM_ATTR spi_flash_unlock()
74 static bool unlocked = false;
76 SpiFlashOpResult rc = SPIUnlock();
77 if (rc != SPI_FLASH_RESULT_OK) {
82 return SPI_FLASH_RESULT_OK;
85 esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
87 return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
90 esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
92 if (start_addr % SPI_FLASH_SEC_SIZE != 0) {
93 return ESP_ERR_INVALID_ARG;
95 if (size % SPI_FLASH_SEC_SIZE != 0) {
96 return ESP_ERR_INVALID_SIZE;
98 if (size + start_addr > spi_flash_get_chip_size()) {
99 return ESP_ERR_INVALID_SIZE;
101 size_t start = start_addr / SPI_FLASH_SEC_SIZE;
102 size_t end = start + size / SPI_FLASH_SEC_SIZE;
103 const size_t sectors_per_block = 16;
105 spi_flash_disable_interrupts_caches_and_other_cpu();
107 rc = spi_flash_unlock();
108 if (rc == SPI_FLASH_RESULT_OK) {
109 for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) {
110 if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) {
111 rc = SPIEraseBlock(sector / sectors_per_block);
112 sector += sectors_per_block;
113 COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE);
116 rc = SPIEraseSector(sector);
118 COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
122 spi_flash_enable_interrupts_caches_and_other_cpu();
124 return spi_flash_translate_rc(rc);
127 esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const uint8_t *src, size_t size)
129 // TODO: replace this check with code which deals with unaligned sources
130 if (((ptrdiff_t) src) % 4 != 0) {
131 return ESP_ERR_INVALID_ARG;
133 // Destination alignment is also checked in ROM code, but we can give
134 // better error code here
135 // TODO: add handling of unaligned destinations
136 if (dest_addr % 4 != 0) {
137 return ESP_ERR_INVALID_ARG;
140 return ESP_ERR_INVALID_SIZE;
142 // Out of bound writes are checked in ROM code, but we can give better
144 if (dest_addr + size > g_rom_flashchip.chip_size) {
145 return ESP_ERR_INVALID_SIZE;
148 spi_flash_disable_interrupts_caches_and_other_cpu();
150 rc = spi_flash_unlock();
151 if (rc == SPI_FLASH_RESULT_OK) {
152 rc = SPIWrite((uint32_t) dest_addr, (const uint32_t*) src, (int32_t) size);
153 COUNTER_ADD_BYTES(write, size);
155 spi_flash_enable_interrupts_caches_and_other_cpu();
157 return spi_flash_translate_rc(rc);
160 esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, uint8_t *dest, size_t size)
162 // TODO: replace this check with code which deals with unaligned destinations
163 if (((ptrdiff_t) dest) % 4 != 0) {
164 return ESP_ERR_INVALID_ARG;
166 // Source alignment is also checked in ROM code, but we can give
167 // better error code here
168 // TODO: add handling of unaligned destinations
169 if (src_addr % 4 != 0) {
170 return ESP_ERR_INVALID_ARG;
173 return ESP_ERR_INVALID_SIZE;
175 // Out of bound reads are checked in ROM code, but we can give better
177 if (src_addr + size > g_rom_flashchip.chip_size) {
178 return ESP_ERR_INVALID_SIZE;
181 spi_flash_disable_interrupts_caches_and_other_cpu();
182 SpiFlashOpResult rc = SPIRead((uint32_t) src_addr, (uint32_t*) dest, (int32_t) size);
183 COUNTER_ADD_BYTES(read, size);
184 spi_flash_enable_interrupts_caches_and_other_cpu();
186 return spi_flash_translate_rc(rc);
189 static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc)
192 case SPI_FLASH_RESULT_OK:
194 case SPI_FLASH_RESULT_TIMEOUT:
195 return ESP_ERR_FLASH_OP_TIMEOUT;
196 case SPI_FLASH_RESULT_ERR:
198 return ESP_ERR_FLASH_OP_FAIL;
202 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
204 static inline void dump_counter(spi_flash_counter_t* counter, const char* name)
206 ESP_LOGI(TAG, "%s count=%8d time=%8dms bytes=%8d\n", name,
207 counter->count, counter->time, counter->bytes);
210 const spi_flash_counters_t* spi_flash_get_counters()
212 return &s_flash_stats;
215 void spi_flash_reset_counters()
217 memset(&s_flash_stats, 0, sizeof(s_flash_stats));
220 void spi_flash_dump_counters()
222 dump_counter(&s_flash_stats.read, "read ");
223 dump_counter(&s_flash_stats.write, "write");
224 dump_counter(&s_flash_stats.erase, "erase");
227 #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS