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

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

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


    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.
  • 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 Source Code

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

    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 Source Code

    1. +$qSupported:qRelocInsn+#9a
    2. +$QStartNoAckMode#b0
    3. $qRcmd,696e7465726661636520535744#b1
    4. $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):
    [img]http://zoubek.scutifer.cz/download/images/jlink-GDB-set.jpg[/img]

    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 Source Code

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


    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):
    [img]http://zoubek.scutifer.cz/download/images/jlink-GBD-swo-show.jpg[/img]

    ADD)
    You can use those gdb commands too:

    C Source Code

    1. //Uart Encoding 19200
    2. +$qSeggerSWO:start:0 4b00+#DA
    3. //Uart Encoding 1000000
    4. +$qSeggerSWO:start:0 f4240+#14
    5. //Menchester Encoding 19200
    6. +$qSeggerSWO:start:1 4b00+#DB
    7. //Menchester Encoding 250kbps
    8. +$qSeggerSWO:start:1 3d090+#15
    9. //Menchester Encoding 1000kbps
    10. +$qSeggerSWO:start:1 f4240+#15
    11. //Stop SWV
    12. +$qSeggerSWO:stop+#F2
    Display All


    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

    The post was edited 1 time, last by memphiscz ().

  • 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 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:
  • Specification of SWO data

    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
  • 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
  • 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. monitor semihosting enable
    2. 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 Source Code

    1. /**
    2. ******************************************************************************
    3. * @file semihosting.c
    4. * @author Coocox
    5. * @version V1.0
    6. * @date 09/10/2011
    7. * @brief Semihosting LowLayer GetChar/SendChar Implement.
    8. *
    9. *******************************************************************************
    10. */
    11. #include <sys/types.h>
    12. #include <sys/stat.h>
    13. #include "semihosting.h"
    14. static char g_buf[16];
    15. static char g_buf_len = 0;
    16. /**************************************************************************//**
    17. * @brief Transmit a char on semihosting mode.
    18. *
    19. * @param ch is the char that to send.
    20. *
    21. * @return Character to write.
    22. *****************************************************************************/
    23. void SH_SendChar(int ch) {
    24. g_buf[g_buf_len++] = ch;
    25. g_buf[g_buf_len] = '\0';
    26. if (g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0') {
    27. g_buf_len = 0;
    28. /* Send the char */
    29. if (SH_DoCommand(0x04, (int) g_buf, NULL) != 0) {
    30. return;
    31. }
    32. }
    33. }
    34. /**************************************************************************//**
    35. * @brief Transmit a null-terminated string on semihosting mode.
    36. *
    37. * @param str is the string that to send.
    38. *
    39. * @return Character to write.
    40. *****************************************************************************/
    41. void SH_SendString(const char *str)
    42. {
    43. int j;
    44. if (SH_DoCommand(0x04, (int)str, NULL) != 0) {
    45. return;
    46. }
    47. }
    48. /**************************************************************************//**
    49. * @brief Read a char on semihosting mode.
    50. *
    51. * @param None.
    52. *
    53. * @return Character that have read.
    54. *****************************************************************************/
    55. char SH_GetChar() {
    56. int nRet;
    57. while (SH_DoCommand(0x101, 0, &nRet) != 0) {
    58. if (nRet != 0) {
    59. SH_DoCommand(0x07, 0, &nRet);
    60. return (char) nRet;
    61. }
    62. }
    63. return 0;
    64. }
    Display All


    And also you need an asm file too:

    C Source Code

    1. /**
    2. ******************************************************************************
    3. * @file semihost_cmd.s
    4. * @author Coocox
    5. * @version V1.0
    6. * @date 09/10/2011
    7. * @brief Semihost command support.
    8. *
    9. *******************************************************************************
    10. */
    11. .text
    12. .global SH_DoCommand
    13. .global HardFault_Handler
    14. .code 16
    15. .syntax unified
    16. .type SH_DoCommand, function
    17. .type HardFault_Handler, function
    18. /**************************************************************************//**
    19. * @brief prototype: int SH_DoCommand(int n32In_R0, int n32In_R1, int *pn32Out_R0)
    20. *
    21. * @param n32In_R0 R0
    22. * @param n32In_R1 R1
    23. * @param pn32Out_R0 R2
    24. *
    25. * @retval None
    26. *****************************************************************************/
    27. SH_DoCommand:
    28. BKPT 0xAB /* Wait ICE or HardFault */
    29. /* ICE will step over BKPT directly */
    30. /* HardFault will step BKPT and the next line */
    31. B SH_ICE
    32. SH_HardFault: /* Captured by HardFault */
    33. MOVS R0, #0 /* Set return value to 0 */
    34. BX LR /* Return */
    35. SH_ICE: /* Captured by ICE */
    36. /* Save return value */
    37. CMP R2, #0
    38. BEQ SH_End
    39. STR R0, [R2] /* Save the return value to *pn32Out_R0 */
    40. SH_End:
    41. MOVS R0, #1 /* Set return value to 1 */
    42. BX LR /* Return */
    43. /**************************************************************************//**
    44. * @brief HardFault Handler
    45. *
    46. * @param None.
    47. *
    48. * Skip the semihost command in free run mode.
    49. *
    50. * @retval None
    51. *****************************************************************************/
    52. HardFault_Handler:
    53. LDR R0, [R13, #24] /* Get previous PC */
    54. LDRH R1, [R0] /* Get instruction */
    55. LDR R2, =0xBEAB /* The sepcial BKPT instruction */
    56. CMP R1, R2 /* Test if the instruction at previous PC is BKPT */
    57. BNE HardFault_Handler_Ret /* Not BKPT */
    58. ADDS R0, #4 /* Skip BKPT and next line */
    59. STR R0, [R13, #24] /* Save previous PC */
    60. BX LR
    61. HardFault_Handler_Ret:
    62. B .
    63. .end
    Display All


    So SEGGER thank you for these thinks, they are really usefull. :thumbup:
    Regards,
    Tomas Kamenicky
    Files
    • semihost_cmd.zip

      (1.92 kB, downloaded 1,380 times, last: )
  • 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).
    [img]http://download.viaexplore.com/get/swo_terminal_eclipse.png[/img]

    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 Source Code

    1. void itm_init(void) {
    2. uint32_t SWOSpeed = 3000000;
    3. uint32_t SWOPrescaler = (120000000 / SWOSpeed) - 1; // SWOSpeed in Hz
    4. CoreDebug->DEMCR = 1 << CoreDebug_DEMCR_TRCENA_Pos;
    5. DBGMCU->CR = 0x00000027; //Enabling TRACE_IOEN, DBG_STANDBY, DBG_STOP, DBG_SLEEP
    6. //Set TPIU register->Selected pinprotocol = 10b: Serial Wire Output - NRZ, 01b = SerialWire Output (Manchester)
    7. *((volatile unsigned *) 0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
    8. //Set TPIU -> Async Clock Prescaler Register [bits 0-12]
    9. *((volatile unsigned *) 0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
    10. //Lock Access Register
    11. *((volatile unsigned *) 0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
    12. *((volatile unsigned *) 0xE0000E80) = 0x0001000D; // ITM Trace Control Register
    13. *((volatile unsigned *) 0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register
    14. *((volatile unsigned *) 0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
    15. *((volatile unsigned *) 0xE0001000) = 0x400003FE; // DWT_CTRL
    16. //And this is really tricky!
    17. *((volatile unsigned *) 0xE0040304) = 0x00000100; // Formatter and Flush Control Register
    18. //initialise_swi();
    19. }
    20. void itm_send_string(uint8_t * p_tbuf) {
    21. volatile uint32_t time_out = 0;
    22. //SH_SendString(p_tbuf);
    23. // Trace enabled
    24. if (CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) {
    25. // ITM enabled
    26. if (ITM->TCR & ITM_TCR_ITMENA_Msk) {
    27. // ITM Port #0 enabled
    28. if (ITM->TER & (1ul << 0)) {
    29. do {
    30. time_out = 0;
    31. while (ITM->PORT[0].u32 == 0) {
    32. time_out++;
    33. if (time_out > 2000) {
    34. return;
    35. }
    36. }
    37. ITM->PORT[0].u8 = *p_tbuf;
    38. p_tbuf++;
    39. } while (*p_tbuf != '\0');
    40. }
    41. }
    42. }
    43. }
    Display All

    The post was edited 1 time, last by memphiscz ().