SPIMemory library - Formerly SPIFlash - now supports SPI FRAM as well! :)

I checked the wiring and tried it again with a new chip and it still didn’t work.

Here are the wiring pics. You can ignore all the wires on the left (they’re for several encoders and a LCD). Also I’m using a surface mounted SPI chip so the chip is on an adapter. The top row of the adapter pins are pins 8 to 5 (left to right) from the SPI chip and the bottom row is pins 1 to 4.

Sorry I know it’s a sloppy board. I will also attach the excel file I used to plan it out before soldering which will hopefully help you find my error. I already tested all the voltage dividers with a simple program that set the data pins at 5V and they were outputting 2.8V which is sufficient for the SPI chip. Thanks!

pin_layout.PNG

Ah. Good old voltage dividers. They can cause some serious performance issues.

All signals have capacitance, partly from the IC pins and partly from the wires/PCB traces connecting the devices. When you throw a resistor into the mix, you are creating an RC filter which smooths out the sharp edges in your signals - especially hurting the clock pulse.

Now, this is usually ok if the resistance is small enough. I have, in a pinch, thrown in a <150 Ohm total resistance to create a voltage divider. Anything higher than that degrades the signal quality too much. Also, voltage divider resultant signal degradation will not affect your MISO, MOSI and CS lines as much as the CLK line. Any clock pulse needs a clean sharp digital transition between low and high. I’d recommend throwing in a Voltage Level converter from Sparkfun or Adafruit. They’re cheap and high quality - I’ve never had issues with them degrading SPI signals.

So if I use a smaller resistance for my clock voltage divider it should work? Or do I need to reduce the resistances for the other pins as well? I'll try reducing the clock resistance first and let you know how it goes! Thanks!

It might work. For clock signals I'd personally recommend against voltage dividers and recommend the use of a proper level shifting set up. However, if you've got an oscilloscope, you should be able to see the high to low transitions clearly and that should help with picking the right resistors to use.

For those of you that have managed to get your hands on ESP32 dev boards, I’ve got v2.6.0-w.i.p currently working with the ESP32 core (as it stands at commit 67fd652). :smiley:

Also, for some unknown reason, SPI clock speeds higher than (board speed)/4 are not stable and so, the clock speed for ESP32 dev boards has currently been throttled to 20MHz (I’m testing with the Sparkfun ESP32 Thing - it has a max speed of 80MHz) - if you have any issues, check your board’s speed first and change the SPICLK define in defines.h to your (board clock speed)/4.

So I finally got back in the lab after thanksgiving to check out the clock pulse on an o-scope and there is nothing coming off of pin 13 (SCK)... Do I have to add some code to output the clock pulse on this pin or is my arduino just dead or something?

Also I got an 8MHz signal on pin 9 using the instructions from here: http://arduino.stackexchange.com/questions/16698/arduino-constant-clock-output

If I can't get pin 13 working can I just put my voltage divider on pin 9 and use it to drive the chip? Thanks!

SCK would only be active for 8 clocks during an SPI.transfer(). Not continuously.

The SCK pulse is started/ended by the library as needed, during an SPI transaction. I'd recommend that you try connecting another SPI based sensor (a 3.3V one, to be specific) to your board and see if it works. That should tell you if you have a busted chip.

Also as CrossRoads said, an SCK does not constantly pulse at 8MHz. This is what a typical SPI signal would look like --> SPI Signal on Logic Analyzer (Image linked directly from Nick Gammon's post on SPI)

I've tested a similar setup with my Arduino Nano & a Winbond W25Q128FV (I don't have a W25Q256FV, but the difference is only the amount of storage) and it works fine with v 2.5.0 - however, I always use a logic level converter in situations like this - this one to be precise

Just pushed through an update to v2.6.0. This update squashes one major bug, adds support forthe ESP32 and other boards, loses a superfluous function and has a large number of optimizations for speed, stability & ease of development.

Bugs Squashed - Fixed issue with reading status register 2 and the Suspend operation where the library was not checking the suspend status correctly.

