JTAG / SWD Documentation

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

JTAG / SWD Documentation

6,387 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Thu Nov 13 11:50:17 MST 2014
Hello,

I'm looking for documentation regarding JTAG or SWD for programming an LPC4337. I wish to program this device using another microcontroller. In my case, USART0 and USART3 are not available for IAP. If you could send me in the right direction I would appreciate.

Thank you
Labels (1)
0 Kudos
32 Replies

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Tue Dec 09 13:13:57 MST 2014
The answer to my last question is:

You don't need to worry about that. The boot routines automatically handle this issue. You just need to make sure you vector table is at the beginning of the flash bank you are using (0x1A000000 or 0x1B000000). At the position 0x04 you will find the reset vector which will point to the entry point address.

Thank you for your help in this 2 week odyssey. This is indeed the hard way of flashing the LPC4337.

By the way, sometimes I get an error in the IAP COMPARE function (not equal). Any idea of what causes this problem?

Thank you
0 Kudos

3,723 Views
TEMCEFF
Contributor IV

Can you please share the source code. Actually i'm trying to build SWD using GPIOs.

0 Kudos

3,723 Views
converse
Senior Contributor V
0 Kudos

3,723 Views
TEMCEFF
Contributor IV

Thanks for your reply. I will go through the link.

0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Sun Dec 07 05:12:03 MST 2014
Hello,

Problem solved! Now I have my application loaded into the flash. What I'm finding difficult to understand is how I'm going to setup the initial address. I know that the initial address should be 0x1A004249 and this information should be located in the reset vector which is at 0x00000004.

How can I write the vector table?

Thank you
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Wed Dec 03 01:27:48 MST 2014
Did you actually check (with normal code) to see if the sector(s) is(are) actually blank or not.
And (stupid question) are you completely sure that you blank check the same sector(s)
that you erased.

Apart from that, I can't think of anything else.

Note: blank check returns also two results: offset to 1st non-blank and the value read there.

From the LPC1778 manual:
This command must be executed before executing "Copy RAM to Flash" or "Erase Sector(s)" command. 
Successful execution of the "Copy RAM to Flash" or "Erase Sector(s)" command causes relevant sectors to 
be protected again. To prepare a single sector use the same "Start" and "End" sector numbers.


Mike
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Tue Dec 02 18:51:11 MST 2014
Thank you for your inputs

My erasing sequence is:

-> INIT................................................................CMD_SUCCESS
-> BLANK CHECK (if blank return).....................SECTOR_NOT_BLANK
-> PREPARE......................................................CMD_SUCCESS
-> ERASE...........................................................CMD_SUCCESS
-> BLANK CHECK..............................................SECTOR_NOT_BLANK


As far as I know, the PREPARE command already deactivates the memory protection. Is there anything else that I should take care of?

Thank you
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Tue Dec 02 15:46:44 MST 2014
Well, now that you have done the hard part (the SWD interface), this is a 'normal' program debugging scenario.
There are many posts/threads on IAP here that you can look for.

Do you need to 'prepare' again before a blank check'?

However, I seem to remember that I had issues with the sector not blank error,
so (for this error only) I do a code based blank check along these lines ...
    tmp = 0xFFFFFFFF;
    for (p = start, n = wordCount; n--; )
        tmp &= *p++;
    return(tmp == 0xFFFFFFFF? good: ohPooh);


Invariably, I find that the sector is blank after all.

EDIT: I checked my code. I do a blank check before the erase (and skip if already blank).
After the erase, I was always getting the 'busy' error. It is in that case that I do the another blank check.

;-----------------------------------------------------------------------!
; Erase Flash!
;-----------------------------------------------------------------------!

; r0 = start sector, r1 = sector count

fn FLZap

push{r7,lr};
ldrr7, =cmdBuff;
strr0, [r7, 1*4]; stash first sector
addsr0, r1; calc last sector
subsr0, 1; first+count-1
strr0, [r7, 2*4]; stash last sector
ldrr0, =clkKHz; get   clock speed
strr0, [r7, 3*4]; stash clock speed

