Debugging Application in KDS with Bootloader

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

Debugging Application in KDS with Bootloader

Jump to solution
2,293 Views
thebhef
Contributor II


I'm working on a custom bootloader and I'm having some problems with the debug configuration for my application. I've got a binary build set up and I've tested that I can jump to it from the bootloader.

 

I started with the Processor Expert linker files and have adapted them for my application. The target micro is an MK64FN1M0xxx12. I've got a config working with the application located at 0x0, and have had no problems with debugging it before moving it to make room for my bootloader. I'm using a Segger J-Link.

 

The problem I'm having is with my debug build configuration. When I start the debugger (flash & debug), the PC is at 0x0, unless I set a program counter in the debug configurations/start options. My application lives at 0x5800. The vector table starts at 0x5800, and is 0x198 bytes long, application starts at 0x5C00. I _think_ my problem might be setting the VTOR register, but GDB doesn't seem to know what that is, reporting "unsupported register !" when I try to write to vtor and scb->vtor. I've also tried writing it on startup manually using the EmbSys register plugin, to no avail. The debugger doesn't help once the application's started, the PC seems to jump from one end of the memory space to the other.

 

Summary:

  • I'm writing the flash configuration region at 0x400
  • Bootloader vector table starts at 0x0, runs to 0x198
  • Bootloader application starts at 0x410, ends at to 0x57fff
  • Application starts at 0x5800, ends at 0xfffff
  • SP gets set to 0xFFFFFFFC when not set by GDB
  • Application does not proceed into startup code when PC is set to 0x5800 or 0x5804
  • Writing the VTOR using the EmbSys register view doesn't seem to fix anything.
  • I've verified the flash config section, application vector table, and application are all in the right places in memory.

 

