[C] 纯文本查看 复制代码
static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer,
uint32_t address, uint32_t hwords_count)
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size;
struct working_area *write_algorithm;
struct working_area *source;
struct armv7m_algorithm armv7m_info;
int retval;
static const uint8_t stm32x_flash_write_code[] = {
#include "../../../contrib/loaders/flash/stm32/stm32f1x.inc"
};
/* flash write code */
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
buffer_size = target_get_working_area_avail(target);
buffer_size = MIN(hwords_count * 2 + 8, MAX(buffer_size, 256));
/* Normally we allocate all available working area.
* MIN shrinks buffer_size if the size of the written block is smaller.
* MAX prevents using async algo if the available working area is smaller
* than 256, the following allocation fails with
* ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place.
*/
retval = target_alloc_working_area(target, buffer_size, &source);
/* Allocated size is always 32-bit word aligned */
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
LOG_WARNING("no large enough working area available, can't do block memory writes");
/* target_alloc_working_area() may return ERROR_FAIL if area backup fails:
* convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE
*/
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
struct reg_param reg_params[5];
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */
init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
buf_set_u32(reg_params[1].value, 0, 32, hwords_count);
buf_set_u32(reg_params[2].value, 0, 32, source->address);
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[4].value, 0, 32, address);
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2,
0, NULL,
ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
/* Actually we just need to check for programming errors
* stm32x_wait_status_busy also reports error and clears status bits.
*
* Target algo returns flash status in r0 only if properly finished.
* It is safer to re-read status register.
*/
int retval2 = stm32x_wait_status_busy(bank, 5);
if (retval2 != ERROR_OK)
retval = retval2;
LOG_ERROR("flash write failed just before address 0x%"PRIx32,
buf_get_u32(reg_params[4].value, 0, 32));
}
for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++)
destroy_reg_param(®_params[i]);
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
return retval;
}