user69478: I have been trying to program an AT24C16 EEPROM and have set up a circuit as per the attached image.

I have been using the following Arduino code:
#include <Wire.h>    
 
#define disk1 0x50    //Address of 24LC256 eeprom chip
 
void setup(void)
{
  Serial.begin(9600);
  Wire.begin();  
 
  unsigned int address = 10;
 
  writeEEPROM(disk1, address, 72);
  Serial.println(readEEPROM(disk1, address), DEC);
}
 
void loop(){}
 
void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Serial.println(Wire.endTransmission());
 
  delay(5);
}
 
byte readEEPROM(int deviceaddress, unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
  
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Serial.println(Wire.endTransmission());
 
  Wire.requestFrom(deviceaddress,1);
 
  if (Wire.available()) rdata = Wire.read();
 
  return rdata;
}

Unfortunately I only ever receive '255' in the serial monitor suggesting that no data has been written.
The code was from this tutorial which explains how the wiring on pins 1-3 governs the address of the chip.

user70020: Well, I think I see part of what is happening.  I'm not sure to what degree this is an Arduino problem, but it may be of some use to someone wanting to interface this chip with an Arduino.  So, here's what I see:
You're writing to the chip just fine so far as I2C is concerned.  But the content of what you're writing is not exactly correct to the chip itself.
You have:
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8));   // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB

Which is intuitive, but unfortunately not how the AT24C16 apparently works.   To be clear, the tutorial you've referenced uses the 24LC256, which does use the addressing scheme above.  But you're not using that chip.
The chips in the series covered by the AT24LC16 datasheet need progressively larger EEPROM addresses for the larger memory sizes.  As the size of the chip increases they are effectively stealing configurable bits from the A0, A1, A2 pins and repurposing them as part of the EEPROM address encoded into the I2C address.  You'll see that the for up to the 2Kbit/256byte/8-bit addressable EEPROM, all of A0, A1, A2 can be used to set the I2C address (to have multiple of these chips).  By the time you work your way up to the 16kbit/2kbyte/11-bit addressable chip, all of the A0, A1, A2 are specified as no connect; the datasheet says that can be connected to ground.  The reason for doing this probably just for controlling noise.
The chip expects only the lower 8 bits of the EEPROM word address to be sent in the data portion of the I2C write (or "dummy" write).  But the bits in excess of 8-bits, the upper 3-bits for your 11-bit addressable, are expected to be encoded into the I2C address itself, like so:
const uint8_t i2c_base_address = 0x50;
const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
Wire.beginTransmission(i2c_address);
Wire.write(eeaddress & 0xFF); // address LSB


The datasheet speaks of "BYTE WRITE" where single bytes per I2C write transactions are written to EEPROM.  And it speaks of "PAGE WRITE" where an entire page payload is sent, 16-bytes for your model.  Because you are sending two bytes as part of data portion of the I2C write, you are doing neither of these things.  The chip's notion of "current address" is updated differently for "byte" vs "page" writes.
If I had guess, they didn't want there to be a qualitative difference in handling 1 vs 2 byte I2C write transactions or alternately between 15 (page size minus one) vs 16 (page size) byte I2C write transactions.  So, they just decided anything in the middle ground between a single byte write and an entire page write should be ignored, so no EEPROM write operation carried out.

user69478: In response to the answer from @timemage I updated my code which now allows me to read and write to the EEPROM chip as intended. Here is the code just in case anyone else wants it quickly:
#include <Wire.h>

#define disk1 0x50    //Address of eeprom chip

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();

  unsigned int address0 = 0;

  writeEEPROM(disk1, address0, 1);

  Serial.println(readEEPROM(disk1, address0), DEC);
}

void loop() {}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{

  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress & 0xFF); // address LSB

  Wire.write(data);
  Wire.endTransmission();

  delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;


  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress & 0xFF); // address LSB
  
  Wire.endTransmission();

  Wire.requestFrom(deviceaddress, 1);

  if (Wire.available()) rdata = Wire.read();

  return rdata;
}


69478: <p>I have been trying to program an <a href="http://ww1.microchip.com/downloads/en/devicedoc/doc0180.pdf" rel="nofollow noreferrer">AT24C16 EEPROM</a> and have set up a circuit as per the attached image.</p>
<p><a href="https://i.stack.imgur.com/yK4gd.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yK4gd.jpg" alt="enter image description here" /></a></p>
<p>I have been using the following Arduino code:</p>
<pre class="lang-cpp prettyprint-override"><code>#include &lt;Wire.h&gt;    
 
#define disk1 0x50    //Address of 24LC256 eeprom chip
 
void setup(void)
{
  Serial.begin(9600);
  Wire.begin();  
 
  unsigned int address = 10;
 
  writeEEPROM(disk1, address, 72);
  Serial.println(readEEPROM(disk1, address), DEC);
}
 
void loop(){}
 
void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) 
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress &gt;&gt; 8));   // MSB
  Wire.write((int)(eeaddress &amp; 0xFF)); // LSB
  Wire.write(data);
  Serial.println(Wire.endTransmission());
 
  delay(5);
}
 
