On Fri, 2009-02-27 at 16:51 +0100, Øyvind Harboe wrote:
> I've looked a bit more into STM32 flash programming performance and
> most of the time is spent waiting for the target to complete
> flash programming, i.e. it appears that it is the *target* that is
> slow.
>
> Could this be the case?
The STM32 flash write is self-timed and should take 40us to 70us for a
16 bit halfword (according to datasheet). this should lead to write
performances of 29kByte/s to 50kByte/s (without code overhead).
I added some timing measurement to flash/stm32.c to see how long it
takes to download the buffer to the working area and to write it into
the flash. After comparing the times with different buffer sizes it
turned out that there is quit some overhead in the communication setup
(i don't know where it originates).
I use a ftdi based jtag-dongle (oocdlink) on linux.
The current svn version (1383) allocates a maximum of 8kBytes buffer for
downloading data into flash regardless of the size of the working area.
The patch below tries to allocate as much memory as possible for the
download buffer. In my testcase it gains quite some speed.
flashing 128kBytes all zero image (jtag speed 500kHz, working area
0x5000, STM32F103RB)
current svn (1383):
wrote 131072 byte from file testdata.bin in 27.148705s (4.714774 kb/s)
with patch applied:
wrote 131072 byte from file testdata.bin in 15.796163s (8.103234 kb/s)
The patch also adds the output of some timing information during
flashing (with -d 3). Just grep the output for "stm32x_write_block".
Maybe other flash drivers could increase the buffer too (at least for
the stellaris parts).
BTW: I think the CEIL(m,n) macro in binarybuffer.h is wrong. I did not
touch it to not break anything. See FIXEDCEIL() in the patch.
Hope it helps....
Clemens
--- openocd_svn1383.orig/src/flash/stm32x.c 2009-02-28 09:14:19.000000000 +0100
+++ openocd/src/flash/stm32x.c 2009-02-28 11:45:15.000000000 +0100
@@ -33,6 +33,7 @@
#include "armv7m.h"
#include "algorithm.h"
#include "binarybuffer.h"
+#include "time_support.h"
#include <stdlib.h>
#include <string.h>
@@ -484,13 +485,15 @@
{
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
target_t *target = bank->target;
- u32 buffer_size = 8192;
+ u32 buffer_size;
working_area_t *source;
u32 address = bank->base + offset;
reg_param_t reg_params[4];
armv7m_algorithm_t armv7m_info;
int retval = ERROR_OK;
-
+ char *tstr;
+ duration_t duration;
+
u8 stm32x_flash_write_code[] = {
/* write: */
0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */
@@ -513,6 +516,7 @@
0x0C, 0x20, 0x02, 0x40 /* STM32_FLASH_SR: .word 0x4002200C */
};
+ LOG_DEBUG("writing total %u halfwords", count);
/* flash write code */
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
{
@@ -523,10 +527,22 @@
if ((retval=target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code))!=ERROR_OK)
return retval;
- /* memory buffer */
+ /* memory buffer
+ * (cg)
+ * target_alloc_working_area() only allows a multiple of 4 bytes
+ * imho the CEIL(m,n) definition in binarybuffer.h is broken.
+ * use FIXEDCEIL(m,n) here to not break anything else.
+ * XXX: Please check CEIL(n,m)
+ */
+#define FIXEDCEIL(m, n) (((m + n - 1) / n)* n)
+ buffer_size = FIXEDCEIL(target->working_area_size - sizeof(stm32x_flash_write_code), 4);
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
{
- buffer_size /= 2;
+ /* if not enough memory free just decrement by 4
+ * may need more tries but will give more buffer than dividing by 2
+ * old: buffer_size /= 2;
+ */
+ buffer_size -= 4;
if (buffer_size <= 256)
{
/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
@@ -546,17 +562,33 @@
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
init_reg_param(®_params[3], "r3", 32, PARAM_IN);
+ LOG_DEBUG("buffer_size: %u", buffer_size);
while (count > 0)
{
u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+ LOG_DEBUG("writing block of %u halfwords", thisrun_count);
+ if (LOG_LEVEL_IS( LOG_LVL_DEBUG ))
+ duration_start_measure(&duration);
+
if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer))!=ERROR_OK)
break;
+ if (LOG_LEVEL_IS( LOG_LVL_DEBUG ))
+ {
+ duration_stop_measure(&duration, &tstr);
+ LOG_DEBUG("download (target_write_buffer) took %s", tstr);
+ free(tstr);
+ }
+
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, address);
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
-
+
+
+ if (LOG_LEVEL_IS( LOG_LVL_DEBUG ))
+ duration_start_measure(&duration);
+
if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
{
@@ -564,6 +596,12 @@
retval = ERROR_FLASH_OPERATION_FAILED;
break;
}
+ if (LOG_LEVEL_IS( LOG_LVL_DEBUG ))
+ {
+ duration_stop_measure(&duration, &tstr);
+ LOG_DEBUG("write (run_algorythm) took %s", tstr);
+ free(tstr);
+ }
if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
{
_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development