NuMaker SPI flash-backed file system

Committer:
cyliang
Date:
Wed Mar 01 04:00:38 2023 +0000
Revision:
11:82c5a2fca797
Parent:
10:f866fc9e7387
Update to os v6.17.0 for M467 target

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ccli8 1:772d0adf75cc 1 /* mbed Microcontroller Library
ccli8 6:5904bcfd7c00 2 * Copyright (c) 2006-2019 ARM Limited
ccli8 1:772d0adf75cc 3 *
ccli8 1:772d0adf75cc 4 * Licensed under the Apache License, Version 2.0 (the "License");
ccli8 1:772d0adf75cc 5 * you may not use this file except in compliance with the License.
ccli8 1:772d0adf75cc 6 * You may obtain a copy of the License at
ccli8 1:772d0adf75cc 7 *
ccli8 1:772d0adf75cc 8 * http://www.apache.org/licenses/LICENSE-2.0
ccli8 1:772d0adf75cc 9 *
ccli8 1:772d0adf75cc 10 * Unless required by applicable law or agreed to in writing, software
ccli8 1:772d0adf75cc 11 * distributed under the License is distributed on an "AS IS" BASIS,
ccli8 1:772d0adf75cc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ccli8 1:772d0adf75cc 13 * See the License for the specific language governing permissions and
ccli8 1:772d0adf75cc 14 * limitations under the License.
ccli8 1:772d0adf75cc 15 */
ccli8 1:772d0adf75cc 16 #include "mbed.h"
ccli8 1:772d0adf75cc 17 #include <stdio.h>
ccli8 1:772d0adf75cc 18 #include <errno.h>
ccli8 1:772d0adf75cc 19
ccli8 1:772d0adf75cc 20 #include "SPIFBlockDevice.h"
ccli8 1:772d0adf75cc 21
ccli8 6:5904bcfd7c00 22 // Maximum number of elements in buffer
ccli8 6:5904bcfd7c00 23 #define BUFFER_MAX_LEN 10
ccli8 1:772d0adf75cc 24
ccli8 10:f866fc9e7387 25 /* Disable write-protect (/WP) and hold (/HOLD) functions
ccli8 10:f866fc9e7387 26 *
ccli8 10:f866fc9e7387 27 * Excerpt on QE bit of Winbond SPI Flash:
ccli8 10:f866fc9e7387 28 *
ccli8 10:f866fc9e7387 29 * The Quad Enable (QE) bit is a non-volatile read/write bit in the status
ccli8 10:f866fc9e7387 30 * register (S9) that enables Quad SPI operation. When the QE bit is set to
ccli8 10:f866fc9e7387 31 * a 0 state (factory default for part numbers with ordering options “IM”),
ccli8 10:f866fc9e7387 32 * the /HOLD are enabled, the device operates in Standard/Dual SPI modes.
ccli8 10:f866fc9e7387 33 * When the QE bit is set to a 1 (factory fixed default for part numbers with
ccli8 10:f866fc9e7387 34 * ordering options “IQ”), the Quad IO2 and IO3 pins are enabled, and /HOLD
ccli8 10:f866fc9e7387 35 * function is disabled, the device operates in Standard/Dual/Quad SPI modes.
ccli8 10:f866fc9e7387 36 *
ccli8 10:f866fc9e7387 37 * So that we need to disable write-protect and hold functions by driving /WP
ccli8 10:f866fc9e7387 38 * and /HOLD pins to high if QE bit is not set.
ccli8 10:f866fc9e7387 39 */
ccli8 10:f866fc9e7387 40 #if defined(TARGET_NUMAKER_IOT_M467)
ccli8 10:f866fc9e7387 41 /* Can comment out the below lines if QE bit is set, e.g. W25Q32JVSSIQ, or keep them for safe */
ccli8 10:f866fc9e7387 42 DigitalOut onboard_spi_wp(PI_13, 1);
ccli8 10:f866fc9e7387 43 DigitalOut onboard_spi_hold(PI_12, 1);
ccli8 10:f866fc9e7387 44 #elif defined(TARGET_NUMAKER_PFM_M487) || defined(TARGET_NUMAKER_IOT_M487)
ccli8 1:772d0adf75cc 45 DigitalOut onboard_spi_wp(PC_5, 1);
ccli8 1:772d0adf75cc 46 DigitalOut onboard_spi_hold(PC_4, 1);
ccli8 1:772d0adf75cc 47 #endif
ccli8 3:977ed4dda7da 48
ccli8 6:5904bcfd7c00 49 BlockDevice *bd = new SPIFBlockDevice(MBED_CONF_SPIF_DRIVER_SPI_MOSI,
ccli8 6:5904bcfd7c00 50 MBED_CONF_SPIF_DRIVER_SPI_MISO,
ccli8 6:5904bcfd7c00 51 MBED_CONF_SPIF_DRIVER_SPI_CLK,
ccli8 6:5904bcfd7c00 52 MBED_CONF_SPIF_DRIVER_SPI_CS);
ccli8 3:977ed4dda7da 53
ccli8 6:5904bcfd7c00 54 // This example uses LittleFileSystem as the default file system
ccli8 6:5904bcfd7c00 55 #include "LittleFileSystem.h"
ccli8 6:5904bcfd7c00 56 LittleFileSystem fs("fs");
ccli8 1:772d0adf75cc 57
ccli8 6:5904bcfd7c00 58 // Uncomment the following two lines and comment the previous two to use FAT file system.
ccli8 6:5904bcfd7c00 59 // #include "FATFileSystem.h"
ccli8 6:5904bcfd7c00 60 // FATFileSystem fs("fs");
ccli8 1:772d0adf75cc 61
ccli8 8:47803c22154e 62 // Support bare-metal build in which RTOS will be absent
ccli8 8:47803c22154e 63 #if MBED_CONF_RTOS_PRESENT
ccli8 1:772d0adf75cc 64 // Set up the button to trigger an erase
ccli8 1:772d0adf75cc 65 InterruptIn irq(BUTTON1);
ccli8 1:772d0adf75cc 66 void erase() {
ccli8 1:772d0adf75cc 67 printf("Initializing the block device... ");
ccli8 1:772d0adf75cc 68 fflush(stdout);
ccli8 6:5904bcfd7c00 69 int err = bd->init();
ccli8 1:772d0adf75cc 70 printf("%s\n", (err ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 71 if (err) {
ccli8 1:772d0adf75cc 72 error("error: %s (%d)\n", strerror(-err), err);
ccli8 1:772d0adf75cc 73 }
ccli8 1:772d0adf75cc 74
ccli8 1:772d0adf75cc 75 printf("Erasing the block device... ");
ccli8 1:772d0adf75cc 76 fflush(stdout);
ccli8 6:5904bcfd7c00 77 err = bd->erase(0, bd->size());
ccli8 1:772d0adf75cc 78 printf("%s\n", (err ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 79 if (err) {
ccli8 1:772d0adf75cc 80 error("error: %s (%d)\n", strerror(-err), err);
ccli8 1:772d0adf75cc 81 }
ccli8 1:772d0adf75cc 82
ccli8 1:772d0adf75cc 83 printf("Deinitializing the block device... ");
ccli8 1:772d0adf75cc 84 fflush(stdout);
ccli8 6:5904bcfd7c00 85 err = bd->deinit();
ccli8 1:772d0adf75cc 86 printf("%s\n", (err ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 87 if (err) {
ccli8 1:772d0adf75cc 88 error("error: %s (%d)\n", strerror(-err), err);
ccli8 1:772d0adf75cc 89 }
ccli8 1:772d0adf75cc 90 }
ccli8 8:47803c22154e 91 #endif
ccli8 1:772d0adf75cc 92
ccli8 9:6ce52eb7b6c4 93 #if MBED_CONF_RTOS_PRESENT
ccli8 9:6ce52eb7b6c4 94 #if MBED_MAJOR_VERSION >= 6
ccli8 9:6ce52eb7b6c4 95 static auto erase_event = mbed_event_queue()->make_user_allocated_event(erase);
ccli8 9:6ce52eb7b6c4 96 #endif
ccli8 9:6ce52eb7b6c4 97 #endif
ccli8 9:6ce52eb7b6c4 98
ccli8 1:772d0adf75cc 99 // Entry point for the example
ccli8 1:772d0adf75cc 100 int main() {
ccli8 1:772d0adf75cc 101 printf("--- Mbed OS filesystem example ---\n");
ccli8 1:772d0adf75cc 102
ccli8 8:47803c22154e 103 #if MBED_CONF_RTOS_PRESENT
ccli8 5:af8e8a91a373 104 // Setup the erase event on button press, use the event queue
ccli8 5:af8e8a91a373 105 // to avoid running in interrupt context
ccli8 9:6ce52eb7b6c4 106 #if MBED_MAJOR_VERSION >= 6
ccli8 9:6ce52eb7b6c4 107 irq.fall(std::ref(erase_event));
ccli8 9:6ce52eb7b6c4 108 #else
ccli8 5:af8e8a91a373 109 irq.fall(mbed_event_queue()->event(erase));
ccli8 8:47803c22154e 110 #endif
ccli8 9:6ce52eb7b6c4 111 #endif
ccli8 1:772d0adf75cc 112
ccli8 1:772d0adf75cc 113 // Try to mount the filesystem
ccli8 1:772d0adf75cc 114 printf("Mounting the filesystem... ");
ccli8 1:772d0adf75cc 115 fflush(stdout);
ccli8 6:5904bcfd7c00 116 int err = fs.mount(bd);
ccli8 1:772d0adf75cc 117 printf("%s\n", (err ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 118 if (err) {
ccli8 1:772d0adf75cc 119 // Reformat if we can't mount the filesystem
ccli8 1:772d0adf75cc 120 // this should only happen on the first boot
ccli8 1:772d0adf75cc 121 printf("No filesystem found, formatting... ");
ccli8 1:772d0adf75cc 122 fflush(stdout);
ccli8 6:5904bcfd7c00 123 err = fs.reformat(bd);
ccli8 1:772d0adf75cc 124 printf("%s\n", (err ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 125 if (err) {
ccli8 1:772d0adf75cc 126 error("error: %s (%d)\n", strerror(-err), err);
ccli8 1:772d0adf75cc 127 }
ccli8 1:772d0adf75cc 128 }
ccli8 1:772d0adf75cc 129
ccli8 1:772d0adf75cc 130 // Open the numbers file
ccli8 1:772d0adf75cc 131 printf("Opening \"/fs/numbers.txt\"... ");
ccli8 1:772d0adf75cc 132 fflush(stdout);
ccli8 1:772d0adf75cc 133 FILE *f = fopen("/fs/numbers.txt", "r+");
ccli8 1:772d0adf75cc 134 printf("%s\n", (!f ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 135 if (!f) {
ccli8 1:772d0adf75cc 136 // Create the numbers file if it doesn't exist
ccli8 1:772d0adf75cc 137 printf("No file found, creating a new file... ");
ccli8 1:772d0adf75cc 138 fflush(stdout);
ccli8 1:772d0adf75cc 139 f = fopen("/fs/numbers.txt", "w+");
ccli8 1:772d0adf75cc 140 printf("%s\n", (!f ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 141 if (!f) {
ccli8 1:772d0adf75cc 142 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 143 }
ccli8 1:772d0adf75cc 144
ccli8 1:772d0adf75cc 145 for (int i = 0; i < 10; i++) {
ccli8 1:772d0adf75cc 146 printf("\rWriting numbers (%d/%d)... ", i, 10);
ccli8 1:772d0adf75cc 147 fflush(stdout);
ccli8 1:772d0adf75cc 148 err = fprintf(f, " %d\n", i);
ccli8 1:772d0adf75cc 149 if (err < 0) {
ccli8 1:772d0adf75cc 150 printf("Fail :(\n");
ccli8 1:772d0adf75cc 151 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 152 }
ccli8 1:772d0adf75cc 153 }
ccli8 1:772d0adf75cc 154 printf("\rWriting numbers (%d/%d)... OK\n", 10, 10);
ccli8 1:772d0adf75cc 155
ccli8 1:772d0adf75cc 156 printf("Seeking file... ");
ccli8 1:772d0adf75cc 157 fflush(stdout);
ccli8 1:772d0adf75cc 158 err = fseek(f, 0, SEEK_SET);
ccli8 1:772d0adf75cc 159 printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 160 if (err < 0) {
ccli8 1:772d0adf75cc 161 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 162 }
ccli8 1:772d0adf75cc 163 }
ccli8 1:772d0adf75cc 164
ccli8 1:772d0adf75cc 165 // Go through and increment the numbers
ccli8 1:772d0adf75cc 166 for (int i = 0; i < 10; i++) {
ccli8 1:772d0adf75cc 167 printf("\rIncrementing numbers (%d/%d)... ", i, 10);
ccli8 1:772d0adf75cc 168 fflush(stdout);
ccli8 1:772d0adf75cc 169
ccli8 1:772d0adf75cc 170 // Get current stream position
ccli8 1:772d0adf75cc 171 long pos = ftell(f);
ccli8 1:772d0adf75cc 172
ccli8 1:772d0adf75cc 173 // Parse out the number and increment
ccli8 6:5904bcfd7c00 174 char buf[BUFFER_MAX_LEN];
ccli8 6:5904bcfd7c00 175 if (!fgets(buf, BUFFER_MAX_LEN, f)) {
ccli8 6:5904bcfd7c00 176 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 6:5904bcfd7c00 177 }
ccli8 6:5904bcfd7c00 178 char *endptr;
ccli8 6:5904bcfd7c00 179 int32_t number = strtol(buf, &endptr, 10);
ccli8 6:5904bcfd7c00 180 if (
ccli8 6:5904bcfd7c00 181 (errno == ERANGE) || // The number is too small/large
ccli8 6:5904bcfd7c00 182 (endptr == buf) || // No character was read
ccli8 6:5904bcfd7c00 183 (*endptr && *endptr != '\n') // The whole input was not converted
ccli8 6:5904bcfd7c00 184 ) {
ccli8 6:5904bcfd7c00 185 continue;
ccli8 6:5904bcfd7c00 186 }
ccli8 1:772d0adf75cc 187 number += 1;
ccli8 1:772d0adf75cc 188
ccli8 1:772d0adf75cc 189 // Seek to beginning of number
ccli8 1:772d0adf75cc 190 fseek(f, pos, SEEK_SET);
ccli8 1:772d0adf75cc 191
ccli8 1:772d0adf75cc 192 // Store number
ccli8 1:772d0adf75cc 193 fprintf(f, " %d\n", number);
ccli8 6:5904bcfd7c00 194
ccli8 6:5904bcfd7c00 195 // Flush between write and read on same file
ccli8 6:5904bcfd7c00 196 fflush(f);
ccli8 1:772d0adf75cc 197 }
ccli8 1:772d0adf75cc 198 printf("\rIncrementing numbers (%d/%d)... OK\n", 10, 10);
ccli8 1:772d0adf75cc 199
ccli8 1:772d0adf75cc 200 // Close the file which also flushes any cached writes
ccli8 1:772d0adf75cc 201 printf("Closing \"/fs/numbers.txt\"... ");
ccli8 1:772d0adf75cc 202 fflush(stdout);
ccli8 1:772d0adf75cc 203 err = fclose(f);
ccli8 1:772d0adf75cc 204 printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 205 if (err < 0) {
ccli8 1:772d0adf75cc 206 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 207 }
ccli8 1:772d0adf75cc 208
ccli8 1:772d0adf75cc 209 // Display the root directory
ccli8 1:772d0adf75cc 210 printf("Opening the root directory... ");
ccli8 1:772d0adf75cc 211 fflush(stdout);
ccli8 1:772d0adf75cc 212 DIR *d = opendir("/fs/");
ccli8 1:772d0adf75cc 213 printf("%s\n", (!d ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 214 if (!d) {
ccli8 1:772d0adf75cc 215 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 216 }
ccli8 1:772d0adf75cc 217
ccli8 1:772d0adf75cc 218 printf("root directory:\n");
ccli8 1:772d0adf75cc 219 while (true) {
ccli8 1:772d0adf75cc 220 struct dirent *e = readdir(d);
ccli8 1:772d0adf75cc 221 if (!e) {
ccli8 1:772d0adf75cc 222 break;
ccli8 1:772d0adf75cc 223 }
ccli8 1:772d0adf75cc 224
ccli8 1:772d0adf75cc 225 printf(" %s\n", e->d_name);
ccli8 1:772d0adf75cc 226 }
ccli8 1:772d0adf75cc 227
ccli8 1:772d0adf75cc 228 printf("Closing the root directory... ");
ccli8 1:772d0adf75cc 229 fflush(stdout);
ccli8 1:772d0adf75cc 230 err = closedir(d);
ccli8 1:772d0adf75cc 231 printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 232 if (err < 0) {
ccli8 1:772d0adf75cc 233 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 234 }
ccli8 1:772d0adf75cc 235
ccli8 1:772d0adf75cc 236 // Display the numbers file
ccli8 1:772d0adf75cc 237 printf("Opening \"/fs/numbers.txt\"... ");
ccli8 1:772d0adf75cc 238 fflush(stdout);
ccli8 1:772d0adf75cc 239 f = fopen("/fs/numbers.txt", "r");
ccli8 1:772d0adf75cc 240 printf("%s\n", (!f ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 241 if (!f) {
ccli8 1:772d0adf75cc 242 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 243 }
ccli8 1:772d0adf75cc 244
ccli8 1:772d0adf75cc 245 printf("numbers:\n");
ccli8 1:772d0adf75cc 246 while (!feof(f)) {
ccli8 1:772d0adf75cc 247 int c = fgetc(f);
ccli8 1:772d0adf75cc 248 printf("%c", c);
ccli8 1:772d0adf75cc 249 }
ccli8 1:772d0adf75cc 250
ccli8 1:772d0adf75cc 251 printf("\rClosing \"/fs/numbers.txt\"... ");
ccli8 1:772d0adf75cc 252 fflush(stdout);
ccli8 1:772d0adf75cc 253 err = fclose(f);
ccli8 1:772d0adf75cc 254 printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 255 if (err < 0) {
ccli8 1:772d0adf75cc 256 error("error: %s (%d)\n", strerror(errno), -errno);
ccli8 1:772d0adf75cc 257 }
ccli8 1:772d0adf75cc 258
ccli8 1:772d0adf75cc 259 // Tidy up
ccli8 1:772d0adf75cc 260 printf("Unmounting... ");
ccli8 1:772d0adf75cc 261 fflush(stdout);
ccli8 1:772d0adf75cc 262 err = fs.unmount();
ccli8 1:772d0adf75cc 263 printf("%s\n", (err < 0 ? "Fail :(" : "OK"));
ccli8 1:772d0adf75cc 264 if (err < 0) {
ccli8 1:772d0adf75cc 265 error("error: %s (%d)\n", strerror(-err), err);
ccli8 1:772d0adf75cc 266 }
ccli8 1:772d0adf75cc 267
ccli8 1:772d0adf75cc 268 printf("Mbed OS filesystem example done!\n");
ccli8 1:772d0adf75cc 269 }
ccli8 1:772d0adf75cc 270