From d1b51b6328623dcd88b926e5ad668a5c7d74d9ca Mon Sep 17 00:00:00 2001
From: Martin Kojtal <0xc0170@gmail.com>
Date: Fri, 10 Nov 2017 12:24:13 +0000
Subject: [PATCH] QSPI: initial HAL nrf52840 version
This commit adds QSPI HAL implementation for nrf52840 MCU targets
---
.../TARGET_MCU_NRF52840/config/sdk_config.h | 130 +++++++++++
.../TARGET_NRF5x/TARGET_NRF52/objects.h | 11 +
targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c | 214 ++++++++++++++++++
targets/targets.json | 3 +-
4 files changed, 357 insertions(+), 1 deletion(-)
create mode 100644 targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c
diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/config/sdk_config.h b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/config/sdk_config.h
index 201402a18e..203602ec0a 100644
--- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/config/sdk_config.h
+++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/config/sdk_config.h
@@ -2748,6 +2748,136 @@
//
+// QSPI_ENABLED - nrf_drv_qspi - QSPI peripheral driver.
+//==========================================================
+#ifndef QSPI_ENABLED
+#define QSPI_ENABLED 1
+#endif
+#if QSPI_ENABLED
+// QSPI_CONFIG_SCK_DELAY - tSHSL, tWHSL and tSHWL in number of 16 MHz periods (62.5 ns). <0-255>
+
+
+#ifndef QSPI_CONFIG_SCK_DELAY
+#define QSPI_CONFIG_SCK_DELAY 1
+#endif
+
+// QSPI_CONFIG_READOC - Number of data lines and opcode used for reading.
+
+// <0=> FastRead
+// <1=> Read2O
+// <2=> Read2IO
+// <3=> Read4O
+// <4=> Read4IO
+
+#ifndef QSPI_CONFIG_READOC
+#define QSPI_CONFIG_READOC 4
+#endif
+
+// QSPI_CONFIG_WRITEOC - Number of data lines and opcode used for writing.
+
+// <0=> PP
+// <1=> PP2O
+// <2=> PP4O
+// <3=> PP4IO
+
+#ifndef QSPI_CONFIG_WRITEOC
+#define QSPI_CONFIG_WRITEOC 3
+#endif
+
+// QSPI_CONFIG_ADDRMODE - Addressing mode.
+
+// <0=> 24bit
+// <1=> 32bit
+
+#ifndef QSPI_CONFIG_ADDRMODE
+#define QSPI_CONFIG_ADDRMODE 0
+#endif
+
+// QSPI_CONFIG_MODE - SPI mode.
+
+// <0=> Mode 0
+// <1=> Mode 1
+
+#ifndef QSPI_CONFIG_MODE
+#define QSPI_CONFIG_MODE 0
+#endif
+
+// QSPI_CONFIG_FREQUENCY - Frequency divider.
+
+// <0=> 32MHz/1
+// <1=> 32MHz/2
+// <2=> 32MHz/3
+// <3=> 32MHz/4
+// <4=> 32MHz/5
+// <5=> 32MHz/6
+// <6=> 32MHz/7
+// <7=> 32MHz/8
+// <8=> 32MHz/9
+// <9=> 32MHz/10
+// <10=> 32MHz/11
+// <11=> 32MHz/12
+// <12=> 32MHz/13
+// <13=> 32MHz/14
+// <14=> 32MHz/15
+// <15=> 32MHz/16
+
+#ifndef QSPI_CONFIG_FREQUENCY
+#define QSPI_CONFIG_FREQUENCY 1
+#endif
+
+// QSPI_PIN_SCK - SCK pin value.
+#ifndef QSPI_PIN_SCK
+#define QSPI_PIN_SCK NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_PIN_CSN - CSN pin value.
+#ifndef QSPI_PIN_CSN
+#define QSPI_PIN_CSN NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_PIN_IO0 - IO0 pin value.
+#ifndef QSPI_PIN_IO0
+#define QSPI_PIN_IO0 NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_PIN_IO1 - IO1 pin value.
+#ifndef QSPI_PIN_IO1
+#define QSPI_PIN_IO1 NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_PIN_IO2 - IO2 pin value.
+#ifndef QSPI_PIN_IO2
+#define QSPI_PIN_IO2 NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_PIN_IO3 - IO3 pin value.
+#ifndef QSPI_PIN_IO3
+#define QSPI_PIN_IO3 NRF_QSPI_PIN_NOT_CONNECTED
+#endif
+
+// QSPI_CONFIG_IRQ_PRIORITY - Interrupt priority
+
+
+// Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
+// <0=> 0 (highest)
+// <1=> 1
+// <2=> 2
+// <3=> 3
+// <4=> 4
+// <5=> 5
+// <6=> 6
+// <7=> 7
+
+#ifndef QSPI_CONFIG_IRQ_PRIORITY
+#define QSPI_CONFIG_IRQ_PRIORITY 7
+#endif
+
+#endif //QSPI_ENABLED
+
+//
+
+//
+
// TIMER_ENABLED - nrf_drv_timer - TIMER periperal driver
//==========================================================
#ifndef TIMER_ENABLED
diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h
index 47e6276a82..1a26f28db4 100644
--- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h
+++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h
@@ -142,6 +142,17 @@ struct flash_s {
uint32_t placeholder;
};
+#if DEVICE_QSPI
+
+// #include "nrf_drv_qspi.h"
+
+struct qspi_s {
+ uint32_t placeholder;
+ // nrf_drv_qspi_config_t config;
+};
+
+#endif
+
#include "gpio_object.h"
#ifdef __cplusplus
diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c
new file mode 100644
index 0000000000..b3f547e074
--- /dev/null
+++ b/targets/TARGET_NORDIC/TARGET_NRF5x/qspi_api.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017 Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic Semiconductor ASA
+ * integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary or object form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OR CONTRIBUTORS 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 "qspi_api.h"
+
+#if DEVICE_QSPI
+
+#include "nrf_drv_common.h"
+#include "nrf_drv_qspi.h"
+
+/*
+TODO
+ - config inside obj - nordic headers have some problems with inclusion
+ - free - is it really empty, nothing to do there?
+ - prepare command - support more protocols that nordic can do (now limited)
+ - nordic does not support
+ - alt
+ - dummy cycles
+*/
+
+#define MBED_HAL_QSPI_HZ_TO_CONFIG(hz) ((32000000/(hz))-1)
+#define MBED_HAL_QSPI_MAX_FREQ 32000000UL
+
+static nrf_drv_qspi_config_t config;
+
+qspi_status_t qspi_prepare_command(qspi_t *obj, const qspi_command_t *command, bool write)
+{
+ // we need to remap to command-address-data - x_x_x
+ // most commmon are 1-1-1, 1-1-4, 1-4-4
+ // 1-1-1
+ if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE &&
+ command->address.bus_width == QSPI_CFG_BUS_SINGLE &&
+ command->data.bus_width == QSPI_CFG_BUS_SINGLE) {
+ if (write) {
+ config.prot_if.writeoc = NRF_QSPI_WRITEOC_PP;
+ } else {
+ config.prot_if.readoc = NRF_QSPI_READOC_FASTREAD;
+ }
+ // 1-1-4
+ } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE &&
+ command->address.bus_width == QSPI_CFG_BUS_SINGLE &&
+ command->data.bus_width == QSPI_CFG_BUS_QUAD) {
+ // 1_1_4
+ if (write) {
+ config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4O;
+ } else {
+ config.prot_if.readoc = NRF_QSPI_READOC_READ4O;
+ }
+ // 1-4-4
+ } else if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE &&
+ command->address.bus_width == QSPI_CFG_BUS_QUAD &&
+ command->data.bus_width == QSPI_CFG_BUS_QUAD) {
+ // 1_4_4
+ if (write) {
+ config.prot_if.writeoc = QSPI_IFCONFIG0_WRITEOC_PP4IO;
+ } else {
+ config.prot_if.readoc = NRF_QSPI_READOC_READ4IO;
+ }
+ }
+
+ qspi_status_t ret = QSPI_STATUS_OK;
+
+ // supporting only 24 or 32 bit address
+ if (command->address.size == QSPI_CFG_ADDR_SIZE_24) {
+ config.prot_if.addrmode = NRF_QSPI_ADDRMODE_24BIT;
+ } else if (command->address.size == QSPI_CFG_ADDR_SIZE_32) {
+ config.prot_if.addrmode = QSPI_CFG_ADDR_SIZE_32;
+ } else {
+ ret = QSPI_STATUS_INVALID_PARAMETER;
+ }
+ return ret;
+}
+
+qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode)
+{
+ (void)(obj);
+ if (hz > MBED_HAL_QSPI_MAX_FREQ) {
+ return QSPI_STATUS_INVALID_PARAMETER;
+ }
+
+ // memset(config, 0, sizeof(config));
+
+ config.pins.sck_pin = (uint32_t)sclk;
+ config.pins.csn_pin = (uint32_t)ssel;
+ config.pins.io0_pin = (uint32_t)io0;
+ config.pins.io1_pin = (uint32_t)io1;
+ config.pins.io2_pin = (uint32_t)io2;
+ config.pins.io3_pin = (uint32_t)io3;
+ config.irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY;
+
+ config.phy_if.sck_freq = MBED_HAL_QSPI_HZ_TO_CONFIG(hz),
+ config.phy_if.sck_delay = 0x05,
+ config.phy_if.dpmen = false;
+ config.phy_if.spi_mode = mode == 0 ? NRF_QSPI_MODE_0 : NRF_QSPI_MODE_1;
+
+ nrf_drv_qspi_init(&config, NULL , NULL);
+
+ return 0;
+}
+
+qspi_status_t qspi_free(qspi_t *obj)
+{
+ (void)(obj);
+ // possibly here uninit from SDK driver
+ return QSPI_STATUS_OK;
+}
+
+qspi_status_t qspi_frequency(qspi_t *obj, int hz)
+{
+ config.phy_if.sck_freq = MBED_HAL_QSPI_HZ_TO_CONFIG(hz);
+ // use sync version, no handler
+ ret_code_t ret = nrf_drv_qspi_init(&config, NULL , NULL);
+ if (ret == NRF_SUCCESS ) {
+ return QSPI_STATUS_OK;
+ } else if (ret == NRF_ERROR_INVALID_PARAM) {
+ return QSPI_STATUS_INVALID_PARAMETER;
+ } else {
+ return QSPI_STATUS_ERROR;
+ }
+}
+
+qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length)
+{
+ qspi_status_t status = qspi_prepare_command(obj, command, true);
+ if (status != QSPI_STATUS_OK) {
+ return status;
+ }
+
+ // write here does not return how much it transfered, we return transfered all
+ ret_code_t ret = nrf_drv_qspi_write(data, *length, command->address.value);
+ if (ret == NRF_SUCCESS ) {
+ return QSPI_STATUS_OK;
+ } else {
+ return QSPI_STATUS_ERROR;
+ }
+}
+
+qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length)
+{
+ qspi_status_t status = qspi_prepare_command(obj, command, false);
+ if (status != QSPI_STATUS_OK) {
+ return status;
+ }
+
+ ret_code_t ret = nrf_drv_qspi_read(data, *length, command->address.value);
+ if (ret == NRF_SUCCESS ) {
+ return QSPI_STATUS_OK;
+ } else {
+ return QSPI_STATUS_ERROR;
+ }
+}
+
+// they provide 2 functions write or nrf_drv_qspi_cinstr_xfer
+// nrf_drv_qspi_cinstr_xfer seems like it accepts simplified config that is very simplified
+// and might not be useful for us.
+// write on other hand, needs to write some data (errors if buffer is NULL!)
+qspi_status_t qspi_write_command(qspi_t *obj, const qspi_command_t *command)
+{
+ // use simplified API, as we are sending only instruction here
+ nrf_qspi_cinstr_conf_t config;
+ config.length = NRF_QSPI_CINSTR_LEN_1B; // no data
+ config.opcode = command->instruction.value;
+ config.io2_level = false;
+ config.io3_level = false;
+ config.wipwait = false;
+ config.wren = false;
+
+ // no data phase, send only config
+ ret_code_t ret = nrf_drv_qspi_cinstr_xfer(&config, NULL, NULL);
+ if (ret == NRF_SUCCESS ) {
+ return QSPI_STATUS_OK;
+ } else {
+ return QSPI_STATUS_ERROR;
+ }
+}
+
+#endif
+
+/** @}*/
diff --git a/targets/targets.json b/targets/targets.json
index 85b6623557..88c57e7871 100755
--- a/targets/targets.json
+++ b/targets/targets.json
@@ -3873,7 +3873,8 @@
"SPI_ASYNCH",
"STCLK_OFF_DURING_SLEEP",
"TRNG",
- "USTICKER"
+ "USTICKER",
+ "QSPI"
],
"extra_labels": [
"NORDIC",