Hi everyone,
I'm using Teensy4.1 Board. It include MIMXRT1062DVJ6B and external flash W25Q64JVSSIQ.
I used evkmimxrt1060_flexspi_nor_polling_transfer to read, write and erase the external flash.
But i have issues: Cannot erase sector 3,4,6,7. In while others can be erased.
Below is my configuration and test:
- boot.conf
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".boot_hdr.conf"), used))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.conf"
#endif
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClksrc=kFlexSPIReadSampleClk_LoopbackFromDqsPad,
.csHoldTime = 3u,
.csSetupTime = 3u,
.controllerMiscOption = (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable),
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_4Pads,
.serialClkFreq = kFlexSpiSerialClk_133MHz,
.sflashA1Size = 8u * 1024u * 1024u,
.lookupTable =
{
// Read LUTs
[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
[1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04),
// Read Status LUTs
[4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04),
// Write Enable LUTs
[4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x0),
// Erase Sector LUTs
[4 * 5 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18),
// Erase Block LUTs
[4 * 8 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD8, RADDR_SDR, FLEXSPI_1PAD, 0x18),
// Pape Program LUTs
[4 * 9 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),
[4 * 9 + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0),
// Erase Chip LUTs
[4 * 11 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0x0),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.ipcmdSerialClkFreq = 1u,
.blockSize = 64u * 1024u,
.isUniformBlockSize = false,
};
- Test function:
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2018 NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_debug_console.h"
#include "board.h"
#include "hal/flash.h"
#include "fsl_cache.h"
#define BEGIN_SECTOR 8
#define END_SECTOR 20
#define BUFFER_SIZE 256
static void print_array(uint8_t *data , size_t size){
DbgConsole_Printf("Array: [");
for (size_t i = 0; i < size - 1; i++)
{
if((i+ 1) % 16 == 0){
DbgConsole_Printf("%x,\r\n" , data[i]);
}
else{
DbgConsole_Printf("%x," , data[i]);
}
}
DbgConsole_Printf("%x]\r\n" , data[size-1]);
}
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/* Program data buffer should be 4-bytes alignment, which can avoid busfault due to this memory region is configured as
Device Memory by MPU. */
SDK_ALIGN(static uint8_t s_nor_program_buffer[BUFFER_SIZE] , 4);
static uint8_t s_nor_read_buffer[BUFFER_SIZE];
int flash_test(void)
{
uint32_t i = 0;
FLASH_init();
for (i = 0; i < 0xFFU; i++)
{
s_nor_program_buffer[i] = i;
}
for (size_t sector_index = BEGIN_SECTOR; sector_index < END_SECTOR; sector_index++)
{
DbgConsole_Printf("Erase sector %d\r\n" , sector_index);
DbgConsole_Printf("Data Before Program:\r\n");
FLASH_read(sector_index * SECTOR_SIZE, s_nor_read_buffer, 256);
print_array(s_nor_read_buffer, 256);
FLASH_erase_sector(sector_index * SECTOR_SIZE);
DCACHE_InvalidateByRange(FLASH_SPI_AMBA_BASE + sector_index * SECTOR_SIZE , 256);
DbgConsole_Printf("Data After Program:\r\n");
FLASH_read(sector_index * SECTOR_SIZE, s_nor_read_buffer, 256);
print_array(s_nor_read_buffer, 256);
}
while (1)
{
}
}
Erase flash:
extern void FLASH_erase_sector(const uint32_t address)
{
flexspi_transfer_t flashXfer;
flexspi_cache_status_t cacheStatus;
// Disable Cache
FLASH_disable_cache(&cacheStatus);
/* Write enable */
FLASH_write_enable(FLASH_SPI, address);
flashXfer.deviceAddress = address;
flashXfer.port = FLASH_PORT;
flashXfer.cmdType = kFLEXSPI_Command;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;
FLEXSPI_TransferBlocking(FLASH_SPI, &flashXfer);
FLASH_wait_bus_busy(FLASH_SPI);
/* Do software reset. */
FLEXSPI_SoftwareReset(FLASH_SPI);
// Enable Cache
FLASH_enable_cache(cacheStatus);
}
Custom LUT:
static const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
/* Normal read mode -SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* Fast read mode - SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Fast read quad mode - SDR */
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
/* Read extend parameters */
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Write Enable */
[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* Erase Sector */
[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
/* Page Program - single mode */
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* Page Program - quad mode */
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* Read ID */
[4 * NOR_CMD_LUT_SEQ_IDX_READID] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Enable Quad mode */
[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
/* Read status register */
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Read status register 2*/
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG2] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Read status register 3*/
[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG3] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x15, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),
/* Global Unlock*/
[4 * NOR_CMD_LUT_SEQ_IDX_GLOBAL_UNLOCK] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x98, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x04),
/* Erase Sector */
[4 * NOR_CMD_LUT_SEQ_IDX_INDIVIDUAL_UNLOCK] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x39, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
/* Erase whole chip */
[4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
};
Read flash:
extern bool FLASH_read(volatile const uint8_t *const start_addr_p, uint8_t data_p[const], const uint32_t size_bytes)
{
status_t status;
flexspi_transfer_t flashXfer;
flexspi_cache_status_t cacheStatus;
// Disable Cache
FLASH_disable_cache(&cacheStatus);
/* Prepare read data command */
flashXfer.deviceAddress = start_addr_p;
flashXfer.port = FLASH_PORT;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD;
flashXfer.data = (uint32_t *)data_p;
flashXfer.dataSize = size_bytes;
// Flash Send Write Command
status = FLEXSPI_TransferBlocking(FLASH_SPI, &flashXfer);
//Wait Bus Busy
FLASH_wait_bus_busy(FLASH_SPI);
/* Do software reset*/
FLEXSPI_SoftwareReset(FLASH_SPI);
// Enable Cache
FLASH_enable_cache(cacheStatus);
return status;
}
Result
***************************************** Case Erase 3-4 (Failed)*********************************
***************************************** Case Erase 8-9-10 (Success)*********************************
Please help me!
Thank you so much.
It is interesting, but from you 'erase3/4' picture, i don't see the data difference between Data Before Program and Data After Program.
If some block/sectors cannot be erased, you need to check Status Register-1
Thanks for your response,
From erase3/4 picture, It cause blocking process after I send erasing command sector 3,4.
About Status Register-1, I checked that it's in PROTECTED BLOCK 0 and 1 (attached image).
So I still don't know why i can erase other sector (5,8,9,...) , in while it's in BLOCK 0 and 1.
Hi @xuanthodo did you have the same issue with the internal memory?
Can you give me an example for booting from internal memory and flash-api to read/write/erase it?
Thank you.