What I've tried so far:

  • startup options:
    • set PC to 0x5800
    • set PC to 0x5804
    • Set executable and symbols offset to 0x5800 (with both of the above PC locations)
  • Writing 0x5800 to the VTOR with GDB
  • Writing 0x5800 to the SP with GDB
  • Writing 0x2002FFF0 to the SP with GDB (I've located a struct shared by the main app and bootloader at the end of RAM, so I moved the stack pointer down to accomodate.)

 

Questions:

  • How do I get this working? I want to be able to debug the application at the correct address, and ideally, be able to run it without flashing the bootloader on the micro.
  • What do the executable and symbol offsets do in the debug config/startup options? I haven't seen any difference in the registers I'm looking at (PC, SP, VTOR).
  • Are there any other registers (besides PC, SP, VTOR) that I need to be concerned with to get this working?
  • Is it possible to set register init values in the linker file? It'd be nice if the application would still run without the debugger attached.
  • Does anyone know of any good (complete and well-explained) reference materials for the GDB settings in KDS? for GCC linker file settings?
  • Any other advice for resolving these kinds of issues?
  • Is there any difference between using 'set $<register> = <value>' and 'monitor reg <register> = <value>'?

 

Please let me know if you need anything else from me.

Thanks!

 

Linker file:

/* Entry Point */ ENTRY(__thumb_startup)   /* Highest address of the user mode stack */ /*_estack = 0x20030000;    had to move this because of the shared variable.*/ _estack = 0x2002FFF0; __SP_INIT = _estack; __stack = _estack;   /* Generate a link error if heap and stack don't fit into RAM */ __heap_size = 0x00;                    /* required amount of heap  */ __stack_size = 0x0400;                 /* required amount of stack */   MEMORY {   m_interrupts (RX) : ORIGIN = 0x00005800, LENGTH = 0x00000198   m_text      (RX) : ORIGIN = 0x00005C00, LENGTH = 0x000FA3FF   m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000   m_data      (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000   m_cfmprotrom  (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 }   /* Define output sections */ SECTIONS {   /******************************************************************************/   /*******************************app sections***********************************/   /*data shared between application and bootloader. The NOLOAD parameter is used to prevent jumps between applications from causing re-initialization of the data.*/   .BootloaderSharedData 0x2002FFF8 (NOLOAD):   {     KEEP(*(.BootloaderSharedData)) /* keep my variable even if not referenced */   } > m_data   /******************************************************************************/     /* The startup code goes first into INTERNAL_FLASH */   .interrupts:   {     __vector_table = .;     . = ALIGN(4);     KEEP(*(.vectortable)) /* Startup code */     . = ALIGN(4);   } > m_interrupts     .cfmprotect :   {     . = ALIGN(4);   KEEP(*(.cfmconfig)) /* Flash Configuration Field (FCF) */   . = ALIGN(4);   } > m_cfmprotrom      /* The program code and other data goes into INTERNAL_FLASH */   .text :   {     . = ALIGN(4);     *(.text)           /* .text sections (code) */     *(.text*)          /* .text* sections (code) */     *(.rodata)         /* .rodata sections (constants, strings, etc.) */     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */     *(.glue_7)         /* glue arm to thumb code */     *(.glue_7t)        /* glue thumb to arm code */     *(.eh_frame)       KEEP (*(.init))     KEEP (*(.fini))       . = ALIGN(4);       _etext = .;        /* define a global symbols at end of code */   } > m_text      .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > m_text     .ARM : {     __exidx_start = .;       *(.ARM.exidx*)       __exidx_end = .;   } > m_text    .ctors :   {     __CTOR_LIST__ = .;     /* gcc uses crtbegin.o to find the start of        the constructors, so we make sure it is        first.  Because this is a wildcard, it        doesn't matter if the user does not        actually link against crtbegin.o; the        linker won't look for a file to match a        wildcard.  The wildcard also means that it        doesn't matter which directory crtbegin.o        is in.  */     KEEP (*crtbegin.o(.ctors))     /* We don't want to include the .ctor section from        from the crtend.o file until after the sorted ctors.        The .ctor section from the crtend file contains the        end of ctors marker and it must be last */     KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))     KEEP (*(SORT(.ctors.*)))     KEEP (*(.ctors))     __CTOR_END__ = .;   } > m_text     .dtors :   {     __DTOR_LIST__ = .;     KEEP (*crtbegin.o(.dtors))     KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))     KEEP (*(SORT(.dtors.*)))     KEEP (*(.dtors))     __DTOR_END__ = .;   } > m_text     .preinit_array     :   {     PROVIDE_HIDDEN (__preinit_array_start = .);     KEEP (*(.preinit_array*))     PROVIDE_HIDDEN (__preinit_array_end = .);   } > m_text   .init_array :   {     PROVIDE_HIDDEN (__init_array_start = .);     KEEP (*(SORT(.init_array.*)))     KEEP (*(.init_array*))     PROVIDE_HIDDEN (__init_array_end = .);   } > m_text   .fini_array :   {     PROVIDE_HIDDEN (__fini_array_start = .);     KEEP (*(SORT(.fini_array.*)))     KEEP (*(.fini_array*))     PROVIDE_HIDDEN (__fini_array_end = .);     ___ROM_AT = .;   } > m_text   /* Initialized data sections goes into RAM, load LMA copy after code */   .data : AT(___ROM_AT)   {     . = ALIGN(4);     _sdata = .;        /* create a global symbol at data start */     *(.data)           /* .data sections */     *(.data*)          /* .data* sections */       . = ALIGN(4);       _edata = .;        /* define a global symbol at data end */   } > m_data     ___data_size = _edata - _sdata;   ___m_data_1FFF0000_ROMStart = ___ROM_AT + SIZEOF(.data);   .m_data_1FFF0000 : AT(___m_data_1FFF0000_ROMStart)   {      . = ALIGN(4);      ___m_data_1FFF0000_RAMStart = .;      *(.m_data_1FFF0000) /* This is an User defined section */      ___m_data_1FFF0000_RAMEnd = .;      . = ALIGN(4);   } > m_data_1FFF0000   ___m_data_1FFF0000_ROMSize = ___m_data_1FFF0000_RAMEnd - ___m_data_1FFF0000_RAMStart;          /* Uninitialized data section */   . = ALIGN(4);   .bss :   {     /* This is used by the startup in order to initialize the .bss section */     __START_BSS = .;    PROVIDE ( __bss_start__ = __START_BSS );       *(.bss)     *(.bss*)     *(COMMON)       . = ALIGN(4);     __END_BSS = .;    PROVIDE ( __bss_end__ = __END_BSS );   } > m_data     _romp_at = ___ROM_AT + SIZEOF(.data) +SIZEOF(.m_data_1FFF0000);   .romp : AT(_romp_at)   {     __S_romp = _romp_at;     LONG(___ROM_AT);     LONG(_sdata);     LONG(___data_size);     LONG(___m_data_1FFF0000_ROMStart);     LONG(___m_data_1FFF0000_RAMStart);     LONG(___m_data_1FFF0000_ROMSize);     LONG(0);     LONG(0);     LONG(0);   } > m_data      text_end = ORIGIN(m_text) + LENGTH(m_text);   data_init_end = ___m_data_1FFF0000_ROMStart + SIZEOF(.m_data_1FFF0000) + SIZEOF(.romp);   ASSERT( data_init_end <= text_end, "region m_text overflowed with text and data")      /* User_heap_stack section, used to check that there is enough RAM left */   ._user_heap_stack :   {     . = ALIGN(4);     PROVIDE ( end = . );     PROVIDE ( _end = . );     PROVIDE ( __end__ = . );     __heap_addr = .;     __HeapBase = .;     . = . + __heap_size;     __HeapLimit = .;     . = . + __stack_size;     . = ALIGN(4);   } > m_data     .ARM.attributes 0 : { *(.ARM.attributes) } }
Labels (1)
1 Solution
992 Views
Carlos_Mendoza
NXP Employee
NXP Employee

