summaryrefslogtreecommitdiff
path: root/supervisor
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2018-11-30 14:40:01 -0800
committerScott Shawcroft <scott@tannewt.org>2018-11-30 14:40:01 -0800
commit95e03092630bbad9949c5fe32cd51e7c29bc065b (patch)
tree484cb7535142eaabe873bc10552bbfa1b48ab43b /supervisor
parent754d6afd163ae5f295444166863b5d11afd1b2e4 (diff)
parentab94344baee1a5d73d3890de16319cab1e2616de (diff)
Merge remote-tracking branch 'adafruit/master' into mini_sam
Diffstat (limited to 'supervisor')
-rw-r--r--supervisor/flash.h54
-rw-r--r--supervisor/flash_root_pointers.h35
-rw-r--r--supervisor/port.h3
-rw-r--r--supervisor/serial.h10
-rw-r--r--supervisor/shared/external_flash/common_commands.h47
-rw-r--r--supervisor/shared/external_flash/devices.h375
-rw-r--r--supervisor/shared/external_flash/external_flash.c546
-rw-r--r--supervisor/shared/external_flash/external_flash.h48
-rw-r--r--supervisor/shared/external_flash/external_flash_root_pointers.h35
-rw-r--r--supervisor/shared/external_flash/qspi_flash.c56
-rw-r--r--supervisor/shared/external_flash/qspi_flash.h31
-rw-r--r--supervisor/shared/external_flash/spi_flash.c150
-rw-r--r--supervisor/shared/filesystem.c107
-rw-r--r--supervisor/shared/flash.c202
-rw-r--r--supervisor/shared/micropython.c58
-rw-r--r--supervisor/shared/rgb_led_status.h2
-rw-r--r--supervisor/shared/serial.c63
-rw-r--r--supervisor/shared/status_leds.c62
-rw-r--r--supervisor/shared/status_leds.h36
-rw-r--r--supervisor/shared/usb/tusb_config.h116
-rw-r--r--supervisor/shared/usb/usb.c140
-rw-r--r--supervisor/shared/usb/usb_desc.c46
-rw-r--r--supervisor/shared/usb/usb_desc.h43
-rw-r--r--supervisor/shared/usb/usb_msc_flash.c208
-rw-r--r--supervisor/spi_flash_api.h45
-rw-r--r--supervisor/supervisor.mk72
-rw-r--r--supervisor/usb.h44
27 files changed, 2627 insertions, 7 deletions
diff --git a/supervisor/flash.h b/supervisor/flash.h
new file mode 100644
index 000000000..ae6a44fd0
--- /dev/null
+++ b/supervisor/flash.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_FLASH_H
+#define MICROPY_INCLUDED_SUPERVISOR_FLASH_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/mpconfig.h"
+
+#ifdef EXTERNAL_FLASH_DEVICE_COUNT
+#include "supervisor/shared/external_flash/external_flash.h"
+#else
+#include "supervisor/internal_flash.h"
+#endif
+
+void supervisor_flash_set_usb_writable(bool usb_writable);
+void supervisor_flash_init(void);
+uint32_t supervisor_flash_get_block_size(void);
+uint32_t supervisor_flash_get_block_count(void);
+void supervisor_flash_flush(void);
+
+// these return 0 on success, non-zero on error
+mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks);
+mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks);
+
+struct _fs_user_mount_t;
+void supervisor_flash_init_vfs(struct _fs_user_mount_t *vfs);
+void supervisor_flash_flush(void);
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_FLASH_H
diff --git a/supervisor/flash_root_pointers.h b/supervisor/flash_root_pointers.h
new file mode 100644
index 000000000..634ae58d3
--- /dev/null
+++ b/supervisor/flash_root_pointers.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
+#define MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
+
+#ifdef EXTERNAL_FLASH_DEVICE_COUNT
+#include "supervisor/shared/external_flash/external_flash_root_pointers.h"
+#else
+#include "supervisor/internal_flash_root_pointers.h"
+#endif
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
diff --git a/supervisor/port.h b/supervisor/port.h
index f30d87b47..dd4a82209 100644
--- a/supervisor/port.h
+++ b/supervisor/port.h
@@ -57,6 +57,9 @@ void reset_port(void);
// Reset the rest of the board.
void reset_board(void);
+// Reset to the bootloader
+void reset_to_bootloader(void);
+
#ifdef NRF52_SERIES
void HardFault_Handler(void);
#endif
diff --git a/supervisor/serial.h b/supervisor/serial.h
index 9446ee71c..84b3062a3 100644
--- a/supervisor/serial.h
+++ b/supervisor/serial.h
@@ -30,8 +30,18 @@
#include <stdbool.h>
#include <stdint.h>
+#include "py/mpconfig.h"
+
+#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
+#include "lib/oofatfs/ff.h"
+
+FIL* boot_output_file;
+#endif
+
void serial_init(void);
void serial_write(const char* text);
+// Only writes up to given length. Does not check for null termination at all.
+void serial_write_substring(const char* text, uint32_t length);
char serial_read(void);
bool serial_bytes_available(void);
bool serial_connected(void);
diff --git a/supervisor/shared/external_flash/common_commands.h b/supervisor/shared/external_flash/common_commands.h
new file mode 100644
index 000000000..cc0da2175
--- /dev/null
+++ b/supervisor/shared/external_flash/common_commands.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_COMMON_COMMANDS_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_COMMON_COMMANDS_H
+
+#define CMD_READ_JEDEC_ID 0x9f
+#define CMD_READ_DATA 0x03
+#define CMD_FAST_READ_DATA 0x0B
+#define CMD_SECTOR_ERASE 0x20
+// #define CMD_SECTOR_ERASE CMD_READ_JEDEC_ID
+#define CMD_DISABLE_WRITE 0x04
+#define CMD_ENABLE_WRITE 0x06
+#define CMD_PAGE_PROGRAM 0x02
+// #define CMD_PAGE_PROGRAM CMD_READ_JEDEC_ID
+#define CMD_READ_STATUS 0x05
+#define CMD_READ_STATUS2 0x35
+#define CMD_WRITE_STATUS_BYTE1 0x01
+#define CMD_WRITE_STATUS_BYTE2 0x31
+#define CMD_DUAL_READ 0x3b
+#define CMD_QUAD_READ 0x6b
+#define CMD_ENABLE_RESET 0x66
+#define CMD_RESET 0x99
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_COMMON_COMMANDS_H
diff --git a/supervisor/shared/external_flash/devices.h b/supervisor/shared/external_flash/devices.h
new file mode 100644
index 000000000..86e0868d0
--- /dev/null
+++ b/supervisor/shared/external_flash/devices.h
@@ -0,0 +1,375 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t total_size;
+ uint16_t start_up_time_us;
+
+ // Three response bytes to 0x9f JEDEC ID command.
+ uint8_t manufacturer_id;
+ uint8_t memory_type;
+ uint8_t capacity;
+
+ // Max clock speed for all operations and the fastest read mode.
+ uint8_t max_clock_speed_mhz;
+
+ // Bitmask for Quad Enable bit if present. 0x00 otherwise. This is for the highest byte in the
+ // status register.
+ uint8_t quad_enable_bit_mask;
+
+ bool has_sector_protection : 1;
+
+ // Supports the 0x0b fast read command with 8 dummy cycles.
+ bool supports_fast_read : 1;
+
+ // Supports the fast read, quad output command 0x6b with 8 dummy cycles.
+ bool supports_qspi : 1;
+
+ // Supports the quad input page program command 0x32. This is known as 1-1-4 because it only
+ // uses all four lines for data.
+ bool supports_qspi_writes: 1;
+
+ // Requires a separate command 0x31 to write to the second byte of the status register.
+ // Otherwise two byte are written via 0x01.
+ bool write_status_register_split: 1;
+
+ // True when the status register is a single byte. This implies the Quad Enable bit is in the
+ // first byte and the Read Status Register 2 command (0x35) is unsupported.
+ bool single_status_byte: 1;
+} external_flash_device;
+
+// Settings for the Adesto Tech AT25DF081A 1MiB SPI flash. Its on the SAMD21
+// Xplained board.
+// Datasheet: https://www.adestotech.com/wp-content/uploads/doc8715.pdf
+#define AT25DF081A {\
+ .total_size = (1 << 20), /* 1 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x1f, \
+ .memory_type = 0x45, \
+ .capacity = 0x01, \
+ .max_clock_speed_mhz = 85, \
+ .quad_enable_bit_mask = 0x00, \
+ .has_sector_protection = true, \
+ .supports_fast_read = true, \
+ .supports_qspi = false, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Gigadevice GD25Q16C 2MiB SPI flash.
+// Datasheet: http://www.gigadevice.com/datasheet/gd25q16c/
+#define GD25Q16C {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc8, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 104, /* if we need 120 then we can turn on high performance mode */ \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Gigadevice GD25Q64C 8MiB SPI flash.
+// Datasheet: http://www.elm-tech.com/en/products/spi-flash-memory/gd25q64/gd25q64.pdf
+#define GD25Q64C {\
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc8, \
+ .memory_type = 0x40, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 104, /* if we need 120 then we can turn on high performance mode */ \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = true, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL064L 8MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/316661/download
+#define S25FL064L {\
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 300, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x60, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 108, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL116K 2MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/196886/download
+#define S25FL116K {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 108, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL216K 2MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/197346/download
+#define S25FL216K {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 65, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = false, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16FW 2MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q16fw%20revj%2005182017%20sfdp.pdf
+#define W25Q16FW {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16JV-IQ 2MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q16jv%20spi%20revf%2005092017.pdf
+#define W25Q16JV_IQ {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16JV-IM 2MiB SPI flash. Note that JV-IQ has a different .memory_type (0x40)
+// Datasheet: https://www.winbond.com/resource-files/w25q16jv%20spi%20revf%2005092017.pdf
+#define W25Q16JV_IM {\
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .has_quad_enable = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q32BV 4MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf
+#define W25Q32BV {\
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 104, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+// Settings for the Winbond W25Q32JV-IM 4MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q32jv%20revg%2003272018%20plus.pdf
+#define W25Q32JV_IM {\
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 133, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .has_quad_enable = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q64JV-IM 8MiB SPI flash. Note that JV-IQ has a different .memory_type (0x40)
+// Datasheet: http://www.winbond.com/resource-files/w25q64jv%20revj%2003272018%20plus.pdf
+#define W25Q64JV_IM {\
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .has_quad_enable = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q64JV-IQ 8MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: http://www.winbond.com/resource-files/w25q64jv%20revj%2003272018%20plus.pdf
+#define W25Q64JV_IQ {\
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q80DL 1MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q80dv%20dl_revh_10022015.pdf
+#define W25Q80DL {\
+ .total_size = (1 << 20), /* 1 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x14, \
+ .max_clock_speed_mhz = 104, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+
+// Settings for the Winbond W25Q128JV-SQ 16MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
+#define W25Q128JV_SQ {\
+ .total_size = (1 << 24), /* 16 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x18, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Macronix MX25R6435F 8MiB SPI flash.
+// Datasheet: http://www.macronix.com/Lists/Datasheet/Attachments/7428/MX25R6435F,%20Wide%20Range,%2064Mb,%20v1.4.pdf
+// By default its in lower power mode which can only do 8mhz. In high power mode it can do 80mhz.
+#define MX25R6435F {\
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc2, \
+ .memory_type = 0x28, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 8, \
+ .quad_enable_bit_mask = 0x40, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+}
+
+// Settings for the Winbond W25Q128JV-PM 16MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
+#define W25Q128JV_PM {\
+ .total_size = (1 << 24), /* 16 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x18, \
+ .max_clock_speed_mhz = 133, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .has_quad_enable = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
diff --git a/supervisor/shared/external_flash/external_flash.c b/supervisor/shared/external_flash/external_flash.c
new file mode 100644
index 000000000..73b7f7f91
--- /dev/null
+++ b/supervisor/shared/external_flash/external_flash.c
@@ -0,0 +1,546 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "external_flash.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "supervisor/spi_flash_api.h"
+#include "supervisor/shared/external_flash/common_commands.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "py/misc.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "lib/oofatfs/ff.h"
+#include "shared-bindings/microcontroller/__init__.h"
+#include "supervisor/memory.h"
+#include "supervisor/shared/rgb_led_status.h"
+
+#define NO_SECTOR_LOADED 0xFFFFFFFF
+
+// The currently cached sector in the cache, ram or flash based.
+static uint32_t current_sector;
+
+const external_flash_device possible_devices[EXTERNAL_FLASH_DEVICE_COUNT] = {EXTERNAL_FLASH_DEVICES};
+
+static const external_flash_device* flash_device = NULL;
+
+// Track which blocks (up to 32) in the current sector currently live in the
+// cache.
+static uint32_t dirty_mask;
+
+static supervisor_allocation* supervisor_cache = NULL;
+
+// Wait until both the write enable and write in progress bits have cleared.
+static bool wait_for_flash_ready(void) {
+ uint8_t read_status_response[1] = {0x00};
+ bool ok = true;
+ // Both the write enable and write in progress bits should be low.
+ do {
+ ok = spi_flash_read_command(CMD_READ_STATUS, read_status_response, 1);
+ } while (ok && (read_status_response[0] & 0x3) != 0);
+ return ok;
+}
+
+// Turn on the write enable bit so we can program and erase the flash.
+static bool write_enable(void) {
+ return spi_flash_command(CMD_ENABLE_WRITE);
+}
+
+// Read data_length's worth of bytes starting at address into data.
+static bool read_flash(uint32_t address, uint8_t* data, uint32_t data_length) {
+ if (flash_device == NULL) {
+ return false;
+ }
+ if (!wait_for_flash_ready()) {
+ return false;
+ }
+ return spi_flash_read_data(address, data, data_length);
+}
+
+// Writes data_length's worth of bytes starting at address from data. Assumes
+// that the sector that address resides in has already been erased. So make sure
+// to run erase_sector.
+static bool write_flash(uint32_t address, const uint8_t* data, uint32_t data_length) {
+ if (flash_device == NULL) {
+ return false;
+ }
+ // Don't bother writing if the data is all 1s. Thats equivalent to the flash
+ // state after an erase.
+ bool all_ones = true;
+ for (uint16_t i = 0; i < data_length; i++) {
+ if (data[i] != 0xff) {
+ all_ones = false;
+ break;
+ }
+ }
+ if (all_ones) {
+ return true;
+ }
+
+ for (uint32_t bytes_written = 0;
+ bytes_written < data_length;
+ bytes_written += SPI_FLASH_PAGE_SIZE) {
+ if (!wait_for_flash_ready() || !write_enable()) {
+ return false;
+ }
+
+ if (!spi_flash_write_data(address + bytes_written, (uint8_t*) data + bytes_written,
+ SPI_FLASH_PAGE_SIZE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool page_erased(uint32_t sector_address) {
+ // Check the first few bytes to catch the common case where there is data
+ // without using a bunch of memory.
+ uint8_t short_buffer[4];
+ if (read_flash(sector_address, short_buffer, 4)) {
+ for (uint16_t i = 0; i < 4; i++) {
+ if (short_buffer[i] != 0xff) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ // Now check the full length.
+ uint8_t full_buffer[FILESYSTEM_BLOCK_SIZE];
+ if (read_flash(sector_address, full_buffer, FILESYSTEM_BLOCK_SIZE)) {
+ for (uint16_t i = 0; i < FILESYSTEM_BLOCK_SIZE; i++) {
+ if (short_buffer[i] != 0xff) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+// Erases the given sector. Make sure you copied all of the data out of it you
+// need! Also note, sector_address is really 24 bits.
+static bool erase_sector(uint32_t sector_address) {
+ // Before we erase the sector we need to wait for any writes to finish and
+ // and then enable the write again.
+ if (!wait_for_flash_ready() || !write_enable()) {
+ return false;
+ }
+
+ spi_flash_sector_command(CMD_SECTOR_ERASE, sector_address);
+ return true;
+}
+
+// Sector is really 24 bits.
+static bool copy_block(uint32_t src_address, uint32_t dest_address) {
+ // Copy page by page to minimize RAM buffer.
+ uint16_t page_size = SPI_FLASH_PAGE_SIZE;
+ uint8_t buffer[page_size];
+ for (uint32_t i = 0; i < FILESYSTEM_BLOCK_SIZE / page_size; i++) {
+ if (!read_flash(src_address + i * page_size, buffer, page_size)) {
+ return false;
+ }
+ if (!write_flash(dest_address + i * page_size, buffer, page_size)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void supervisor_flash_init(void) {
+ if (flash_device != NULL) {
+ return;
+ }
+
+ // Delay to give the SPI Flash time to get going.
+ // TODO(tannewt): Only do this when we know power was applied vs a reset.
+ uint16_t max_start_up_delay_us = 0;
+ for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
+ if (possible_devices[i].start_up_time_us > max_start_up_delay_us) {
+ max_start_up_delay_us = possible_devices[i].start_up_time_us;
+ }
+ }
+ common_hal_mcu_delay_us(max_start_up_delay_us);
+
+ spi_flash_init();
+
+ // The response will be 0xff if the flash needs more time to start up.
+ uint8_t jedec_id_response[3] = {0xff, 0xff, 0xff};
+ while (jedec_id_response[0] == 0xff) {
+ spi_flash_read_command(CMD_READ_JEDEC_ID, jedec_id_response, 3);
+ }
+
+ for (uint8_t i = 0; i < EXTERNAL_FLASH_DEVICE_COUNT; i++) {
+ const external_flash_device* possible_device = &possible_devices[i];
+ if (jedec_id_response[0] == possible_device->manufacturer_id &&
+ jedec_id_response[1] == possible_device->memory_type &&
+ jedec_id_response[2] == possible_device->capacity) {
+ flash_device = possible_device;
+ break;
+ }
+ }
+
+ if (flash_device == NULL) {
+ return;
+ }
+
+ // We don't know what state the flash is in so wait for any remaining writes and then reset.
+ uint8_t read_status_response[1] = {0x00};
+ // The write in progress bit should be low.
+ do {
+ spi_flash_read_command(CMD_READ_STATUS, read_status_response, 1);
+ } while ((read_status_response[0] & 0x1) != 0);
+ // The suspended write/erase bit should be low.
+ do {
+ spi_flash_read_command(CMD_READ_STATUS2, read_status_response, 1);
+ } while ((read_status_response[0] & 0x80) != 0);
+
+
+ spi_flash_command(CMD_ENABLE_RESET);
+ spi_flash_command(CMD_RESET);
+
+ // Wait 30us for the reset
+ common_hal_mcu_delay_us(30);
+
+ spi_flash_init_device(flash_device);
+
+ // Activity LED for flash writes.
+#ifdef MICROPY_HW_LED_MSC
+ gpio_set_pin_function(SPI_FLASH_CS_PIN, GPIO_PIN_FUNCTION_OFF);
+ gpio_set_pin_direction(MICROPY_HW_LED_MSC, GPIO_DIRECTION_OUT);
+ // There's already a pull-up on the board.
+ gpio_set_pin_level(MICROPY_HW_LED_MSC, false);
+#endif
+
+ if (flash_device->has_sector_protection) {
+ write_enable();
+
+ // Turn off sector protection
+ uint8_t data[1] = {0x00};
+ spi_flash_write_command(CMD_WRITE_STATUS_BYTE1, data, 1);
+ }
+
+ // Turn off writes in case this is a microcontroller only reset.
+ spi_flash_command(CMD_DISABLE_WRITE);
+
+ wait_for_flash_ready();
+
+ current_sector = NO_SECTOR_LOADED;
+ dirty_mask = 0;
+ MP_STATE_VM(flash_ram_cache) = NULL;
+}
+
+// The size of each individual block.
+uint32_t supervisor_flash_get_block_size(void) {
+ return FILESYSTEM_BLOCK_SIZE;
+}
+
+// The total number of available blocks.
+uint32_t supervisor_flash_get_block_count(void) {
+ // We subtract one erase sector size because we may use it as a staging area
+ // for writes.
+ return (flash_device->total_size - SPI_FLASH_ERASE_SIZE) / FILESYSTEM_BLOCK_SIZE;
+}
+
+// Flush the cache that was written to the scratch portion of flash. Only used
+// when ram is tight.
+static bool flush_scratch_flash(void) {
+ // First, copy out any blocks that we haven't touched from the sector we've
+ // cached.
+ bool copy_to_scratch_ok = true;
+ uint32_t scratch_sector = flash_device->total_size - SPI_FLASH_ERASE_SIZE;
+ for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
+ if ((dirty_mask & (1 << i)) == 0) {
+ copy_to_scratch_ok = copy_to_scratch_ok &&
+ copy_block(current_sector + i * FILESYSTEM_BLOCK_SIZE,
+ scratch_sector + i * FILESYSTEM_BLOCK_SIZE);
+ }
+ }
+ if (!copy_to_scratch_ok) {
+ // TODO(tannewt): Do more here. We opted to not erase and copy bad data
+ // in. We still risk losing the data written to the scratch sector.
+ return false;
+ }
+ // Second, erase the current sector.
+ erase_sector(current_sector);
+ // Finally, copy the new version into it.
+ for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
+ copy_block(scratch_sector + i * FILESYSTEM_BLOCK_SIZE,
+ current_sector + i * FILESYSTEM_BLOCK_SIZE);
+ }
+ return true;
+}
+
+// Attempts to allocate a new set of page buffers for caching a full sector in
+// ram. Each page is allocated separately so that the GC doesn't need to provide
+// one huge block. We can free it as we write if we want to also.
+static bool allocate_ram_cache(void) {
+ uint8_t blocks_per_sector = SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE;
+ uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
+
+ uint32_t table_size = blocks_per_sector * pages_per_block * sizeof(uint32_t);
+ // Attempt to allocate outside the heap first.
+ supervisor_cache = allocate_memory(table_size + SPI_FLASH_ERASE_SIZE, false);
+ if (supervisor_cache != NULL) {
+ MP_STATE_VM(flash_ram_cache) = (uint8_t **) supervisor_cache->ptr;
+ uint8_t* page_start = (uint8_t *) supervisor_cache->ptr + table_size;
+
+ for (uint8_t i = 0; i < blocks_per_sector; i++) {
+ for (uint8_t j = 0; j < pages_per_block; j++) {
+ uint32_t offset = i * pages_per_block + j;
+ MP_STATE_VM(flash_ram_cache)[offset] = page_start + offset * SPI_FLASH_PAGE_SIZE;
+ }
+ }
+ return true;
+ }
+
+ MP_STATE_VM(flash_ram_cache) = m_malloc_maybe(blocks_per_sector * pages_per_block * sizeof(uint32_t), false);
+ if (MP_STATE_VM(flash_ram_cache) == NULL) {
+ return false;
+ }
+ // Declare i and j outside the loops in case we fail to allocate everything
+ // we need. In that case we'll give it back.
+ uint8_t i = 0;
+ uint8_t j = 0;
+ bool success = true;
+ for (i = 0; i < blocks_per_sector; i++) {
+ for (j = 0; j < pages_per_block; j++) {
+ uint8_t *page_cache = m_malloc_maybe(SPI_FLASH_PAGE_SIZE, false);
+ if (page_cache == NULL) {
+ success = false;
+ break;
+ }
+ MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j] = page_cache;
+ }
+ if (!success) {
+ break;
+ }
+ }
+ // We couldn't allocate enough so give back what we got.
+ if (!success) {
+ // We add 1 so that we delete 0 when i is 1. Going to zero (i >= 0)
+ // would never stop because i is unsigned.
+ i++;
+ for (; i > 0; i--) {
+ for (; j > 0; j--) {
+ m_free(MP_STATE_VM(flash_ram_cache)[(i - 1) * pages_per_block + (j - 1)]);
+ }
+ j = pages_per_block;
+ }
+ m_free(MP_STATE_VM(flash_ram_cache));
+ MP_STATE_VM(flash_ram_cache) = NULL;
+ }
+ return success;
+}
+
+// Flush the cached sector from ram onto the flash. We'll free the cache unless
+// keep_cache is true.
+static bool flush_ram_cache(bool keep_cache) {
+ // First, copy out any blocks that we haven't touched from the sector
+ // we've cached. If we don't do this we'll erase the data during the sector
+ // erase below.
+ bool copy_to_ram_ok = true;
+ uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
+ for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
+ if ((dirty_mask & (1 << i)) == 0) {
+ for (uint8_t j = 0; j < pages_per_block; j++) {
+ copy_to_ram_ok = read_flash(
+ current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
+ MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j],
+ SPI_FLASH_PAGE_SIZE);
+ if (!copy_to_ram_ok) {
+ break;
+ }
+ }
+ }
+ if (!copy_to_ram_ok) {
+ break;
+ }
+ }
+
+ if (!copy_to_ram_ok) {
+ return false;
+ }
+ // Second, erase the current sector.
+ erase_sector(current_sector);
+ // Lastly, write all the data in ram that we've cached.
+ for (uint8_t i = 0; i < SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE; i++) {
+ for (uint8_t j = 0; j < pages_per_block; j++) {
+ write_flash(current_sector + (i * pages_per_block + j) * SPI_FLASH_PAGE_SIZE,
+ MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j],
+ SPI_FLASH_PAGE_SIZE);
+ if (!keep_cache && supervisor_cache == NULL) {
+ m_free(MP_STATE_VM(flash_ram_cache)[i * pages_per_block + j]);
+ }
+ }
+ }
+ // We're done with the cache for now so give it back.
+ if (!keep_cache) {
+ if (supervisor_cache != NULL) {
+ free_memory(supervisor_cache);
+ supervisor_cache = NULL;
+ } else {
+ m_free(MP_STATE_VM(flash_ram_cache));
+ }
+ MP_STATE_VM(flash_ram_cache) = NULL;
+ }
+ return true;
+}
+
+// Delegates to the correct flash flush method depending on the existing cache.
+static void spi_flash_flush_keep_cache(bool keep_cache) {
+ if (current_sector == NO_SECTOR_LOADED) {
+ return;
+ }
+ #ifdef MICROPY_HW_LED_MSC
+ port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
+ #endif
+ temp_status_color(ACTIVE_WRITE);
+ // If we've cached to the flash itself flush from there.
+ if (MP_STATE_VM(flash_ram_cache) == NULL) {
+ flush_scratch_flash();
+ } else {
+ flush_ram_cache(keep_cache);
+ }
+ current_sector = NO_SECTOR_LOADED;
+ clear_temp_status();
+ #ifdef MICROPY_HW_LED_MSC
+ port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
+ #endif
+}
+
+// External flash function used. If called externally we assume we won't need
+// the cache after.
+void supervisor_flash_flush(void) {
+ spi_flash_flush_keep_cache(false);
+}
+
+static int32_t convert_block_to_flash_addr(uint32_t block) {
+ if (0 <= block && block < supervisor_flash_get_block_count()) {
+ // a block in partition 1
+ return block * FILESYSTEM_BLOCK_SIZE;
+ }
+ // bad block
+ return -1;
+}
+
+bool external_flash_read_block(uint8_t *dest, uint32_t block) {
+ int32_t address = convert_block_to_flash_addr(block);
+ if (address == -1) {
+ // bad block number
+ return false;
+ }
+
+ // Mask out the lower bits that designate the address within the sector.
+ uint32_t this_sector = address & (~(SPI_FLASH_ERASE_SIZE - 1));
+ uint8_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % (SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE);
+ uint8_t mask = 1 << (block_index);
+ // We're reading from the currently cached sector.
+ if (current_sector == this_sector && (mask & dirty_mask) > 0) {
+ if (MP_STATE_VM(flash_ram_cache) != NULL) {
+ uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
+ for (int i = 0; i < pages_per_block; i++) {
+ memcpy(dest + i * SPI_FLASH_PAGE_SIZE,
+ MP_STATE_VM(flash_ram_cache)[block_index * pages_per_block + i],
+ SPI_FLASH_PAGE_SIZE);
+ }
+ return true;
+ } else {
+ uint32_t scratch_address = flash_device->total_size - SPI_FLASH_ERASE_SIZE + block_index * FILESYSTEM_BLOCK_SIZE;
+ return read_flash(scratch_address, dest, FILESYSTEM_BLOCK_SIZE);
+ }
+ }
+ return read_flash(address, dest, FILESYSTEM_BLOCK_SIZE);
+}
+
+bool external_flash_write_block(const uint8_t *data, uint32_t block) {
+ // Non-MBR block, copy to cache
+ int32_t address = convert_block_to_flash_addr(block);
+ if (address == -1) {
+ // bad block number
+ return false;
+ }
+ // Wait for any previous writes to finish.
+ wait_for_flash_ready();
+ // Mask out the lower bits that designate the address within the sector.
+ uint32_t this_sector = address & (~(SPI_FLASH_ERASE_SIZE - 1));
+ uint8_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % (SPI_FLASH_ERASE_SIZE / FILESYSTEM_BLOCK_SIZE);
+ uint8_t mask = 1 << (block_index);
+ // Flush the cache if we're moving onto a sector or we're writing the
+ // same block again.
+ if (current_sector != this_sector || (mask & dirty_mask) > 0) {
+ // Check to see if we'd write to an erased page. In that case we
+ // can write directly.
+ if (page_erased(address)) {
+ return write_flash(address, data, FILESYSTEM_BLOCK_SIZE);
+ }
+ if (current_sector != NO_SECTOR_LOADED) {
+ spi_flash_flush_keep_cache(true);
+ }
+ if (MP_STATE_VM(flash_ram_cache) == NULL && !allocate_ram_cache()) {
+ erase_sector(flash_device->total_size - SPI_FLASH_ERASE_SIZE);
+ wait_for_flash_ready();
+ }
+ current_sector = this_sector;
+ dirty_mask = 0;
+ }
+ dirty_mask |= mask;
+ // Copy the block to the appropriate cache.
+ if (MP_STATE_VM(flash_ram_cache) != NULL) {
+ uint8_t pages_per_block = FILESYSTEM_BLOCK_SIZE / SPI_FLASH_PAGE_SIZE;
+ for (int i = 0; i < pages_per_block; i++) {
+ memcpy(MP_STATE_VM(flash_ram_cache)[block_index * pages_per_block + i],
+ data + i * SPI_FLASH_PAGE_SIZE,
+ SPI_FLASH_PAGE_SIZE);
+ }
+ return true;
+ } else {
+ uint32_t scratch_address = flash_device->total_size - SPI_FLASH_ERASE_SIZE + block_index * FILESYSTEM_BLOCK_SIZE;
+ return write_flash(scratch_address, data, FILESYSTEM_BLOCK_SIZE);
+ }
+}
+
+mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!external_flash_read_block(dest + i * FILESYSTEM_BLOCK_SIZE, block_num + i)) {
+ return 1; // error
+ }
+ }
+ return 0; // success
+}
+
+mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!external_flash_write_block(src + i * FILESYSTEM_BLOCK_SIZE, block_num + i)) {
+ return 1; // error
+ }
+ }
+ return 0; // success
+}
diff --git a/supervisor/shared/external_flash/external_flash.h b/supervisor/shared/external_flash/external_flash.h
new file mode 100644
index 000000000..72b619a2a
--- /dev/null
+++ b/supervisor/shared/external_flash/external_flash.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_H
+#define MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "py/mpconfig.h"
+
+// Erase sector size.
+#define SPI_FLASH_SECTOR_SIZE (0x1000 - 100)
+
+// These are common across all NOR Flash.
+#define SPI_FLASH_ERASE_SIZE (1 << 12)
+#define SPI_FLASH_PAGE_SIZE (256)
+
+#define SPI_FLASH_SYSTICK_MASK (0x1ff) // 512ms
+#define SPI_FLASH_IDLE_TICK(tick) (((tick) & SPI_FLASH_SYSTICK_MASK) == 2)
+
+#ifndef SPI_FLASH_MAX_BAUDRATE
+#define SPI_FLASH_MAX_BAUDRATE 8000000
+#endif
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_H
diff --git a/supervisor/shared/external_flash/external_flash_root_pointers.h b/supervisor/shared/external_flash/external_flash_root_pointers.h
new file mode 100644
index 000000000..cb1b86d19
--- /dev/null
+++ b/supervisor/shared/external_flash/external_flash_root_pointers.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_ROOT_POINTERS_H
+#define MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_ROOT_POINTERS_H
+
+#include <stdint.h>
+
+// We use this when we can allocate the whole cache in RAM.
+#define FLASH_ROOT_POINTERS \
+ uint8_t** flash_ram_cache; \
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_EXTERNAL_FLASH_ROOT_POINTERS_H
diff --git a/supervisor/shared/external_flash/qspi_flash.c b/supervisor/shared/external_flash/qspi_flash.c
new file mode 100644
index 000000000..48266540c
--- /dev/null
+++ b/supervisor/shared/external_flash/qspi_flash.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017, 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/spi_flash_api.h"
+
+#include "supervisor/shared/external_flash/common_commands.h"
+
+void check_quad_enable(const external_flash_device* device) {
+ if (device->quad_enable_bit_mask == 0x00) {
+ return;
+ }
+
+ // Verify that QSPI mode is enabled.
+ uint8_t status;
+ if (device->single_status_byte) {
+ spi_flash_read_command(CMD_READ_STATUS, &status, 1);
+ } else {
+ spi_flash_read_command(CMD_READ_STATUS2, &status, 1);
+ }
+
+ // Check the quad enable bit.
+ if ((status & device->quad_enable_bit_mask) == 0) {
+ uint8_t full_status[2] = {0x00, device->quad_enable_bit_mask};
+ spi_flash_command(CMD_ENABLE_WRITE);
+ if (device->write_status_register_split) {
+ spi_flash_write_command(CMD_WRITE_STATUS_BYTE2, full_status + 1, 1);
+ } else if (device->single_status_byte) {
+ spi_flash_write_command(CMD_WRITE_STATUS_BYTE1, full_status + 1, 1);
+ } else {
+ spi_flash_write_command(CMD_WRITE_STATUS_BYTE1, full_status, 2);
+ }
+ }
+}
diff --git a/supervisor/shared/external_flash/qspi_flash.h b/supervisor/shared/external_flash/qspi_flash.h
new file mode 100644
index 000000000..b72e37b26
--- /dev/null
+++ b/supervisor/shared/external_flash/qspi_flash.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_QSPI_FLASH_H
+#define MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_QSPI_FLASH_H
+
+void check_quad_enable(const external_flash_device* device);
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_EXTERNAL_FLASH_QSPI_FLASH_H
diff --git a/supervisor/shared/external_flash/spi_flash.c b/supervisor/shared/external_flash/spi_flash.c
new file mode 100644
index 000000000..ec7101bc9
--- /dev/null
+++ b/supervisor/shared/external_flash/spi_flash.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "supervisor/spi_flash_api.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "supervisor/shared/external_flash/common_commands.h"
+#include "supervisor/shared/external_flash/external_flash.h"
+#include "py/mpconfig.h"
+
+digitalio_digitalinout_obj_t cs_pin;
+busio_spi_obj_t spi;
+
+const external_flash_device* flash_device;
+uint32_t spi_flash_baudrate;
+
+// Enable the flash over SPI.
+static void flash_enable(void) {
+ while (!common_hal_busio_spi_try_lock(&spi)) {}
+ common_hal_digitalio_digitalinout_set_value(&cs_pin, false);
+}
+
+// Disable the flash over SPI.
+static void flash_disable(void) {
+ common_hal_digitalio_digitalinout_set_value(&cs_pin, true);
+ common_hal_busio_spi_unlock(&spi);
+}
+
+static bool transfer(uint8_t* command, uint32_t command_length, uint8_t* data_in, uint8_t* data_out, uint32_t data_length) {
+ flash_enable();
+ bool status = common_hal_busio_spi_write(&spi, command, command_length);
+ if (status) {
+ if (data_in != NULL && data_out != NULL) {
+ status = common_hal_busio_spi_transfer(&spi, data_out, data_in, data_length);
+ } else if (data_out != NULL) {
+ status = common_hal_busio_spi_read(&spi, data_out, data_length, 0xff);
+ } else if (data_in != NULL) {
+ status = common_hal_busio_spi_write(&spi, data_in, data_length);
+ }
+ }
+ flash_disable();
+ return status;
+}
+
+static bool transfer_command(uint8_t command, uint8_t* data_in, uint8_t* data_out, uint32_t data_length) {
+ return transfer(&command, 1, data_in, data_out, data_length);
+}
+
+bool spi_flash_command(uint8_t command) {
+ return transfer_command(command, NULL, NULL, 0);
+}
+
+bool spi_flash_read_command(uint8_t command, uint8_t* data, uint32_t data_length) {
+ return transfer_command(command, NULL, data, data_length);
+}
+
+bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t data_length) {
+ return transfer_command(command, data, NULL, data_length);
+}
+
+// Pack the low 24 bits of the address into a uint8_t array.
+static void address_to_bytes(uint32_t address, uint8_t* bytes) {
+ bytes[0] = (address >> 16) & 0xff;
+ bytes[1] = (address >> 8) & 0xff;
+ bytes[2] = address & 0xff;
+}
+
+bool spi_flash_sector_command(uint8_t command, uint32_t address) {
+ uint8_t request[4] = {command, 0x00, 0x00, 0x00};
+ address_to_bytes(address, request + 1);
+ return transfer(request, 4, NULL, NULL, 0);
+}
+
+bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t data_length) {
+ uint8_t request[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
+ // Write the SPI flash write address into the bytes following the command byte.
+ address_to_bytes(address, request + 1);
+ flash_enable();
+ common_hal_busio_spi_configure(&spi, spi_flash_baudrate, 0, 0, 8);
+ bool status = common_hal_busio_spi_write(&spi, request, 4);
+ if (status) {
+ status = common_hal_busio_spi_write(&spi, data, data_length);
+ }
+ flash_disable();
+ return status;
+}
+
+bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t data_length) {
+ uint8_t request[5] = {CMD_READ_DATA, 0x00, 0x00, 0x00};
+ uint8_t command_length = 4;
+ if (flash_device->supports_fast_read) {
+ request[0] = CMD_FAST_READ_DATA;
+ command_length = 5;
+ }
+ // Write the SPI flash write address into the bytes following the command byte.
+ address_to_bytes(address, request + 1);
+ flash_enable();
+ common_hal_busio_spi_configure(&spi, spi_flash_baudrate, 0, 0, 8);
+ bool status = common_hal_busio_spi_write(&spi, request, command_length);
+ if (status) {
+ status = common_hal_busio_spi_read(&spi, data, data_length, 0xff);
+ }
+ flash_disable();
+ return status;
+}
+
+void spi_flash_init(void) {
+ common_hal_digitalio_digitalinout_construct(&cs_pin, SPI_FLASH_CS_PIN);
+
+ // Set CS high (disabled).
+ common_hal_digitalio_digitalinout_switch_to_output(&cs_pin, true, DRIVE_MODE_PUSH_PULL);
+
+ common_hal_busio_spi_construct(&spi, SPI_FLASH_SCK_PIN, SPI_FLASH_MOSI_PIN, SPI_FLASH_MISO_PIN);
+ common_hal_busio_spi_never_reset(&spi);
+}
+
+void spi_flash_init_device(const external_flash_device* device) {
+ flash_device = device;
+ spi_flash_baudrate = device->max_clock_speed_mhz * 1000000;
+ if (spi_flash_baudrate > SPI_FLASH_MAX_BAUDRATE) {
+ spi_flash_baudrate = SPI_FLASH_MAX_BAUDRATE;
+ }
+}
diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c
new file mode 100644
index 000000000..d968f4798
--- /dev/null
+++ b/supervisor/shared/filesystem.c
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "extmod/vfs_fat.h"
+#include "lib/oofatfs/ff.h"
+#include "lib/oofatfs/diskio.h"
+
+#include "py/mpstate.h"
+
+#include "supervisor/flash.h"
+
+static mp_vfs_mount_t _mp_vfs;
+static fs_user_mount_t _internal_vfs;
+
+static void make_empty_file(FATFS *fatfs, const char *path) {
+ FIL fp;
+ f_open(fatfs, &fp, path, FA_WRITE | FA_CREATE_ALWAYS);
+ f_close(&fp);
+}
+
+// we don't make this function static because it needs a lot of stack and we
+// want it to be executed without using stack within main() function
+void filesystem_init(bool create_allowed, bool force_create) {
+ // init the vfs object
+ fs_user_mount_t *vfs_fat = &_internal_vfs;
+ vfs_fat->flags = 0;
+ supervisor_flash_init_vfs(vfs_fat);
+
+ // try to mount the flash
+ FRESULT res = f_mount(&vfs_fat->fatfs);
+
+ if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) {
+ // No filesystem so create a fresh one, or reformat has been requested.
+ uint8_t working_buf[_MAX_SS];
+ res = f_mkfs(&vfs_fat->fatfs, FM_FAT, 0, working_buf, sizeof(working_buf));
+ // Flush the new file system to make sure it's repaired immediately.
+ supervisor_flash_flush();
+ if (res != FR_OK) {
+ return;
+ }
+
+ // set label
+ f_setlabel(&vfs_fat->fatfs, "CIRCUITPY");
+
+ // inhibit file indexing on MacOS
+ f_mkdir(&vfs_fat->fatfs, "/.fseventsd");
+ make_empty_file(&vfs_fat->fatfs, "/.metadata_never_index");
+ make_empty_file(&vfs_fat->fatfs, "/.Trashes");
+ make_empty_file(&vfs_fat->fatfs, "/.fseventsd/no_log");
+
+ // and ensure everything is flushed
+ supervisor_flash_flush();
+ } else if (res != FR_OK) {
+ return;
+ }
+ mp_vfs_mount_t *vfs = &_mp_vfs;
+ vfs->str = "/";
+ vfs->len = 1;
+ vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
+ vfs->next = NULL;
+ MP_STATE_VM(vfs_mount_table) = vfs;
+
+ // The current directory is used as the boot up directory.
+ // It is set to the internal flash filesystem by default.
+ MP_STATE_PORT(vfs_cur) = vfs;
+}
+
+void filesystem_flush(void) {
+ supervisor_flash_flush();
+}
+
+void filesystem_writable_by_python(bool writable) {
+ fs_user_mount_t *vfs = &_internal_vfs;
+
+ if (writable) {
+ vfs->flags |= FSUSER_USB_WRITABLE;
+ } else {
+ vfs->flags &= ~FSUSER_USB_WRITABLE;
+ }
+}
+
+bool filesystem_present(void) {
+ return true;
+}
diff --git a/supervisor/shared/flash.c b/supervisor/shared/flash.c
new file mode 100644
index 000000000..c8921aa85
--- /dev/null
+++ b/supervisor/shared/flash.c
@@ -0,0 +1,202 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "supervisor/flash.h"
+
+#include "extmod/vfs_fat.h"
+#include "py/runtime.h"
+#include "lib/oofatfs/ff.h"
+
+#define VFS_INDEX 0
+
+#define PART1_START_BLOCK (0x1)
+
+void supervisor_flash_set_usb_writable(bool usb_writable) {
+ mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
+ for (uint8_t i = 0; current_mount != NULL; i++) {
+ if (i == VFS_INDEX) {
+ break;
+ }
+ current_mount = current_mount->next;
+ }
+ if (current_mount == NULL) {
+ return;
+ }
+ fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj;
+
+ if (usb_writable) {
+ vfs->flags |= FSUSER_USB_WRITABLE;
+ } else {
+ vfs->flags &= ~FSUSER_USB_WRITABLE;
+ }
+}
+
+// there is a singleton Flash object
+const mp_obj_type_t supervisor_flash_type;
+STATIC const mp_obj_base_t supervisor_flash_obj = {&supervisor_flash_type};
+
+STATIC mp_obj_t supervisor_flash_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ // return singleton object
+ return (mp_obj_t)&supervisor_flash_obj;
+}
+
+uint32_t flash_get_block_count(void) {
+ return PART1_START_BLOCK + supervisor_flash_get_block_count();
+}
+
+static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
+ buf[0] = boot;
+
+ if (num_blocks == 0) {
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ } else {
+ buf[1] = 0xff;
+ buf[2] = 0xff;
+ buf[3] = 0xff;
+ }
+
+ buf[4] = type;
+
+ if (num_blocks == 0) {
+ buf[5] = 0;
+ buf[6] = 0;
+ buf[7] = 0;
+ } else {
+ buf[5] = 0xff;
+ buf[6] = 0xff;
+ buf[7] = 0xff;
+ }
+
+ buf[8] = start_block;
+ buf[9] = start_block >> 8;
+ buf[10] = start_block >> 16;
+ buf[11] = start_block >> 24;
+
+ buf[12] = num_blocks;
+ buf[13] = num_blocks >> 8;
+ buf[14] = num_blocks >> 16;
+ buf[15] = num_blocks >> 24;
+}
+
+mp_uint_t flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
+ if (block_num == 0) {
+ if (block_num > 1) {
+ return 1; // error
+ }
+ // fake the MBR so we can decide on our own partition table
+
+ for (int i = 0; i < 446; i++) {
+ dest[i] = 0;
+ }
+
+ build_partition(dest + 446, 0, 0x01 /* FAT12 */, PART1_START_BLOCK, supervisor_flash_get_block_count());
+ build_partition(dest + 462, 0, 0, 0, 0);
+ build_partition(dest + 478, 0, 0, 0, 0);
+ build_partition(dest + 494, 0, 0, 0, 0);
+
+ dest[510] = 0x55;
+ dest[511] = 0xaa;
+
+ return 0; // ok
+
+ }
+ return supervisor_flash_read_blocks(dest, block_num - PART1_START_BLOCK, num_blocks);
+}
+
+mp_uint_t flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
+ if (block_num == 0) {
+ if (num_blocks > 1) {
+ return 1; // error
+ }
+ // can't write MBR, but pretend we did
+ return 0;
+ } else {
+ return supervisor_flash_write_blocks(src, block_num - PART1_START_BLOCK, num_blocks);
+ }
+}
+
+STATIC mp_obj_t supervisor_flash_obj_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
+ mp_uint_t ret = flash_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FILESYSTEM_BLOCK_SIZE);
+ return MP_OBJ_NEW_SMALL_INT(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(supervisor_flash_obj_readblocks_obj, supervisor_flash_obj_readblocks);
+
+STATIC mp_obj_t supervisor_flash_obj_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ mp_uint_t ret = flash_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / FILESYSTEM_BLOCK_SIZE);
+ return MP_OBJ_NEW_SMALL_INT(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(supervisor_flash_obj_writeblocks_obj, supervisor_flash_obj_writeblocks);
+
+STATIC mp_obj_t supervisor_flash_obj_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
+ mp_int_t cmd = mp_obj_get_int(cmd_in);
+ switch (cmd) {
+ case BP_IOCTL_INIT: supervisor_flash_init(); return MP_OBJ_NEW_SMALL_INT(0);
+ case BP_IOCTL_DEINIT: supervisor_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
+ case BP_IOCTL_SYNC: supervisor_flash_flush(); return MP_OBJ_NEW_SMALL_INT(0);
+ case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(flash_get_block_count());
+ case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(supervisor_flash_get_block_size());
+ default: return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(supervisor_flash_obj_ioctl_obj, supervisor_flash_obj_ioctl);
+
+STATIC const mp_rom_map_elem_t supervisor_flash_obj_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&supervisor_flash_obj_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&supervisor_flash_obj_writeblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&supervisor_flash_obj_ioctl_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(supervisor_flash_obj_locals_dict, supervisor_flash_obj_locals_dict_table);
+
+const mp_obj_type_t supervisor_flash_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Flash,
+ .make_new = supervisor_flash_obj_make_new,
+ .locals_dict = (mp_obj_t)&supervisor_flash_obj_locals_dict,
+};
+
+void supervisor_flash_init_vfs(fs_user_mount_t *vfs) {
+ vfs->base.type = &mp_fat_vfs_type;
+ vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
+ vfs->fatfs.drv = vfs;
+ vfs->fatfs.part = 1; // flash filesystem lives on first partition
+ vfs->readblocks[0] = (mp_obj_t)&supervisor_flash_obj_readblocks_obj;
+ vfs->readblocks[1] = (mp_obj_t)&supervisor_flash_obj;
+ vfs->readblocks[2] = (mp_obj_t)flash_read_blocks; // native version
+ vfs->writeblocks[0] = (mp_obj_t)&supervisor_flash_obj_writeblocks_obj;
+ vfs->writeblocks[1] = (mp_obj_t)&supervisor_flash_obj;
+ vfs->writeblocks[2] = (mp_obj_t)flash_write_blocks; // native version
+ vfs->u.ioctl[0] = (mp_obj_t)&supervisor_flash_obj_ioctl_obj;
+ vfs->u.ioctl[1] = (mp_obj_t)&supervisor_flash_obj;
+}
diff --git a/supervisor/shared/micropython.c b/supervisor/shared/micropython.c
new file mode 100644
index 000000000..245db11d4
--- /dev/null
+++ b/supervisor/shared/micropython.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "supervisor/serial.h"
+#include "lib/oofatfs/ff.h"
+#include "py/mpconfig.h"
+
+#include "supervisor/shared/status_leds.h"
+
+int mp_hal_stdin_rx_chr(void) {
+ for (;;) {
+ #ifdef MICROPY_VM_HOOK_LOOP
+ MICROPY_VM_HOOK_LOOP
+ #endif
+ if (serial_bytes_available()) {
+ toggle_rx_led();
+ return serial_read();
+ }
+ }
+}
+
+void mp_hal_stdout_tx_strn(const char *str, size_t len) {
+ toggle_tx_led();
+
+ #ifdef CIRCUITPY_BOOT_OUTPUT_FILE
+ if (boot_output_file != NULL) {
+ UINT bytes_written = 0;
+ f_write(boot_output_file, str, len, &bytes_written);
+ }
+ #endif
+
+ serial_write_substring(str, len);
+}
diff --git a/supervisor/shared/rgb_led_status.h b/supervisor/shared/rgb_led_status.h
index 24e071aac..9542b3197 100644
--- a/supervisor/shared/rgb_led_status.h
+++ b/supervisor/shared/rgb_led_status.h
@@ -33,7 +33,7 @@
#include "lib/utils/pyexec.h"
#include "supervisor/port.h"
-#include "mpconfigport.h"
+#include "py/mpconfig.h"
#include "rgb_led_colors.h"
// Overall, the time module must be implemented.
diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c
new file mode 100644
index 000000000..c57688ddc
--- /dev/null
+++ b/supervisor/shared/serial.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "supervisor/serial.h"
+#include "supervisor/usb.h"
+
+#include "tusb.h"
+
+void serial_init(void) {
+ usb_init();
+}
+
+bool serial_connected(void) {
+ return tud_cdc_connected();
+}
+
+char serial_read(void) {
+ return (char) tud_cdc_read_char();
+}
+
+bool serial_bytes_available(void) {
+ return tud_cdc_available() > 0;
+}
+
+void serial_write_substring(const char* text, uint32_t length) {
+ if (!tud_cdc_connected()) {
+ return;
+ }
+ uint32_t count = 0;
+ while (count < length) {
+ count += tud_cdc_write(text + count, length - count);
+ usb_background();
+ }
+}
+
+void serial_write(const char* text) {
+ serial_write_substring(text, strlen(text));
+}
diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c
new file mode 100644
index 000000000..d99853ceb
--- /dev/null
+++ b/supervisor/shared/status_leds.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/shared/status_leds.h"
+
+#include "common-hal/digitalio/DigitalInOut.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+
+#ifdef MICROPY_HW_LED_RX
+digitalio_digitalinout_obj_t rx_led;
+#endif
+
+#ifdef MICROPY_HW_LED_TX
+digitalio_digitalinout_obj_t tx_led;
+#endif
+
+void init_status_leds(void) {
+ #ifdef MICROPY_HW_LED_RX
+ common_hal_digitalio_digitalinout_construct(&rx_led, MICROPY_HW_LED_RX);
+ common_hal_digitalio_digitalinout_switch_to_output(&rx_led, true, DRIVE_MODE_PUSH_PULL);
+ #endif
+ #ifdef MICROPY_HW_LED_TX
+ common_hal_digitalio_digitalinout_construct(&tx_led, MICROPY_HW_LED_TX);
+ common_hal_digitalio_digitalinout_switch_to_output(&tx_led, true, DRIVE_MODE_PUSH_PULL);
+ #endif
+}
+
+void toggle_rx_led(void) {
+ #ifdef MICROPY_HW_LED_RX
+ common_hal_digitalio_digitalinout_set_value(&rx_led, !common_hal_digitalio_digitalinout_get_value(&rx_led));
+ #endif
+}
+
+
+void toggle_tx_led(void) {
+ #ifdef MICROPY_HW_LED_TX
+ common_hal_digitalio_digitalinout_set_value(&tx_led, !common_hal_digitalio_digitalinout_get_value(&tx_led));
+ #endif
+}
diff --git a/supervisor/shared/status_leds.h b/supervisor/shared/status_leds.h
new file mode 100644
index 000000000..30132753f
--- /dev/null
+++ b/supervisor/shared/status_leds.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H
+#define MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H
+
+void init_status_leds(void);
+
+void toggle_rx_led(void);
+
+void toggle_tx_led(void);
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H
diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h
new file mode 100644
index 000000000..649c390ac
--- /dev/null
+++ b/supervisor/shared/usb/tusb_config.h
@@ -0,0 +1,116 @@
+/**************************************************************************/
+/*!
+ @file tusb_config.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2013, hathach (tinyusb.org)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+/**************************************************************************/
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#include "genhdr/autogen_usb_descriptor.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------+
+#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
+
+#define CFG_TUSB_DEBUG 0
+
+/*------------- RTOS -------------*/
+#define CFG_TUSB_OS OPT_OS_NONE
+//#define CFG_TUD_TASK_QUEUE_SZ 16
+//#define CFG_TUD_TASK_PRIO 0
+//#define CFG_TUD_TASK_STACK_SZ 150
+
+//--------------------------------------------------------------------+
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------+
+
+#define CFG_TUD_ENDOINT0_SIZE 64
+
+/*------------- Descriptors -------------*/
+/* Enable auto generated descriptor, tinyusb will try its best to create
+ * descriptor ( device, configuration, hid ) that matches enabled CFG_* in this file
+ *
+ * Note: All CFG_TUD_DESC_* are relevant only if CFG_TUD_DESC_AUTO is enabled
+ */
+#define CFG_TUD_DESC_AUTO 0
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC 1
+#define CFG_TUD_MSC 1
+#define CFG_TUD_HID 1
+#define CFG_TUD_CUSTOM_CLASS 0
+
+/*------------------------------------------------------------------*/
+/* CLASS DRIVER
+ *------------------------------------------------------------------*/
+
+/* TX is sent automatically on every Start of Frame event ~ 1ms.
+ * If not enabled, application must call tud_cdc_flush() periodically
+ * Note: Enabled this could overflow device task, if it does, define
+ * CFG_TUD_TASK_QUEUE_SZ with large value
+ */
+#define CFG_TUD_CDC_FLUSH_ON_SOF 0
+
+
+/*------------- MSC -------------*/
+// Number of supported Logical Unit Number (At least 1)
+#define CFG_TUD_MSC_MAXLUN 1
+
+// Number of Blocks
+#define CFG_TUD_MSC_BLOCK_NUM (256*1024)/512
+
+
+
+// Product revision string included in Inquiry response, max 4 bytes
+#define CFG_TUD_MSC_PRODUCT_REV "1.0"
+
+
+//--------------------------------------------------------------------+
+// USB RAM PLACEMENT
+//--------------------------------------------------------------------+
+#define CFG_TUSB_ATTR_USBRAM
+#define CFG_TUSB_MEM_ALIGN ATTR_ALIGNED(4)
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c
new file mode 100644
index 000000000..1aa34e9e6
--- /dev/null
+++ b/supervisor/shared/usb/usb.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tick.h"
+#include "shared-bindings/microcontroller/Processor.h"
+#include "supervisor/port.h"
+#include "supervisor/usb.h"
+#include "lib/utils/interrupt_char.h"
+#include "lib/mp-readline/readline.h"
+
+#include "tusb.h"
+
+// Serial number as hex characters. This writes directly to the USB
+// descriptor.
+extern uint16_t usb_serial_number[1 + COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2];
+
+void load_serial_number(void) {
+ // create serial number based on device unique id
+ uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
+ common_hal_mcu_processor_get_uid(raw_id);
+
+ const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'};
+ for (int i = 0; i < COMMON_HAL_MCU_PROCESSOR_UID_LENGTH; i++) {
+ for (int j = 0; j < 2; j++) {
+ uint8_t nibble = (raw_id[i] >> (j * 4)) & 0xf;
+ // Strings are UTF-16-LE encoded.
+ usb_serial_number[1 + i * 2 + j] = nibble_to_hex[nibble];
+ }
+ }
+}
+
+bool _usb_enabled = false;
+
+bool usb_enabled(void) {
+ return _usb_enabled;
+}
+
+void usb_init(void) {
+ init_usb_hardware();
+ load_serial_number();
+
+ tusb_init();
+ _usb_enabled = true;
+
+#if MICROPY_KBD_EXCEPTION
+ // Set Ctrl+C as wanted char, tud_cdc_rx_wanted_cb() callback will be invoked when Ctrl+C is received
+ // This callback always got invoked regardless of mp_interrupt_char value since we only set it once here
+ tud_cdc_set_wanted_char(CHAR_CTRL_C);
+#endif
+}
+
+void usb_background(void) {
+ if (usb_enabled()) {
+ tusb_task();
+ tud_cdc_write_flush();
+ }
+}
+
+//--------------------------------------------------------------------+
+// tinyusb callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void) {
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void) {
+}
+
+uint32_t tusb_hal_millis(void) {
+ uint64_t ms;
+ uint32_t us;
+ current_tick(&ms, &us);
+ return (uint32_t) ms;
+}
+
+
+// Invoked when cdc when line state changed e.g connected/disconnected
+// Use to reset to DFU when disconnect with 1200 bps
+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
+ (void) itf; // interface ID, not used
+
+ // DTR = false is counted as disconnected
+ if ( !dtr )
+ {
+ cdc_line_coding_t coding;
+ tud_cdc_get_line_coding(&coding);
+
+ if ( coding.bit_rate == 1200 )
+ {
+ reset_to_bootloader();
+ }
+ }
+}
+
+#if MICROPY_KBD_EXCEPTION
+
+/**
+ * Callback invoked when received an "wanted" char.
+ * @param itf Interface index (for multiple cdc interfaces)
+ * @param wanted_char The wanted char (set previously)
+ */
+void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char)
+{
+ (void) itf; // not used
+
+ // Workaround for using lib/utils/interrupt_char.c
+ // Compare mp_interrupt_char with wanted_char and ignore if not matched
+ if (mp_interrupt_char == wanted_char) {
+ tud_cdc_read_flush(); // flush read fifo
+ mp_keyboard_interrupt();
+ }
+}
+
+#endif
diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c
new file mode 100644
index 000000000..5a0de1ffc
--- /dev/null
+++ b/supervisor/shared/usb/usb_desc.c
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "supervisor/shared/usb/usb_desc.h"
+#include "shared-module/usb_hid/Device.h"
+
+#include "genhdr/autogen_usb_descriptor.h"
+
+// tud_desc_set is required by tinyusb stack
+tud_desc_set_t tud_desc_set =
+{
+ .device = &usb_desc_dev,
+ .config = &usb_desc_cfg,
+ .string_arr = (uint8_t const **) string_desc_arr,
+ .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
+
+ .hid_report =
+ {
+ .generic = hid_report_descriptor,
+ .boot_keyboard = NULL,
+ .boot_mouse = NULL
+ }
+};
diff --git a/supervisor/shared/usb/usb_desc.h b/supervisor/shared/usb/usb_desc.h
new file mode 100644
index 000000000..250147aa6
--- /dev/null
+++ b/supervisor/shared/usb/usb_desc.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_DESC_H_
+#define USB_DESC_H_
+
+#include "lib/tinyusb/src/tusb.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// Descriptors set used by tinyusb stack
+extern tud_desc_set_t tud_desc_set;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* USB_DESC_H_ */
diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c
new file mode 100644
index 000000000..658aab0d8
--- /dev/null
+++ b/supervisor/shared/usb/usb_msc_flash.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "tusb.h"
+// // #include "supervisor/flash.h"
+
+// For updating fatfs's cache
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "lib/oofatfs/diskio.h"
+#include "lib/oofatfs/ff.h"
+#include "py/mpstate.h"
+
+#include "supervisor/shared/autoreload.h"
+
+#define MSC_FLASH_BLOCK_SIZE 512
+
+static bool ejected[1];
+
+// The root FS is always at the end of the list.
+static fs_user_mount_t* get_vfs(int lun) {
+ // TODO(tannewt): Return the mount which matches the lun where 0 is the end
+ // and is counted in reverse.
+ if (lun > 0) {
+ return NULL;
+ }
+ mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table);
+ if (current_mount == NULL) {
+ return NULL;
+ }
+ while (current_mount->next != NULL) {
+ current_mount = current_mount->next;
+ }
+ return current_mount->obj;
+}
+
+// Callback invoked when received an SCSI command not in built-in list below
+// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
+// - READ10 and WRITE10 have their own callbacks
+int32_t tud_msc_scsi_cb (uint8_t lun, const uint8_t scsi_cmd[16], void* buffer, uint16_t bufsize) {
+ const void* response = NULL;
+ int32_t resplen = 0;
+
+ switch ( scsi_cmd[0] ) {
+ case SCSI_CMD_TEST_UNIT_READY:
+ // Command that host uses to check our readiness before sending other commands
+ resplen = 0;
+ if (lun > 1) {
+ resplen = -1;
+ } else {
+ fs_user_mount_t* current_mount = get_vfs(lun);
+ if (current_mount == NULL) {
+ resplen = -1;
+ }
+ if (ejected[lun]) {
+ resplen = -1;
+ }
+ }
+ break;
+
+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ // Host is about to read/write etc ... better not to disconnect disk
+ resplen = 0;
+ break;
+
+ case SCSI_CMD_START_STOP_UNIT:
+ {
+ // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
+ const scsi_start_stop_unit_t* start_stop = (const scsi_start_stop_unit_t*) scsi_cmd;
+ // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
+ // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
+ resplen = 0;
+ if (start_stop->load_eject == 1) {
+ if (lun > 1) {
+ resplen = -1;
+ } else {
+ fs_user_mount_t* current_mount = get_vfs(lun);
+ if (current_mount == NULL) {
+ resplen = -1;
+ }
+ if (disk_ioctl(current_mount, CTRL_SYNC, NULL) != RES_OK) {
+ resplen = -1;
+ } else {
+ ejected[lun] = true;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ // Set Sense = Invalid Command Operation
+ tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+ // negative means error -> tinyusb could stall and/or response with failed status
+ resplen = -1;
+ break;
+ }
+
+ // return len must not larger than bufsize
+ if ( resplen > bufsize ) {
+ resplen = bufsize;
+ }
+
+ // copy response to stack's buffer if any
+ if ( response && resplen ) {
+ memcpy(buffer, response, resplen);
+ }
+
+ return resplen;
+}
+
+void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
+ fs_user_mount_t * vfs = get_vfs(lun);
+ disk_ioctl(vfs, GET_SECTOR_COUNT, block_count);
+ disk_ioctl(vfs, GET_SECTOR_SIZE, block_size);
+}
+
+bool tud_msc_is_writable_cb(uint8_t lun) {
+ if (lun > 1) {
+ return false;
+ }
+
+ fs_user_mount_t* vfs = get_vfs(lun);
+ if (vfs == NULL) {
+ return false;
+ }
+ if (vfs->writeblocks[0] == MP_OBJ_NULL ||
+ (vfs->flags & FSUSER_USB_WRITABLE) == 0) {
+ return false;
+ }
+ return true;
+}
+
+// Callback invoked when received READ10 command.
+// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
+int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
+ (void) lun;
+ (void) offset;
+
+ const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
+
+ fs_user_mount_t * vfs = get_vfs(lun);
+ disk_read(vfs, buffer, lba, block_count);
+
+ return block_count * MSC_FLASH_BLOCK_SIZE;
+}
+
+// Callback invoked when received WRITE10 command.
+// Process data in buffer to disk's storage and return number of written bytes
+int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
+ (void) lun;
+ (void) offset;
+
+ const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
+
+ fs_user_mount_t * vfs = get_vfs(lun);
+ disk_write(vfs, buffer, lba, block_count);
+ // Since by getting here we assume the mount is read-only to
+ // MicroPython let's update the cached FatFs sector if it's the one
+ // we just wrote.
+ #if _MAX_SS != _MIN_SS
+ if (vfs->ssize == MSC_FLASH_BLOCK_SIZE) {
+ #else
+ // The compiler can optimize this away.
+ if (_MAX_SS == FILESYSTEM_BLOCK_SIZE) {
+ #endif
+ if (lba == vfs->fatfs.winsect && lba > 0) {
+ memcpy(vfs->fatfs.win,
+ buffer + MSC_FLASH_BLOCK_SIZE * (vfs->fatfs.winsect - lba),
+ MSC_FLASH_BLOCK_SIZE);
+ }
+ }
+
+ return block_count * MSC_FLASH_BLOCK_SIZE;
+}
+
+// Callback invoked when WRITE10 command is completed (status received and accepted by host).
+// used to flush any pending cache.
+void tud_msc_write10_complete_cb (uint8_t lun) {
+ (void) lun;
+
+ // This write is complete, start the autoreload clock.
+ autoreload_start();
+}
diff --git a/supervisor/spi_flash_api.h b/supervisor/spi_flash_api.h
new file mode 100644
index 000000000..28cccb1b1
--- /dev/null
+++ b/supervisor/spi_flash_api.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SUPERVISOR_SPI_FLASH_H
+#define MICROPY_INCLUDED_SUPERVISOR_SPI_FLASH_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "supervisor/shared/external_flash/devices.h"
+
+// This API is implemented for both normal SPI peripherals and QSPI peripherals.
+
+bool spi_flash_command(uint8_t command);
+bool spi_flash_read_command(uint8_t command, uint8_t* response, uint32_t length);
+bool spi_flash_write_command(uint8_t command, uint8_t* data, uint32_t length);
+bool spi_flash_sector_command(uint8_t command, uint32_t address);
+bool spi_flash_write_data(uint32_t address, uint8_t* data, uint32_t data_length);
+bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t data_length);
+void spi_flash_init(void);
+void spi_flash_init_device(const external_flash_device* device);
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_SPI_FLASH_H
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index e516dcb2d..73c76ebb7 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -2,22 +2,82 @@ SRC_SUPERVISOR = \
main.c \
supervisor/port.c \
supervisor/shared/autoreload.c \
+ supervisor/shared/filesystem.c \
+ supervisor/shared/flash.c \
+ supervisor/shared/micropython.c \
supervisor/shared/rgb_led_status.c \
supervisor/shared/stack.c \
+ supervisor/shared/status_leds.c \
supervisor/shared/translate.c
-ifeq ($(wildcard atmel-samd/supervisor/filesystem.c),)
- SRC_SUPERVISOR += supervisor/filesystem.c
+ifndef $(NO_USB)
+NO_USB = $(wildcard supervisor/usb.c)
+endif
+
+
+# Choose which flash filesystem impl to use.
+# (Right now INTERNAL_FLASH_FILESYSTEM and SPI_FLASH_FILESYSTEM are mutually exclusive.
+# But that might not be true in the future.)
+ifdef EXTERNAL_FLASH_DEVICES
+ CFLAGS += -DEXTERNAL_FLASH_DEVICES=$(EXTERNAL_FLASH_DEVICES) \
+ -DEXTERNAL_FLASH_DEVICE_COUNT=$(EXTERNAL_FLASH_DEVICE_COUNT)
+
+ SRC_SUPERVISOR += supervisor/shared/external_flash/external_flash.c
+ ifeq ($(SPI_FLASH_FILESYSTEM),1)
+ CFLAGS += -DSPI_FLASH_FILESYSTEM
+ SRC_SUPERVISOR += supervisor/shared/external_flash/spi_flash.c
+ endif
+ ifeq ($(QSPI_FLASH_FILESYSTEM),1)
+ CFLAGS += -DQSPI_FLASH_FILESYSTEM
+ SRC_SUPERVISOR += supervisor/qspi_flash.c supervisor/shared/external_flash/qspi_flash.c
+ endif
else
- SRC_SUPERVISOR += supervisor/stub/filesystem.c
+ SRC_SUPERVISOR += supervisor/internal_flash.c
endif
-ifeq ($(wildcard atmel-samd/supervisor/serial.c),)
- SRC_SUPERVISOR += supervisor/serial.c
+ifeq ($(USB),FALSE)
+ ifeq ($(wildcard supervisor/serial.c),)
+ SRC_SUPERVISOR += supervisor/stub/serial.c
+ else
+ SRC_SUPERVISOR += supervisor/serial.c
+ endif
else
- SRC_SUPERVISOR += supervisor/stub/serial.c
+ SRC_SUPERVISOR += lib/tinyusb/src/common/tusb_fifo.c \
+ lib/tinyusb/src/device/usbd.c \
+ lib/tinyusb/src/device/usbd_control.c \
+ lib/tinyusb/src/class/msc/msc_device.c \
+ lib/tinyusb/src/class/cdc/cdc_device.c \
+ lib/tinyusb/src/class/hid/hid_device.c \
+ lib/tinyusb/src/tusb.c \
+ supervisor/shared/serial.c \
+ supervisor/usb.c \
+ supervisor/shared/usb/usb_desc.c \
+ supervisor/shared/usb/usb.c \
+ supervisor/shared/usb/usb_msc_flash.c \
+ shared-bindings/usb_hid/__init__.c \
+ shared-bindings/usb_hid/Device.c \
+ shared-module/usb_hid/__init__.c \
+ shared-module/usb_hid/Device.c \
+ $(BUILD)/autogen_usb_descriptor.c
+ CFLAGS += -DUSB_AVAILABLE
endif
SUPERVISOR_O = $(addprefix $(BUILD)/, $(SRC_SUPERVISOR:.c=.o))
$(BUILD)/supervisor/shared/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h
+
+$(BUILD)/autogen_usb_descriptor.c $(BUILD)/genhdr/autogen_usb_descriptor.h: autogen_usb_descriptor.intermediate
+
+.INTERMEDIATE: autogen_usb_descriptor.intermediate
+
+autogen_usb_descriptor.intermediate: ../../tools/gen_usb_descriptor.py Makefile | $(HEADER_BUILD)
+ $(STEPECHO) "GEN $@"
+ $(Q)install -d $(BUILD)/genhdr
+ $(Q)$(PYTHON3) ../../tools/gen_usb_descriptor.py \
+ --manufacturer $(USB_MANUFACTURER)\
+ --product $(USB_PRODUCT)\
+ --vid $(USB_VID)\
+ --pid $(USB_PID)\
+ --serial_number_length $(USB_SERIAL_NUMBER_LENGTH)\
+ --output_c_file $(BUILD)/autogen_usb_descriptor.c\
+ --output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h
diff --git a/supervisor/usb.h b/supervisor/usb.h
new file mode 100644
index 000000000..c87540d40
--- /dev/null
+++ b/supervisor/usb.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 hathach for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SUPERVISOR_USB_H
+#define MICROPY_INCLUDED_SUPERVISOR_USB_H
+
+#include <stdbool.h>
+
+// Ports must call this as frequently as they can in order to keep the USB connection
+// alive and responsive.
+void usb_background(void);
+
+// Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
+// TinyUSB.
+void init_usb_hardware(void);
+
+// Shared implementation.
+bool usb_enabled(void);
+void usb_init(void);
+
+#endif // MICROPY_INCLUDED_SUPERVISOR_USB_H