You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/04/19 12:45:59 UTC

[GitHub] andrzej-kaczmarek closed pull request #1015: nrf52840 support for qspi flash

andrzej-kaczmarek closed pull request #1015: nrf52840 support for qspi flash
URL: https://github.com/apache/mynewt-core/pull/1015
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/bsp/nrf52840pdk/src/hal_bsp.c b/hw/bsp/nrf52840pdk/src/hal_bsp.c
index b5d6dc369..fa868c829 100644
--- a/hw/bsp/nrf52840pdk/src/hal_bsp.c
+++ b/hw/bsp/nrf52840pdk/src/hal_bsp.c
@@ -146,10 +146,15 @@ hal_bsp_flash_dev(uint8_t id)
     /*
      * Internal flash mapped to id 0.
      */
-    if (id != 0) {
-        return NULL;
+    if (id == 0) {
+        return &nrf52k_flash_dev;
     }
-    return &nrf52k_flash_dev;
+#if MYNEWT_VAL(QSPI_ENABLE)
+    if (id == 1) {
+        return &nrf52k_qspi_dev;
+    }
+#endif
+    return NULL;
 }
 
 const struct hal_bsp_mem_dump *
diff --git a/hw/bsp/nrf52840pdk/syscfg.yml b/hw/bsp/nrf52840pdk/syscfg.yml
index 221a0dbd4..da0b5c248 100644
--- a/hw/bsp/nrf52840pdk/syscfg.yml
+++ b/hw/bsp/nrf52840pdk/syscfg.yml
@@ -117,6 +117,16 @@ syscfg.vals:
     COREDUMP_FLASH_AREA: FLASH_AREA_IMAGE_1
     MCU_DCDC_ENABLED: 1
     XTAL_32768: 1
+    QSPI_FLASH_SECTOR_SIZE: 4096
+    QSPI_FLASH_PAGE_SIZE: 256
+    QSPI_FLASH_SECTOR_COUNT: 4096
+    QSPI_PIN_CS: 17
+    QSPI_PIN_SCK: 19
+    QSPI_PIN_DIO0: 20
+    QSPI_PIN_DIO1: 21
+    QSPI_PIN_DIO2: 22
+    QSPI_PIN_DIO3: 23
+
 
 syscfg.vals.BLE_LP_CLOCK:
     OS_CPUTIME_FREQ: 32768
diff --git a/hw/mcu/nordic/nrf52xxx/include/mcu/nrf52_hal.h b/hw/mcu/nordic/nrf52xxx/include/mcu/nrf52_hal.h
index 97c5781ec..2e5f3ab26 100644
--- a/hw/mcu/nordic/nrf52xxx/include/mcu/nrf52_hal.h
+++ b/hw/mcu/nordic/nrf52xxx/include/mcu/nrf52_hal.h
@@ -53,6 +53,7 @@ struct nrf52_hal_i2c_cfg {
 };
 struct hal_flash;
 extern const struct hal_flash nrf52k_flash_dev;