Hi George,

You are not able to debug your application because when a reset occurs the program counter goes to the address 0x0 where it finds the first vector which loads the stack pointer. Then the program counter moves to next address 0x4 and the second vector jumps to the startup routine. The reset vector must always be stored in address 0x4. In startup routine all the hardware initialization is performed and the vector can be copied to RAM. This is recommended as interrupts will work faster in RAM than in Flash. In this case you must change VTOR register to point to the address in RAM where the vectors are copied.

So I would recommend you to try debugging the application and bootloader at the same time, here is a document that explains how to do this:

Debugging Bootloader and Application using Kinetis Design Studio

or do not relocate the m_interrupts section if you want to debug your application without  the bootloader.

You can find more information about debugging with gdb on the following link:

https://sourceware.org/gdb/current/onlinedocs/gdb/

And for detailed information on the GCC Linker please refer to “The GNU Linker” by Steve Chamberlain and Ian Lance Taylor.

Regarding the register monitoring, are you using the EmbSys Register view?

Hope it helps!

Best Regards,

Carlos Mendoza

Technical Support Engineer

View solution in original post

0 Kudos
2 Replies
992 Views
thebhef
Contributor II

I followed the instructions at the link and it's working OK now, with a huge caveat: I discovered after about an hour of confusion that some of the variables in the application, in code common with my bootloader (i.e. the same variables exist in both applications), are showing up with completely unexpected values; all 0's in one struct, and the reset address of the stack pointer in some of my ints. When I close the bootloader project and remove it from the application's debug args(apparently giving up the ability to debug it), my vars are as I expect them to be.

This isn't a huge problem for me, now that I'm aware of it, as I don't really need to debug both applications together.

0 Kudos
993 Views
Carlos_Mendoza
NXP Employee
NXP Employee

Hi George,

You are not able to debug your application because when a reset occurs the program counter goes to the address 0x0 where it finds the first vector which loads the stack pointer. Then the program counter moves to next address 0x4 and the second vector jumps to the startup routine. The reset vector must always be stored in address 0x4. In startup routine all the hardware initialization is performed and the vector can be copied to RAM. This is recommended as interrupts will work faster in RAM than in Flash. In this case you must change VTOR register to point to the address in RAM where the vectors are copied.

So I would recommend you to try debugging the application and bootloader at the same time, here is a document that explains how to do this:

Debugging Bootloader and Application using Kinetis Design Studio

or do not relocate the m_interrupts section if you want to debug your application without  the bootloader.

You can find more information about debugging with gdb on the following link:

https://sourceware.org/gdb/current/onlinedocs/gdb/

And for detailed information on the GCC Linker please refer to “The GNU Linker” by Steve Chamberlain and Ian Lance Taylor.

Regarding the register monitoring, are you using the EmbSys Register view?

Hope it helps!

Best Regards,

Carlos Mendoza

Technical Support Engineer

0 Kudos