Setting JTD bit in MCUCR

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

I am trying to disable the JTAG port on an ATmega2560 using C code in WinAVR. I have read the documentation which says the JTD bit must be set twice within four clock cycles. I tried the obvious:

MCUCR = (1 << JTD);
MCUCR = (1 << JTD);

which didn't work so I then tried the next obvious thing of setting it more than twice:

MCUCR = (1 << JTD);
MCUCR = (1 << JTD);
MCUCR = (1 << JTD);
MCUCR = (1 << JTD);

which didn't work either. One of the other forum posts said the bit shift may be consuming clock cycles so I tried:

MCUCR = 0x80;
MCUCR = 0x80;

as well as:

MCUCR = 0x80;
MCUCR = 0x80;
MCUCR = 0x80;
MCUCR = 0x80;

which didn't work either. Someone mentioned that it may have to do with compiler optimizations.

I believe the right way to address it would be to use inline assembly statements. I read the documentation and I'm not exactly sure how to use the asm function.

I tried the following:

asm volatile ("sbi 0x0E,2;");

as a sample and KNOW that it sets bit 2 on PORTE. When I try:

asm volatile ("sbi 0x35,7;");

which is what I believe logically needs to be done, I get the error message "number must be than 32" (for the register).

Can anyone provide the proper syntax on how to set the JTD bit using inline asm code?

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

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch
Thanks for the reply - I read this post prior to posting my question. I have not yet tried the -Os optimization setting. I figured a 'safer', more predictable approach would be to use assembly code. Maybe I should have requested a tutorial on the inline asm command and how to deal with registers greater than 31.

Can anyone weigh in on optimization vs. assembly or how to implement in assembly?

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

Quote:

I have not yet tried the -Os optimization setting.

So it was easier to construct a post (in the general Forum instead of the GCC Forum) and to wait for a reply and post this response?

Quote:

I figured a 'safer', more predictable approach would be to use assembly code.

Are you sure that WinAVR has not provided a "foolproof" way of doing this? There was a fairly extensive thread on this not too long ago https://www.avrfreaks.net/index.p... where I was soundly put into right-think. Surely if I got lambasted that hard about CLKPR there must be something for JTD? [Hmmm--re-reading the thread I don't see answers to my query about handling the other entries in the list of clock-sensitive sequences.]

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

0x35 is outside the address range of SBI. You will need to use out (which means that you need to use a temporary register).

Regards,
Steve A.

The Board helps those that help themselves.

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

Lee, I don't think a proper macro for twiddling JTD exists yet in avr-libc.

However, a macro such as this ought to work, and be guaranteed regardless of optimization level, and safe from interruption:

#define jtd_set(x) \
{ \
        __asm__ __volatile__ ( \
                "in __tmp_reg__,__SREG__" "\n\t" \
                "cli" "\n\t" \
                "out %1, %0" "\n\t" \
                "out __SREG__, __tmp_reg__" "\n\t"\
                "out %1, %0" "\n\t" \
                : /* no outputs */ \
                : "r" ((uint8_t)(x ? (1<<JTD) : 0)), \
                  "M" (_SFR_IO_ADDR(MCUCR)) \
                : "r0"); \
}

Pass the macro either true or false, depending on whether you want to disable the jtag (true) or enable it (false).

But this has evolved into a discussion of inline assembly and most definitely qualifies as a GCC-specific discussion. So if a mod wouldn't mind moving it into the avr-gcc forum, I think all the non-GCC users would thank you.

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