Deletions - flash.getChipName() has been removed as it is superfluous now that the library is now on its way to multi-chip compatibility. - The library is not compatible with the ATTiny85 anymore. Currently working on a fix which will hopefully be rolled out in v2.7.0

New Boards supported - RTL8195A compatibility tested and enabled by @boseji on 02.03.17. Code modified to fit with the library structure by Prajwal Bhattaram on 14.04.17. - Now supports the ESP32 core for Arduino as of the current commit 7d0968c on 16.04.2017. The ESP32 core currently does not support analogRead and so randomSeed(AnalogRead(A0)) cannot be used. Also, for some unknown reason, SPI clock speeds higher than board speed/4 are not stable and so, the clock speed for ESP32 dev boards has currently been throttled to 20MHz. - Added support for the Simblee module.

Enhancements & Optimizations - flash.error() now takes an optional argument 'VERBOSE'. By default the verbosity argument is set to false and calling flash.error() still returns the latest error code as an unsigned byte. However, running flash.error(VERBOSE) will not only return the latest error code, but will also print it to serial. This - especially in boards with resources to spare - will result in a detailed error report printed to serial. - flash.begin() now returns a boolean value to indicate establishment of successful comms with the flash chip. Usercode can be made more efficient now by calling

if (!flash.begin()) {
      Serial.println(flash.error(VERBOSE));
}

to identify a problem as soon as the library code is run. - The internal _addressCheck() function now locks up usercode with appropriate error codes if

  • flash.begin() has not been called (or)
  • There is a possible issue with the wiring - i.e. the flash chip is non-responsive (or)
  • If the chip's capacity either cannot be identified & the user has not defined a chipSize in flash.begin().

  • Fixed powerDown() to be more efficient. The chip now powers down much faster than before.

  • Added a new error code. Library can now detect non-responsive chips - bad wiring or otherwise.

  • Streamlined variables to make code structure better.

  • Changed library structure to enable the addition of multi-flash compatibility in the near future.

  • moved #define RUNDIAGNOSTIC & #define HIGHSPEED to SPIFlash.h from SPIFlash.cpp.

  • Now works with other Winbond modules (not in the official supported module list) (beta) by taking the flash memory size in bits as an argument in flash.begin(_chipSize);

  • Formatted code to be better human readable.

  • Changed the internal _troubleshoot() function to use fewer resources.

As always, you can find this version on Github here --> SPIFlash Library for Arduino v2.6.0 A ZIP file is also attached to the first post on this thread. The easiest way, as always, is to open up Library Manager on your Arduino IDE and update the libary to v2.6.0 :)

Hi Marzogh

I've recenetly got back to your SPI Library. I've been using it previously on version 2.3.1 with chip Winbond 25q40bvnig.

After update to version 2.6.0 it throws random errors on diagnostics. Errors are showing up since version 2.4.0

It looks like this:

Initialising Flash memory..........


SPIFlash Library version: 2.6.0

Get ID


JEDEC ID: ef4013h Manufacturer ID: efh Memory Type: 40h Capacity: 524288 bytes

Maximum pages: 2048

Data Check

Data Written || Data Read || Result || Write Time || Read Time || Write Time || Fast Read Time

|| || || || || (No Error Chk) ||

35 || 35 || Pass || 52 us || 48 us || 52 us || 64 us -110 || -110 || Pass || 52 us || 48 us || 52 us || 48 us 4520 || 4520 || Pass || 64 us || 60 us || 64 us || 56 us -1250 || -1250 || Pass || 64 us || 56 us || 64 us || 56 us 876532 || 4294967075 || Fail || 64 us || 60 us || 68 us || 60 us -10959 || -221 || Fail || 64 us || 60 us || 68 us || 68 us 3.14 || 3.14 || Pass ⸮⸮

Read values are completely random. Number of pass / fail tests are also completely random.

Did you dropped support for this particular chip ? Wiring is rather ok.

miduchp: Hi Marzogh

I've recenetly got back to your SPI Library. I've been using it previously on version 2.3.1 with chip Winbond 25q40bvnig.

