Suga koubou / at45db161d

Dependents:   AT45DB161D SPIFLASH_AT45DB n-bed_AT45DB161E AT45DB161D

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers at45db161d.cpp Source File

at45db161d.cpp

00001 /**
00002  * AT45DB161D module for arduino (C) Vincent
00003  *   SPI flash memory
00004  *   http://blog.blockos.org/?p=27
00005  *
00006  * bug fix by todotani
00007  *   http://todotani.cocolog-nifty.com/blog/2009/07/arduino-4cf4.html
00008  *
00009  * Modified for mbed, 2011 Suga.
00010  */
00011 #include "at45db161d.h"
00012 
00013 /** CTOR **/
00014 ATD45DB161D::ATD45DB161D(PinName mosi, PinName miso, PinName sclk, PinName cs)
00015   : _spi(mosi, miso, sclk), _cs(cs)
00016 {}
00017 
00018 ATD45DB161D::ATD45DB161D(SPI &spi, PinName cs)
00019   : _spi(spi), _cs(cs)
00020 {}
00021 
00022 /** DTOR **/
00023 ATD45DB161D::~ATD45DB161D()
00024 {}
00025 
00026 /** Setup SPI and pinout **/
00027 void ATD45DB161D::Init()
00028 {
00029 //    uint8_t clr;
00030     
00031     /* Initialize pinout */
00032 /*
00033     pinMode(DATAOUT, OUTPUT);
00034     pinMode(DATAIN, INPUT);
00035     pinMode(SPICLOCK, OUTPUT);
00036     pinMode(SLAVESELECT, OUTPUT);
00037     pinMode(DATAIN, INPUT);
00038 */  
00039       /* Disable device */
00040       DF_CS_inactive;
00041   
00042     /* Setup SPI */
00043 //    SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);
00044     _spi.format(8, 0);
00045 
00046     /* Cleanup registers */
00047 //    clr = SPSR;
00048 //    clr = SPDR;
00049 }
00050 
00051 /** 
00052  * Read status register
00053  * @return The content of the status register
00054  **/
00055 uint8_t ATD45DB161D::ReadStatusRegister()
00056 {
00057     uint8_t status;
00058 
00059     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00060     DF_CS_active;      /* to reset Dataflash command decoder     */
00061   
00062     /* Send status read command */
00063     spi_transfer(AT45DB161D_STATUS_REGISTER_READ);
00064     /* Get result with a dummy write */
00065     status = spi_transfer(0x00);
00066 
00067     return status;
00068 }
00069 
00070 /** 
00071  * Read Manufacturer and Device ID 
00072  * @note if id.extendedInfoLength is not equal to zero,
00073  *       successive calls to spi_transfer(0xff) will return
00074  *       the extended device information string bytes.
00075  * @param id Pointer to the ID structure to initialize
00076  **/
00077 void ATD45DB161D::ReadManufacturerAndDeviceID(struct ATD45DB161D::ID *id)
00078 {
00079     
00080     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00081     DF_CS_active;      /* to reset Dataflash command decoder     */
00082   
00083     /* Send status read command */
00084     spi_transfer(AT45DB161D_READ_MANUFACTURER_AND_DEVICE_ID);
00085 
00086     /* Manufacturer ID */
00087     id->manufacturer = spi_transfer(0xff);
00088     /* Device ID (part 1) */
00089     id->device[0] = spi_transfer(0xff);
00090     /* Device ID (part 2) */
00091     id->device[1] = spi_transfer(0xff);
00092     /* Extended Device Information String Length */
00093     id->extendedInfoLength = spi_transfer(0xff);
00094     
00095 }
00096 
00097 /** 
00098  * Main Memory Page Read. 
00099  * A main memory page read allows the user to read data directly from
00100  * any one of the 4096 pages in the main memory, bypassing both of the
00101  * data buffers and leaving the contents of the buffers unchanged.
00102  *
00103  * @param page Page of the main memory to read
00104  * @param offset Starting byte address within the page
00105  **/
00106 void ATD45DB161D::ReadMainMemoryPage(uint16_t page, uint16_t offset)
00107 {
00108     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00109     DF_CS_active;      /* to reset Dataflash command decoder     */
00110 
00111     /* Send opcode */
00112     spi_transfer(AT45DB161D_PAGE_READ);
00113     
00114     /* Address (page | offset)  */
00115     spi_transfer((uint8_t)(page >> 6));
00116     spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
00117     spi_transfer((uint8_t)(offset & 0xff));
00118     
00119     /* 4 "don't care" bytes */
00120     spi_transfer(0x00);
00121     spi_transfer(0x00);
00122     spi_transfer(0x00);
00123     spi_transfer(0x00);
00124 }
00125 
00126 /** 
00127  * Continuous Array Read.
00128  * Sequentially read a continuous stream of data.
00129  * @param page Page of the main memory where the sequential read will start
00130  * @param offset Starting byte address within the page
00131  * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
00132  * @note The legacy mode is not currently supported
00133  **/
00134 void ATD45DB161D::ContinuousArrayRead(uint16_t page, uint16_t offset, uint8_t low)
00135 {
00136     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00137     DF_CS_active;      /* to reset Dataflash command decoder     */
00138 
00139     /* Send opcode */
00140     spi_transfer( low ? AT45DB161D_CONTINUOUS_READ_LOW_FREQ :
00141                         AT45DB161D_CONTINUOUS_READ_HIGH_FREQ );
00142 
00143     /* Address (page | offset)  */
00144     spi_transfer((uint8_t)(page >> 6));
00145     spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
00146     spi_transfer((uint8_t)(offset & 0xff));
00147     
00148     if (!low) { spi_transfer(0x00); }
00149 }
00150 
00151 
00152 /** 
00153  * Read the content of one of the SRAM data buffers (in low or high speed mode).
00154  * @param bufferNum Buffer to read (1 or 2)
00155  * @param offset Starting byte within the buffer
00156  * @param low If true the read operation will be performed in low speed mode (and in high speed mode if it's false).
00157  **/
00158 void ATD45DB161D::BufferRead(uint8_t bufferNum, uint16_t offset, uint8_t low)
00159 {
00160     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00161     DF_CS_active;      /* to reset Dataflash command decoder     */
00162 
00163     /* Send opcode */
00164     if(bufferNum == 1)
00165     {
00166         spi_transfer(low ? AT45DB161D_BUFFER_1_READ_LOW_FREQ :
00167                            AT45DB161D_BUFFER_1_READ);
00168     }
00169     else
00170     {
00171         spi_transfer(low ? AT45DB161D_BUFFER_2_READ_LOW_FREQ :
00172                            AT45DB161D_BUFFER_2_READ);
00173 
00174     }
00175     
00176     /* 14 "Don't care" bits */
00177     spi_transfer(0x00);
00178     /* Rest of the "don't care" bits + bits 8,9 of the offset */
00179     spi_transfer((uint8_t)(offset >> 8));
00180     /* bits 7-0 of the offset */
00181     spi_transfer((uint8_t)(offset & 0xff));
00182 }
00183 
00184 /** 
00185  * Write data to one of the SRAM data buffers. Any further call to
00186  * spi_tranfer will return bytes contained in the data buffer until
00187  * a low-to-high transition is detected on the CS pin. If the end of
00188  * the data buffer is reached, the device will wrap around back to the
00189  * beginning of the buffer. 
00190  * @param bufferNum Buffer to read (1 or 2)
00191  * @param offset Starting byte within the buffer
00192  **/
00193 void ATD45DB161D::BufferWrite(uint8_t bufferNum, uint16_t offset)
00194 {
00195     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00196     DF_CS_active;      /* to reset Dataflash command decoder     */
00197 
00198     spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_WRITE :
00199                                      AT45DB161D_BUFFER_2_WRITE);
00200     
00201     /* 14 "Don't care" bits */
00202     spi_transfer(0x00);
00203     /* Rest of the "don't care" bits + bits 8,9 of the offset */
00204     spi_transfer((uint8_t)(offset >> 8));
00205     /* bits 7-0 of the offset */
00206     spi_transfer((uint8_t)(offset & 0xff));
00207 }
00208 
00209 /**
00210  * Transfer data from buffer 1 or 2 to main memory page.
00211  * @param bufferNum Buffer to use (1 or 2)
00212  * @param page Page where the content of the buffer will transfered
00213  * @param erase If set the page will be first erased before the buffer transfer.
00214  * @note If erase is equal to zero, the page must have been previously erased using one of the erase command (Page or Block Erase).
00215  **/
00216 void ATD45DB161D::BufferToPage(uint8_t bufferNum, uint16_t page, uint8_t erase)
00217 {
00218     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00219     DF_CS_active;      /* to reset Dataflash command decoder     */
00220 
00221     /* Opcode */
00222     if(erase)
00223     {
00224         spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_TO_PAGE_WITH_ERASE :
00225                                          AT45DB161D_BUFFER_2_TO_PAGE_WITH_ERASE);
00226     }
00227     else
00228     {
00229         spi_transfer( (bufferNum == 1) ? AT45DB161D_BUFFER_1_TO_PAGE_WITHOUT_ERASE :
00230                                          AT45DB161D_BUFFER_2_TO_PAGE_WITHOUT_ERASE);
00231     }
00232     
00233     /*
00234      * 3 address bytes consist of :
00235      *     - 2 don&#65533;ft care bits
00236      *     - 12 page address bits (PA11 - PA0) that specify the page in 
00237      *       the main memory to be written
00238      *     - 10 don&#65533;ft care bits
00239      */
00240     spi_transfer((uint8_t)(page >> 6));
00241     spi_transfer((uint8_t)(page << 2));
00242     spi_transfer(0x00);
00243     
00244     DF_CS_inactive;  /* Start transfer */
00245     DF_CS_active;    /* If erase was set, the page will first be erased */
00246 
00247     /* Wait for the end of the transfer */
00248       while(!(ReadStatusRegister() & READY_BUSY))
00249       {}
00250 }
00251 
00252 /**
00253  * Transfer a page of data from main memory to buffer 1 or 2.
00254  * @param page Main memory page to transfer
00255  * @param buffer Buffer (1 or 2) where the data will be written
00256  **/
00257 void ATD45DB161D::PageToBuffer(uint16_t page, uint8_t bufferNum)
00258 {
00259     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00260     DF_CS_active;      /* to reset Dataflash command decoder     */
00261  
00262     /* Send opcode */
00263     spi_transfer((bufferNum == 1) ? AT45DB161D_TRANSFER_PAGE_TO_BUFFER_1 :
00264                                     AT45DB161D_TRANSFER_PAGE_TO_BUFFER_2);
00265 
00266     /*
00267      * 3 address bytes consist of :
00268      *     - 2 don&#65533;ft care bits
00269      *     - 12 page address bits (PA11 - PA0) that specify the page in 
00270      *       the main memory to be written
00271      *     - 10 don&#65533;ft care bits
00272      */
00273     spi_transfer((uint8_t)(page >> 6));
00274     spi_transfer((uint8_t)(page << 2));
00275     spi_transfer(0x00);
00276         
00277     DF_CS_inactive;  /* Start page transfer */
00278     DF_CS_active;
00279 
00280     /* Wait for the end of the transfer */
00281       while(!(ReadStatusRegister() & READY_BUSY))
00282       {}
00283 }
00284 
00285 /** 
00286  * Erase a page in the main memory array.
00287  * @param page Page to erase
00288  **/
00289 void ATD45DB161D::PageErase(uint16_t page)
00290 {
00291     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00292     DF_CS_active;      /* to reset Dataflash command decoder     */
00293 
00294     /* Send opcode */
00295     spi_transfer(AT45DB161D_PAGE_ERASE);
00296     
00297     /*
00298      * 3 address bytes consist of :
00299      *     - 2 don&#65533;ft care bits
00300      *     - 12 page address bits (PA11 - PA0) that specify the page in 
00301      *       the main memory to be written
00302      *     - 10 don&#65533;ft care bits
00303      */
00304     spi_transfer((uint8_t)(page >> 6));
00305     spi_transfer((uint8_t)(page << 2));
00306     spi_transfer(0x00);
00307         
00308     DF_CS_inactive;  /* Start block erase */
00309     DF_CS_active;
00310 
00311     /* Wait for the end of the block erase operation */
00312       while(!(ReadStatusRegister() & READY_BUSY))
00313       {}
00314 }
00315 
00316 /**
00317  * Erase a block of eight pages at one time.
00318  * @param block Index of the block to erase
00319  **/
00320 void ATD45DB161D::BlockErase(uint16_t block)
00321 {
00322     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00323     DF_CS_active;      /* to reset Dataflash command decoder     */
00324 
00325     /* Send opcode */
00326     spi_transfer(AT45DB161D_BLOCK_ERASE);
00327     
00328     /*
00329      * 3 address bytes consist of :
00330      *     - 2 don&#65533;ft care bits
00331      *     - 9 block address bits (PA11 - PA3)
00332      *     - 13 don&#65533;ft care bits
00333      */
00334     spi_transfer((uint8_t)(block >> 3));
00335     spi_transfer((uint8_t)(block << 5));
00336     spi_transfer(0x00);
00337         
00338     DF_CS_inactive;  /* Start block erase */
00339     DF_CS_active;
00340 
00341     /* Wait for the end of the block erase operation */
00342       while(!(ReadStatusRegister() & READY_BUSY))
00343       {}
00344 }
00345 
00346 /** 
00347  * Erase a sector in main memory. There are 16 sector on the
00348  * at45db161d and only one can be erased at one time.
00349  * @param sector Sector to erase (1-15)
00350  **/
00351 void ATD45DB161D::SectoreErase(uint8_t sector)
00352 {
00353     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00354     DF_CS_active;      /* to reset Dataflash command decoder     */
00355 
00356     /* Send opcode */
00357     spi_transfer(AT45DB161D_SECTOR_ERASE);
00358     
00359     /*
00360      * 3 address bytes consist of :
00361      */
00362     if((sector == 0x0a) || (sector == 0x0b))
00363     {
00364         /*
00365          *  - 11 don&#65533;ft care bits
00366          *  - 
00367          *  - 12 don&#65533;ft care bits
00368          */
00369         spi_transfer(0x00);
00370         spi_transfer(((sector & 0x01) << 4));
00371         spi_transfer(0x00);
00372     }
00373     else
00374     {
00375         /*
00376          *  - 2 don't care bits 
00377          *  - 4 sector number bits
00378          *  - 18 don't care bits 
00379          */
00380         spi_transfer(sector << 1);
00381         spi_transfer(0x00);
00382         spi_transfer(0x00);
00383     }
00384                 
00385     DF_CS_inactive;  /* Start block erase */
00386     DF_CS_active;
00387 
00388     /* Wait for the end of the block erase operation */
00389       while(!(ReadStatusRegister() & READY_BUSY))
00390       {}
00391 }
00392 
00393 /** 
00394  * Erase the entire chip memory. Sectors proteced or locked down will
00395  * not be erased.
00396  **/
00397 void ATD45DB161D::ChipErase()
00398 {
00399     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00400     DF_CS_active;      /* to reset Dataflash command decoder     */
00401 
00402     /* Send chip erase sequence */
00403     spi_transfer(AT45DB161D_CHIP_ERASE_0);
00404     spi_transfer(AT45DB161D_CHIP_ERASE_1);
00405     spi_transfer(AT45DB161D_CHIP_ERASE_2);
00406     spi_transfer(AT45DB161D_CHIP_ERASE_3);
00407                 
00408     DF_CS_inactive;  /* Start chip erase */
00409     DF_CS_active;
00410 
00411     /* Wait for the end of the chip erase operation */
00412       while(!(ReadStatusRegister() & READY_BUSY))
00413       {}
00414 }
00415 
00416 /**
00417  * This a combination of Buffer Write and Buffer to Page with
00418  * Built-in Erase.
00419  * @note You must call EndAndWait in order to start transfering data from buffer to page
00420  * @param page Page where the content of the buffer will transfered
00421  * @param offset Starting byte address within the buffer
00422  * @param bufferNum Buffer to use (1 or 2)
00423  * @warning UNTESTED
00424  **/
00425 void ATD45DB161D::BeginPageWriteThroughBuffer(uint16_t page, uint16_t offset, uint8_t bufferNum)
00426 {
00427     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00428     DF_CS_active;      /* to reset Dataflash command decoder     */
00429 
00430     /* Send opcode */
00431     spi_transfer((bufferNum == 1) ? AT45DB161D_PAGE_THROUGH_BUFFER_1 :
00432                                     AT45DB161D_PAGE_THROUGH_BUFFER_2);
00433 
00434     /* Address */
00435     spi_transfer((uint8_t)(page >> 6));
00436     spi_transfer((uint8_t)((page << 2) | (offset >> 8)));
00437     spi_transfer((uint8_t)offset);
00438 }
00439 
00440 /**
00441  * Perform a low-to-high transition on the CS pin and then poll
00442  * the status register to check if the dataflash is busy.
00443  **/
00444 void ATD45DB161D::EndAndWait()
00445 {
00446     DF_CS_inactive;  /* End current operation */
00447     DF_CS_active;    /* Some internal operation may occur
00448                       * (buffer to page transfer, page erase, etc... ) */
00449 
00450     /* Wait for the chip to be ready */
00451       while(!(ReadStatusRegister() & READY_BUSY))
00452       {}
00453       
00454     DF_CS_inactive;  /* Release SPI Bus */ 
00455 }
00456 
00457 /**
00458  * Compare a page of data in main memory to the data in buffer 1 or 2.
00459  * @param page Page to test
00460  * @param bufferNum Buffer number
00461  * @return
00462  *        - 1 if the page and the buffer contains the same data
00463  *         - 0 else
00464  * @warning UNTESTED
00465  **/
00466 int8_t ATD45DB161D::ComparePageToBuffer(uint16_t page, uint8_t bufferNum)
00467 {
00468     uint8_t status;
00469     
00470     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00471     DF_CS_active;      /* to reset Dataflash command decoder     */
00472 
00473     /* Send opcode */
00474     spi_transfer((bufferNum == 1) ? AT45DB161D_COMPARE_PAGE_TO_BUFFER_1 :
00475                                     AT45DB161D_COMPARE_PAGE_TO_BUFFER_2);
00476     
00477     /* Page address */
00478     spi_transfer((uint8_t)(page >> 6));
00479     spi_transfer((uint8_t)(page << 2));
00480     spi_transfer(0x00);
00481     
00482     DF_CS_inactive;  /* Start comparaison */
00483     DF_CS_active;
00484 
00485     /* Wait for the end of the comparaison and get the result */
00486       while(!((status = ReadStatusRegister()) & READY_BUSY))
00487       {}
00488           
00489 //      return ((status & COMPARE) == COMPARE);
00490       return ((status & COMPARE) ? 0 : 1);
00491 }
00492 
00493 /**
00494  * Put the device into the lowest power consumption mode.
00495  * Once the device has entered the Deep Power-down mode, all
00496  * instructions are ignored except the Resume from Deep
00497  * Power-down command.
00498  * @warning UNTESTED
00499  **/
00500 void ATD45DB161D::DeepPowerDown()
00501 {
00502     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00503     DF_CS_active;      /* to reset Dataflash command decoder     */
00504     
00505     /* Send opcode */
00506     spi_transfer(AT45DB161D_DEEP_POWER_DOWN);
00507     
00508     /* Enter Deep Power-Down mode */
00509     DF_CS_inactive;
00510     
00511     /* Safety delay */
00512 //    delay(100);
00513     wait_ms(100);
00514 }
00515 
00516 /**
00517  * Takes the device out of Deep Power-down mode.
00518  **/
00519 void ATD45DB161D::ResumeFromDeepPowerDown()
00520 {
00521     DF_CS_inactive;    /* Make sure to toggle CS signal in order */
00522     DF_CS_active;      /* to reset Dataflash command decoder     */
00523     
00524     /* Send opcode */
00525     spi_transfer(AT45DB161D_RESUME_FROM_DEEP_POWER_DOWN);
00526     
00527     /* Resume device */
00528     DF_CS_inactive;
00529     
00530     /* The CS pin must stay high during t_RDPD microseconds before the device
00531      * can receive any commands.
00532      * On the at45db161D t_RDPD = 35 microseconds. But we will wait 100
00533      * (just to be sure). */
00534 //    delay(100);
00535     wait_ms(100);
00536 }
00537  
00538 /** **/