aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/ex/Micron/m25q.c181
-rw-r--r--os/ex/Micron/m25q.h27
-rw-r--r--os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c16
-rw-r--r--os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h22
4 files changed, 219 insertions, 27 deletions
diff --git a/os/ex/Micron/m25q.c b/os/ex/Micron/m25q.c
index 9a170a17f..84a67f2cc 100644
--- a/os/ex/Micron/m25q.c
+++ b/os/ex/Micron/m25q.c
@@ -25,8 +25,9 @@
* @{
*/
-#include "hal.h"
+#include <string.h>
+#include "hal.h"
#include "m25q.h"
/*===========================================================================*/
@@ -82,11 +83,7 @@ static flash_descriptor_t descriptor = {
.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
.page_size = 256U,
-#if M25Q_USE_SUB_SECTORS == TRUE
- .sectors_count = 4096U,
-#else
- .sectors_count = 256U,
-#endif
+ .sectors_count = 0U, /* It is overwritten.*/
.sectors = NULL,
.sectors_size = SECTOR_SIZE,
.address = 0U
@@ -209,9 +206,11 @@ static const uint8_t evconf_value[1] = {0xCF};
#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
static const uint8_t evconf_value[1] = {0x8F};
#else
-static const uint8_t evconf_value[1] = {0xCF};//{0x4F};
+static const uint8_t evconf_value[1] = {0x4F};
#endif
+static const uint8_t flash_status[1] = {(M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU};
+
#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
/*===========================================================================*/
@@ -314,6 +313,39 @@ static void flash_cmd_receive(M25QDriver *devp,
#endif
}
+static void flash_cmd_send(M25QDriver *devp,
+ uint8_t cmd,
+ size_t n,
+ const uint8_t *p) {
+#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI
+ qspi_command_t mode;
+
+ mode.cfg = QSPI_CFG_CMD(cmd) |
+#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_DATA_MODE_ONE_LINE;
+#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES |
+ QSPI_CFG_DATA_MODE_TWO_LINES;
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES |
+ QSPI_CFG_DATA_MODE_FOUR_LINES;
+
+#endif
+ mode.addr = 0U;
+ mode.alt = 0U;
+ qspiSend(devp->config->qspip, &mode, n, p);
+#else
+ uint8_t buf[1];
+
+ spiSelect(devp->config->spip);
+ buf[0] = cmd;
+ spiSend(devp->config->spip, 1, buf);
+ spiSend(devp->config->spip, n, p);
+ spiUnselect(devp->config->spip);
+#endif
+}
+
static void flash_cmd_addr(M25QDriver *devp,
uint8_t cmd,
flash_address_t addr) {
@@ -437,6 +469,42 @@ static void flash_cmd_addr_receive(M25QDriver *devp,
#endif
}
+#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) || defined(__DOXYGEN__)
+static void flash_cmd_addr_dummy_receive(M25QDriver *devp,
+ uint8_t cmd,
+ flash_address_t addr,
+ uint8_t dummy,
+ size_t n,
+ uint8_t *p) {
+ qspi_command_t mode;
+
+ mode.cfg = QSPI_CFG_CMD(cmd) |
+#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L
+ QSPI_CFG_CMD_MODE_ONE_LINE |
+ QSPI_CFG_ADDR_MODE_ONE_LINE |
+ QSPI_CFG_ADDR_SIZE_24 |
+ QSPI_CFG_DUMMY_CYCLES(dummy) |
+ QSPI_CFG_DATA_MODE_ONE_LINE;
+#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L
+ QSPI_CFG_CMD_MODE_TWO_LINES |
+ QSPI_CFG_ADDR_MODE_TWO_LINES |
+ QSPI_CFG_ADDR_SIZE_24 |
+ QSPI_CFG_DUMMY_CYCLES(dummy) |
+ QSPI_CFG_DATA_MODE_TWO_LINES;
+#else
+ QSPI_CFG_CMD_MODE_FOUR_LINES |
+ QSPI_CFG_ADDR_MODE_FOUR_LINES |
+ QSPI_CFG_ADDR_SIZE_24 |
+ QSPI_CFG_DUMMY_CYCLES(dummy) |
+ QSPI_CFG_DATA_MODE_FOUR_LINES;
+
+#endif
+ mode.addr = addr;
+ mode.alt = 0U;
+ qspiReceive(devp->config->qspip, &mode, n, p);
+}
+#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
+
static flash_error_t flash_poll_status(M25QDriver *devp) {
return FLASH_NO_ERROR;
@@ -454,6 +522,38 @@ static const flash_descriptor_t *get_descriptor(void *instance) {
static flash_error_t read(void *instance, flash_address_t addr,
uint8_t *rp, size_t n) {
+ M25QDriver *devp = (M25QDriver *)instance;
+
+ osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
+ osalDbgCheck((size_t)addr + n <= (size_t)descriptor.sectors_count *
+ (size_t)descriptor.sectors_size);
+ osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
+ "invalid state");
+
+ if (devp->state == FLASH_ERASE) {
+ return FLASH_BUSY_ERASING;
+ }
+
+ /* Bus acquired.*/
+ flash_bus_acquire(devp);
+
+ /* FLASH_READY state while the operation is performed.*/
+ devp->state = FLASH_READ;
+
+#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI
+ /* Fast read command in QSPI mode.*/
+ flash_cmd_addr_dummy_receive(devp, M25Q_CMD_FAST_READ,
+ addr, M25Q_READ_DUMMY_CYCLES,
+ n, rp);
+#else
+ /* Normal read command in SPI mode.*/
+#endif
+
+ /* Ready state again.*/
+ devp->state = FLASH_READY;
+
+ /* Bus released.*/
+ flash_bus_release(devp);
return FLASH_NO_ERROR;
}
@@ -516,6 +616,18 @@ void m25qObjectInit(M25QDriver *devp) {
#endif
}
+static const qspi_command_t cmd_test_reset_enable_4 = {
+ .cfg = QSPI_CFG_ALT_MODE_FOUR_LINES,
+ .addr = 0,
+ .alt = M25Q_CMD_RESET_ENABLE
+};
+
+static const qspi_command_t cmd_test_reset_memory_4 = {
+ .cfg = QSPI_CFG_ALT_MODE_FOUR_LINES,
+ .addr = 0,
+ .alt = M25Q_CMD_RESET_MEMORY
+};
+
/**
* @brief Configures and activates N25Q128 driver.
*
@@ -532,7 +644,6 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {
devp->config = config;
if (devp->state == FLASH_STOP) {
- uint8_t id[3];
/* Bus acquisition.*/
flash_bus_acquire(devp);
@@ -546,46 +657,62 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {
/* QSPI initialization.*/
qspiStart(devp->config->qspip, devp->config->qspicfg);
+ /* Reading device ID and unique ID.*/
+
#if M25Q_SWITCH_WIDTH == TRUE
- /* Attempting a device reset with decreasing bus widths, commands
+ /* Attempting a device reset with different bus widths, commands
shorter than 8 bits are ignored.*/
- qspiCommand(devp->config->qspip, &cmd_reset_enable_4);
- qspiCommand(devp->config->qspip, &cmd_reset_memory_4);
- qspiCommand(devp->config->qspip, &cmd_reset_enable_2);
- qspiCommand(devp->config->qspip, &cmd_reset_memory_2);
qspiCommand(devp->config->qspip, &cmd_reset_enable_1);
qspiCommand(devp->config->qspip, &cmd_reset_memory_1);
+ qspiCommand(devp->config->qspip, &cmd_reset_enable_2);
+ qspiCommand(devp->config->qspip, &cmd_reset_memory_2);
+ qspiCommand(devp->config->qspip, &cmd_reset_enable_4);
+ qspiCommand(devp->config->qspip, &cmd_reset_memory_4);
#endif
- /* Reading device ID.*/
- qspiReceive(devp->config->qspip, &cmd_read_id, 3, id);
+ /* Reading device ID and unique ID.*/
+ qspiReceive(devp->config->qspip, &cmd_read_id,
+ sizeof devp->device_id, devp->device_id);
#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */
/* Checking if the device is white listed.*/
- osalDbgAssert(find_id(manufacturer_ids, sizeof manufacturer_ids, id[0]),
+ osalDbgAssert(find_id(manufacturer_ids,
+ sizeof manufacturer_ids,
+ devp->device_id[0]),
"invalid manufacturer id");
- osalDbgAssert(find_id(memory_type_ids, sizeof memory_type_ids, id[1]),
+ osalDbgAssert(find_id(memory_type_ids,
+ sizeof memory_type_ids,
+ devp->device_id[1]),
"invalid memory type id");
#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
/* Setting up final bus width.*/
qspiCommand(devp->config->qspip, &cmd_write_enable);
qspiSend(devp->config->qspip, &cmd_write_evconf, 1, evconf_value);
-#endif
- flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id);
+ {
+ uint8_t id[3];
- flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id);
+ /* Reading ID again for confirmation.*/
+ flash_cmd_receive(devp, M25Q_CMD_MULTIPLE_IO_READ_ID, 3, id);
- /* Reading device ID.*/
- qspiReceive(devp->config->qspip, &cmd_read_id, 3, id);
+ /* Checking if the device is white listed.*/
+ osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
+ "id confirmation failed");
+ }
+#endif
- /* Reset Enable command.*/
-// flash_short_cmd(devp, M25Q_CMD_RESET_ENABLE);
+ /* Setting up the device size.*/
+ descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) / SECTOR_SIZE;
- /* Reset Memory command.*/
-// flash_short_cmd(devp, M25Q_CMD_RESET_MEMORY);
+#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI)
+ /* Setting up the dummy cycles to be used for rast read operations.*/
+ flash_cmd(devp, M25Q_CMD_WRITE_ENABLE);
+ flash_cmd_send(devp, M25Q_CMD_WRITE_V_CONF_REGISTER,
+ 1, flash_status);
+#endif
+ /* Driver in ready state.*/
devp->state = FLASH_READY;
/* Bus release.*/
@@ -617,6 +744,8 @@ void m25qStop(M25QDriver *devp) {
#endif
devp->config = NULL;
+
+ /* Driver stopped.*/
devp->state = FLASH_STOP;
/* Bus release.*/
diff --git a/os/ex/Micron/m25q.h b/os/ex/Micron/m25q.h
index 27ee06afc..865cc32ea 100644
--- a/os/ex/Micron/m25q.h
+++ b/os/ex/Micron/m25q.h
@@ -41,9 +41,10 @@
#define M25Q_CMD_RESET_ENABLE 0x66
#define M25Q_CMD_RESET_MEMORY 0x99
#define M25Q_CMD_READ_ID 0x9F
+#define M25Q_CMD_MULTIPLE_IO_READ_ID 0xAF
#define M25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A
#define M25Q_CMD_READ 0x03
-#define M25Q_CMD_FAST_READ 0x08
+#define M25Q_CMD_FAST_READ 0x0B
#define M25Q_CMD_WRITE_ENABLE 0x06
#define M25Q_CMD_WRITE_DISABLE 0x04
#define M25Q_CMD_READ_STATUS_REGISTER 0x05
@@ -112,6 +113,15 @@
#endif
/**
+ * @brief Number of dummy cycles for fast read (1..15).
+ * @details This is the number of dummy cycles to be used for fast read
+ * operations.
+ */
+#if !defined(M25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__)
+#define M25Q_READ_DUMMY_CYCLES 8
+#endif
+
+/**
* @brief Switch QSPI bus width on initialization.
* @details A bus width initialization is performed by writing the
* Enhanced Volatile Configuration Register. If the flash
@@ -185,6 +195,17 @@
#error "M25Q_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
#endif
+#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) && \
+ (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI1L) && \
+ (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI2L) && \
+ (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI4L)
+#error "invalid M25Q_BUS_MODE selected"
+#endif
+
+#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15)
+#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)"
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@@ -250,6 +271,10 @@ typedef struct {
*/
uint32_t qspi_mode;
#endif
+ /**
+ * @brief Device ID and unique ID.
+ */
+ uint8_t device_id[20];
} M25QDriver;
/*===========================================================================*/
diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
index 40df845db..f914b6163 100644
--- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
+++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c
@@ -211,6 +211,22 @@ void qspi_lld_stop(QSPIDriver *qspip) {
*/
void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp) {
+#if STM32_USE_STM32_D1_WORKAROUND == TRUE
+ /* If it is a command without address and alternate phases then the command
+ is sent as an alternate byte, the command phase is suppressed.*/
+ if ((cmdp->cfg & (QSPI_CFG_ADDR_MODE_MASK | QSPI_CFG_ALT_MODE_MASK)) == 0U) {
+ uint32_t cfg;
+
+ /* The command mode field is copied in the alternate mode field. All
+ other fields are not used in this scenario.*/
+ cfg = (cmdp->cfg & QSPI_CFG_CMD_MODE_MASK) << 6U;
+
+ qspip->qspi->DLR = 0U;
+ qspip->qspi->ABR = cmdp->cfg & QSPI_CFG_CMD_MASK;
+ qspip->qspi->CCR = cfg;
+ return;
+ }
+#endif
qspip->qspi->DLR = 0U;
qspip->qspi->ABR = cmdp->alt;
qspip->qspi->CCR = cmdp->cfg;
diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
index c3a82d690..4465755bf 100644
--- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
+++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h
@@ -31,6 +31,17 @@
/* Driver constants. */
/*===========================================================================*/
+/**
+ * @name DCR register options
+ * @{
+ */
+#define STM32_DCR_CK_MODE (1U << 0U)
+#define STM32_DCR_CSHT_MASK (7U << 8U)
+#define STM32_DCR_CSHT(n) ((n) << 8U)
+#define STM32_DCR_FSIZE_MASK (31U << 16U)
+#define STM32_DCR_FSIZE(n) ((n) << 16U)
+/** @} */
+
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
@@ -85,6 +96,17 @@
#if !defined(STM32_QSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_QSPI_DMA_ERROR_HOOK(qspip) osalSysHalt("DMA failure")
#endif
+
+/**
+ * @brief Enables a workaround for a STM32L476 QUADSPI errata.
+ * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an
+ * input when the command is sent in dual or quad SPI mode".
+ * This workaround makes commands without address or data phases
+ * to be sent as alternate bytes.
+ */
+#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__)
+#define STM32_USE_STM32_D1_WORKAROUND TRUE
+#endif
/** @} */
/*===========================================================================*/