This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

slow flash erase performance with sd_flash_page_erase()

In my bootloader I'm using sd_flash_page_erase() directly without pstorage.

The flash erase performance is exceedingly slow. It is taking 13.187 seconds to erase 132 pages or 99.9ms/page (does that have any significance). I'm using sd7.1.0 on a week old 51822QFAC. The datasheet claims 22.3ms worst case, is there really that much overhead in erasing with the softdevice?

While erasing the system should be fairly idle, except for the 7.5-30ms connection interval (not sure what ble_dfu.py is setting it to). The next erase is triggered directly from the system event and I have tried with both the scheduler enabled and disabled.

The data receive and flash write performance isn't horrible. Using ble_dfu.py with RCPT_NOTIF not enabled, I'm receiving 132K in 31.2s (34718bps) with never more then 100 bytes of flash writes pending. As a result, the erase time represents a significant portion of the upgrade time. The best part is this is on a board without an antenna, just a trace and a non-populated ceramic antenna (part hadn't arrived when the board was assembled). For my application, DFU performance is critical because I'm also using it to upgrade an external 2MB SPI flash, so hopefully there is more room to increase the BLE performance.

Any ideas where to look for the source of the slow erase?

EDIT: Additional info. The problem is caused by the connection interval, the performance I was seeing above was at 20ms, I can't imagine how bad it is at 7.5ms. At 90ms the erase took 3.94s, which is much more reasonable, but this is with android, it seems the python dfu/MasterEmulator ignores the connection parameter requests, I never get the response event.

The erase may be faster on android (lollipop), but the download is painful, with a 18.75ms interval and 20pkts/notif I'm only getting 7789bps, with a somewhat modifed python script at 20ms I get 46856bps.

If I ever have to upgrade my full 2MB external flash (ouch) it would take 6min with the python script, but 36min with the current performance I'm seeing with android. Ouch!

  • gmaynard, changing the slave_latency on the peripheral side just long enough to do the erase sounds like a less painful way of doing it, but how do you actually do that without renegotiating?

    sd_ble_gap_conn_param_update() just request re-negotiation, and sd_ble_gap_ppcp_set() just updates the value the central can query. Temporarily bumping up the slave_latency would be useful the central would just treat it as normal packet loss, but how do you convince the sd to do that?

    However, I still ended up needing to convince the central stack to keep a small connection interval. At least with android I get the 7.5ms connection interval, which makes the dfu update on my Nexus 4 only very painfully slow as opposed to extremely painfully slow. I am really not looking forward to having to update several megabytes of external SPI flash over the air.

    The whole connection interval behavior is weird:

    connect randPriv: 7F:57:ED:2D:DC:98 487/10ms
    req min=900/10ms max=1250/10ms  /*  initial slow down request */
    interval update 1237/10ms /* android repsonds to my request*/
    interval update 75/10ms /* unexpected switch back to 7.5ms */
    interval update 1237/10ms /* another switch back to 123.7ms */
    /* dfu start, erase starts, erase completes */
    req min=75/10ms max=200/10ms /* another try, max value is for iOS */
    interval update 187/10ms /* android responds */
    req min=75/10ms max=75/10ms /* one more try */
    interval update 75/10ms /* finally the value I want */
    ... upload 19kbps for crappy nexus 4, faster on other phones ...
    
  • Don't change the slave latency. Change the local connection latency (gap_opt.local_conn_latency.requested_latency). That doesn't renegotiate.

    The difference is that the slave latency is negotiated with the host, but the local connection latency overrides that and ignores more packets anyway. This just looks like packet loss to the host, so it's OK as long as it doesn't ignore so many connections that the supervisory timeout expires and you get disconnected (and the SD won't let you set it this high). In this case, it basically tells the SD that it's OK to miss a couple packets in order to get the flash erase done. I'm not sure why the BTLE slave latency setting is even negotiated at all.

    So far I've found that it works fine if I just set it to a big value (50) and let the SD figure out what the maximum reasonable value is.

  • My grep-foo failed me. Many thanks, I knew you should be able to set the slave latency dynamically, but missed the how. I tried that out and it is a cleaner way to erase the flash. I still have the code to re-negotiate the connection interval, but I only do it on connection and try and convince the other side to use the fastest possible interval (7.5ms/android or 20ms/iOS).

Related