External EEPROM memory addreses

I played few days with EEPROM AT24C256.

This one:

I found 3-4 reliable examples of coding.
The most basic (for me) is this one:
http://www.hobbytronics.co.uk/arduino-external-eeprom

I read the datasheet from Atmel and other producers - notably Shangai Fudan Manufacturers appear to be the most explanatory I can find.

I experiment examples and try changing commands (statements etc.) using this chip mounted on I2C and the example codes.

I re-read the C++ tutorial from the net and learning section here.

====

Still not getting it in deep:

  • When coding, shall I refer to memory addresses in decimal, binary or hexa? In other words, does the write and read to eeprom convert the address given to an internal format or better provide it in hexa?

  • How is in fact organized the memory (map)? It is a page-like, I got it. But then it is said x and y reference, that is to be done by the register , OK but how the register interpret the one byte address then, since it shall point in a 2-D space?!

  • Memory is to be written byte by byte, OK. But first octet - the one which stores the type of the device and is address for I2C- is address zero? Or shall not be counted and the next octet is zero?

  • When I say to the EEPROM "write to address 2000", is that address including - as a zero - this first device address byte?

  • And it looks like the address "2000" is in decimal, am I correctly understanding? It means the octet address number 2000?

===

Since this is not about a certain project, I did not post the coding and the wiring. The wiring I know is correct and the tests confirmed I can write and read to eeprom.

My point is to understand, not to copy-paste codes.

I could not find an internet extended reference for this basic EEPROM knowledge (e.g. a memory map, an explanation of the commands or an extended explanation of memory addressing in either Arduino or plain C++.

Thank you for any interenet reference, personal explanations/tips!

Hardware memory arrays are always binary addressed, of a size that is a power of two, and the address
ranges from 0 to 2^N-1

Or put another way every pattern of address bits is valid.

Learn that a number is just a number. Only the representation of a number has a radix. Numbers in
programs are represented in binary in the hardware - how they are displayed to you via serial print's
is an entirely different matter (you can choose whatever radix you like in fact).

If you wanted to break a 16 bit address into two bytes programatically you'd probably do something like:

  byte hibyte = (addr >> 8) & 0xFF ;
  byte lobyte = addr & 0xFF ;

@ Mark

So, in other words, if I want to point to a certain address in decimal fromarduino IDE, I can do it, providing is a multiple of 16?

In fact, I had to split it in two (high -low).

However, when I bitwise (as in your exemple) the address shall be converted from decimal to binary before splitting?

Let's me think, to see if I get it correctly:

My EPROM is 256 kb EEPROM=32kB.

Divided by 16 bits= 16.000 locations of 2 B length each. It means that address 16 (in decimal) is in fact the beginning of the second octet. To use it, I have to convert it in binary Adr = byte(16). And use it as reference to write my data.

However, this address is a linear one. So, if I want to know in which actual page it is located, I have to see how large a memory page is. But still - I just cant point to a location in a specified page (a sort of page address).

Correct?

falexandru:
@ Mark

So, in other words, if I want to point to a certain address in decimal fromarduino IDE, I can do it, providing is a multiple of 16?

In fact, I had to split it in two (high -low).

However, when I bitwise (as in your exemple) the address shall be converted from decimal to binary before splitting?

No. You are confusing external and internal representations of the address. In the Arduino's variable its
represented in binary, it has to be, that's all the hardware can do.

Anything decimal or hexadecimal is a printed representation for human use, not relevant to driving
an EEPROM via I2C.

MarkT:
No. You are confusing external and internal representations of the address. In the Arduino's variable its
represented in binary, it has to be, that's all the hardware can do.

Anything decimal or hexadecimal is a printed representation for human use, not relevant to driving
an EEPROM via I2C.

Right. But in the code itself (IDE) - I need to keep track of the addresses. So If for instance I want to write to adresss 16 (in my human decimal representation) I certainly prefer to write it in this decimal format, is that correct? Because I may have tremendous problems in writing and judging binary addresses.

Then, when I have to pass address 16 to WriteEeprom function, I must convert it (16 in decimal) in my code to binary, in order to allow the function to actually write data to that address. Or shall I leave it in decimal and pass it like that to the fucntion?

No, you are not getting it.

The internal representation is always binary.

Whether you specify it as decimal, hex, or binary doesn't matter. They are all the same number

int x=65;
int x=0x41;
int x=0b01000001;

Are all identical, they produce the same compiled code. You can use whatever representation you want in your code.

@ Mark
I got that - internal is binary.

The point is the variable to store the binary address in my code, in IDE - could that be decimal?

Like that:

unsigned int address = 0;

address = 16;

badress = byte(16);

writeEprom,,, here is my question:

(address...) or (badress)?

If well I understood @Drazzy:

  • I can have address whatever decimal, bunary or hexa
  • I do not have to convert the address myself, the function will take it as it is and the final output (complied) will be anyway in binary (which is obvious)

Right, so say you use eepromWrite (address, data); the syntax is something like that.
Then address for the internal EEPROM is 1024, from 0 to 1023, or 0x00 to 0x3FF, or 0b000000000000 to 0b001111111111.
Any of those can be used for the address, the compiller takes care of getting the right format in the code to go over the internal bus.

Same for the data.
0 to 255 for any one location, or 0x00 to 0xFF, or 0b00000000 to 0b11111111.

Use whatever is easiest for your implementation.

If you're using external memory, and not using a library that handles the addresses for you, then you might have to break an address up into 2 o3 bytes to send to the chip
Say you wanted to access location 235467 out of 256K (256 x 1024 (or 1K)).

Decimal 234567 = 0x039447, so you'd need to break that into 3 bytes, 0x03, 0x94, 0x47 to send to the chip, or their binary equivalents, 0b00000011, 0b10010100, 0x01000111. Hex format is a lot easier to visualize for humans. Or the awkward (computationally) decimal equivalents of 0x03, 0x94, 0x047 of, 3, 148, and 71, the compiler will in the end convert it to binary to send to the chip over the I2C or SPI bus.

The 234567 might come in handy if you were displaying a range of addresses and data for debugging, and with a little practice it's just as easy to "see" it in hex, which is just a shorthand version if you will of the actual binary addressing that's actually done in the chip.

I use only wire.h.

In my chip I assume each 2 octets (B) has an unique address.

Since th data field has only 2 octets no more no less, then it comes to the point that addresses shall have reserved three B (octets), coming in blocks of three octets from the very o address.

So - the first data octet is for device type and address (something like 0x50). The next octet shall be then left blank (zero), if the each location has 2 octets.

Alternatively, I can imagine the device address is somehow separated, not counting in the 256 kb total memory size. And for each 2 octet data location - a three octets area is reserved, separately from the 2 octets data.

The locations shall be managed somehow by the chip. What confuses me is that it is said the addreses and the data are located in the same place for this type of chips.

We call them bytes - not octets. Nobody calls them octets.

So assuming you wanted to write to location 0x0010 (the 16th byte), you're sending 4 bytes - the device address byte (0xA1 is what is sent down the wire, but you just pass the 0x50 to the Wire library, and it handles this), 0x00, 0x10, and the data to write to that location.

The way addressing works on these is:

On the AT24's 32kbit and larger, when you write to them to set the address, that's always three bytes - The address (7 bits of address, plus the r/w bit. The 7-bit address gets leftshifted one place by Wire), and the two bytes that specify the address.

On AT24's larger than 512kbit (64kbyte, the most you can address with 2 bytes), they use the low bits of the address for the additional addressing (and the corresponding address-selection pins are disabled - I've only seen them go up to 2mbit, leaving 1 pin free, which you can use like a chip select pin)

