arduino-dataflash icon indicating copy to clipboard operation
arduino-dataflash copied to clipboard

Sector delete of sectors 0a and 0b fails

Open drp0 opened this issue 5 years ago • 9 comments

I am using an AT45DB161E. After reviewing the manual I can not find any significant difference to the AT45DB161D Sector erase works correctly with blocks 1 to 15 and not with sectors 0a and 0b. The issue seems to originate in sectorErase

void DataFlash::sectorErase(int8_t sector)
{
    /* Wait for the end of the previous operation. */
    waitUntilReady();

    reEnable();
    
    /* Send opcode */
    SPI.transfer(DATAFLASH_SECTOR_ERASE); // 0x7C
	
    if((sector == AT45_SECTOR_0A) || (sector == AT45_SECTOR_0B))
    {
        SPI.transfer(0x00);
        if(sector == AT45_SECTOR_0A) SPI.transfer(0x00); else SPI.transfer(32);
	   //SPI.transfer((static_cast<uint8_t>(-sector) & 0x01) << (m_bufferSize - 5));
    }
    else
    {
        uint8_t shift = m_bufferSize + m_pageSize - m_sectorSize - 16;        
        SPI.transfer(sector << shift);
        SPI.transfer(0x00);
    }
	
	SPI.transfer(0x00);
	
    /* Start sector erase.
    The chip remains busy until this operation finishes. */
    disable();
}

In the documentation, the E chip sector erase appears functionally the same to the D chip,

The AT45_SECTOR_0A/0B section appears to yield the correct values of 32 and 0, but allocates them to the wrong sector. Sector -1 shoud be 0 and sector 0, 32. My replacement line "if(sector == AT45_SECTOR_0A) SPI.transfer(0x00); else SPI.transfer(32)" fixes the issue.

Here is my flash_SectorErase:

// flash_sectorErase

/*
 *                   mini, mega
 * pin1(misi) to mosi  11, 51  
 * pin2(sck ) to sck   13, 52
 * pin3(rest) to reset 8,  8
 * pin4(sc  ) to cS    10, 53
 * pin5(wp  ) to wp    7,  7
 * pin6 Vcc   3v3
 * pin7 gnd   0v
 * pin8(miso) to misi  12, 50
 */

#include <SPI.h>
#include "DataFlash.h"

#if defined(__AVR_ATmega2560__)
static const int csPin= 53; // mega
#else
static const int csPin= 10;
#endif

static const int resetPin = 8;
static const int wpPin= 7;

DataFlash dataflash;
uint8_t currentSector;

static const uint16_t bufferSize[7] = { 264, 264, 264, 264, 528, 528, 528 };
static const uint16_t pagesSector0b[7]  = { 120, 120, 248, 248, 248, 120, 248 };
static const uint16_t pagesPerSector[7] = { 128, 128, 256, 256, 256, 128, 256 };

void setup(){

Serial.begin(115200);
delay(1000);

/* Initialize SPI */
SPI.begin();
delay(10);
/* Initialize dataflash */
dataflash.setup(csPin, resetPin, wpPin);
delay(10);
dataflash.begin();
delay(10);

Serial.print("Manual buffer erase : on\n");
dataflash.manualErase();

flashInfo();

int8_t res = 0;

res += testSectorErase(AT45_SECTOR_0A);
res += testSectorErase(AT45_SECTOR_0B);
  for(uint8_t i=1; i<16; i++) res += testSectorErase(i);
Serial.print("\nTest ");
  if(res != 17) Serial.println("failed!"); else Serial.println("successful!");
delay(2000);

testAll(); // check each byte = 0xFF
}

