32UC3A TWI Status Register Dummy Read in C

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

I've been working with some TWI sample code for a 32UC3A. In the TWI Init Routine, I have the following:

	// Disable TWI interrupts
	cpu_irq_disable();
80002294:	d3 03       	ssrf	0x10
	twi->idr = ~0UL;	//idr = Interrupt Disable Register - Write Only.  For whatever reason, this MCU has an IDR and an IER Interrupt Disable and Enable Only.  
80002296:	3f f9       	mov	r9,-1
80002298:	99 a9       	st.w	r12[0x28],r9
						//There is also an IMR - Interrupt Mask register, which allows reading of Interrupt Enable/Disable... WTF?
						// IDR and IER are Write Only
						// IMR is Read Only
	twi->sr;	// What is this??  Why?  "Dummy Read" as noted elsewhere?
8000229a:	78 89       	ld.w	r9,r12[0x20]
	//The only affect of doing this is clearing the flags in SR that are "Clear On Read", which include GACC, OVRE, NACK, ARBLST and EOSACC,  
	//NOTHING is done with the read value...  See the next statement, r9 get's overwritten without ever being used.
//8000229a:	78 89       	ld.w	r9,r12[0x20]	

	// Reset TWI
	twi->cr = AVR32_TWI_CR_SWRST_MASK;
8000229c:	e0 69 00 80 	mov	r9,128
800022a0:	99 09       	st.w	r12[0x0],r9

This line:

twi->sr; // What is this?? Why?
8000229a: 78 89 ld.w r9,r12[0x20]

Confuses me. Looking at the compiled code, helped explain WHAT it does, which as far as I can see the only result is that 5 status bits will be cleared when it's read.

What really is throwing me off is the presence of what appears to me to be essentially a line of code comprised of nothing but a variable. I conducted another test, with a single lone variable on a line (that wasn't associated with a register), and everything still compiled fine. However, no corresponding machine instruction was generated for it.

Can anyone offer some insight into this situation? What it means to have nothing but a variable on a single line, why one case generates code that reads a register, and the other nothing?

I'm using Atmel Studio 6.1, AVR/GNU Toolchain

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

You don't show the declaration of twi but from your results I'd bet you declared it from a definition from Atmel supplied headers. If you trace this back to its definition you'll find the keyword volatile in there somewhere. This keeps the compiler from optimizing it away. Add volatile to the declaration of your other variable and you should see similar results.

Letting the smoke out since 1978

 

 

 

 

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

Thanks for the direction! Retested with your suggestions, and as you said, it is declared as volatile.

TWI Declaration:

int twi_master_init(volatile avr32_twi_t *twi, const twi_options_t *opt)

I retested the second variable after adding the volatile keyword and code was generated for it this time.

// TEST CODE
	status;
800022cc:	40 08       	lddsp	r8,sp[0x0]
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've acquired a little more insight into the purpose of the code in my original post. Just thought I'd update the post in case anyone else ran into this as well.

From what I can tell, this status register dummy read is what is referred to as a Data Memory Barrier in the AVR32UC Technical Reference and is particularly applicable to use in interrupt handlers.

It is described as follows:
"A data memory barrier (DMB) is used to make sure that a data memory access, either a read or
write, is actually performed before the rest of the code is executed. Caches, write buffers and bus latency may cause a memory access to be seen by a slave many cycles after it has been
executed by the pipeline. In some cases, this may lead to UNPREDICTABLE behavior in the system."

Essentially, it is to ensure that the interrupt request flags have been cleared before returning from the interrupt. Code execution will stall on the read until the write is complete.

32002F–03/2010 Page 65