TRC 630401
Revision 0:0b6c94a21953, committed 2020-04-02
- Comitter:
- supawat
- Date:
- Thu Apr 02 03:41:57 2020 +0000
- Commit message:
- VMS3GTRC vers. 630401
Changed in this revision
at45db161e.cpp | Show annotated file Show diff for this revision Revisions of this file |
at45db161e.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 0b6c94a21953 at45db161e.cpp --- /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; +}
diff -r 000000000000 -r 0b6c94a21953 at45db161e.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/at45db161e.h Thu Apr 02 03:41:57 2020 +0000 @@ -0,0 +1,75 @@ +/** + * @file at45db161e.h + * @brief AT45DB161E module + **/ +#ifndef AT45DB161E_H +#define AT45DB161E_H + +#include "mbed.h" + +/** + * @brief ID structure + * This structure contains various informations about the + * dataflash chip being used. + **/ + struct flash_id + { + unsigned char manufacturer; /**< Manufacturer id **/ + unsigned char device[1]; /**< Device id **/ + unsigned char extendedInfoLength; /**< Extended device information string length **/ + }; + +class ATD45DB161E +{ + + // Public functions + public: + + ATD45DB161E(PinName mosi, PinName miso, PinName clk, PinName cs); + ATD45DB161E(SPI &spi, PinName cs); + + void initial_chip(void); + void pollbusy (void); + int ReadStatusRegister(void); + void ReadManufacturerAndDeviceID(struct flash_id *id); + + void PageRead(unsigned int,unsigned int,unsigned char *,unsigned int); + void ContinuousArrayRead(unsigned int,unsigned char *,unsigned int); + + void ChipErase(void); + void PageErase(unsigned int); + + void PageWriteThroughBuffer(unsigned int, unsigned int, unsigned char ,unsigned char *,unsigned int); + void ContinuousWriteThroughBuffer(unsigned int, unsigned char ,unsigned char *,unsigned int); + + void BufferRead(unsigned char, unsigned int, unsigned char, unsigned char *, unsigned int); + void BufferWrite(unsigned char, unsigned,unsigned char *,unsigned int); + void BufferToPage(unsigned char, unsigned int, unsigned char); + void PageToBuffer(unsigned int, unsigned char); + + void DeepPowerDown(unsigned char); + void UltraDeepPowerDown(unsigned char); + bool is_it_awake(void); + + // Private variables + private: + SPI _spi; + DigitalOut _cs; + bool _wake_flag; + bool _deepsleep_flag; + bool _udeepsleep_flag; + + void _set_pageszie_to_binary(void); + void _select(); + void _deselect(); + void _pollbusy (void); + + // Send 3 byte address + void _sendaddr (unsigned int address); +}; + +/** + * @} + **/ + +#endif /* AT45DB161E_H */