[Sigh...and I got lambasted about the "trial&error hack" defending the CV Wizard code that used a #pragma. No wonder--the above is perfectly-clear to the new user, and obvious to implement. There you go, attigeek!]

Luke--why would you turn interrupts back on before the second JTD?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
[Sigh...and I got lambasted about the "trial&error hack" defending the CV Wizard code that used a #pragma. No wonder--the above is perfectly-clear to the new user, and obvious to implement. There you go, attigeek!]

Luke--why would you turn interrupts back on before the second JTD?

So that I spend the absolute minimum possible amount of time in an interrupt-inhibited state.

There was a lengthy discussion about this in the past with regards to GCC automatically inhibiting and re-enabling interrupts surrounding its direct manipulations of the stack pointer during function entry and exit to allocate space for local variables. Basically, following any 0->1 transition of the I bit in SREG (regardless of the cause) the AVR always runs at least 1 more instruction from the current line of execution before any interruption is possible.

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

Oh, now THAT is pretty sneaky. I hope with all the new models that Atmel doesn't figure out a way to relax that restriction to get interrupts invoked faster. ;)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Is there a way to ensure the required timing in pure C? I don't believe so, but am willing to be proved wrong. Even tricks involving using register variables and volatile aren't guaranteed to work. IMHO this is one of those occasions when the only solution is to use assembler. (Which will no doubt please js no end :wink: )

Jim

Your message here - reasonable rates.

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

Quote:
Is there a way to ensure the required timing in pure C?

No. Time of execution of any statement is outside the scope of C.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Quote:
Is there a way to ensure the required timing in pure C?

No. Time of execution of any statement is outside the scope of C.

Outside the scope of C, agreed.
With OP's compiler, agreed.
Referencing the lambasting thread above, with my compiler brand, certain #pragma manipulations, simple expressions, and the inherent volatile nature of I/O register names it is "ensured" with C. (Are #pragma's "pure C"?) "Guaranteed" forever under all possible compiler rewrites--noone can know that. But I feel confident enough to do all of my production cycle-critical sequences in straight C. [As I mentioned in the other thread, most (all? nearly all?) of these in my apps are set-it-and-forget-it: one-time CLKPR setup; one-time WDT setup. EEPROM is taken care of in the compiler-provided primitives. I do JTD with fuse so never bother with it. No SPM so no considerations there. YMMV]

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Thanks to everyone that has weighed in on this. Here's some feedback on my end:

1) I tried the -Os optimization along with:

MCUCR = (1 << JTD);
MCUCR = (1 << JTD);

which still did not work, but:

MCUCR = 0x80; 
MCUCR = 0x80;

did in fact work! I also noticed that it sped up the execution of my code. I have a heartbeat (activity) LED as part of my PCB that blinked noticably quicker. The -Os setting also seemed to affect a sprintf command that I was using to format a response message. The sprintf message now results in some garbage characters at the end of the string. If I return to the -O0 setting I do not get this. I tried a couple of non-specific things to work around this but I could not seem to get rid of the garbage under the -Os setting. It does not help that I do not have a formal background in C programming and I am probably overlooking something obvious. I would welcome any constructive suggestions as I would like to run the uC at full speed and now that I have discovered the benefit of the -Os setting I would like to stick with it.

2) The suggested macro from lfmorrison (Luke?):

#define jtd_set(x) \ 
{ \ 
        __asm__ __volatile__ ( \ 
                "in __tmp_reg__,__SREG__" "\n\t" \ 
                "cli" "\n\t" \ 
                "out %1, %0" "\n\t" \ 
                "out __SREG__, __tmp_reg__" "\n\t"\ 
                "out %1, %0" "\n\t" \ 
                : /* no outputs */ \ 
                : "r" ((uint8_t)(x ? (1<<JTD) : 0)), \ 
                  "M" (_SFR_IO_ADDR(MCUCR)) \ 
                : "r0"); \ 
} 

worked like a champ regardless of the -Os or -O0 setting. It did however generate roughly a dozen or so warnings (NO errors) during the compile for those who are interested. I'm not sure I understand exactly what the macro is doing but it does work and only needs to be called once.

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

1) Those are TOTALLY identical - look at the generated assembler and you'll see this. For example, here are two functions that demonstrate this:

void setJTD1(void) {
  9c:	80 e8       	ldi	r24, 0x80	; 128
  9e:	85 bf       	out	0x35, r24	; 53
	MCUCR = (1<<JTD);
	MCUCR = (1<<JTD);
  a0:	85 bf       	out	0x35, r24	; 53
  a2:	08 95       	ret

000000a4 :
}

void setJTD2(void) {
  a4:	80 e8       	ldi	r24, 0x80	; 128
  a6:	85 bf       	out	0x35, r24	; 53
	MCUCR = 0x80;
	MCUCR = 0x80;
  a8:	85 bf       	out	0x35, r24	; 53
  aa:	08 95       	ret

Oh and just for the record this is why the code doesn't work if built -O0 rather than -Os:

void setJTD1(void) {
  f4:	cf 93       	push	r28
  f6:	df 93       	push	r29
  f8:	cd b7       	in	r28, 0x3d	; 61
  fa:	de b7       	in	r29, 0x3e	; 62
	MCUCR = (1<<JTD);
  fc:	e5 e5       	ldi	r30, 0x55	; 85
  fe:	f0 e0       	ldi	r31, 0x00	; 0
 100:	80 e8       	ldi	r24, 0x80	; 128
 102:	80 83       	st	Z, r24
	MCUCR = (1<<JTD);
 104:	e5 e5       	ldi	r30, 0x55	; 85
 106:	f0 e0       	ldi	r31, 0x00	; 0
 108:	80 e8       	ldi	r24, 0x80	; 128
 10a:	80 83       	st	Z, r24
 10c:	df 91       	pop	r29
 10e:	cf 91       	pop	r28
 110:	08 95       	ret

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

FAQ#6: If PORTF pins 4-7 don't seem to work and you are using a megaxx9, JTAG probably needs disabling.

Attachment(s): 

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

I know this is an ancient thread, but the solution is useful to others searching for current problems.

I have used @attigeeks solution of :-

MCUCSR=0x80;
MCUCSR=0x80;

and it works fine (previous attempt of MCUCSR|=_BV(JTD) did not.

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

To preserve other bits in MCUCSR why not

............
register uint8_t temp = MCUCSR;
temp |= _BV(JTD);
MCUCSR = temp;
MCUCSR = temp;
..............

Also I hope MCUCSR is declared volatile someplace so the compiler doesn't optimize out one of the MCUCSR=temp statements!

While I never needed to turn off the jtag to make use of the dedicated 4 pins, it is a good idea to do so just before putting the cpu to sleep to reduce power consumption, and I have done so in a project. (I re-enabled the jtag when waking up.)

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

d.stuchbury wrote:
I know this is an ancient thread, but the solution is useful to others searching for current problems.

I have used @attigeeks solution of :-

MCUCSR=0x80;
MCUCSR=0x80;

and it works fine (previous attempt of MCUCSR|=_BV(JTD) did not.

    MCUCSR |= _BV(JTD);  // read-modify-write
    MCUCSR |= _BV(JTD);  // read-modify-write
...
    MCUCSR = 0x80;       // just write
    MCUCSR = 0x80;       // just write
...
    register uint8_t temp = MCUCSR; // read into a register 
    temp |= _BV(JTD);    // manipulate the register
    MCUCSR = temp;       // just write
    MCUCSR = temp;       // just write

If the avr-gcc Compiler was a little more clever it could possibly manage a read-modify-write in a single instruction. e.g. SBI
The straightforward assignments are often managed 'better' by most compilers. All the same, the '0x80' needs to be put into a register befor you can use OUT.
kscharf's solution will probably work even with avr-gcc in brain-dead mode (-O0)

Note that the 'register' modifier does not guarantee anything in C.

So actually this particular operation is an ideal candidate for a 'avr-libc.a' function.

The alternative is for avr-gcc to alter the brain-dead interpretation of -O0. i.e. allow 100% safe and reliable peephole optimisations, yet not re-arrange code. I will not hold my breath !!

David.

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

Quote:

kscharf's solution will probably work even with avr-gcc in brain-dead mode (-O0)

Ummm--not, according to Cliff's test above.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Quote:

kscharf's solution will probably work even with avr-gcc in brain-dead mode (-O0)

Ummm--not, according to Cliff's test above.

Maybe. Cliff's test uses the move immediate to i/o location method, my code would move a register content to i/o location. If the compiler generates another register to register transfer BEFORE each the i/o move it won't work. Only way to tell is to compile it.

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

Lee,

Cliff was showing the |= generation.

kscharf was usinf a register.

8:            register uint8_t temp = MCUCR; // read into a register 
+00000091:   LDI       R30,0x55       
+00000092:   LDI       R31,0x00       
+00000093:   LDD       R24,Z+0        
9:            temp |= _BV(JTD);    // manipulate the register 
+00000094:   ORI       R24,0x80       
10:           MCUCR = temp;       // just write 
+00000095:   LDI       R30,0x55       
+00000096:   LDI       R31,0x00       
+00000097:   STD       Z+0,R24        
11:           MCUCR = temp;       // just write 
+00000098:   LDI       R30,0x55       
+00000099:   LDI       R31,0x00       
+0000009A:   STD       Z+0,R24        

And sure enough avr-gcc is showing off just how brain-dead it can be. Using two LDIs and an STD makes it 5 cycles in my book. (counting the one cycle from the previous STD)
I am never too sure how to count the 4-cycle limit.

Edit. Yes, I can confirm that the above C sequence does not work for a mega32. i.e. it must count as 5 cycles.

David.

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

Yeah that IS brain dead. It is loading Z THREE TIMES to access the MCUCR when ONE will do. Heck, what I would do is to write my own assembly language function that returns nothing and takes nothing. It would only have to have 7 instructions and would use the 'temp' register. Would be callable from "C".

IE:
NOJTAG.S
global NoJtag
NoJtag:
LDI R30,0x55
LDI R31,0x00
LDD R24,Z+0
ORI R0,0x80
STD Z+0,R0
STD Z+0,R0
RET

Actually to be truly C compatible it might have to first save the 'Z' register and restore it on the way out.

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

Quote:

Cliff was showing the |= generation.

Am I going blind?
Quote:

Oh and just for the record this is why the code doesn't work if built -O0 rather than -Os:
Code:
void setJTD1(void) {
f4: cf 93 push r28
f6: df 93 push r29
f8: cd b7 in r28, 0x3d ; 61
fa: de b7 in r29, 0x3e ; 62
MCUCR = (1<<JTD);
fc: e5 e5 ldi r30, 0x55 ; 85
fe: f0 e0 ldi r31, 0x00 ; 0
100: 80 e8 ldi r24, 0x80 ; 128
102: 80 83 st Z, r24
MCUCR = (1<<JTD);
104: e5 e5 ldi r30, 0x55 ; 85
106: f0 e0 ldi r31, 0x00 ; 0
108: 80 e8 ldi r24, 0x80 ; 128
10a: 80 83 st Z, r24
10c: df 91 pop r29
10e: cf 91 pop r28
110: 08 95 ret

Not an |= in sight, that I can see.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I built it with gcc 01 optimisation and it definately works in C using MCUCSR=0x80. In my instance I don't care about the other bits.

I am suprised their isn't better Atmel / compiler support for this, because without using some method like this you can't get the micro to sleep properly. Before getting this working the best power save mode sleep current I could get was 150uA, now the JTAG is disabled (in sleep only) I get 20uA. I switch the bits zero again on wake-up.
In my instance I use a AVR JTAG MKII, so if I switch off the fuses, I get an un-programmable device.

Writing to this register in C without checout ORing the contents is dicey (OK in my instance) and deep diving into assebler isn't for everybody, espcially for a 'standard' feature of sleep.

By the way, thanks everybody for the mass of responses.

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

d.stuchbury wrote:
In my instance I use a AVR JTAG MKII, so if I switch off the fuses, I get an un-programmable device.

The MKII comes with the squid cable so you could always reprogram the fuses using the ISP or PDI (xmega) if necessary. I've 'lost' the jtag on several xmega cpu's and had to reprogram the fuses using the PDI. Thankfully I had the squid cable and the newer version of the jtag that does PDI so the processor was recoverable. I did have to solder one wire to the cpu (thankfully was a TQFP and not a BGA!)

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

theusch wrote:
Quote:

Cliff was showing the |= generation.

Am I going blind?
Not an |= in sight, that I can see.

Oops. My mistake. Cliff's example was assigning an immediate value not an 'OR' in.

Seeing as how any normal human being can understand:

     sbi MCUCR,JTD
     sbi MCUCR,JTD

or

     ldi r24,(1<<JTD)
     out MCUCR,r24 
     out MCUCR,r24 

it is clear that avr-gcc performs brain-death intentionally.

As far as I know, IAR, CV, ImageCraft can not be persuaded to generate the extent of brain death achieved by avr-gcc with any optimisation setting. But hey-ho, avr-gcc is cheap.

David.

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

Hi there, I've tried disabling JTAG by setting the JTD bit using lfmorrison's method above (inline assembly macro), and have confirmed that the instructions appear in the list file when I use it. However the only way I seem to be able to enable the desired pins for GPIO use is by clearing the JTAGEN and OCDEN fuse bits. According to the datasheet, this shouldn't be the case (setting JTD should do the trick). Has anyone had this problem? I'm testing PORTC of my atmega32 by simply toggling all the bits' states, and PORTC pins 2-5 don't toggle unless JTAG is disabled via the fuse bits.

Here's my main:

int main(void)
{

	//PORT A pin 1 = output LED
	DDRA = 0x01;
	PORTA = 0x00;
	DDRC = 0xff;
	PORTC = 0xFF;

	int i = 0;
	jtd_set(1);	//disable JTAG so that portC is available for GPIO
	// send a message once per second
	while(1)
	{
		//crap delay
		for (i = 0; i < 30000; i++)
		{
			i+=1;
			i-=1;
		}
		for (i = 0; i < 30000; i++)
		{
			i+=1;
			i-=1;
		}

		PORTA ^= 0x1; // toggle status LED
		PORTC ^= 0xff;
	}

	return 0;
}