Sunday, July 23rd 2017, 10:43pm UTC+2

You are not logged in.

  • Login
  • Register

Dear visitor, welcome to SEGGER Forum. If this is your first visit here, please read the Help. It explains how this page works. You must be registered before you can use all the page's features. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

1

Monday, December 5th 2011, 10:56am

STM32F2 + SWO + JLINK + JLINK server + GDB client elf console

Hi,

I am trying to get debug messages out to GDB elf/prorgam console when debuging:
I am using STM32F207IG CPU. The init code looks like:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
uint32_t SWOSpeed = 19200; //Baud rate
uint32_t SWOPrescaler = (120000000 / SWOSpeed) - 1; // SWOSpeed in Hz
CoreDebug->DEMCR = 1<<CoreDebug_DEMCR_TRCENA_Pos;
DBGMCU->CR = 0x00000027; //Enabling TRACE_IOEN, DBG_STANDBY, DBG_STOP, DBG_SLEEP
//Set TPIU register->Selected pinprotocol = 10b: Serial Wire Output - NRZ
*((volatile unsigned *) 0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
//Set TPIU -> Async Clock Prescaler Register [bits 0-12]
*((volatile unsigned *) 0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
//Lock Access Register
*((volatile unsigned *) 0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
*((volatile unsigned *) 0xE0000E80) = 0x0001000D; // ITM Trace Control Register
*((volatile unsigned *) 0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register
*((volatile unsigned *) 0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
*((volatile unsigned *) 0xE0001000) = 0x400003FE; // DWT_CTRL
//And this is really tricky! No document for this register at ARM site.
*((volatile unsigned *) 0xE0040304) = 0x00000100; // Formatter and Flush Control Register

uint8_t buf[]="Some text to print out the console";

while(buf!=0) {
 if (CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) // Trace enabled
 {
  if (ITM->TCR & ITM_TCR_ITMENA_Msk) // ITM enabled
  {
   if (ITM->TER & (1ul << 0)) // ITM Port #0 enabled 
   {
   while (ITM->PORT[0].u32 == 0) ;
   ITM->PORT[0].u8 = (uint8_t) *buf;
   }
  }
 }
buf++;
}


The messages/data are going out from CPU at baud speed 19200. When i start JLink.exe and type SWOStart, i can see in SWV control panel that data is arriving 8) .

I need few things:
1.] How to enable SWV support on JLINK GDB server. By typing:
JLinkGDBServerCL.exe -SWOPort 4444
it opens the port 4444 but no messages are inside. Maybe missing protocol ?(

2.] What kind of protocol i have to use to transfer data/messages between CPU a GDB elf console.
Somehow it must work :!: becouse i can clearly see that GDB server sends some messages to client side console like:
Resetting target...and so on


3.] How can i change the baud rate from 19200 to something else?
Is there any documentation about that part? Because i cant find them in standart Docs, and in your market brosure you writing:
Serial Wire Debug (SWD) and Serial Wire Viewer (SWV) support 8|


Thank you,

Regards
Ing.Tomas Kamenicky
Green CENTER s.r.o.

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

2

Thursday, December 8th 2011, 6:43pm

Somehow solved, but...

Hi everybody,
i was playing a little with the GDB server and found a provisor solution for STM32F2xx:

First of all you need to setup the ARM core:

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void init_SWO(void) {
		uint32_t SWOSpeed = 1000000; //1000kbps
		uint32_t SWOPrescaler = (120000000 / SWOSpeed) - 1; // SWOSpeed in Hz
		CoreDebug->DEMCR = 1 << CoreDebug_DEMCR_TRCENA_Pos;
		DBGMCU->CR = 0x00000027; //Enabling TRACE_IOEN, DBG_STANDBY, DBG_STOP, DBG_SLEEP
		*((volatile unsigned *) 0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
		*((volatile unsigned *) 0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
		*((volatile unsigned *) 0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
		*((volatile unsigned *) 0xE0000E80) = 0x0001000D; // ITM Trace Control Register
		*((volatile unsigned *) 0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register
		*((volatile unsigned *) 0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
		*((volatile unsigned *) 0xE0001000) = 0x400003FE; // DWT_CTRL
		*((volatile unsigned *) 0xE0040304) = 0x00000100; // Formatter and Flush Control Register
}

After that you run the GDB server like this:
JLinkGDBServerCL.exe -SWOPort 4000

Now open the http://www.putty.org/ , and connect to GDB`s default port 127.0.0.1:2331 in RAW format, and put following commands (you can use CTR+C and right mouse click in putty):

C/C++ Source code

1
2
3
4
+$qSupported:qRelocInsn+#9a
+$QStartNoAckMode#b0
$qRcmd,696e7465726661636520535744#b1
$qSeggerSWO:start:0 f4240+#14

The GDB server will response and it looks like this (http://zoubek.scutifer.cz/download/images/jlink-GDB-set.jpg):


Now disconnect from GDB server by closing the putty. The SWV set will kept, and all data captured on SWO port will be available on terminal at 127.0.0.1:4000.
So make a simple write function:

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
int8_t write_byte(uint8_t byte) {
if (CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) // Trace enabled
		{ if (ITM->TCR & ITM_TCR_ITMENA_Msk) // ITM enabled
			{ if (ITM->TER & (1ul << 0)) // ITM Port #0 enabled
						{
					while (ITM->PORT[0].u32 == 0)
						;
					ITM->PORT[0].u16 = 0x08 | (byte<<8);
				}
			}
		}
}


And enjoy the ITM debug window at 1000kbps!!! My laboring after few coding looks like this(http://zoubek.scutifer.cz/download/images/jlink-GBD-swo-show.jpg):


ADD)
You can use those gdb commands too:

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Uart Encoding 19200
+$qSeggerSWO:start:0 4b00+#DA

//Uart Encoding 1000000
+$qSeggerSWO:start:0 f4240+#14

//Menchester Encoding 19200
+$qSeggerSWO:start:1 4b00+#DB

//Menchester Encoding 250kbps
+$qSeggerSWO:start:1 3d090+#15

//Menchester Encoding 1000kbps
+$qSeggerSWO:start:1 f4240+#15

//Stop SWV
+$qSeggerSWO:stop+#F2


ADD2) You can play with output buffer and send more than just one byte at once. Dont forget that jlink server will add one byte to sended token, the structure of that byte looks like this:
bit - means
7 - ?
6,5,4 - Relative time stamp bits ?
3 - ?
2 - HW/SW packet idn
1,0 - ITM message size = 2^([1,0] - 1), so size can be 1,2 or 4 bytes
For example token with sended ascii 'A' will look in hex form> 0x0141

ADD3) The cmd SeggerSWO:start:par1 par2 means that it will start the SWV capture with encoding par1 at hexa speed par2

TODO: Cant get Menchester to work, in my tests its seems that it is going out of sync. Any ideas or solutions for that encoding?

Regards,
TK

This post has been edited 1 times, last edit by "memphiscz" (Sep 5th 2012, 10:04pm)


memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

3

Friday, December 9th 2011, 3:40pm

SWO server`s default port is 2332

You dont need to set the SWO port by passing argument -SWOPort <port_num>

The SWO server thread is automaticaly started with default port 2332.

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

4

Friday, December 9th 2011, 8:15pm

Semihosting for Cortex-M3

Hi,
do you plan to support semihosting on Cortex-M3 core :?:

Regards,
TK

PS: For those who wanna play/change with/the Semihosting vector address try:

C/C++ Source code

1
monitor semihosting enable =0xAABBCCDD

The charater '=' must be there 8| , otherwise set will not work and default address 0x08 will be set instead.
If you create 'bkpt' instruction in your code, and set semihosting vector address to point to this instruction, then GDB server will try to handle the halted event as semihosting event. The problem is that GDB server will faily recognize that you are in thumb mode and than it reads out the incorrect registers/memory area which will emit error :thumbdown: :
Software interrupt (SWI) 0x00AAAAAA occured in ARM mode...

If you try set the semihosting ARMSWI to 0xAAAAAA, than the same event will emit:
Unsupported semihosting functionality R0 = 0xSOMETHING ...:cursing:

The problem could be easilly fixed by repairing the GDB`s server code, exactly in point when server is checking if semihosting global variable is set and if halted addr is same as set vector addr. After that server calls DLLs readout regs with parameter 27 and 25, i thing for Cortex-M3 it should be something else ^^ .
BTW: The GDB server is nicelly programed, good work! :thumbsup:

Date of registration: Dec 12th 2011

Posts: 2

5

Monday, December 12th 2011, 12:34pm

Specification of SWO data

Quoted

ADD2) You can play with output buffer and send more than just one byte at once. Dont forget that jlink server will add one byte to sended token, the structure of that byte looks like this:
bit - means
7 - ?
6,5,4 - Relative time stamp bits ?
3 - ?
...



The format of the SWO data is specified in ARMv7-M Architecture Reference Manual ( DDI0403D ), Appendix D "Debug ITM and DWT Packet Protocol". ITM packets are sent as source packets with a payload of 1, 2 or 4 byte.

Header

Bit 0 and 1: payload -> 01 = 1 byte, 10 = 2 byte, 11 = 4 byte

Bit 3: source -> 0 = SW, 1 = HW

Bit 3 - 7: ITM stimulus port number -> should be 00000 for "printf"-ITM port 0

Payload

The payload depends on how to access the stimulus register. Byte access generates 1 byte payload, halfword 2 byte and word access 4 byte payload. If you redirect printf to SWO then fputc writes the string byte-by-byte to the stimulus register and 2 packets for 1 character are generated.


Best regards,
Joerg

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

6

Wednesday, December 14th 2011, 8:33pm

Hi Joerg

Can be the header generation cancelled or bypassed? I was searching thru registers on ARM site and did not find anything about that.

Regards,
TK

Date of registration: Dec 12th 2011

Posts: 2

7

Monday, December 19th 2011, 3:26pm

Hello Tomas,

I think the header generation can't be cancelled. Debuggers like J-Link and others need the header to identify different packets from different sources. The ITM merges its own packets ( stimulus port, timestamp, sync, overflow ) with DWT packets and sends these packets to TPUI. The TPUI merges these packets with ( optional ) ETM packets and sends these to the debugger. So the debugger must be able to identify these packets in all possible situations.

I know that there is this overhead also for minimal "printf"-only debugging. However it is always possible to receive overflow packets ( too many "printf" or slow SWO connection ), so the debugger or debug application must handle this situation.

In my case I do ignore all packets other than my "printf" packets and enjoy SWO as Debug-UART replacement :)



Best regards,

Joerg

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

8

Wednesday, September 11th 2013, 2:18pm

SWO data in new version v474a

To enable SWO readout in newer version of jlink gdb you dont need to put direct GDB commands as it was mentioned in previous posts.
To enable SWO you can enter monitor command in gdbinit:

Source code

1
monitor SWO Start 0 1000000

To disable SWO just type:

Source code

1
monitor SWO Stop

Syntax looks like:
monitor SWO Start <0:UART,1:MENCHESTER> <freq in Hz>

In other way, a new GDB version also supports semihosting for thumb instruction bkpt 0xab
To see what it does you have to execute following gdb commands:

Source code

1
2
monitor semihosting enable
monitor semihosting ThumbSWI 0xAB


Then just connect to gdb server via port 2333 (default port for Terminal output channel) by telnet or putty in raw.
In C code use this functions (also available as attachment):

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
 ******************************************************************************
 * @file      semihosting.c
 * @author    Coocox
 * @version   V1.0
 * @date      09/10/2011
 * @brief     Semihosting LowLayer GetChar/SendChar Implement.
 *
 *******************************************************************************
 */
 
#include <sys/types.h>
#include <sys/stat.h>
#include "semihosting.h"

static char g_buf[16];
static char g_buf_len = 0;

/**************************************************************************//**
 * @brief  Transmit a char on semihosting mode.
 *
 * @param  ch is the char that to send.
 *
 * @return Character to write.
 *****************************************************************************/
void SH_SendChar(int ch) {
	g_buf[g_buf_len++] = ch;
	g_buf[g_buf_len] = '\0';
	if (g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0') {
		g_buf_len = 0;
		/* Send the char */
		if (SH_DoCommand(0x04, (int) g_buf, NULL) != 0) {
			return;
		}
	}
}

/**************************************************************************//**
 * @brief  Transmit a null-terminated string on semihosting mode.
 *
 * @param  str is the string that to send.
 *
 * @return Character to write.
 *****************************************************************************/
void SH_SendString(const char *str)
{
	int j;
	if (SH_DoCommand(0x04, (int)str, NULL) != 0) {
		return;
	}
}

/**************************************************************************//**
 * @brief  Read a char on semihosting mode.
 *
 * @param  None.
 *
 * @return Character that have read.
 *****************************************************************************/
char SH_GetChar() {
	int nRet;

	while (SH_DoCommand(0x101, 0, &nRet) != 0) {
		if (nRet != 0) {
			SH_DoCommand(0x07, 0, &nRet);
			return (char) nRet;
		}
	}

	return 0;
}


And also you need an asm file too:

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
 ******************************************************************************
 * @file      semihost_cmd.s
 * @author    Coocox
 * @version   V1.0
 * @date      09/10/2011
 * @brief     Semihost command support.
 *
 *******************************************************************************
 */


.text
.global SH_DoCommand
.global HardFault_Handler
.code 16
.syntax unified
.type SH_DoCommand, function
.type HardFault_Handler, function


/**************************************************************************//**
  * @brief  prototype: int SH_DoCommand(int n32In_R0, int n32In_R1, int *pn32Out_R0)
  *
  * @param  n32In_R0	R0
  * @param  n32In_R1    R1
  * @param  pn32Out_R0  R2
  *
  * @retval None
  *****************************************************************************/
SH_DoCommand:
    BKPT 0xAB                 		/* Wait ICE or HardFault */
                              		/* ICE will step over BKPT directly */
                              		/* HardFault will step BKPT and the next line */

    B SH_ICE

SH_HardFault:                 		/* Captured by HardFault */
    MOVS   R0, #0             		/* Set return value to 0 */
    BX LR                         	/* Return */

SH_ICE:                           	/* Captured by ICE */
                                  	/* Save return value */
    CMP R2, #0
    BEQ SH_End
    STR R0, [R2]                  	/* Save the return value to *pn32Out_R0 */
SH_End:
    MOVS R0, #1                   	/* Set return value to 1 */
	BX LR                         	/* Return */

/**************************************************************************//**
  * @brief  HardFault Handler
  *
  * @param  None.
  *
  * Skip the semihost command in free run mode.
  *
  * @retval None
  *****************************************************************************/
HardFault_Handler:
	LDR    R0, [R13, #24]         	/* Get previous PC */
	LDRH   R1, [R0]               	/* Get instruction */
	LDR    R2, =0xBEAB            	/* The sepcial BKPT instruction */
	CMP    R1, R2                 	/* Test if the instruction at previous PC is BKPT */
	BNE    HardFault_Handler_Ret  	/* Not BKPT */

	ADDS   R0, #4                 	/* Skip BKPT and next line */
	STR    R0, [R13, #24]         	/* Save previous PC */

	BX     LR

HardFault_Handler_Ret:
	B      .

.end


So SEGGER thank you for these thinks, they are really usefull. :thumbup:
Regards,
Tomas Kamenicky
memphiscz has attached the following file:
  • semihost_cmd.zip (1.92 kB - 595 times downloaded - Last download: Jul 21st 2017, 8:00pm)

memphiscz

Beginner

Date of registration: Nov 30th 2011

Posts: 16

9

Thursday, September 12th 2013, 5:15pm

SWO data parser for eclipse (decoding ITM packets)

Hi,

if you need a good plugin for parsing SWO data comming from GDB server at default port 2332, than you are lucky :D, i have created one for you.
First of all before you start you need "Target Management Terminal" from "Eclipse TM Project". You can install it using Help -> Install new software
After that you also need to install "RXTX End-User Runtime" and "RXTX Extender SDK" from "RXTX.org".

Now you have a Terminal (to show him up use Window -> Show View -> other -> Terminal -> Terminal).
To get SWO parser for that terminal, download following jar file:
org.eclipse.tm.terminal.swo_1.0.0.v201302010911.jar
and save it directly to ....Eclipse/plugins/ folder.

Restart your eclipse and in Terminal Settings you should see in Connection Type: SWO (open the combo box and select SWO).


Play with check box, hit OK and you ready for your debug data from ITM.

For those one who are interested in source code, here it is:
org.eclipse.tm.terminal.swo.source_1.0.0.v201302010911.jar

PS: I am using eclipse indigo with CDT and Target Management Terminal 3.2.1.R33

Regards,
Tomáš Kamenický


At least this code i am using for ITM to output data:

C/C++ Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void itm_init(void) {
	uint32_t SWOSpeed = 3000000;
	uint32_t SWOPrescaler = (120000000 / SWOSpeed) - 1; // SWOSpeed in Hz

	CoreDebug->DEMCR = 1 << CoreDebug_DEMCR_TRCENA_Pos;

	DBGMCU->CR = 0x00000027; //Enabling TRACE_IOEN, DBG_STANDBY, DBG_STOP, DBG_SLEEP
	//Set TPIU register->Selected pinprotocol = 10b: Serial Wire Output - NRZ, 01b = SerialWire Output (Manchester)
	*((volatile unsigned *) 0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
	//Set TPIU -> Async Clock Prescaler Register [bits 0-12]
	*((volatile unsigned *) 0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
	//Lock Access Register
	*((volatile unsigned *) 0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
	*((volatile unsigned *) 0xE0000E80) = 0x0001000D; // ITM Trace Control Register
	*((volatile unsigned *) 0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register
	*((volatile unsigned *) 0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
	*((volatile unsigned *) 0xE0001000) = 0x400003FE; // DWT_CTRL
	//And this is really tricky!
	*((volatile unsigned *) 0xE0040304) = 0x00000100; // Formatter and Flush Control Register

	//initialise_swi();
}

void itm_send_string(uint8_t * p_tbuf) {
	volatile uint32_t time_out = 0;
	//SH_SendString(p_tbuf);
	// Trace enabled
	if (CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) {
		// ITM enabled
		if (ITM->TCR & ITM_TCR_ITMENA_Msk) {
			// ITM Port #0 enabled
			if (ITM->TER & (1ul << 0)) {
				do {
					time_out = 0;
					while (ITM->PORT[0].u32 == 0) {
						time_out++;
						if (time_out > 2000) {
							return;
						}
					}
					ITM->PORT[0].u8 = *p_tbuf;
					p_tbuf++;
				} while (*p_tbuf != '\0');
			}
		}
	}
}

This post has been edited 1 times, last edit by "memphiscz" (Sep 12th 2013, 5:21pm)