TRC 630401
at45db161e.cpp
- Committer:
- supawat
- Date:
- 2020-04-02
- Revision:
- 0:0b6c94a21953
File content as of revision 0:0b6c94a21953:
#include "at45db161e.h" //extern Serial debug_pc; ATD45DB161E::ATD45DB161E(PinName mosi, PinName miso, PinName clk, PinName cs) : _spi(mosi, miso, clk), _cs(cs) {} ATD45DB161E::ATD45DB161E(SPI &spi, PinName cs) : _spi(spi), _cs(cs) {} /** Setup SPI **/ void ATD45DB161E::initial_chip(void) { _spi.format(8,0); _spi.frequency(16000000); _set_pageszie_to_binary(); _wake_flag = true; _deepsleep_flag = false; _udeepsleep_flag = false; } void ATD45DB161E::_select() { // ensure that the SPI port is set up correctly still // This allows SPI channel sharing _spi.format(8,0); _spi.frequency(16000000); _cs = 0; } /* * Deselect simply returns nCS to high */ void ATD45DB161E::_deselect() { _cs = 1; } /* * Sends the three lest significant bytes of the supplied address */ void ATD45DB161E::_sendaddr (unsigned int address) { _spi.write(address >> 16); _spi.write(address >> 8); _spi.write(address); } /** * Set page size of the flash chip into deep power down mode. **/ void ATD45DB161E::_set_pageszie_to_binary(void) { _pollbusy(); // make sure flash isn't already in busy. _select(); _spi.write(0x3d); _spi.write(0x2a); _spi.write(0x80); _spi.write(0xa6); _deselect(); _pollbusy(); // waitting for the operation complete. } /* * return the Status */ int ATD45DB161E::ReadStatusRegister(void) { int status = 0; _select(); _spi.write(0xd7); status = _spi.write(0x00); _deselect(); return status; } /* * Make sure the Flash isnt already doing something */ void ATD45DB161E::_pollbusy() { volatile int busy = 1; while (busy) { if(!_wake_flag) { if(_deepsleep_flag) DeepPowerDown(false); else if(_udeepsleep_flag) UltraDeepPowerDown(false); } // if bit 7 is set, we can proceed if ( ReadStatusRegister() & 0x80 ) { busy = 0;} } } void ATD45DB161E::pollbusy() { _pollbusy(); } /** * 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 ATD45DB161E::ReadManufacturerAndDeviceID(struct flash_id *id) { _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send status read command */ _spi.write(0x9f); /* Manufacturer ID */ id->manufacturer = _spi.write(0x00); /* Device ID (part 1) */ id->device[0] = _spi.write(0x00); /* Device ID (part 2) */ id->device[1] = _spi.write(0x00); /* Extended Device Information String Length */ id->extendedInfoLength = _spi.write(0x00); _deselect(); } /** * 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 * @param *data: Data buffer to be return the value in flash memory * @param len: Lenght of data that you want to read * Note: When the end of a page in main memory is reached, the device will continue reading back at the beginning of the same page. **/ void ATD45DB161E::PageRead(unsigned int page,unsigned int offset,unsigned char *data,unsigned int len) { unsigned int address,i; address = (page<<9)|offset; _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(0xd2); _sendaddr(address); // send three address byte /* 4 "don't care" bytes */ _spi.write(0x00); _spi.write(0x00); _spi.write(0x00); _spi.write(0x00); for(i=0;i<len;i++) { *data++ = _spi.write(0x00); } _deselect(); } /** * Continuous Array Read in low power mode. * Continuous Array Read in low power mode allows the user to read data * directly from any address 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 addr_st: Starting byte address within the main memory * @param *data: Data buffer to be return the value in flash memory * @param len: Lenght of data that you want to read * Note: When the end of a page in main memory is reached, the device will continue reading at the beginning of the next page with no delays incurred during the page boundary crossover. **/ void ATD45DB161E::ContinuousArrayRead(unsigned int addr_st,unsigned char *data,unsigned int len) { unsigned int i; _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(0x01); _sendaddr(addr_st); // send three address byte for(i=0;i<len;i++) { *data++ = _spi.write(0x00); } _deselect(); } /** * Erase the entire chip memory. Sectors proteced or locked down will * not be erased. **/ void ATD45DB161E::ChipErase(void) { _pollbusy(); // make sure flash isn't already in busy. // There are errata on this. For now, do itthe long way :-( _select(); // 4 byte command sequence _spi.write(0xc7); _spi.write(0x94); _spi.write(0x80); _spi.write(0x9a); _deselect(); _pollbusy(); // waiting for chip erase } /** * Erase a page in the main memory array. * @param page: Number of page that you want to erase **/ void ATD45DB161E::PageErase(unsigned int page) { unsigned int address; address = page<<9; _pollbusy(); // make sure flash isn't already in busy. // There are errata on this. For now, do itthe long way :-( _select(); _spi.write(0x81); // Command for page erase _sendaddr(address); // Send 3 address bytes _deselect(); _pollbusy(); // waiting for page erase } /** * This is a combination of Buffer Write and Buffer to Page with * Built-in Erase. * @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) * @param *data: Data that you want to write into flash memory * @param len: Lenght of data that you want to write * Note: If the end of the buffer is reached, the device will wrap around back to the beginning of the buffer. **/ void ATD45DB161E::PageWriteThroughBuffer(unsigned int page, unsigned int offset, unsigned char bufferNum,unsigned char *data,unsigned int len) { unsigned int address,i; unsigned char opcode; address = (page<<9)|offset; // select opcode which buffer have been used if (bufferNum == 1) opcode = 0x82; else opcode = 0x85; _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(opcode); /* Address */ _sendaddr(address); // send three address byte for(i=0;i<len;i++) { _spi.write(*data++); } _deselect(); _pollbusy(); // waiting for programming from buffer into main memory } /** * This is a combination of the Main Memory Page to Buffer Transfer, Buffer Write, * and Buffer to Main Memory Page Program with Built-in Erase commands. * @param addr_st Starting byte address of the flash chip * @param bufferNum Buffer to use (1 or 2) * @param *data: Data that you want to write into flash memory * @param len: Lenght of data that you want to write * Note: If the end of the buffer is reached, the device will wrap around back to the beginning of the buffer. **/ void ATD45DB161E::ContinuousWriteThroughBuffer(unsigned int addr_st, unsigned char bufferNum,unsigned char *data,unsigned int len) { unsigned int i,data_len; unsigned int page_start,page_end; unsigned int page_count,dif_page; unsigned char opcode; page_start = addr_st>>9; page_end = (addr_st+len)>>9; dif_page = page_end - page_start; // select opcode which buffer have been used if (bufferNum == 1) opcode = 0x58; else opcode = 0x59; for(page_count=0;page_count<=dif_page;page_count++) { if(512-(addr_st&0x1ff)<len) data_len = 512-(addr_st&0x1ff); else data_len = len; _pollbusy(); // make sure flash isn't already in busy. _select(); _spi.write(opcode); /* Send opcode */ _sendaddr(addr_st); // send three address byte for(i=0;i<data_len;i++) { _spi.write(*data++); } _deselect(); _pollbusy(); // waiting for programming from buffer into main memory addr_st = addr_st + data_len; len = len - data_len; } } /** * 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). * @param *data: Data that you want to read from flash memory * @param len: Lenght of data that you want to read **/ void ATD45DB161E::BufferRead(unsigned char bufferNum, unsigned int offset, unsigned char low,unsigned char *data,unsigned int len) { unsigned int i; unsigned char opcode; /* Send opcode */ if(bufferNum == 1) { if(low) opcode = 0xd1; // opcode for read buffer 1 in low speed else opcode = 0xd4; // opcode for read buffer 1 } else { if(low) opcode = 0xd3; // opcode for read buffer 1 in low speed else opcode = 0xd6; // opcode for read buffer 2 } _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(opcode); _sendaddr(offset); // send three address byte if(!low) _spi.write(0x00); // send dummy byte for(i=0;i<len;i++) { *data++ = _spi.write(0x00); } _deselect(); } /** * 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 * @param *data: Data that you want to write into flash memory * @param len: Lenght of data that you want to write **/ void ATD45DB161E::BufferWrite(unsigned char bufferNum, unsigned int offset,unsigned char *data,unsigned int len) { unsigned int i; unsigned char opcode; if (bufferNum == 1) opcode = 0x84; else opcode = 0x87; _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(opcode); _sendaddr(offset); // send three address byte for(i=0;i<len;i++) { _spi.write(*data++); } _deselect(); _pollbusy(); // waiting for operation complete. } /** * 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 ATD45DB161E::BufferToPage(unsigned char bufferNum, unsigned int page, unsigned char erase) { unsigned int address; unsigned char opcode; address = page<<9; if(erase) { if (bufferNum == 1) opcode = 0x83; else opcode = 0x86; } else { if (bufferNum == 1) opcode = 0x88; else opcode = 0x89; } _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(opcode); _sendaddr(address); // send three address byte _deselect(); _pollbusy(); // Wait for buffer write to main memory page } /** * Transfer data from main memory page to buffer 1 or 2. * @param page Page where the content of the main memory page will transfered * @param bufferNum Buffer to use (1 or 2) **/ void ATD45DB161E::PageToBuffer(unsigned int page, unsigned char bufferNum) { unsigned int address; unsigned char opcode; address = page<<9; if (bufferNum == 1) opcode = 0x53; else opcode = 0x55; _pollbusy(); // make sure flash isn't already in busy. _select(); /* Send opcode */ _spi.write(opcode); _sendaddr(address); // send three address byte _deselect(); _pollbusy(); // Wait for buffer write to main memory page } /** * Enter the chip into deep power down mode. * @param deep_down_onoff: If set the chip will be entered into deep power down mode. Otherwise, wake up command will be sent to the chip. **/ void ATD45DB161E::DeepPowerDown(unsigned char deep_down_onoff) { if(deep_down_onoff) { _pollbusy(); // make sure flash isn't already in busy. _select(); _spi.write(0xb9); _deselect(); _wake_flag = false; _deepsleep_flag = true; wait_us(2); } else { _select(); _spi.write(0xab); _deselect(); _wake_flag = true; _deepsleep_flag = false; wait_us(35); } } /** * Enter the chip into ultra deep power down mode. * @param ultra_deep_down_onoff: If set the chip will be entered into ultra deep power down mode. Otherwise, CS pin will be asseeted for wake up the chip. **/ void ATD45DB161E::UltraDeepPowerDown(unsigned char ultra_deep_down_onoff) { if(ultra_deep_down_onoff) { _pollbusy(); // make sure flash isn't already in busy. _select(); _spi.write(0x79); _deselect(); _wake_flag = false; _udeepsleep_flag = true; wait_us(4); } else { _select(); wait_us(1); _deselect(); wait_us(180); _wake_flag = true; _udeepsleep_flag = false; } } /** * Check the chip is wake up. * Return true if the chip is wake up. Otherwise, the chip is entered in deep power down or ultra deep power down mode mode. **/ bool ATD45DB161E::is_it_awake(void) { return _wake_flag; }