On AT24's that are 16kbit (2kbyte) or smaller, there's only 1 address byte, so you only send 2 bytes to set the address (the 4/8/16 kbit versions use the low bits in the device address to get the extra bits needed, and the corresponding address pins aren't available)

Note - I say AT24, but everyone and their mom makes near identical eeproms with the same interface, not just atmel.

@DrAzzy

Then, what would be the command to write to EEPROM, without involvment of wire.h library? Ok, I need it for I2C itself. But besides this.

The 2 Bytes that specifies the address may not suffice for all potential addresses in the 256 kB chip?

1 B the device + 2 B the address + 1 B the data itself.

The I2C allows B by B transmission, as far as I understood. But the wire.h library shall take care of this, right?

+++

[OT - I used to say octets (I guess is French origin word, but not sure) because it is a clear differnt word from Byte which can be confused by bit very easy. But I will try to use Bytes.]

falexandru:
The 2 Bytes that specifies the address may not suffice for all potential addresses in the 256 kB chip?

It is 256 kb (kilobit) = 256/8 = 32 kB (kilobyte) chip. 2 bytes of address suffice for 2^16 = 64 k adresses. Since you may address only whole bytes (you cannot do unaligned writes/reads) it is enough even for 512 kb chip.

falexandru:
@ Mark
I got that - internal is binary.

The point is the variable to store the binary address in my code, in IDE - could that be decimal?

Clearly you hadn't got that at all... The variable is internal, it is not in the IDE, and it must be
binary.

Perhaps you mean the value passed to the variable via the IDE could be in a different representation?
You are confusing variable and value if so.