+extern const struct hal_flash nrf52k_qspi_dev;
 
 /* SPI configuration (used for both master and slave) */
 struct nrf52_hal_spi_cfg {
diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_qspi.c b/hw/mcu/nordic/nrf52xxx/src/hal_qspi.c
new file mode 100644
index 000000000..c77938325
--- /dev/null
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_qspi.c
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include "os/mynewt.h"
+#if MYNEWT_VAL(QSPI_ENABLE)
+#include <mcu/cmsis_nvic.h>
+#include <hal/hal_flash_int.h>
+#include "mcu/nrf52_hal.h"
+#include "nrf.h"
+#include <nrfx/hal/nrf_qspi.h>
+
+#if MYNEWT_VAL(QSPI_FLASH_SECTOR_SIZE) < 1
+#error QSPI_FLASH_SECTOR_SIZE must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_FLASH_PAGE_SIZE) < 1
+#error QSPI_FLASH_PAGE_SIZE must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_FLASH_SECTOR_COUNT) < 1
+#error QSPI_FLASH_SECTOR_COUNT must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_CS) < 0
+#error QSPI_PIN_CS must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_SCK) < 0
+#error QSPI_PIN_SCK must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_DIO0) < 0
+#error QSPI_PIN_DIO0 must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_DIO1) < 0
+#error QSPI_PIN_DIO1 must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_DIO2) < 0 && (MYNEWT_VAL(QSPI_READOC) > 2 || MYNEWT_VAL(QSPI_WRITEOC) > 1)
+#error QSPI_PIN_DIO2 must be set to the correct value in bsp syscfg.yml
+#endif
+
+#if MYNEWT_VAL(QSPI_PIN_DIO3) < 0 && (MYNEWT_VAL(QSPI_READOC) > 2 || MYNEWT_VAL(QSPI_WRITEOC) > 1)
+#error QSPI_PIN_DIO3 must be set to the correct value in bsp syscfg.yml
+#endif
+
+static int
+nrf52k_qspi_read(const struct hal_flash *dev, uint32_t address,
+        void *dst, uint32_t num_bytes);
+static int
+nrf52k_qspi_write(const struct hal_flash *dev, uint32_t address,
+        const void *src, uint32_t num_bytes);
+static int
+nrf52k_qspi_erase_sector(const struct hal_flash *dev,
+        uint32_t sector_address);
+static int
+nrf52k_qspi_sector_info(const struct hal_flash *dev, int idx,
+        uint32_t *address, uint32_t *sz);
+static int
+nrf52k_qspi_init(const struct hal_flash *dev);
+
+static const struct hal_flash_funcs nrf52k_qspi_funcs = {
+    .hff_read = nrf52k_qspi_read,
+    .hff_write = nrf52k_qspi_write,
+    .hff_erase_sector = nrf52k_qspi_erase_sector,
+    .hff_sector_info = nrf52k_qspi_sector_info,
+    .hff_init = nrf52k_qspi_init
+};
+
+const struct hal_flash nrf52k_qspi_dev = {
+    .hf_itf = &nrf52k_qspi_funcs,
+    .hf_base_addr = 0x00000000,
+    .hf_size = MYNEWT_VAL(QSPI_FLASH_SECTOR_COUNT) * MYNEWT_VAL(QSPI_FLASH_SECTOR_SIZE),
+    .hf_sector_cnt = MYNEWT_VAL(QSPI_FLASH_SECTOR_COUNT),
+    .hf_align = 1
+};
+
+static int
+nrf52k_qspi_read(const struct hal_flash *dev, uint32_t address,
+        void *dst, uint32_t num_bytes) {
+    uint32_t ram_buffer[4];
+    uint8_t *ram_ptr = NULL;
+    uint32_t read_bytes;
+
+    while ((NRF_QSPI->STATUS & QSPI_STATUS_READY_Msk) == 0)
+        ;
+
+    while (num_bytes != 0) {
+        /*
+         * If address or destination pointer are unaligned or
+         * number of bytes to read is less then 4 read using ram buffer.
+         */
+        if (((address & 3) != 0) ||
+            ((((uint32_t) dst) & 3) != 0) ||
+            num_bytes < 4) {
+            uint32_t to_read = (num_bytes + (address & 3) + 3) & ~3;
+            if (to_read > sizeof(ram_buffer)) {
+                to_read = sizeof(ram_buffer);
+            }
+            ram_ptr = (uint8_t *)((uint32_t) ram_buffer + (address & 3));
+            read_bytes = to_read - (address & 3);
+            if (read_bytes > num_bytes) {
+                read_bytes = num_bytes;
+            }
+            NRF_QSPI->READ.DST = (uint32_t) ram_buffer;
+            NRF_QSPI->READ.SRC = address & ~3;
+            NRF_QSPI->READ.CNT = to_read;
+        } else {
+            read_bytes = num_bytes & ~3;
+            NRF_QSPI->READ.DST = (uint32_t) dst;
+            NRF_QSPI->READ.SRC = address;
+            NRF_QSPI->READ.CNT = read_bytes;
+        }
+        NRF_QSPI->EVENTS_READY = 0;
+        NRF_QSPI->TASKS_READSTART = 1;
+        while (NRF_QSPI->EVENTS_READY == 0)
+            ;
+        if (ram_ptr != NULL) {
+            memcpy(dst, ram_ptr, read_bytes);
+            ram_ptr = NULL;
+        }
+        address += read_bytes;
+        dst = (void *) ((uint32_t) dst + read_bytes);
+        num_bytes -= read_bytes;
+    }
+    return 0;
+}
+
+static int
+nrf52k_qspi_write(const struct hal_flash *dev, uint32_t address,
+        const void *src, uint32_t num_bytes)
+{
+    uint32_t ram_buffer[4];
+    uint8_t *ram_ptr = NULL;
+    uint32_t written_bytes;
+    const char src_not_in_ram = (((uint32_t) src) & 0xE0000000) != 0x20000000;
+    uint32_t page_limit;
+
+    while ((NRF_QSPI->STATUS & QSPI_STATUS_READY_Msk) == 0)
+        ;
+
+    while (num_bytes != 0) {
+        page_limit = (address & ~(MYNEWT_VAL(QSPI_FLASH_PAGE_SIZE) - 1)) +
+                MYNEWT_VAL(QSPI_FLASH_PAGE_SIZE);
+        /*
+         * Use RAM buffer if src or address is not 4 bytes aligned,
+         * or number of bytes to write is less then 4
+         * or src pointer is not from RAM.
+         */
+        if (((address & 3) != 0) ||
+            ((((uint32_t) src) & 3) != 0) ||
+            num_bytes < 4 ||
+            src_not_in_ram) {
+            uint32_t to_write;
+            if (address + num_bytes > page_limit) {
+                to_write = ((page_limit - address) + 3) & ~3;
+            } else {
+                to_write = (num_bytes + (address & 3) + 3) & ~3;
+            }
+            if (to_write > sizeof(ram_buffer)) {
+                to_write = sizeof(ram_buffer);
+            }
+            memset(ram_buffer, 0xFF, sizeof(ram_buffer));
+            ram_ptr = (uint8_t *)((uint32_t) ram_buffer + (address & 3));
+
+            written_bytes = to_write - (address & 3);
+            if (written_bytes > num_bytes) {
+                written_bytes = num_bytes;
+            }
+            memcpy(ram_ptr, src, written_bytes);
+
+            NRF_QSPI->WRITE.SRC = (uint32_t) ram_buffer;
+            NRF_QSPI->WRITE.DST = address & ~3;
+            NRF_QSPI->WRITE.CNT = to_write;
+        } else {
+            NRF_QSPI->WRITE.SRC = (uint32_t) src;
+            NRF_QSPI->WRITE.DST = address;
+            /*
+             * Limit write to single page.
+             */
+            if (address + num_bytes > page_limit) {
+                written_bytes = page_limit - address;
+            } else {
+                written_bytes = num_bytes & ~3;
+            }
+            NRF_QSPI->WRITE.CNT = written_bytes;
+        }
+        NRF_QSPI->EVENTS_READY = 0;
+        NRF_QSPI->TASKS_WRITESTART = 1;
+        while (NRF_QSPI->EVENTS_READY == 0)
+            ;
+
+        address += written_bytes;
+        src = (void *) ((uint32_t) src + written_bytes);
+        num_bytes -= written_bytes;
+    }
+    return 0;
+}
+
+static int
+nrf52k_qspi_erase_sector(const struct hal_flash *dev,
+        uint32_t sector_address)
+{
+    while ((NRF_QSPI->STATUS & QSPI_STATUS_READY_Msk) == 0)
+        ;
+    NRF_QSPI->EVENTS_READY = 0;
+    NRF_QSPI->ERASE.PTR = sector_address;
+    NRF_QSPI->ERASE.LEN = MYNEWT_VAL(QSPI_FLASH_SECTOR_SIZE);
+    NRF_QSPI->TASKS_ERASESTART = 1;
+    while (NRF_QSPI->EVENTS_READY == 0)
+        ;
+    return 0;
+}
+
+static int
+nrf52k_qspi_sector_info(const struct hal_flash *dev, int idx,
+        uint32_t *address, uint32_t *sz)
+{
+    *address = idx * MYNEWT_VAL(QSPI_FLASH_SECTOR_SIZE);
+    *sz = MYNEWT_VAL(QSPI_FLASH_SECTOR_SIZE);
+
+    return 0;
+}
+
+static int
+nrf52k_qspi_init(const struct hal_flash *dev)
+{
+    const nrf_qspi_prot_conf_t config0 = {
+            .readoc = MYNEWT_VAL(QSPI_READOC),
+            .writeoc = MYNEWT_VAL(QSPI_WRITEOC),
+            .addrmode = MYNEWT_VAL(QSPI_ADDRMODE),
+            .dpmconfig = MYNEWT_VAL(QSPI_DPMCONFIG)
+    };
+    const nrf_qspi_phy_conf_t config1 = {
+            .sck_delay = MYNEWT_VAL(QSPI_SCK_DELAY),
+            .dpmen = 0,
+            .spi_mode = MYNEWT_VAL(QSPI_SPI_MODE),
+            .sck_freq = MYNEWT_VAL(QSPI_SCK_FREQ),
+    };
+    /*
+     * Configure pins
+     */
+    NRF_QSPI->PSEL.CSN = MYNEWT_VAL(QSPI_PIN_CS);
+    NRF_QSPI->PSEL.SCK = MYNEWT_VAL(QSPI_PIN_SCK);
+    NRF_QSPI->PSEL.IO0 = MYNEWT_VAL(QSPI_PIN_DIO0);
+    NRF_QSPI->PSEL.IO1 = MYNEWT_VAL(QSPI_PIN_DIO1);
+    /*
+     * Setup only known fields of IFCONFIG0. Other bits may be set by erratas code.
+     */
+    nrf_qspi_ifconfig0_set(NRF_QSPI, &config0);
+    nrf_qspi_ifconfig1_set(NRF_QSPI, &config1);
+
+    NRF_QSPI->ENABLE = 1;
+    NRF_QSPI->TASKS_ACTIVATE = 1;
+    while (NRF_QSPI->EVENTS_READY == 0)
+        ;
+
+#if (MYNEWT_VAL(QSPI_READOC) > 2) || (MYNEWT_VAL(QSPI_WRITEOC) > 1)
+    NRF_QSPI->PSEL.IO2 = MYNEWT_VAL(QSPI_PIN_DIO2);
+    NRF_QSPI->PSEL.IO3 = MYNEWT_VAL(QSPI_PIN_DIO3);
+#endif
+
+    return 0;
+}
+
+#endif
diff --git a/hw/mcu/nordic/nrf52xxx/src/system_nrf52.c b/hw/mcu/nordic/nrf52xxx/src/system_nrf52.c
index a813f3b6e..c43cf3618 100644
--- a/hw/mcu/nordic/nrf52xxx/src/system_nrf52.c
+++ b/hw/mcu/nordic/nrf52xxx/src/system_nrf52.c
@@ -51,6 +51,7 @@ static bool errata_98(void);
 static bool errata_103(void);
 static bool errata_115(void);
 static bool errata_120(void);
+static bool errata_121(void);
 #endif
 
 #ifdef NRF52
@@ -245,6 +246,12 @@ void SystemInit(void)
             *(volatile uint32_t *)0x40029640ul = 0x200ul;
         }
 