;---------------------------------------;
movsr0, 53; blank check
strr0, [r7];
movsr0, r7; 'in'  parameters
addsr1, r7,  5*4; 'out' parameters
blGoIAP;
ldrr0, [r7, 5*4]; get status code
cbzr0, 9f; skip erase if blank

;---------------------------------------;
movsr0, 50; prepare
strr0, [r7];
movsr0, r7; 'in'  parameters
addsr1, r7,  5*4; 'out' parameters
blGoIAP;
ldrr0, [r7, 5*4]; get status code
cbnzr0, 9f; OOPS -- IAP failed

movsr0, 52; erase
strr0, [r7];
movsr0, r7; 'in'  parameters
addsr1, r7,  5*4; 'out' parameters
blGoIAP;
ldrr0, [r7, 5*4]; get status code
cmpr0, 11; is it lying about being 'busy'?
bne9f; nope

;---------------------------------------;
movsr0, 53; yup -- is it actually blank?
strr0, [r7];
movsr0, r7; 'in'  parameters
addsr1, r7,  5*4; 'out' parameters
blGoIAP;
ldrr0, [r7, 5*4]; get status code
;cbnzr0, 9f; OOPS -- IAP failed

;---------------------------------------;
9:pop{r7,pc}; return (zero == success)

fe FLZap

;-----------------------------------------------------------------------!
; IAP Invoke Wrapper!
;-----------------------------------------------------------------------!

fn GoIAP

push{lr};
ldrr12, =IAP; get abs entry point
cpsidi; let's try disabling interrupts
blxr12; go IAP
cpsiei; and re-enable
pop{pc}; return

fe GoIAP



HTH, Mike
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Tue Dec 02 10:49:03 MST 2014
Hello!

Actually the document you recommended solved my problem. In the documentation I was reading there wasn't any reference to the "REGWnR" bit in the DCRSR register. This was my problem.. When you want to write you need to set it.

Am I the only one that sometimes feels lost in the ARM documentation?

At this moment my flashloader program is responding. I'm able to get the "part id" and the "code version" by asking my flashloader to invoke the IAP with the correct arguments.

