nobby
nobby

Reputation: 465

Debug Application via SWD on Cortex-M Starting At FLASH Address Besides 0x00

I have used multiple Cortex M parts in the past, primarily using IAR as my IDE. I am currently developing a project for a Cortex M0+ part using an Eclipse-based IDE (Infineon ModusToolbox).

I'd like to place my application in FLASH at an address besides 0x00 (I'll have a bootloader at 0x00 eventually). In this case, let's say 0x00001000. I modified my linker script to reflect this. However, when attempting to debug via SWD at an address other than 0x00, it fails to debug. The Reset vector is mapped to my new FLASH start address as expected (according to the map file).

The manufacturer says it's not possible to begin debugging at an address besides 0x00 with an ARM-core device, but I am 99% positive that in the past I have done just what I'm trying now. Am I misremembering? Isn't the Program Counter always going to initially be set to the address of the Reset vector? Or is there some extra debugger instruction needed?

EDIT: Added linker script and source code.

//** file cy8c4xx9.ld
* \version 1.10.1
*****************************************************************/

OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

/*--------------------- Flash Configuration ----------------------------------
; <h> Flash Configuration
;   <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
;   <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
 -----------------------------------------------------------------------------*/
__FLASH_START = 0x00000000;
__FLASH_SIZE =  0x00060000;

/*--------------------- Embedded RAM Configuration ---------------------------
; <h> RAM Configuration
;   <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>
;   <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
 -----------------------------------------------------------------------------*/
__RAM_START = 0x20000000;
__RAM_SIZE =  0x00008000;

/*--------------------- Stack Configuration ----------------------------------
; <h> Stack Configuration
;   <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
 -----------------------------------------------------------------------------*/
__STACK_SIZE = 0x00000400;
__HEAP_SIZE  = 0x00000080;

/* The MEMORY section below describes the location and size of 
blocks of memory in the target.
 * Use this section to specify the memory regions available for allocation.
     */
MEMORY
{
     /* The ram and flash regions control RAM and flash memory allocation.
      *  You can change the memory allocation by editing the 'ram' and 'flash' regions.
  */
  FLASH_Application (rx) : ORIGIN = 0x00001000, LENGTH = 
__FLASH_SIZE - 0x00001000
  RAM   (rwx) : ORIGIN = __RAM_START,   LENGTH = __RAM_SIZE
  flash_boot_meta   (rw)  : ORIGIN = 0x0005FA00, LENGTH = 0x100
}

/*
* DFU SDK specific: aliases regions, so the rest of code does not use
* application specific memory region names
*/
REGION_ALIAS("FLASH", FLASH_Application);

/* DFU SDK specific: sets an app Id */
__cy_app_id = 1;

CY_APPL_ORIGIN                  = 0;
CY_FLASH_ROW_SIZE               = 256;
CY_APPL_NUM                     = 1;
CY_APPL_MAX                     = 1;
CY_METADATA_SIZE                = 64;
CY_APPL_LOADABLE                = 1;
CY_CHECKSUM_EXCLUDE_SIZE        = ALIGN(0, CY_FLASH_ROW_SIZE);
CY_APP_FOR_STACK_AND_COPIER     = 0;

APPL_STACK_SIZE = 0x0c00;
APPL_HEAP_SIZE  = 0x0000;

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 *   Reset_Handler : Entry of reset handler
 *
 * It define ssymbols, which code can use without definition*/

ENTRY(Reset_Handler)

SECTIONS
{
    .cy_app_header :
    {
        KEEP(*(.cy_app_header))
    } > FLASH

    .text :
    {
        . = ALIGN(4);
        KEEP(*(.vectors))
        . = ALIGN(4);
        __end__ = .;

Sample code:

#include "cy_pdl.h"
#include "cybsp.h"

#define LED_DELAY_MS              (500u)
#define CY_ASSERT_FAILED          (0u)
#define APP_ORIGIN 0x00001000

/*Function Name: main*/

int main(void)
{
    SCB->VTOR = (uint32_t)APP_ORIGIN;

    __set_MSP(*(volatile uint32_t*)APP_ORIGIN);

    cy_rslt_t result;

    /* Initialize the device and board peripherals */
    result = cybsp_init();

    /* Board init failed. Stop program execution */
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(CY_ASSERT_FAILED);
    }

    /* Enable global interrupts */
    __enable_irq();

    for(;;)
    {
        /* Toggle the user LED state */
        //Cy_GPIO_Inv(CYBSP_USER_LED_PORT, CYBSP_USER_LED_PIN);

        /* Wait for 0.5 seconds */
        Cy_SysLib_Delay(LED_DELAY_MS);
    }
}

Upvotes: 1

Views: 174

Answers (2)

nv317
nv317

Reputation: 180

I have done it a lot of times an that is surely possible.

I have moved start of .text area for the app and used the real bootloader.

You may repeat those actions from debugger, but i prefer to flash real bootloader each time.

Here is the code, that works in my hardware:

static void _execute()
{
    /* Disable interrupts */
    __disable_irq();
    for (uint_fast8_t x = 0; x <= 7; x++)
    {
        NVIC->ICER[x] = 0xFFFFFFFF; // disable interrupts
        NVIC->ICPR[x] = 0xFFFFFFFF; // clear pending interrupts
    }

    /* Reset interrupt priorities */
    for (uint_fast8_t N = 0; N < 240; N++)
    {
        NVIC->IP[N] = 0xFF;
    }

    /* Reset peripherals */
    RCU->APB2RST    = 0xFFFFFFFF; RCU->APB2RST    = 0;
    RCU->APB1RST    = 0xFFFFFFFF; RCU->APB1RST    = 0;
    RCU->ADDAPB1RST = 0xFFFFFFFF; RCU->ADDAPB1RST = 0;

    /* Disable peripherals */
    RCU->APB2EN    = 0;
    RCU->APB1EN    = 0;
    RCU->AHBEN     = 0;
    RCU->ADDAPB1EN = 0;

    /* Relocate the vector table */
    SCB->VTOR = (uint32_t)APP_ORIGIN;

    /* Set stack pointer */
    __set_MSP(*(volatile uint32_t*)APP_ORIGIN); // TODO: not sure it's necessary

    /* Enable interrupts */
    __enable_irq();

    /* Jump to Reset_Handler of application */
    (*((void (*volatile *volatile)())((uint32_t)APP_ORIGIN + 4)))();
    while (1);
}

Bonus: you can give 2 elf files to gdb, so it will be possible to debug both bootloader and app, but there may be name collisions, so i use it only to debug something, while the other part is a stub.

Upvotes: 0

pmacfarlane
pmacfarlane

Reputation: 4317

It's definitely possible to debug an application on a Cortex-M0+ that does not start at address 0x0.

You'll need to ensure that your application sets the CPU's VTOR register to point to your vector table, quite early on in your initialisation code, before any interrupts are enabled.

You'll also need to ensure that your linker script specifies the entry point for your program, typically something like:

ENTRY(Reset_Handler)

Of course, code like that will only run when started by the debugger. If you just reset the CPU with no debugger attached, it would fail to run.

Upvotes: 1

Related Questions