Go Down

Topic: TWI Bus Operation using Arduino UNO and 24C512 EEPROM (Read 257 times) previous topic - next topic


Sep 29, 2017, 03:45 pm Last Edit: Oct 12, 2017, 02:58 am by GolamMostafa
Hello Everybody!

Figure-1 depicts the TWI Bus Interface Circuit between Arduino UNO and 24C512 EEPROM. LCD is a non-TWI device connected for monitoring various statuses of the TWI Bus as the BusEvents progress. The circuit appears as working (eepromUno512.ino). Fig-2 is the timing diagram for the START and Device-Address-Inquiry (DAI) BusEvents. I have few Queries of which Query-1 is stated below (after the diagrams and codes):

Figure-1: TWI Bus connection between ARduino UNO and 24C512 EEPROM

Figure-2A: TWI Bus timing diagram showing BusEvents

Figure-2B: TWI Bus timing diagram showing BusEvents

Figure-2C: TWI Bus timing diagram showing BusEvents

Figure-2D: TWI Bus timing diagram showing BusEvents
Code: [Select]

void setup()
   pinMode(13, OUTPUT);
   TWBR = 0x02;         //200 KHz TWI Bus speed                                                //L1
   TWSR = 0x02;                                                                                     //L2  
   TWCR = 0b10100100; //TWINT  X  TWSTA  TWSTO  X  TWEN  X  TWIE                            L3
   while(bitRead(TWCR, 7), ! = HIGH)                                                                 //L4  
        ;                                                                                                  //L5
   lcd.print((TWSR & 0b11111000), HEX);    //shows: 0x08 (correct as per data sheet)            //L6
   lcd.print(PINC, HEX);                              //shows: PC5(SCL) PC4(SDA) XXXX = 0 0 XXXX   //L7
   TWDR = 0b10100100;   //0xA4 = Devivice-Address-Inquiry with Write Mode       //L8  
   TWCR = 0b10100100; TWINT  X  TWSTA  TWSTO  X  TWEN  X  TWIE                 //L9
   while(bitRead(TWCR, 7), ! = HIGH)                                                                  //L10
        ;                                                                                                    //L11
   lcd.print((TWSR & 0b11111000), HEX);    //shows: 0x18 (correct as per data sheet)            //L12
   lcd.print(PINC, HEX);                              //shows: 0x15=PC5(SCL) PC4(SDL) XXXX=0 1 XXXX   //L13

void loop()
    digitalWrite(13, !digitalRead(13));    //keep blinking built-in LED (L) of Arduino UNO

Query-1 : Monitoring Logic Values of SCL and SDA Lines
Execution of codes (lines L3 - L5) causes BusEvent (S) to happen in Fig-2; execution of codes (lines L8 - L11) causes BusEvent (C) to happen in Fig-2.

Atmel data sheet says that after the occurrence of BusEvnet-(S), SCL and SDA lines assume L-states (there is a time gap between them), and the status value is 0x08. How can we monitor the logic values of the SCL and SDA lines after BusEvent-(S)? Is it valid to execute the lcd.print (PINC, HEX) instruction to monitor the logic values of SCL and SDA lines via PINC5 and PINC4 bits of PINC Register as is done in Line-7 (L7)? Does PINC Register exist along with TWI Bus scheme?  

Reasoning similar to above is for BusEvent-(V) of Fig-2 when the executing codes are given in L8-L11.


Sep 30, 2017, 05:12 pm Last Edit: Oct 02, 2017, 05:27 pm by GolamMostafa
Query-2 : Code Equivalency (Arduino Function and Register Instruction)
The following Table of Fig-3 contains Programming Procedures to write a data byte (0x23) into location 0x1234 of the 24C512 EEPROM using TWI Bus under Arduino UNO Platform (Fig-1 of OP). The data has been successfully written. (It has been verified by reading back the data from the EEPROM location. The codes are shown in the Table).

