From c6ff29272105979b6043878cc4100dad7039ac89 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 4 Jul 2012 12:36:42 +1000 Subject: [PATCH] DataFlash: fallback to BlockErase if ChipErase fails The errata on the APM2 dataflash chip says that ChipErase may not work on some chips --- libraries/DataFlash/DataFlash.cpp | 21 ++++++++++++++++++++ libraries/DataFlash/DataFlash.h | 4 ++++ libraries/DataFlash/DataFlash_APM1.cpp | 23 ++++++++++++++++++++++ libraries/DataFlash/DataFlash_APM1.h | 1 + libraries/DataFlash/DataFlash_APM2.cpp | 27 ++++++++++++++++++++++++++ libraries/DataFlash/DataFlash_APM2.h | 1 + 6 files changed, 77 insertions(+) diff --git a/libraries/DataFlash/DataFlash.cpp b/libraries/DataFlash/DataFlash.cpp index 3a7d8db9ed..8ad82c2ecc 100644 --- a/libraries/DataFlash/DataFlash.cpp +++ b/libraries/DataFlash/DataFlash.cpp @@ -3,6 +3,7 @@ DataFlash.cpp - DataFlash log library generic code */ +#include #include #include "DataFlash.h" @@ -188,8 +189,28 @@ uint16_t DataFlash_Class::GetFilePage() void DataFlash_Class::EraseAll(void (*delay_cb)(unsigned long)) { + // write a bad value to the last page + StartWrite(df_NumPages+1); + WriteLong(DF_LOGGING_FORMAT_INVALID); + BufferToPage(df_BufferNum,df_PageAdr,1); + ChipErase(delay_cb); SetFileNumber(0xFFFF); + + StartRead(0); + StartRead(df_NumPages+1); + int32_t format = ReadLong(); + + if (format == DF_LOGGING_FORMAT_INVALID) { + // the chip erase didn't work - fall back to a erasing + // each page separately. The errata on the APM2 dataflash chip + // suggests that chip erase won't always work + for(uint16_t j = 1; j <= (df_NumPages+1)/8; j++) { + BlockErase(j); + delay_cb(1); + } + } + // write the logging format in the last page StartWrite(df_NumPages+1); WriteLong(DF_LOGGING_FORMAT); diff --git a/libraries/DataFlash/DataFlash.h b/libraries/DataFlash/DataFlash.h index 371bf0af60..3138471619 100644 --- a/libraries/DataFlash/DataFlash.h +++ b/libraries/DataFlash/DataFlash.h @@ -12,6 +12,9 @@ // this if (and only if!) the low level format changes #define DF_LOGGING_FORMAT 0x28122011 +// we use an invalie logging format to test the chip erase +#define DF_LOGGING_FORMAT_INVALID 0x28122012 + class DataFlash_Class { private: @@ -32,6 +35,7 @@ class DataFlash_Class virtual void PageToBuffer(unsigned char BufferNum, uint16_t PageAdr) = 0; virtual unsigned char BufferRead (unsigned char BufferNum, uint16_t IntPageAdr) = 0; virtual void PageErase(uint16_t PageAdr) = 0; + virtual void BlockErase(uint16_t BlockAdr) = 0; virtual void ChipErase(void (*delay_cb)(unsigned long)) = 0; // internal high level functions diff --git a/libraries/DataFlash/DataFlash_APM1.cpp b/libraries/DataFlash/DataFlash_APM1.cpp index cbbf30c2c2..d0c390825b 100644 --- a/libraries/DataFlash/DataFlash_APM1.cpp +++ b/libraries/DataFlash/DataFlash_APM1.cpp @@ -294,6 +294,29 @@ void DataFlash_APM1::PageErase (uint16_t PageAdr) } +void DataFlash_APM1::BlockErase (uint16_t BlockAdr) +{ + dataflash_CS_active(); // activate dataflash command decoder + SPI.transfer(DF_BLOCK_ERASE); // Command + + if (df_PageSize==512) { + SPI.transfer((unsigned char)(BlockAdr >> 3)); + SPI.transfer((unsigned char)(BlockAdr << 5)); + } else { + SPI.transfer((unsigned char)(BlockAdr >> 4)); + SPI.transfer((unsigned char)(BlockAdr << 4)); + } + + SPI.transfer(0x00); // "dont cares" + dataflash_CS_inactive(); //initiate flash page erase + dataflash_CS_active(); + while(!ReadStatus()); + + dataflash_CS_inactive(); // deactivate dataflash command decoder +} + + + void DataFlash_APM1::ChipErase(void (*delay_cb)(unsigned long)) { diff --git a/libraries/DataFlash/DataFlash_APM1.h b/libraries/DataFlash/DataFlash_APM1.h index 1bff7b4d99..fb1aa3b34e 100644 --- a/libraries/DataFlash/DataFlash_APM1.h +++ b/libraries/DataFlash/DataFlash_APM1.h @@ -19,6 +19,7 @@ class DataFlash_APM1 : public DataFlash_Class unsigned char ReadStatus(); uint16_t PageSize(); void PageErase (uint16_t PageAdr); + void BlockErase (uint16_t BlockAdr); void ChipErase(void (*delay_cb)(unsigned long)); public: diff --git a/libraries/DataFlash/DataFlash_APM2.cpp b/libraries/DataFlash/DataFlash_APM2.cpp index b9d4639ce9..0a1b52abc5 100644 --- a/libraries/DataFlash/DataFlash_APM2.cpp +++ b/libraries/DataFlash/DataFlash_APM2.cpp @@ -349,6 +349,33 @@ void DataFlash_APM2::PageErase (uint16_t PageAdr) CS_inactive(); } +// erase a block of 8 pages. +void DataFlash_APM2::BlockErase(uint16_t BlockAdr) +{ + // activate dataflash command decoder + CS_active(); + + // Send block erase command + SPI_transfer(DF_BLOCK_ERASE); + + if (df_PageSize==512) { + SPI_transfer((unsigned char)(BlockAdr >> 3)); + SPI_transfer((unsigned char)(BlockAdr << 5)); + } else { + SPI_transfer((unsigned char)(BlockAdr >> 4)); + SPI_transfer((unsigned char)(BlockAdr << 4)); + } + SPI_transfer(0x00); + + //initiate flash page erase + CS_inactive(); + CS_active(); + while(!ReadStatus()); + + // release SPI bus for use by other sensors + CS_inactive(); +} + void DataFlash_APM2::ChipErase(void (*delay_cb)(unsigned long)) { diff --git a/libraries/DataFlash/DataFlash_APM2.h b/libraries/DataFlash/DataFlash_APM2.h index cb4d343a6b..b81246bf35 100644 --- a/libraries/DataFlash/DataFlash_APM2.h +++ b/libraries/DataFlash/DataFlash_APM2.h @@ -23,6 +23,7 @@ class DataFlash_APM2 : public DataFlash_Class void CS_inactive(); void CS_active(); void PageErase (uint16_t PageAdr); + void BlockErase (uint16_t BlockAdr); void ChipErase(void (*delay_cb)(unsigned long)); public: