Trying to avoid JTAG conflict with ATMEGA6450

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

I'm using the 6450 in an application that requires every single IO line, including the JTAG ones on port F.  Those particular pins read some DIP switches via the following code:

char read_switches(void){
    char s;
    JTD_Clear();    // Disable JTAG interface
    s = (PINF & 0x70);
    JTD_Set();      // Re-enable JTAG interface
    return s;
}

void JTD_Set(void) {
    char x = 0;

// JTD isn't supposed to be changed if OCDEN is programmed (== 0),
// so test it and only set JTD if it's unprogrammed (== 1).

    x = read_fuse();    // Read fuse high byte to check OCDEN
    if ((x & (1 << OCDEN)) != 0) {
        SREG &= 0x7ff;      // Disable interrupts to insure uninterrupted write to MCUCR.
        MCUCR |= 0x80;  // Set JTD to disable JTAG interface
        MCUCR |= 0x80;  // Must write it twice within 4 cycles
        SREG |= 0x80;   // Re-enable interrupts
    }
}

void JTD_Clear(void) {
    char x = 0;

// JTD isn't supposed to be changed if OCDEN is programmed (== 0),
// so test it and only clear JTD if OCDEN's unprogrammed (== 1).

    x = read_fuse();    // Read fuse high byte to check OCDEN
    if ((x & (1 << OCDEN)) != 0) {
        SREG &= 0x7ff;      // Disable interrupts to insure uninterrupted write to MCUCR.
        MCUCR &= 0x7f;  // Clear JTD to enable JTAG interface
        MCUCR &= 0x7f;  // Must write it twice within 4 cycles
        SREG |= 0x80;   // Re-enable interrupts
    }
}

char read_fuse(void) {
//  point z to 0x0003 (high fuse byte )
asm("ldi R31,0x00\n"
"ldi  R30,0x03\n"
"ldi  R16,0x09\n"
"out  0x37,R16\n"
"lpm  R16,z\n"
"ret\n");
}

read_switches() is executed once per second and should prevent reads during debug sessions, which would disrupt the JTAG interface.  I'm willing to live with the inability to use the debugger to debug my switch-related code.  What I'm wondering is, what would happen in the (admittedly unlikely) event of my debugger (or programmer) trying to establish a connection during the brief period in JTD_set() after OCDEN is tested and JTD is set?  I could move the disable interrupts line to before the test, to reduce the window of exposure, but it doesn't seem like I can eliminate it completely, which, of course, would be my preference.  Is there a potential hosing in store for me (here or anyplace else you notice)?  Thanks for your help.

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

You also have an inherent problem when any of those switches (the ones shared with JTAG) is closed during the time that JTAG is in use. Switch closed = JTAG no work. No way to avoid that I can see. 

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Yes, aware of that, too.  That''s why I got everything else working first and saved the switch testing for the end of the project.  Hopefully I can avoid bricking the CPU at this point.

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

Use 1K resistors in series with the DIP switch, then you can use the JTAG for debugging (use a "software" switch while doing that) and when finished use the real switches.

 

I usually have a conditional switch to disable JTAG in release version.

 

Edit Found diagram snippet

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Mon. Jul 3, 2017 - 08:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, js.  That solves the h/w problem between the switches and JTAG i/f, but I'm still wondering if my code protects me from a conflict between OCDEN/JTD and the JTAG pod trying to connect to the CPU.

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

How about not using the JTAG for production releases, opting for a bootloader instead, and if you're using a UART anywhere use that for debugging (i.e printf() debugging)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
        MCUCR &= 0x7f;  // Clear JTD to enable JTAG interface
        MCUCR &= 0x7f;  // Must write it twice within 4 cycles

This is WRONG, you need to write a 1 to the JTD bit. I must run now but "I'll be back" later on in the day.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Howard_Smith wrote:

How about not using the JTAG for production releases, opting for a bootloader instead, and if you're using a UART anywhere use that for debugging (i.e printf() debugging)?

I'm probably only making a couple of these things, 25 at most.  Once the code is done, I can ensure the switches are off during programming.  Not using the UART; its pins are committed.

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

js wrote:

        MCUCR &= 0x7f;  // Clear JTD to enable JTAG interface
        MCUCR &= 0x7f;  // Must write it twice within 4 cycles

This is WRONG, you need to write a 1 to the JTD bit. I must run now but "I'll be back" later on in the day.

Per the 6450 datasheet (2570N–AVR–05/11), section 25.5.1:  

• Bit 7 – JTD: JTAG Interface Disable
When this bit is zero, the JTAG interface is enabled if the JTAGEN Fuse is programmed. 
If this bit is one, the JTAG interface is disabled. In order to avoid unintentional 
disabling or enabling of the JTAG interface, a timed sequence must be followed when 
changing this bit: The application software must write this bit to the desired value 
twice within four cycles to change its value. Note that this bit must not be altered 
when using the On-chip Debug system.

What's wrong?

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

What's wrong?

 The next 2 lines in my datasheet say:

If the JTAG interface is left unconnected to other JTAG circuitry, the JTD bit should be set to one.

also 10.8.7 JTAG Interface and On-chip Debug System
 

Writing the JTD bit in the MCUCSR register to one or leaving the JTAG fuse unprogrammed disables the JTAG interface.

 

by looking at your code again I see that you are inverting the bits and this is confusing me, so maybe it is doing what is supposed to do.

 

I use

int	main(void)
{

#if debug==0
	MCUCR = (1<<JTD); 							//Disable JTAG in run mode
	MCUCR = (1<<JTD); 
#endif

// PORTA All inputs with pullups
	DDRA = 0x00;
	PORTA = 0xff;

 

edit (above) and I only do this ONCE at the beginning of the code, turning on and off is likely to crash things.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Tue. Jul 4, 2017 - 04:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JTD_Set() and JTD_Clear() seem to me to do what they're supposed to do, except you made me realize I'm invoking them in the wrong order. Thanks.

As for leaving JTD = 1 for production, I hadn't thought about that, so thanks also for pointing it out. I assume it's OK to violate the note during development since you wouldn't be able to connect an ICE if you always had JTD = 1.

Finally, I'm not sure what you mean when you say I'm "inverting" the bits. I'm just preserving the bits I don't want to change and changing the one that I do. Wouldn't MCUCR = (1<<JTD); place a 1 in bit 7 (JTD) and zero out the rest (well, the writeable ones)?

Last Edited: Tue. Jul 4, 2017 - 06:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you wouldn't be able to connect an ICE if you always had JTD = 1.

No problem if you bring out the reset pin to the JTAG header, JTAG will assert reset and allows for reprogramming or further debugging if necessary.

 

I see now that you have

MCUCR |= 0x80;  // Set JTD to disable JTAG interface
MCUCR |= 0x80;  // Must write it twice within 4 cycles

blush which is equivalent to MCUCR = (1<<JTD); except that the later tells you EXACTLY which bit you are messing with. wink

 

I was only looking at the lines with

        MCUCR &= 0x7f;  // Clear JTD to enable JTAG interface
        MCUCR &= 0x7f;  // Must write it twice within 4 cycles

which of course I would never use. Just disable JTAG in software in the release version, you can still get a hold of the chip if you bring out the reset line to the JTAG header as explained above.

 

At least that's what I have been doing since "ye olde" JTAG Mk1 was around.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

js wrote:
which is equivalent to MCUCR
Except that it isn't. You use '=', he uses '|='. The latter is a read-modify-write and will have a much harder job meeting the 4 cycle timing requirement. Far better to just assign 0x80 to the register to set the bit - I don't think there's anything else in the register that cares/matters if other bits are written at the same time.

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

The latter is a read-modify-write and will have a much harder job meeting the 4 cycle timing requirement.

You see? I was 100% correct, I was confused.....

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

clawson wrote:

I don't think there's anything else in the register that cares/matters if other bits are written at the same time.

The other bits are currently 0, which is how I'd currently like them to remain.  For future proofing, though, maybe something like this would be better:

void JTD_Set(void) {
    char x = 0, MCUCR_x;
    MCUCR_x = MCUCR | (1 << JTD);
    x = read_fuse();    // Read fuse high byte to check OCDEN
    SREG &= 0x7ff;      // Disable interrupts to insure uninterrupted write to MCUCR.

// JTD isn't supposed to be changed if OCDEN is programmed (== 0),
// so test OCDEN and only set JTD if OCDEN's unprogrammed (== 1).

    if ((x & (1 << OCDEN)) != 0) {
        MCUCR = MCUCR_s;  // Set JTD to disable JTAG interface
        MCUCR = MCUCR_s;  // Must write it twice within 4 cycles
    }
    SREG |= 0x80;   // Re-enable interrupts
}

 

js wrote:

No problem if you bring out the reset pin to the JTAG header, 

 

I also have RESET brought out to the JTAG header.  So, that allows the ICE to override the JTD bit disabling the JTAG interface?

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

So, that allows the ICE to override the JTD bit disabling the JTAG interface?

Yep.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Have you ever actually tried it, js?  I bricked a couple of CPUs earlier in this project and I'm pretty sure it's because my code disabled the JTAG interface via the JTD bit without re-enabling it, but you say that shouldn't have mattered.

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

Have you ever actually tried it, js?

 At least that's what I have been doing since "ye olde" JTAG Mk1 was around.

 I bricked a couple of CPUs earlier in this project and I'm pretty sure it's because my code disabled the JTAG.....but you say that shouldn't have mattered. 

Correct as long as the reset pin is on the JTAG header.

 

The programmer will complain that JTAG is disabled and then it asks you if you want to use the external reset or something along those line.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Wed. Jul 5, 2017 - 09:54 PM