Can we say that the collective codes of Step-2 to Step-6 of Fig-3 are equivalent to the following codes of Wire.h Library?
Code: [Select]

    Wire.beginTransmission(0b1010010);             //EPROM (Slave Device) 7-bit address
    Wire.write(0x12);                                    // MSByte of the EEPROM location address
    Wire.write(0x34);                                   // LSByte of the EEPROM location address
    Wire.write(0x23);                                         //data byte to be written at location 0x1234
    Wire.endTransmission();                        //?

Figure-3: Register oriented instructions for 1-byte (random address) write/read using TWI Bus


Don't send me technical questions via Private Message.


Why don't you open up Wire.cpp on your system and check for yourself?
"The problem is in the code you didn't post."


Sep 30, 2017, 06:27 pm Last Edit: Sep 30, 2017, 06:56 pm by GolamMostafa
The Wire.cpp file contains about 261 lines of codes; but, none of them matches with the codes of the Table of Fig-3 (Post#1). The file also does not contain these Arduino Functions: Wire.beginTransmission(), Wire.write(), and Wire.endTransmissiion().

Therefore, we have no alternative but to place query (ask a question about something, especially in order to express one's doubts about it or to check its validity or accuracy - Google) in the Forum to receive reasonable certification on the accuracy of the information that we have created from the data of our studies/findings.


Sep 30, 2017, 06:37 pm Last Edit: Sep 30, 2017, 06:48 pm by GolamMostafa

Thank you!

The pupils have a lot of questions about the Arduino Library Functions. They are interested to know, what these hidden functions are actually doing, by bringing them in line with the corresponding register based instructions. It is cool that the Arduino Forum Members are generously putting their opinions on our queries.

BTW: At which path of my PC should I look for the Wire.h file/folder? I don't find it in the following path:

c:\Program Files (x86)\Arduino\libraries


If you have a 24C512, it would be easy to test the code yourself. Your pupils could also get "hands-on" experience with TWI and 24C512 etc.

Don't send me technical questions via Private Message.


The Wire library is closely linked to the actual hardware it's running on. The registers are different on each chip.
 So there's a different version for a UNO and a Due. Those files end up in the "hardware" Arduino folder. The basic Arduino hardwares like the UNO are kept in a different place to the ones you download like the Due.

Using a trick suggested by someone else yesterday, I opened a Wire example and then used the "show sketch folder" menu item to open the sketch folder. That led me to C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c which contains the register instructions you're looking for.
"The problem is in the code you didn't post."



You're the TEACHER in this class and you don't know how to even find a file on your computer?  I worry for these students. 
If at first you don't succeed, up - home - sudo - enter.


Oct 01, 2017, 10:10 pm Last Edit: Oct 02, 2017, 10:04 am by GolamMostafa
Query-3 : Status Words  
Atmel data sheet says that a Slave is obliged to generate an acknowledge (ACK) bit which is reflected as an 8-bit status word in the TWSR Register of the TWI Interface. In Fig-2A, 2B, 2C, 2D, and 3 of OP, we observe that the BusEvents-(S), (V), (W), (X), and (Y) have generated five such Status Words (0x08, 0x18, 0x28, 0x28, 0x28). These five BusEvents together write a data byte (0x23) into an EEPROM location (0x1234). The Master reads these status words sequentially as they are generated, check their correctness, and then move to the next transmission task. This process is clearly seen in the register instructions of Fig-3 (OP).

The following Arduino Functions writes a data byte (0x23) into an EEPROM location (0x1234). Do these functions, in the background, read these status words (0x08, 0x18, 0x28, 0x28, 0x28) and check their validity before moving to the next step? How do these Arduino Functions raise error message when there is a mismatch in one or more of the status words? Or do these Arduino Functions just assume that these status information would be correctly generated; there is no need to read/check them; next task could be taken confidently?
Code: [Select]

  Wire.write(0x12);                            // MSByte of EEPROM location address (0x1234)
  Wire.write((0x34);                          // LSByte of EEPROM location address (0x1234)
  Wire.write(0x23);                           //data byte to be written into location 0x1234
  Wire.endTransmission();                 //



Look at the damn library. See how it works. Change it if you like.
"The problem is in the code you didn't post."


Query-4 : Detecting 'Writing Ends into EEPROM Location' Event
After presenting a data byte into a location of 24C512 EEPROM and then issuing the STOP command, the Processor needs to wait for a while (typical value is about 5 ms) to allow the data byte actually getting written into the specified location of the EEPROM. This time delay can be achieved in one of the following ways:

(1)  Insert fixed time delay by executing the instruction:
Code: [Select]

(2)  By executing the following algoritthm of Fig-1 (extracted from Microchip Data Sheet)

Figure-1: Algorithm describing the procedure of detecting 'Writing Ends into EEPROM Location'  event  

(3)  By executing the following Register Instructions for Fig-1
Code: [Select]
   TWCR = 0b10100100;    //START command to seize Bus (TWINT TWEA TWSTA TWSTO TWCC TWEA X TWIE)
   while((bitRead(TWCR, 7) != HIGH)
        ;                                //wait until action is completed
   TWDR = 0b10100100;     //EEPROM (device) address in write mode (SLA + W)
   while((bitRead(TWCR, 7) != HIGH)
        ;                 //wait until action is completed and status triggered by ACK of Slave

while((TWSR & 0b11111000) != 0x18);  // Status code triggered by ACK of TWDR = (SL+W)

(4)  By executing the following Arduino Functions for Fig-1
Code: [Select]
   Wire.beginTransmission(deviceAddress);  //EEPROM (device) address
   Wire.write (0x00);                      //dummy; it is to insert W-bit after 7-bit device address

while (Wire.endTransmission() != 0x00); //returns 0x00 if transmission is successful

The Flow Chart of Fig-1 recommends to send 8-bit control byte as SLA + W (Slave Address + W-bit) where W stands for Write Mode and it has to be zero. In the codes of Step-4, the deviceAddress argument of the Wire.beginTransmission() function has the 7-bit value of 0b1010010. We have observed that the system still works even we don't include the Wire.write(0x00) function. If so, how does the W-bit (0) appears at the end of the 7-bit deviceAddress value? Is it taken as 0 by default?   


Here's the actual I2C manual for how the protocol is supposed to operate.

Note that most devices don't support the full protocol - they don't need to. You may also find devices which claim to be I2C and which actually work with many other I2C devices but they have significant deviations from the standard.
"The problem is in the code you didn't post."


Oct 04, 2017, 11:42 am Last Edit: Oct 04, 2017, 07:05 pm by GolamMostafa
First of all, thanks a lot for the User Manual on I2C Protocol. Sometimes, Application Manual is very helpful for people who are interested in making the system working first and then doing the Reverse Engineering to understand the Mechanics of Functional Behavior of the system.  A Cookbook is even much better to some people who wish to learn things by playing with gadgets that can be made straightway following the steps of the Cookbook.

Yes! It is not needed that all the TWI devices have to comply with the specifications of Full Protocol. However, they must satisfy the minimum requirements. The codes of Step-3 of Post#11 are the minimum codes (START and DAI for device address inquiry) that must be executed before looking for a desired status word in an ATmega328 Platform. Therefore, the High Level Arduino Codes of Step-4 (after compilation under Arduino UNO Board) must produce codes that are functionally equivalent to the codes of Step-3. When we observed that the codes of Step-4 works without the Wire.write(0x00) function, we started looking for the source of W-bit from two view points: academic and system reliability. In many occasions, systems work with unseen internal faults; but, these systems are inherently weak and unreliable; periodic diagnostic checks, as a part of preventive program, are performed to catch these weaknesses. I claim that the function Wire.write(0x00) needs to be inserted in the codes of Step-4 of Post#11.  

Go Up