SPI Flash memory

Dependents:   AT45DB161D SPIFLASH_AT45DB n-bed_AT45DB161E AT45DB161D

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Sun Sep 11 06:12:15 2011 +0000
Child:
1:b379e16fdf6f
Commit message:
AT45DB161D module

AT45DB161D (16Mbits, 2MB, 528B/block) /AT45DB081D (8Mbits, 1MB, 264B/block)

Changed in this revision

at45db161d.cpp Show annotated file Show diff for this revision Revisions of this file
at45db161d.h Show annotated file Show diff for this revision Revisions of this file
at45db161d_commands.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/at45db161d.cpp	Sun Sep 11 06:12:15 2011 +0000
@@ -0,0 +1,539 @@
+/**
+ * AT45DB161D module for arduino (C) Vincent
+ *   SPI flash memory
+ *   http://blog.blockos.org/?p=27
+ *
+ * bug fix by todotani
+ *   http://todotani.cocolog-nifty.com/blog/2009/07/arduino-4cf4.html
+ *
+ * Modified for mbed, 2011 Suga.
+ */
+#include "at45db161d.h"
+
+/** CTOR **/
+ATD45DB161D::ATD45DB161D(PinName mosi, PinName miso, PinName sclk, PinName cs)
+  : _spi(mosi, miso, sclk), _cs(cs)
+{}
+
+ATD45DB161D::ATD45DB161D(SPI &spi, PinName cs)
+  : _spi(spi), _cs(cs)
+{}
+
+/** DTOR **/
+ATD45DB161D::~ATD45DB161D()
+{}
+
+/** Setup SPI and pinout **/
+void ATD45DB161D::Init()
+{
+//    uint8_t clr;
+    
+    /* Initialize pinout */
+/*
+    pinMode(DATAOUT, OUTPUT);
+    pinMode(DATAIN, INPUT);
+    pinMode(SPICLOCK, OUTPUT);
+    pinMode(SLAVESELECT, OUTPUT);
+    pinMode(DATAIN, INPUT);
+*/  
+      /* Disable device */
+      DF_CS_inactive;
+  
+    /* Setup SPI */
+//    SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);
+    _spi.format(8, 0);
+    _spi.frequency(1000000);
+
+    /* Cleanup registers */
+//    clr = SPSR;
+//    clr = SPDR;
+}
+
+/** 
+ * Read status register
+ * @return The content of the status register
+ **/
+uint8_t ATD45DB161D::ReadStatusRegister()
+{
+    uint8_t status;
+
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+  
+    /* Send status read command */
+    spi_transfer(AT45DB161D_STATUS_REGISTER_READ);
+    /* Get result with a dummy write */
+    status = spi_transfer(0x00);
+
+    return status;
+}
+
+/** 
+ * Read Manufacturer and Device ID 
+ * @note if id.extendedInfoLength is not equal to zero,
+ *       successive calls to spi_transfer(0xff) will return
+ *       the extended device information string bytes.
+ * @param id Pointer to the ID structure to initialize
+ **/
+void ATD45DB161D::ReadManufacturerAndDeviceID(struct ATD45DB161D::ID *id)
+{
+    
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+  
+    /* Send status read command */
+    spi_transfer(AT45DB161D_READ_MANUFACTURER_AND_DEVICE_ID);
+
+    /* Manufacturer ID */
+    id->manufacturer = spi_transfer(0xff);
+    /* Device ID (part 1) */
+    id->device[0] = spi_transfer(0xff);
+    /* Device ID (part 2) */
+    id->device[1] = spi_transfer(0xff);
+    /* Extended Device Information String Length */
+    id->extendedInfoLength = spi_transfer(0xff);
+    
+}
+
+/** 
+ * Main Memory Page Read. 
+ * A main memory page read allows the user to read data directly from
+ * any one of the 4096 pages in the main memory, bypassing both of the
+ * data buffers and leaving the contents of the buffers unchanged.
+ *
+ * @param page Page of the main memory to read
+ * @param offset Starting byte address within the page
+ **/
+void ATD45DB161D::ReadMainMemoryPage(uint16_t page, uint16_t offset)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer(AT45DB161D_PAGE_READ);
+    
+    /* Address (page | offset)  */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
+    spi_transfer((uint8_t)(offset & 0xff));
+    
+    /* 4 "don't care" bytes */
+    spi_transfer(0x00);
+    spi_transfer(0x00);
+    spi_transfer(0x00);
+    spi_transfer(0x00);
+}
+
+/** 
+ * Continuous Array Read.
+ * Sequentially read a continuous stream of data.
+ * @param page Page of the main memory where the sequential read will start
+ * @param offset Starting byte address within the page
+ * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
+ * @note The legacy mode is not currently supported
+ **/
+void ATD45DB161D::ContinuousArrayRead(uint16_t page, uint16_t offset, uint8_t low)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer( low ? AT45DB161D_CONTINUOUS_READ_LOW_FREQ :
+                        AT45DB161D_CONTINUOUS_READ_HIGH_FREQ );
+
+    /* Address (page | offset)  */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
+    spi_transfer((uint8_t)(offset & 0xff));
+    
+    if (!low) { spi_transfer(0x00); }
+}
+
+
+/** 
+ * Read the content of one of the SRAM data buffers (in low or high speed mode).
+ * @param bufferNum Buffer to read (1 or 2)
+ * @param offset Starting byte within the buffer
+ * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
+ **/
+void ATD45DB161D::BufferRead(uint8_t bufferNum, uint16_t offset, uint8_t low)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    if(bufferNum == 1)
+    {
+        spi_transfer(low ? AT45DB161D_BUFFER_1_READ_LOW_FREQ :
+                           AT45DB161D_BUFFER_1_READ);
+    }
+    else
+    {
+        spi_transfer(low ? AT45DB161D_BUFFER_2_READ_LOW_FREQ :
+                           AT45DB161D_BUFFER_2_READ);
+
+    }
+    
+    /* 14 "Don't care" bits */
+    spi_transfer(0x00);
+    /* Rest of the "don't care" bits + bits 8,9 of the offset */
+    spi_transfer((uint8_t)(offset >> 8));
+    /* bits 7-0 of the offset */
+    spi_transfer((uint8_t)(offset & 0xff));
+}
+
+/** 
+ * Write data to one of the SRAM data buffers. Any further call to
+ * spi_tranfer will return bytes contained in the data buffer until
+ * a low-to-high transition is detected on the CS pin. If the end of
+ * the data buffer is reached, the device will wrap around back to the
+ * beginning of the buffer. 
+ * @param bufferNum Buffer to read (1 or 2)
+ * @param offset Starting byte within the buffer
+ **/
+void ATD45DB161D::BufferWrite(uint8_t bufferNum, uint16_t offset)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_WRITE :
+                                     AT45DB161D_BUFFER_2_WRITE);
+    
+    /* 14 "Don't care" bits */
+    spi_transfer(0x00);
+    /* Rest of the "don't care" bits + bits 8,9 of the offset */
+    spi_transfer((uint8_t)(offset >> 8));
+    /* bits 7-0 of the offset */
+    spi_transfer((uint8_t)(offset & 0xff));
+}
+
+/**
+ * Transfer data from buffer 1 or 2 to main memory page.
+ * @param bufferNum Buffer to use (1 or 2)
+ * @param page Page where the content of the buffer will transfered
+ * @param erase If set the page will be first erased before the buffer transfer.
+ * @note If erase is equal to zero, the page must have been previously erased using one of the erase command (Page or Block Erase).
+ **/
+void ATD45DB161D::BufferToPage(uint8_t bufferNum, uint16_t page, uint8_t erase)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Opcode */
+    if(erase)
+    {
+        spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_TO_PAGE_WITH_ERASE :
+                                         AT45DB161D_BUFFER_2_TO_PAGE_WITH_ERASE);
+    }
+    else
+    {
+        spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_TO_PAGE_WITHOUT_ERASE :
+                                         AT45DB161D_BUFFER_2_TO_PAGE_WITHOUT_ERASE);
+    }
+    
+    /*
+     * 3 address bytes consist of :
+     *     - 2 don&#65533;ft care bits
+     *     - 12 page address bits (PA11 - PA0) that specify the page in 
+     *       the main memory to be written
+     *     - 10 don&#65533;ft care bits
+     */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)(page << 2));
+    spi_transfer(0x00);
+    
+    DF_CS_inactive;  /* Start transfer */
+    DF_CS_active;    /* If erase was set, the page will first be erased */
+
+    /* Wait for the end of the transfer */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/**
+ * Transfer a page of data from main memory to buffer 1 or 2.
+ * @param page Main memory page to transfer
+ * @param buffer Buffer (1 or 2) where the data will be written
+ **/
+void ATD45DB161D::PageToBuffer(uint16_t page, uint8_t bufferNum)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+ 
+    /* Send opcode */
+    spi_transfer((bufferNum == 1) ? AT45DB161D_TRANSFER_PAGE_TO_BUFFER_1 :
+                                    AT45DB161D_TRANSFER_PAGE_TO_BUFFER_2);
+
+    /*
+     * 3 address bytes consist of :
+     *     - 2 don&#65533;ft care bits
+     *     - 12 page address bits (PA11 - PA0) that specify the page in 
+     *       the main memory to be written
+     *     - 10 don&#65533;ft care bits
+     */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)(page << 2));
+    spi_transfer(0x00);
+        
+    DF_CS_inactive;  /* Start page transfer */
+    DF_CS_active;
+
+    /* Wait for the end of the transfer */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/** 
+ * Erase a page in the main memory array.
+ * @param page Page to erase
+ **/
+void ATD45DB161D::PageErase(uint16_t page)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer(AT45DB161D_PAGE_ERASE);
+    
+    /*
+     * 3 address bytes consist of :
+     *     - 2 don&#65533;ft care bits
+     *     - 12 page address bits (PA11 - PA0) that specify the page in 
+     *       the main memory to be written
+     *     - 10 don&#65533;ft care bits
+     */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)(page << 2));
+    spi_transfer(0x00);
+        
+    DF_CS_inactive;  /* Start block erase */
+    DF_CS_active;
+
+    /* Wait for the end of the block erase operation */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/**
+ * Erase a block of eight pages at one time.
+ * @param block Index of the block to erase
+ **/
+void ATD45DB161D::BlockErase(uint16_t block)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer(AT45DB161D_BLOCK_ERASE);
+    
+    /*
+     * 3 address bytes consist of :
+     *     - 2 don&#65533;ft care bits
+     *     - 9 block address bits (PA11 - PA3)
+     *     - 13 don&#65533;ft care bits
+     */
+    spi_transfer((uint8_t)(block >> 3));
+    spi_transfer((uint8_t)(block << 5));
+    spi_transfer(0x00);
+        
+    DF_CS_inactive;  /* Start block erase */
+    DF_CS_active;
+
+    /* Wait for the end of the block erase operation */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/** 
+ * Erase a sector in main memory. There are 16 sector on the
+ * at45db161d and only one can be erased at one time.
+ * @param sector Sector to erase (1-15)
+ **/
+void ATD45DB161D::SectoreErase(uint8_t sector)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer(AT45DB161D_SECTOR_ERASE);
+    
+    /*
+     * 3 address bytes consist of :
+     */
+    if((sector == 0x0a) || (sector == 0x0b))
+    {
+        /*
+         *  - 11 don&#65533;ft care bits
+         *  - 
+         *  - 12 don&#65533;ft care bits
+         */
+        spi_transfer(0x00);
+        spi_transfer(((sector & 0x01) << 4));
+        spi_transfer(0x00);
+    }
+    else
+    {
+        /*
+         *  - 2 don't care bits 
+         *  - 4 sector number bits
+         *  - 18 don't care bits 
+         */
+        spi_transfer(sector << 1);
+        spi_transfer(0x00);
+        spi_transfer(0x00);
+    }
+                
+    DF_CS_inactive;  /* Start block erase */
+    DF_CS_active;
+
+    /* Wait for the end of the block erase operation */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/** 
+ * Erase the entire chip memory. Sectors proteced or locked down will
+ * not be erased.
+ **/
+void ATD45DB161D::ChipErase()
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send chip erase sequence */
+    spi_transfer(AT45DB161D_CHIP_ERASE_0);
+    spi_transfer(AT45DB161D_CHIP_ERASE_1);
+    spi_transfer(AT45DB161D_CHIP_ERASE_2);
+    spi_transfer(AT45DB161D_CHIP_ERASE_3);
+                
+    DF_CS_inactive;  /* Start chip erase */
+    DF_CS_active;
+
+    /* Wait for the end of the chip erase operation */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+}
+
+/**
+ * This a combination of Buffer Write and Buffer to Page with
+ * Built-in Erase.
+ * @note You must call EndAndWait in order to start transfering data from buffer to page
+ * @param page Page where the content of the buffer will transfered
+ * @param offset Starting byte address within the buffer
+ * @param bufferNum Buffer to use (1 or 2)
+ * @warning UNTESTED
+ **/
+void ATD45DB161D::BeginPageWriteThroughBuffer(uint16_t page, uint16_t offset, uint8_t bufferNum)
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer((bufferNum == 1) ? AT45DB161D_PAGE_THROUGH_BUFFER_1 :
+                                    AT45DB161D_PAGE_THROUGH_BUFFER_2);
+
+    /* Address */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
+    spi_transfer((uint8_t)offset);
+}
+
+/**
+ * Perform a low-to-high transition on the CS pin and then poll
+ * the status register to check if the dataflash is busy.
+ **/
+void ATD45DB161D::EndAndWait()
+{
+    DF_CS_inactive;  /* End current operation */
+    DF_CS_active;    /* Some internal operation may occur
+                      * (buffer to page transfer, page erase, etc... ) */
+
+    /* Wait for the chip to be ready */
+      while(!(ReadStatusRegister() & READY_BUSY))
+      {}
+      
+    DF_CS_inactive;  /* Release SPI Bus */ 
+}
+
+/**
+ * Compare a page of data in main memory to the data in buffer 1 or 2.
+ * @param page Page to test
+ * @param bufferNum Buffer number
+ * @return
+ *        - 1 if the page and the buffer contains the same data
+ *         - 0 else
+ * @warning UNTESTED
+ **/
+int8_t ATD45DB161D::ComparePageToBuffer(uint16_t page, uint8_t bufferNum)
+{
+    uint8_t status;
+    
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+
+    /* Send opcode */
+    spi_transfer((bufferNum == 1) ? AT45DB161D_COMPARE_PAGE_TO_BUFFER_1 :
+                                    AT45DB161D_COMPARE_PAGE_TO_BUFFER_2);
+    
+    /* Page address */
+    spi_transfer((uint8_t)(page >> 6));
+    spi_transfer((uint8_t)(page << 2));
+    spi_transfer(0x00);
+    
+    DF_CS_inactive;  /* Start comparaison */
+    DF_CS_active;
+
+    /* Wait for the end of the comparaison and get the result */
+      while(!((status = ReadStatusRegister()) & READY_BUSY))
+      {}
+          
+//      return ((status & COMPARE) == COMPARE);
+      return ((status & COMPARE) ? 0 : 1);
+}
+
+/**
+ * Put the device into the lowest power consumption mode.
+ * Once the device has entered the Deep Power-down mode, all
+ * instructions are ignored except the Resume from Deep
+ * Power-down command.
+ * @warning UNTESTED
+ **/
+void ATD45DB161D::DeepPowerDown()
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+    
+    /* Send opcode */
+    spi_transfer(AT45DB161D_DEEP_POWER_DOWN);
+    
+    /* Enter Deep Power-Down mode */
+    DF_CS_inactive;
+    
+    /* Safety delay */
+//    delay(100);
+    wait_ms(100);
+}
+
+/**
+ * Takes the device out of Deep Power-down mode.
+ **/
+void ATD45DB161D::ResumeFromDeepPowerDown()
+{
+    DF_CS_inactive;    /* Make sure to toggle CS signal in order */
+    DF_CS_active;      /* to reset Dataflash command decoder     */
+    
+    /* Send opcode */
+    spi_transfer(AT45DB161D_RESUME_FROM_DEEP_POWER_DOWN);
+    
+    /* Resume device */
+    DF_CS_inactive;
+    
+    /* The CS pin must stay high during t_RDPD microseconds before the device
+     * can receive any commands.
+     * On the at45db161D t_RDPD = 35 microseconds. But we will wait 100
+     * (just to be sure). */
+//    delay(100);
+    wait_ms(100);
+}
+ 
+/** **/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/at45db161d.h	Sun Sep 11 06:12:15 2011 +0000
@@ -0,0 +1,308 @@
+/**
+ * @file at45db161d.h
+ * @brief AT45DB161D module
+ **/
+#ifndef AT45DB161D_H
+#define AT45DB161D_H
+
+#include "mbed.h"
+
+extern "C" {
+
+//#include <avr/pgmspace.h>
+#include <inttypes.h>
+//#include "WConstants.h"
+
+};
+
+#include "at45db161d_commands.h"
+
+/**
+ * @defgroup AT45DB161D AT45DB161D module
+ * @{
+ **/
+
+/**
+ * @defgroup SPI SPI pinout and transfert function
+ * @{
+ **/
+#ifndef SPI
+/**
+ * @defgroup SPI_Pinout SPI pinout
+ * @{
+ **/
+/** Serial input (SI) **/
+#define DATAOUT     11
+/** Serial output (SO) **/
+#define DATAIN      12
+/** Serial clock (SCK) **/
+#define SPICLOCK    13
+/** Chip select (CS) **/
+#define SLAVESELECT 10
+/** Reset (Reset) **/
+#define RESET        8
+/** Write protect (WP) **/
+#define WP           7
+/**
+ * @} 
+ **/
+
+/**
+ * @fn inline uint8_t spi_transfer(uint8_t data)
+ * @brief Transfer a byte via spi
+ * @param data Data to transfer via SPI
+ * @return The content of the SPI data register (SPDR)
+ **/
+/*
+inline uint8_t spi_transfer(uint8_t data)
+{
+    SPDR = data;
+    while(!(SPSR & (1 << SPIF))) ;
+    return SPDR;
+}
+*/
+#define spi_transfer(data) _spi.write(data)
+
+/** De-assert CS **/
+//#define DF_CS_inactive digitalWrite(SLAVESELECT,HIGH)
+#define DF_CS_inactive _cs = 1
+/** Assert CS **/
+//#define DF_CS_active digitalWrite(SLAVESELECT,LOW)
+#define DF_CS_active _cs = 0
+
+#endif /* SPI */
+/**
+ * @}
+ **/
+
+/**
+ * @defgroup STATUS_REGISTER_FORMAT Status register format
+ * @{
+ **/
+/**
+ * Ready/busy status is indicated using bit 7 of the status register.
+ * If bit 7 is a 1, then the device is not busy and is ready to accept
+ * the next command. If bit 7 is a 0, then the device is in a busy 
+ * state.
+ **/
+#define READY_BUSY 0x80
+/**
+ * Result of the most recent Memory Page to Buffer Compare operation.
+ * If this bit is equal to 0, then the data in the main memory page
+ * matches the data in the buffer. If it's 1 then at least 1 byte in 
+ * the main memory page does not match the data in the buffer.
+ **/
+#define COMPARE 0x40
+/**
+ * Bit 1 in the Status Register is used to provide information to the
+ * user whether or not the sector protection has been enabled or
+ * disabled, either by software-controlled method or 
+ * hardware-controlled method. 1 means that the sector protection has
+ * been enabled and 0 that it has been disabled.
+ **/
+#define PROTECT 0x02
+/**
+ * Bit 0 indicates wether the page size of the main memory array is
+ * configured for "power of 2" binary page size (512 bytes) (bit=1) or 
+ * standard DataFlash page size (528 bytes) (bit=0).
+ **/
+#define PAGE_SIZE 0x01
+/**
+ * Bits 5, 4, 3 and 2 indicates the device density. The decimal value
+ * of these four binary bits does not equate to the device density; the
+ * four bits represent a combinational code relating to differing
+ * densities of DataFlash devices. The device density is not the same
+ * as the density code indicated in the JEDEC device ID information.
+ * The device density is provided only for backward compatibility.
+ **/
+#define DEVICE_DENSITY 0x2C 
+/**
+ * @}
+ **/
+
+/**
+ * @brief at45db161d module
+ * @todo
+ *     - TESTS!
+ *     - Protection and Security Commands
+ *     - Auto Page Rewrite through Buffer 1
+ *     - Auto Page Rewrite through Buffer 2
+ **/
+class ATD45DB161D
+{
+    public:
+        /** 
+         * @brief ID structure 
+         * This structure contains various informations about the
+         * dataflash chip being used.
+         **/
+        struct ID
+        {
+            uint8_t manufacturer;       /**< Manufacturer id                           **/
+            uint8_t device[2];          /**< Device id                                 **/
+            uint8_t extendedInfoLength; /**< Extended device information string length **/
+        };
+
+    public:
+        /** CTOR **/
+        ATD45DB161D(PinName mosi, PinName miso, PinName sclk, PinName cs);
+        ATD45DB161D(SPI &spi, PinName cs);
+        /** DTOR **/
+        ~ATD45DB161D();
+
+        /** Setup SPI and pinout **/
+        void Init();
+
+        /** 
+         * Read status register 
+         * @return The content of the status register
+         * **/
+        uint8_t ReadStatusRegister();
+
+        /** 
+         * Read Manufacturer and Device ID 
+         * @note if id.extendedInfoLength is not equal to zero,
+         *       successive calls to spi_transfer(0xff) will return
+         *       the extended device information string bytes.
+         * @param id Pointer to the ID structure to initialize
+         **/
+        void ReadManufacturerAndDeviceID(struct ATD45DB161D::ID *id);
+        
+        /** 
+         * A main memory page read allows the user to read data directly from
+         * any one of the 4096 pages in the main memory, bypassing both of the
+         * data buffers and leaving the contents of the buffers unchanged.
+         * @param page Page of the main memory to read
+         * @param offset Starting byte address within the page
+         **/
+        void ReadMainMemoryPage(uint16_t page, uint16_t offset);
+
+        /** 
+         * Sequentially read a continuous stream of data.
+         * @param page Page of the main memory where the sequential read will start
+         * @param offset Starting byte address within the page
+         * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
+         * @note The legacy mode is not currently supported
+         * @warning UNTESTED
+         **/
+        void ContinuousArrayRead(uint16_t page, uint16_t offset, uint8_t low);
+
+        /** 
+         * Read the content of one of the SRAM data buffers (in low or high speed mode).
+         * @param bufferNum Buffer to read (1 or 2)
+         * @param offset Starting byte within the buffer
+         * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
+         **/
+        void BufferRead(uint8_t bufferNum, uint16_t offset, uint8_t low);
+
+        /** 
+         * Write data to one of the SRAM data buffers. Any further call to
+         * spi_tranfer will return bytes contained in the data buffer until
+         * a low-to-high transition is detected on the CS pin. If the end of
+         * the data buffer is reached, the device will wrap around back to the
+         * beginning of the buffer. 
+         * @param bufferNum Buffer to read (1 or 2)
+         * @param offset Starting byte within the buffer
+         **/
+        void BufferWrite(uint8_t bufferNum, uint16_t offset);
+        
+        /**
+         * Transfer data from buffer 1 or 2 to main memory page.
+         * @param bufferNum Buffer to use (1 or 2)
+         * @param page Page where the content of the buffer will transfered
+         * @param erase If set the page will be first erased before the buffer transfer.
+         * @note If erase is equal to zero, the page must have been previously erased using one of the erase command (Page or Block Erase).
+         **/
+        void BufferToPage(uint8_t bufferNum, uint16_t page, uint8_t erase);        
+
+        /**
+         * Transfer a page of data from main memory to buffer 1 or 2.
+         * @param page Main memory page to transfer
+         * @param buffer Buffer (1 or 2) where the data will be written
+         **/
+        void PageToBuffer(uint16_t page, uint8_t bufferNum);
+
+        /** 
+         * Erase a page in the main memory array.
+         * @param page Page to erase
+         * @warning UNTESTED
+         **/
+        void PageErase(uint16_t page);
+        
+        /**
+         * Erase a block of eight pages at one time.
+         * @param block Index of the block to erase
+         * @warning UNTESTED
+         **/
+        void BlockErase(uint16_t block);
+
+        /** 
+         * Erase a sector in main memory. There are 16 sector on the
+         * at45db161d and only one can be erased at one time.
+         * @param sector Sector to erase
+         * @warning UNTESTED
+         **/
+        void SectoreErase(uint8_t sector);
+
+        /** 
+         * Erase the entire chip memory. Sectors proteced or locked down will
+         * not be erased.
+         * @warning UNTESTED
+         **/
+        void ChipErase();
+
+        /**
+         * This a combination of Buffer Write and Buffer to Page with
+         * Built-in Erase.
+         * @note You must call EndAndWait in order to start transfering data from buffer to page
+         * @param page Page where the content of the buffer will transfered
+         * @param offset Starting byte address within the buffer
+         * @param bufferNum Buffer to use (1 or 2)
+         * @warning UNTESTED
+         **/
+        void BeginPageWriteThroughBuffer(uint16_t page, uint16_t offset, uint8_t bufferNum);
+        
+        /**
+         * Perform a low-to-high transition on the CS pin and then poll
+         * the status register to check if the dataflash is busy.
+         **/
+        void EndAndWait();
+
+        /**
+         * Compare a page of data in main memory to the data in buffer 1 or 2.
+         * @param page Page to test
+         * @param bufferNum Buffer number
+         * @return
+         *        - 1 if the page and the buffer contains the same data
+         *         - 0 else
+         * @warning UNTESTED
+         **/
+        int8_t ComparePageToBuffer(uint16_t page, uint8_t bufferNum);
+
+        /**
+         * Put the device into the lowest power consumption mode.
+         * Once the device has entered the Deep Power-down mode, all
+         * instructions are ignored except the Resume from Deep
+         * Power-down command.
+         * @warning UNTESTED
+         **/
+        void DeepPowerDown();
+
+        /**
+         * Takes the device out of Deep Power-down mode.
+         * @warning UNTESTED
+         **/
+        void ResumeFromDeepPowerDown();
+
+    private:
+        /* Nothing atm but who knows... */
+
+        SPI _spi;
+        DigitalOut _cs;
+};
+
+/**
+ * @}
+ **/
+
+#endif /* AT45DB161D_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/at45db161d_commands.h	Sun Sep 11 06:12:15 2011 +0000
@@ -0,0 +1,169 @@
+/**
+ * @file at45db161d_commands.h
+ * @brief AT45DB161D commands opcodes
+ **/
+#ifndef AT45DB161D_COMMANDS_H
+#define AT45DB161D_COMMANDS_H
+
+/**
+ * @defgroup AT45DB161D_commands AT45DB161D commands opcodes
+ * @{
+ **/
+
+/**
+ * @defgroup Read_commands Read commands
+ * @{
+ **/
+/** Main Memory Page Read */
+#define AT45DB161D_PAGE_READ 0xD2
+/** Continuous Array Read (Low Frequency) **/
+#define AT45DB161D_CONTINUOUS_READ_LOW_FREQ 0x03
+/** Continuous Array Read (High Frequency) **/ 
+#define AT45DB161D_CONTINUOUS_READ_HIGH_FREQ 0x0B
+/** Buffer 1 Read (Low Frequency) **/
+#define AT45DB161D_BUFFER_1_READ_LOW_FREQ 0xD1
+/** Buffer 2 Read (Low Frequency) **/
+#define AT45DB161D_BUFFER_2_READ_LOW_FREQ 0xD3
+/** Buffer 1 Read **/
+#define AT45DB161D_BUFFER_1_READ 0xD4
+/** Buffer 2 Read **/
+#define AT45DB161D_BUFFER_2_READ 0xD6
+/**
+ * @}
+ **/
+
+/**
+ * @defgroup Program_Erase_commands Program and Erase commands
+ * @{
+ **/
+/** Buffer 1 Write **/
+#define AT45DB161D_BUFFER_1_WRITE 0x84
+/** Buffer 2 Write **/
+#define AT45DB161D_BUFFER_2_WRITE 0x87
+/** Buffer 1 to Main Memory Page Program with Built-in Erase **/
+#define AT45DB161D_BUFFER_1_TO_PAGE_WITH_ERASE 0x83
+/** Buffer 2 to Main Memory Page Program with Built-in Erase **/
+#define AT45DB161D_BUFFER_2_TO_PAGE_WITH_ERASE 0x86
+/** Buffer 1 to Main Memory Page Program without Built-in Erase **/
+#define AT45DB161D_BUFFER_1_TO_PAGE_WITHOUT_ERASE 0x88
+/** Buffer 2 to Main Memory Page Program without Built-in Erase **/
+#define AT45DB161D_BUFFER_2_TO_PAGE_WITHOUT_ERASE 0x89
+/** Page Erase **/
+#define AT45DB161D_PAGE_ERASE 0x81
+/** Block Erase **/
+#define AT45DB161D_BLOCK_ERASE 0x50
+/** Sector Erase **/
+#define AT45DB161D_SECTOR_ERASE 0x7C
+/** Chip Erase Sequence **/
+#define AT45DB161D_CHIP_ERASE_0 0xC7
+#define AT45DB161D_CHIP_ERASE_1 0x94
+#define AT45DB161D_CHIP_ERASE_2 0x80
+#define AT45DB161D_CHIP_ERASE_3 0x9A
+/** Main Memory Page Program Through Buffer 1 **/
+#define AT45DB161D_PAGE_THROUGH_BUFFER_1 0x82
+/** Main Memory Page Program Through Buffer 2 **/
+#define AT45DB161D_PAGE_THROUGH_BUFFER_2 0x85
+/**
+ * @}
+ **/
+
+/**
+ * @defgroup ProtectionSecurity_Commands Protection and Security Commands
+ * @warning UNIMPLEMENTED
+ * @{
+ **/
+#ifdef AT45DB161D_EXPERT_MODE
+/* Use the following commands at your own risk ! */
+/** Enable Sector Protection **/
+#define AT45DB161D_ENABLE_SECTOR_PROTECTION_0 0x3D
+#define AT45DB161D_ENABLE_SECTOR_PROTECTION_1 0x2A
+#define AT45DB161D_ENABLE_SECTOR_PROTECTION_2 0x7F
+#define AT45DB161D_ENABLE_SECTOR_PROTECTION_3 0xA9
+/** Disable Sector Protection **/
+#define AT45DB161D_DISABLE_SECTOR_PROTECTION_0 0x3D
+#define AT45DB161D_DISABLE_SECTOR_PROTECTION_1 0x2A
+#define AT45DB161D_DISABLE_SECTOR_PROTECTION_2 0x7F
+#define AT45DB161D_DISABLE_SECTOR_PROTECTION_3 0x9A
+/** Erase Sector Protection Register **/
+#define AT45DB161D_ERASE_SECTOR_PROTECTION_REGISTER_0 0x3D
+#define AT45DB161D_ERASE_SECTOR_PROTECTION_REGISTER_0 0x2A
+#define AT45DB161D_ERASE_SECTOR_PROTECTION_REGISTER_0 0x7F
+#define AT45DB161D_ERASE_SECTOR_PROTECTION_REGISTER_0 0xCF
+/** Program Sector Protection Register **/
+#define AT45DB161D_PROGRAM_SECTOR_PROTECTION_REGISTER_0 0x3D
+#define AT45DB161D_PROGRAM_SECTOR_PROTECTION_REGISTER_1 0x2A
+#define AT45DB161D_PROGRAM_SECTOR_PROTECTION_REGISTER_2 0x7F
+#define AT45DB161D_PROGRAM_SECTOR_PROTECTION_REGISTER_3 0xFC
+/** Sector Lockdown **/
+#define AT45DB161D_SECTOR_LOCKDOWN_0 0X3D
+#define AT45DB161D_SECTOR_LOCKDOWN_1 0x2A
+#define AT45DB161D_SECTOR_LOCKDOWN_2 0x7F
+#define AT45DB161D_SECTOR_LOCKDOWN_3 0x30
+/** Program Security Register **/
+#define AT45DB161D_PROGRAM_SECURITY_REGISTER_0 0x9B
+#define AT45DB161D_PROGRAM_SECURITY_REGISTER_1 0x00
+#define AT45DB161D_PROGRAM_SECURITY_REGISTER_2 0x00
+#define AT45DB161D_PROGRAM_SECURITY_REGISTER_3 0x00
+#endif /* AT45DB161D_EXPERT_MODE */
+
+/** Read Sector Protection Register **/
+#define AT45DB161D_READ_SECTOR_PROTECTION_REGISTER 0x32
+/** Read Sector Lockdown Register **/
+#define AT45DB161D_READ_SECTOR_LOCKDOWN_REGISTER 35H
+/** Read Security Register **/
+#define AT45DB161D_READ_SECURITY_REGISTER 0x77
+/**
+ * @}
+ **/
+
+/**
+ * @defgroup Additional_commands Additional Commands
+ * @{
+ **/
+/** Main Memory Page to Buffer 1 Transfer **/
+#define AT45DB161D_TRANSFER_PAGE_TO_BUFFER_1 0x53
+/** Main Memory Page to Buffer 2 Transfer **/
+#define AT45DB161D_TRANSFER_PAGE_TO_BUFFER_2 0x55
+/** Main Memory Page to Buffer 1 Compare **/
+#define AT45DB161D_COMPARE_PAGE_TO_BUFFER_1 0x60
+/** Main Memory Page to Buffer 2 Compare **/
+#define AT45DB161D_COMPARE_PAGE_TO_BUFFER_2 0x61
+/** Auto Page Rewrite through Buffer 1 **/
+#define AT45DB161D_AUTO_PAGE_REWRITE_THROUGH_BUFFER_1 0x58
+/** Auto Page Rewrite through Buffer 2 **/
+#define AT45DB161D_AUTO_PAGE_REWRITE_THROUGH_BUFFER_2 0x59
+/** Deep Power-down **/
+#define AT45DB161D_DEEP_POWER_DOWN 0xB9
+/** Resume from Deep Power-down **/
+#define AT45DB161D_RESUME_FROM_DEEP_POWER_DOWN 0xAB
+/** Status Register Read **/
+#define AT45DB161D_STATUS_REGISTER_READ 0xD7
+/** Manufacturer and Device ID Read **/
+#define AT45DB161D_READ_MANUFACTURER_AND_DEVICE_ID 0x9F
+/**
+ * @}
+ **/
+
+/**
+ * @defgroup Legacy_commands Legacy Commands
+ * @{
+ **/
+/** Buffer 1 Read **/
+#define AT45DB161D_BUFFER_1_READ_LEGACY 0X54
+/** Buffer 2 Read **/
+#define AT45DB161D_BUFFER_2_READ_LEGACY 0x56
+/** Main Memory Page Read **/
+#define AT45DB161D_PAGE_READ_LEGACY 0x52
+/** Continuous Array Read **/
+#define AT45DB161D_CONTINUOUS_READ_LEGACY 0x68
+/** Status Register Read **/
+#define AT45DB161D_STATUS_REGISTER_READ_LEGACY 0x57
+/**
+ * @}
+ **/
+
+/**
+ * @}
+ **/
+
+#endif /* AT45DB161D_COMMANDS_H */