After update to version 2.6.0 it throws random errors on diagnostics. Errors are showing up since version 2.4.0

It looks like this:

Read values are completely random. Number of pass / fail tests are also completely random.

Did you dropped support for this particular chip ? Wiring is rather ok.

That is strange. I am not able to replicate the issue with a Q40BV chip that I have with me. Could you uncomment #RUNDIAGNOSTIC in SPIFlash.h and tell me what errors the library is throwing?

Also, I'm about to release v2.7.0 in a few minutes. Could you check and see if that fixes your issues?

Just pushed through an update to v2.7.0. With this update the library officially supports the Arduino Zero and derivants based on the SAMD21, squashes one major bug and brings back support for the ATTiny85 (Trinket) and updates support for the ESP32 (to the latest commit to the esp32-arduino core as of 02.08.17).

As always, you can find this version on Github here --> SPIFlash Library for Arduino v2.7.0 A ZIP file is also attached to the first post on this thread. The easiest way, as always, is to open up Library Manager on your Arduino IDE and update the libary to v2.7.0 :)

[u]Update on future development:[/u]

I started working on SPIFlash as a little project to improve my programming skills (in 2015) but it has quickly turned into something that barely resembles the first release on the surface.

No matter how many new features I added, the fundamental functions of the library have remained the same from day one. This means any new features I would like to add today are hamstrung by sloppy coding from 2 years ago (Don't tell this to 2015 me. I thought it was the bees-knees when I figured out how to work *flash.writeAnything()* ! I'd never heard of templates before then). With all I have learnt about programming with C & C++ over the last two years, there are a number of changes I would like to bring in to make the library lean and efficient, support more chips, and add more features - all without any more bloat. As of v2.7.0 I appear to have hit a solid wall with improving I/O speeds. I know its possible to go faster, but not with the base code as clumsy as it is.

This brings us to the next major release milestone - v3.0.0. It is going to be a complete overhaul of the library. The changes I have made so far have resulted in a pretty dramatic increase of I/O speeds - especially when working with large chunks of data like structs, arrays and strings (>50% increase in speed with strings, for example). I am doing my best to preserve the functions currently in use, but, some will have to go the way of the dodo in the name of efficiency. The following changes will be made to the library as it stands. (This is a very preliminary list - more changes will happen before final release)

  • The ability to read and write using page numbers + offsets will be retired and the library will transition to using addresses only. For users wanting to keep old programs working, the getAddress() function should help generate addresses from the page number+offset numbers
  • Preliminary testing with Microchip Flash memory has succeeded. This version will be compatible with Flash memory from multiple manufacturers, starting with Microchip.
  • The Arduino platform is now switching towards using ARM chips - more ARM chips/platforms will be supported with future releases starting with STM32. This however has started making life difficult with trying to maintain compatibility with the ATTiny platform. All versions >v3.0.0 will not support the ATTiny series any more
  • Restructuring the library has let me make the troubleshooting function more efficient and human readable. It will compile better and use far fewer resources than the current version.
  • I am working on making it easy for users to get the library working with flash memory that is not officially supported. This will roll out with v3.0.0

If any of you have any suggestions for improvement or a wishlist of features, I'd love to hear from you! - MicroPython port anyone? :sunglasses:

Hello, Firstly want to thank you very much for your hard work, it's very helpful and useful. Personally I have a wish. To be honest, main usage scenario of your library is to READ and WRITE SPI EEPROM. Mainly it means doing full backup and restore or upgrade some firmware or bios. That what programmer do. So, I think your library could be more popular if you supply with it crossplatform app to identify, read and flash ROMs. To turn Arduino into powerfull and easy to use programmer.

Hi, I try to change from SD to SPIFlash and all is working fine so far. Absolutly great Job! I try to load some picture (bmp) into the flash. I imagine to convert the image content in a string and then store into the flash.

think this is basically possible :roll_eyes:

Open requested file on SD card

  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print("File not found");
    return;
  }

Convert to string

 String SD_Read;
  while (bmpFile.available()) {
    char ltr = bmpFile.read();
    SD_Read += ltr;
  }

