Initial commit of Silicon Labs QSPI HAL implementation

* For EFM32GG11, since that is the only Silicon Labs target with QSPI per today
* Verified working using the on-board flash and tests-mbed_hal-qspi
pull/7825/head
Steven 2018-08-18 23:22:42 +02:00 committed by Steven Cooreman
parent 2f8e679183
commit 845a5beb30
10 changed files with 674 additions and 2 deletions

View File

@ -0,0 +1,192 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed 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.
*/
#ifndef MBED_QSPI_FLASH_MX25R3235F_H
#define MBED_QSPI_FLASH_MX25R3235F_H
#define QSPI_FLASH_CHIP_STRING "macronix MX25R3235F"
// Command for reading status register
#define QSPI_CMD_RDSR 0x05
// Command for reading configuration register
#define QSPI_CMD_RDCR0 0x15
// Command for writing status/configuration register
#define QSPI_CMD_WRSR 0x01
// Command for reading security register
#define QSPI_CMD_RDSCUR 0x2B
// Command for setting Reset Enable
#define QSPI_CMD_RSTEN 0x66
// Command for setting Reset
#define QSPI_CMD_RST 0x99
// Command for setting write enable
#define QSPI_CMD_WREN 0x06
// Command for setting write disable
#define QSPI_CMD_WRDI 0x04
// WRSR operations max time [us] (datasheet max time + 15%)
#define QSPI_WRSR_MAX_TIME 34500 // 30ms
// general wait max time [us]
#define QSPI_WAIT_MAX_TIME 100000 // 100ms
// Commands for writing (page programming)
#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode
#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode
// write operations max time [us] (datasheet max time + 15%)
#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms
#define QSPI_PAGE_SIZE 256 // 256B
// Commands for reading
#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode
#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode
#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode
#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode
#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode
#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode
#define QSPI_READ_1IO_DUMMY_CYCLE 0
#define QSPI_READ_FAST_DUMMY_CYCLE 8
#define QSPI_READ_2IO_DUMMY_CYCLE 4
#define QSPI_READ_1I2O_DUMMY_CYCLE 8
#define QSPI_READ_4IO_DUMMY_CYCLE 6
#define QSPI_READ_1I4O_DUMMY_CYCLE 8
// Commands for erasing
#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB
#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB
#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB
#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7
// erase operations max time [us] (datasheet max time + 15%)
#define QSPI_ERASE_SECTOR_MAX_TIME 276000 // 240 ms
#define QSPI_ERASE_BLOCK_32_MAX_TIME 3450000 // 3s
#define QSPI_ERASE_BLOCK_64_MAX_TIME 4025000 // 3.5s
// max frequency for basic rw operation
#define QSPI_COMMON_MAX_FREQUENCY 32000000
#define QSPI_STATUS_REG_SIZE 1
#define QSPI_CONFIG_REG_0_SIZE 2
#define QSPI_SECURITY_REG_SIZE 1
#define QSPI_MAX_REG_SIZE 2
// status register
#define STATUS_BIT_WIP (1 << 0) // write in progress bit
#define STATUS_BIT_WEL (1 << 1) // write enable latch
#define STATUS_BIT_BP0 (1 << 2) //
#define STATUS_BIT_BP1 (1 << 3) //
#define STATUS_BIT_BP2 (1 << 4) //
#define STATUS_BIT_BP3 (1 << 5) //
#define STATUS_BIT_QE (1 << 6) // Quad Enable
#define STATUS_BIT_SRWD (1 << 7) // status register write protect
// configuration register 0
// bit 0, 1, 2, 4, 5, 7 reserved
#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect
#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle
// configuration register 1
// bit 0, 2, 3, 4, 5, 6, 7 reserved
#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode
// single quad enable flag for both dual and quad mode
#define QUAD_ENABLE() \
\
uint8_t reg_data[QSPI_STATUS_REG_SIZE]; \
\
if (write_enable(qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
WAIT_FOR(WRSR_MAX_TIME, qspi); \
\
reg_data[0] = STATUS_BIT_QE; \
qspi.cmd.build(QSPI_CMD_WRSR); \
\
if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), \
reg_data, QSPI_STATUS_REG_SIZE, NULL, 0) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
WAIT_FOR(WRSR_MAX_TIME, qspi); \
\
memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \
if (read_register(STATUS_REG, reg_data, \
QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
\
return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \
QSPI_STATUS_OK : QSPI_STATUS_ERROR)
#define QUAD_DISABLE() \
\
uint8_t reg_data[QSPI_STATUS_REG_SIZE]; \
\
if (write_enable(qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
WAIT_FOR(WRSR_MAX_TIME, qspi); \
\
reg_data[0] = 0; \
qspi.cmd.build(QSPI_CMD_WRSR); \
\
if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), \
reg_data, QSPI_STATUS_REG_SIZE, NULL, 0) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
WAIT_FOR(WRSR_MAX_TIME, qspi); \
\
reg_data[0] = 0; \
if (read_register(STATUS_REG, reg_data, \
QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
\
return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \
QSPI_STATUS_OK : QSPI_STATUS_ERROR)
#define FAST_MODE_ENABLE() \
\
qspi_status_t ret; \
const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \
uint8_t reg_data[reg_size]; \
\
if (read_register(STATUS_REG, reg_data, \
QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \
QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \
return QSPI_STATUS_ERROR; \
} \
\
reg_data[2] |= CONFIG1_BIT_LH; \
qspi.cmd.build(QSPI_CMD_WRSR); \
\
return qspi_command_transfer(&qspi.handle, qspi.cmd.get(), \
reg_data, reg_size, NULL, 0)
#endif // MBED_QSPI_FLASH_MX25R3235F_H

View File

@ -0,0 +1,22 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed 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.
*/
#ifndef MBED_QSPI_FLASH_CONFIG_H
#define MBED_QSPI_FLASH_CONFIG_H
#include "../../MX25R3235F_config.h"
#endif // MBED_QSPI_FLASH_CONFIG_H

View File

@ -23,6 +23,8 @@
#include "NORDIC/NRF52840_DK/flash_config.h"
#elif defined(TARGET_DISCO_F413ZH)
#include "STM/DISCO_F413ZH/flash_config.h"
#elif defined(TARGET_EFM32GG11_STK3701)
#include "SiliconLabs/EFM32GG11_STK3701/flash_config.h"
#endif
#endif // MBED_FLASH_CONFIGS_H

View File

@ -136,6 +136,14 @@ typedef enum {
} UARTName;
#endif
#if DEVICE_QSPI
typedef enum {
#ifdef QSPI0_BASE
QSPI_0 = QSPI0_BASE,
#endif
} QSPIName;
#endif
#ifdef __cplusplus
}
#endif

View File

@ -68,5 +68,15 @@ extern const PinMap PinMap_CAN_TX[];
extern const PinMap PinMap_CAN_RX[];
#endif
#if DEVICE_QSPI
/************QSPI**************/
extern const PinMap PinMap_QSPI_DQ0[];
extern const PinMap PinMap_QSPI_DQ1[];
extern const PinMap PinMap_QSPI_DQ2[];
extern const PinMap PinMap_QSPI_DQ3[];
extern const PinMap PinMap_QSPI_SCLK[];
extern const PinMap PinMap_QSPI_CS0[];
#endif
#endif

View File

@ -579,3 +579,53 @@ MBED_WEAK const PinMap PinMap_CAN_RX[] = {
#endif
};
#endif
#if DEVICE_QSPI
MBED_WEAK const PinMap PinMap_QSPI_DQ0[] = {
#ifdef QSPI0_BASE
{PD9, QSPI_0, 0},
{PA2, QSPI_0, 1},
{PG1, QSPI_0, 2},
#endif
};
MBED_WEAK const PinMap PinMap_QSPI_DQ1[] = {
#ifdef QSPI0_BASE
{PD10, QSPI_0, 0},
{PA3, QSPI_0, 1},
{PG2, QSPI_0, 2},
#endif
};
MBED_WEAK const PinMap PinMap_QSPI_DQ2[] = {
#ifdef QSPI0_BASE
{PD11, QSPI_0, 0},
{PA4, QSPI_0, 1},
{PG3, QSPI_0, 2},
#endif
};
MBED_WEAK const PinMap PinMap_QSPI_DQ3[] = {
#ifdef QSPI0_BASE
{PD12, QSPI_0, 0},
{PA5, QSPI_0, 1},
{PG4, QSPI_0, 2},
#endif
};
MBED_WEAK const PinMap PinMap_QSPI_SCLK[] = {
#ifdef QSPI0_BASE
{PF6, QSPI_0, 0},
{PE14, QSPI_0, 1},
{PG0, QSPI_0, 2},
#endif
};
MBED_WEAK const PinMap PinMap_QSPI_CS0[] = {
#ifdef QSPI0_BASE
{PF7, QSPI_0, 0},
{PA0, QSPI_0, 1},
{PG9, QSPI_0, 2},
#endif
};
#endif

View File

@ -76,7 +76,16 @@ typedef enum {
/* Board Controller */
STDIO_UART_TX = USBTX,
STDIO_UART_RX = USBRX
STDIO_UART_RX = USBRX,
/* On-board MX25R3235F */
QSPI_PIN_IO0 = PG1,
QSPI_PIN_IO1 = PG2,
QSPI_PIN_IO2 = PG3,
QSPI_PIN_IO3 = PG4,
QSPI_PIN_SCK = PG0,
QSPI_PIN_CSN = PG9,
} PinName;
#ifdef __cplusplus

View File

@ -154,6 +154,18 @@ struct can_s {
};
#endif
#if DEVICE_QSPI
struct qspi_s {
QSPI_TypeDef *instance;
PinName io0;
PinName io1;
PinName io2;
PinName io3;
PinName sclk;
PinName ssel;
};
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,362 @@
/***************************************************************************//**
* @file rtc_rtcc.c
*******************************************************************************
* @section License
* <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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 "device.h"
#if DEVICE_QSPI && defined(QSPI_PRESENT)
#include "stddef.h"
#include "qspi_api.h"
#include "mbed_error.h"
#include "em_cmu.h"
#include "em_qspi.h"
#include "pinmap.h"
#include "PeripheralPins.h"
#include "pinmap_function.h"
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)
{
#if defined(QSPI_FLASH_EN)
pin_mode(QSPI_FLASH_EN, PushPull);
GPIO_PinOutSet((GPIO_Port_TypeDef)(QSPI_FLASH_EN >> 4 & 0xF), QSPI_FLASH_EN & 0xF);
#endif
// There's only one QSPI per chip for now
obj->instance = QSPI0;
obj->io0 = io0;
obj->io1 = io1;
obj->io2 = io2;
obj->io3 = io3;
obj->ssel = ssel;
obj->sclk = sclk;
CMU_ClockEnable(cmuClock_GPIO, true);
#if (CORE_CLOCK_SOURCE == HFXO)
CMU_ClockSelectSet(cmuClock_QSPI0REF, cmuSelect_HFXO);
#endif
CMU_ClockEnable(cmuClock_QSPI0, true);
CMU_ClockEnable(cmuClock_QSPI0REF, true);
qspi_frequency(obj, hz);
if (mode) {
obj->instance->CONFIG |= QSPI_CONFIG_SELCLKPOL | QSPI_CONFIG_SELCLKPHASE;
} else {
obj->instance->CONFIG &= ~(QSPI_CONFIG_SELCLKPOL | QSPI_CONFIG_SELCLKPHASE);
}
uint32_t loc = pin_location(io0, PinMap_QSPI_DQ0);
if (loc != pin_location(io1, PinMap_QSPI_DQ1) ||
loc != pin_location(io2, PinMap_QSPI_DQ2) ||
loc != pin_location(io3, PinMap_QSPI_DQ3) ||
loc != pin_location(sclk, PinMap_QSPI_SCLK) ||
loc != pin_location(ssel, PinMap_QSPI_CS0)) {
// All pins need to be on the same location number
qspi_free(obj);
return QSPI_STATUS_INVALID_PARAMETER;
}
// Configure QSPI pins
GPIO_PinOutClear((GPIO_Port_TypeDef)(io0 >> 4 & 0xF), io0 & 0xF);
pin_mode(io0, PushPull);
GPIO_PinOutClear((GPIO_Port_TypeDef)(io1 >> 4 & 0xF), io1 & 0xF);
pin_mode(io1, PushPull);
GPIO_PinOutClear((GPIO_Port_TypeDef)(io2 >> 4 & 0xF), io2 & 0xF);
pin_mode(io2, PushPull);
GPIO_PinOutClear((GPIO_Port_TypeDef)(io3 >> 4 & 0xF), io3 & 0xF);
pin_mode(io3, PushPull);
GPIO_PinOutClear((GPIO_Port_TypeDef)(sclk >> 4 & 0xF), sclk & 0xF);
pin_mode(sclk, PushPull);
GPIO_PinOutSet((GPIO_Port_TypeDef)(ssel >> 4 & 0xF), ssel & 0xF);
pin_mode(ssel, PushPull);
// Configure QSPI routing to GPIO
obj->instance->ROUTELOC0 = loc;
obj->instance->ROUTEPEN = QSPI_ROUTEPEN_SCLKPEN
| QSPI_ROUTEPEN_CS0PEN
| QSPI_ROUTEPEN_DQ0PEN
| QSPI_ROUTEPEN_DQ1PEN
| QSPI_ROUTEPEN_DQ2PEN
| QSPI_ROUTEPEN_DQ3PEN;
// Configure direct read
QSPI_ReadConfig_TypeDef readConfig = QSPI_READCONFIG_DEFAULT;
QSPI_ReadConfig(obj->instance, &readConfig);
// Configure direct write
QSPI_WriteConfig_TypeDef writeConfig = QSPI_WRITECONFIG_DEFAULT;
QSPI_WriteConfig(obj->instance, &writeConfig);
return QSPI_STATUS_OK;
}
qspi_status_t qspi_free(qspi_t *obj)
{
pin_mode(obj->io0, Disabled);
pin_mode(obj->io1, Disabled);
pin_mode(obj->io2, Disabled);
pin_mode(obj->io3, Disabled);
pin_mode(obj->ssel, Disabled);
pin_mode(obj->sclk, Disabled);
obj->instance->ROUTEPEN = 0;
QSPI_Enable(obj->instance, false);
CMU_ClockEnable(cmuClock_QSPI0REF, false);
CMU_ClockEnable(cmuClock_QSPI0, false);
return QSPI_STATUS_OK;
}
qspi_status_t qspi_frequency(qspi_t *obj, int hz)
{
if (hz <= 0) {
return QSPI_STATUS_INVALID_PARAMETER;
}
QSPI_Enable(obj->instance, false);
// Need at least a DIV4 for non-PHY mode and SDR transfers
uint32_t basefreq = CMU_ClockFreqGet(cmuClock_QSPI0REF);
uint32_t basediv = 4;
if ((uint32_t)hz < (basefreq / basediv)) {
basediv = (basefreq / hz) + 1;
}
QSPI_Init_TypeDef initQspi = QSPI_INIT_DEFAULT;
initQspi.divisor = basediv;
QSPI_Init(obj->instance, &initQspi);
return QSPI_STATUS_OK;
}
qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length)
{
QSPI_WriteConfig_TypeDef cfg = QSPI_WRITECONFIG_DEFAULT;
uint32_t to_write = *length;
// Enforce word-aligned and word-sized access
if ((to_write & 0x3) != 0 || ((uint32_t)data & 0x3) != 0) {
return QSPI_STATUS_INVALID_PARAMETER;
}
cfg.dummyCycles = command->dummy_count;
if (command->instruction.disabled) {
cfg.opCode = 0x02;
} else {
cfg.opCode = command->instruction.value;
}
if (command->address.disabled) {
return QSPI_STATUS_INVALID_PARAMETER;
} else {
if (command->address.bus_width == QSPI_CFG_BUS_SINGLE) {
cfg.addrTransfer = qspiTransferSingle;
} else if (command->address.bus_width == QSPI_CFG_BUS_DUAL) {
cfg.addrTransfer = qspiTransferDual;
} else if (command->address.bus_width == QSPI_CFG_BUS_QUAD) {
cfg.addrTransfer = qspiTransferQuad;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
}
}
if (command->data.bus_width == QSPI_CFG_BUS_SINGLE) {
cfg.dataTransfer = qspiTransferSingle;
} else if (command->data.bus_width == QSPI_CFG_BUS_DUAL) {
cfg.dataTransfer = qspiTransferDual;
} else if (command->data.bus_width == QSPI_CFG_BUS_QUAD) {
cfg.dataTransfer = qspiTransferQuad;
}
QSPI_WriteConfig(obj->instance, &cfg);
if (!command->alt.disabled) {
// Do not support alt mode in write mode
return QSPI_STATUS_INVALID_PARAMETER;
}
// Do an indirect write
obj->instance->INDAHBADDRTRIGGER = QSPI0_MEM_BASE;
obj->instance->INDIRECTWRITEXFERSTART = command->address.value;
obj->instance->INDIRECTWRITEXFERNUMBYTES = to_write;
obj->instance->INDIRECTWRITEXFERCTRL = QSPI_INDIRECTWRITEXFERCTRL_START;
// For the size of the transfer, poll the SRAM and fetch words from the SRAM
for (uint32_t i = 0; i < to_write; i+=4) {
// Wait for the QSPI in case we're writing too fast
while (((obj->instance->SRAMFILL & _QSPI_SRAMFILL_SRAMFILLINDACWRITE_MASK) >> _QSPI_SRAMFILL_SRAMFILLINDACWRITE_SHIFT) >= 126);
*((uint32_t*)QSPI0_MEM_BASE) = ((uint32_t*)data)[i/4];
}
return QSPI_STATUS_OK;
}
qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size)
{
QSPI_StigCmd_TypeDef cfg;
if (tx_size > 8 || rx_size > 8) {
return QSPI_STATUS_INVALID_PARAMETER;
}
cfg.writeDataSize = tx_size;
cfg.writeBuffer = (void*)tx_data;
cfg.readDataSize = rx_size;
cfg.readBuffer = rx_data;
if (command->address.disabled) {
cfg.addrSize = 0;
cfg.address = 0;
} else {
if (command->address.size == QSPI_CFG_ADDR_SIZE_8) {
cfg.addrSize = 1;
} else if (command->address.size == QSPI_CFG_ADDR_SIZE_16) {
cfg.addrSize = 2;
} else if (command->address.size == QSPI_CFG_ADDR_SIZE_24) {
cfg.addrSize = 3;
} else if (command->address.size == QSPI_CFG_ADDR_SIZE_32) {
cfg.addrSize = 4;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
}
cfg.address = command->address.value;
}
if (command->instruction.disabled) {
return QSPI_STATUS_INVALID_PARAMETER;
} else {
cfg.cmdOpcode = command->instruction.value;
}
cfg.dummyCycles = command->dummy_count;
if (!command->alt.disabled) {
cfg.modeBitEnable = true;
obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK;
if(command->alt.size != QSPI_CFG_ALT_SIZE_8) {
//do not support 'alt' bigger than 8 bit
return QSPI_STATUS_INVALID_PARAMETER;
}
} else {
cfg.modeBitEnable = false;
}
QSPI_ExecStigCmd(obj->instance, &cfg);
return QSPI_STATUS_OK;
}
qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length)
{
QSPI_ReadConfig_TypeDef cfg = QSPI_READCONFIG_DEFAULT;
uint32_t to_read = *length;
// Enforce word-aligned and word-sized access
if ((to_read & 0x3) != 0 || ((uint32_t)data & 0x3) != 0) {
return QSPI_STATUS_INVALID_PARAMETER;
}
cfg.dummyCycles = command->dummy_count;
if (command->instruction.disabled) {
cfg.opCode = 0x03;
cfg.instTransfer = qspiTransferSingle;
} else {
cfg.opCode = command->instruction.value;
if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE) {
cfg.instTransfer = qspiTransferSingle;
} else if (command->instruction.bus_width == QSPI_CFG_BUS_DUAL) {
cfg.instTransfer = qspiTransferDual;
} else if (command->instruction.bus_width == QSPI_CFG_BUS_QUAD) {
cfg.instTransfer = qspiTransferQuad;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
}
}
if (command->address.disabled) {
return QSPI_STATUS_INVALID_PARAMETER;
} else {
if (command->address.bus_width == QSPI_CFG_BUS_SINGLE) {
cfg.addrTransfer = qspiTransferSingle;
} else if (command->address.bus_width == QSPI_CFG_BUS_DUAL) {
cfg.addrTransfer = qspiTransferDual;
} else if (command->address.bus_width == QSPI_CFG_BUS_QUAD) {
cfg.addrTransfer = qspiTransferQuad;
} else {
return QSPI_STATUS_INVALID_PARAMETER;
}
}
if (command->data.bus_width == QSPI_CFG_BUS_SINGLE) {
cfg.dataTransfer = qspiTransferSingle;
} else if (command->data.bus_width == QSPI_CFG_BUS_DUAL) {
cfg.dataTransfer = qspiTransferDual;
} else if (command->data.bus_width == QSPI_CFG_BUS_QUAD) {
cfg.dataTransfer = qspiTransferQuad;
}
QSPI_ReadConfig(obj->instance, &cfg);
if (!command->alt.disabled) {
// Need to set up alt mode manually, called 'mode bits' in EFM32GG11 refman
obj->instance->DEVINSTRRDCONFIG |= QSPI_DEVINSTRRDCONFIG_MODEBITENABLE;
obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK;
if(command->alt.size != QSPI_CFG_ALT_SIZE_8) {
// Do not support 'alt' bigger than 8 bit
return QSPI_STATUS_INVALID_PARAMETER;
}
}
// Do an indirect read
obj->instance->INDAHBADDRTRIGGER = QSPI0_MEM_BASE;
obj->instance->INDIRECTREADXFERSTART = command->address.value;
obj->instance->INDIRECTREADXFERNUMBYTES = to_read;
obj->instance->INDIRECTREADXFERCTRL = QSPI_INDIRECTREADXFERCTRL_START;
// For the size of the transfer, poll the SRAM and fetch words from the SRAM
for (uint32_t i = 0; i < to_read; i+=4) {
// Wait for the FIFO in case we're reading too fast
while ((obj->instance->SRAMFILL & _QSPI_SRAMFILL_SRAMFILLINDACREAD_MASK) >> _QSPI_SRAMFILL_SRAMFILLINDACREAD_SHIFT == 0);
((uint32_t*)data)[i/4] = *((uint32_t*)QSPI0_MEM_BASE);
}
return QSPI_STATUS_OK;
}
#endif /* DEVICE_QSPI && QSPI_PRESENT */

View File

@ -3628,7 +3628,7 @@
"EFM32GG11_STK3701": {
"inherits": ["EFM32GG11B820F2048GL192"],
"device_name": "EFM32GG11B820F2048GL192",
"device_has": ["ANALOGIN", "CRC", "EMAC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"],
"device_has": ["ANALOGIN", "CRC", "EMAC", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "QSPI", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "USTICKER", "TRNG", "FLASH"],
"forced_reset_timeout": 5,
"config": {
"hf_clock_src": {
@ -3665,6 +3665,11 @@
"help": "Pin to pull high for enabling the USB serial port",
"value": "PE1",
"macro_name": "EFM_BC_EN"
},
"qspi_flash_enable": {
"help": "Pin to pull high for enabling the on-board QSPI flash",
"value": "PG13",
"macro_name": "QSPI_FLASH_EN"
}
}
},