However when I try to erase sectors, the program counter gets stuck at 0x10400FDA (somewhere inside the ROM area). I have initialized the VTOR register with the address of the ISR vector aligned to 0x80 defined in the linker file

    /* MAIN TEXT SECTION */   
    .text 0x10000180 : ALIGN(4)
    {
        FILL(0xff)
        __vectors_start__ = ABSOLUTE(.) ;
        KEEP(*(.isr_vector))
       
        /* Global Section Table */
        . = ALIGN(4) ;
        __section_table_start = .;
        __data_section_table = .;
        LONG(LOADADDR(.data));


EDIT:

I forgot to initialize the clock parameter of the erase function.

Now the program counter does not get stuck. Returns CMD_SUCCESS but when I execute the BLANK_CHECK after the erase it returns SECTOR_NOT_BLANK
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Mon Dec 01 23:25:11 MST 2014

Quote: v0ynich
Thank you for your reply

By "providing a stack" you mean set an address in the Stack Pointer to the upper part of the RAM which is not being used for anything else, right?

Regarding VTOR: No, I didn't initialized that register. I will take a look.

I also noticed that by reading the DFSR register I'm getting 0x00000001 which means (I think) an Alignment Fault in a read instruction. Does this mean that I'm trying to read something that it is not word aligned? How am I supposed to clear this fault? By writing 0 to DFSR?

Many thanks



Provided you write the stack pointer with an address which allows for adequate driver stack space, you should be good. The importance of the VTOR setting is to vector into your own handlers should an exception occur. Ideally, you want no exceptions while the flash driver is operating.

The purpose of the DFSR is to record the reason a debug event occurred. You need to write a 1 to the DFSR bit position you want to clear. If you read a 1 from the DFSR register, it means a debug halt event occurred (likely C_HALT).

Here's a reference to a useful ARM document if you don't already have it.

ARM®v7-M Architecture Reference Manual ARM DDI 0403D-3 (ID011210)

Regards,

LPCXpresso Support.
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Mon Dec 01 17:36:12 MST 2014
Not to worry, I found DBSTATUS in Joseph Yiu's Guide to M3/M4. Arm documents this as DeviceEn and is RO anyway.
Regards, Mike
0 Kudos

3,723 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Mon Dec 01 17:24:36 MST 2014

Quote: v0ynich
Hello,

Yes, I solved it. I needed to set the DBSTATUS, MASTERTYPE and HPROT bits also in the CSW register to be able to access the addresses that were giving me the error. No idea which one made the trick.



What documentation are you using, your register and bit field names do not seem to exactly match the ARM docs I have.
[IHI0031A_ARM_debug_interface_v5.pdf and the ADIv5.1 Supplement]
I searched both for DBSTATUS and came up empty.
Are you allowed to share your CMSIS-DAP modified source? Which source repositry did you start with?

Regards, Mike

0 Kudos

3,805 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Mon Dec 01 16:47:30 MST 2014
Thank you for your reply

By "providing a stack" you mean set an address in the Stack Pointer to the upper part of the RAM which is not being used for anything else, right?

Regarding VTOR: No, I didn't initialized that register. I will take a look.

I also noticed that by reading the DFSR register I'm getting 0x00000001 which means (I think) an Alignment Fault in a read instruction. Does this mean that I'm trying to read something that it is not word aligned? How am I supposed to clear this fault? By writing 0 to DFSR?

Many thanks

0 Kudos

3,813 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Mon Dec 01 11:44:54 MST 2014
ResetISR implementations usually require a stack. Have you provided one? Also, is the VTOR register initialized to your RAM vector table address?

LPCXpresso Support
0 Kudos

3,813 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Mon Dec 01 08:41:16 MST 2014
Hello,

Yes, I solved it. I needed to set the DBSTATUS, MASTERTYPE and HPROT bits also in the CSW register to be able to access the addresses that were giving me the error. No idea which one made the trick.

lpcxpresso-support: The FAULT and OK "responses" in my last post were the 3-bit ACK. Yes, I'm using a customized CMSIS-DAP


At this moment I'm able to run, halt and reset the CPU. A flashloader was loaded to RAM and the program counter set to 0x100002F9 (which is the ResetISR -> entry point according to the .map file) However, I'm facing two problems:

- I'm only able to change the state of the program counter when the CPU is running. If I do it with the CPU halted it has no effect. The previous value remains.

- The program counter stays still (@ 0x100002F9 ResetISR). I have ensured that the CPU is not halted and it is not in sleep mode. The interrupt requests are disabled. If a read the CYCCNT register I can notice that it is being incremented.

Ideas?

Thank you
0 Kudos

3,813 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Mon Dec 01 08:04:23 MST 2014
V0ynich, did you resolve your issue with the debug registers?
If you did, can you share the 'trick' or 'step' required for access?

Regards, Mike
0 Kudos

3,815 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Fri Nov 28 18:26:56 MST 2014

I understand you've got low-level access to SW-DP, but you didn't make it clear what that is. Are you using CMSIS-DAP, or something else? To save time and trouble, our recommendation is to use an existing probe firmware (like CMSIS-DAP). I'd also recommend you not use overrun detection (if indeed it's enabled). We don't believe it's used by CMSIS-DAP. You can determine the success/fail status of the transaction when you read out the 3 bits of ACK. More information on this is found in the ARM documentation.

To halt the part requires you write a DBGKEY value in addition to the C_HALT and C_DEBUGEN bits. If you combine these, the halt "word" you write to DHCSR (0xE000EDF0) is 0xA05F0003. Has this been done?

Regards,
LPCXpresso Support
0 Kudos

3,815 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Fri Nov 28 05:47:00 MST 2014
Hello,

Yes, I'm aware of those blog entries. I'm actually doing the  steps 5 and 6 which are (in my description):

-> Write SELECT with bank pointing to IDR
-> Read IDR

Any attempt of write/read to the ARM private bus (0xE000 0000 to 0xE010 0000) where the DHCSR and other registers are results in FAULT.
Any write or read to the SRAM memory segment works perfectly.

