@Juraj and @cattledog
Your generous responses to my post have indeed encouraged me to delve a little more into the implementation technology of TWI Bus under Wire.h-Wire.cpp-(twi.h-twi.c) Libraries. I have tried to understand experimentally the Library Protocols, particularly the Wire.onReceive() and Wire.onRequest() interrupt sub routines, by bringing in the corresponding Register Level Instructions and the Status Words (SWRD). The studies have appeared meaningful and enhanced my understanding on TWI Bus, which I would like to present here in Q/A format.
Q1: The Master sends to the Slave 2 bytes data (say, 0x23 and 0x45). How does the Slave receive them using interrupt sub routine -- the Wire.onReceive().
A1: The Master executes the following Arduino instructions:
Wire.beginTransmission(slaveAddress);
Wire.write(0x23);
Wire.write(0x45);
Wire.endTransmission();
The above Arduino Level instructions could be broken down into the following Register Level Instructions (approximately and conceptually) in order to understand when the Wire.onReceive() ISR is called upon. The full program codes are given at the end of this Section.
TWCR = 0b10100100; //no SCL is ON (TWCR = TWINT TWEA TWSTA TWSTO TWWC TWEN X TWIE)
while(bitRead(TWCR,7)!= HIGH) //detecting the end of process by finding LH at TWINT-bit
;
lcd.print((TWSR & 0b11111000),HEX); //SWRD = 0x08 indicates -- Master has acquired TWI Bus
Reaction of Slave: none.
//---------------------------------------------------------------------------------------------------------------
TWDR = 0b00001110; //slaveAddres+W-bit = 0b0000111 + 0
TWCR = 0b10000100; //9 SCL is ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //SWORD=0x18 -- Slave has recognized its address; creates ACK
Reaction of Slave: Slave is ready to read data from Master, which are coming next. The expected SWRD that has been generated in the TWSR of the Slave is 0x60. The Slave has kept interrupt logic disabled; it will be enabled when needed.
//----------------------------------------------------------------------------------------------------------------
TWDR = 0x23; //sending data byte 0x23 to the Slave
TWCR = 0b10000100; //9 SCL in ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //SWRD = 0x28 genertaed in TWSR Register of Master;
//it indicates that the Slave has received data 0x23
Reaction of Slave: It has received data 0x23, and it is saved in a variable x. Slave sends ACK to Master. Expected SWRD 0x80 has been generated in its TWSR Register.
//---------------------------------------------------------------------------------------------------------------
TWDR = 0x45; //2nd data byte 0x45 will be sent to Slave
TWCR = 0b10000100; //9 SCL in ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //SWRD = 0x28 genertaed in TWSR Register of Master;
//it indicates that the Slave has received data 0x45
Reaction of Slave: It has received data 0x45, and it is saved in a variable y. Slave sends ACK to Master. Expected SWRD 0x80 has been generated in its TWSR Register.
//---------------------------------------------------------------------------------------------------------------
TWCR = 0b10010100; //no SCL is ON STOP command; the TWI Bus released
Reaction of Slave: Slave recognized STOP command and accordingly generates SWRD 0xA0. Because Slave knows that STOP command is coming, it enables the interrupt logic before starting the polling of TWINT-bit to detect the end of process. (Pls See Slave Codes)
The TWINT-bit of the TWCR Register shortly assumes LH-state; it interrupts the the MCU. The MCU will go to the ISR(TWI_vect)/Wire.onReceive(), and it will read the value of x and y from the FIFO buffer.
//------------------------------------------------------------------------------------------------------------------
Program Codes for Master
#include<LiquidCrystal.h>
LiquidCrystal lcd(A0, A1, A2, A3, 8, 9);
void setup()
{
lcd.begin(16, 2);
lcd.setCursor(0, 0);
pinMode(13, OUTPUT);
TWBR = 0x02;
TWSR = 0x02;
TWCR = 0b10100100; //no SCL is ON//(TWINT TWEA TWSTA TWSTO TWWC TWEN X TWIE
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //0x08
//--------------------------------------
TWDR = 0b00001110; //slaveAddress = SLA+W-bit = 0b0000111 + 0
TWCR = 0b10000100; //9 SCL is ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //0x18
//------------------------------------------
TWDR = 0x23;
TWCR = 0b10000100; //9 SCL in ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //SWRD = 0x28
//-------------------------------------------------
TWDR = 0x45;
TWCR = 0b10000100; //9 SCL in ON
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //SWRD = 0x28
//-------------------------------------------------
TWCR = 0b10010100; //no SCL is ON STOP command
}
void loop()
{
digitalWrite(13, !digitalRead(13));
delay(1000);
}
Program Codes for Slave
#include<LiquidCrystal.h>
LiquidCrystal lcd(A0, A1, A2, A3, 8,9);
byte x, y;
void setup()
{
TWBR = 0x02; //TWI BUs speed: 200 kHz
TWSR = 0x02;
lcd.begin(16, 2);
lcd.setCursor(0, 0);
pinMode(13, OUTPUT);
// lcd.print("OK");
TWAR = 0b00001110; //slaveAddress
TWCR = 0b11000100; //TWI Interrupt is disabled
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //print: SWRD 0x60 (correct)
//--------------------------------------------
TWCR = 0b11000100; //TWI Interrupt is disabled
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //print: SWRD 0x80 (correct)
x = TWDR; //data byte 0x23 read
lcd.print(x, HEX); //data is shown on LCD
//----------------------------------------------
TWCR = 0b11000100; //TWI Interrupt is disabled
while(bitRead(TWCR,7)!= HIGH)
;
lcd.print((TWSR & 0b11111000),HEX); //print: SWRD 0x80 (correct)
y = TWDR; //data byte 0x45 read
lcd.print(y, HEX); //data is shown on LCD
//----------------------------------------------
TWCR = 0b11000100; //TWI Interrupt is disabled; TWINT-bit cleared
bitSet(TWCR, 0); //TWI interruot is enabled
bitSet(SREG, 7); //Global interrupt bit is enabled
while(bitRead(TWCR,7)!= HIGH)
;
//lcd.print((TWSR & 0b11111000),HEX); //print: SWRD 0xA0(correct)
//The MCU is interrupte; it goes to ISR(TW_vect) which is the same as
//Wire.onReceive() ISR of Wire.h Library
}
void loop()
{
digitalWrite(13, !digitalRead(13));
delay(1000);
}
ISR(TWI_vect)
{
lcd.setCursor(0, 1);
lcd.print(x, HEX);
lcd.print(y, HEX);
}