diff --git a/lib/bio/debug.c b/lib/bio/debug.c
index 631747d5..8f04871f 100644
--- a/lib/bio/debug.c
+++ b/lib/bio/debug.c
@@ -45,6 +45,8 @@ STATIC_COMMAND_START
STATIC_COMMAND("bio", "block io debug commands", &cmd_bio)
STATIC_COMMAND_END(bio);
+#define DMA_ALIGNMENT (CACHE_LINE)
+
static int cmd_bio(int argc, const cmd_args *argv)
{
int rc = 0;
@@ -288,7 +290,7 @@ usage:
static bool is_valid_block(bdev_t *device, bnum_t block_num, uint8_t* pattern,
size_t pattern_length)
{
- uint8_t *block_contents = malloc(device->block_size);
+ uint8_t *block_contents = memalign(DMA_ALIGNMENT, device->block_size);
ssize_t n_bytes = device->read_block(device, block_contents, block_num, 1);
if (n_bytes < 0 || n_bytes != (ssize_t)device->block_size) {
@@ -331,13 +333,19 @@ static ssize_t erase_test(bdev_t *device)
return num_invalid_blocks;
}
+static uint8_t get_signature(uint32_t word)
+{
+ uint8_t* sigptr = (uint8_t*)(&word);
+ return sigptr[0] ^ sigptr[1] ^ sigptr[2] ^ sigptr[3];
+}
+
// returns the number of blocks where the write was not successful.
static ssize_t write_test(bdev_t *device)
{
- uint8_t *test_buffer = malloc(device->block_size);
+ uint8_t *test_buffer = memalign(DMA_ALIGNMENT, device->block_size);
for (bnum_t bnum = 0; bnum < device->block_count; bnum++) {
- memset(test_buffer, (uint8_t)bnum, device->block_size);
+ memset(test_buffer, get_signature(bnum), device->block_size);
ssize_t err = bio_write_block(device, test_buffer, bnum, 1);
if (err < 0) {
free(test_buffer);
@@ -348,7 +356,7 @@ static ssize_t write_test(bdev_t *device)
size_t num_errors = 0;
uint8_t expected_pattern[1];
for (bnum_t bnum = 0; bnum < device->block_count; bnum++) {
- expected_pattern[0] = (uint8_t)bnum;
+ expected_pattern[0] = get_signature(bnum);
if (!is_valid_block(device, bnum, expected_pattern, sizeof(expected_pattern))) {
num_errors++;
}
diff --git a/platform/stm32f7xx/include/platform/n25q512a.h b/platform/stm32f7xx/include/platform/n25q512a.h
new file mode 100644
index 00000000..4494679e
--- /dev/null
+++ b/platform/stm32f7xx/include/platform/n25q512a.h
@@ -0,0 +1,261 @@
+/**
+ ******************************************************************************
+ * @file n25q512a.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 28-April-2015
+ * @brief This file contains all the description of the N25Q512A QSPI memory.
+ ******************************************************************************
+ * @attention
+ *
+ *
© COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * 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 STMicroelectronics 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 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __N25Q512A_H
+#define __N25Q512A_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup Components
+ * @{
+ */
+
+/** @addtogroup n25q512a
+ * @{
+ */
+
+/** @defgroup N25Q512A_Exported_Types
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup N25Q512A_Exported_Constants
+ * @{
+ */
+
+/**
+ * @brief N25Q512A Configuration
+ */
+#define N25Q512A_FLASH_SIZE 0x4000000 /* 512 MBits => 64MBytes */
+#define N25Q512A_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */
+#define N25Q512A_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */
+#define N25Q512A_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */
+
+#define N25Q512A_DUMMY_CYCLES_READ 8
+#define N25Q512A_DUMMY_CYCLES_READ_QUAD 10
+#define N25Q512A_DUMMY_CYCLES_READ_DTR 6
+#define N25Q512A_DUMMY_CYCLES_READ_QUAD_DTR 8
+
+#define N25Q512A_BULK_ERASE_MAX_TIME 480000
+#define N25Q512A_SECTOR_ERASE_MAX_TIME 3000
+#define N25Q512A_SUBSECTOR_ERASE_MAX_TIME 800
+
+/**
+ * @brief N25Q512A Commands
+ */
+/* Reset Operations */
+#define RESET_ENABLE_CMD 0x66
+#define RESET_MEMORY_CMD 0x99
+
+/* Identification Operations */
+#define READ_ID_CMD 0x9E
+#define READ_ID_CMD2 0x9F
+#define MULTIPLE_IO_READ_ID_CMD 0xAF
+#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A
+
+/* Read Operations */
+#define READ_CMD 0x03
+#define READ_4_BYTE_ADDR_CMD 0x13
+
+#define FAST_READ_CMD 0x0B
+#define FAST_READ_DTR_CMD 0x0D
+#define FAST_READ_4_BYTE_ADDR_CMD 0x0C
+
+#define DUAL_OUT_FAST_READ_CMD 0x3B
+#define DUAL_OUT_FAST_READ_DTR_CMD 0x3D
+#define DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x3C
+
+#define DUAL_INOUT_FAST_READ_CMD 0xBB
+#define DUAL_INOUT_FAST_READ_DTR_CMD 0xBD
+#define DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xBC
+
+#define QUAD_OUT_FAST_READ_CMD 0x6B
+#define QUAD_OUT_FAST_READ_DTR_CMD 0x6D
+#define QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x6C
+
+#define QUAD_INOUT_FAST_READ_CMD 0xEB
+#define QUAD_INOUT_FAST_READ_DTR_CMD 0xED
+#define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xEC
+
+/* Write Operations */
+#define WRITE_ENABLE_CMD 0x06
+#define WRITE_DISABLE_CMD 0x04
+
+/* Register Operations */
+#define READ_STATUS_REG_CMD 0x05
+#define WRITE_STATUS_REG_CMD 0x01
+
+#define READ_LOCK_REG_CMD 0xE8
+#define WRITE_LOCK_REG_CMD 0xE5
+
+#define READ_FLAG_STATUS_REG_CMD 0x70
+#define CLEAR_FLAG_STATUS_REG_CMD 0x50
+
+#define READ_NONVOL_CFG_REG_CMD 0xB5
+#define WRITE_NONVOL_CFG_REG_CMD 0xB1
+
+#define READ_VOL_CFG_REG_CMD 0x85
+#define WRITE_VOL_CFG_REG_CMD 0x81
+
+#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65
+#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61
+
+#define READ_EXT_ADDR_REG_CMD 0xC8
+#define WRITE_EXT_ADDR_REG_CMD 0xC5
+
+/* Program Operations */
+#define PAGE_PROG_CMD 0x02
+#define PAGE_PROG_4_BYTE_ADDR_CMD 0x12
+
+#define DUAL_IN_FAST_PROG_CMD 0xA2
+#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2
+
+#define QUAD_IN_FAST_PROG_CMD 0x32
+#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /*0x38*/
+#define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD 0x34
+
+/* Erase Operations */
+#define SUBSECTOR_ERASE_CMD 0x20
+#define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD 0x21
+
+#define SECTOR_ERASE_CMD 0xD8
+#define SECTOR_ERASE_4_BYTE_ADDR_CMD 0xDC
+
+#define BULK_ERASE_CMD 0xC7
+
+#define PROG_ERASE_RESUME_CMD 0x7A
+#define PROG_ERASE_SUSPEND_CMD 0x75
+
+/* One-Time Programmable Operations */
+#define READ_OTP_ARRAY_CMD 0x4B
+#define PROG_OTP_ARRAY_CMD 0x42
+
+/* 4-byte Address Mode Operations */
+#define ENTER_4_BYTE_ADDR_MODE_CMD 0xB7
+#define EXIT_4_BYTE_ADDR_MODE_CMD 0xE9
+
+/* Quad Operations */
+#define ENTER_QUAD_CMD 0x35
+#define EXIT_QUAD_CMD 0xF5
+
+/**
+ * @brief N25Q512A Registers
+ */
+/* Status Register */
+#define N25Q512A_SR_WIP ((uint8_t)0x01) /*!< Write in progress */
+#define N25Q512A_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */
+#define N25Q512A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */
+#define N25Q512A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */
+#define N25Q512A_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */
+
+/* Non volatile Configuration Register */
+#define N25Q512A_NVCR_NBADDR ((uint16_t)0x0001) /*!< 3-bytes or 4-bytes addressing */
+#define N25Q512A_NVCR_SEGMENT ((uint16_t)0x0002) /*!< Upper or lower 128Mb segment selected by default */
+#define N25Q512A_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */
+#define N25Q512A_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */
+#define N25Q512A_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */
+#define N25Q512A_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */
+#define N25Q512A_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */
+#define N25Q512A_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */
+
+/* Volatile Configuration Register */
+#define N25Q512A_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */
+#define N25Q512A_VCR_XIP ((uint8_t)0x08) /*!< XIP */
+#define N25Q512A_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */
+
+/* Extended Address Register */
+#define N25Q512A_EAR_A24 ((uint8_t)0x01) /*!< Select the lower or upper 128Mb segment */
+
+/* Enhanced Volatile Configuration Register */
+#define N25Q512A_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */
+#define N25Q512A_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */
+#define N25Q512A_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */
+#define N25Q512A_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */
+#define N25Q512A_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */
+
+/* Flag Status Register */
+#define N25Q512A_FSR_NBADDR ((uint8_t)0x01) /*!< 3-bytes or 4-bytes addressing */
+#define N25Q512A_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */
+#define N25Q512A_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */
+#define N25Q512A_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */
+#define N25Q512A_FSR_PGERR ((uint8_t)0x10) /*!< Program error */
+#define N25Q512A_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */
+#define N25Q512A_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */
+#define N25Q512A_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */
+
+/**
+ * @}
+ */
+
+/** @defgroup N25Q512A_Exported_Functions
+ * @{
+ */
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __N25Q512A_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/platform/stm32f7xx/include/platform/n25qxxa.h b/platform/stm32f7xx/include/platform/n25qxxa.h
new file mode 100644
index 00000000..ae10a20a
--- /dev/null
+++ b/platform/stm32f7xx/include/platform/n25qxxa.h
@@ -0,0 +1,216 @@
+/**
+ ******************************************************************************
+ * @file n25qxxa.h
+ * @author MCD Application Team, Adapted by Gurjant Kalsi
+ * @version V1.0.0
+ * @date 28-April-2015
+ * @brief This file contains all the description of the N25QXXA QSPI memory.
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * 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 STMicroelectronics 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 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.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __N25QXXA_H
+#define __N25QXXA_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup Components
+ * @{
+ */
+
+/** @addtogroup n25qXXA
+ * @{
+ */
+
+/** @defgroup N25QXXA_Exported_Types
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup N25QXXA_Exported_Constants
+ * @{
+ */
+
+/**
+ * @brief N25QXXA Configuration
+ */
+#define N25QXXA_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */
+#define N25QXXA_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */
+#define N25QXXA_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */
+
+#define N25QXXA_DUMMY_CYCLES_READ 8
+#define N25QXXA_DUMMY_CYCLES_READ_QUAD 10
+
+#define N25QXXA_SECTOR_ERASE_MAX_TIME 3000
+#define N25QXXA_SUBSECTOR_ERASE_MAX_TIME 800
+
+/**
+ * @brief N25QXXA Commands
+ */
+/* Reset Operations */
+#define RESET_ENABLE_CMD 0x66
+#define RESET_MEMORY_CMD 0x99
+
+/* Identification Operations */
+#define READ_ID_CMD 0x9E
+#define READ_ID_CMD2 0x9F
+#define MULTIPLE_IO_READ_ID_CMD 0xAF
+#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A
+
+/* Read Operations */
+#define READ_CMD 0x03
+#define FAST_READ_CMD 0x0B
+#define DUAL_OUT_FAST_READ_CMD 0x3B
+#define DUAL_INOUT_FAST_READ_CMD 0xBB
+#define QUAD_OUT_FAST_READ_CMD 0x6B
+#define QUAD_INOUT_FAST_READ_CMD 0xEB
+
+/* Write Operations */
+#define WRITE_ENABLE_CMD 0x06
+#define WRITE_DISABLE_CMD 0x04
+
+/* Register Operations */
+#define READ_STATUS_REG_CMD 0x05
+#define WRITE_STATUS_REG_CMD 0x01
+
+#define READ_LOCK_REG_CMD 0xE8
+#define WRITE_LOCK_REG_CMD 0xE5
+
+#define READ_FLAG_STATUS_REG_CMD 0x70
+#define CLEAR_FLAG_STATUS_REG_CMD 0x50
+
+#define READ_NONVOL_CFG_REG_CMD 0xB5
+#define WRITE_NONVOL_CFG_REG_CMD 0xB1
+
+#define READ_VOL_CFG_REG_CMD 0x85
+#define WRITE_VOL_CFG_REG_CMD 0x81
+
+#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65
+#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61
+
+/* Program Operations */
+#define PAGE_PROG_CMD 0x02
+#define DUAL_IN_FAST_PROG_CMD 0xA2
+#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2
+#define QUAD_IN_FAST_PROG_CMD 0x32
+#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /*0x38*/
+
+/* Erase Operations */
+#define SUBSECTOR_ERASE_CMD 0x20
+#define SECTOR_ERASE_CMD 0xD8
+#define BULK_ERASE_CMD 0xC7
+
+#define PROG_ERASE_RESUME_CMD 0x7A
+#define PROG_ERASE_SUSPEND_CMD 0x75
+
+/* One-Time Programmable Operations */
+#define READ_OTP_ARRAY_CMD 0x4B
+#define PROG_OTP_ARRAY_CMD 0x42
+
+/**
+ * @brief N25QXXA Registers
+ */
+/* Status Register */
+#define N25QXXA_SR_WIP ((uint8_t)0x01) /*!< Write in progress */
+#define N25QXXA_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */
+#define N25QXXA_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */
+#define N25QXXA_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */
+#define N25QXXA_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */
+
+/* Non volatile Configuration Register */
+#define N25QXXA_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */
+#define N25QXXA_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */
+#define N25QXXA_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */
+#define N25QXXA_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */
+#define N25QXXA_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */
+#define N25QXXA_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */
+
+/* Volatile Configuration Register */
+#define N25QXXA_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */
+#define N25QXXA_VCR_XIP ((uint8_t)0x08) /*!< XIP */
+#define N25QXXA_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */
+
+/* Enhanced Volatile Configuration Register */
+#define N25QXXA_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */
+#define N25QXXA_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */
+#define N25QXXA_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */
+#define N25QXXA_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */
+#define N25QXXA_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */
+
+/* Flag Status Register */
+#define N25QXXA_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */
+#define N25QXXA_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */
+#define N25QXXA_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */
+#define N25QXXA_FSR_PGERR ((uint8_t)0x10) /*!< Program error */
+#define N25QXXA_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */
+#define N25QXXA_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */
+#define N25QXXA_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */
+
+/**
+ * @}
+ */
+
+/** @defgroup N25QXXA_Exported_Functions
+ * @{
+ */
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __N25QXXA_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/platform/stm32f7xx/include/platform/qspi.h b/platform/stm32f7xx/include/platform/qspi.h
index cb24fe4c..818aa69d 100644
--- a/platform/stm32f7xx/include/platform/qspi.h
+++ b/platform/stm32f7xx/include/platform/qspi.h
@@ -27,6 +27,6 @@
#include
// Initialize the QSPI Flash device.
-status_t qspi_flash_init(void);
+status_t qspi_flash_init(size_t flash_size);
#endif // __PLATFORM_STM32_QSPI_H
diff --git a/platform/stm32f7xx/qspi.c b/platform/stm32f7xx/qspi.c
index 49755f90..ba536801 100644
--- a/platform/stm32f7xx/qspi.c
+++ b/platform/stm32f7xx/qspi.c
@@ -29,9 +29,12 @@
#include
#include
#include
-#include
+#include
+#include
#include
+#define FOUR_BYTE_ADDR_THRESHOLD (1 << 24)
+
static QSPI_HandleTypeDef qspi_handle;
static DMA_HandleTypeDef hdma;
@@ -50,10 +53,10 @@ static int spiflash_ioctl(struct bdev* device, int request, void* argp);
static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data);
-static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction);
-static ssize_t qspi_bulk_erase(void);
-static ssize_t qspi_erase_sector(uint32_t block_addr);
-static ssize_t qspi_erase_subsector(uint32_t block_addr);
+static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction);
+static ssize_t qspi_bulk_erase(bdev_t *device);
+static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr);
+static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr);
static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*);
static HAL_StatusTypeDef qspi_tx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*, uint8_t*);
@@ -61,6 +64,9 @@ static HAL_StatusTypeDef qspi_rx_dma(QSPI_HandleTypeDef*, QSPI_CommandTypeDef*,
status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi);
+static uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address);
+static uint32_t get_address_size(uint32_t address);
+
static event_t cmd_event;
static event_t rx_event;
static event_t tx_event;
@@ -91,8 +97,8 @@ static status_t qspi_write_enable_unsafe(QSPI_HandleTypeDef* hqspi)
}
/* Configure automatic polling mode to wait for write enabling */
- s_config.Match = N25Q128A_SR_WREN;
- s_config.Mask = N25Q128A_SR_WREN;
+ s_config.Match = N25QXXA_SR_WREN;
+ s_config.Mask = N25QXXA_SR_WREN;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
@@ -149,8 +155,8 @@ static status_t qspi_dummy_cycles_cfg_unsafe(QSPI_HandleTypeDef* hqspi)
/* Update volatile configuration register (with new dummy cycles) */
s_command.Instruction = WRITE_VOL_CFG_REG_CMD;
MODIFY_REG(
- reg, N25Q128A_VCR_NB_DUMMY,
- (N25Q128A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q128A_VCR_NB_DUMMY)));
+ reg, N25QXXA_VCR_NB_DUMMY,
+ (N25QXXA_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25QXXA_VCR_NB_DUMMY)));
/* Configure the write volatile configuration register command */
status = HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
@@ -186,7 +192,7 @@ static status_t qspi_auto_polling_mem_ready_unsafe(QSPI_HandleTypeDef* hqspi)
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
s_config.Match = 0;
- s_config.Mask = N25Q128A_SR_WIP;
+ s_config.Mask = N25QXXA_SR_WIP;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
@@ -251,12 +257,12 @@ static ssize_t spiflash_bdev_read(struct bdev* device, void* buf, off_t offset,
// /* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
- s_command.Instruction = QUAD_OUT_FAST_READ_CMD;
+ s_command.Instruction = get_specialized_instruction(QUAD_OUT_FAST_READ_CMD, offset);
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
- s_command.AddressSize = QSPI_ADDRESS_24_BITS;
+ s_command.AddressSize = get_address_size(offset);
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
- s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD;
+ s_command.DummyCycles = N25QXXA_DUMMY_CYCLES_READ_QUAD;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
@@ -311,14 +317,14 @@ static ssize_t spiflash_bdev_write_block(struct bdev* device, const void* _buf,
ssize_t total_bytes_written = 0;
for (; count > 0; count--, block++) {
- ssize_t bytes_written = qspi_write_page_unsafe(block * N25Q128A_PAGE_SIZE, buf);
+ ssize_t bytes_written = qspi_write_page_unsafe(block * N25QXXA_PAGE_SIZE, buf);
if (bytes_written < 0) {
printf("qspi_write_page_unsafe failed\n");
total_bytes_written = bytes_written;
goto err;
}
- buf += N25Q128A_PAGE_SIZE;
+ buf += N25QXXA_PAGE_SIZE;
total_bytes_written += bytes_written;
}
@@ -340,16 +346,16 @@ static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset,
mutex_acquire(&spiflash_mutex);
// Choose an erase strategy based on the number of bytes being erased.
- if (len == N25Q128A_FLASH_SIZE && offset == 0) {
+ if (len == device->total_size && offset == 0) {
// Bulk erase the whole flash.
- total_erased = qspi_bulk_erase();
+ total_erased = qspi_bulk_erase(device);
goto finish;
}
// Erase as many sectors as necessary, then switch to subsector erase for
// more fine grained erasure.
- while (((ssize_t)len - total_erased) >= N25Q128A_SECTOR_SIZE) {
- ssize_t erased = qspi_erase_sector(offset);
+ while (((ssize_t)len - total_erased) >= N25QXXA_SECTOR_SIZE) {
+ ssize_t erased = qspi_erase_sector(device, offset);
if (erased < 0) {
total_erased = erased;
goto finish;
@@ -359,7 +365,7 @@ static ssize_t spiflash_bdev_erase(struct bdev* device, off_t offset,
}
while (total_erased < (ssize_t)len) {
- ssize_t erased = qspi_erase_subsector(offset);
+ ssize_t erased = qspi_erase_subsector(device, offset);
if (erased < 0) {
total_erased = erased;
goto finish;
@@ -380,7 +386,7 @@ static int spiflash_ioctl(struct bdev* device, int request, void* argp)
static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data)
{
- if (!IS_ALIGNED(addr, N25Q128A_PAGE_SIZE)) {
+ if (!IS_ALIGNED(addr, N25QXXA_PAGE_SIZE)) {
return ERR_INVALID_ARGS;
}
@@ -388,9 +394,9 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data)
QSPI_CommandTypeDef s_command = {
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
- .Instruction = QUAD_IN_FAST_PROG_CMD,
+ .Instruction = get_specialized_instruction(QUAD_IN_FAST_PROG_CMD, addr),
.AddressMode = QSPI_ADDRESS_1_LINE,
- .AddressSize = QSPI_ADDRESS_24_BITS,
+ .AddressSize = get_address_size(addr),
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
.DataMode = QSPI_DATA_4_LINES,
.DummyCycles = 0,
@@ -398,7 +404,7 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data)
.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY,
.SIOOMode = QSPI_SIOO_INST_EVERY_CMD,
.Address = addr,
- .NbData = N25Q128A_PAGE_SIZE
+ .NbData = N25QXXA_PAGE_SIZE
};
status_t write_enable_result = qspi_write_enable_unsafe(&qspi_handle);
@@ -422,11 +428,11 @@ static ssize_t qspi_write_page_unsafe(uint32_t addr, const uint8_t *data)
return auto_polling_mem_ready_result;
}
- return N25Q128A_PAGE_SIZE;
+ return N25QXXA_PAGE_SIZE;
}
-status_t qspi_flash_init(void)
+status_t qspi_flash_init(size_t flash_size)
{
status_t result = NO_ERROR;
@@ -455,7 +461,7 @@ status_t qspi_flash_init(void)
qspi_handle.Init.ClockPrescaler = 1;
qspi_handle.Init.FifoThreshold = 4;
qspi_handle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
- qspi_handle.Init.FlashSize = POSITION_VAL(N25Q128A_FLASH_SIZE) - 1;
+ qspi_handle.Init.FlashSize = POSITION_VAL(flash_size) - 1;
qspi_handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
qspi_handle.Init.ClockMode = QSPI_CLOCK_MODE_0;
qspi_handle.Init.FlashID = QSPI_FLASH_ID_1;
@@ -486,13 +492,13 @@ status_t qspi_flash_init(void)
}
// Initialize the QSPI Flash and register it as a Block I/O device.
- geometry.erase_size = log2_uint(N25Q128A_SUBSECTOR_SIZE);
- geometry.erase_shift = log2_uint(N25Q128A_SUBSECTOR_SIZE);
+ geometry.erase_size = log2_uint(N25QXXA_SUBSECTOR_SIZE);
+ geometry.erase_shift = log2_uint(N25QXXA_SUBSECTOR_SIZE);
geometry.start = 0;
- geometry.size = N25Q128A_FLASH_SIZE;
+ geometry.size = flash_size;
- bio_initialize_bdev(&qspi_flash_device, device_name, N25Q128A_PAGE_SIZE,
- (N25Q128A_FLASH_SIZE / N25Q128A_PAGE_SIZE), 1, &geometry);
+ bio_initialize_bdev(&qspi_flash_device, device_name, N25QXXA_PAGE_SIZE,
+ (flash_size / N25QXXA_PAGE_SIZE), 1, &geometry);
qspi_flash_device.read = &spiflash_bdev_read;
qspi_flash_device.read_block = &spiflash_bdev_read_block;
@@ -527,7 +533,7 @@ status_t hal_error_to_status(HAL_StatusTypeDef hal_status)
}
}
-static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction)
+static ssize_t qspi_erase(bdev_t *device, uint32_t block_addr, uint32_t instruction)
{
if (instruction == BULK_ERASE_CMD && block_addr != 0) {
// This call was probably not what the user intended since the
@@ -540,18 +546,21 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction)
ssize_t num_erased_bytes;
switch (instruction) {
case SUBSECTOR_ERASE_CMD: {
- num_erased_bytes = N25Q128A_SUBSECTOR_SIZE;
- erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
+ num_erased_bytes = N25QXXA_SUBSECTOR_SIZE;
+ erase_cmd.AddressMode = get_address_size(block_addr);
+ erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr);
break;
}
case SECTOR_ERASE_CMD: {
- num_erased_bytes = N25Q128A_SECTOR_SIZE;
- erase_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
+ num_erased_bytes = N25QXXA_SECTOR_SIZE;
+ erase_cmd.AddressMode = get_address_size(block_addr);
+ erase_cmd.Instruction = get_specialized_instruction(instruction, block_addr);
break;
}
case BULK_ERASE_CMD: {
- num_erased_bytes = N25Q128A_FLASH_SIZE;
+ num_erased_bytes = device->total_size;
erase_cmd.AddressMode = QSPI_ADDRESS_NONE;
+ erase_cmd.Instruction = instruction;
break;
}
default: {
@@ -570,8 +579,6 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction)
erase_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
erase_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
- erase_cmd.Instruction = instruction;
-
/* Enable write operations */
status_t qspi_write_enable_result = qspi_write_enable_unsafe(&qspi_handle);
@@ -594,19 +601,19 @@ static ssize_t qspi_erase(uint32_t block_addr, uint32_t instruction)
return num_erased_bytes;
}
-static ssize_t qspi_bulk_erase(void)
+static ssize_t qspi_bulk_erase(bdev_t *device)
{
- return qspi_erase(0, BULK_ERASE_CMD);
+ return qspi_erase(device, 0, BULK_ERASE_CMD);
}
-static ssize_t qspi_erase_sector(uint32_t block_addr)
+static ssize_t qspi_erase_sector(bdev_t *device, uint32_t block_addr)
{
- return qspi_erase(block_addr, SECTOR_ERASE_CMD);
+ return qspi_erase(device, block_addr, SECTOR_ERASE_CMD);
}
-static ssize_t qspi_erase_subsector(uint32_t block_addr)
+static ssize_t qspi_erase_subsector(bdev_t *device, uint32_t block_addr)
{
- return qspi_erase(block_addr, SUBSECTOR_ERASE_CMD);
+ return qspi_erase(device, block_addr, SUBSECTOR_ERASE_CMD);
}
static HAL_StatusTypeDef qspi_cmd(QSPI_HandleTypeDef* qspi_handle,
@@ -708,4 +715,45 @@ status_t qspi_dma_init(QSPI_HandleTypeDef *hqspi)
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
return NO_ERROR;
-}
\ No newline at end of file
+}
+
+uint32_t get_address_size(uint32_t address)
+{
+ if (address >= FOUR_BYTE_ADDR_THRESHOLD) {
+ return QSPI_ADDRESS_32_BITS;
+ }
+ return QSPI_ADDRESS_24_BITS;
+}
+
+// Converts a 3 byte instruction into a 4 byte instruction if necessary.
+uint32_t get_specialized_instruction(uint32_t instruction, uint32_t address)
+{
+ if (address < FOUR_BYTE_ADDR_THRESHOLD) {
+ return instruction;
+ }
+
+ switch (instruction) {
+ case READ_CMD:
+ return READ_4_BYTE_ADDR_CMD;
+ case FAST_READ_CMD:
+ return FAST_READ_4_BYTE_ADDR_CMD;
+ case DUAL_OUT_FAST_READ_CMD:
+ return DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD;
+ case DUAL_INOUT_FAST_READ_CMD:
+ return DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD;
+ case QUAD_OUT_FAST_READ_CMD:
+ return QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD;
+ case QUAD_INOUT_FAST_READ_CMD:
+ return QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD;
+ case PAGE_PROG_CMD:
+ return PAGE_PROG_4_BYTE_ADDR_CMD;
+ case QUAD_IN_FAST_PROG_CMD:
+ return QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD;
+ case SUBSECTOR_ERASE_CMD:
+ return SUBSECTOR_ERASE_4_BYTE_ADDR_CMD;
+ case SECTOR_ERASE_CMD:
+ return SECTOR_ERASE_4_BYTE_ADDR_CMD;
+ }
+
+ return instruction;
+}
diff --git a/target/stm32746g-eval2/init.c b/target/stm32746g-eval2/init.c
index d71c2e4c..8c34e85c 100644
--- a/target/stm32746g-eval2/init.c
+++ b/target/stm32746g-eval2/init.c
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -75,7 +76,7 @@ void target_init(void)
TRACE_ENTRY;
stm32_debug_init();
- qspi_flash_init();
+ qspi_flash_init(N25Q512A_FLASH_SIZE);
#if WITH_LIB_MINIP
uint8_t mac_addr[6];
diff --git a/target/stm32f746g-disco/init.c b/target/stm32f746g-disco/init.c
index 48c95fb4..a5932cf7 100644
--- a/target/stm32f746g-disco/init.c
+++ b/target/stm32f746g-disco/init.c
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -70,7 +71,7 @@ void target_init(void)
{
stm32_debug_init();
- qspi_flash_init();
+ qspi_flash_init(N25Q128A_FLASH_SIZE);
#if WITH_LIB_MINIP
uint8_t mac_addr[6];