forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spiffs_hal.cpp
184 lines (159 loc) · 6.55 KB
/
spiffs_hal.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
spiffs_hal.cpp - SPI read/write/erase functions for SPIFFS.
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include <stdlib.h>
#include <algorithm>
#include "spiffs/spiffs.h"
#include "debug.h"
extern "C" {
#include "c_types.h"
#include "spi_flash.h"
}
/*
spi_flash_read function requires flash address to be aligned on word boundary.
We take care of this by reading first and last words separately and memcpy
relevant bytes into result buffer.
alignment: 012301230123012301230123
bytes requested: -------***********------
read directly: --------xxxxxxxx--------
read pre: ----aaaa----------------
read post: ----------------bbbb----
alignedBegin: ^
alignedEnd: ^
*/
int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) {
optimistic_yield(10000);
uint32_t result = SPIFFS_OK;
uint32_t alignedBegin = (addr + 3) & (~3);
uint32_t alignedEnd = (addr + size) & (~3);
if (alignedEnd < alignedBegin) {
alignedEnd = alignedBegin;
}
if (addr < alignedBegin) {
uint32_t nb = alignedBegin - addr;
uint32_t tmp;
if (!ESP.flashRead(alignedBegin - 4, &tmp, 4)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
memcpy(dst, &tmp + 4 - nb, nb);
}
if (alignedEnd != alignedBegin) {
if (!ESP.flashRead(alignedBegin, (uint32_t*) (dst + alignedBegin - addr),
alignedEnd - alignedBegin)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
}
if (addr + size > alignedEnd) {
uint32_t nb = addr + size - alignedEnd;
uint32_t tmp;
if (!ESP.flashRead(alignedEnd, &tmp, 4)) {
DEBUGV("_spif_read(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
memcpy(dst + size - nb, &tmp, nb);
}
return result;
}
/*
Like spi_flash_read, spi_flash_write has a requirement for flash address to be
aligned. However it also requires RAM address to be aligned as it reads data
in 32-bit words. Flash address (mis-)alignment is handled much the same way
as for reads, but for RAM alignment we have to copy data into a temporary
buffer. The size of this buffer is a tradeoff between number of writes required
and amount of stack required. This is chosen to be 512 bytes here, but might
be adjusted in the future if there are good reasons to do so.
*/
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512;
int32_t spiffs_hal_write(uint32_t addr, uint32_t size, uint8_t *src) {
optimistic_yield(10000);
uint32_t alignedBegin = (addr + 3) & (~3);
uint32_t alignedEnd = (addr + size) & (~3);
if (alignedEnd < alignedBegin) {
alignedEnd = alignedBegin;
}
if (addr < alignedBegin) {
uint32_t ofs = alignedBegin - addr;
uint32_t nb = (size < ofs) ? size : ofs;
uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff};
memcpy(tmp + 4 - ofs, src, nb);
if (!ESP.flashWrite(alignedBegin - 4, (uint32_t*) tmp, 4)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
}
if (alignedEnd != alignedBegin) {
uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr);
uint32_t srcAlign = ((uint32_t) srcLeftover) & 3;
if (!srcAlign) {
if (!ESP.flashWrite(alignedBegin, (uint32_t*) srcLeftover,
alignedEnd - alignedBegin)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
}
else {
uint8_t buf[UNALIGNED_WRITE_BUFFER_SIZE];
for (uint32_t sizeLeft = alignedEnd - alignedBegin; sizeLeft; ) {
size_t willCopy = std::min(sizeLeft, sizeof(buf));
memcpy(buf, srcLeftover, willCopy);
if (!ESP.flashWrite(alignedBegin, (uint32_t*) buf, willCopy)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
sizeLeft -= willCopy;
srcLeftover += willCopy;
alignedBegin += willCopy;
}
}
}
if (addr + size > alignedEnd) {
uint32_t nb = addr + size - alignedEnd;
uint32_t tmp = 0xffffffff;
memcpy(&tmp, src + size - nb, nb);
if (!ESP.flashWrite(alignedEnd, &tmp, 4)) {
DEBUGV("_spif_write(%d) addr=%x size=%x ab=%x ae=%x\r\n",
__LINE__, addr, size, alignedBegin, alignedEnd);
return SPIFFS_ERR_INTERNAL;
}
}
return SPIFFS_OK;
}
int32_t spiffs_hal_erase(uint32_t addr, uint32_t size) {
if ((size & (SPI_FLASH_SEC_SIZE - 1)) != 0 ||
(addr & (SPI_FLASH_SEC_SIZE - 1)) != 0) {
DEBUGV("_spif_erase called with addr=%x, size=%d\r\n", addr, size);
abort();
}
const uint32_t sector = addr / SPI_FLASH_SEC_SIZE;
const uint32_t sectorCount = size / SPI_FLASH_SEC_SIZE;
for (uint32_t i = 0; i < sectorCount; ++i) {
optimistic_yield(10000);
if (!ESP.flashEraseSector(sector + i)) {
DEBUGV("_spif_erase addr=%x size=%d i=%d\r\n", addr, size, i);
return SPIFFS_ERR_INTERNAL;
}
}
return SPIFFS_OK;
}