aboutsummaryrefslogtreecommitdiffstats
path: root/arduino/cores/nRF5/flash
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
committerClyne Sullivan <tullivan99@gmail.com>2019-02-28 17:04:22 -0500
commitd6869d1ec4bd24cd2c3eafa534f0849b25ec5607 (patch)
tree79e54ed27b39c31864895535d11399708d5a45c0 /arduino/cores/nRF5/flash
parent614ee97bf3a2270c413527a7f35c54cbecd9e601 (diff)
added basic code
Diffstat (limited to 'arduino/cores/nRF5/flash')
-rwxr-xr-xarduino/cores/nRF5/flash/flash_cache.c141
-rwxr-xr-xarduino/cores/nRF5/flash/flash_cache.h69
-rwxr-xr-xarduino/cores/nRF5/flash/flash_devices.h69
-rwxr-xr-xarduino/cores/nRF5/flash/flash_nrf5x.c173
-rwxr-xr-xarduino/cores/nRF5/flash/flash_nrf5x.h103
-rwxr-xr-xarduino/cores/nRF5/flash/flash_qspi.c289
-rwxr-xr-xarduino/cores/nRF5/flash/flash_qspi.h107
7 files changed, 951 insertions, 0 deletions
diff --git a/arduino/cores/nRF5/flash/flash_cache.c b/arduino/cores/nRF5/flash/flash_cache.c
new file mode 100755
index 0000000..09126f3
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_cache.c
@@ -0,0 +1,141 @@
+/**************************************************************************/
+/*!
+ @file flash_cache.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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.
+*/
+/**************************************************************************/
+
+#include "flash_cache.h"
+#include "common_func.h"
+#include "variant.h"
+#include "wiring_digital.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+static inline uint32_t page_addr_of (uint32_t addr)
+{
+ return addr & ~(FLASH_CACHE_SIZE - 1);
+}
+
+static inline uint32_t page_offset_of (uint32_t addr)
+{
+ return addr & (FLASH_CACHE_SIZE - 1);
+}
+
+uint32_t flash_cache_write (flash_cache_t* fc, uint32_t dst, void const * src, uint32_t len)
+{
+ uint8_t const * src8 = (uint8_t const *) src;
+ uint32_t remain = len;
+
+ // Program up to page boundary each loop
+ while ( remain )
+ {
+ uint32_t const page_addr = page_addr_of(dst);
+ uint32_t const offset = page_offset_of(dst);
+
+ uint32_t wr_bytes = FLASH_CACHE_SIZE - offset;
+ wr_bytes = min32(remain, wr_bytes);
+
+ // Page changes, flush old and update new cache
+ if ( page_addr != fc->cache_addr )
+ {
+ flash_cache_flush(fc);
+ fc->cache_addr = page_addr;
+
+ // read a whole page from flash
+ fc->read(fc->cache_buf, page_addr, FLASH_CACHE_SIZE);
+ }
+
+ memcpy(fc->cache_buf + offset, src8, wr_bytes);
+
+ // adjust for next run
+ src8 += wr_bytes;
+ remain -= wr_bytes;
+ dst += wr_bytes;
+ }
+
+ return len - remain;
+}
+
+void flash_cache_flush (flash_cache_t* fc)
+{
+ if ( fc->cache_addr == FLASH_CACHE_INVALID_ADDR ) return;
+
+ // skip erase & program if verify() exists, and memory matches
+ if ( !(fc->verify && fc->verify(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE)) )
+ {
+ // indicator
+ ledOn(LED_BUILTIN);
+
+ fc->erase(fc->cache_addr);
+ fc->program(fc->cache_addr, fc->cache_buf, FLASH_CACHE_SIZE);
+
+ ledOff(LED_BUILTIN);
+ }
+
+ fc->cache_addr = FLASH_CACHE_INVALID_ADDR;
+}
+
+void flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count)
+{
+ // overwrite with cache value if available
+ if ( (fc->cache_addr != FLASH_CACHE_INVALID_ADDR) &&
+ !(addr < fc->cache_addr && addr + count <= fc->cache_addr) &&
+ !(addr >= fc->cache_addr + FLASH_CACHE_SIZE) )
+ {
+ int dst_off = fc->cache_addr - addr;
+ int src_off = 0;
+
+ if ( dst_off < 0 )
+ {
+ src_off = -dst_off;
+ dst_off = 0;
+ }
+
+ int cache_bytes = minof(FLASH_CACHE_SIZE-src_off, count - dst_off);
+
+ // start to cached
+ if ( dst_off ) fc->read(dst, addr, dst_off);
+
+ // cached
+ memcpy(dst + dst_off, fc->cache_buf + src_off, cache_bytes);
+
+ // cached to end
+ int copied = dst_off + cache_bytes;
+ if ( copied < count ) fc->read(dst + copied, addr + copied, count - copied);
+ }
+ else
+ {
+ fc->read(dst, (void*) addr, count);
+ }
+}
diff --git a/arduino/cores/nRF5/flash/flash_cache.h b/arduino/cores/nRF5/flash/flash_cache.h
new file mode 100755
index 0000000..792fe83
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_cache.h
@@ -0,0 +1,69 @@
+/**************************************************************************/
+/*!
+ @file flash_cache.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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 FLASH_CACHE_H_
+#define FLASH_CACHE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define FLASH_CACHE_SIZE 4096 // must be a erasable page size
+#define FLASH_CACHE_INVALID_ADDR 0xffffffff
+
+typedef struct
+{
+ bool (*erase) (uint32_t addr);
+ uint32_t (*program) (uint32_t dst, void const * src, uint32_t len);
+ uint32_t (*read) (void* dst, uint32_t src, uint32_t len);
+ bool (*verify) (uint32_t addr, void const * buf, uint32_t len);
+
+ uint32_t cache_addr;
+ uint8_t* cache_buf;
+} flash_cache_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint32_t flash_cache_write (flash_cache_t* fc, uint32_t dst, void const *src, uint32_t count);
+void flash_cache_flush (flash_cache_t* fc);
+void flash_cache_read (flash_cache_t* fc, void* dst, uint32_t addr, uint32_t count);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FLASH_CACHE_H_ */
diff --git a/arduino/cores/nRF5/flash/flash_devices.h b/arduino/cores/nRF5/flash/flash_devices.h
new file mode 100755
index 0000000..96b4703
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_devices.h
@@ -0,0 +1,69 @@
+/*
+ * 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 FLASH_DEVICES_H_
+#define FLASH_DEVICES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct {
+ uint32_t total_size;
+
+ // Three response bytes to 0x90 JEDEC REMS ID command.
+ uint8_t manufacturer_id;
+ uint8_t device_id;
+
+ // Status register value enable quad mode
+ uint16_t status_quad_enable;
+
+} qspi_flash_device_t;
+
+// Settings for the Gigadevice GD25Q16C 2MiB SPI flash.
+// Datasheet: http://www.gigadevice.com/wp-content/uploads/2017/12/DS-00086-GD25Q16C-Rev2.6.pdf
+#define GD25Q16C {\
+ .total_size = 2*1024*1024, \
+ .manufacturer_id = 0xc8, \
+ .device_id = 0x14, \
+ .status_quad_enable = (1 << 9)\
+}
+
+#define MX25R6435F {\
+ .total_size = 8*1024*1024, \
+ .manufacturer_id = 0xc2, \
+ .device_id = 0x17, \
+ .status_quad_enable = (1 << 6)\
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FLASH_DEVICES_H_ */
diff --git a/arduino/cores/nRF5/flash/flash_nrf5x.c b/arduino/cores/nRF5/flash/flash_nrf5x.c
new file mode 100755
index 0000000..bafde34
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_nrf5x.c
@@ -0,0 +1,173 @@
+/**************************************************************************/
+/*!
+ @file flash_nrf5x.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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.
+*/
+/**************************************************************************/
+
+#include "flash_nrf5x.h"
+#include "flash_cache.h"
+#include "nrf_sdm.h"
+#include "nrf_soc.h"
+#include "rtos.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+static SemaphoreHandle_t _sem = NULL;
+
+void flash_nrf5x_event_cb (uint32_t event)
+{
+// if (event != NRF_EVT_FLASH_OPERATION_SUCCESS) LOG_LV1("IFLASH", "Flash op Failed");
+ if ( _sem ) xSemaphoreGive(_sem);
+}
+
+// Flash Abstraction Layer
+static bool fal_erase (uint32_t addr);
+static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len);
+static uint32_t fal_read (void* dst, uint32_t src, uint32_t len);
+static bool fal_verify (uint32_t addr, void const * buf, uint32_t len);
+
+static uint8_t _cache_buffer[FLASH_CACHE_SIZE] __attribute__((aligned(4)));
+
+static flash_cache_t _cache = {
+ .erase = fal_erase,
+ .program = fal_program,
+ .read = fal_read,
+ .verify = fal_verify,
+ .cache_addr = FLASH_CACHE_INVALID_ADDR,
+ .cache_buf = _cache_buffer
+};
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+void flash_nrf5x_flush (void)
+{
+ flash_cache_flush(&_cache);
+}
+
+uint32_t flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len)
+{
+ // TODO prevent write SD + bootloader region
+ return flash_cache_write(&_cache, dst, src, len);
+}
+
+uint32_t flash_nrf5x_read (void* dst, uint32_t src, uint32_t len)
+{
+ // return cache value if available
+ flash_cache_read(&_cache, dst, src, len);
+ return len;
+}
+
+bool flash_nrf5x_erase(uint32_t addr)
+{
+ return fal_erase(addr);
+}
+
+//--------------------------------------------------------------------+
+// HAL for caching
+//--------------------------------------------------------------------+
+bool fal_erase (uint32_t addr)
+{
+ // Init semaphore for first call
+ if ( _sem == NULL )
+ {
+ _sem = xSemaphoreCreateCounting(10, 0);
+ VERIFY(_sem);
+ }
+
+ // retry if busy
+ uint32_t err;
+ while ( NRF_ERROR_BUSY == (err = sd_flash_page_erase(addr / FLASH_NRF52_PAGE_SIZE)) )
+ {
+ delay(1);
+ }
+ VERIFY_STATUS(err, false);
+
+ // wait for async event if SD is enabled
+ uint8_t sd_en = 0;
+ (void) sd_softdevice_is_enabled(&sd_en);
+
+ if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
+
+ return true;
+}
+
+static uint32_t fal_program (uint32_t dst, void const * src, uint32_t len)
+{
+ // wait for async event if SD is enabled
+ uint8_t sd_en = 0;
+ (void) sd_softdevice_is_enabled(&sd_en);
+
+ uint32_t err;
+
+ // Somehow S140 v6.1.1 assert an error when writing a whole page
+ // https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert
+ // Workaround: write half page at a time.
+#if NRF52832_XXAA
+ while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/4)) )
+ {
+ delay(1);
+ }
+ VERIFY_STATUS(err, 0);
+
+ if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
+#else
+ while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) dst, (uint32_t const *) src, len/8)) )
+ {
+ delay(1);
+ }
+ VERIFY_STATUS(err, 0);
+ if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
+
+ while ( NRF_ERROR_BUSY == (err = sd_flash_write((uint32_t*) (dst+ len/2), (uint32_t const *) (src + len/2), len/8)) )
+ {
+ delay(1);
+ }
+ VERIFY_STATUS(err, 0);
+ if ( sd_en ) xSemaphoreTake(_sem, portMAX_DELAY);
+#endif
+
+ return len;
+}
+
+static uint32_t fal_read (void* dst, uint32_t src, uint32_t len)
+{
+ memcpy(dst, (void*) src, len);
+ return len;
+}
+
+static bool fal_verify (uint32_t addr, void const * buf, uint32_t len)
+{
+ return 0 == memcmp((void*) addr, buf, len);
+}
diff --git a/arduino/cores/nRF5/flash/flash_nrf5x.h b/arduino/cores/nRF5/flash/flash_nrf5x.h
new file mode 100755
index 0000000..be907fb
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_nrf5x.h
@@ -0,0 +1,103 @@
+/**************************************************************************/
+/*!
+ @file flash_nrf5x.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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 FLASH_NRF52_H_
+#define FLASH_NRF52_H_
+
+#include "common_inc.h"
+
+#define FLASH_NRF52_PAGE_SIZE 4096
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+void flash_nrf5x_flush (void);
+bool flash_nrf5x_erase(uint32_t addr);
+
+uint32_t flash_nrf5x_write (uint32_t dst, void const * src, uint32_t len);
+uint32_t flash_nrf5x_read (void* dst, uint32_t src, uint32_t len);
+
+//--------------------------------------------------------------------+
+// Write helper
+//--------------------------------------------------------------------+
+static inline uint32_t flash_nrf5x_write8 (uint32_t dst, uint8_t num)
+{
+ flash_nrf5x_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+
+static inline uint32_t flash_nrf5x_write16 (uint32_t dst, uint8_t num)
+{
+ flash_nrf5x_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+static inline uint32_t flash_nrf5x_write32 (uint32_t dst, uint8_t num)
+{
+ flash_nrf5x_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+
+//--------------------------------------------------------------------+
+// Read helper
+//--------------------------------------------------------------------+
+static inline uint8_t flash_nrf5x_read8 (uint32_t src)
+{
+ uint8_t num;
+ flash_nrf5x_read(&num, src, sizeof(num));
+ return num;
+}
+
+static inline uint16_t flash_nrf5x_read16 (uint32_t src)
+{
+ uint16_t num;
+ flash_nrf5x_read(&num, src, sizeof(num));
+ return num;
+}
+
+static inline uint16_t flash_nrf5x_read32 (uint32_t src)
+{
+ uint32_t num;
+ flash_nrf5x_read(&num, src, sizeof(num));
+ return num;
+}
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* FLASH_NRF52_H_ */
diff --git a/arduino/cores/nRF5/flash/flash_qspi.c b/arduino/cores/nRF5/flash/flash_qspi.c
new file mode 100755
index 0000000..b415d03
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_qspi.c
@@ -0,0 +1,289 @@
+/**************************************************************************/
+/*!
+ @file flash_qspi.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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.
+*/
+/**************************************************************************/
+
+#ifdef NRF52840_XXAA
+
+#include "Arduino.h"
+#include "flash_devices.h"
+#include "flash_qspi.h"
+#include "flash_cache.h"
+#include "nrfx_qspi.h"
+
+#define _VALID_PIN(n) (defined(PIN_QSPI_DATA##n) && (PIN_QSPI_DATA##n != 0xff))
+
+#define QSPI_FLASH_MODE \
+ (( _VALID_PIN(0) && _VALID_PIN(1) && _VALID_PIN(2) && _VALID_PIN(3) ) ? 4 : \
+ ( _VALID_PIN(0) && _VALID_PIN(1) ) ? 2 : \
+ ( _VALID_PIN(0) ) ? 1 : 0)
+
+#if QSPI_FLASH_MODE
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+enum
+{
+ QSPI_CMD_RSTEN = 0x66,
+ QSPI_CMD_RST = 0x99,
+ QSPI_CMD_WRSR = 0x01,
+ QSPI_CMD_READID = 0x90
+};
+
+// If Flash device is not specified, support all devices in flash_devices.h
+#ifdef EXTERNAL_FLASH_DEVICES
+const qspi_flash_device_t _flash_devices_arr[] = { EXTERNAL_FLASH_DEVICES };
+#else
+const qspi_flash_device_t _flash_devices_arr[] = { GD25Q16C, MX25R6435F };
+#endif
+
+enum
+{
+ FLASH_DEVICE_COUNT = arrcount(_flash_devices_arr)
+};
+
+const qspi_flash_device_t* _flash_dev = NULL;
+
+// Flash Abstraction Layer
+static bool fal_qspi_erase (uint32_t addr);
+static uint32_t fal_qspi_program (uint32_t dst, void const * src, uint32_t len);
+static uint32_t fal_qspi_read (void* dst, uint32_t src, uint32_t len);
+static bool fal_qspi_verify (uint32_t addr, void const * buf, uint32_t len);
+
+static uint8_t _cache_buffer[FLASH_CACHE_SIZE] __attribute__((aligned(4)));
+
+static flash_cache_t _cache = {
+ .erase = fal_qspi_erase,
+ .program = fal_qspi_program,
+ .read = fal_qspi_read,
+ .verify = fal_qspi_verify,
+ .cache_addr = FLASH_CACHE_INVALID_ADDR,
+ .cache_buf = _cache_buffer
+};
+
+static SemaphoreHandle_t _qspi_mutex;
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+uint32_t flash_qspi_size (void)
+{
+ VERIFY(_flash_dev, 0);
+ return _flash_dev->total_size;
+}
+
+uint32_t flash_qspi_write (uint32_t dst, void const * src, uint32_t len)
+{
+ VERIFY(_flash_dev, 0);
+
+ xSemaphoreTake(_qspi_mutex, portMAX_DELAY);
+ uint32_t res = flash_cache_write(&_cache, dst, src, len);
+ xSemaphoreGive(_qspi_mutex);
+
+ return res;
+}
+
+uint32_t flash_qspi_read (void* dst, uint32_t src, uint32_t len)
+{
+ VERIFY(_flash_dev, 0);
+
+// xSemaphoreTake(_qspi_mutex, portMAX_DELAY);
+ flash_cache_read(&_cache, dst, src, len);
+// xSemaphoreGive(_qspi_mutex);
+
+ return len;
+}
+
+void flash_qspi_flush (void)
+{
+ VERIFY(_flash_dev,);
+
+ xSemaphoreTake(_qspi_mutex, portMAX_DELAY);
+ flash_cache_flush(&_cache);
+ xSemaphoreGive(_qspi_mutex);
+}
+
+bool flash_qspi_chiperase (void)
+{
+ VERIFY(_flash_dev);
+
+ xSemaphoreTake(_qspi_mutex, portMAX_DELAY);
+ VERIFY(NRFX_SUCCESS == nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0));
+ xSemaphoreGive(_qspi_mutex);
+
+ return true;
+}
+
+void flash_qspi_init (void)
+{
+ // Init QSPI flash
+ nrfx_qspi_config_t qspi_cfg = {
+ .xip_offset = 0,
+ .pins = {
+ .sck_pin = g_ADigitalPinMap[PIN_QSPI_SCK],
+ .csn_pin = g_ADigitalPinMap[PIN_QSPI_CS],
+ .io0_pin = g_ADigitalPinMap[PIN_QSPI_DATA0],
+ .io1_pin = NRF_QSPI_PIN_NOT_CONNECTED,
+ .io2_pin = NRF_QSPI_PIN_NOT_CONNECTED,
+ .io3_pin = NRF_QSPI_PIN_NOT_CONNECTED,
+
+ },
+ .prot_if = {
+ .readoc = NRF_QSPI_READOC_FASTREAD,
+ .writeoc = NRF_QSPI_WRITEOC_PP,
+ .addrmode = NRF_QSPI_ADDRMODE_24BIT,
+ .dpmconfig = false
+ },
+ .phy_if = {
+ .sck_freq = NRF_QSPI_FREQ_32MDIV1,
+ .sck_delay = 1, // min time CS must stay high before going low again. in unit of 62.5 ns
+ .spi_mode = NRF_QSPI_MODE_0,
+ .dpmen = false
+ },
+ .irq_priority = 7,
+ };
+
+#if QSPI_FLASH_MODE == 2
+ qspi_cfg.pins.io1_pin = g_ADigitalPinMap[PIN_QSPI_DATA1];
+ qspi_cfg.prot_if.readoc = NRF_QSPI_READOC_READ2IO;
+ qspi_cfg.prot_if.writeoc = NRF_QSPI_WRITEOC_PP2O;
+#elif QSPI_FLASH_MODE == 4
+ qspi_cfg.pins.io1_pin = g_ADigitalPinMap[PIN_QSPI_DATA1];
+ qspi_cfg.pins.io2_pin = g_ADigitalPinMap[PIN_QSPI_DATA2];
+ qspi_cfg.pins.io3_pin = g_ADigitalPinMap[PIN_QSPI_DATA3];
+ qspi_cfg.prot_if.readoc = NRF_QSPI_READOC_READ4IO;
+ qspi_cfg.prot_if.writeoc = NRF_QSPI_WRITEOC_PP4O;
+#endif
+
+ // No callback for blocking API
+ nrfx_qspi_init(&qspi_cfg, NULL, NULL);
+
+ nrf_qspi_cinstr_conf_t cinstr_cfg = {
+ .opcode = 0,
+ .length = 0,
+ .io2_level = true,
+ .io3_level = true,
+ .wipwait = false,
+ .wren = false
+ };
+
+ // Send reset enable
+ cinstr_cfg.opcode = QSPI_CMD_RSTEN;
+ cinstr_cfg.length = 1;
+ nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
+
+ // Send reset command
+ cinstr_cfg.opcode = QSPI_CMD_RST;
+ cinstr_cfg.length = 1;
+ nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
+
+ NRFX_DELAY_US(100); // wait for flash device to reset
+
+ // Send (Read ID + 3 dummy bytes) + Receive 2 bytes of (Manufacture + Device ID)
+ uint8_t dummy[6] = { 0 };
+ uint8_t id_resp[6] = { 0 };
+ cinstr_cfg.opcode = QSPI_CMD_READID;
+ cinstr_cfg.length = 6;
+
+ // Bug with -nrf_qspi_cinstrdata_get() didn't combine data.
+ // https://devzone.nordicsemi.com/f/nordic-q-a/38540/bug-nrf_qspi_cinstrdata_get-didn-t-collect-data-from-both-cinstrdat1-and-cinstrdat0
+ nrfx_qspi_cinstr_xfer(&cinstr_cfg, dummy, id_resp);
+
+ // Due to the bug, we collect data manually
+ uint8_t dev_id = (uint8_t) NRF_QSPI->CINSTRDAT1;
+ uint8_t mfgr_id = (uint8_t) ( NRF_QSPI->CINSTRDAT0 >> 24);
+
+ // quick hack
+ //printf("qspi mfgr id : 0x%02X\n", mfgr_id);
+ //printf("qspi device id: 0x%02X\n", dev_id);
+
+ // Look up the flash device in supported array
+ for ( int i = 0; i < FLASH_DEVICE_COUNT; i++ )
+ {
+ // Match ID
+ if ( _flash_devices_arr[i].manufacturer_id == mfgr_id && _flash_devices_arr[i].device_id == dev_id )
+ {
+ _flash_dev = &_flash_devices_arr[i];
+ break;
+ }
+ }
+
+ if ( _flash_dev )
+ {
+ // Enable quad mode if needed
+#if QSPI_FLASH_MODE == 4
+ cinstr_cfg.opcode = QSPI_CMD_WRSR;
+ cinstr_cfg.length = 3;
+ cinstr_cfg.wipwait = cinstr_cfg.wren = true;
+ nrfx_qspi_cinstr_xfer(&cinstr_cfg, &_flash_dev->status_quad_enable, NULL);
+#endif
+ }
+
+ // create mutex
+ _qspi_mutex = xSemaphoreCreateMutex();
+}
+
+//--------------------------------------------------------------------+
+// HAL for caching
+//--------------------------------------------------------------------+
+static bool fal_qspi_erase (uint32_t addr)
+{
+ VERIFY(_flash_dev);
+ VERIFY(NRFX_SUCCESS == nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, addr));
+ return true;
+}
+
+static uint32_t fal_qspi_program (uint32_t dst, void const * src, uint32_t len)
+{
+ VERIFY(_flash_dev, 0);
+ VERIFY(NRFX_SUCCESS == nrfx_qspi_write(src, len, dst));
+ return len;
+}
+
+static uint32_t fal_qspi_read (void* dst, uint32_t src, uint32_t len)
+{
+ VERIFY(_flash_dev, 0);
+ VERIFY(NRFX_SUCCESS == nrfx_qspi_read(dst, len, src));
+ return len;
+}
+
+static bool fal_qspi_verify (uint32_t addr, void const * buf, uint32_t len)
+{
+ return false;
+}
+
+#endif // valid pin
+#endif // nrf52840
+
diff --git a/arduino/cores/nRF5/flash/flash_qspi.h b/arduino/cores/nRF5/flash/flash_qspi.h
new file mode 100755
index 0000000..24cdca4
--- /dev/null
+++ b/arduino/cores/nRF5/flash/flash_qspi.h
@@ -0,0 +1,107 @@
+/**************************************************************************/
+/*!
+ @file flash_qspi.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, Adafruit Industries (adafruit.com)
+ 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 FLASH_QSPI_H_
+#define FLASH_QSPI_H_
+
+#include "common_inc.h"
+
+#define FLASH_QSPI_PAGE_SIZE 4096
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+void flash_qspi_init (void);
+uint32_t flash_qspi_size (void);
+void flash_qspi_flush (void);
+bool flash_qspi_erase (uint32_t addr);
+bool flash_qspi_chiperase (void);
+
+uint32_t flash_qspi_write (uint32_t dst, void const * src, uint32_t len);
+uint32_t flash_qspi_read (void* dst, uint32_t src, uint32_t len);
+
+//--------------------------------------------------------------------+
+// Write helper
+//--------------------------------------------------------------------+
+static inline uint32_t flash_qspi_write8 (uint32_t dst, uint8_t num)
+{
+ flash_qspi_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+
+static inline uint32_t flash_qspi_write16 (uint32_t dst, uint8_t num)
+{
+ flash_qspi_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+static inline uint32_t flash_qspi_write32 (uint32_t dst, uint8_t num)
+{
+ flash_qspi_write(dst, &num, sizeof(num));
+ return sizeof(num);
+}
+
+//--------------------------------------------------------------------+
+// Read helper
+//--------------------------------------------------------------------+
+static inline uint8_t flash_qspi_read8 (uint32_t src)
+{
+ uint8_t num;
+ flash_qspi_read(&num, src, sizeof(num));
+ return num;
+}
+
+static inline uint16_t flash_qspi_read16 (uint32_t src)
+{
+ uint16_t num;
+ flash_qspi_read(&num, src, sizeof(num));
+ return num;
+}
+
+static inline uint16_t flash_qspi_read32 (uint32_t src)
+{
+ uint32_t num;
+ flash_qspi_read(&num, src, sizeof(num));
+ return num;
+}
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+#endif /* FLASH_QSPI_H_ */