TRC 630401

Revision:
0:0b6c94a21953
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/at45db161e.cpp	Thu Apr 02 03:41:57 2020 +0000
@@ -0,0 +1,522 @@
+#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;
+}