[ABANDONED] Open flash loader is too slow

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

  • [ABANDONED] 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 423 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 438 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.