Forked library from okini3939/at45db161d
Fork of at45db161d by
at45db161d.cpp
- Committer:
- okini3939
- Date:
- 2011-09-11
- Revision:
- 0:2e953bbaf3a5
- Child:
- 1:b379e16fdf6f
File content as of revision 0:2e953bbaf3a5:
/** * 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�ft care bits * - 12 page address bits (PA11 - PA0) that specify the page in * the main memory to be written * - 10 don�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�ft care bits * - 12 page address bits (PA11 - PA0) that specify the page in * the main memory to be written * - 10 don�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�ft care bits * - 12 page address bits (PA11 - PA0) that specify the page in * the main memory to be written * - 10 don�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�ft care bits * - 9 block address bits (PA11 - PA3) * - 13 don�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�ft care bits * - * - 12 don�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); } /** **/