void fillPages(uint16_t pageStart, uint16_t pageCount, uint16_t bufferSize){
uint8_t  myBuffer = 0;
uint16_t page   = 0;

  for(page=pageStart; page<(pageStart+pageCount); page++){

  dataflash.bufferWrite(myBuffer, 0);
    for(uint16_t j=0; j<bufferSize; j++)SPI.transfer( j & 0xff );
  dataflash.bufferToPage(myBuffer, page);
   
  int8_t res = dataflash.isPageEqualBuffer(page, myBuffer);
    if(res == 0){
    Serial.print("Page ");
    Serial.print(page);
    Serial.print(" failed to fill");      
    }
  myBuffer ^= 1; // toggle buffer 0 and 1
  }
}

void setBuffer(uint8_t thisBuffer, uint8_t val, uint16_t bufSize){
dataflash.bufferWrite(thisBuffer, 0);
  for(uint16_t i=0; i<bufSize; i++) SPI.transfer(val);
}

int8_t testSectorErase(int8_t sectorId){//int8_t ?

uint16_t pageStart, pageCount;
  
uint8_t thisStatus = dataflash.status();
uint8_t deviceIndex = ((thisStatus & 0x38) >> 3) - 1;   

  if(sectorId == AT45_SECTOR_0A){
  pageStart = 0;
  pageCount = 8;
  }
  else if(sectorId == AT45_SECTOR_0B){
  pageStart = 8;
  pageCount = pagesSector0b[deviceIndex];
  }
  else 
  {
  pageStart = pagesPerSector[deviceIndex] * static_cast<uint16_t>(sectorId);
  pageCount = pagesPerSector[deviceIndex];
  }

Serial.print("\nTesting sector "); Serial.println(sectorId);
Serial.print("Page start ");Serial.print(pageStart);
Serial.print(" Page count "); Serial.println(pageCount);

Serial.print("Filling pages\n");
fillPages(pageStart, pageCount, bufferSize[deviceIndex]);

Serial.println("Erasing sector");
dataflash.sectorErase(sectorId);

Serial.println("Check pages");
uint16_t res = checkPages(pageStart, pageCount, deviceIndex);  
  if(res != pageCount){
  Serial.print("\nFAILURE! ("); Serial.print(res);Serial.print(" out of ");
  Serial.print(pageCount); Serial.println(")");
  return 0;
  }
return 1;
}

uint16_t  checkPages(uint16_t pageStart, uint16_t pageCount, uint8_t deviceIndex){
uint16_t count = 0;
int8_t res;
setBuffer(0, 0xFF, bufferSize[deviceIndex]); // fill buffer 0 with 0xFF

  for(uint16_t page = pageStart; page < (pageCount+pageStart); page++){
  res = dataflash.isPageEqualBuffer(page, 0);
  Serial.print("Page "); Serial.print(page);
    if(res == 1) {
    count++;
    Serial.println(" was succesfully erased.");
    }else Serial.println (" was not properly erased.");
  }
return count;
}

void testAll(){
unsigned long errcount = 0;
int pcount = 0;
Serial.println("\nTest all:");
  for (int pagecount = 0; pagecount <4095; pagecount++){//4096
  dataflash.pageRead(pagecount,0);
  pcount = 0;
  Serial.print("Page ");Serial.print(pagecount);  
  //Serial.println();
    for(int i=0; i< DF_45DB161_PAGESIZE; i++){ // 528
    uint8_t data = SPI.transfer(0xff);
      if (data != 255) {

      //Serial.print(i);Serial.print(" ");
      //Serial.print( (char)data);
      //Serial.print(" "); Serial.println(data);
      errcount ++;
      pcount++;
      }
    }
    
    if(pcount > 0) {
    Serial.print("  Page error ");Serial.println(pcount);
    } else Serial.println();
  }
Serial.print("Error count ");Serial.println(errcount);
}

void flashInfo(){
/* Read status register */
uint8_t myStatus = dataflash.status();

DataFlash::ID id;
/* Read manufacturer and device ID */
dataflash.readID(id);

/* Display status register */
Serial.print("Status register :");
Serial.println(myStatus, BIN);

/* Display manufacturer and device ID */
Serial.print("Manufacturer ID : "); // Should be 00011111
Serial.println(id.manufacturer, HEX);

Serial.print("Device ID (part 1) : "); // Should be 00011111
Serial.println(id.device[0], HEX);

Serial.print("Device ID (part 2) : "); // Should be 00000000
Serial.println(id.device[1], HEX);

Serial.print("Extended Device Information String Length : "); // 00000000
Serial.println(id.extendedInfoLength, HEX);
}

