Skip to content

Commit

Permalink
Merge pull request #836 from Orie22/dev-option-bytes
Browse files Browse the repository at this point in the history
Added Read/Write command for Option-Bytes on STM32F2 series
  • Loading branch information
texane committed Oct 7, 2019
2 parents c3577b5 + 94aef45 commit a28ba53
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 11 deletions.
2 changes: 2 additions & 0 deletions include/stlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ typedef struct flash_loader {
int stlink_mwrite_flash(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_t addr);
int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr);
int stlink_fwrite_option_bytes(stlink_t *sl, const char* path, stm32_addr_t addr);
int stlink_fwrite_option_bytes_32bit(stlink_t *sl,uint32_t val);
int stlink_mwrite_sram(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_t addr);
int stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr);
int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length);
Expand All @@ -221,6 +222,7 @@ typedef struct flash_loader {
int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size);
int stlink_fread(stlink_t* sl, const char* path, bool is_ihex, stm32_addr_t addr, size_t size);
int stlink_load_device_params(stlink_t *sl);
int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t* option_byte);

#include "stlink/sg.h"
#include "stlink/usb.h"
Expand Down
5 changes: 4 additions & 1 deletion include/stlink/tools/flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4};
enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1};
enum flash_area {FLASH_MAIN_MEMORY = 0, FLASH_SYSTEM_MEMORY = 1,FLASH_OTP = 2, FLASH_OPTION_BYTES = 3};
struct flash_opts
{
enum flash_cmd cmd;
Expand All @@ -20,10 +21,12 @@ struct flash_opts
int reset;
int log_level;
enum flash_format format;
enum flash_area area;
uint32_t val;
size_t flash_size; /* --flash=n[k][m] */
};

#define FLASH_OPTS_INITIALIZER {0, NULL, { 0 }, NULL, 0, 0, 0, 0, 0, 0 }
#define FLASH_OPTS_INITIALIZER {0, NULL, { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0 }

int flash_get_opts(struct flash_opts* o, int ac, char** av);

Expand Down
2 changes: 1 addition & 1 deletion include/stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
#define STM32_SRAM_BASE ((uint32_t)0x20000000)
#define STM32_G0_OPTION_BYTES_BASE ((uint32_t)0x1FFF7800)
#define STM32_L0_CAT2_OPTION_BYTES_BASE ((uint32_t)0x1FF80000)

#define STM32_F2_OPTION_BYTES_BASE ((uint32_t)0x1FFFC000)
#endif /* STM32_H */
120 changes: 119 additions & 1 deletion src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@
#define FLASH_F4_CR_SNB_MASK 0xf8
#define FLASH_F4_SR_BSY 16

//STM32F2
#define FLASH_F2_REGS_ADDR ((uint32_t)0x40023c00)
#define FLASH_F2_KEYR (FLASH_F2_REGS_ADDR + 0x04)
#define FLASH_F2_OPT_KEYR (FLASH_F2_REGS_ADDR + 0x08)
#define FLASH_F2_SR (FLASH_F2_REGS_ADDR + 0x0c)
#define FLASH_F2_CR (FLASH_F2_REGS_ADDR + 0x10)
#define FLASH_F2_OPT_CR (FLASH_F2_REGS_ADDR + 0x14)
#define FLASH_F2_OPT_LOCK_BIT (1u << 0)
#define FLASH_F2_CR_STRT 16
#define FLASH_F2_CR_LOCK 31

#define FLASH_F2_CR_SER 1
#define FLASH_F2_CR_SNB 3
#define FLASH_F2_CR_SNB_MASK 0x78
#define FLASH_F2_SR_BSY 16


#define L1_WRITE_BLOCK_SIZE 0x80
#define L0_WRITE_BLOCK_SIZE 0x40

Expand Down Expand Up @@ -2642,6 +2659,89 @@ static int stlink_write_option_bytes_l0_cat2(stlink_t *sl, uint8_t* base, uint32
return 0;
}

