Go Down

Topic: SPIFlash library - Now works with Winbond/Microchip/Spansion/Cypress (Read 36209 times) previous topic - next topic

Marzogh

Hi all, I've just written up a library with a bunch of basic and advanced functions for the SPI Flash modules.

I'm looking at adding more functionality to the library in time. Any suggestions/improvements are welcome.

Update 17.11.2017:
      - Just updated to v 3.0.1 with a number of optimizations and improvements. Refer to ReadMe.md for further details.
.

As always, You can find the latest version on Github here --> SPIFlash Library for Arduino. v3.0.1 is also attached to this post as a ZIP file. :)

Marzogh

Just updated to v 1.0.1 and added the ability to output data to Serial as CSV decimal values.

As always, You can find the latest version on Github here --> SPI Flash library for Arduino. V1.0.1 is attached to this post. :)

ghlawrence2000

#2
Jun 04, 2015, 07:34 pm Last Edit: Jun 04, 2015, 07:36 pm by ghlawrence2000
Nice work, but it is not specific to the W25Q08! not 80...  they all share the same command structure, as such will also work for 2M, 4M, 8M & 16M :-

Code: [Select]
#define CHIP_SIZE128     16L * 1024L * 1024L  //W25Q128
#define CHIP_SIZE64       8L * 1024L * 1024L  //W25Q64
#define CHIP_SIZE32       4L * 1024L * 1024L  //W25Q32
#define CHIP_SIZE16       2L * 1024L * 1024L  //W25Q16
#define CHIP_SIZE8        1L * 1024L * 1024L  //W25Q08


Regards,

Graham
UTFT_SdRaw now included in library manager!! ;) High speed image drawing from SD card to UTFT displays for Mega & DUE.
UTFT_GHL - a VASTLY upgraded version of UTFT_CTE. Coming soon to a TFT near you! 8) Shipping April 1 2016!

chucktodd

How does your Library handle the 4k Erase sector size?  do you use a triangle buffer? The Uno only has 2k of ram.  If you need to change a value in the flash you have to erase an entire 4KB sector.

I wrote a similar Library, but I added a 64KB SPI Ram chip to use as a temporary buffer to copy the sector data into.  My library first verifies that the write is possible (memory bits can be programed to '0' only), if a bit is already '0' and needs to be a '1', it copies the corresponding sector to the SPI RAM, initiates a Sector Erase, merges the new data into the SPI RAM image, then after the Sector Erase Completes writes all non '0xff' bytes back into the FLASH by 256byte pages.

Chuck.
-----------------
check out my Kickstarter Memory Panes a 1MB RAM expansion Shield for MEGA2560 projects.
Currently built mega http server, Now converting it to ESP32.

ghlawrence2000

#4
Jun 05, 2015, 09:41 am Last Edit: Jun 05, 2015, 09:50 am by ghlawrence2000
Regarding your kickstarter project, NICE!! But why is it specific to the MEGA? Same form factor as the DUE, SPI pinout virtually the same, consider making the necessary modifications to work with MEGA AND DUE and I can see your project will do well or at least increase the potential number of devices pledged.

Regards,

Graham
UTFT_SdRaw now included in library manager!! ;) High speed image drawing from SD card to UTFT displays for Mega & DUE.
UTFT_GHL - a VASTLY upgraded version of UTFT_CTE. Coming soon to a TFT near you! 8) Shipping April 1 2016!

chucktodd

The DUE doesn't express all of the necessary pins from the Atmel processor.  The SAM3x does not multiplex A0-A7 and D0-D7.  The Processor has D0-D15 (PC2-PC17) A0-A22 (PC21-PC30,PD0-PD9)

But the DUE only expresses 

PC 2-9,12-17,21-26,28,30  Missing Data D8,9 Address A6,A8
PD 0-3,6-9 Missing Address A14,15

So, it is not possible unless a NEW Mega DUE is created and all of the necessary pins are expressed.

Chuck.
Currently built mega http server, Now converting it to ESP32.

robtillaart

Had a very quick look, and I noticed writepage does check the pagenumber but readpage doesn't.
shouldn't that be checked too?

Code: [Select]

boolean  SPIFlash::_readPage(uint16_t page_number, uint8_t *page_buffer) {
if(!_notBusy())
return false;
...

boolean SPIFlash::_writePage(uint16_t page_number, uint8_t *page_buffer) {
if(!_notBusy() || page_number >= 4096 || !_writeEnable())
return false;



page_number >= 4096  part
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

debugging refactored
Code: (not tested) [Select]

//Prints hex/dec formatted data from page reads - for debugging
void SPIFlash::_printPageBytes(uint8_t *page_buffer, uint8_t outputType)
{
  char buffer[10];
  if (outPutType == 1)
  {
    for (int idx = 0; idx < 256; ++idx)
    {
      sprintf(buffer, "%02x,", page_buffer[idx]);
      Serial.print(buffer);
    }
  }
  else   // if (outPutType == 2)
  {
    for (int idx = 0; idx < 256; ++idx)
    {
      int x = page_buffer[idx];
      if (x < 10) Serial.print("0");
      if (x < 100) Serial.print("0");
      Serial.print(x);
      Serial.print(',');
    }
  }
}


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#8
Jun 06, 2015, 09:18 am Last Edit: Jun 06, 2015, 09:20 am by robtillaart
using the return values of the private function result in faster failing.

Code: [Select]

boolean SPIFlash::writePage(uint16_t page_number, uint8_t *page_buffer)
{
  uint8_t temp_buffer[256];
  char buffer[28];  // <<<<<<< 80 is overkill, wastes heap space (more places)

  if (false == _writePage(page_number, page_buffer)) return false;
  if (false == _readPage(page_number, temp_buffer)) return false;

  for (int a=0; a<256; ++a)
  {
    if (!temp_buffer[a] == page_buffer[a]) return false;
  }
  sprintf(buffer, "Writing page (%04x) done", page_number);
  Serial.println(buffer);

  return true;
}


my 2 cents
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Marzogh

Just updated to v 1.2.1 with a bunch of optimizations and improvements .

As always, You can find the latest version on Github here -->SPIFlash Library for Arduino v1.2.1 A ZIP file is also attached to this post. :)

My apologies for not getting on here in a while. It was a very busy month at Uni with the semester coming to an end and field trip season starting up. I've only just managed to get back on now.

@Graham I haven't played around with the other chips or looked at their datasheets yet, so thank you for pointing it out. It'll be the next thing I get on to. :)

