Skip to content

Commit

Permalink
Merge pull request #1112 from 2a17/option_bytes_for_stm32f0
Browse files Browse the repository at this point in the history
Support for writing option bytes on STM32F0/F1/F3
  • Loading branch information
Nightwalker-87 authored May 10, 2021
2 parents db9219b + 7afa063 commit 48ebad3
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 66 deletions.
14 changes: 0 additions & 14 deletions flashloaders/stm32f0.s
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,9 @@ copy:
# add r3 to flash_base for support dual bank (see flash_loader.c)
ldr r7, flash_base
add r7, r7, r3
ldr r6, flash_off_cr
add r6, r6, r7
ldr r5, flash_off_sr
add r5, r5, r7

# FLASH_CR = 0x01 (set PG)
ldr r4, =0x1
str r4, [r6]

loop:
# copy 2 bytes
ldrh r4, [r0]
Expand Down Expand Up @@ -68,18 +62,10 @@ wait:
bgt loop

exit:
# FLASH_CR &= ~1
ldr r7, =0x1
ldr r4, [r6]
bics r4, r4, r7
str r4, [r6]

bkpt

.align 2
flash_base:
.word 0x40022000
flash_off_cr:
.word 0x10
flash_off_sr:
.word 0x0c
214 changes: 193 additions & 21 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@
#define FLASH_CR_PER 1
#define FLASH_CR_MER 2
#define FLASH_CR_OPTPG 4
#define FLASH_CR_OPTER 5
#define FLASH_CR_STRT 6
#define FLASH_CR_LOCK 7
#define FLASH_CR_OPTWRE 9
#define FLASH_CR_OBL_LAUNCH 13

#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
Expand Down Expand Up @@ -3137,17 +3139,6 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
}

int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {

// According to DDI0419C, Table C1-7 firstly force halt
stlink_write_debug32(sl, STLINK_REG_DHCSR,
STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
STLINK_REG_DHCSR_C_HALT);
// and only then disable interrupts
stlink_write_debug32(sl, STLINK_REG_DHCSR,
STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
STLINK_REG_DHCSR_C_HALT |
STLINK_REG_DHCSR_C_MASKINTS);

// disable DMA
set_dma_state(sl, fl, 0);

Expand Down Expand Up @@ -3257,6 +3248,15 @@ int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {
ELOG("stlink_flash_loader_init() == -1\n");
return (-1);
}

// unlock flash
unlock_flash_if(sl);

// set programming mode
set_flash_cr_pg(sl, BANK_1);
if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
set_flash_cr_pg(sl, BANK_2);
}
} else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
ILOG("Starting Flash write for H7\n");

Expand Down Expand Up @@ -3437,7 +3437,9 @@ int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl,
int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
uint32_t dhcsr;

if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
(sl->flash_type == STLINK_FLASH_TYPE_F1_XL) ||
(sl->flash_type == STLINK_FLASH_TYPE_F4) ||
(sl->flash_type == STLINK_FLASH_TYPE_F7) ||
(sl->flash_type == STLINK_FLASH_TYPE_L4) ||
(sl->flash_type == STLINK_FLASH_TYPE_WB) ||
Expand All @@ -3446,8 +3448,9 @@ int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
(sl->flash_type == STLINK_FLASH_TYPE_H7)) {

clear_flash_cr_pg(sl, BANK_1);
if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
if ((sl->flash_type == STLINK_FLASH_TYPE_H7 &&
sl->chip_flags & CHIP_F_HAS_DUAL_BANK) ||
sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
clear_flash_cr_pg(sl, BANK_2);
}
lock_flash(sl);
Expand Down Expand Up @@ -3840,6 +3843,64 @@ int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
return (err);
}

/**
* Write option bytes
* @param sl
* @param base option bytes to write
* @param addr of the memory mapped option bytes
* @param len of options bytes to write
* @return 0 on success, -ve on failure.
*/
static int stlink_write_option_bytes_f0(
stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) {
int ret = 0;

if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) {
WLOG("Only full write of option bytes area is supported\n");
return -1;
}

clear_flash_error(sl);

WLOG("Erasing option bytes\n");

/* erase option bytes */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE));
ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE));
if (ret) {
return ret;
}

wait_flash_busy(sl);

ret = check_flash_error(sl);
if (ret) {
return ret;
}

WLOG("Writing option bytes to %#10x\n", addr);

/* Set the Option PG bit to enable programming */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE));

/* Use flash loader for write OP
* because flash memory writable by half word */
flash_loader_t fl;
ret = stlink_flash_loader_init(sl, &fl);
if (ret) {
return ret;
}
ret = stlink_flash_loader_run(sl, &fl, addr, base, len);
if (ret) {
return ret;
}