/**
* Write option bytes
* @param sl
* @param option_byte value to write
* @return 0 on success, -ve on failure.
*/
static int stlink_write_option_bytes_f2(stlink_t *sl, uint32_t option_byte) {
uint32_t val;

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
if (val & FLASH_F2_OPT_LOCK_BIT) {
WLOG("Unlocking option flash\n");
//Unlock the FLASH_OPT_CR register (FLASH Programming manual page 15)
//https://www.st.com/resource/en/programming_manual/cd00233952.pdf
stlink_write_debug32(sl, FLASH_F2_OPT_KEYR, 0x08192A3B);
stlink_write_debug32(sl, FLASH_F2_OPT_KEYR, 0x4C5D6E7F);

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
if (val & FLASH_F2_OPT_LOCK_BIT) {
ELOG("Option flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
}

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
WLOG("option bytes CR = %x\n",val);

stlink_write_debug32(sl, FLASH_F2_OPT_CR, option_byte & 0x0FFFFFFC);

stlink_write_debug32(sl, FLASH_F2_OPT_CR, (option_byte & 0x0FFFFFFC)|0x00000002);


stlink_read_debug32(sl, FLASH_F2_SR, &val);
WLOG("wait BSY flag to be 0\n");

while(val & 0x00010000){
stlink_read_debug32(sl, FLASH_F2_SR, &val);
}
WLOG("BSY flag is 0\n");

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
WLOG("option bytes CR = %x\n",val);
WLOG("Option flash re-lock\n");
stlink_write_debug32(sl, FLASH_F2_OPT_CR, val | 0x00000001);

DLOG("STM32 F2 option bytes are written\n");

return 0;
}

/**
* Read option bytes
* @param sl
* @param option_byte value to write
* @return 0 on success, -ve on failure.
*/
int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t* option_byte) {
uint32_t val;

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
if (val & FLASH_F2_OPT_LOCK_BIT) {
WLOG("Unlocking option flash\n");
//Unlock the FLASH_OPT_CR register (FLASH Programming manual page 15)
//https://www.st.com/resource/en/programming_manual/cd00233952.pdf
stlink_write_debug32(sl, FLASH_F2_OPT_KEYR, 0x08192A3B);
stlink_write_debug32(sl, FLASH_F2_OPT_KEYR, 0x4C5D6E7F);

stlink_read_debug32(sl, FLASH_F2_OPT_CR, &val);
if (val & FLASH_F2_OPT_LOCK_BIT) {
ELOG("Option flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
}

stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte);
WLOG("option bytes CR = %x\n",option_byte);

WLOG("Option flash re-lock\n");
stlink_write_debug32(sl, FLASH_F2_OPT_CR, val | 0x00000001);

return 0;
}

/**
* Write option bytes
* @param sl
Expand All @@ -2662,7 +2762,7 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui
return stlink_write_option_bytes_l0_cat2(sl, base, len);
}
else {
ELOG("Option bytes writing is currently only supported for the STM32G0 and STM32L0\n");
ELOG("Option bytes writing is currently only supported for the STM32F2, STM32G0 and STM32L0\n");
return -1;
}

Expand Down Expand Up @@ -2690,3 +2790,21 @@ int stlink_fwrite_option_bytes(stlink_t *sl, const char* path, stm32_addr_t addr
unmap_file(&mf);
return err;
}

/**
* Write the given 32-bit value with option byte
* @param sl
* @param option_byte value to write
* @return 0 on success, -ve on failure.
*/
int stlink_fwrite_option_bytes_32bit(stlink_t *sl, uint32_t val) {

if(sl->chip_id == STLINK_CHIPID_STM32_F2){
return stlink_write_option_bytes_f2(sl, val);
}
else
{
ELOG("Option bytes writing is currently only supported for the STM32F2, STM32G0 and STM32L0\n");
return -1;
}
}
34 changes: 27 additions & 7 deletions src/tools/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static void usage(void)
puts(" fsize: Use decimal, octal or hex by prefix 0xXXX for hex, optionally followed by k=KB, or m=MB (eg. --flash=128k)");
puts(" Format may be 'binary' (default) or 'ihex', although <addr> must be specified for binary format only.");
puts(" ./st-flash [--version]");
puts("example write option byte: ./st-flash --debug --reset --area=option write 0xXXXXXXXX");
puts("example read option byte: ./st-flash --debug --reset --area=option read > option_byte");
}

int main(int ac, char** av)
Expand Down Expand Up @@ -131,15 +133,13 @@ int main(int ac, char** av)
if (o.cmd == FLASH_CMD_WRITE) /* write */
{
size_t size = 0;

if(o.format == FLASH_FORMAT_IHEX) {
err = stlink_parse_ihex(o.filename, stlink_get_erased_pattern(sl), &mem, &size, &o.addr);
if (err == -1) {
printf("Cannot parse %s as Intel-HEX file\n", o.filename);
goto on_error;
}
}

if ((o.addr >= sl->flash_base) &&
(o.addr < sl->flash_base + sl->flash_size)) {
if(o.format == FLASH_FORMAT_IHEX)
Expand All @@ -164,14 +164,22 @@ int main(int ac, char** av)
goto on_error;
}
}
else if (o.addr == STM32_G0_OPTION_BYTES_BASE || o.addr == STM32_L0_CAT2_OPTION_BYTES_BASE) {
else if (o.addr == STM32_G0_OPTION_BYTES_BASE || o.addr == STM32_L0_CAT2_OPTION_BYTES_BASE){
err = stlink_fwrite_option_bytes(sl, o.filename, o.addr);
if (err == -1)
{
printf("stlink_fwrite_option_bytes() == -1\n");
goto on_error;
}
}
else if (o.area == FLASH_OPTION_BYTES){
err = stlink_fwrite_option_bytes_32bit(sl, o.val);
if (err == -1)
{
printf("stlink_fwrite_option_bytes() == -1\n");
goto on_error;
}
}
else {
err = -1;
printf("Unknown memory region\n");
Expand Down Expand Up @@ -201,13 +209,25 @@ int main(int ac, char** av)
}
else /* read */
{
if ((o.addr >= sl->flash_base) && (o.size == 0) &&
(o.addr < sl->flash_base + sl->flash_size))
if(o.area == FLASH_OPTION_BYTES){
if(sl->chip_id == STLINK_CHIPID_STM32_F2){
uint32_t option_byte = 0;
err = stlink_read_option_bytes_f2(sl,&option_byte);
printf("%x\n",option_byte);
}else{
printf("This format is available for STM32F2 Only\n");
}
}
else if ((o.addr >= sl->flash_base) && (o.size == 0) &&
(o.addr < sl->flash_base + sl->flash_size)){
o.size = sl->flash_size;
err = stlink_fread(sl, o.filename, o.format == FLASH_FORMAT_IHEX, o.addr, o.size);
}
else if ((o.addr >= sl->sram_base) && (o.size == 0) &&
(o.addr < sl->sram_base + sl->sram_size))
(o.addr < sl->sram_base + sl->sram_size)){
o.size = sl->sram_size;
err = stlink_fread(sl, o.filename, o.format == FLASH_FORMAT_IHEX, o.addr, o.size);
err = stlink_fread(sl, o.filename, o.format == FLASH_FORMAT_IHEX, o.addr, o.size);
}
if (err == -1)
{
printf("stlink_fread() == -1\n");
Expand Down
31 changes: 30 additions & 1 deletion src/tools/flash_opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,29 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av)

serial_specified = true;
}
else if (strcmp(av[0], "--area") == 0 || starts_with(av[0], "--area=")) {
const char * area;
if(strcmp(av[0], "--area") == 0) {
ac--;
av++;
if (ac < 1) return -1;
area = av[0];
}
else {
area = av[0] + strlen("--area=");
}
if (strcmp(area, "main") == 0)
o->area = FLASH_MAIN_MEMORY;
else if (strcmp(area, "system") == 0)
o->area = FLASH_SYSTEM_MEMORY;
else if (strcmp(area, "otp") == 0)
o->area = FLASH_OTP;
else if (strcmp(area, "option") == 0)
o->area = FLASH_OPTION_BYTES;
else
return -1;

}
else if (strcmp(av[0], "--format") == 0 || starts_with(av[0], "--format=")) {
const char * format;
if(strcmp(av[0], "--format") == 0) {
Expand Down Expand Up @@ -149,6 +172,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av)
break;

case FLASH_CMD_READ: // expect filename, addr and size
if((o->area == FLASH_OPTION_BYTES) &&(ac == 0)) break;
if (ac != 3) return -1;

o->filename = av[0];
Expand All @@ -161,7 +185,12 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av)
break;

case FLASH_CMD_WRITE:
if(o->format == FLASH_FORMAT_BINARY) { // expect filename and addr
if(o->area == FLASH_OPTION_BYTES){
if(ac != 1) return -1;

o->val = (uint32_t)strtoul(av[0], &tail, 16);
}
else if(o->format == FLASH_FORMAT_BINARY) { // expect filename and addr
if (ac != 2) return -1;

o->filename = av[0];
Expand Down

0 comments on commit a28ba53

Please sign in to comment.