I promised to look at an I2C eeprom next and so....
In the video, there was a simple test program writing to and reading back from an I2C serial eeprom where the device in question is a 24C32 32k x 8 bit serial E2
chip. The eeprom is resident on the RTC module we saw in the video to presumably provide bonus functionality and the device is in fact very similar to the AT28C256 we’ve already put hard to work in our Beebs. The 28C256 differs in that it is a 28-pin parallel device and to access it, we have some high order address bus decoding which condenses down to a unique chip select for the specific device we want to talk to, some low order address lines to select a particular location within the chip and finally, some variation of a RnW line to indicate a read or write operation. In the case of a serial random-access memory device, we have to effectively do all these same operations but now sequentially using the I2C bus. This typically involves sending a unique device identifier to wake up the target chip, an indication of Read or Write, an address Hi byte, an address Lo byte and finally, we have to send data to the chip when writing or receive data from the chip when reading.
Pictorially, the write process for the 24C32 looks like this…
In the video, you were enthralled by addresses and data scrolling up the screen and this was the output of a simple eeprom write/read program that nicely demonstrates the Byte Write
process shown in the graphic above, with each write being additionally followed by a read-back of the same address.
Code: Select all
40 *I2CTXB 57 H%;
50 *I2CTXB FF L%;
60 *I2CTXB FF A%
70 *I2CTXB 57 H%;
80 *I2CTXB FF L%;
90 *I2CRXB 57 D%
Lines 10 and 120 loop the test through all 32k of the eeprom locations, i.e. &0000 to &7FFF. Lines 20 and 30 set H% and L% to the upper and lower bytes of the 16-bit eeprom address such that, for example, at an address of &1234, H% is set to &12 and L% is set to &34.
Referring now to the Byte Write graphic, the Start
, Control Byte
are constructed by the I2C rom in response to the *I2CTXB 57
component of line 40 where our E2
module has a device address of &57 and the H%
component of line 40 results in the Word Address H
of the graphic. (Note that all ACK
in the graphic are transparently handled for you by the rom.)
You can see that there is no Stop specified after the Word Address H
and no Start preceding the Word Address L
. The Stop is suppressed by the trailing ;
in line 40 and to ensure that we only send the eight bits of L% byte in line 50, the device address is set to the special value of &FF (out of range for I2C devices) which directs the rom to transmit only a single naked byte. Again, from the graphic, there is no Stop specified after the Word Address L
and no Start preceding the Data byte so as before, line 50 is terminated with a ;
and in line 60, the device address is specified as &FF. Line 60 specifies A% as the data byte to send and because the rom will only use the lowest eight bits of A%, each location of the eeprom has a value written to it which equates to the low byte of the target location address. For example, the eeprom memory location at address &1234 will have data &34 written to it. The graphic shows that a byte write is completed with a Stop and therefore, unlike the preceding two lines, line 60 is not terminated with a ;
and hence a Stop is sent by default.
After each write, the program reads back the just-written data and the procedure for this is slightly unusual when compared to parallel devices because we have to begin the read with a couple of writes! Read on...
Most I2C devices maintain an internal latched counter that is used to keep track of either the last-accessed register in the case of bespoke–function chips such as our RTC or, the last-accessed memory location in the case of memory-based devices such as eeproms. If sequential reads or writes are made to a device with such a counter, the latter is simply auto-incremented from its last accessed value. However, if we want to read a specific (or random) location, we need to first set this counter to point to the target address and this explains the need for the writes prior to a random read. (In the more usual parallel system, the process just described is the equivalent of the CPU setting up the low order address bus lines to configure the target memory device prior to the read.)
Pictorially, the read process for the 24C32 looks like this…
So, in the demo program, you can see that although we now want to read the eeprom, lines 70 and 80 are identical to earlier lines 40 and 50 where we were preparing to write data to the eeprom because in both cases, we first need to set the address counter to point to our target location. The difference now is that in line 90, we perform a Re-Start (a Start without a previous Stop) and request a read of the data byte at the current address (that we have just set) into D%. Finally, there is no trailing ;
in line 90 and so a Stop is sent on completion.
Line 100 hex-prints the current address (A%) followed by the read-back data (D%) and the data is validated in line 110 since we know it should be equal to the lower byte of the eeprom subject address.
Now, I described how eeproms can auto-increment their address counter and during sequential contiguous writes, this is known as a Page Write. However, because E2
devices require a finite time to update a memory location, during a Page Write, an eeprom has to internally buffer sequentially-written data prior to its been physically written to memory. This means that eeproms will have an upper limit to the size of a Page Write and in the case of the specific 24C32 I’m using (the sub-types vary), the page size is 32 bytes – generally specified as one Byte Write (or Random Write) plus 31 further page byte writes.
The program below demonstrates a single, full 32-byte Page Write
beginning at eeprom address &1234. For homework, I’ll leave it to you to figure out how its done…
Code: Select all
10 *I2CTXB 57 12;
20 *I2CTXB FF 34;
40 *I2CTXB FF A%;
70 *I2CTXB 57 12;
80 *I2CTXB FF 34;
90 *I2CRXD 57 20
Answers on a postcard to MartinB @ I2C 4 U
( Note that this employs the new *I2CSTOP command which is introduced in v0.3 of the rom so I’ll post that in a little while.)