Suggestions for using external flash SPI

Hi, I looking for advices.

I have a project where I use a particle photon with external 1MB flash (winbond or IS25LQ080-JNLE-TR) or particle p1 with an LCD and I want to store fonts and image to the external memory.

I wont write anything to this memory while my code is running. I only need to program it once and after that I will only read it.

I did some research and found that one way would be to use the flahsee-eeprom library with fatfs. Using a virutal fat drive to build generate an image file and after upload it using dfu-util (not sure about that) or by creating a custom firmware only for loading the data on the flash.

I’m not sure how to do that.

What are you suggestions for creating an image that I would program on the external flash? Is there any programs that can help to do this? I tried with windows disk management but it doesnt work with small vhd.

One other solution would be to find code that allow the particle devices to act as mass storage devices so I would only need to plug it to my computer to copy files.

Other solution would be to get files content via HTTP (so it would be easier and automatic) and store it on the eeprom.

What do you think? I would like to use something that is already existing.

Another solution would be to use a Micro SD card, since I know that's something that's easy to program on a computer and seems like a common solution within the Particle community:

I’m using an sd card for development but for the final product, I dont have space for an sd card and holder. and price is more than 10-20 times the price of a spi flash… (holder + card).

@mdma should be able to shed some light on this. You can customize parts of the system firmware for P1 to suit your needs. You could potentially do this over serial.

If this is a one time write operation, and you plan to commercialize it, I believe you can use traditional EEPROM burners to load an image onto the memory before populating on the PCB. A lot of JTAG programmers also support this feature and can accomplish this in-system.

Yes I could do it over serial but this would mean to create to software to do it and I cannot find any info regarding this. I would really like to not to have to start from scratch.

And I would need to generate an bin image to send to the eeprom (I’m not sure how to do that and I wasnt able to find any software to help me doing this).

The eeprom is SOIC-8 and assembled by the pcb assembly so I cannot burn it with an eeprom burner.
Regarding the JTAG, I’m not sure how I would do this with the particle photon. It seems too complicated…

Still looking for ideas…

Right now I think that I would use the eeprom use it as fat with the library and I’ll send files over http (ftp maybe) or via serial with a custom software on windows…

I found this nice project which is perfect for me and work well with an SD card: FTPino - A FTP Client and Server for the Particle

But now I need something to do the same thing with the eeprom.
So I can use the flashee-eeprom library, support my chip IS25LQ080 which is compatible with W25Q80BV and I found a small adafruit library for it (but the code is very simple).

So my question now is how do I integrate a new library for my external eeprom in the flashee library.
I’m not good with c++ and all the classes.

I think the way to go would be to do the same thing as the SparkExternalFlashDevice but right now I dont know how to make this work…
I know this is not a big deal but I dont know how to do that… Here is my code and the error I get is:

