Skip to content

Commit

Permalink
Added support to write option bytes for the STM32G0 (#778)
Browse files Browse the repository at this point in the history
* poc worked, writting stm32G070 option bytes

* Update README.md

adjust layout

* code review changes
  • Loading branch information
xeniter authored and xor-gate committed Mar 20, 2019
1 parent 18ec7e2 commit c6836b4
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ If you would link your executable to `0x08000000` and then do

then it would be written to the memory.

## Writing Option Bytes

Example to read and write option bytes (currently writing only supported for STM32G0)
```
./st-flash --debug --reset --format binary --flash=128k read option_bytes_dump.bin 0x1FFF7800 4
./st-flash --debug --reset --format binary --flash=128k write option_bytes_dump.bin 0x1FFF7800
```

## FAQ

Q: My breakpoints do not work at all or only work once.
Expand Down
14 changes: 3 additions & 11 deletions include/stlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <stddef.h>
#include <stdbool.h>

#include "stm32.h"

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -50,15 +52,6 @@ extern "C" {

#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43

/* cortex core ids */
// TODO clean this up...
#define STM32VL_CORE_ID 0x1ba01477
#define STM32F7_CORE_ID 0x5ba02477

// Constant STM32 memory map figures
#define STM32_FLASH_BASE 0x08000000
#define STM32_SRAM_BASE 0x20000000

// Baud rate divisors for SWDCLK
#define STLINK_SWDCLK_4MHZ_DIVISOR 0
#define STLINK_SWDCLK_1P8MHZ_DIVISOR 1
Expand All @@ -73,8 +66,6 @@ extern "C" {
#define STLINK_SWDCLK_15KHZ_DIVISOR 265
#define STLINK_SWDCLK_5KHZ_DIVISOR 798



/* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
#define C_BUF_LEN 32

Expand Down Expand Up @@ -205,6 +196,7 @@ typedef struct flash_loader {
uint8_t stlink_get_erased_pattern(stlink_t *sl);
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_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 Down
19 changes: 19 additions & 0 deletions include/stm32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* File: stm32.h
*
* STM32 specific defines
*/

#ifndef STM32_H
#define STM32_H

// cortex core ids
#define STM32VL_CORE_ID 0x1ba01477
#define STM32F7_CORE_ID 0x5ba02477

// Constant STM32 memory map figures
#define STM32_FLASH_BASE ((uint32_t)0x08000000)
#define STM32_SRAM_BASE ((uint32_t)0x20000000)
#define STM32_G0_OPTION_BYTES_BASE ((uint32_t)0x1FFF7800)

#endif /* STM32_H */
128 changes: 128 additions & 0 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@
#define STM32G0_FLASH_PCROP1BER (STM32G0_FLASH_REGS_ADDR + 0x38)
#define STM32G0_FLASH_SECR (STM32G0_FLASH_REGS_ADDR + 0x80)

// GO FLASH control register
#define STM32G0_FLASH_CR_PG 0 /* Program */
#define STM32G0_FLASH_CR_PER 1 /* Page erase */
#define STM32G0_FLASH_CR_MER1 2 /* Mass erase */
#define STM32G0_FLASH_CR_PNB 3 /* Page number (5 bits) */
#define STM32G0_FLASH_CR_STRT 16 /* Start */
#define STM32G0_FLASH_CR_OPTSTRT 17 /* Start of modification of option bytes */
#define STM32G0_FLASH_CR_FSTPG 18 /* Fast programming */
#define STM32G0_FLASH_CR_EOPIE 24 /* End of operation interrupt enable */
#define STM32G0_FLASH_CR_ERRIE 25 /* Error interrupt enable */
#define STM32G0_FLASH_CR_OBL_LAUNCH 27 /* Forces the option byte loading */
#define STM32G0_FLASH_CR_OPTLOCK 30 /* Options Lock */
#define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock*/

//32L4 register base is at FLASH_REGS_ADDR (0x40022000)
#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
Expand Down Expand Up @@ -2407,3 +2421,117 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
unmap_file(&mf);
return err;
}

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

uint32_t val;

if(len != 4) {
ELOG("Wrong length for writting option bytes, must be 4 is %d\n", len);
return -1;
}

// Make sure we've loaded the context with the chip details
stlink_core_id(sl);

/* Check if chip is supported and for correct address */
if((sl->chip_id != STLINK_CHIPID_STM32_G0X1) || (addr != STM32_G0_OPTION_BYTES_BASE)) {
ELOG("Option bytes writing is currently only supported for the STM32G0\n");
return -1;
}

/* Unlock flash if necessary (ref manuel page 52) */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
if ((val & (1 << STM32G0_FLASH_CR_LOCK))) {

/* disable flash write protection. */
stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123);
stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB);

// check that the lock is no longer set.
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
if ((val & (1 << STM32G0_FLASH_CR_LOCK))) {
ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
}

/* Unlock option bytes if necessary (ref manuel page 61) */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
if ((val & (1 << STM32G0_FLASH_CR_OPTLOCK))) {

/* disable option byte write protection. */
stlink_write_debug32(sl, STM32G0_FLASH_OPTKEYR, 0x08192A3B);
stlink_write_debug32(sl, STM32G0_FLASH_OPTKEYR, 0x4C5D6E7F);

/* check that the lock is no longer set. */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
if ((val & (1 << STM32G0_FLASH_CR_OPTLOCK))) {
ELOG("Options bytes unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
}

/* Write options bytes */
uint32_t data;
write_uint32((unsigned char*) &data, *(uint32_t*) (base));
WLOG("Writing option bytes 0x%04x\n", data);
//stlink_write_debug32(sl, addr, data);
stlink_write_debug32(sl, STM32G0_FLASH_OPTR, data);

/* Set Options Start bit */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
val |= (1 << STM32G0_FLASH_CR_OPTSTRT);
stlink_write_debug32(sl, STM32G0_FLASH_CR, val);

/* Wait for 'busy' bit in FLASH_SR to clear. */
do {
stlink_read_debug32(sl, STM32G0_FLASH_SR, &val);
} while ((val & (1 << 16)) != 0);

/* apply options bytes immediate */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
val |= (1 << STM32G0_FLASH_CR_OBL_LAUNCH);
stlink_write_debug32(sl, STM32G0_FLASH_CR, val);

/* Re-lock option bytes */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
val |= (1 << STM32G0_FLASH_CR_OPTLOCK);
stlink_write_debug32(sl, STM32G0_FLASH_CR, val);
/* Re-lock flash. */
stlink_read_debug32(sl, STM32G0_FLASH_CR, &val);
val |= (1 << STM32G0_FLASH_CR_LOCK);
stlink_write_debug32(sl, STM32G0_FLASH_CR, val);

return 0;
}

/**
* Write the given binary file with option bytes
* @param sl
* @param path readable file path, should be binary image
* @param addr of the memory mapped option bytes
* @return 0 on success, -ve on failure.
*/
int stlink_fwrite_option_bytes(stlink_t *sl, const char* path, stm32_addr_t addr) {
/* write the file in flash at addr */
int err;
mapped_file_t mf = MAPPED_FILE_INITIALIZER;

if (map_file(&mf, path) == -1) {
ELOG("map_file() == -1\n");
return -1;
}

err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t) mf.len);
stlink_fwrite_finalize(sl, addr);
unmap_file(&mf);
return err;
}
8 changes: 8 additions & 0 deletions src/tools/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ int main(int ac, char** av)
goto on_error;
}
}
else if (o.addr == STM32_G0_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 {
err = -1;
printf("Unknown memory region\n");
Expand Down

0 comments on commit c6836b4

Please sign in to comment.