/* Reload option bytes */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH));

return check_flash_error(sl);
}

/**
* Write option bytes
* @param sl
Expand Down Expand Up @@ -4192,6 +4253,18 @@ int stlink_read_option_control_register_f7(stlink_t *sl,
return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
}

/**
* Read option bytes
* @param sl
* @param option_byte value to read
* @return 0 on success, -ve on failure.
*/
int stlink_read_option_control_register_f0(stlink_t *sl,
uint32_t *option_byte) {
DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR);
return stlink_read_debug32(sl, FLASH_OBR, option_byte);
}

/**
* Read option bytes
* @param sl
Expand Down Expand Up @@ -4335,8 +4408,8 @@ int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
default:
return -1;
Expand All @@ -4356,12 +4429,14 @@ int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
return stlink_read_option_control_register_f0(sl, option_byte);
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_control_register_f7(sl, option_byte);
default:
return -1;
// return stlink_read_option_control_register_generic(sl, option_byte);
}
}

Expand All @@ -4378,8 +4453,8 @@ int stlink_read_option_control_register1_32(stlink_t *sl,
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_control_register1_f7(sl, option_byte);
default:
return -1;
Expand Down Expand Up @@ -4441,6 +4516,10 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
}

switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
ret = stlink_write_option_bytes_f0(sl, base, addr, len);
break;
case STLINK_FLASH_TYPE_F4:
ret = stlink_write_option_bytes_f4(sl, base, addr, len);
break;
Expand Down Expand Up @@ -4511,6 +4590,95 @@ stlink_write_option_control_register_f7(stlink_t *sl,
return ret;
}


/**
* Write option bytes
* @param sl
* @param option_byte value to write
* @return 0 on success, -ve on failure.
*/
static int
stlink_write_option_control_register_f0(stlink_t *sl,
uint32_t option_control_register) {
int ret = 0;
uint16_t opt_val[8];
unsigned protection, optiondata;
uint16_t user_options, user_data, rdp;
unsigned option_offset, user_data_offset;

ILOG("Asked to write option control register %#10x to %#010x.\n",
option_control_register, FLASH_OBR);

/* Clear errors */
clear_flash_error(sl);

/* Retrieve current values */
ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata);
if (ret) {
return ret;
}
ret = stlink_read_debug32(sl, FLASH_WRPR, &protection);
if (ret) {
return ret;
}

/* Translate OBR value to flash store structure
* F0: RM0091, Option byte description, pp. 75-78
* F1: PM0075, Option byte description, pp. 19-22
* F3: RM0316, Option byte description, pp. 85-87 */
switch(sl->chip_id)
{
case 0x422: /* STM32F30x */
case 0x432: /* STM32F37x */
case 0x438: /* STM32F303x6/8 and STM32F328 */
case 0x446: /* STM32F303xD/E and STM32F398xE */
case 0x439: /* stm32f302x6/8 */
case 0x440: /* stm32f05x */
case 0x444: /* stm32f03x */
case 0x445: /* stm32f04x */
case 0x448: /* stm32f07x */
case 0x442: /* stm32f09x */
option_offset = 6;
user_data_offset = 16;
rdp = 0x55AA;
break;
default:
option_offset = 0;
user_data_offset = 10;
rdp = 0x5AA5;
break;
}

user_options = (option_control_register >> option_offset >> 2) & 0xFFFF;
user_data = (option_control_register >> user_data_offset) & 0xFFFF;

#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00))

opt_val[0] = (option_control_register & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp;
opt_val[1] = VAL_WITH_COMPLEMENT(user_options);
opt_val[2] = VAL_WITH_COMPLEMENT(user_data);
opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8);
opt_val[4] = VAL_WITH_COMPLEMENT(protection);
opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8);
opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16);
opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24);

#undef VAL_WITH_COMPLEMENT

/* Write bytes and check errors */
ret = stlink_write_option_bytes_f0(sl, (uint8_t*)opt_val, STM32_F0_OPTION_BYTES_BASE, sizeof(opt_val));
if (ret)
return ret;

ret = check_flash_error(sl);
if (!ret) {
ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register,
FLASH_OBR);
}

return ret;
}

/**
* Write option bytes
* @param sl
Expand Down Expand Up @@ -4631,6 +4799,10 @@ int stlink_write_option_control_register32(stlink_t *sl,
}

switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
ret = stlink_write_option_control_register_f0(sl, option_control_register);
break;
case STLINK_FLASH_TYPE_F7:
ret = stlink_write_option_control_register_f7(sl, option_control_register);
break;
Expand Down
Loading

0 comments on commit 48ebad3

Please sign in to comment.