undefined reference to `Flashee::Adafruit_TinyFlash::Adafruit_TinyFlash(unsigned char)’

#ifndef HAS_SERIAL_FLASH
#define HAS_SERIAL_FLASH
#define sFLASH_PAGESIZE (256)
#define sFLASH_PAGECOUNT (4096)
#endif
#elif defined(HAS_SERIAL_FLASH)
#endif
#include "Adafruit_TinyFlash.h"
#ifdef HAS_SERIAL_FLASH

class SparkExternalFlashDevice : public FlashDevice {
    
    Adafruit_TinyFlash flash;
    
    
public:
    SparkExternalFlashDevice()
    {
        uint8_t manID, devID;
        
        flash.begin(&manID, &devID);
    }

    /**
    * @return The size of each page in this flash device.
    */
    virtual page_size_t pageSize() const {
        return sFLASH_PAGESIZE;
    }

    /**
    * @return The number of pages in this flash device.
    */
    virtual page_count_t pageCount() const {
        return sFLASH_PAGECOUNT;
    }

    virtual bool erasePage(flash_addr_t address) {
        bool success = false;
        if (address < pageAddress(pageCount()) && (address % pageSize()) == 0) {
            //sFLASH_EraseSector(address);
            success = flash.eraseSector(address);
            //success = true;
        }
        return success;
    }

    /**
    * Writes directly to the flash. Depending upon the state of the flash, the
    * write may provide the data required or it may not.
    * @param data
    * @param address
    * @param length
    * @return
    */
    virtual bool writePage(const void* data, flash_addr_t address, page_size_t length) {
        // TODO: SPI interface shouldn't need mutable data buffer to write?
        //sFLASH_WriteBuffer(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(data)), address, length);
        while (length > 0)
        {
            flash.writePage(address, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(data)));
            address += sFLASH_PAGESIZE;
            length -= sFLASH_PAGESIZE;
        }
        return true;
    }

    virtual bool readPage(void* data, flash_addr_t address, page_size_t length) const {
        //sFLASH_ReadBuffer((uint8_t*)data, address, length);
        //flash.readblock((uint8_t*)data, address, length);
        page_size_t i;
        uint8_t*  _data = (uint8_t*)data;
        flash.beginRead(address);
        for(i = 0; i < length; i++)
        {
            _data[i] = flash.readNextByte();
        }
        flash.endRead();
        return true;
    }

    /**
    * Writes data to the flash memory, performing an erase beforehand if necessary
    * to ensure the data is written correctly.
    * @param data
    * @param address
    * @param length
    * @return
    */
    virtual bool writeErasePage(const void* data, flash_addr_t address, page_size_t length) {
        return false;
    }

    /**
    * Internally re-reorganizes the page's storage by passing the page contents via
    * a buffer through a handler function and then writing the buffer back to
    * memory.
    *
    * @param address
    * @param handler
    * @param data
    * @param buf
    * @param bufSize
    * @return
    */
    virtual bool copyPage(flash_addr_t address, TransferHandler handler, void* data, uint8_t* buf, page_size_t bufSize) {
        return false;
    }

};
#endif // HAS_SERIAL_FLASH
#endif // SPARK

Finally I’m using SPIFFS https://github.com/pellepl/spiffs for my external eeprom and I integrated that to the FTP server application.

1 Like

@Suprazz So you added SPIFFS to communicate with the external SPI flash chip.

Then you modified the FTP server application so you can update the data on the SPI flash chip remotely over the internet right?

Since a remote firmware update on the Photon or Electron does not allow you also to update the external flash or the extra flash on the P1 module your solution looks like a good way to update the data on the SPI flash chip remotely also after a firmware update happens.

Can you see your solution as a way of doing this?

How are you using this?

I dont plan to leave the ftpserver application running. I only plan to use it to upload the files needed for my application (images, fonts, configuration).

Using a ftp server remotly is a problem because of the firewall configuration. So I dont think it’s a good idea. It would be better to be a ftp client and check on a ftp server for firmware updates instead.

2 Likes

@Suprazz Yea that makes sense.

If I’m following you correctly, the code on the Photon or Electron would be set up as an FTP client that connects to a remote FTP server when we tell it to pull in the new image, font data?

This way I just set up a web hosted FTP server and the Photons or Electrons just connect to it when we tell it to do so?

Would this be easy to do with the current library you are using?

Do you just add the FTP server address, user name, and password to the Photon’s application code to access the FTP server.

I’m just wondering how easy and reliable this could be.

I want to push LCD images and new fonts to the external memory so I can update the graphics on the 2.7 inch LCD display any time I want to update the product.

Yes you can do that.

An other solution would be to host your files on a http server and simply make a get command in a tcp socket. Its easy to do and you dont have to support ftp…

Sounds perfect :smiley:

I don’t know how to code that but you make it sound like anybody with some skill should be able to make it happen. Is that right?

I just want to be able to wipe the external flash after a firmware update and then update the Flash with image/font data via your TCP Get request if needed. This way I can remotely upgrade the whole system, and I’m not limited to the limited memory of the Photon / Electron.

@Peekay123 @ScruffR Do you guys see any reasons this would not work?

Just define clearly what you want.
Then after the firmware upgrade, you can hard code links to the news files and wipe the memory, download the new files and you should be good to go.

Regarding the http request. look for a simple get. Here is an example of what I do in an other C project.

strcpy(tcpBuffer, "GET ");
strcat(tcpBuffer, address);
strcat(tcpBuffer, " HTTP/1.1\r\nHost: ");	
strcat(tcpBuffer, ServerName);
strcat(tcpBuffer, "\r\n\r\n");
TCPSend();

@Suprazz I need help creating a function that I can call after I do a remote firmware update that does the following:

1 - Wipes the current SPI Flash chip clean.
2 - Call the HTTP Get request.
3 - Dump the new data onto the external SPI Flash Chip.
4 - Set a Flag to indicate that this function has executed so it will not run again unless we clear the flag.

What external SPI memory chip are you using?

To make this easy, I can just use the same brand SPI chip that you are since you already have the Photon / Electron working with it. I’m just looking for 1 or 2 Mb sized chip.

I can send you some cash, or a few Photons, or an Electron in return for your time to help out with this if you’re able to help me out with this. :smiley:

Thanks!

yes I can help you with that.

You can use a winbond flash or any equivalent. I’m using the IS25LQ080.

Contact me in pm

Sweet!

Do you see any problem with using a FRAM chip instead of the chip you’re using? I want to use this one mainly because of it’s lower power consumption due to it’s quicker read times. Plus the read / write cycle life is virtually unlimited.

http://www.digikey.com/product-detail/en/fujitsu-electronics-america-inc/MB85RS1MTPNF-G-JNERE1/865-1255-1-ND/4022688

There is a working library for this FRAM chip for the Photon & Electron here:

Do you see any problems with using this FRAM chip instead considering the working library is available?

Thanks :smiley:

NAND Flash is a better solution for you.
Write speed is not important in your case because it wont happen often.
This FRAM chip is 10x the cost of a flash chip and it’s only 128k bytes, versus 1mega bytes.

The read cycle of a flash chip is unlimited, it’s only the write that is limited but write cycle is like 1 million. I’m pretty sure you’ll never get close to that by simply storing few images when you upgrade the firmware.

I agree with you. It’s better to only spend 30 cents.

I’ll order up one of the IS25LQ080 chips now.

How do we proceed? I prefer to keep it public so others can benefit from this also.

@RWB, with external fonts and graphics you’ll need to adapt your display libraries to get the data from SPI. I will slow down the display refresh but I suspect in your case, that is not a problem.

Thanks @peekay123

Did you ever get the Sharp LCD’s working with the FRAM memory chip’s I sent you awhile back? Just wondering if you already have the adapted library written for FRAM or not.

If not, would you be able to help with altering the Sharp LCD code to pull Bitmap data from the external memory? I have no idea how to accomplish this.