Store to flash

  while (!flash.eraseSector(17, 0));


  if (flash.writeStr(17, 0, SD_Read)) {
    Serial.println("SAVED");
  } else {
    Serial.println("ERROR");
  }

then to display on the TFT, I have to read from Flash convert from String to File. :confused:

Did some one try this already?

pasaf: Hello, Firstly want to thank you very much for your hard work, it's very helpful and useful. Personally I have a wish. To be honest, main usage scenario of your library is to READ and WRITE SPI EEPROM. Mainly it means doing full backup and restore or upgrade some firmware or bios. That what programmer do. So, I think your library could be more popular if you supply with it crossplatform app to identify, read and flash ROMs. To turn Arduino into powerfull and easy to use programmer.

Hi @pasaf, Thank you for the kind words. Your idea is a very interesting one. However, as much as I'd like to write code for a living, my main job actually involves dealing with stuff in a biology lab - I'm a geneticist by trade, so this library and the support I provide it are things I do in my free time. But, that is the beauty of Open Access/Free software - you can always take my code and turn it into whatever you wish :slight_smile: The main aim of this library is to provide you with the basic tools to build an app with any function you want, yourself. The upcoming release might help with what you want to do.

Release v3.0.0 will support read/write from/to multiple SPI Flash chips connected to one Arduino board. Using that version of the library it should be reasonably easy to put together a program that reads some data from Flash chip A and saves to to Flash chip B; repeating the process till all the data on chip A is on chip B. Afterward, the same program can be used to transfer the data from chip B to chip C. Easy backup & clone! ???

I know you want to read of EEPROMs - as long as the EEPROMs communicate over SPI, getting them to work with this library is only a matter of modifying it slightly. Take a look at the opcodes in 'defines.h' and see if any need changing - then change the JEDEC ID (specifically the manufacturer ID) that the library recognises, to the one one from your EEPROM. Everything else should just work.

(If you wait till v3.0.0 comes out, you should be able to do this straight from your code, release 3.0.0 will come with the ability to define custom chip size/ID in user code. :slight_smile: )

Feel free to play around with the code in the developer branch on the Github repo. Its not stable yet and is a work in progress, but it already has some of the features you'll need.

mysource: Hi, I try to change from SD to SPIFlash and all is working fine so far. Absolutly great Job! I try to load some picture (bmp) into the flash. I imagine to convert the image content in a string and then store into the flash.

think this is basically possible :roll_eyes:

then to display on the TFT, I have to read from Flash convert from String to File. :confused:

Did some one try this already?

