Dear All,
We are using a QSPI Flash, MT25QL256ABA1EW7, on e2Studio SSP2.3.0, Custom BSP on S5D9.
The QSPI open, erase, pageprogram, close is working fine, I can write, read erase data, and is kept when I reset the board.
So the low level driver for QSPI works great, no complaints.
On FileX I can format the media, write and read files, all working fine. I also get the correct size of available space when fx_media_space_available is sent.
But when I write a file, verify successfully that the file has been written, and reset the board, the file is not there anymore.
This is my configuration:
I first format the media (enabling the option "Format media during initialization", and I write some files.
The I disable that option and I keep trying to write files and read files.
When I reset the board, and I try to read files written previously, seems like the files never exist, but are written everytime successfully.
Some code:
CHAR entry_name[3][25] = {"entry1.txt", "entry2.txt", "entry3.txt"}; for(uint8_t index = 0; index < 3; index++){ res = fx_media_space_available(&g_fx_media0, &space_available); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Unable to get available space: 0x%02X", res); __BKPT(0); } HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Available space on qspi FAT32 area: %lu bytes", space_available); FX_FILE my_file; //Check if previous file is still there status = fx_file_open(&g_fx_media0, &my_file, entry_name[index], FX_OPEN_FOR_READ); if ((uint8_t)FX_SUCCESS == status) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Entry name found %s", entry_name[index]); res = fx_file_close(&my_file); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to close file: 0x%02X", res); } } else{ if (FX_NOT_FOUND == status){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "File not found %s", entry_name[index]); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "No entry found, status 0x%02X", status); } } //Create from data (test) and verify err = file_create_verify(&g_fx_media0, &g_file, entry_name[index], test, (uint32_t) sizeof(test), 1); if ((uint8_t)SSP_SUCCESS != err) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "File error: 0x%02X", err); __BKPT(0); } res = fx_media_space_available(&g_fx_media0, &new_space_available); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Unable to get available space: 0x%02X", res); __BKPT(0); } HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Space used: %lu bytes, space available %lu bytes", (space_available - new_space_available), new_space_available); //Check if previous file is still there status = fx_file_open(&g_fx_media0, &my_file, entry_name[index], FX_OPEN_FOR_READ); if ((uint8_t)FX_SUCCESS == status) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Entry name found %s", entry_name[index]); res = fx_file_close(&my_file); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to close file: 0x%02X", res); } } else{ if (FX_NOT_FOUND == status){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "File not found %s", entry_name[index]); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "No entry found, status 0x%02X", status); } } } status = fx_media_close(&g_fx_media0); if ((uint8_t)FX_SUCCESS != status) { HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Unable to close media: 0x%02X", status); __BKPT(0); } ssp_err_t file_create_verify(FX_MEDIA* media_hdl, FX_FILE* file_hdl, char* filename, uint8_t* data, uint32_t length, bool create_verify){ ULONG res; ULONG file_size; uint8_t read_buffer[FILE_SIZE]; //Create and verify, if create_verify is true //cleanup read buffer memset(read_buffer, 0, FILE_SIZE * sizeof(uint8_t)); if(create_verify){ /* Create a file */ res = fx_file_create(media_hdl, filename); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to create file: 0x%02X", res); return SSP_ERR_NOT_OPEN; } HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "File %s created successfully", filename); /* Write data to the file */ res = fx_file_open(media_hdl, file_hdl, filename, FX_OPEN_FOR_WRITE); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_open: 0x%02X - %s", res, res ? "ERROR" : "SUCCESS"); res = fx_file_truncate(file_hdl, 0u); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_truncate: 0x%02X - %s", res, res ? "ERROR" : "SUCCESS"); res = fx_file_write(file_hdl, data, length); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_write: 0x%02X - %s", res, res ? "ERROR" : "SUCCESS"); res = fx_file_close(file_hdl); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_close: 0x%02X - %s", res, res ? "ERROR" : "SUCCESS"); res = fx_media_flush(media_hdl); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_media_flush: 0x%02X - %s", res, res ? "ERROR" : "SUCCESS"); tx_thread_sleep(20); } // Verify only //Read a buffer of data res = fx_file_open(media_hdl, file_hdl, filename, FX_OPEN_FOR_READ); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to open file: 0x%02X", res); return SSP_ERR_NOT_OPEN; } res = fx_file_read(file_hdl, read_buffer, FILE_SIZE, &file_size); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to read file: 0x%02X", res); return SSP_ERR_READ_FAILED; } res = fx_file_close(file_hdl); if ((uint8_t)FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Unable to close file: 0x%02X", res); return SSP_ERR_NOT_OPEN; } if(!memcmp(test, read_buffer, FILE_SIZE) == 0){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Data verify error - not match"); return SSP_ERR_ABORTED; } else HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Formatted data verified correctly"); return SSP_SUCCESS; }
Some logs on POR..
[0000000000][][new_thread0_entry.c:0055] - Thread EMM start..[0000000000][][new_thread0_entry.c:0094] - Available space on qspi FAT32 area: 33525760 bytes[0000000000][][new_thread0_entry.c:0111] - File not found entry1.txt[0000000000][][new_thread0_entry.c:0306] - File entry1.txt created successfully[0000000000][][new_thread0_entry.c:0310] - fx_file_open: 0x00 - SUCCESS[0000000000][][new_thread0_entry.c:0312] - fx_file_truncate: 0x00 - SUCCESS[0000000000][][new_thread0_entry.c:0314] - fx_file_write: 0x00 - SUCCESS[0000000003][][new_thread0_entry.c:0316] - fx_file_close: 0x00 - SUCCESS[0000000003][][new_thread0_entry.c:0318] - fx_media_flush: 0x00 - SUCCESS[0000000023][][new_thread0_entry.c:0353] - Formatted data verified correctly[0000000023][][new_thread0_entry.c:0135] - Space used: 4096 bytes, space available 33521664 bytes[0000000023][][new_thread0_entry.c:0142] - Entry name found entry1.txt[0000000023][][new_thread0_entry.c:0094] - Available space on qspi FAT32 area: 33521664 bytes[0000000023][][new_thread0_entry.c:0111] - File not found entry2.txt[0000000023][][new_thread0_entry.c:0306] - File entry2.txt created successfully[0000000023][][new_thread0_entry.c:0310] - fx_file_open: 0x00 - SUCCESS[0000000023][][new_thread0_entry.c:0312] - fx_file_truncate: 0x00 - SUCCESS[0000000023][][new_thread0_entry.c:0314] - fx_file_write: 0x00 - SUCCESS[0000000025][][new_thread0_entry.c:0316] - fx_file_close: 0x00 - SUCCESS[0000000026][][new_thread0_entry.c:0318] - fx_media_flush: 0x00 - SUCCESS[0000000046][][new_thread0_entry.c:0353] - Formatted data verified correctly[0000000046][][new_thread0_entry.c:0135] - Space used: 4096 bytes, space available 33517568 bytes[0000000046][][new_thread0_entry.c:0142] - Entry name found entry2.txt[0000000046][][new_thread0_entry.c:0094] - Available space on qspi FAT32 area: 33517568 bytes[0000000046][][new_thread0_entry.c:0111] - File not found entry3.txt[0000000046][][new_thread0_entry.c:0306] - File entry3.txt created successfully[0000000046][][new_thread0_entry.c:0310] - fx_file_open: 0x00 - SUCCESS[0000000046][][new_thread0_entry.c:0312] - fx_file_truncate: 0x00 - SUCCESS[0000000046][][new_thread0_entry.c:0314] - fx_file_write: 0x00 - SUCCESS[0000000048][][new_thread0_entry.c:0316] - fx_file_close: 0x00 - SUCCESS[0000000048][][new_thread0_entry.c:0318] - fx_media_flush: 0x00 - SUCCESS[0000000068][][new_thread0_entry.c:0353] - Formatted data verified correctly[0000000068][][new_thread0_entry.c:0135] - Space used: 4096 bytes, space available 33513472 bytes[0000000068][][new_thread0_entry.c:0142] - Entry name found entry3.txt
Questions:
I tried also to create files in directories, but I always get "name not valid or invalid path", tried the followings all failed:
char entry[] = "dir/entry1.txt";
char entry[] = "dir//entry1.txt";
char entry[] = "dir\\entry1.txt";
Thanks a lot,
S
Hi Sergey,
Unfortunately I'm not able to read my QSPI Flash externally, but I came across a possible solution which works in my specific case.
While debbuging with FileX/ThreadX Source enabled, I…
Hello, Rusty.Thanks for posting your question. We are looking into this and will reach out to you.Regards,Jayesh
Thanks Jayesh,
I'm really concerned on how instable FileX on QSPI is for me.
I would like to use it, otherwise I need to store and manage my data manually using directly the QSPI driver.
Looking forward to it,
KR
Hello Rusty.
Rusty said:Even if I prepare a smaller file (256 Bytes for example) space used goes down by 4096 bytes anyway. Any hints ?
This is because the flash has been formatted with FAT32 FS, and the minimum cluster size is of 4096 bytes. So this is the minimum possible unit.
Rusty said:What is the correct way to put files inside a directory?
Did you create the directory manually before using it?As for the main issue, we suspect that it still formats the FS at the initialization. Please consider checking the initialization flow step-by-step and see if it calls the formatting function somewhere.Regards,Jayesh If this response, or one provided by another user, answers your question, please verify the answer. Thank you!Renesas Engineering Community Moderatorshttps://community.renesas.com/https://academy.renesas.com/en-support.renesas.com/.../
Thanks Jayesh, 4096 then that makes sense.
Yes, the directory is created manually prior creating a file in it, seems like no valid path exists.
Can you please share an example of directory creation and file creation/write/read inside of it? I think that could be fast as an answer.
In regards of the main issue, I wrote an even simpler code, same setup as above, but still at every reset the content of the memory is not kept.
I also put a breakpoint at common_data.c and fx_media_format is never called, as it should be.
ssp_err_t err; ULONG avail_space; ULONG read_size; FX_FILE fp; char filename[] = "primo.txt"; typedef char content_type; content_type content[] = "Some content to write"; content_type read_buffer[128]; err = fx_media_space_available(&g_fx_media0, &avail_space); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Available space %lu", avail_space); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Available space query error 0x%02X", err); } /////////////////////////////////////// /// Create and write /// err = fx_file_create(&g_fx_media0, filename); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "File created"); err = fx_file_open(&g_fx_media0, &fp, filename, FX_OPEN_FOR_WRITE); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Writing file"); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_truncate 0x%02X", fx_file_truncate(&fp, 0u)); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_write 0x%02X", fx_file_write(&fp, content, sizeof(content)/sizeof(content_type))); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_close 0x%02X", fx_file_close(&fp)); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_media_flush 0x%02X", fx_media_flush(&g_fx_media0)); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_open FX_OPEN_FOR_WRITE error 0x%02X", err); } } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_create error 0x%02X", err); } /////////////////////////////////////// /// Read /// err = fx_file_open(&g_fx_media0, &fp, filename, FX_OPEN_FOR_READ); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Reading file"); err = fx_file_read(&fp, read_buffer, (ULONG) 128, &read_size); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Content\n %s", read_buffer); HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Read size %lu", read_size); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_read FX_OPEN_FOR_READ error 0x%02X", err); } } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "fx_file_open FX_OPEN_FOR_READ error 0x%02X", err); } err = fx_media_space_available(&g_fx_media0, &avail_space); if(FX_SUCCESS == err){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Available space %lu", avail_space); } else{ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Available space query error 0x%02X", err); }
This should give an error at reboot, and just read the file afterwards.. but it always create the file.
My linker script includes
QSPI_FLASH (rx) : ORIGIN = 0x60000000, LENGTH = 0x2000000
QSPI alone works and keeps data between reboots, no issues there.
Any hints?
Thanks
Hello, S
I have a couple of follow-up questions and suggestions.
1. Can you make sure somehow that the files are really created and located in the QSPI Flash? Maybe connect it to USB as an MSC device and see the Flash content?
2. In this post there is a similar issue with the directories, and the suggestion that helped was to increase the stack size https://community.renesas.com/mcu-mpu/embedded-system-platform/f/forum/16354/filex-directory-create-lead-to-nmi-handler. Please check it on your side as well.
Kind regards,
Sergey
If this response, or one provided by another user, answers your question, please verify the answer. Thank you!
Renesas Engineering Community Moderatorhttps://community.renesas.com/https://academy.renesas.com/https://en-support.renesas.com/knowledgeBase/
While debbuging with FileX/ThreadX Source enabled, I was coming across random errors in the QSPI Writ page / pageprogramm, and I noticed that if I ran the writes step by step in the debugger, the behaviour kind of stabilised itself.. at least I was getting something written and read consintently.
What I did is copy out bsp_qspi.c from the synergy "autogen" folder to my source folder, and disable the compilation of that resource.
I though maybe I'm writing too fast, and indeed slowing down dramatically the QSPI clock, from DIV2 to DIV10 (so from 120MHz / 2 to 120MHz / 10), and switching from QUAD FAST IO to STANDARD IO, everything now works, I can write, reboot, and read back files.
/* Read mode to operate the device in */ #define BSP_PRV_QSPI_READ_MODE QSPI_READMODE_STANDARD /* QSPI Clock rate */ #define BSP_PRV_QSPI_CLOCK_RATE QSPI_CLK_DIV10 ///< QSPI CLK runs at 60.00 MHz if PCLKA is set to 120MHz
So basically, I'm using the QSPI as a normal one channell SPI If I understand correctly. Speed in my case is not an issue, so I will probably try to increase again to at least QSPI_READMODE_FAST_DUAL_IO (it was QSPI_READMODE_FAST_QUAD_IO).
End of story, probably my QSPI or the combination of the QSPI driver and the upper block media framework have a limit in terms of speed.
Now that all works, I can write and read files, kept under reset.
Only little "issue" I have now is that I can not create more than 128 files, If I try to create more I get
FX_NO_MORE_SPACE from fx_file_create().
I suppose is a limit given by the entries, even though I've put 256 as max directory entries in the configuration.
How comes I get FX_NO_MORE_SPACE ?
If I get the available space I still have
Available space 98.44% : 33001472 / 33525760 bytes
How many files can I create in this FAT partition?
Do I need to create a different directory everytime to accomodate a max number of files per directory?
Thanks again for your support,
P.S. Find my actual QSPI configuration down below:
/*********************************************************************************************************************** * Copyright [2019] Renesas Electronics Corporation and/or its licensors. All Rights Reserved. * * This file is part of Renesas SynergyTM Software Package (SSP) * * The contents of this file (the "contents") are proprietary and confidential to Renesas Electronics Corporation * and/or its licensors ("Renesas") and subject to statutory and contractual protections. * * This file is subject to a Renesas SSP license agreement. Unless otherwise agreed in an SSP license agreement with * Renesas: 1) you may not use, copy, modify, distribute, display, or perform the contents; 2) you may not use any name * or mark of Renesas for advertising or publicity purposes or in connection with your use of the contents; 3) RENESAS * MAKES NO WARRANTY OR REPRESENTATIONS ABOUT THE SUITABILITY OF THE CONTENTS FOR ANY PURPOSE; THE CONTENTS ARE PROVIDED * "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, AND NON-INFRINGEMENT; AND 4) RENESAS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, OR * CONSEQUENTIAL DAMAGES, INCLUDING DAMAGES RESULTING FROM LOSS OF USE, DATA, OR PROJECTS, WHETHER IN AN ACTION OF * CONTRACT OR TORT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CONTENTS. Third-party contents * included in this file may be subject to different terms. **********************************************************************************************************************/ /********************************************************************************************************************** * File Name : bsp_qspi.c * Description : QSPI initialization. **********************************************************************************************************************/ /*******************************************************************************************************************//** * @addtogroup BSP_DK2M_QSPI * @brief QSPI initialization * * This file contains code that initializes the QSPI flash controller connected to a MX25L12835F Maxonic NOR Flash/ N25Q256A Micron Serial NOR Flash * Memory mounted on a DK2 development board. * @{ **********************************************************************************************************************/ /*********************************************************************************************************************** * Includes **********************************************************************************************************************/ #include "bsp_api.h" #include "common_data.h" #if defined(BSP_BOARD_PLGEN2_03) /*********************************************************************************************************************** * Configuration parameters **********************************************************************************************************************/ /* Number of bytes to be used for the address (3 or 4) */ #define BSP_PRV_QSPI_NUM_ADDRESS_BYTES 4U #if BSP_PRV_QSPI_NUM_ADDRESS_BYTES != 3U && BSP_PRV_QSPI_NUM_ADDRESS_BYTES != 4U #error BSP_PRV_QSPI_NUM_ADDRESS_BYTES must be equal to 3 or 4 #endif /* XIP entry and exit confirmation codes for the flash device */ #define BSP_PRV_QSPI_N25Q256A_XIP_ENTRY_CODE 0U #define BSP_PRV_QSPI_N25Q256A_XIP_EXIT_CODE 0xffU #define BSP_PRV_QSPI_MX25L12835F_XIP_ENTRY_CODE 0U #define BSP_PRV_QSPI_MX25L12835F_XIP_EXIT_CODE 0xffU /* Number of dummy clocks to set on the flash device for FAST READ operations */ #define BSP_PRV_QSPI_N25Q256A_NUM_DUMMY_CLOCKS 5U #define BSP_PRV_QSPI_MX25L12835F_NUM_DUMMY_CLOCKS 5U /* QSSL high between cycles */ #define BSP_PRV_QSPI_N25Q256A_DE_SELECT_DELAY 4U #define BSP_PRV_QSPI_MX25L12835F_DE_SELECT_DELAY 4U /* Read mode to operate the device in */ #define BSP_PRV_QSPI_READ_MODE QSPI_READMODE_STANDARD /* Enter XIP mode after bsp_qspi_init is called. */ #define BSP_PRV_QSPI_XIP_MODE_AFTER_INIT 1U /* Is prefetch used for ROM access mode */ #define BSP_PRV_QSPI_ROM_PREFTECH_MODE 1U /* QSPI Clock rate */ #define BSP_PRV_QSPI_CLOCK_RATE QSPI_CLK_DIV10 ///< QSPI CLK runs at 60.00 MHz if PCLKA is set to 120MHz /* Flash device page size */ #define BSP_PRV_QSPI_N25Q256A_PAGE_SIZE (256U) #define BSP_PRV_QSPI_MX25L12835F_PAGE_SIZE (256U) /* The GPIO pins used to connect to the QSPI on the BSP_BOARD_PLGEN2_03 board */ #define QSPI_SEL IOPORT_PORT_02_PIN_07 #define QSPI_CLK IOPORT_PORT_02_PIN_14 #define QSPI_DQ0 IOPORT_PORT_02_PIN_11 #define QSPI_DQ1 IOPORT_PORT_02_PIN_10 /*********************************************************************************************************************** * Private global variables **********************************************************************************************************************/ /* Non-volatile configuration register */ static n25q256a_nv_cfg n25_nv_cfg = {{(uint8_t) 0U}}; static mx25l12835f_nv_cfg mx25_nv_cfg = {{(uint8_t) 0U}}; /* Volatile configuration register */ static n25q256a_volatile_cfg n25_volatile_cfg = {{(uint8_t) 0U}}; static mx25l12835f_volatile_cfg mx25_volatile_cfg = {{(uint8_t) 0U}}; /* Device ID and characteristics */ static n25q256a_characteristics n25_device_characteristics = { 0, 0, 0 }; static mx25l12835f_characteristics mx25_device_characteristics = { 0, 0, 0 }; /* Device flag status */ static n25q256a_flag_status flag_status = {{(uint8_t) 0U}}; /* Flash Erase sizes */ static uint32_t n25q256a_flash_erase_sizes[] = { 4096U, ///< 4KB 65536U, ///< 64KB 33554432U ///< 32MB }; static uint32_t mx25l12835f_flash_erase_sizes[] = { 4096U, ///< 4KB 32768U, ///< 32KB 65536U, ///< 64KB 16777216U ///< 16MB }; /* Flash erase commands for 4byte address */ static uint8_t n25q256a_4byte_erase_commands[]= { #if 0 0x21U, ///< QSPI COMMAND 4BYTE_SUBSECTOR_ERASE 0xDCU, ///< QSPI COMMAND 4BYTE_SECTOR_ERASE 0xC7U ///< QSPI_COMMAND_CHIP_ERASE #else /* JB as we are using the NV register to enable 4 byte addressing, the standard command will accept a 4 byte address for the N25Q256A */ 0x20U, ///< QSPI COMMAND SUBSECTOR_ERASE 0xD8U, ///< QSPI COMMAND SECTOR_ERASE 0xC7U ///< QSPI_COMMAND_CHIP_ERASE #endif }; /* Flash erase commands */ static uint8_t n25q256a_erase_commands[]= { 0x20U, ///< QSPI COMMAND SUBSECTOR_ERASE 0xD8U, ///< QSPI COMMAND SECTOR_ERASE 0xC7U ///< QSPI_COMMAND_CHIP_ERASE }; static uint8_t mx25l12835f_erase_commands[]= { 0x20U, ///< QSPI COMMAND SECTOR_ERASE 0x52U, ///< QSPI COMMAND BLOCK_ERASE 0xD8U, ///< QSPI COMMAND BLOCK_ERASE 0xC7U ///< QSPI_COMMAND_CHIP_ERASE }; static uint32_t qspi_device = QSPI_DEVICE_N25; /*******************************************************************************************************************//** * @brief Reset the flash device **********************************************************************************************************************/ static void bsp_qspi_device_reset () { if(QSPI_DEVICE_MX25 == qspi_device) { /* Reset the flash device. */ R_QSPI->SFMCOM = QSPI_COMMAND_RESET_ENABLE; /* Write the command */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_RESET_MEMORY; /* Write the command */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ } else { /* send 0xFF to device to take the device out of XIP, If a warm reset occurred */ /* and the QSPI device was previously in XIP (continuous access) mode */ #if 0 R_QSPI->SFMCOM = BSP_PRV_QSPI_N25Q256A_XIP_EXIT_CODE; R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ #else /* Take the QSPI device out of XIP mode, so it will accept SPI commands again after a warm reboot/reset */ /* We can't drive the I/O pins during the dummy cycles of a FAST READ to avoid contention between the Synergy device and the external QSPI device IO pins */ /* This means we can't use the QSPI peripheral to send the commands as it is fixed to 8 bit length */ /* Set the SSL, CLK and QIO0 as GPIO, and bit bang the required number of clock cycles to take the QSPI device out of XIP mode, with DQ0 set HIGH */ uint32_t i; #define NUMBER_OF_CLOCK_CYCLES (((BSP_PRV_QSPI_NUM_ADDRESS_BYTES * 8) /4) + 2) /* (Number of address bits /4) + 2 */ g_ioport.p_api->pinCfg(QSPI_SEL, IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH); g_ioport.p_api->pinCfg(QSPI_CLK, IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH); g_ioport.p_api->pinCfg(QSPI_DQ0, IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH); g_ioport.p_api->pinWrite(QSPI_SEL, IOPORT_LEVEL_LOW); R_BSP_SoftwareDelay(20,BSP_DELAY_UNITS_MICROSECONDS); for (i = 0; i < NUMBER_OF_CLOCK_CYCLES; i++) { g_ioport.p_api->pinWrite(QSPI_CLK, IOPORT_LEVEL_LOW); R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MICROSECONDS); g_ioport.p_api->pinWrite(QSPI_CLK, IOPORT_LEVEL_HIGH); R_BSP_SoftwareDelay(1,BSP_DELAY_UNITS_MICROSECONDS); } R_BSP_SoftwareDelay(20,BSP_DELAY_UNITS_MICROSECONDS); g_ioport.p_api->pinWrite(QSPI_SEL, IOPORT_LEVEL_HIGH); g_ioport.p_api->pinCfg(QSPI_SEL, IOPORT_CFG_DRIVE_HIGH | IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_QSPI); g_ioport.p_api->pinCfg(QSPI_CLK, IOPORT_CFG_DRIVE_HIGH | IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_QSPI); g_ioport.p_api->pinCfg(QSPI_DQ0, IOPORT_CFG_DRIVE_HIGH | IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_QSPI); #endif /* Reset the flash device. */ R_QSPI->SFMCOM = QSPI_COMMAND_RESET_ENABLE; /* Write the command */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_RESET_MEMORY; /* Write the command */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ } } /*******************************************************************************************************************//** * @brief Enable or disable XIP mode on the flash device * * @param[in] enable_mode 0 = disable XIP mode, 1 = enable XIP mode * **********************************************************************************************************************/ static void bsp_qspi_device_xip_mode (bool enable_mode) { bool write_in_progress; volatile uint32_t timeout; R_QSPI->SFMCMD_b.DCOM = 1U; /* Enter Direct Communication mode */ /* Enable or disable XIP mode in the flash device */ n25_volatile_cfg.xip = (uint8_t)enable_mode ? (0x01 & 0) : (0x01 & 1); /* Program the volatile configuration register in the device */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_ENABLE; /* Enable writing */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_VOLATILE_CFGREG; /* Write the command */ R_QSPI->SFMCOM = n25_volatile_cfg.entire_cfg; /* Write the volatile configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ /* Wait for the write to complete */ write_in_progress = 1; timeout = 0xfffU; while (write_in_progress) { bsp_qspi_status_get(&write_in_progress); timeout--; if (0 == timeout) { return; } } R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_DISABLE; /* disable writing */ R_QSPI->SFMCMD_b.DCOM = (uint32_t)1; /* close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = (uint32_t)0; /* enter ROM access mode */ } /*******************************************************************************************************************//** * This function reads the flag status register from the device which indicates errors that occurred during various * operations like erasing and programming. **********************************************************************************************************************/ static void bsp_qspi_read_status_flag_register (n25q256a_flag_status * p_flag_status) { uint8_t regval; /* Send command to read status */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_FLAG_STATUS_REGISTER; /* Read the device status register */ regval = R_QSPI->SFMCOM_b.SFMD; /* Close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; p_flag_status->entire_cfg = regval; } /*******************************************************************************************************************//** * @brief Enter or exit XIP mode * * @param[in] enter_mode 0 = exit XIP mode, 1 = enter XIP mode * **********************************************************************************************************************/ static void bsp_qspi_xip_mode (bool enter_mode) { volatile uint32_t i = 0; volatile uint32_t timeout; SSP_PARAMETER_NOT_USED(i); R_QSPI->SFMCMD_b.DCOM = (uint32_t)0; if (enter_mode) { R_QSPI->SFMSDC_b.SFMXD = (uint32_t)BSP_PRV_QSPI_N25Q256A_XIP_ENTRY_CODE; /* Set the XIP entry * confirmation * code */ R_QSPI->SFMSDC_b.SFMXEN = true; /* Enter XIP mode in QSPI * controller */ i = *(volatile uint32_t *) BSP_PRV_QSPI_DEVICE_PHYSICAL_ADDRESS; /* Read from the device * set the * code */ /* Wait for the controller to enter XIP mode */ timeout = 0xfffU; while (0 == R_QSPI->SFMSDC_b.SFMXST) { timeout--; if (0 == timeout) { return; } } } else { R_QSPI->SFMSDC_b.SFMXD = BSP_PRV_QSPI_N25Q256A_XIP_EXIT_CODE; /* Set the XIP exit * confirmation * code */ R_QSPI->SFMSDC_b.SFMXEN = false; /* Exit XIP mode in the * QSPI * controller * block */ i = *(volatile uint32_t *) BSP_PRV_QSPI_DEVICE_PHYSICAL_ADDRESS; /* Read from the device * to * set the * code */ /* Wait for the controller to exit XIP mode */ timeout = 0xfffU; while (R_QSPI->SFMSDC_b.SFMXST) { timeout--; if (0 == timeout) { return; } } } } /*********************************************************************************************************************** * Functions **********************************************************************************************************************/ /*******************************************************************************************************************//** * @brief Initializes QSPI. * * This function initializes QSPI and Micron Serial Flash Memory device on the board. * * @note This function is executed once after reset. **********************************************************************************************************************/ void bsp_qspi_init (void) { uint32_t regval; bool write_in_progress; #ifdef BSP_BOARD_PLGEN2_03 qspi_device = QSPI_DEVICE_N25; #endif if(QSPI_DEVICE_MX25 == qspi_device) { R_MSTP->MSTPCRB_b.MSTPB6 = 0U; /* Initialized unused bits */ R_QSPI->SFMSPC = 0x10U; R_QSPI->SFMCST = 0U; R_QSPI->SFMSIC = 0U; R_QSPI->SFMPMD = 0U; R_QSPI->SFMCNT1 = 0U; R_QSPI->SFMCMD = 1U; /* Enable Quad mode */ R_QSPI->SFMCOM = QSPI_COMMAND_ENABLE_QPI; R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCMD = 1U; bsp_qspi_device_reset(); R_QSPI->SFMSKC_b.SFMDV = 6U; //6 //Setting SPI protocol R_QSPI->SFMSPC_b.SFMSPI = 2U; //Setting dummy cycle R_QSPI->SFMSDC_b.SFMDN = 0x4U; //8 //DCOM mode R_QSPI->SFMCMD = 1U; /* Read the ID of the device. Confirm it is the correct device. */ R_QSPI->SFMCOM = QSPI_COMMAND_QUAD_READ_ID; /* Write the command */ mx25_device_characteristics.manufacturer_id = R_QSPI->SFMCOM_b.SFMD; /* Read the manufacturer ID */ mx25_device_characteristics.memory_type = R_QSPI->SFMCOM_b.SFMD; /* Read the memory type */ mx25_device_characteristics.memory_capacity = R_QSPI->SFMCOM_b.SFMD; /* Read the memory capacity */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ if ((BSP_PRV_MX25_QSPI_MANUFACTURER_ID != mx25_device_characteristics.manufacturer_id) || (BSP_PRV_MX25_QSPI_MEMORY_TYPE != mx25_device_characteristics.memory_type) || (BSP_PRV_MX25_QSPI_MEMORY_CAPACITY != mx25_device_characteristics.memory_capacity)) { mx25_device_characteristics.manufacturer_id = 0U; mx25_device_characteristics.memory_type = 0U; mx25_device_characteristics.memory_capacity = 0U; return; } /* Read the non-volatile configuration of the device */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_NONVOLATILE_CFGREG; /* Write the command */ regval = (uint32_t)(R_QSPI->SFMCOM_b.SFMD << 8);/* Read the nv configuration register */ regval |= R_QSPI->SFMCOM_b.SFMD; /* Read the nv configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ mx25_nv_cfg.entire_cfg = regval; /* Change the configuration of the device if it differs from the configuration specified above */ if (((4U - BSP_PRV_QSPI_NUM_ADDRESS_BYTES) != mx25_nv_cfg.address_bytes) || (BSP_PRV_QSPI_MX25L12835F_NUM_DUMMY_CLOCKS != mx25_nv_cfg.number_dummy_clock_cycles)) { mx25_nv_cfg.address_bytes = (4U - BSP_PRV_QSPI_NUM_ADDRESS_BYTES); mx25_nv_cfg.number_dummy_clock_cycles = BSP_PRV_QSPI_MX25L12835F_NUM_DUMMY_CLOCKS; regval = mx25_nv_cfg.entire_cfg; /* Program the non-volatile configuration register in the device */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_ENABLE; /* Enable writing */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_NONVOLATILE_CFGREG; /* Write the command */ R_QSPI->SFMCOM = (regval >> 8); /* Write the nv configuration register */ R_QSPI->SFMCOM = (uint32_t)regval; /* Write the nv configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ /* Wait for the write to complete */ do { bsp_qspi_status_get(&write_in_progress); } while (write_in_progress); /* close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; } /* Read the volatile configuration of the device */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_VOLATILE_CFGREG; /* Write the command */ regval = R_QSPI->SFMCOM_b.SFMD; /* Read the volatile configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ mx25_volatile_cfg.entire_cfg = regval; /* Set the number of dummy cycles in the flash device */ mx25_volatile_cfg.num_dummy_clock_cycles = BSP_PRV_QSPI_MX25L12835F_NUM_DUMMY_CLOCKS; regval = mx25_volatile_cfg.entire_cfg; /* Program the volatile configuration register in the device */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_ENABLE; /* Enable writing */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_VOLATILE_CFGREG; /* Write the command */ R_QSPI->SFMCOM = (uint32_t)regval; /* Write the volatile configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ /* Wait for the write to complete */ do { bsp_qspi_status_get(&write_in_progress); } while (write_in_progress); /* disable writing */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_DISABLE; /* close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Maxon QSPI needs 50ns de-select (QSSL high between cycles) for nonREAD commands */ /* (20ns for a read command) Need 3 and a bit clock (i.e. 4) cycles at 60MHz */ R_QSPI->SFMSSC_b.SFMSW = BSP_PRV_QSPI_MX25L12835F_DE_SELECT_DELAY; /* Set the read mode */ R_QSPI->SFMSMD_b.SFMRM = BSP_PRV_QSPI_READ_MODE; #if BSP_PRV_QSPI_ROM_PREFTECH_MODE R_QSPI->SFMSMD_b.SFMPFE = 1U; #endif /* Enter ROM access mode */ R_QSPI->SFMCMD_b.DCOM = (uint32_t)0; } else { /* enable clocks to the QSPI block */ R_MSTP->MSTPCRB_b.MSTPB6 = 0U; /* Initialized unused bits */ R_QSPI->SFMSPC = 0x10U; R_QSPI->SFMCST = 0U; R_QSPI->SFMSIC = 0U; R_QSPI->SFMPMD = 0U; R_QSPI->SFMCNT1 = 0U; /* Set the SPI clock rate */ R_QSPI->SFMSKC_b.SFMDV = BSP_PRV_QSPI_CLOCK_RATE; /* enter direct communication mode */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Reset the flash device */ bsp_qspi_device_reset(); /* Read the ID of the device. Confirm it is the correct device. */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_ID; /* Write the command */ n25_device_characteristics.manufacturer_id = R_QSPI->SFMCOM_b.SFMD; /* Read the manufacturer ID */ n25_device_characteristics.memory_type = R_QSPI->SFMCOM_b.SFMD; /* Read the memory type */ n25_device_characteristics.memory_capacity = R_QSPI->SFMCOM_b.SFMD; /* Read the memory capacity */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ if ((BSP_PRV_N25_QSPI_MANUFACTURER_ID != n25_device_characteristics.manufacturer_id) || (BSP_PRV_N25_QSPI_MEMORY_TYPE != n25_device_characteristics.memory_type) || (BSP_PRV_N25_QSPI_MEMORY_CAPACITY != n25_device_characteristics.memory_capacity)) { n25_device_characteristics.manufacturer_id = 0U; n25_device_characteristics.memory_type = 0U; n25_device_characteristics.memory_capacity = 0U; return; } /* Read the non-volatile configuration of the device */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_NONVOLATILE_CFGREG; /* Write the command */ regval = (uint32_t)(R_QSPI->SFMCOM_b.SFMD); /* Read the nv configuration register, JB - Least Significant Byte First */ regval |= (uint32_t)(R_QSPI->SFMCOM_b.SFMD << 8); /* Read the nv configuration register, JB - Least Significant Byte First */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ n25_nv_cfg.entire_cfg = regval; /* Change the configuration of the device if it differs from the configuration specified above */ if (((4U - BSP_PRV_QSPI_NUM_ADDRESS_BYTES) != n25_nv_cfg.address_bytes) || (BSP_PRV_QSPI_N25Q256A_NUM_DUMMY_CLOCKS != n25_nv_cfg.number_dummy_clock_cycles)) { n25_nv_cfg.address_bytes = (4U - BSP_PRV_QSPI_NUM_ADDRESS_BYTES); n25_nv_cfg.number_dummy_clock_cycles = BSP_PRV_QSPI_N25Q256A_NUM_DUMMY_CLOCKS; regval = n25_nv_cfg.entire_cfg; /* Program the non-volatile configuration register in the device */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_ENABLE; /* Enable writing */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_NONVOLATILE_CFGREG; /* Write the command */ R_QSPI->SFMCOM = (regval); /* Write the nv configuration register, JB - Least Significant Byte First */ R_QSPI->SFMCOM = (uint32_t)regval >> 8; /* Write the nv configuration register, JB - Least Significant Byte First */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ /* Wait for the write to complete */ do { bsp_qspi_status_get(&write_in_progress); } while (write_in_progress); /* close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; /* JB - Reset the flash device as we have changed the setting in the NV config register */ bsp_qspi_device_reset(); } /* Read the volatile configuration of the device */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_VOLATILE_CFGREG; /* Write the command */ regval = R_QSPI->SFMCOM_b.SFMD; /* Read the volatile configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ n25_volatile_cfg.entire_cfg = regval; /* Set the number of dummy cycles in the flash device */ n25_volatile_cfg.num_dummy_clock_cycles = BSP_PRV_QSPI_N25Q256A_NUM_DUMMY_CLOCKS; regval = n25_volatile_cfg.entire_cfg; /* Program the volatile configuration register in the device */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_ENABLE; /* Enable writing */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_VOLATILE_CFGREG; /* Write the command */ R_QSPI->SFMCOM = (uint32_t)regval; /* Write the volatile configuration register */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Close the SPI bus cycle */ /* Wait for the write to complete */ do { bsp_qspi_status_get(&write_in_progress); } while (write_in_progress); /* disable writing */ R_QSPI->SFMCOM = QSPI_COMMAND_WRITE_DISABLE; /* close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; /* Read the flag status of the device to determine the addressing mode of the device. */ bsp_qspi_read_status_flag_register(&flag_status); /* If the device is in 4-byte addressing mode then configure the QSPI block that way as well */ if (flag_status.addressing_4_byte_mode) { R_QSPI->SFMSAC_b.SFMAS = 3U; /* 4 byte address */ #if 0 R_QSPI->SFMSAC_b.SFM4BC = 1U; /* Select default instruction code - JB we are enabling 4 byte addressing by the NV register */ /* This means the standard N25Q256A QSPI commands will accept a 4 byte address */ #endif } /* Set the number of dummy cycles in QSPI peripheral */ R_QSPI->SFMSDC_b.SFMDN = (uint32_t)(BSP_PRV_QSPI_N25Q256A_NUM_DUMMY_CLOCKS - 2U); /* Micron QSPI needs 50ns de-select (QSSL high between cycles) for nonREAD commands */ /* (20ns for a read command) Need 3 and a bit clock (i.e. 4) cycles at 60MHz */ R_QSPI->SFMSSC_b.SFMSW = BSP_PRV_QSPI_N25Q256A_DE_SELECT_DELAY; /* Set the read mode */ R_QSPI->SFMSMD_b.SFMRM = BSP_PRV_QSPI_READ_MODE; #if BSP_PRV_QSPI_ROM_PREFTECH_MODE R_QSPI->SFMSMD_b.SFMPFE = 1U; #endif #if BSP_PRV_QSPI_XIP_MODE_AFTER_INIT /* Enable XIP mode on the flash device */ bsp_qspi_xip_enter(); #endif /* Enter ROM access mode */ R_QSPI->SFMCMD_b.DCOM = (uint32_t)0; } } /*******************************************************************************************************************//** * @brief Enter XIP mode * * This function enters XIP mode in both the QSPI controller block and on the flash device. * **********************************************************************************************************************/ void bsp_qspi_xip_enter (void) { if(QSPI_DEVICE_MX25 == qspi_device) { /* Not supported by MX25L12835F. */ } else { /* Check there is no serial transfer in progress */ while (R_QSPI->SFMCST_b.COMBSY == (uint32_t)1) { } /* Since the device on the S7 DK board is 25Q256A 13E40, we need first need to set the XIP bit (bit 3) */ /* In the volatile config register to enter XIP mode */ bsp_qspi_device_xip_mode(true); /* then drive the XIP confirmation bit to 0 during */ /* the next FAST-READ cycle */ bsp_qspi_xip_mode(true); } } /*******************************************************************************************************************//** * @brief Exit XIP mode * * This function exits XIP mode in both the QSPI controller block and on the flash device. * **********************************************************************************************************************/ void bsp_qspi_xip_exit (void) { if(QSPI_DEVICE_MX25 == qspi_device) { /* Not supported by MX25L12835F. */ } else { /* Check there is no serial transfer in progress */ while (R_QSPI->SFMCST_b.COMBSY == (uint32_t)1) { } bsp_qspi_xip_mode(false); } } /*******************************************************************************************************************//** * @brief Get the status from the MX25L12835F QSPI device. * * This function reads the status byte from the device and returns the write status. Used by write and erase operations * in the QSPI module driver. * * @param[in] p_write_in_progress Pointer to a boolean that indicates if a write or erase is in progress. * **********************************************************************************************************************/ void bsp_mx25_qspi_status_get (bool * p_write_in_progress) { uint32_t regval; mx25l12835f_status status; /* Send command to read status */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_STATUS_REGISTER; /* Read the device status register */ regval = R_QSPI->SFMCOM_b.SFMD; /* Close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; status.entire_cfg = regval; *p_write_in_progress = (status.write_in_progress > 0U); } /*******************************************************************************************************************//** * @brief Get the status from the N25Q256A QSPI device. * * This function reads the status byte from the device and returns the write status. Used by write and erase operations * in the QSPI module driver. * * @param[in] p_write_in_progress Pointer to a boolean that indicates if a write or erase is in progress. * **********************************************************************************************************************/ void bsp_n25_qspi_status_get (bool * p_write_in_progress) { uint32_t regval; n25q256a_status status; /* Send command to read status */ R_QSPI->SFMCOM = QSPI_COMMAND_READ_STATUS_REGISTER; /* Read the device status register */ regval = R_QSPI->SFMCOM_b.SFMD; /* Close the SPI bus cycle */ R_QSPI->SFMCMD_b.DCOM = 1U; status.entire_cfg = regval; *p_write_in_progress = (status.write_in_progress > 0U); } /*******************************************************************************************************************//** * @brief Get the status from the QSPI device. * * This function reads the status byte from the device and returns the write status. Used by write and erase operations * in the QSPI module driver. * * @param[in] p_write_in_progress Pointer to a boolean that indicates if a write or erase is in progress. * **********************************************************************************************************************/ void bsp_qspi_status_get (bool * p_write_in_progress) { if(QSPI_DEVICE_MX25 == qspi_device) { bsp_mx25_qspi_status_get(p_write_in_progress); } else { bsp_n25_qspi_status_get(p_write_in_progress); } } /*******************************************************************************************************************//** * @brief Get the flags from the QSPI device. * * This function reads the flag status register from the device which indicates errors that occurred during various * operations like erasing and programming. * **********************************************************************************************************************/ void bsp_qspi_flags_get (bool * p_addressing_4_byte_mode, bool * p_program_suspended, bool * p_erase_failure, bool * p_program_failure, bool * p_protection_failure) { if(QSPI_DEVICE_MX25 == qspi_device) { *p_addressing_4_byte_mode = 0U; *p_erase_failure = 0U; *p_program_failure = 0U; *p_protection_failure = 0U; *p_program_suspended = 0U; } else { n25q256a_flag_status flag_stat; bsp_qspi_read_status_flag_register(&flag_stat); *p_addressing_4_byte_mode = (flag_stat.addressing_4_byte_mode > 0U); *p_erase_failure = (flag_stat.erase > 0U); *p_program_failure = (flag_stat.program > 0U); *p_protection_failure = (flag_stat.protection > 0U); *p_program_suspended = (flag_stat.program_suspend > 0U); } } /*******************************************************************************************************************//** * @brief Get the current configuration of the QSPI device. * * This function reads the volatile and non-volatile registers of the device and returns portions of these to the QSPI * module driver for use in direct communication mode. * * @param[out] num_address_bytes Number of bytes used for the address - 3 bytes or 4 bytes * @param[out] spi_mode SPI mode used - 0 = Extended, 1 = Dual, 2 = Quad * **********************************************************************************************************************/ void bsp_qspi_config_get (uint8_t * p_manufacturer_id, uint8_t * p_memory_type, uint8_t * p_memory_capacity, uint32_t * p_max_eraseable_size, uint32_t * p_num_address_bytes, uint32_t * p_spi_mode, uint32_t * p_page_size, bool * p_xip_mode) { if(QSPI_DEVICE_MX25 == qspi_device) { *p_manufacturer_id = mx25_device_characteristics.manufacturer_id; *p_memory_type = mx25_device_characteristics.memory_type; *p_memory_capacity = mx25_device_characteristics.memory_capacity; *p_max_eraseable_size = 4U; /* 4k bytes */ *p_num_address_bytes = 3U; *p_spi_mode = (uint32_t) QSPI_EXTENDED_SPI_PROTOCOL; *p_page_size = BSP_PRV_QSPI_MX25L12835F_PAGE_SIZE; #if BSP_PRV_QSPI_XIP_MODE_AFTER_INIT *p_xip_mode = true; #else *p_xip_mode = false; #endif } else { *p_manufacturer_id = n25_device_characteristics.manufacturer_id; *p_memory_type = n25_device_characteristics.memory_type; *p_memory_capacity = n25_device_characteristics.memory_capacity; *p_max_eraseable_size = 4U; /* 4k bytes */ *p_num_address_bytes = (uint32_t)(flag_status.addressing_4_byte_mode + 3U); *p_spi_mode = (uint32_t) QSPI_EXTENDED_SPI_PROTOCOL; *p_page_size = BSP_PRV_QSPI_N25Q256A_PAGE_SIZE; #if BSP_PRV_QSPI_XIP_MODE_AFTER_INIT *p_xip_mode = true; #else *p_xip_mode = false; #endif } } /*******************************************************************************************************************//** * @brief Get the supported erase sizes of Flash. * * QSPI Flash erase sizes are arranged in acceding order.Function returns the address of the ordered array of * erase size to upper layer. * **********************************************************************************************************************/ void bsp_qspi_erase_sizes_get(uint32_t ** pp_sizes, uint8_t *p_len) { if(QSPI_DEVICE_MX25 == qspi_device) { *pp_sizes = &mx25l12835f_flash_erase_sizes[0]; *p_len = (uint8_t)(sizeof(mx25l12835f_flash_erase_sizes)/sizeof(mx25l12835f_flash_erase_sizes[0])); } else { *pp_sizes = &n25q256a_flash_erase_sizes[0]; *p_len = (uint8_t)(sizeof(n25q256a_flash_erase_sizes)/sizeof(n25q256a_flash_erase_sizes[0])); } } /*******************************************************************************************************************//** * @brief Get erase command based on index value. * * QSPI Flash erase size commands are arranged in a acceding order. * **********************************************************************************************************************/ void bsp_qspi_erase_command_get(uint8_t *p_erase_command, uint8_t index) { if(QSPI_DEVICE_MX25 == qspi_device) { *p_erase_command = mx25l12835f_erase_commands[index]; } else { if(4U == (flag_status.addressing_4_byte_mode + 3U)) { *p_erase_command = n25q256a_4byte_erase_commands[index]; } else { *p_erase_command = n25q256a_erase_commands[index]; } } } #endif /* if defined(BSP_BOARD_S7G2_DK) */ /** @} (end addtogroup BSP_DK2M_QSPI) */
EDIT:
If I create a directory, select that directory as default, I can write thousands of files in it (tested up to 2500 files, 4KByte each). I guess this doesn't apply if I write files into the root directory directly?
res = fx_directory_create(&g_fx_media0, "TESTDIR"); if (FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Could not create directory TESTDIR"); } res = fx_directory_default_set(&g_fx_media0, "\\TESTDIR"); if (FX_SUCCESS != res) { HSP_EEM_LOG(HSP_LOG_LEVEL_ERROR, "Could not set local path to directory 0x%02X", res); } // Get all entries in the current directory do{ res = fx_directory_next_entry_find(&g_fx_media0, return_entry_name); if(FX_SUCCESS == res){ HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Entry #%lu found : \"%s\"", entry_count, return_entry_name); entry_count++; } } while ((res != FX_NO_MORE_ENTRIES) | (FX_SUCCESS == res)); if(FX_NO_MORE_ENTRIES == res) HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "No more entries"); else HSP_EEM_LOG(HSP_LOG_LEVEL_DEBUG, "Next Entry error 0x%02X", res);
So, up to now, seems everything is working fine.
Thanks again to everyone,
Hello S,
I'm glad you have solved your issue even though with certain restrictions. Thank you for sharing your solution with us. I'll mark your last reply as a "verified answer" so other people can see it as solution.