Go Down

Topic: Wire.available() and Serial.available() : How do they differ? (Read 270 times) previous topic - next topic

GolamMostafa

I could never come up with clear meaning of the Serial.available() method; but, I have owned some satisfying meaning on the Wire.available() method.

Wire.available() method belongs to TWI Protocol, and it is called upon after the execution of the Wire.requestFrom(deviceaddress, 7) function which requests a slave to release 7-byte data one after another. If the function (Wire.requestFrom()) executes with success, the Wire.available() function will return 7. Now, the user is ensured that the master has received 7-byte data from the slave, and he may proceed to read them from the buffer. Wire.requestFrom() is inherently a loop instruction, and it might fail (for some reasons) after the transfer of only 5-byte data instead of 7-byte. In this case, the user will be able to get 5-byte data.

Serial.available() method belongs to Asynchronous Serial Protocol. In the Arduino UNO platform, the receiver section of the USART Port acquires incoming data character-by-character on interrupt basis. It means that UNO-2 sends a data byte (in the form of ASCII Code) to UNO-1; UNO-1 gets interrupted; UNO-1 goes to ISR; UNO-1 reads the data byte and saves it in a buffer.

My question is: In TWI protocol, the user knows when to read known number of data items and process them. In Serial Protocol, how does the user know how many data items to read from buffer before applying Serial.available() method in order to be sure that the buffer has accumulated data? Is this number (number of data items to be transferred) be set earlier on mutual agreement between UNO-2 and UNO-1 -- before the communication begins between UNO-2 and UNO-1?

pylon

Quote
My question is: In TWI protocol, the user knows when to read known number of data items and process them. In Serial Protocol, how does the user know how many data items to read from buffer before applying Serial.available() method in order to be sure that the buffer has accumulated data? Is this number (number of data items to be transferred) be set earlier on mutual agreement between UNO-2 and UNO-1 -- before the communication begins between UNO-2 and UNO-1?
To answer your direct question: Yes.

In both interface types the protocol used on them defines how many bytes to be transfered. On I2C this is enforced by the master (it clocks only that many spikes on SCL) while on UART it's simply a rule both sides should have agreed on.
The available() method of both interfaces (Serial and Wire) just returns the number of bytes in the reception buffer. Using the Wire object you get exactly the same value from the requestFrom() method, at least until you start reading out the buffer.

cattledog

Quote
If the function (Wire.requestFrom()) executes with success, the Wire.available() function will return 7. Now, the user is ensured that the master has received 7-byte data from the slave, and he may proceed to read them from the buffer. Wire.requestFrom() is inherently a loop instruction, and it might fail (for some reasons) after the transfer of only 5-byte data instead of 7-byte. In this case, the user will be able to get 5-byte data.
I don't think this is correct. Wire.requestFrom() either returns zero (if the slave could not be connected to) or the number of bytes requested, regardless of how many bytes the slave actually sent.

http://www.gammon.com.au/forum/?id=10896&reply=10#reply10

GolamMostafa

If I have understood Post#1 and Post#2 correctly:

1.  When the function Wire.requestFrom() executes correctly, the value returned by this function will always be equal to the value returned by Wire.available() function.

2.  If the function requestFrom() is executed partially due to internal fault either in the Master or Slave, the value returned by requestFrom() will be less than the value returned by available(). What value will Wire.available() return in this abnormal case?

Thanks to pylon and cattledog for the valuable information/comments.


cattledog

Quote
2.  If the function requestFrom() is executed partially due to internal fault either in the Master or Slave, the value returned by requestFrom() will be less than the value returned by available(). What value will Wire.available() return in this abnormal case?
This is not how I understand it. Wire.requestFrom() and Wire.available() will always show either 0 or the number of bytes requested. The master actually receives all the bytes requested, but some of them will be 0xff if the slave does not send anything.

See this discussion from the git hub issue on Wire.requestFrom().

Quote
The I2C protocol does not support a slave refusing to send data. When the onRequestEvent()'s data is exhausted, the TWI code just turns off the hardware until it see a DATA_NAK from the Master. Meanwhile the Master is just receiving 0xFF because no one is driving the SDA line. The documentation should be change to say requestFrom either returns 0, or number of requested bytes. 0 if the Slave NAKed the address or (requested bytes) that might have a bunch of 0xff appended.

GolamMostafa

There are human beings behind the development of the Wire.requestFrom(deviceaddress, 7) method; unfortunately, they have not prepared detailed Technical Manual describing the functional/design anatomy of the method; as a result, a curious mind desires to proceed as per following critical thinking (Platform: UNO and 24C512 EEPROM, Fig-1) to formulate the functional mechanism of the requestFrom() function.


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

1.  Assume that the Master wishes to read 7-byte data from 24C512 EEPROM starting at location 0x1000. Also, assume that the base address has been successfully set by executing the following instructions:

