TWI - TWINT bit in TWCR not understood

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just failed to understand what the role TWINT plays in TWI communication. Firstly, I look up the datasheet of Atmega328p which describes TWINT as following.

 

This bit is set by hardware when the TWI has finished its current job and expects application
software response. If the I-bit in SREG and TWIE in TWCR are set, the MCU will jump to the
TWI Interrupt Vector. While the TWINT Flag is set, the SCL low period is stretched. The TWINT
Flag must be cleared by software by writing a logic one to it. Note that this flag is not automatically
cleared by hardware when executing the interrupt routine. Also note that clearing this flag
starts the operation of the TWI, so all accesses to the TWI Address Register (TWAR), TWI Status
Register (TWSR), and TWI Data Register (TWDR) must be complete before clearing this
flag.

When I read this on the first time, I thought that TWINT looks like an "indicator" that we should write 1 to TWINT to start TWI and waiting for it go 0 which shows TWI finished its job. But when I look at code about TWI on forum, I found they all look like (copied from this thread)

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);	// Send Start
while (!(TWCR & (1<<TWINT)));			// Wait for TWINT set to 1
/* ....... */
TWCR = (1<<TWINT) | (1<<TWEN);	//start transmission

It seems that we are setting TWINT to 1 to trigger the TWI, but after that we still wait it to go high which confuses me quite a lot. So how does the microcontroller know when to start transmission by TWINT indeed?  Thanks.

This topic has a solution.
Last Edited: Sat. Jul 13, 2019 - 01:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

well the answer is all in your snippet from the datasheet, you just missed to put the things together.....

 

The flag is as stated an indicator, but also is a interrupt status bit. The second bold thing states that it is not automatically cleared, so once set by the internal peripheral an interrupt will be fired, but inside the ISR the flag is not automatically cleared by the same peripheral. ( The uart for instance, when you enter ( or exit I am not sure there) the interrupt automatically the interrupt flag is cleared )

Now you have to do that yourself in the firmware by writing a logical 1 to it. And that thus is what you are doing all the time. This to ensure the next interrupt will be fired.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think basically I understood the datasheet as you said and I believe my concern is on how uC know interrupt flag was cleared. Here, I'd like to take another piece of code I have just tested for example to state my questions in another clearer way.

 

TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // Firstly write TWINT to 1
while (!(TWCR & (1 << TWINT)));                   // Q1: But immediately I've to wait for it to become 1? How and When does it become 0?
if (TW_STATUS != TW_START) return twiError();     // Go out of the loop which means TWINT = 1
TWDR = SLA_W;
TWCR = (1 << TWINT) | (1 << TWEN);                // Q2: Writing TWINT to 1 to clear flag, but TWINT does not change at all, how uC know flag is cleared?
while (!(TWCR & (1 << TWINT)));
if (TW_STATUS != TW_MT_SLA_ACK) return twiError();

(Maybe I did not express myself clearly at first, sorry for that.)

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

writing and reading TWINT refers to two different operations - as such, you're not reading/writing TWINT like you would, say, a port bit. As mentioned in the datasheet, the TWI hardware sets the TWINT flag. In reality I'd say there is a flip/flop. So the hardware sets this flip/flop. When you read TWINT, you're reading the state of this flip/flop. When you write a '1' bit to TWINT, you're actually resetting the flip/flop.

 

In the following, two things are happening. 1. the flip/flop is cleared. 2. You're issuing a START operation.

TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // Firstly write TWINT to 1

Immediately after this operation, TWINT is cleared and a Start is issued. This takes a little time. Once done, TWINT is set by the hardware. The next line of code waits for TWINT to be set - ie: that the start operation has completed.