Skip to content

Commit 76c1b8f

Browse files
committed
libraries/Storage: Add flash FS examples.
Signed-off-by: iabdalkader <[email protected]>
1 parent e493c01 commit 76c1b8f

File tree

5 files changed

+5989
-0
lines changed

5 files changed

+5989
-0
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*
2+
Flash Format
3+
4+
The sketch formats the board flash storage as follows:
5+
6+
* Partition 1 1MB: used for network certificates
7+
* Partition 2 5MB: OTA
8+
* Partition 3 1MB: Provisioning KVStore
9+
* Partition 4 7MB: User data
10+
11+
This example code is in the public domain.
12+
*/
13+
14+
#include <Arduino.h>
15+
#include <zephyr/fs/fs.h>
16+
#include <zephyr/storage/flash_map.h>
17+
#include "certificates.h"
18+
19+
// MBR structures
20+
struct __attribute__((packed)) mbrEntry {
21+
uint8_t status;
22+
uint8_t chsStart[3];
23+
uint8_t type;
24+
uint8_t chsStop[3];
25+
uint32_t lbaOffset;
26+
uint32_t lbaSize;
27+
};
28+
29+
struct __attribute__((packed)) mbrTable {
30+
mbrEntry entries[4];
31+
uint8_t signature[2];
32+
};
33+
34+
bool waitResponse() {
35+
bool proceed = false;
36+
bool confirmation = false;
37+
38+
while (confirmation == false) {
39+
if (!Serial.available()) {
40+
continue;
41+
}
42+
43+
switch (Serial.read()) {
44+
case 'y':
45+
case 'Y':
46+
confirmation = true;
47+
proceed = true;
48+
break;
49+
case 'n':
50+
case 'N':
51+
confirmation = true;
52+
proceed = false;
53+
break;
54+
default:
55+
continue;
56+
}
57+
}
58+
59+
return proceed;
60+
}
61+
62+
int formatPartition(unsigned int partition_id, int fs_type) {
63+
Serial.print("Formatting partition as ");
64+
Serial.println(fs_type == FS_FATFS ? "FAT..." : "LittleFS...");
65+
66+
int rc = 0;
67+
if (fs_type == FS_FATFS) {
68+
rc = fs_mkfs(FS_FATFS, partition_id, NULL, 0);
69+
} else {
70+
rc = fs_mkfs(FS_LITTLEFS, partition_id, NULL, 0);
71+
}
72+
73+
if (rc < 0) {
74+
Serial.print("Error formatting partition: ");
75+
Serial.println(rc);
76+
return rc;
77+
}
78+
79+
Serial.print("Partition formatted successfully!");
80+
return 0;
81+
}
82+
83+
int flashCertificates() {
84+
Serial.print("Certificate size: ");
85+
Serial.print(cacert_pem_len);
86+
Serial.println(" bytes");
87+
88+
struct fs_file_t file;
89+
fs_file_t_init(&file);
90+
91+
Serial.println("Opening /wlan:/cacert.pem for writing...");
92+
int rc = fs_open(&file, "/wlan:/cacert.pem", FS_O_CREATE | FS_O_WRITE);
93+
if (rc != 0) {
94+
Serial.print("Error opening cacert.pem: ");
95+
Serial.println(rc);
96+
return rc;
97+
}
98+
99+
Serial.println("Writing certificates...");
100+
ssize_t ret = fs_write(&file, cacert_pem, cacert_pem_len);
101+
if (ret < 0) {
102+
Serial.print("Error writing certificates: ");
103+
Serial.println(ret);
104+
fs_close(&file);
105+
return rc;
106+
}
107+
108+
rc = fs_sync(&file);
109+
if (rc != 0) {
110+
Serial.print("Warning: fs_sync failed: ");
111+
Serial.println(rc);
112+
fs_close(&file);
113+
return rc;
114+
}
115+
116+
fs_close(&file);
117+
Serial.println("Certificates written successfully!");
118+
return 0;
119+
}
120+
121+
int flashMBR() {
122+
Serial.println("Creating MBR partition table...");
123+
124+
// Open the MBR partition
125+
const struct flash_area *fa;
126+
int ret = flash_area_open(FIXED_PARTITION_ID(mbr_partition), &fa);
127+
if (ret) {
128+
Serial.print("Error opening MBR partition: ");
129+
Serial.println(ret);
130+
return ret;
131+
}
132+
133+
// Prepare 512-byte sector with MBR
134+
uint8_t sector[512];
135+
memset(sector, 0, 512);
136+
137+
// MBR partition table starts at offset 446
138+
mbrTable *table = (mbrTable*)&sector[446];
139+
140+
// Note: lbaSize is in units of 4096-byte blocks (not standard 512-byte sectors)
141+
// This matches the original Arduino implementation which uses 4KB sectors
142+
143+
// Partition 1: WLAN (FAT32) - starts at 0x1000, size ~1020KB (255 blocks of 4KB)
144+
table->entries[0].status = 0x00; // Not bootable
145+
table->entries[0].chsStart[0] = 0;
146+
table->entries[0].chsStart[1] = 2;
147+
table->entries[0].chsStart[2] = 0;
148+
table->entries[0].type = 0x0B; // FAT32
149+
table->entries[0].chsStop[0] = 4;
150+
table->entries[0].chsStop[1] = 0;
151+
table->entries[0].chsStop[2] = 0;
152+
table->entries[0].lbaOffset = 1; // 0x1000 / 4096 = 1
153+
table->entries[0].lbaSize = 255; // (1MB - 4KB) / 4096 = 255
154+
155+
// Partition 2: OTA (FAT32) - starts at 0x100000, size 5MB (1280 blocks of 4KB)
156+
table->entries[1].status = 0x00;
157+
table->entries[1].chsStart[0] = 4;
158+
table->entries[1].chsStart[1] = 1;
159+
table->entries[1].chsStart[2] = 0;
160+
table->entries[1].type = 0x0B; // FAT32
161+
table->entries[1].chsStop[0] = 24;
162+
table->entries[1].chsStop[1] = 0;
163+
table->entries[1].chsStop[2] = 0;
164+
table->entries[1].lbaOffset = 256; // 0x100000 / 4096 = 256
165+
table->entries[1].lbaSize = 1280; // 5MB / 4096 = 1280
166+
167+
// Partition 3: KVS (FAT32) - starts at 0x600000, size 1MB (256 blocks of 4KB)
168+
table->entries[2].status = 0x00;
169+
table->entries[2].chsStart[0] = 24;
170+
table->entries[2].chsStart[1] = 1;
171+
table->entries[2].chsStart[2] = 0;
172+
table->entries[2].type = 0x0B; // FAT32
173+
table->entries[2].chsStop[0] = 28;
174+
table->entries[2].chsStop[1] = 0;
175+
table->entries[2].chsStop[2] = 0;
176+
table->entries[2].lbaOffset = 1536; // 0x600000 / 4096 = 1536
177+
table->entries[2].lbaSize = 256; // 1MB / 4096 = 256
178+
179+
// Partition 4: Storage (LittleFS/FAT32) - starts at 0x700000, size 7MB (1792 blocks of 4KB)
180+
table->entries[3].status = 0x00;
181+
table->entries[3].chsStart[0] = 28;
182+
table->entries[3].chsStart[1] = 1;
183+
table->entries[3].chsStart[2] = 0;
184+
table->entries[3].type = 0x0B; // FAT32 (could be 0x83 for LittleFS)
185+
table->entries[3].chsStop[0] = 56;
186+
table->entries[3].chsStop[1] = 0;
187+
table->entries[3].chsStop[2] = 0;
188+
table->entries[3].lbaOffset = 1792; // 0x700000 / 4096 = 1792
189+
table->entries[3].lbaSize = 1792; // 7MB / 4096 = 1792
190+
191+
// MBR signature
192+
table->signature[0] = 0x55;
193+
table->signature[1] = 0xAA;
194+
195+
// Erase the MBR partition
196+
ret = flash_area_erase(fa, 0, fa->fa_size);
197+
if (ret) {
198+
Serial.print("Error erasing MBR partition: ");
199+
Serial.println(ret);
200+
flash_area_close(fa);
201+
return ret;
202+
}
203+
204+
// Write the MBR sector
205+
ret = flash_area_write(fa, 0, sector, 512);
206+
if (ret) {
207+
Serial.print("Error writing MBR: ");
208+
Serial.println(ret);
209+
flash_area_close(fa);
210+
return ret;
211+
}
212+
213+
flash_area_close(fa);
214+
Serial.println("MBR created successfully!");
215+
return 0;
216+
}
217+
218+
void setup() {
219+
Serial.begin(115200);
220+
while (!Serial);
221+
222+
Serial.println("\nWARNING! Running the sketch all the content of the flash storage will be erased.");
223+
Serial.println("The following partitions will be created:");
224+
Serial.println("Partition 1: Network certificates 1MB");
225+
Serial.println("Partition 2: OTA 5MB");
226+
Serial.println("Partition 3: Provisioning KVStore 1MB");
227+
Serial.println("Partition 4: User data 7MB");
228+
Serial.println("Do you want to proceed? Y/[n]");
229+
230+
if (!waitResponse()) {
231+
return;
232+
}
233+
234+
// Create MBR partition table FIRST before formatting
235+
if (flashMBR()) {
236+
return;
237+
}
238+
239+
// Format Partition 1: WLAN
240+
Serial.println("\nPartition 1 (/wlan:) will be formatted as FAT.");
241+
Serial.println("Do you want to format it? Y/[n]");
242+
bool format_wlan = waitResponse();
243+
244+
if (format_wlan) {
245+
if (formatPartition((uintptr_t) "wlan:", FS_FATFS)) {
246+
return;
247+
}
248+
249+
Serial.println("\nDo you want to restore the TLS certificates? Y/[n]");
250+
if (waitResponse() && flashCertificates()) {
251+
return;
252+
}
253+
}
254+
255+
// Format Partition 2: OTA
256+
Serial.println("\nPartition 2 (/ota:) will be formatted as FAT.");
257+
Serial.println("Do you want to format it? Y/[n]");
258+
if (waitResponse()) {
259+
if (formatPartition((uintptr_t) "ota:", FS_FATFS)) {
260+
return;
261+
}
262+
}
263+
264+
// Format Partition 4: Storage
265+
Serial.println("\nDo you want to use LittleFS to format user data partition? Y/[n]");
266+
Serial.println("If No, FatFS will be used to format user partition.");
267+
bool useLittleFS = waitResponse();
268+
269+
Serial.println("\nPartition 4 (/storage) will be formatted.");
270+
Serial.println("Do you want to format it? Y/[n]");
271+
if (waitResponse()) {
272+
if (useLittleFS) {
273+
unsigned int partition_id = DT_FIXED_PARTITION_ID(DT_PROP(DT_NODELABEL(storage_fs), partition));
274+
if (formatPartition(partition_id, FS_LITTLEFS)) {
275+
return;
276+
}
277+
} else {
278+
Serial.println("FatFS for storage partition not implemented in this example.");
279+
Serial.println("Please use LittleFS or update device tree configuration.");
280+
}
281+
}
282+
283+
Serial.println("\nFlash storage formatted!");
284+
Serial.println("It's now safe to reboot or disconnect your board.");
285+
}
286+
287+
void loop() {
288+
delay(1000);
289+
}

0 commit comments

Comments
 (0)