From 859c04f782d44cde68af08457cab00405b00748e Mon Sep 17 00:00:00 2001 From: true Date: Sat, 21 Oct 2023 16:44:31 -0700 Subject: [PATCH] Update flash routines Support setting HSI to multiple speeds, but do it in a way that doesn't waste bytes. Remove dead code. --- include/flash.h | 8 +++-- src/flash.c | 93 ++++++++++++++++++++++++------------------------- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/include/flash.h b/include/flash.h index de81eda..1a89283 100644 --- a/include/flash.h +++ b/include/flash.h @@ -9,9 +9,13 @@ -void flash_optr_checkfix(); +#define FLASH_HSI_4MHz (uint32_t *)0x1FFF0F1C +#define FLASH_HSI_8MHz (uint32_t *)0x1FFF0F30 +#define FLASH_HSI_16MHz (uint32_t *)0x1FFF0F44 +#define FLASH_HSI_22_12MHz (uint32_t *)0x1FFF0F58 +#define FLASH_HSI_24MHz (uint32_t *)0x1FFF0F6C + -void flash_optr_set(); void flash_init(); diff --git a/src/flash.c b/src/flash.c index b1f0a2d..d3846ad 100644 --- a/src/flash.c +++ b/src/flash.c @@ -12,77 +12,71 @@ #include "py32f0xx_conf.h" +#include "flash.h" /* - * checks the flash option byte to determine if the reset pin - * is configured to be PF2. if not, sets this bit as well as - * the BOR values. if the bits were updated, they will be reloaded. - * - * only call this function during startup, before interrupts - * are enabled. - * - * note: this code caused me to lose MCU. consider it buggy. + * loads flash timing values. + * ensure flash is unlocked before calling this function, + * otherwise the writes will silently fail. */ -void flash_optr_checkfix() +void flash_set_timing(uint32_t *timing_table) { - FLASH_OBProgramInitTypeDef opt; + // load flash write timings from provided timing table + // these are listed in the datasheet, but are also in ROM on the MCU - if ((FLASH->OPTR & FLASH_OPTR_NRST_MODE) == OB_RESET_MODE_RESET) { - // let's update this - opt.OptionType = OPTIONBYTE_RDP | OPTIONBYTE_USER; - opt.USERType = 0xff00; - opt.USERConfig = OB_BOR_ENABLE | OB_BOR_LEVEL_2p3_2p4 | OB_IWDG_SW | OB_WWDG_SW | OB_RESET_MODE_GPIO | OB_BOOT1_SYSTEM | OB_RDP_LEVEL_0; + // note: if you decide to operate at a different frequency other than + // a supported frequency for which timing tables do not exist + // in ROM, you'll have to figure out what these values actually mean, + // as the meaning of the values isn't documented in DS or RM - if (LL_FLASH_Unlock() != SUCCESS) return; - if (LL_FLASH_OB_Unlock() != SUCCESS) return; - - LL_FLASH_OBProgram(&opt); + // note: the PRETPE and SMERTPE values seem to differ in MCU ROM from + // the values listed in the reference manual. this is true of + // all versions I have access to - English v1.0 and Chinese v1.2. + // for example, @8MHz, RM says 0x5dc0 for PERTPE but ROM holds 0x6b60 - LL_FLASH_OB_Lock(); - LL_FLASH_Lock(); + // note: the datasheet doesn't say it anywhere, but if flash is not unlocked, + // then flash timing values aren't writeable - // reload newly programmed option bytes - LL_FLASH_OB_Launch(); - } -} - -void flash_write_timings_8MHz() -{ - // load flash write timings for 8MHz operation - // (these are listed in the datasheet) - // note: if you decide to operate at a different frequency, then either - // update these values, or reduce speed to 8MHz when writing to flash - FLASH->TS0 = 0x3c; - FLASH->TS2P = 0x3c; - FLASH->TS3 = 0x3c; + // apply flash table timing values + FLASH->TS0 = (timing_table[0] >> 0) & 0xff; + FLASH->TS3 = (timing_table[0] >> 8) & 0xff; + FLASH->TS1 = (timing_table[0] >> 16) & 0x1ff; - FLASH->TS1 = 0x90; - FLASH->TPS3 = 0x240; + FLASH->TS2P = (timing_table[1] >> 0) & 0xff; + FLASH->TPS3 = (timing_table[1] >> 16) & 0x7ff; - FLASH->PERTPE = 0x5dc0; - FLASH->SMERTPE = 0x5dc0; - FLASH->PRGTPE = 0x1f40; - FLASH->PRETPE = 0x640; + FLASH->PERTPE = timing_table[2]; // & 0x1ffff; + FLASH->SMERTPE = timing_table[3]; // & 0x1ffff; + + FLASH->PRGTPE = (timing_table[4] >> 0) & 0xffff; + FLASH->PRETPE = (timing_table[4] >> 16) & 0x7ff; } +/* + * initializes flash timing values, and configures OPTR as necessary + * if OPTR needs configured, the MCU will reset + * call this function before interrupts are enabled. + */ __attribute__ ((long_call, section(".ramfunc"))) void flash_init() { + // unlock flash (necessary for writing timing registers + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + while (FLASH->CR & FLASH_CR_LOCK); // still locked? then stall forever + // configure flash timings - flash_write_timings_8MHz(); + flash_set_timing(FLASH_HSI_8MHz); // is the PF2/NRST pin configured as reset? if ((FLASH->OPTR & FLASH_OPTR_NRST_MODE) == OB_RESET_MODE_RESET) { // it is but shouldn't be, so let's configure it as GPIO. - // per datasheet, we must unlock FLASH->CR and then unlock OPTLOCK - FLASH->KEYR = FLASH_KEY1; - FLASH->KEYR = FLASH_KEY2; - if (FLASH->CR & FLASH_CR_LOCK) return; // somehow, flash is still locked - + // per datasheet, we must unlock FLASH->CR (already done above) + // and then unlock OPTLOCK FLASH->OPTKEYR = FLASH_OPTKEY1; FLASH->OPTKEYR = FLASH_OPTKEY2; - if (FLASH->CR & FLASH_CR_OPTLOCK) return; // somehow, OB is still locked + while (FLASH->CR & FLASH_CR_OPTLOCK); // somehow, OB is still locked // write new OPTR values FLASH->OPTR = OB_RESET_MODE_GPIO | OB_WWDG_SW | OB_IWDG_SW | OB_BOR_LEVEL_2p3_2p4 | FLASH_OPTR_RDP_LEVEL_0; @@ -105,4 +99,7 @@ __attribute__ ((long_call, section(".ramfunc"))) void flash_init() // as the MCU should have reset, we should never get here. while(1); } + + // re-lock flash when done + FLASH->CR = FLASH_CR_LOCK; } \ No newline at end of file