+        /* Workaround for Errata 120 "QSPI: Second read and long read commands fail" found at the Errata document
+           for your device located at https://infocenter.nordicsemi.com/  */
+        if (errata_121()){
+            *(volatile uint32_t *)0x40029600ul = 0x00040400ul;
+        }
+
         /* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
          * compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
          * operations are not used in your code. */
@@ -475,6 +482,16 @@ static bool errata_120(void)
 
 	return false;
 }
+
+static bool errata_121(void)
+{
+	if ((*(uint32_t *)0x10000130ul == 0x8ul) &&
+			(*(uint32_t *)0x10000134ul == 0x0ul)) {
+		return true;
+	}
+
+	return false;
+}
 #endif
 
 /*lint --flb "Leave library region" */
diff --git a/hw/mcu/nordic/nrf52xxx/syscfg.yml b/hw/mcu/nordic/nrf52xxx/syscfg.yml
index e2a761f87..612503c01 100644
--- a/hw/mcu/nordic/nrf52xxx/syscfg.yml
+++ b/hw/mcu/nordic/nrf52xxx/syscfg.yml
@@ -114,6 +114,78 @@ syscfg.defs:
         description: 'SOFT PWM'
         value: 0
 
+    QSPI_ENABLE:
+        description: 'NRF52 QSPI'
+        value: 0
+
+    QSPI_READOC:
+        description: >
+            QSPI Command to use
+            0 - 0x09 Fast Read
+            1 - 0x3B Fast Read Dual Output
+            2 - 0xBB Fast Read Dual I/O
+            3 - 0x6B Fast Read Quad Output
+            4 - 0xEB Fast Read Quad I/O
+        value: 0
+    QSPI_WRITEOC:
+        description: >
+            QSPI Command to use
+            0 - 0x02 Page program
+            1 - 0xA2 Page program Dual Data
+            2 - 0x32 Page program Quad Data
+            3 - 0x38 Page program Quad I/O
+        value: 0
+    QSPI_ADDRMODE:
+        description: 'Address lentgh 0=24 bits, 1=32 bits'
+        value: 0
+    QSPI_DPMCONFIG:
+        description: 'Deep power mode enable'
+        value: 0
+    QSPI_SCK_DELAY:
+        description: >
+            Minimum amount of time that the CSN pin must stay high
+            before it can go low again. Value is specified in number of 16
+            MHz periods (62.5 ns).
+        value: 0
+    QSPI_SCK_FREQ:
+        description: '32MHz clock divider (0-31). Clock = 32MHz / (1+divider)'
+        value: 0
+    QSPI_SPI_MODE:
+        description: 'SPI 0=Mode0 or 1=Mode3'
+        value: 0
+
+    QSPI_FLASH_SECTOR_SIZE:
+        description: 'QSPI sector size. In most cases it should be 4096.'
+        value: 0
+    QSPI_FLASH_PAGE_SIZE:
+        description: >
+            QSPI page size. Writes can only be perfrmed to one page at a time.
+            In most cases it should be 256.
+        value: 0
+
+    QSPI_FLASH_SECTOR_COUNT:
+        description: 'QSPI sector count'
+        value: -1
+    QSPI_PIN_CS:
+        description: 'CS pin for QSPI'
+        value: -1
+    QSPI_PIN_SCK:
+        description: 'SCK pin for QSPI'
+        value: -1
+    QSPI_PIN_DIO0:
+        description: 'DIO0 pin for QSPI'
+        value: -1
+    QSPI_PIN_DIO1:
+        description: 'DIO1 pin for QSPI'
+        value: -1
+    QSPI_PIN_DIO2:
+        description: 'DIO2 pin for QSPI'
+        value: -1
+    QSPI_PIN_DIO3:
+        description: 'DIO3 pin for QSPI'
+        value: -1
+
+
 # The XTAL_xxx definitions are used to set the clock source used for the low
 # frequency clock. It is required that at least one of these sources is
 # enabled (the bsp should set one of these clock sources).


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services