Update flash routines

Support setting HSI to multiple speeds, but do it in a way that doesn't waste bytes.
Remove dead code.
This commit is contained in:
true 2023-10-21 16:44:31 -07:00
parent 79a52374de
commit 859c04f782
2 changed files with 51 additions and 50 deletions

View File

@ -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(); void flash_init();

View File

@ -12,77 +12,71 @@
#include "py32f0xx_conf.h" #include "py32f0xx_conf.h"
#include "flash.h"
/* /*
* checks the flash option byte to determine if the reset pin * loads flash timing values.
* is configured to be PF2. if not, sets this bit as well as * ensure flash is unlocked before calling this function,
* the BOR values. if the bits were updated, they will be reloaded. * otherwise the writes will silently fail.
*
* only call this function during startup, before interrupts
* are enabled.
*
* note: this code caused me to lose MCU. consider it buggy.
*/ */
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) { // note: if you decide to operate at a different frequency other than
// let's update this // a supported frequency for which timing tables do not exist
opt.OptionType = OPTIONBYTE_RDP | OPTIONBYTE_USER; // in ROM, you'll have to figure out what these values actually mean,
opt.USERType = 0xff00; // as the meaning of the values isn't documented in DS or RM
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;
if (LL_FLASH_Unlock() != SUCCESS) return; // note: the PRETPE and SMERTPE values seem to differ in MCU ROM from
if (LL_FLASH_OB_Unlock() != SUCCESS) return; // 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_OBProgram(&opt); // note: the datasheet doesn't say it anywhere, but if flash is not unlocked,
// then flash timing values aren't writeable
LL_FLASH_OB_Lock(); // apply flash table timing values
LL_FLASH_Lock(); FLASH->TS0 = (timing_table[0] >> 0) & 0xff;
FLASH->TS3 = (timing_table[0] >> 8) & 0xff;
FLASH->TS1 = (timing_table[0] >> 16) & 0x1ff;
// reload newly programmed option bytes FLASH->TS2P = (timing_table[1] >> 0) & 0xff;
LL_FLASH_OB_Launch(); FLASH->TPS3 = (timing_table[1] >> 16) & 0x7ff;
}
} FLASH->PERTPE = timing_table[2]; // & 0x1ffff;
FLASH->SMERTPE = timing_table[3]; // & 0x1ffff;
void flash_write_timings_8MHz()
{ FLASH->PRGTPE = (timing_table[4] >> 0) & 0xffff;
// load flash write timings for 8MHz operation FLASH->PRETPE = (timing_table[4] >> 16) & 0x7ff;
// (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;
FLASH->TS1 = 0x90;
FLASH->TPS3 = 0x240;
FLASH->PERTPE = 0x5dc0;
FLASH->SMERTPE = 0x5dc0;
FLASH->PRGTPE = 0x1f40;
FLASH->PRETPE = 0x640;
} }
/*
* 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() __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 // configure flash timings
flash_write_timings_8MHz(); flash_set_timing(FLASH_HSI_8MHz);
// is the PF2/NRST pin configured as reset? // is the PF2/NRST pin configured as reset?
if ((FLASH->OPTR & FLASH_OPTR_NRST_MODE) == OB_RESET_MODE_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. // it is but shouldn't be, so let's configure it as GPIO.
// per datasheet, we must unlock FLASH->CR and then unlock OPTLOCK // per datasheet, we must unlock FLASH->CR (already done above)
FLASH->KEYR = FLASH_KEY1; // and then unlock OPTLOCK
FLASH->KEYR = FLASH_KEY2;
if (FLASH->CR & FLASH_CR_LOCK) return; // somehow, flash is still locked
FLASH->OPTKEYR = FLASH_OPTKEY1; FLASH->OPTKEYR = FLASH_OPTKEY1;
FLASH->OPTKEYR = FLASH_OPTKEY2; 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 // 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; 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. // as the MCU should have reset, we should never get here.
while(1); while(1);
} }
// re-lock flash when done
FLASH->CR = FLASH_CR_LOCK;
} }