@Chuck Unfortunately all the erase functions just erase, thanks to the Uno's 2K RAM. I can't think of any way to get around it without resorting to what you've done with external SPI RAM. The onboard RAM also limits the use of the readBytes() and writeBytes() functions in the latest version of the library. :(

I've been considering tossing in some FRAM. I just got some samples from Fujitsu and I'm waiting for a few components to arrive from Element14 before I cook up some breakout boards in the toaster. I'll test them out and post the results ASAP. :)

Good luck with the Kickstarter! :)

@Rob Thanks for the feedback. :) The latest version of the library does not have _readPage() and _writePage() anymore. It also has page_number and offset checking built in where ever they are used. Also, Address rollover is the default action for when the end of the memory bank is reached during any operation - rollover can be disabled globally with an optional argument in the constructor. (Now that I think of it, perhaps I should make it a local argument in any function that requires it - it might give a user more flexibility?).

Thank you for your suggestion on the debug code. My version is a bit clumsy I admit, but it outputs the code in a neat 16/16 grid which makes it easy to read. I'm still trying to see if there's a cleaner way of formatting the output, but I'm pretty much a self-taught programmer (I'm a geneticist by trade) and I'd love to learn a new way of doing things if you have any suggestions. :)

I've used some of the code from your suggestion (below) in the latest version of the library. Thank you for that!
Code: [Select]
uint8_t x = data_buffer[a * 16 + b];
if (x < 10) Serial.print("0");
if (x < 100) Serial.print("0");
Serial.print(x);
Serial.print(',');


I've actually re-written writePage() completely so it no longer uses _writePage(). My current version checks the written data byte by byte without actually having to read it all into a buffer first. Saves a ton of time in the process and catches errors exactly where they happen. I'm toying with the idea of including a subroutine in my error checking protocol to return the exact location of the error so a user can ID any faulty registers.

chucktodd

Just updated to v 1.2.1 with a bunch of optimizations and improvements .


@Chuck Unfortunately all the erase functions just erase, thanks to the Uno's 2K RAM. I can't think of any way to get around it without resorting to what you've done with external SPI RAM. The onboard RAM also limits the use of the readBytes() and writeBytes() functions in the latest version of the library. :(

I've been considering tossing in some FRAM. I just got some samples from Fujitsu and I'm waiting for a few components to arrive from Element14 before I cook up some breakout boards in the toaster. I'll test them out and post the results ASAP. :)

Good luck with the Kickstarter! :)
I was hoping you had came up with some magical way, that did not encounter this issue.  But I guess magic is rare :smiley-money: .

When you say you work with 'software' your really mean 'Wetware?' :)

Well, I'm up to 14 backers, only Need 55 :(

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560's.  It adds 1MB of RAM for those projects where 8KB is not enough.

 
Currently built mega http server, Now converting it to ESP32.

Marzogh

Just updated to v1.3.0 with a serious set of improvements including writeAnything() & readAnything(), support for writing & reading most supported variable types (String support to come in future updates) and built in error checking. :)

As always, You can find the latest version on Github here -->SPIFlash Library for Arduino v1.3.0 A ZIP file is also attached to the first post on this thread. :)

@Chuck: Too bad the Kickstarter didn't go through. :( I was a backer. Are you going to open source your design?

jtewell

Hi Marzogh

Brilliant library, got a W25Q128FV working with my Mega board. Tried to wire it up to my Due board but encountered some problems. Commenting out the #include <util/delay.h> in the SPIFlash.cpp file gets it to compile, but my Due board becomes unresponsive after calling the constructor. It seems to occur after the SPI.begin() call. Any ideas for a quick fix?

Marzogh

Hi Jtewell,

Thanks for that. I'm glad it works well with the Mega. :) It has been throwing errors with the Leonardo and I haven't had time to fix that yet. :( Unfortunately I have close to zero experience working with ARM processors and can't help with the issue you are facing. I'm still working on learning more about the Due and plan on including support once I figure out where I stand.

If you do find a way to add Due support, feel free to fork the github repo and submit any changes - I'm always open to learning something new. :)

Marzogh

Just updated to v1.3.2 which supports storage and retrieval of Strings, along with a raft of other features. :)

As always the latest version can be found at here.

Go Up