byte readEEPROM(int deviceaddress, unsigned int eeaddress ) 
{
  byte rdata = 0xFF;
  
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress &gt;&gt; 8));   // MSB
  Wire.write((int)(eeaddress &amp; 0xFF)); // LSB
  Serial.println(Wire.endTransmission());
 
  Wire.requestFrom(deviceaddress,1);
 
  if (Wire.available()) rdata = Wire.read();
 
  return rdata;
}
</code></pre>
<p>Unfortunately I only ever receive '255' in the serial monitor suggesting that no data has been written.</p>
<p>The code was from <a href="https://www.hobbytronics.co.uk/arduino-external-eeprom" rel="nofollow noreferrer">this</a> tutorial which explains how the wiring on pins 1-3 governs the address of the chip.</p>
 70020: <p>Well, I think I see part of what is happening.  I'm not sure to what degree this is an Arduino problem, but it may be of some use to someone wanting to interface this chip with an Arduino.  So, here's what I see:</p>
<p>You're writing to the chip just fine so far as I2C is concerned.  But the content of what you're writing is not exactly correct to the chip itself.</p>
<p>You have:</p>
<pre class="lang-cpp prettyprint-override"><code>Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress &gt;&gt; 8));   // MSB
Wire.write((int)(eeaddress &amp; 0xFF)); // LSB
</code></pre>
<p>Which is intuitive, but unfortunately not how the AT24C16 apparently works.   To be clear, the tutorial you've referenced uses the 24LC256, which <em>does</em> use the addressing scheme above.  But you're not using that chip.</p>
<p>The chips in the series covered by the AT24LC16 datasheet need progressively larger EEPROM addresses for the larger memory sizes.  As the size of the chip increases they are effectively stealing configurable bits from the A0, A1, A2 pins and repurposing them as part of the EEPROM address <strong>encoded into</strong> the I2C address.  You'll see that the for up to the 2Kbit/256byte/8-bit addressable EEPROM, all of A0, A1, A2 can be used to set the I2C address (to have multiple of these chips).  By the time you work your way up to the 16kbit/2kbyte/11-bit addressable chip, all of the A0, A1, A2 are specified as <strong>no connect</strong>; the datasheet says that <em>can</em> be connected to ground.  The reason for doing this probably just for controlling noise.</p>
<p>The chip expects only the lower 8 bits of the EEPROM word address to be sent in the data portion of the I2C write (or &quot;dummy&quot; write).  But the bits in excess of 8-bits, the upper 3-bits for your 11-bit addressable, are expected to be encoded into the I2C address itself, like so:</p>
<pre class="lang-cpp prettyprint-override"><code>const uint8_t i2c_base_address = 0x50;
const uint8_t upper_three_eeprom_adress_bits = (eeaddress &gt;&gt; 8) &amp; 0x7;
const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
Wire.beginTransmission(i2c_address);
Wire.write(eeaddress &amp; 0xFF); // address LSB
</code></pre>
<hr />
<p>The datasheet speaks of &quot;BYTE WRITE&quot; where single bytes per I2C write transactions are written to EEPROM.  And it speaks of &quot;PAGE WRITE&quot; where an entire page payload is sent, 16-bytes for your model.  Because you are sending two bytes as part of data portion of the I2C write, <strong>you are doing neither of these things</strong>.  The chip's notion of &quot;current address&quot; is updated differently for &quot;byte&quot; vs &quot;page&quot; writes.</p>
<p>If I had guess, they didn't want there to be a qualitative difference in handling 1 vs 2 byte I2C write transactions or alternately between 15 (page size minus one) vs 16 (page size) byte I2C write transactions.  So, they just decided anything in the middle ground between a single byte write and an entire page write should be ignored, so no EEPROM write operation carried out.</p>
 69478: <p>In response to the answer from @timemage I updated my code which now allows me to read and write to the EEPROM chip as intended. Here is the code just in case anyone else wants it quickly:</p>
<pre><code>#include &lt;Wire.h&gt;

#define disk1 0x50    //Address of eeprom chip

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();

  unsigned int address0 = 0;

  writeEEPROM(disk1, address0, 1);

  Serial.println(readEEPROM(disk1, address0), DEC);
}

void loop() {}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{

  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress &gt;&gt; 8) &amp; 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress &amp; 0xFF); // address LSB

  Wire.write(data);
  Wire.endTransmission();

  delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;


  const uint8_t i2c_base_address = 0x50;
  const uint8_t upper_three_eeprom_adress_bits = (eeaddress &gt;&gt; 8) &amp; 0x7;
  const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
  Wire.beginTransmission(i2c_address);
  Wire.write(eeaddress &amp; 0xFF); // address LSB
  
  Wire.endTransmission();

  Wire.requestFrom(deviceaddress, 1);

  if (Wire.available()) rdata = Wire.read();

  return rdata;
}
</code></pre>
