I have found a few old EEPROM chips marked as 93C46N (DIP8):
It has only 128 bytes (to be exact 64 words), but it has serious advantage - more than 1 000 000 erase/write cycles, so I'm planning to utilize them for daily recording of some of my devices' indications.
93C46 is serial EEPROM which means it may be accessed via Arduino SPI.
Take a look at the datasheet and wire it up with your Arduino properly:
LED has been added to the circuit to indicate data transmission process and bypass capacitor wired up in order to reduce voltage swing.
Code:
1 // 2 // LED <--> Arduino: 3 // Anode <--> Digital 8 (via 220 Ohm resistor) 4 // Cathode <--> GND 5 // 6 // 93C46 <--> Arduino: 7 // CS <--> Digital 53 (SS) 8 // SCK <--> Digital 52 (SCK) 9 // DI <--> Digital 51 (MOSI) 10 // DO <--> Digital 50 (MISO) 11 // VCC <--> 5V 12 // GND <--> GND 13 // 14 15 #include <avr/io.h> 16 #include <util/delay.h> 17 18 #define CLEAN 0b00000000 19 20 #define DDR93C46 DDRB 21 #define PORT93C46 PORTB 22 #define PIN93C46 PINB 23 24 #define SK PB1 //SCK - Digital 52 25 #define DO PB3 //MISO - Digital 50 26 #define DI PB2 //MOSI - Digital 51 27 #define CS PB0 //SS - Digital 53 28 29 #define READ 0x02 // 10 00ABCD - 0x02 ADDR 30 #define EWEN1 0x00 // 00 11XXXX 31 #define EWEN2 0x30 // - 0x00 0x30 32 #define ERASE 0x03 // 11 00ABCD - 0x03 ADDR 33 #define ERAL1 0x00 // 00 10XXXX 34 #define ERAL2 0x20 // - 0x00 0x20 35 #define WRITE 0x01 // 01 00ABCD - 0x01 ADDR 36 #define WRAL1 0x00 // 00 01XXXX 37 #define WRAL2 0x10 // - 0x00 0x10 38 #define EWDS1 0x00 // 00 00XXXX 39 #define EWDS2 0x00 // - 0x00 0x00 40 41 #define SET_CS PORT93C46 |= (1 << CS) 42 #define CLR_CS PORT93C46 &= ~(1 << CS) 43 44 #define SET_SK {PORT93C46 |= (1 << SK); _delay_us(0.01);} 45 #define CLR_SK PORT93C46 &= ~(1 << SK) 46 47 #define SET_DI PORT93C46 |= (1 << DI) 48 #define CLR_DI PORT93C46 &= ~(1 << DI) 49 50 class SPI_93C46N { 51 private: 52 uint8_t Transfer(uint8_t data) { 53 SPDR = data; 54 while(!(SPSR & (1 << SPIF))); // Wait for SPI interrupt flag 55 return SPDR; // Return byte gathered from SPI data register 56 } 57 void Opcode(uint8_t opcode, uint8_t address) { 58 SET_CS; 59 SPCR &= ~(1 << SPE); // SPI disable 60 _delay_us(1); 61 CLR_SK; 62 SET_DI; // Send start bit 63 SET_SK; 64 CLR_SK; 65 SPCR |= (1 << SPE); // SPI enable 66 Transfer((opcode << 6) | address); // Transmit byte 67 } 68 public: 69 SPI_93C46N() { 70 SPCR = CLEAN // Set SPI control register 71 & ~(1 << SPIE) // SPI interrupt disable 72 | (1 << SPE) // SPI enable 73 & ~(1 << DORD) // MSB first 74 | (1 << MSTR) // SPI master device 75 & ~(1 << CPOL) // SPI 76 & ~(1 << CPHA) // mode 0 77 | (1 << SPR1) // XX/64 MHz 78 & ~(1 << SPR0); // speed 79 SPSR = CLEAN // Init SPI status register 80 & ~(1 << SPI2X); // SPI double speed 81 DDR93C46 = CLEAN // Set up inputs/outputs 82 | (1 << SK) // Serial clock output 83 | (1 << DI) // Data input (MOSI) output 84 | (1 << CS) // Chip select output 85 & ~(1 << DO); // Data output (MISO) input 86 PORT93C46 |= (1 << DO); // Data output (MISO) high 87 CLR_DI; 88 CLR_CS; 89 CLR_SK; 90 _delay_us(1); 91 } 92 ~SPI_93C46N() { 93 // 94 } 95 uint16_t Read(uint8_t address) { 96 uint16_t data = 0; 97 Opcode(READ, address); // READ instruction 98 CLR_DI; 99 SET_SK; // "0" DUMMY bit 100 CLR_SK; 101 SPCR |= (1 << CPHA); // Invert PHA, very important! 102 data = Transfer(0); 103 data = (data << 8) | (Transfer(0)); 104 _delay_us(1); 105 CLR_CS; 106 CLR_DI; 107 SPCR &= ~(1 << CPHA); 108 return data; 109 } 110 void EraseWriteEnable(void) { 111 Opcode(EWEN1, EWEN2); 112 CLR_DI; 113 CLR_CS; 114 SET_CS; 115 _delay_us(0.1); 116 while(!(PIN93C46 & (1 << DO))); // Wait 1 117 CLR_CS; 118 } 119 void EraseWriteDisable(void) { 120 Opcode(EWDS1, EWDS2); 121 CLR_DI; 122 CLR_CS; 123 SET_CS; 124 _delay_us(0.1); 125 while(!(PIN93C46 & (1 << DO))); // Wait 1 126 CLR_CS; 127 } 128 void Erase(uint8_t address) { 129 Opcode(ERASE, address); 130 CLR_DI; 131 CLR_CS; 132 SET_CS; 133 _delay_us(0.1); 134 while(!(PIN93C46 & (1 << DO))); // Wait 1 135 CLR_CS; 136 } 137 void EraseAll(void) { 138 Opcode(ERAL1, ERAL2); 139 CLR_DI; 140 CLR_CS; 141 SET_CS; 142 _delay_us(0.1); 143 while(!(PIN93C46 & (1 << DO))); // Wait 1 144 CLR_CS; 145 } 146 void Write(uint8_t address, uint16_t data) { 147 Opcode(WRITE, address); // WRITE instruction 148 Transfer(data >> 8); // Write data high byte to addreCS 149 Transfer(data & 0xFF); // Write data low byte to addreCS 150 CLR_DI; 151 CLR_CS; 152 SET_CS; 153 _delay_us(0.1); 154 while(!(PIN93C46 & (1 << DO))); // Wait "1" 155 CLR_CS; 156 } 157 void WriteAll(uint16_t data) { 158 Opcode(WRAL1, WRAL2); // WRITE instruction 159 Transfer(data >> 8); // Write data high byte to addreCS 160 Transfer(data & 0xFF); // Write data low byte to addreCS 161 CLR_DI; 162 CLR_CS; 163 SET_CS; 164 _delay_us(0.1); 165 while(!(PIN93C46 & (1 << DO))); // Wait "1" 166 CLR_CS; 167 } 168 }; 169 170 void setup(void) { 171 Serial.begin(115200); 172 _delay_ms(100); 173 Serial.println("EEPROM writing/reading"); 174 pinMode(8, OUTPUT); 175 } 176 177 void loop(void) { 178 SPI_93C46N _93C46N; 179 int i; 180 uint16_t data; 181 _93C46N.EraseWriteEnable(); 182 // for(i = 0; i < 32; i++) 183 // _93C46N.Write(i, 0xDEAD); 184 // for(i = 32; i < 64; i++) 185 // _93C46N.Write(i, 0xBEEF); 186 _93C46N.WriteAll(0xB00B); 187 _93C46N.EraseWriteDisable(); 188 for(i = 0; i < 64; i++) { 189 data = _93C46N.Read(i); 190 analogWrite(8, (unsigned char)(data >> 8)); 191 _delay_ms(50); 192 analogWrite(8, (unsigned char)data); 193 _delay_ms(50); 194 Serial.print(data, HEX); 195 Serial.print(" "); 196 if((i + 1) % 8 == 0) 197 Serial.println(); 198 } 199 analogWrite(8, 0); 200 _delay_ms(10000); 201 }