16Mb Flash
The AT45DB161D is a serial interface flash memory chip, that can hold a lot of those 1 and 0's we are so fond of.
Specifically about 16 mega bits worth. Because the chip is a SOIC wide format, the Sparkfun adapter is a bit tight.
Although all the I/O lines are 5 volt tolerant, the chip still needs a 3.3 volt supply.
Datasheet
More stuff
Library
Now the cool part is where my LD33V voltage regulator can fit right across three of the pins:
Blue pin 1 --> Gnd pin 7
3.3 v pin 2 --> VCC pin 6
Yellow pin 3 --> WP pin 5
So your saying that I should put some sort of filtering capacitor on the output of my voltage regulator? Well
yes, I should but I don't want my little silicone friends to get all soft and start crying every time a little ripple
comes their way. I want them to be tough as nails and smoking from time to time. Just trying to weed out
the weak chips is all.
By the way I left the really hard part of the code to somebody else. I think I found the library here.
Two application defined subroutines (pack_and_write_record and read_and_unpack_record) combine all the custom fields into a record (dat) that will ultimately be written to the flash. Then the generic subroutines (write record and read_record) get the record to and from the device.
The other sweet thing about this code is it will flush the 528 byte buffer to the main memory page only when the next record should be written to a different main memory page. This allows you to continuously or randomly write records while keeping main memory writes to a minimum (maximizing longevity). One down side to this design is the waste of space because a record can not span two pages. The bits wasted is calculated by (528 mod record size) * 4095. From then on your code can deal with simple record numbers without fiddling with pages, buffers and what not.
Care should be taken not to "burn up" your chip by needlessly writing to it. Also because of the way I flush the buffer only when I have too, you need to force the last buffer flush by reading a different page before powering off.
extern "C" { #include "at45db161d.h" } // defines for splitting the unsigned long int into bytes for storage: #define HIGHBYTELONG(x) ((byte)((x) >> 24)) #define LOWBYTELONG(x) ((byte)((x) >> 16)) #define HIGHBYTE(x) ((byte)((x) >> 8)) #define LOWBYTE(x) ((byte)((x) & 0x00ff)) #define WORD(x,y) (( ((byte)(x)) << 8) | ((byte)(y))) #define MAX_PAGE_SIZE 528 #define MAX_PAGES 4096 byte dat[11]; unsigned int record_len = sizeof(dat); unsigned int records_per_page = MAX_PAGE_SIZE / record_len; unsigned long max_records = (long)MAX_PAGES * (long)records_per_page; unsigned int current_page = 0; unsigned int buffer_flushed = 1; ATD45DB161D dataflash; /////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { uint8_t status; ATD45DB161D::ID id; delay(3000); // Allow time to press the serial monitor button. dataflash.Init(); // Initialize dataflash //dataflash.ChipErase(); // Clean the chip off every 10,000 writes delay(10); status = dataflash.ReadStatusRegister(); // Read status register dataflash.ReadManufacturerAndDeviceID(&id); // Read manufacturer and device ID pinMode(2, INPUT); Serial.begin(115200); // Set baud rate for serial communication // Display status register Serial.print("Status register: "); Serial.println(status, BIN); // Display manufacturer and device ID Serial.print("Manufacturer ID: "); // Should be 00011111 Serial.println(id.manufacturer, HEX); Serial.print("Device ID (part 1): "); // Should be 00011111 Serial.println(id.device[0], HEX); Serial.print("Device ID (part 2): "); // Should be 00000000 Serial.println(id.device[1], HEX); Serial.print("Extended Device Information String Length: "); // 00000000 Serial.println(id.extendedInfoLength, HEX); Serial.print("records_per_page: "); Serial.println(records_per_page); Serial.print("max_records: "); Serial.println(max_records); Serial.println("--------------------------------------"); } /////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { if (digitalRead(2) == HIGH) { pack_and_write_record(47, millis(), 53, 11, "ABCD"); pack_and_write_record(48, millis(), 64, 22, "EFGH"); pack_and_write_record(49, millis(), 75, -33, "IJKL"); pack_and_write_record(4300, millis(), 86, 44, "MNOP"); } Serial.println("--------------------------------------"); read_and_unpack_record(47); read_and_unpack_record(48); read_and_unpack_record(49); read_and_unpack_record(4300); delay(60000); } /////////////////////////////////////////////////////////////////////////////////////////////////////// void read_record(unsigned long record) { unsigned int i; unsigned int requested_page = record / records_per_page; unsigned int record_offset = (record % records_per_page) * record_len; Serial.print("Read_record "); Serial.print(record); if (! buffer_flushed) { // Transfer buffer 1 to current_page (with builtin erase) dataflash.BufferToPage(1, current_page, 1); buffer_flushed = 1; Serial.print(" after flushing page "); Serial.print(current_page); } dataflash.ReadMainMemoryPage(requested_page, record_offset); for (i=0; i dat[i] = spi_transfer(0xff); } Serial.println(); } /////////////////////////////////////////////////////////////////////////////////////////////////////// void write_record(unsigned long record) { unsigned int i; unsigned int requested_page = record / records_per_page; unsigned int record_offset = (record % records_per_page) * record_len; Serial.print("Write_record "); Serial.print(record); Serial.print(" to page "); Serial.print(requested_page); if (current_page != requested_page) { if (! buffer_flushed) { // Transfer buffer 1 to current_page (with builtin erase) dataflash.BufferToPage(1, current_page, 1); buffer_flushed = 1; Serial.print(" after flushing page "); Serial.print(current_page); } dataflash.PageToBuffer(requested_page, 1); dataflash.BufferRead(1, 0, 1); current_page = requested_page; } // Set dataflash so that any call to spi_tranfer will write the byte // given as argument to the Buffer 1, offset by record_offset dataflash.BufferWrite(1, record_offset); buffer_flushed = 0; // Transfer the message for(i=0; i spi_transfer(dat[i]); } Serial.println(); } /////////////////////////////////////////////////////////////////////////////////////////////////////// void pack_and_write_record(unsigned long record, unsigned long time, unsigned int val1, int val2, char* str1) { unsigned int i; dat[0]=(HIGHBYTELONG(time)); dat[1]=(LOWBYTELONG(time)); dat[2]=(HIGHBYTE(time)); dat[3]=(LOWBYTE(time)); dat[4]=(HIGHBYTE(val1)); dat[5]=(LOWBYTE(val1)); dat[6]=(HIGHBYTE(val2)); dat[7]=(LOWBYTE(val2)); for (i=0; i<3; i++) { dat[i+8] = str1[i]; } write_record(record); } /////////////////////////////////////////////////////////////////////////////////////////////////////// void read_and_unpack_record(unsigned long record) { //unsigned int i; unsigned long mytime; unsigned long myulong; unsigned int myuint; int myint; char mystr[4]; read_record(record); mytime = (dat[0] << 8) | (dat[1] << 8) | (dat[2] << 8) | (dat[3] ); myuint = (dat[4] << 8) | dat[5]; myint = (dat[6] << 8) | dat[7]; mystr[0] = dat[8]; mystr[1] = dat[9]; mystr[2] = dat[10]; mystr[3] = '\\0'; Serial.print("millis: "); Serial.println(mytime); Serial.print("myuint: "); Serial.println(myuint); Serial.print("myint: "); Serial.println(myint); Serial.print("mystr: "); Serial.println(mystr); Serial.println("--------------------------------------"); delay(5); // Add a little delay otherwise the display will be too fast } ///////////////////////////////////////////////////////////////////////////////////////////////////////
Example Output:
Status register: 10101100 Manufacturer ID: 1F Device ID (part 1): 26 Device ID (part 2): 0 Extended Device Information String Length: 0 records_per_page: 48 max_records: 196608 -------------------------------------- Write_record 47 to page 0 Write_record 48 to page 1 after flushing page 0 Write_record 49 to page 1 Write_record 4300 to page 89 after flushing page 1 -------------------------------------- Read_record 47 after flushing page 89 millis: 3032 myuint: 53 myint: 11 mystr: ABC -------------------------------------- Read_record 48 millis: 3034 myuint: 64 myint: 22 mystr: EFG -------------------------------------- Read_record 49 millis: 3048 myuint: 75 myint: -33 mystr: IJK -------------------------------------- Read_record 4300 millis: 3050 myuint: 86 myint: 44 mystr: MNO --------------------------------------
created: Dec. 1, 2013, 1:01 a.m.
modified: April 13, 2019, 5:10 p.m.