Code: [Select]
//----- put eeprom address = 0x1000
   Wire.beginTransmission(0B1010010);    //EEPROM deviceaddress
   Wire.write((int)(eelocaddress >> 8));   // MSB
   Wire.write((int)(eelocaddress & 0xFF)); // LSB
   byte sts = Wire.endTransmission();
   if (ss != 0x00)
   {
      return;                                            //transmission is not successful
   }


2.  Master generates 8 SCL pulses (Fig-2); 8-data bits from current EEPROM location enters into Data Register (TWDR) of Master. After releasing 8 data bits and at the end of 8th SCL pulse, the Slave releases the SDA line which, by virtue of pull-up resistor, assumes H-state.


Figure-2: Diagram depicting the BusEvents of TWI Bus Transmission(data reception from Slave)

3.  Master generates 9th SCL pulse during which Master creates ACK signal by pulsating the SDA line (LH ---> LL ---> LH). This ACK signal works as a supplementary clock which advances the Address Counter of the EPROM to 0x1001, generates a known valued status word (0x50 for ACK) within Status Register (TWSR) of the Master, and triggers the TWI Logic of the Master to generate the next set of SCL pulses for reading the data of the EEPROM location 0x1001. The user increments the byteCounter.

4.  Assume that there has happened two successful Transmissions. The user program has removed the data bytes from TWDR register into a pre-declared buffer (the dataArray[7]). Now, we have the following situations:

byteCounter = 0x02
Address Counter = 0x1002;
dataArray[0], dataArray[1] are filled up locations.

5.  The 3rd Transmission has begun. The Master has generated 8 SCL pulses; 8-bit data of EEPROM location 0x1002 has entered into TWDR. At the end of 8th SCL pulse, something has gone wrong within the TWI Logic of the Slave; the Slave could not release the SDA line to H-state or the SDA line is permanently stuck at H-state. The following events are expected to occur:

a.  The Master can not create the ACK pulse by pulsating the SDA line (LH ---> LL ---> LH); instead, there appears a NACK signal to the TWI Logic of the Master.

b.  The user does not increment the byteCounter; he does not move data from TWDR into dataArray[2]. The Address Counter is not advanced. The status word (0x58 for NACK) is generated within TWSR Register of the Master instead of 0x50 for ACK.

c.  The Intellect of ATmega328 finds status word 0x58 and understands that there is no need to generate anymore SCL pulses; it terminates the communication session and makes a safe return to the Control Program.

6.  I ask questions to myself:
a.  What value would Wire.requestFrom() return? Ans: 2.
b.  What value would Wire.available() return? Ans: I am not sure?
c.  How many data bytes are there for the user to process? Ans: 2.
d.  What is the actual benefit of incorporating the Wire.available() function in the TWI Protocol?Ans:  I am not sure!
e.  Is it possible to frame the above critical thinking into an experimental setup? Ans: It can be tried!




pylon

Quote
a.  The Master can not create the ACK pulse by pulsating the SDA line (LH ---> LL ---> LH); instead, there appears a NACK signal to the TWI Logic of the Master.
I don't think this is correct. The master does not check the state of the SDA line before pulling it down. It pulls SDA down to signal an ACK, at least that's what the datasheet says.

Quote
a.  What value would Wire.requestFrom() return? Ans: 2.
It returns 7.

Quote
b.  What value would Wire.available() return? Ans: I am not sure?
It returns 7 until you start reading the buffer.

Quote
c.  How many data bytes are there for the user to process? Ans: 2.
There a 7 although only 2 are correct. But the slave has no way to signal the master that it has a problem.

Quote
d.  What is the actual benefit of incorporating the Wire.available() function in the TWI Protocol?Ans:  I am not sure!
That you can check how many bytes of the buffer you haven't read yet.

