Xiao BLE Sense using Mbed LittleFS on QSPI blockdevice

Hello, I am unable to mount a mbed littlefs filesystem to the Xiao BLE Sense on-board qspi flash. Urgent help needed.
I am using Windows Arduino IDE 2.04, and I installed the Seeed NRF52 mbed-enabled Boards v2.9.1 through board manager.
First, I checked this post about qspi demo code.

However, the qspi demo code does not work with the above mentioned seeed library v2.9.1. I went to the lib repo and found a commit after the v2.9.1 release. I updated the lib files according to the commit and the demo code worked. The commit is linked below.

Second, I tried to mount a mbed littlefs to the qspi, but failed. Then I tried to mount the littlefs to a heap blockdevice, it worked! So I was wondering what should I do to mount the littlefs to the on-board qspi.
My testing code is attached below. The format error code is -4005, and the mount error code is -138. Thanks a lot!

#include “mbed.h”
#include “BlockDevice.h”
#include “QSPIFBlockDevice.h”
#include “LittleFileSystem.h”
#include “HeapBlockDevice.h”

//QSPIFBlockDevice bd(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_1, MBED_CONF_QSPIF_QSPI_FREQ);

//mbed::BlockDevice *bd = new mbed::HeapBlockDevice(2048, 1, 1, 512);

mbed::BlockDevice *bd = new QSPIFBlockDevice(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_1, MBED_CONF_QSPIF_QSPI_FREQ);

mbed::LittleFileSystem fs(“fs”);

void setup() {
Serial.begin(115200);
while (!Serial);

Serial.println(“init the blockdevice…”);

int err = bd->init();
if(err) {
Serial.print(“init error. err code=”);
Serial.println(err);
}

Serial.print("bd read size = ");
Serial.println(bd->get_read_size());
Serial.print("bd program size = ");
Serial.println(bd->get_program_size());
Serial.print("bd erase size = ");
Serial.println(bd->get_erase_size());
Serial.print("bd erase value at addr 0 = ");
Serial.println(bd->get_erase_size(0));

int force_format = 1;
if (force_format) {
err = fs.format(bd);
if (err) {
Serial.print("format err = ");
Serial.println(err);
}
}

err = fs.mount(bd);
if (err) {
Serial.print("mount err = ");
Serial.println(err);
}

bd->deinit();
}

void loop() {
Serial.println(“testing done”);
delay(10000);
}

Hi,

Is there a repository where I can get the raw code, or maybe you can use the code quotation so I can copy and paste it without too much headache.

Regards

By the way, from a quick search in mbed source code, I found that:

  • 4005 error stands for :
    QSPIF_BD_ERROR_INVALID_ERASE_PARAMS = -4005, /* Erase command not on sector aligned addresses or exceeds device size */

Though, I couldn’t find a relevant reference to error -138.

I could not find any reference to the size of the flash within the source files.

I think that the mbed environment is misconfigured. But it’s hard to find any documentation. For example, this file from the commit that you linked: variants/SEEED_XIAO_NRF52840_SENSE/mbed_config.h is automatically generated, but the source of that generated file has not been committed, that’s probably why the feature has been later reverted later.

Try to add this:

Serial.print("bd size = ");
Serial.println((int)bd->size());

I get 0, but since, I have a non-“sense” board, I’m not sure that the test is totally valid. I built the programm and sent it to my board. Anyway I would not be surprised if you get the same result.

I got it work!
I had to make a change in your code to get it work as you describe:
mbed::BlockDevice *bd = new QSP... turns to QSPIFBlockDevice *bd = new QSP...
With that I can reproduce the issue and I noticed that the erase size is 256 which is the PAGE size, while blocks are expected as described in BlockDevice.h:

    /** Get the size of an erasable block
     *
     *  @return         Size of an erasable block in bytes
     *  @note Must be a multiple of the program size
     */
    virtual bd_size_t get_erase_size() const
    {
        return get_program_size();
    }

So I implemented a derived class of QSPIFBlockDevice and that’s it, here is my solution:

#include "mbed.h"
#include "BlockDevice.h"
#include "QSPIFBlockDevice.h"
#include "LittleFileSystem.h"
#include "HeapBlockDevice.h"

