Open flash loader is too slow

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Open flash loader is too slow

      Hello! I made an open loader for my custom board based on this instruction wiki.segger.com/Open_Flashloader . And it works correctly, but very slowly. I checked all functions, complete erasure, loadbin command with verify and also J-Flash read range (full 32 Mbytes). My custom board consists of MCU STM32H753XI and QSPI flash s25fl256 (32 Mbytes). In result I have very slow read/verify speed. For example, I try read 2 Mb internal MCU flash and 2 Mb external QSPI:
      Read range 0x08000000 - 0x081FFFFF (MCU flash 2 Mbytes) 8.824 second
      Read range 0x90000000 - 0x901FFFFF (External flash 2 Mbytes) 45.867 second
      Therefore, I think I can increase the read speed of an external flash. For reading and verification I use the built-in MCU memory mapped mode

      C Source Code: FlashOrg.c

      1. //for example verify function
      2. U32 Verify (U32 Addr, U32 NumBytes, U8 *pSrcBuff )
      3. {
      4. U8* pData = (U8 *)Addr;
      5. _FeedWatchdog();
      6. do {
      7. if (*pData++ != *pSrcBuff++) {
      8. return (U32) pData--;
      9. }
      10. } while (--NumBytes);
      11. return (U32) pData;
      12. }
      Display All
      So, I have some questions:
      1. What do you recommend to increase reading speed?
      2. Can I use data cache and instruction cache?
      3. What I can not use in the open flash loader?
      4. Do I need to reset the watchdog?

      Regards, Maxim Hunko

      The post was edited 1 time, last by MaximHunko ().

    • I managed to discover one pattern, the more I set the size of the PageSize field, the faster the reading process is going on. The maximum that I managed to achieve is 16 Kbytes versus 256 bytes. With such settings, the reading results are as follows:
      Read range 0x08000000 - 0x081FFFFF (MCU flash 2 Mbytes) 0.224 second
      Read range 0x90000000 - 0x901FFFFF (External flash 2 Mbytes) 11.975 second
      I am attaching my FlashDevice array

      C Source Code: FlashDev.c

      1. #define ONCHIP (1) // On-chip Flash Memory
      2. #define MAX_NUM_SECTORS (512) // Max. number of sectors, must not be modified.
      3. #define ALGO_VERSION (0x0101) // Algo version, must not be modified.
      4. #define FLASH_BASE_ADDR (0x90000000)
      5. #define READ_WRITE_BYTES (16 * 1024)
      6. #define PROGRAM_PAGE_TIMEOUT_MS (S25FL256_TIMEOUT_PAGE_WRITE_MAX_MS * 100)
      7. #define ERASE_SECTOR_TIMEOUT_MS (S25FL256_TIMEOUT_SECTOR_ERASE_MAX_MS * 10)
      8. struct FlashDevice const FlashDevice __attribute__ ((section ("DevDscr"))) = {
      9. ALGO_VERSION, // Algo version
      10. "S25FL256S_32H753XI", // Flash device name
      11. ONCHIP, // Flash device type
      12. FLASH_BASE_ADDR, // Flash base address
      13. EXT_FLASH_SIZE, // Total flash device size in Bytes (32 Mbyte)
      14. READ_WRITE_BYTES, // Page Size (number of bytes that will be passed to ProgramPage().
      15. 0, // Reserved, should be 0
      16. 0xFF, // Flash erased value
      17. PROGRAM_PAGE_TIMEOUT_MS, // Program page timeout in ms
      18. ERASE_SECTOR_TIMEOUT_MS, // Erase sector timeout in ms
      19. //
      20. // Flash sector layout definition
      21. //
      22. {
      23. { EXT_FLASH_SECTOR_SIZE, 0x00000000 },
      24. { 0xFFFFFFFF, 0xFFFFFFFF }
      25. }
      26. };
      Display All
    • Today I noticed another detail. When I start erasing in J-Flash, I see in the log that when erasing the internal memory, the CPU is running at 185 MHz. And when the external memory is erased, the log says: CPU speed could not be measured.
      What does that mean? What am I doing wrong initialization? Here is the code of my function init.

      C Source Code: FlashPrg.c

      1. int Init(U32 Addr, U32 Freq, U32 Func)
      2. {
      3. U32 v;
      4. (void)Addr;
      5. (void)Freq;
      6. (void)Func;
      7. driverInit(); //init gpio and qspi
      8. int result = ExtFlash_Init() ? 0 : 1; //try read jdec id and ret 0 if success
      9. if (Func == 3) { //if read operation -> turn on qspi memory mapped mode
      10. ExtFlash_SetMemoryMappedMode();
      11. }
      12. return result;
      13. }
      Display All
      As you can see, I ignore the Freq parameter. Do I have to manually configure PLL in the Init function?
      Images
      • 2.jpg

        74.25 kB, 383×478, viewed 23 times
    • Hello all! In the process of studying the architecture of the flash loader, I discovered the fact that there is no exact description of how reading works: wiki.segger.com/Open_Flashloader#Flash_Read_Procedure
      Dear forum participants, if you are interested in this topic, please write here, what do you think about this. Maybe we can study this issue together faster!
      Now I have managed to achieve the following results:
      • Full chip erase 69 second
      • Full chip blank check 5.5 second
      • Read full memory (after erasing) 5.5 second
      • Program full memory 174 seconds
      • Read full memory (random data) 146 seconds


      The results show that reading blanked memory is much faster than reading memory with random data. Therefore, I think that the j-link first tries to check whether the page is erased (using function BlankCheck(addr, SECTORSIZE, 0xFF) ), and if it is not erased, goes to direct reading, using function SEGGER_OPEN_Read(addr, size, pData)
      Anyone have any ideas on how to increase read speed? Thanks
      Images
      • result.jpg

        96.94 kB, 539×724, viewed 23 times
    • Hi MaximHunko,

      Glad to meet you here, and I'm working on this open flash loader too for our products.
      I saw you've done a lot on the open flash loader.
      If you don't mind, could you share some insensitive source code with me please?
      For the external nor flash with JLink, often some unexpected programming or verifying error comes up.
      To fix it, we only could erase the whole external nor flash, and do the programming again.

      Also, some last bytes in the external nor flash cannot be read out from the STM32 errata.

      Thank you.
    • hi Maxim,

      Thank you for you kind.

      And one more question, have you ever encounter the issue that STM32L4R9 OSPI memory-map read the whole exernal NorFlash, like whole 16MB,
      errors will come up for the last few bytes, like 0x90FFFFFA to 0x90FFFFFF, memory-map read will cause excetpion.

      so a workaround, when the memory-map flash pointer points to an address that is larger than 0x90FFFFFA, I will cancel the read, with __DSB(), and OSPI abort API.

      and then reconfigure the OSPI controller. but for this, a weird issue comes as below,
      when in Segger embedded studio debugger mode, it works fine to memory-map read the higher address flash part, including the last few bytes at the end of flash memory,
      but when flash loader is built as Release version, and put it into STM32L4 folder in JLink install dir, and then run JFlash to read whole external flash chip, it seems, the last few bytes read out are not the bytes as expected.

      if you don't mind, could you do me a favour send source code to me programassem@hotmail.com.

      Thank you so much.

      Shawn
    • I came across a similar problem when I read the full 32 megabytes, the last byte was 0 instead of the correct value. But there was no exception. Later I did this:

      #define SUPPORT_SEGGER_OPEN_READ (1)
      #define SUPPORT_NATIVE_READ_FUNCTION (0)

      In order for the segger software to understand that the data can be read directly in the memory mapped mode, and of course, in Init function, for read, I call ExtFlash_SetMemoryMappedMode();
      It works good for me.
      Here is my FlashPrg.c file:

      C Source Code: FlashPrg.c

      1. /*********************************************************************
      2. * (c) 1995 - 2018 SEGGER Microcontroller GmbH *
      3. * The Embedded Experts *
      4. * www.segger.com *
      5. **********************************************************************
      6. ----------------------------------------------------------------------
      7. File : FlashPrg.c
      8. Purpose : Implementation of RAMCode for ST STM32H753XI/BI
      9. -------- END-OF-HEADER ---------------------------------------------
      10. */
      11. #include <stdint.h>
      12. #include <stddef.h>
      13. #include <stdbool.h>
      14. #include "FlashOS.H"
      15. #include "s25fl256.h"
      16. #include "Driver.h"
      17. #define SUPPORT_BLANK_CHECK (0) // No separate blank check is required as the flash
      18. // is memory mapped readable
      19. #define SUPPORT_SEGGER_OPEN_READ (1)
      20. #define SUPPORT_SEGGER_OPEN_Program (1)
      21. #define SUPPORT_SEGGER_OPEN_ERASE (1)
      22. #define SUPPORT_NATIVE_READ_FUNCTION (0)
      23. #define SUPPORT_WATCHDOG_RESET (0)
      24. #if SUPPORT_WATCHDOG_RESET
      25. void _FeedWatchdog(void)
      26. {
      27. driverFeedWatchdog();
      28. }
      29. #else
      30. #define _FeedWatchdog() *(volatile U32*)(0x4) // Dummy to make sure that function is linked non-inlined
      31. #endif
      32. /*********************************************************************
      33. *
      34. * Types
      35. *
      36. **********************************************************************
      37. */
      38. typedef struct {
      39. U32 acr;
      40. } RESTORE_INFO;
      41. typedef union {
      42. struct {
      43. void* pSrc;
      44. void* pDest;
      45. U32 NumHWords;
      46. U32 WritePara0;
      47. U32 WritePara1;
      48. U32 WritePara2;
      49. } In;
      50. struct {
      51. void* FailAddr;
      52. } Out;
      53. } IO_PARA;
      54. /*********************************************************************
      55. *
      56. * Static code
      57. *
      58. **********************************************************************
      59. */
      60. const U32 SEGGER_OPEN_FLASHLOADER_FLAGS = 0xFEED;
      61. static RESTORE_INFO _pRestoreInfo;
      62. static U32 gFunc = 0;
      63. /*********************************************************************
      64. *
      65. * Public code
      66. *
      67. **********************************************************************
      68. */
      69. /*********************************************************************
      70. *
      71. * Init
      72. *
      73. * Function description
      74. * Handles the initialization of the flash module.
      75. *
      76. * Parameters
      77. * Addr: Flash base address
      78. * Freq: Clock frequency in Hz
      79. * Func: Specifies the action followed by Init() (e.g.: 1 - Erase, 2 - Program, 3 - Verify / Read)
      80. *
      81. * Return value
      82. * 0 O.K.
      83. * 1 Error
      84. */
      85. int Init(U32 Addr, U32 Freq, U32 Func)
      86. {
      87. (void)Addr;
      88. (void)Freq;
      89. _FeedWatchdog();
      90. gFunc = Func;
      91. mcuFreqInit();
      92. driverInit();
      93. int result = ExtFlash_Init() ? 0 : 1;
      94. if (Func != INIT_FOR_WRITE && Func != INIT_FOR_ERASE) {
      95. _FeedWatchdog();
      96. ExtFlash_SetMemoryMappedMode();
      97. }
      98. return result;
      99. }
      100. /*********************************************************************
      101. *
      102. * UnInit
      103. *
      104. * Function description
      105. * Handles the de-initialization of the flash module.
      106. *
      107. * Parameters
      108. * Func: Caller type (e.g.: 1 - Erase, 2 - Program, 3 - Verify)
      109. *
      110. * Return value
      111. * 0 O.K.
      112. * 1 Error
      113. */
      114. int UnInit(U32 Func)
      115. {
      116. (void)Func;
      117. _FeedWatchdog();
      118. driverDeinit();
      119. mcuFreqDeinit();
      120. return 0;
      121. }
      122. /*********************************************************************
      123. * Function description
      124. *
      125. * Compares a specified number of bytes of a provided data buffer with
      126. * the content of the device
      127. * Parameters
      128. *
      129. * Addr: Start address in memory which should be compared
      130. * NumBytes: Number of bytes to be compared
      131. * pBuff: Pointer to the data to be compared
      132. * Return values
      133. *
      134. * == (Addr + NumBytes): O.K.
      135. * != (Addr + NumBytes): *not* O.K.
      136. * (ideally the fail address is returned)
      137. */
      138. U32 Verify (U32 Addr, U32 NumBytes, U8 *pSrcBuff )
      139. {
      140. U8* pData = (U8 *)Addr;
      141. _FeedWatchdog();
      142. do {
      143. if (*pData++ != *pSrcBuff++) {
      144. return (U32) --pData;
      145. }
      146. } while (--NumBytes);
      147. return (U32) pData;
      148. }
      149. /*********************************************************************
      150. *
      151. * EraseSector
      152. *
      153. * Function description
      154. * Erases one flash sector.
      155. *
      156. * Parameters
      157. * SectorAddr: Absolute address of the sector to be erased
      158. *
      159. * Return value
      160. * 0 O.K.
      161. * 1 Error
      162. */
      163. int EraseSector(U32 SectorAddr)
      164. {
      165. _FeedWatchdog();
      166. ExtFlash_EraseSector(SectorAddr - FLASH_BASE_ADDR);
      167. return 0;
      168. }
      169. #if 1 // We do not support EraseChip() as it is much slower than erase the flash sector by sector
      170. /*********************************************************************
      171. *
      172. * EraseChip
      173. *
      174. * Function description
      175. * Erases the entire flash
      176. *
      177. * Return value
      178. * 0 O.K.
      179. * 1 Error
      180. */
      181. int EraseChip(void)
      182. {
      183. _FeedWatchdog();
      184. ExtFlash_EraseChip();
      185. return 0;
      186. }
      187. #endif
      188. /*********************************************************************
      189. *
      190. * ProgramPage
      191. *
      192. * Function description
      193. * Programs one flash page.
      194. *
      195. * Parameters
      196. * DestAddr: Destination address
      197. * NumBytes: Number of bytes to be programmed (always a multiple of program page size, defined in FlashDev.c)
      198. * pSrcBuff: Point to the source buffer
      199. *
      200. * Return value
      201. * 0 O.K.
      202. * 1 Error
      203. */
      204. int ProgramPage(U32 DestAddr, U32 NumBytes, U8 *pSrcBuff)
      205. {
      206. _FeedWatchdog();
      207. ExtFlash_Write(DestAddr - FLASH_BASE_ADDR, pSrcBuff, NumBytes);
      208. return 0;
      209. }
      210. /*********************************************************************
      211. *
      212. * BlankCheck
      213. *
      214. * Function description
      215. * Checks if a memory region is blank
      216. *
      217. * Parameters
      218. * Addr: Blank check start address
      219. * NumBytes: Number of bytes to be checked
      220. * BlankData: Pointer to the destination data
      221. *
      222. * Return value
      223. * 0: O.K., blank
      224. * 1: O.K., *not* blank
      225. * < 0: Error
      226. *
      227. */
      228. #if SUPPORT_BLANK_CHECK
      229. int BlankCheck(U32 Addr, U32 NumBytes, U8 BlankData)
      230. {
      231. int result = 0;
      232. U8* pData = (U8 *)Addr;
      233. U32 bytesToCheck = NumBytes;
      234. _FeedWatchdog();
      235. if (gFunc != INIT_FOR_READ) {
      236. ExtFlash_SetMemoryMappedMode();
      237. }
      238. do {
      239. if (pData[0] != BlankData) {
      240. result = 1;
      241. break;
      242. }
      243. pData++;
      244. } while (--bytesToCheck);
      245. if (gFunc != INIT_FOR_READ) {
      246. driverDeinit();
      247. driverInit();
      248. ExtFlash_Init();
      249. }
      250. return result;
      251. }
      252. #endif
      253. /*********************************************************************
      254. *
      255. * SEGGER_OPEN_Read
      256. *
      257. * Function description
      258. * Reads a specified number of bytes into the provided buffer
      259. *
      260. * Parameters
      261. * Addr: Start read address
      262. * NumBytes: Number of bytes to be read
      263. * pBuff: Pointer to the destination data
      264. *
      265. * Return value
      266. * >= 0: O.K., NumBytes read
      267. * < 0: Error
      268. *
      269. */
      270. #if SUPPORT_NATIVE_READ_FUNCTION
      271. int SEGGER_OPEN_Read(U32 Addr, U32 NumBytes, U8 *pDestBuff)
      272. {
      273. U8* pData;
      274. pData = (U8 *)Addr;
      275. _FeedWatchdog();
      276. for (int32_t i = 0; i < NumBytes; i++) {
      277. pDestBuff[i] = pData[i];
      278. }
      279. return NumBytes;
      280. }
      281. #endif
      282. /*********************************************************************
      283. *
      284. * SEGGER_OPEN_Program
      285. *
      286. * Function description
      287. * Programs a specified number of bytes into the target flash.
      288. * NumBytes is either FlashDevice.PageSize or a multiple of it.
      289. *
      290. * Notes
      291. * (1) This function can rely on that at least FlashDevice.PageSize will be passed
      292. * (2) This function must be able to handle multiple of FlashDevice.PageSize
      293. *
      294. * Parameters
      295. * Addr: Start read address
      296. * NumBytes: Number of bytes to be read
      297. * pBuff: Pointer to the destination data
      298. *
      299. * Return value
      300. * 0 O.K.
      301. * 1 Error
      302. *
      303. */
      304. #if SUPPORT_SEGGER_OPEN_Program
      305. int SEGGER_OPEN_Program(U32 DestAddr, U32 NumBytes, U8 *pSrcBuff)
      306. {
      307. _FeedWatchdog();
      308. ExtFlash_Write(DestAddr - FLASH_BASE_ADDR, pSrcBuff, NumBytes);
      309. return 0;
      310. }
      311. #endif
      312. /*********************************************************************
      313. *
      314. * SEGGER_OPEN_Erase
      315. *
      316. * Function description
      317. * Erases one or more flash sectors
      318. *
      319. * Notes
      320. * (1) This function can rely on that at least one sector will be passed
      321. * (2) This function must be able to handle multiple sectors at once
      322. * (3) This function can rely on that if sector size changes,
      323. *
      324. * Parameters
      325. * SectorAddr: Address of the start sector to be erased
      326. * SectorIndex: Index of the start sector to be erased
      327. * NumSectors: Number of sectors to be erased. At least 1 sector is passed.
      328. *
      329. * Return value
      330. * 0 O.K.
      331. * 1 Error
      332. *
      333. */
      334. #if SUPPORT_SEGGER_OPEN_ERASE
      335. int SEGGER_OPEN_Erase(U32 SectorAddr, U32 SectorIndex, U32 NumSectors)
      336. {
      337. uint32_t sectorCount = NumSectors;
      338. uint32_t realAddress = SectorAddr - FLASH_BASE_ADDR;
      339. _FeedWatchdog();
      340. do {
      341. ExtFlash_EraseSector(realAddress);
      342. realAddress += EXT_FLASH_SECTOR_SIZE;
      343. } while (sectorCount--);
      344. return 0;
      345. }
      346. #endif
      Display All
    • Hi maxim,

      A few questions here

      1. if memory-map read is supported, is it necessary to implement verify()?
      2. in your init() memorymap mode maybe enabled, but I don't find you do the memorymap mode disabling in Uninit()
      should the enable and disable be present in pair, right?

      3. you have
      #define SUPPORT_SEGGER_OPEN_READ (1)

      but the following code appears

      #if SUPPORT_NATIVE_READ_FUNCTION
      int SEGGER_OPEN_Read(U32 Addr, U32 NumBytes, U8 *pDestBuff)

      is it a typo?


      for the problem we both encounter, you mean by defining SUPPORT_SEGGER_OPEN_READ with 1, and implement SEGGER_OPEN_Read(), which would be enough to go across that read last few bytes exception problem, right?

      One more quesiton in Init() and Uninit() code, so I guess, if we first do a read, ExtFlash_SetMemoryMappedMode() is called to enable memory-map read. and after read, we do a program, do you think, at this moment, previous memory-map enabling will take some effect on this program op?

      1. int Init(U32 Addr, U32 Freq, U32 Func)
      2. {
      3. (void)Addr;
      4. (void)Freq;
      5. _FeedWatchdog();
      6. gFunc = Func;
      7. mcuFreqInit();
      8. driverInit();
      9. int result = ExtFlash_Init() ? 0 : 1;
      10. if (Func != INIT_FOR_WRITE && Func != INIT_FOR_ERASE) {
      11. _FeedWatchdog();
      12. ExtFlash_SetMemoryMappedMode();
      13. }
      14. return result;
      15. }
      16. int UnInit(U32 Func)
      17. {
      18. (void)Func;
      19. _FeedWatchdog();
      20. driverDeinit();
      21. mcuFreqDeinit();
      22. return 0;
      23. }
    • let's go a litter futher, I'm not sure if you've read below in STM32 reference manual.

      /******************************************************************************************************
      RM0432

      19.4.6 OCTOSPI busy bit and abort functionality
      • Once the OCTOSPI starts an operation with the external device,
      the BUSY bit is automatically set in the OCTOSPI_SR.
      • In indirect mode, the BUSY bit is reset once the OCTOSPI has completed the requested
      command sequence and the FIFO is empty.
      • In automatic-polling mode, BUSY goes low only after the last periodic access is complete,
      due to a match when APMS=1, or due to an abort.
      • After the first access in memory-mapped mode, BUSY goes low only on a timeout event or
      on an abort.
      • Any operation can be aborted by setting the ABORT bit in the OCTOSPI_CR.
      Once the abort is completed, the BUSY bit and the ABORT bit are automatically reset,
      and the FIFO is flushed.
      • Before setting the ABORT bit, the software must ensure that all the current transactions are
      finished using the synchronization barriers.
      Note that some devices might misbehave if a write operation to a status registers is aborted.
      19.4.7 OCTOSPI reconfiguration or deactivation
      Prior to any OCTOSPI reconfiguration, the software must ensure that all the transactions
      are completed:
      • After a memory-mapped write, the software shall perform a dummy read followed by a
      synchronization barrier then an ABORT.
      • After a memory-mapped read, the software shall do a synchronization barrier then an
      abort.

      *******************************************************************************************************/

      for a complete switch from memory-map OSPI to indirect mode OSPI to read the last few bytes in the external NorFlash,

      some codes according to forementioned RM's description need to be implemented, have you done that already?

      I will try the OPEN read implement, and comment NATIVE READ, actually the code block should be the same, only the function names are different.
      Some segger open flash loader infos are not known to us, what we only can do is to implement and see if it works or not.