void loop(){
}

David

drp0 avatar Nov 16 '18 12:11 drp0

Thanks for the report. How on earth did I come up with such a complicated formula? SPI.transfer((static_cast<uint8_t>(-sector) & 0x01) << (m_bufferSize - 5)); can be replaced with SPI.transfer((sector - 0x0a) << (m_bufferSize - 5))

BlockoS avatar Nov 17 '18 18:11 BlockoS

My solution came from page 13 section 6.9 of the manual at https://www.adestotech.com/wp-content/uploads/doc8782.pdf Perhaps you intended a more generic method across a range of devices?

drp0 avatar Nov 17 '18 19:11 drp0

I tried and failed miserably :) According to the datasheets of the AT45DB041D, AT45DB161D and AT45DB321D, the formula posted above will do the trick:

SPI.transfer((sector - 0x0a) << (m_bufferSize - 5))

BlockoS avatar Nov 17 '18 20:11 BlockoS

Your library works well, thanks.

This is my analysis on sector erase in the AT45DB161E manual: "To perform an erase of Sector 0a or Sector 0b with the standard DataFlash page size (528 bytes), an opcode of 7Ch must be clocked into the device followed by three address bytes comprised of two dummy bits, nine page address bits (PA11 - PA3), and 13 dummy bits. "

0a (all PAn bits = 0) 00 000000000 0000000000000 3 bytes all 0

0b (bit PA3 =1) 00 000000,001 00000,00000000 byte 1 0 byte 2 00100000 (32) byte 3 0

I have found no other issues implementing it on the AT45DB161E. Sector Erasing and protection works. I have written arduino (mega) examples to sequentially write values across successive pages. This includes the use of single data items and structures. Let me know if you would like copies. David

drp0 avatar Nov 20 '18 14:11 drp0

Yes sure. That'd be cool.

BlockoS avatar Nov 21 '18 20:11 BlockoS

software.zip

drp0 avatar Nov 21 '18 22:11 drp0

I found the E chip had an extended byte, so modified dataflash.cpp to grab the value. It turned out to be 0 and not worth the effort. Therefore delete the following lines in flashtestStructure.ino (line 561) and flashtest3.ino (line 374)

  if( id.extendedInfoLength > 0){
  Serial.print(F("Extended byte ")); Serial.println(id.extra);
  }

drp0 avatar Nov 22 '18 07:11 drp0

Thanks!

I found those docs about D/E differences:

  • https://www.adestotech.com/wp-content/uploads/161E.pdf
  • https://www.adestotech.com/wp-content/uploads/321E.pdf

BlockoS avatar Nov 22 '18 08:11 BlockoS

Very useful. There is now a second status byte in the E chip with some good information:

void StatusByte2(){
uint8_t Status;
    
dataflash.reEnable();   // Reset command decoder  
SPI.transfer(0xD7);     // Send status read command
Status = SPI.transfer(0); // Status 1
Status = SPI.transfer(0); // Status 2
dataflash.disable();
Serial.print(F("Status register(2): ")); Serial.println(Status, BIN);
  if (Status & 128) Serial.println(F(" Device is Ready"));
  if (Status & 32) Serial.println(F(" Erase or program Error detected"));
  if (Status & 8) Serial.println(F(" Sector Lockdown command is enabled"));
  if (Status & 4) Serial.println(F(" A sector is program suspended whilst using buffer 2"));
  if (Status & 2) Serial.println(F(" A sector is program suspended whilst using buffer 1"));
  if (Status & 1) Serial.println(F(" A sector is erase suspended "));
Serial.println();
}

drp0 avatar Nov 22 '18 10:11 drp0