class MyQSPIFBlockDevice : public QSPIFBlockDevice
{
public:
  MyQSPIFBlockDevice(PinName io0 = MBED_CONF_QSPIF_QSPI_IO0,
                     PinName io1 = MBED_CONF_QSPIF_QSPI_IO1,
                     PinName io2 = MBED_CONF_QSPIF_QSPI_IO2,
                     PinName io3 = MBED_CONF_QSPIF_QSPI_IO3,
                     PinName sclk = MBED_CONF_QSPIF_QSPI_SCK,
                     PinName csel = MBED_CONF_QSPIF_QSPI_CSN,
                     int clock_mode = MBED_CONF_QSPIF_QSPI_POLARITY_MODE,
                     int freq = MBED_CONF_QSPIF_QSPI_FREQ) :
    QSPIFBlockDevice(io0, io1, io2, io3, sclk, csel, clock_mode, freq)                    
  {
  }
  virtual mbed::bd_size_t get_erase_size() const
  {
      return 32*1024;
  }
  virtual mbed::bd_size_t get_erase_size(mbed::bd_addr_t addr) const
  {
    return QSPIFBlockDevice::get_erase_size(addr);
  }
};

MyQSPIFBlockDevice *bd = new MyQSPIFBlockDevice(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_1, MBED_CONF_QSPIF_QSPI_FREQ);

mbed::LittleFileSystem fs("fs");

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("init the blockdevice…");

  int err = bd->init();
  if(err) {
    Serial.print("init error. err code=");
    Serial.println(err);
  }

  Serial.print("bd read size = ");
  Serial.println(bd->get_read_size());
  Serial.print("bd program size = ");
  Serial.println(bd->get_program_size());
  Serial.print("bd erase size = ");
  Serial.println(bd->get_erase_size());
  Serial.print("bd erase value at addr 0 = ");
  Serial.println(bd->get_erase_size(0));
  Serial.print("bd size = ");
  Serial.println(bd->size());

  int force_format = 1;
  if (force_format) {
    err = fs.format(bd, bd->get_read_size(), bd->get_program_size(), bd->get_erase_size(), 64);
    if (err) {
      Serial.print("format err = ");
      Serial.println(err);
    }
  }

  err = fs.mount(bd);
  if (err) {
    Serial.print("mount err = ");
    Serial.println(err);
  }

  bd->deinit();
}

void loop() {
  Serial.println("testing done");
  delay(10000);
}
2 Likes

WOW!!! This is amazing. Thanks !

One more question, why 32*1024? Thanks.

Well the P25Q16H datasheet states that the size of a block is either 32K or 64K (p17), I tried 32K with the idea that the smaller the block the better it is. But there is something weird, erasing 32K relies on the QSPIF command BE32K, while 64K relies on the command BE. It means that the QSPIF implementation is able to select the right command based on the erase size.

Based on that, I did another trial this morning with the sector size 4*1024 instead of 32*1024, and it works. This is a much better option.

This value is much better because 32kB is very limitating. Indeed there are only 64 blocks of 32kB in a 2MB memory. As far as I know, a file takes at least 1 block, so… you will be able to store only a few tens of files. The best would be to erase a page (256B), but we both know that it doesn’t work.

I wish I could find the cpp file where QSPIF is implemented.

1 Like

Amazing! I’ve been breaking my head around this too and you solved it!! Thanks a lot!

I have been trying to find a solution to same problem for days and finally stumbled upon this, thanks!
However, when I tried running the code, this error was generated- “‘QSPI_FLASH1_IO0’ was not declared in this scope” and I can’t figure out why because it is declared in the QSPIFBlockDevice header file. Do you have an idea?
Thanks in advance.

Hello,

To get access to the QSPI Flash, you need to install the patch as described in the first message of this thread (Patch).

If you’re not feeling comfortable with git, just copy the 6 files of the patch one by one. Pay attention to the fact that updating the package through the board manager will erase these modifications.

IMHO, the mbed implementation is not ready/fully functional, if you have the choice, use the “not mbed” one.

Hi there,
MAn Brother you said it "

If I were seeed Engineering I would stop making new stuff(support problems) and Fix some of these commits. IMHO… C’mon man.(seeed)
GL :slight_smile: PJ