Hi mate, rather than working with a String object (especially on an 8-bit AVR, which I assume is what you're using?), how about you try and read the data on your SD into a byte array? Your code will be a lot more efficient and it'll be much easier to just feed an array to your TFT. Gary - HERE - was using the readByteArray() function to read data off his flash chip and display it on a TFT.

There are two points to note though.

  • If the size of the image file is larger than the free RAM on your MCU, you will not be able to read the entire file off the SD card before you transfer it across to the SPI Flash. You'll have to buffer it somehow
  • The latency will be an issue. Reading an array from Flash and displaying it on a TFT will take time and there will be a noticeable delay in refreshing the image. If you want to be able to read data very quickly off the Flash memory, I'd recommend using the Arduino Due - the library supports DMA on the Due and your latency should be as low as is possible. If not, Using a faster clocked chip like an ESP8266 at 160MHz or an ESP32 @ 80MHz should work in a pinch.

Marzogh: Hi mate, rather than working with a String object (especially on an 8-bit AVR, which I assume is what you're using?), how about you try and read the data on your SD into a byte array?

This is just a "one Time" action. I will store the pic in the flash instead of the SD card. Then to read the pic from flash to display on the TFT. OK first I will tray to store the pic content in an array. something like that. bmpFile.read() returns an integer.

  char *arrayOfChars;
  uint16_t index = 0;
  while (bmpFile.available()) {
    arrayOfChars[index] = bmpFile.read();
    index++;
  }

Will see..... After thet is done will check then -> TFT. Gary - HERE THX for your info.

ok …

Serial.println(read16(bmpFile), HEX);

  // pic size: 49208 bytes
  uint16_t _index = 0;
  uint8_t _page = 16;
  for (int i = _page; i < 209; i++) {
    flash.eraseSector(i, 0);
  }

  while (bmpFile.available()) {
    if (_index == 255) {
      _page++;
      _index = 0;
    }
    flash.writeByte(_page, _index, (byte)bmpFile.read());
    _index++;
  }

  Serial.println(read16(bmpFile), HEX);

Serial.println(read16(bmpFile), HEX); => 4D42 => BMP signature (read LSB and MSB) that is OK. but after flash erase I get C038 and after the while loop I get FFFF. :cold_sweat:… but I’m not changing the file handler so far.

New start :smiley:

some calluclation about the image size…
image size: 49208 bytes
1 page = 256 bytes
1 sector = 4k / 4096 bytes
1 sector = 16 pages
4096 bytes * 256 = 1’048’576 = 1MB

PIC Size = 49208/4096 = 12.01… 13 sectors
13 sectors * 16 Pages = 208 total Pages / 16…207
208 pages and the last page (208 )just 56 bytes.

Clear the Flash from page 16…208

  uint16_t _pageOfset = 16; // Start from page 16. First 16 pages are reserved for configuration
  for (uint16_t p = _pageOfset; p < _pageOfset + 208; p++) {
  while (!flash.eraseSector(p, 0));
  }

Read the file:

File bmpFileTmp;
  // Open requested file on SD card
  if ((bmpFileTmp = SD.open(filename)) == NULL) {
    Serial.print("File not found");
    return;
  }

Write to flash:

 uint16_t _index = 0;
  uint8_t _page = _pageOfset;
  uint16_t maxPage = 0;
  uint16_t lastMaxIndex = 0;
  if (bmpFileTmp) {
    while (bmpFileTmp.available()) {
      if (_index == 256) {
        _page++;
        _index = 0;
      }
      flash.writeByte(_page, _index, (byte)bmpFileTmp.read());
      _index++;
    }
    bmpFileTmp.close();
  }  
maxPage = _page - _pageOfset;
lastMaxIndex = _index;

Check to first page (BMP signature) in the flash:

  printPage(16, 2);
  printPage(16, 1);
Reading page (0010)
066,077,056,192,000,000,000,000,000,000,054,000,000,000,040,000,
000,000,128,000,000,000,128,000,000,000,001,000,024,000,000,000,
000,000,002,192,000,000,229,076,000,000,229,076,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
Reading page (0010)
424d38c0000000000000360000002800
00008000000080000000010018000000
000002c00000e54c0000e54c00000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000

First two bytes are signature for BMP.
066,077 or 0x424d

So far all ok.

Read back from flash to file handler:

  Serial.print("Page to loop: ");
  Serial.println(_pageOfset + maxPage);

  uint32_t _indexTotal = 0;
  for (uint16_t p = _pageOfset; p <= _pageOfset + maxPage; p++) {
    if (p == _pageOfset + maxPage) {
      for (uint16_t i = 0; i <= lastMaxIndex; i++) {
        Serial.print(p);
        Serial.print("\t");
        Serial.print(i);
        Serial.print("\t");
        bmpFile.write((byte)flash.readByte(p, i));
        Serial.println(_indexTotal);
        _indexTotal++;
      }
    } else {
      for (uint16_t i = 0; i <= 255; i++) {
        Serial.print(p);
        Serial.print("\t");
        Serial.print(i);
        Serial.print("\t");
        Serial.println(_indexTotal);
        bmpFile.write((byte)flash.readByte(p, i));
        _indexTotal++;
      }
    }
  }

last output…
pages bytes index
208 56 49208

but when I check first two bytes from the new file handler I get wrong values.

  uint16_t checkBMP = read16(bmpFile);
  Serial.println(checkBMP);


uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

Here I expect 0x424D (d16973) but I get 65535. :roll_eyes:
The Bytes in the Flash looks good. In any case, the signature is correct.

Some Idea?