From: David B. <dbr...@us...> - 2010-01-14 08:34:10
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via b60dd35e33b622216c12d5804f949df087eb59fa (commit) via 73566405b6e105b0a8b7f21db48331926bec97ad (commit) from d91941d5a01ca0b9d43571edc03ba18741076cca (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b60dd35e33b622216c12d5804f949df087eb59fa Author: David Brownell <dbr...@us...> Date: Wed Jan 13 23:33:53 2010 -0800 User's Guide updates Capture various bits of useful information that have come up on the list but haven't yet gotten into the documentation: - Watchdog timers firing during JTAG debug need attention; - Some chips have special registers to help JTAG debug; - Cortex-M3 stepping example with IRQs and maskisr; - Clarifications re adaptive clocking: not all ARMs do it, and explain it a bit better. Signed-off-by: David Brownell <dbr...@us...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 3e0b5db..4446046 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -942,6 +942,33 @@ handling issues like: @itemize @bullet +@item @b{Watchdog Timers}... +Watchog timers are typically used to automatically reset systems if +some application task doesn't periodically reset the timer. (The +assumption is that the system has locked up if the task can't run.) +When a JTAG debugger halts the system, that task won't be able to run +and reset the timer ... potentially causing resets in the middle of +your debug sessions. + +It's rarely a good idea to disable such watchdogs, since their usage +needs to be debugged just like all other parts of your firmware. +That might however be your only option. + +Look instead for chip-specific ways to stop the watchdog from counting +while the system is in a debug halt state. It may be simplest to set +that non-counting mode in your debugger startup scripts. You may however +need a different approach when, for example, a motor could be physically +damaged by firmware remaining inactive in a debug halt state. That might +involve a type of firmware mode where that "non-counting" mode is disabled +at the beginning then re-enabled at the end; a watchdog reset might fire +and complicate the debug session, but hardware (or people) would be +protected.@footnote{Note that many systems support a "monitor mode" debug +that is a somewhat cleaner way to address such issues. You can think of +it as only halting part of the system, maybe just one task, +instead of the whole thing. +At this writing, January 2010, OpenOCD based debugging does not support +monitor mode debug, only "halt mode" debug.} + @item @b{ARM Semihosting}... @cindex ARM semihosting When linked with a special runtime library provided with many @@ -964,7 +991,12 @@ via the @code{WFI} instruction (or its coprocessor equivalent, before ARMv7). You may want to @emph{disable that instruction} in source code, or otherwise prevent using that state, -to ensure you can get JTAG access at any time. +to ensure you can get JTAG access at any time.@footnote{As a more +polite alternative, some processors have special debug-oriented +registers which can be used to change various features including +how the low power states are clocked while debugging. +The STM32 DBGMCU_CR register is an example; at the cost of extra +power consumption, JTAG can be used during low power states.} For example, the OpenOCD @command{halt} command may not work for an idle processor otherwise. @@ -6699,8 +6731,10 @@ to debug remote targets. Setting up GDB to work with OpenOCD can involve several components: @itemize -@item OpenOCD itself may need to be configured. @xref{GDB Configuration}. -@item GDB itself may need configuration, as shown in this chapter. +@item The OpenOCD server support for GDB may need to be configured. +@xref{GDB Configuration}. +@item GDB's support for OpenOCD may need configuration, +as shown in this chapter. @item If you have a GUI environment like Eclipse, that also will probably need to be configured. @end itemize @@ -6803,6 +6837,24 @@ With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. +Another example of useful GDB configuration came from a user who +found that single stepping his Cortex-M3 didn't work well with IRQs +and an RTOS until he told GDB to disable the IRQs while stepping: + +@example +define hook-step +mon cortex_m3 maskisr on +end +define hookpost-step +mon cortex_m3 maskisr off +end +@end example + +Rather than typing such commands interactively, you may prefer to +save them in a file and have GDB execute them as it starts, perhaps +using a @file{.gdbinit} in your project directory or starting GDB +using @command{gdb -x filename}. + @section Programming using GDB @cindex Programming using GDB @@ -6947,36 +6999,48 @@ is jim, not real tcl). In digital circuit design it is often refered to as ``clock synchronisation'' the JTAG interface uses one clock (TCK or TCLK) -operating at some speed, your target is operating at another. The two -clocks are not synchronised, they are ``asynchronous'' +operating at some speed, your CPU target is operating at another. +The two clocks are not synchronised, they are ``asynchronous'' -In order for the two to work together they must be synchronised. Otherwise -the two systems will get out of sync with each other and nothing will -work. There are 2 basic options: +In order for the two to work together they must be synchronised +well enough to work; JTAG can't go ten times faster than the CPU, +for example. There are 2 basic options: @enumerate @item -Use a special circuit. +Use a special "adaptive clocking" circuit to change the JTAG +clock rate to match what the CPU currently supports. @item -One clock must be some multiple slower than the other. +The JTAG clock must be fixed at some speed that's enough slower than +the CPU clock that all TMS and TDI transitions can be detected. @end enumerate @b{Does this really matter?} For some chips and some situations, this -is a non-issue (i.e.: A 500MHz ARM926) but for others - for example some -Atmel SAM7 and SAM9 chips start operation from reset at 32kHz - -program/enable the oscillators and eventually the main clock. It is in -those critical times you must slow the JTAG clock to sometimes 1 to -4kHz. - -Imagine debugging a 500MHz ARM926 hand held battery powered device -that ``deep sleeps'' at 32kHz between every keystroke. It can be -painful. +is a non-issue, like a 500MHz ARM926 with a 5 MHz JTAG link; +the CPU has no difficulty keeping up with JTAG. +Startup sequences are often problematic though, as are other +situations where the CPU clock rate changes (perhaps to save +power). + +For example, Atmel AT91SAM chips start operation from reset with +a 32kHz system clock. Boot firmware may activate the main oscillator +and PLL before switching to a faster clock (perhaps that 500 MHz +ARM926 scenario). +If you're using JTAG to debug that startup sequence, you must slow +the JTAG clock to sometimes 1 to 4kHz. After startup completes, +JTAG can use a faster clock. + +Consider also debugging a 500MHz ARM926 hand held battery powered +device that enters a low power ``deep sleep'' mode, at 32kHz CPU +clock, between keystrokes unless it has work to do. When would +that 5 MHz JTAG clock be usable? @b{Solution #1 - A special circuit} -In order to make use of this, your JTAG dongle must support the RTCK +In order to make use of this, +both your CPU and your JTAG dongle must support the RTCK feature. Not all dongles support this - keep reading! -The RTCK signal often found in some ARM chips is used to help with +The RTCK ("Return TCK") signal in some ARM chips is used to help with this problem. ARM has a good description of the problem described at this link: @url{http://www.arm.com/support/faqdev/4170.html} [checked 28/nov/2008]. Link title: ``How does the JTAG synchronisation logic @@ -7013,8 +7077,9 @@ ARM11 cores use an 8:1 division. Note: Many FTDI2232C based JTAG dongles are limited to 6MHz. You can still debug the 'low power' situations - you just need to -manually adjust the clock speed at every step. While painful and -tedious, it is not always practical. +either use a fixed and very slow JTAG clock rate ... or else +manually adjust the clock speed at every step. (Adjusting is painful +and tedious, and is not always practical.) It is however easy to ``code your way around it'' - i.e.: Cheat a little, have a special debug mode in your application that does a ``high power commit 73566405b6e105b0a8b7f21db48331926bec97ad Author: David Brownell <dbr...@us...> Date: Wed Jan 13 23:33:25 2010 -0800 NOR: add optional "flash erase_address" sector padding Add a NOR flash mechanism where erase_address ranges can be padded out to sector boundaries, triggering a diagnostic: > flash erase_address 0x0001f980 16 address range 0x0001f980 .. 0x0001f98f is not sector-aligned Command handler execution failed in procedure 'flash' called at file "command.c", line 647 called at file "command.c", line 361 > > flash erase_address pad 0x0001f980 16 Adding extra erase range, 0x0001f800 to 0x0001f97f Adding extra erase range, 0x0001f990 to 0x0001fbff erased address 0x0001f980 (length 16) in 0.095975s (0.163 kb/s) > This addresses what would otherwise be something of a functional regression. An earlier version of the interface had a dangerous problem: it would silently erase data outside the range it was told to erase. Fixing that bug turned up some folk who relied on that unsafe behavior. (The classic problem with interface bugs!) Now they can get that behavior again. If they really need it, just specify "pad". Signed-off-by: David Brownell <dbr...@us...> diff --git a/NEWS b/NEWS index a8b2b44..ce4896f 100644 --- a/NEWS +++ b/NEWS @@ -50,7 +50,9 @@ Flash Layer: - <driver_name>[.N]: reference the driver's Nth bank New 'nand verify' command to check bank against an image file. The "flash erase_address" command now rejects partial sectors; - previously it would silently erase extra data. + previously it would silently erase extra data. If you + want to erase the rest of the first and/or last sectors + instead of failing, you must pass an explicit "pad" flag. New at91sam9 NAND controller driver. Board, Target, and Interface Configuration Scripts: diff --git a/doc/openocd.texi b/doc/openocd.texi index 0eb40b1..3e0b5db 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3841,8 +3841,12 @@ specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash erase_address} address length +@deffn Command {flash erase_address} [@option{pad}] address length Erase sectors starting at @var{address} for @var{length} bytes. +Unless @option{pad} is specified, @math{address} must begin a +flash sector, and @math{address + length - 1} must end a sector. +Specifying @option{pad} erases extra data at the beginning and/or +end of the specified region, as needed to erase only full sectors. The flash bank to use is inferred from the @var{address}, and the specified length must stay within that bank. As a special case, when @var{length} is zero and @var{address} is diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 9083ed1..aedaa86 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -287,9 +287,22 @@ int default_flash_blank_check(struct flash_bank *bank) return ERROR_OK; } -/* erase given flash region, selects proper bank according to target and address */ +/* Manipulate given flash region, selecting the bank according to target + * and address. Maps an address range to a set of sectors, and issues + * the callback() on that set ... e.g. to erase or unprotect its members. + * + * (Note a current bad assumption: that protection operates on the same + * size sectors as erase operations use.) + * + * The "pad_reason" parameter is a kind of boolean: when it's NULL, the + * range must fit those sectors exactly. This is clearly safe; it can't + * erase data which the caller said to leave alone, for example. If it's + * non-NULL, rather than failing, extra data in the first and/or last + * sectors will be added to the range, and that reason string is used when + * warning about those additions. + */ static int flash_iterate_address_range(struct target *target, - uint32_t addr, uint32_t length, + char *pad_reason, uint32_t addr, uint32_t length, int (*callback)(struct flash_bank *bank, int first, int last)) { struct flash_bank *c; @@ -328,18 +341,53 @@ static int flash_iterate_address_range(struct target *target, for (i = 0; i < c->num_sectors; i++) { struct flash_sector *f = c->sectors + i; + uint32_t end = f->offset + f->size; /* start only on a sector boundary */ if (first < 0) { + /* scanned past the first sector? */ + if (addr < f->offset) + break; + /* is this the first sector? */ if (addr == f->offset) first = i; - else if (addr < f->offset) - break; + + /* Does this need head-padding? If so, pad and warn; + * or else force an error. + * + * Such padding can make trouble, since *WE* can't + * ever know if that data was in use. The warning + * should help users sort out messes later. + */ + else if (addr < end && pad_reason) { + /* FIXME say how many bytes (e.g. 80 KB) */ + LOG_WARNING("Adding extra %s range, " + "%#8.8x to %#8.8x", + pad_reason, + (unsigned) f->offset, + (unsigned) addr - 1); + first = i; + } else + continue; } /* is this (also?) the last sector? */ - if (last_addr == f->offset + f->size) { + if (last_addr == end) { + last = i; + break; + } + + /* Does this need tail-padding? If so, pad and warn; + * or else force an error. + */ + if (last_addr < end && pad_reason) { + /* FIXME say how many bytes (e.g. 80 KB) */ + LOG_WARNING("Adding extra %s range, " + "%#8.8x to %#8.8x", + pad_reason, + (unsigned) last_addr, + (unsigned) end - 1); last = i; break; } @@ -358,18 +406,17 @@ static int flash_iterate_address_range(struct target *target, return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - /* The NOR driver may trim this range down, based on - * whether or not a given sector is already erased. - * - * REVISIT should *we* trim it... ? + /* The NOR driver may trim this range down, based on what + * sectors are already erased/unprotected. GDB currently + * blocks such optimizations. */ return callback(c, first, last); } int flash_erase_address_range(struct target *target, - uint32_t addr, uint32_t length) + bool pad, uint32_t addr, uint32_t length) { - return flash_iterate_address_range(target, + return flash_iterate_address_range(target, pad ? "erase" : NULL, addr, length, &flash_driver_erase); } @@ -380,7 +427,11 @@ static int flash_driver_unprotect(struct flash_bank *bank, int first, int last) static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length) { - return flash_iterate_address_range(target, + /* By default, pad to sector boundaries ... the real issue here + * is that our (only) caller *permanently* removes protection, + * and doesn't restore it. + */ + return flash_iterate_address_range(target, "unprotect", addr, length, &flash_driver_unprotect); } @@ -394,6 +445,12 @@ int flash_write_unlock(struct target *target, struct image *image, struct flash_bank *c; int *padding; + /* REVISIT do_pad should perhaps just be another parameter. + * GDB wouldn't ever need it, since it erases separately. + * But "flash write_image" commands might want that option. + */ + bool do_pad = false; + section = 0; section_offset = 0; @@ -470,7 +527,8 @@ int flash_write_unlock(struct target *target, struct image *image, * In both cases, the extra writes slow things down. */ - /* if we have multiple sections within our image, flash programming could fail due to alignment issues + /* if we have multiple sections within our image, + * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size); if ((run_address + run_size + pad_bytes) > (c->base + c->size)) @@ -560,7 +618,8 @@ int flash_write_unlock(struct target *target, struct image *image, if (erase) { /* calculate and erase sectors */ - retval = flash_erase_address_range(target, run_address, run_size); + retval = flash_erase_address_range(target, + do_pad, run_address, run_size); } } diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 36e163d..b164b8d 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -102,10 +102,14 @@ int flash_init_drivers(struct command_context *cmd_ctx); /** * Erases @a length bytes in the @a target flash, starting at @a addr. + * The range @a addr to @a addr + @a length - 1 must be strictly + * sector aligned, unless @a pad is true. Setting @a pad true extends + * the range, at beginning and/or end, if needed for sector alignment. * @returns ERROR_OK if successful; otherwise, an error code. */ int flash_erase_address_range(struct target *target, - uint32_t addr, uint32_t length); + bool pad, uint32_t addr, uint32_t length); + /** * Writes @a image into the @a target flash. The @a written parameter * will contain the diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index b7e80df..cf40a81 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -203,14 +203,29 @@ COMMAND_HANDLER(handle_flash_erase_address_command) int retval; int address; int length; - + bool do_pad = false; struct target *target = get_current_target(CMD_CTX); - if (CMD_ARGC != 2) + switch (CMD_ARGC) { + case 3: + /* Optionally pad out the address range to block/sector + * boundaries. We can't know if there's data in that part + * of the flash; only do padding if we're told to. + */ + if (strcmp("pad", CMD_ARGV[0]) != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + do_pad = true; + CMD_ARGC--; + CMD_ARGV++; + /* FALL THROUGH */ + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], length); + break; + default: return ERROR_COMMAND_SYNTAX_ERROR; + } - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], address); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], length); if (length <= 0) { command_print(CMD_CTX, "Length must be >0"); @@ -229,7 +244,7 @@ COMMAND_HANDLER(handle_flash_erase_address_command) struct duration bench; duration_start(&bench); - retval = flash_erase_address_range(target, address, length); + retval = flash_erase_address_range(target, do_pad, address, length); if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { @@ -698,9 +713,12 @@ static const struct command_registration flash_exec_command_handlers[] = { .name = "erase_address", .handler = handle_flash_erase_address_command, .mode = COMMAND_EXEC, - .usage = "address length", - .help = "Erase flash blocks starting at address " - "and continuing for length bytes.", + .usage = "['pad'] address length", + .help = "Erase flash sectors starting at address and " + "continuing for length bytes. If 'pad' is specified, " + "data outside that range may also be erased: the start " + "address may be decreased, and length increased, so " + "that all of the first and last sectors are erased.", }, { .name = "fillw", diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 8018e6f..4191cc2 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1928,9 +1928,19 @@ int gdb_v_packet(struct connection *connection, struct target *target, char *pac flash_set_dirty(); /* perform any target specific operations before the erase */ - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START); - result = flash_erase_address_range(gdb_service->target, addr, length); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END); + target_call_event_callbacks(gdb_service->target, + TARGET_EVENT_GDB_FLASH_ERASE_START); + + /* vFlashErase:addr,length messages require region start and + * end to be "block" aligned ... if padding is ever needed, + * GDB will have become dangerously confused. + */ + result = flash_erase_address_range(gdb_service->target, + false, addr, length); + + /* perform any target specific operations after the erase */ + target_call_event_callbacks(gdb_service->target, + TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ if (result != ERROR_OK) ----------------------------------------------------------------------- Summary of changes: NEWS | 4 +- doc/openocd.texi | 117 +++++++++++++++++++++++++++++++++++++---------- src/flash/nor/core.c | 87 +++++++++++++++++++++++++++++------ src/flash/nor/core.h | 6 ++- src/flash/nor/tcl.c | 34 ++++++++++--- src/server/gdb_server.c | 16 +++++- 6 files changed, 213 insertions(+), 51 deletions(-) hooks/post-receive -- Main OpenOCD repository |