{"id":22063,"date":"2018-01-14T21:40:26","date_gmt":"2018-01-14T14:40:26","guid":{"rendered":"http:\/\/tom.ji42.com\/?p=22063"},"modified":"2020-11-09T07:25:10","modified_gmt":"2020-11-09T00:25:10","slug":"adding-external-i2c-eeprom-to-arduino-24lc256","status":"publish","type":"post","link":"https:\/\/tom.tomwork.net\/?p=22063","title":{"rendered":"Adding External I2C EEPROM to Arduino (24LC256)"},"content":{"rendered":"<p>This tutorial was originally posted on the 10kohms.com website, which now seems to be no longer with us, so we have reproduced it here.<\/p>\n<p>In my last post I discussed using the built in EEPROM to store permanent data on the Arduino. All though this is a very easy and effective way of storing data on the Arduino the built in EEPROM only offers 512 bytes of storage. When working with larger or more advanced Arduino projects we may need to store additional data so an external memory solution like the 24LC256 I\u00b2C EEPROM IC becomes necessary.<\/p>\n<p class=\"info\">We\u2019re using a 256kbit eeprom which is actually 32kbytes of space. 262,144 bits \/ 8 bits in a byte = 32,768 bytes. That\u2019s 62 times the Arduino\u2019s built-in storage!<\/p>\n<p><!--more--><\/p>\n<p><strong>Hardware Setup<\/strong><\/p>\n<p class=\"info\">In this example we\u2019ll be using the Microchip 24LC256 IC. If you\u2019re using a different IC please confirm that the pin-out and power requirements are the same so you don\u2019t damage your chip.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.hobbytronics.co.uk\/image\/data\/tutorial\/arduino-24lc256-eeprom\/17230_PV.jpg\" alt=\"eeprom\" \/><img decoding=\"async\" src=\"http:\/\/www.hobbytronics.co.uk\/image\/data\/tutorial\/arduino-24lc256-eeprom\/pinout-24LC256.png\" alt=\"eeprom\" \/><\/p>\n<p>The Microchip 24LC256 chip can be purchased in a 8 pin DIP package. The pins on the 24LC256 are pretty straightforward and consist of power(8), gnd(4), write protection(7), SCL\/SDA(6,5), and three address pins(1,2,3). Before we get into the software part lets hook up the 24LC256 chip up to our Arduino.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.hobbytronics.co.uk\/image\/data\/tutorial\/arduino-24lc256-eeprom\/24LC256-1.jpg\" alt=\"eeprom\" width=\"500\" \/><\/p>\n<p>Using the image above as a guide lets begin to wire the chip. First connect GND and VCC, pins 4 and 8 respectivly. Next lets go ahead and connect the data pins to the Arduino board. Since we\u2019re using the Arduino I\u00b2C bus we\u2019re going to be using\u00a0<strong>Analog<\/strong>\u00a0pins 4 and 5. Connect the SDA pin on the 24LC256(pin 5) to the pin 4 of the Arduino. Then connect the SCL(pin 6) to pin 5 on the Arduino. Double check that you\u2019ve connected the correct pins on the 24LC256 to the correct pins on the Arduino; strange things will happen if you have them reversed. After our data and power pins are connected we have four left on 24LC256 chip, the WP pin and the three address pins. The WP pin stands for write-protected and this allows you to control if data can be written to the eeprom or not. If this pin is low then writing is enabled but if it\u2019s high then writing is disable; reading is always enabled. For the purpose of this tutorial we\u2019re going to be writing to the eeprom so we can connect the WP pin to GND.<\/p>\n<p>The last three pins set the address of the 24LC256 chip which allows us to target a particular chip on the I\u00b2C bus. This particular I\u00b2C chip comes pre-wired with four bits of it\u2019s address already set(1010) and these can not be changed. The last three bits of the address however can be changed which allows us to run up to eight 24LC256 chips on the same I\u00b2C bus. This is a little confusing at first so lets look at the figure below to explain the address in a little more detail.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/www.hobbytronics.co.uk\/image\/data\/tutorial\/arduino-24lc256-eeprom\/24LC256-address.png\" alt=\"\" \/><\/p>\n<p>For the purpose of explaining how the address works we can ignore the Start and Acknowledge bits. The way the I\u00b2C bus works is a 7-bit address is passed along with a read\/write bit that tells the chip if it should write the incoming data or read it and send it back. The Arduino takes care of the last R\/W bit for us depending on what function we\u2019re using so as long as you\u2019re using the standard Arduino Wire library we don\u2019t have to worry about this bit. This leaves us with the seven middle bits and as I mentioned above the first four bits(Control Code) are hard-wired and we can\u2019t change these. The next three bits(A2,A1,A0) are the important bits that we can change so lets look at the simple table below to see what address the chip will have depending on what we set these pins to.<\/p>\n<p>So, if we were to tie pins 1,2 and 3 on the 24LC256 to GND then the chip would have address 0\u00d750 and if were to assign them all Vcc then the chip would have address 0\u00d757 and every combination in between. To keep things simple lets just tie all pins to GND to make the address 0\u00d750. In a future tutorial I will show you how to use multiple eeprom chips off the same I\u00b2C at which point we will be assigning each chip a different address but for now lets stick with 0\u00d750. With the address pins connected the hardware part of this tutorial is complete and every pin of the 24LC256 should be connected to either Vcc, GND or the Arduino. Time to move on to software!<\/p>\n<p class=\"info\">It\u2019s been brought to my attention that some people use pull-up resistors on the data and clock pins to the Arduino. All though this would not hurt the circuit it\u2019s not needed because when the Wire.h library is initialized it knows pins 4 and 5 are going to be used for I\u00b2C so it also activates the built-in pull-up resistors. For more information please read\u00a0http:\/\/www.arduino.cc\/en\/Reference\/Wire.<\/p>\n<p><strong>Arduino Sketch<\/strong><\/p>\n<p>Below is the entire tutorial code, scan over it and see if you understand it before I dive into what each section does.<\/p>\n<p>Note: This is written for Arduino versions before 1.0. If you are using Arduino 1.0 and above then you need to change\u00a0<strong>Wire.send<\/strong>\u00a0to\u00a0<strong>Wire.write<\/strong>\u00a0and\u00a0<strong>Wire.receive<\/strong>\u00a0to\u00a0<strong>Wire.read<\/strong><\/p>\n<pre>#include\u00a0&lt;Wire.h&gt;    \r\n\u00a0\r\n#define\u00a0disk1\u00a00x50\u00a0\u00a0\u00a0\u00a0\/\/Address of 24LC256 eeprom chip\r\n\u00a0\r\nvoid <b>setup<\/b>(void)\r\n{\r\n\u00a0\u00a0<b>Serial<\/b>.begin(9600);\r\n\u00a0\u00a0Wire.begin();  \r\n\u00a0\r\n\u00a0\u00a0unsigned int address = 0;\r\n\u00a0\r\n\u00a0\u00a0writeEEPROM(disk1,\u00a0address,\u00a0123);\r\n\u00a0\u00a0<b>Serial<\/b>.print(readEEPROM(disk1, address), DEC);\r\n}\r\n\u00a0\r\nvoid <b>loop<\/b>(){}\r\n\u00a0\r\nvoid writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) \r\n{\r\n\u00a0\u00a0Wire.beginTransmission(deviceaddress);\r\n\u00a0\u00a0Wire.send((int)(eeaddress &gt;&gt; 8));   \/\/ MSB\r\n\u00a0\u00a0Wire.send((int)(eeaddress &amp; 0xFF)); \/\/ LSB\r\n\u00a0\u00a0Wire.send(data);\r\n\u00a0\u00a0Wire.endTransmission();\r\n\u00a0\r\n\u00a0\u00a0delay(5);\r\n}\r\n\u00a0\r\nbyte readEEPROM(int deviceaddress, unsigned int eeaddress ) \r\n{\r\n\u00a0\u00a0byte rdata = 0xFF;\r\n\u00a0\r\n\u00a0\u00a0Wire.beginTransmission(deviceaddress);\r\n\u00a0\u00a0Wire.send((int)(eeaddress &gt;&gt; 8));   \/\/ MSB\r\n\u00a0\u00a0Wire.send((int)(eeaddress &amp; 0xFF)); \/\/ LSB\r\n\u00a0\u00a0Wire.endTransmission();\r\n\u00a0\r\n\u00a0\u00a0Wire.requestFrom(deviceaddress,1);\r\n\u00a0\r\n\u00a0\u00a0if (Wire.available()) rdata = Wire.receive();\r\n\u00a0\r\n\u00a0\u00a0return rdata;\r\n}\r\n\r\n<\/pre>\n<p>In order to use the I\u00b2C interface we need to include the Arduino standard Wire library so first things first, include Wire.h at the top of the sketch. You\u2019ll notice directly after the include we define a variable called disk1 and assign it a hex value of 0\u00d750. When we setup the chip above we set the address of the chip to 0\u00d750 by tying all the address pins to GNS so we simple set this variable to that address which allows us to access the chip from within our sketch. This variable is not required but it allows us to easily change the address we want to access without going through all of the code and replacing the value. Also, if you plan on adding more than one chip it\u2019s easier to refer to them as disk1, disk2, etc rather than 0\u00d750, 0\u00d751 which might get confusing.<\/p>\n<p>Moving on we have our standard setup and a loop functions, for this tutorial the loop function is left empty so we\u2019ll just focus on the setup function. We first initialize our Serial connection for printing back to the computer and then we initiate the I\u00b2C connection by calling Wire.begin(). This enables pins 4 and 5 for I\u00b2C and also enabled the internal pull-up resistor(See note above). Next we create a new variable to store the address of the eeprom we want to write to(not the address of the eeprom IC itself but the address of the byte we want to read\/write to). Since this eeprom has 32Kbytes of storage this address can be any number between 0 and 32,767; we\u2019ll start with address 0. After we\u2019ve initialized everything we call our two primary functions, writeEEPROM and readEEPROM which actually do the dirty work of writing and reading the bytes of data.<\/p>\n<p>Lets first start off with the writeEEPROM function. This function takes three arguments, the device address(the disk1 variable), the memory address on the eeprom and the byte of data you want to write. The first argument is the address of the device you want to write to, in our case we only have one device(disk1) so we pass this on. The next argument is the address on the eeprom you want to write to and as stated above can be between 0 and 32,767. Finally we have to pass along the byte we want to store. So, writeEEPROM(disk1, address, 123) is going to write the decimal 123 to \u201caddress\u201d(which is 0) on disk1(0\u00d750). Lets jump into the actual writeEEPROM function to learn what it does.<\/p>\n<pre>void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) \r\n{\r\n\u00a0\u00a0Wire.beginTransmission(deviceaddress);\r\n\u00a0\u00a0Wire.send((int)(eeaddress &gt;&gt; 8));   \/\/ MSB\r\n\u00a0\u00a0Wire.send((int)(eeaddress &amp; 0xFF)); \/\/ LSB\r\n\u00a0\u00a0Wire.send(data);\r\n\u00a0\u00a0Wire.endTransmission();\r\n\u00a0\r\n\u00a0\u00a0delay(5);\r\n}<\/pre>\n<p>We first call the Wire.beginTransmission function which sends the deviceaddress to let the chip know we want to communicate with it. Next we have to send the address on the eeprom we want to write to. Since our eeprom chip has 32,000 address locations we are using two bytes(16 bits) to store the address but we can only send one byte at a time so we have to split it up. The first send function takes the eeaddress and shifts the bits to the right by eight which moves the higher end of the 16 bit address down to the lower eight bits. Next we do a bitwise AND to get just the last eight bits. To illustrate this lets follow the steps below.<\/p>\n<p>Lets say we want to write to address location 20,000 which is 0100 1110 0010 0000 in binary. We need to send the MSB(Most significant bits) first so we have to shift our address to the right eight bits.<\/p>\n<p>0100 1110 0010 0000 (eeaddress)<br \/>\nAfter shifting 8 bits to the right we have<br \/>\n0100 1110<\/p>\n<p>We now have the first half of the address, time to get the second half:<\/p>\n<p>0100 1110 0010 0000 (eeaddress)<br \/>\nAfter we bitwise AND 0xFF with eeadddress we get<br \/>\n0010 0000<\/p>\n<p>This means our 24LC256 chip gets the address 1001 1100 and then 0010 0000 which tells it to store the next byte in address location 20,000. Now that we\u2019ve sent the address we send the data and then we end the process by calling the endTransmission function. The 24LC256 gets the data and writes the data to that address location. To finish up this function you\u2019ll notice I\u2019ve included a delay of 5 milliseconds. This allows the chip time to complete the write operation, without this if you try to do sequential writes weird things might happen.<\/p>\n<p>Now that you\u2019re data has been stored it\u2019s time to get it back, lets examine the readEEPROM function.<\/p>\n<pre>byte readEEPROM(int deviceaddress, unsigned int eeaddress ) \r\n{\r\n\u00a0\u00a0byte rdata = 0xFF;\r\n\u00a0\r\n\u00a0\u00a0Wire.beginTransmission(deviceaddress);\r\n\u00a0\u00a0Wire.send((int)(eeaddress &gt;&gt; 8));   \/\/ MSB\r\n\u00a0\u00a0Wire.send((int)(eeaddress &amp; 0xFF)); \/\/ LSB\r\n\u00a0\u00a0Wire.endTransmission();\r\n\u00a0\r\n\u00a0\u00a0Wire.requestFrom(deviceaddress,1);\r\n\u00a0\r\n\u00a0\u00a0if (Wire.available()) rdata = Wire.receive();\r\n\u00a0\r\n\u00a0\u00a0return rdata;\r\n}<\/pre>\n<p>The readEEPROM accepts two arguments and returns on byte(the data). The arguments it accepts are the same first two arguments the write function, the device address and the address on the eeprom to read from. First we declare a variable to store the byte we\u2019re going to retrieve. Next we start off just like we did with the write function by starting the process with beginTransmission and then we send the address we want to access; this works exactly the same way as the write function. Continuing on we end the the transmission and we\u2019ve now set the 24LC256 with the address we\u2019re interested in so now we just have to request and read the data. The next function requestFrom() sends the command to that chip to start sending the data at the address we set above. The second argument is how many bytes(starting at this address) to send back; we\u2019re only requesting one. Finally we check to see if there is data available on the I\u00b2C bus and if there is we read it into the rdata variable. We return the byte of data and we\u2019re done!<\/p>\n<p>That\u2019s all you really need to know in order to use and external I\u00b2C EEPROM chip with the Arduino. Take this setup and play around with it, see if you can figure out how to store more than one byte at a time or if you want a challenge try using more than one 24LC256 on the same I\u00b2C bus.<\/p>\n<p><strong>See also<br \/>\n<\/strong><\/p>\n<p><a title=\"Eeprom Page Write (Writing long strings to 24LC256)\" href=\"http:\/\/www.hobbytronics.co.uk\/eeprom-page-write\">Eeprom Page Write (Writing long strings to 24LC256)<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial was originally posted on the 10kohms.com website, which now seems to be no longer with us, so we have reproduced it here. In my last post I discussed using the built in EEPROM to store permanent data on the Arduino. All though this is a very easy and effective way of storing data [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[13],"tags":[],"class_list":["post-22063","post","type-post","status-publish","format-standard","hentry","category-13"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6cOVM-5JR","_links":{"self":[{"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/posts\/22063","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=22063"}],"version-history":[{"count":2,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/posts\/22063\/revisions"}],"predecessor-version":[{"id":25291,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=\/wp\/v2\/posts\/22063\/revisions\/25291"}],"wp:attachment":[{"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=22063"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=22063"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tom.tomwork.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=22063"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}