=(

EDIT: Maybe something to do with the Memory Protection Unit (MPU) ?



EDIT2: Maybe this helps to ring a bell

here goes the description of read attempts in several memory segments

32kb local SRAM...................(0x1000 0000 - 0x1000 7FFF) -> OK
Reserved...............................(0x1000 8000 - 0x1007 FFFF) -> FAULT
32+8kb SRAM.......................(0x1008 0000 - 0x1008 9FFF) -> OK
64kb ROM.............................(0x1040 0000 - 0x1040 FFFF) -> OK
Flash Bank A.........................(0x1A00 0000 - 0x1A03 FFFF) -> OK
Flash Bank B.........................(0x1B00 0000 - 0x1A07 FFFF) -> OK
4x16kb AHB SRAM...............(0x2000 0000 - 0x2000 FFFF) -> OK
16kb EEPROM......................(0x2004 0000 - 0x2004 3FFF) -> OK
AHB Peripherals....................(0x4000 0000 - 0x4001 1FFF) -> OK
Clocking/Reset Peripherals...(0x4005 0000 - 0x4005 FFFF) -> OK
APB Peripherals #0...............(0x4008 0000 - 0x4008 FFFF) -> OK
High-speed GPIO..................(0x400F 4000 - 0x400F 7FFF) -> OK

ARM Private Bus...................(0xE000 0000 - 0xE000 0FFF) -> OK
ARM Private Bus...................(0xE000 1000 - 0xE009 FFFF) -> FAULT

This last one, is what I want to read/write in order to halt and run the processor and change the program counter.

Thank you
0 Kudos

3,815 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MikeSimmonds on Thu Nov 27 21:37:47 MST 2014
Did you read the blog linked in post 5? It and the next three are very informative.

Initializing SWD.

The SWD protocol allows full control of an LPC microcontroller. Because of this, it is critical that the port be insensitive to noise under a wide range of design conditions. To make the SWD port insensitive to noise, an unlock or connection sequence must be executed before the port can be used. The unlock sequence consists of several different steps.

SWD Unlock Sequence Steps

step numberdescription
1The Host needs to switch the target from JTAG to SWD mode by clocking 0xE79E onto SWDCLK/SWDIO
2SWD connection sequence- clock out more than 50 binary 1s
3Must read the Debug Port IDCODE register (address 0)
4Turn on Debug Port by settings bits 28 and 30 at DP address 4
5Write AP select (debug port address 8) to 0xF0 (to prep for AP read of 0xFC)
6Unlock Access Port by reading AP ID register (AP address 0xFC)


From your description (code not shown), you may have missed steps 5 and 6.

There are actually 4 parts to this blog, the 4th, here, has code for an LPC1100 'adapter'
that you could take code sequences from.

HTH, Mike
0 Kudos

3,811 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by v0ynich on Thu Nov 27 16:48:12 MST 2014
Hello!

Thank you for your support!

New update:

At this moment and after initialized the SW-DP I'm able to read and write the RAM without any issue. All replies are the expected ones.

However I'm facing some problem when I try to read or write the DHCSR register to halt the core. The target answers "FAULT". By checking the CTRL/STAT register the Overrun flag is set after the read or write of DHCSR. I couldn't find any explanation in the literature for this behaviour.
I'm reading the DHCSR register as if it was normal RAM at address 0xE000EDF0. Do I need to take any special measure before this?

The command sequence:

-> Set reset state
-> JTAG to SWD sequence
-> Set reset state
-> Read IDCODE
-> Write CTRL/STAT with CTRLSTAT_CDBGPWRUPREQ and CTRLSTAT_CSYSPWRUPREQ
-> Read CTRL/STAT
-> Write SELECT with bank pointing to IDR
-> Read IDR
-> Write SELECT with bank that points to CSW, TAR and DRW
-> Write CSW with 0x02 (32bits)
-> Write to RAM
-> Read to RAM
-> Read DHCSR ---> FAULT

Any tips?

Thank you
0 Kudos