Quote
e.  Is it possible to frame the above critical thinking into an experimental setup? Ans: It can be tried!
You can try it but it will be quite difficult to simulate. You have to do the signaling correctly for the first two bytes and pull SDA down after the third byte (it's probably easier to pull it down at the start of byte 3 and keep it pulled down).

If you get the result you described in your post, the datasheet of the ATmega328p is wrong as it doesn't describe the state you forecast here.

GolamMostafa

@ pylon
I acknowledge your opinions and coments with great respect and enthusiasm. These are important inputs for my planned experimental setup which aims at understanding the TWI Bus behavior as described in the Atmel data sheets.  

I understand that the TWI Bus related Arduino's High Level functions/methods are designed based on Atmel's TWI Bus architecture. However, some of the functions are highly abstracted like Wire.endTransmission() which returns 0x00 on success; whereas, in the low level activities we find one or more of the following:  0x08, 0x18, 0x28, 0x40, 0x50, 0x58, and etc.  

pylon

Quote
However, some of the functions are highly abstracted like Wire.endTransmission() which returns 0x00 on success
If you don't like the high level interface of the Wire library you're free to implement your won library, nobody says you need to use the one the Arduino project provides. In some cases (p.e. if you need I2C multimaster functionality) you have to write your own routines because the Wire library doesn't support that.

But keep in mind that the example you described above is quite unusual (the device gets broken in the middle of an I2C transaction) and I don't think that the I2C standard supports that such situations are correctly recognized. So it might be of an academic interest how the AVR hardware reacts in such situations but it's not relevant for practical use in my opinion.

GolamMostafa

Quote
But keep in mind that the example you described above is quite unusual (the device gets broken in the middle of an I2C transaction) and I don't think that the I2C standard supports that such situations are correctly recognized. So it might be of an academic interest how the AVR hardware reacts in such situations but it's not relevant for practical use in my opinion.
Very much practical; but, the issue appeared as we could not authentically resolved the roles played by Wire.requestFrom() and Wire.available() functions in respect of the figures they return. I have firmly recorded the tentative answers you have given voluntarily to my questions, and I wish that I will make responses based on true measurements creating a genuine fault in the active TWI Bus running at ~490 Hz and ~2 Hz speed (SCL frequency = (clkSYS/256)/(16+2(TWBR)*(TWPS)) = (16000000/256)/(16+2*255*64)) =~ 2 Hz). The experiments are in the process where I have bypassed the Wire Library functions where I could; instead, I have employed register-based instructions. However, the Wire Library helped me a lot to debug/develop the low frequency TWI Bus Experimental Setup.

When all kinds of minds -- poetic mind, prophetic mind, philosophical mind, critical mind, rational mind, pragmatic mind, scientific mind, and technological mind come into an association, the divine (natural) mysteries are resolved to a great extent.

We are involved in the studies of TWI Bus which is the creation of a number of scientific/technological minds. It is not a natural phenomenon, and yet it has appeared as a mystery to a few pragmatic minds who want to correlate the observed results with what had been set at design time by the TWI Bus Architects.  

We can try to validate our conceptual understandings with the available test gears that we have in our hands. The aim is to satisfy merely our individual thirsts.

BTW: There are many many good reasons for liking the Wire Library. I like it. The three methods : beginTransmission(), write(), and endTransmission() when placed one after another bring cool to the eyes. They have replaced so many register level instructions that the Wire Library has made TWI Bus programing job easy and comfortable. The developers team deserve great appreciations!! By talking about the return value of endTransmission(), I was actually referring to the highly abstracted feature of the method.    

GolamMostafa

Creating Fault on Active TWI Bus and Recording its behavior


Figure-1: TWi Bus connection between UNO and 24C512 EEPROM with control on Vcc

Register level programming allows us to have access to bit value; therefore, we can control the operation of the TWI Bus in a way we want having maintained full compliance with the data sheets.

Fault is created in an active (operational) TWI Bus by removing Vcc supply from the EEPROM. In Fig-1, we have placed Q1 and Q2 which work as switch to cut-off Vcc supply of the EEPROM.  

The TWI Logic is a programmable State Machine, and it generates sequencing timing functions as per instructions given by the user (attached file:  multibyteRW-1.ino). The program instructions are cooked by the user to see result what he has wanted before. For example: After reading two byte data from the EEPROM, the user has removed the power (creating a fault) from EEPROM (digitalWrite(12, LOW)) at the beginning of the 3rd Transmission. The user knows that the EEPROM is dead now, and there is no need for the Master to communicate with the EEPROM. The usr has simply made a return to the Control Program (the Operating System). So, what is the achievement of this Experimental Setup? Not much except of enjoying the ego that the idea could be tried!

Searching for Wire.requestFrom() behavior under fault condition
Hardwsre Setup: Figure-1
Program: attached file: multibyteRW-2 (Functional at TWI Speed: 2 Hz to 200 KHz)
clkSYS = 62500 Hz
TWI Bus Speed =~ 2Hz
Execution Time of byte n = Wire.requestFrom(deviceaddress, 7); =~ 30 sec (manual counting)
Fault Simulation: Manual asynchronous removal of the Vcc supply from EEPROM.

1.  At the beginning of the execution of requestFrom(), the built-in LED (L) becomes ON.
2.  After 10-12 seconds, fault is created with the EEPROM by switching off its Vcc supply (manually).
3.  The requestFrom() falls in an infinite loop. (Thanks to Watchdog Timer which will bring the MCU out-of-infinite loop in the field applications.)

4.  Vcc is connected back. The requestFrom() comes out-of-loop and switches off L.
5.  Both requestFrom() and available() return 7; but the received data are close to garbage except few bytes at the beginning!

Many many thanks to pylon and others whose interest and guidance have encouraged me to carry out this experiment.

Go Up