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:
parent
79a52374de
commit
859c04f782
|
@ -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();
|
||||
|
||||
|
|
93
src/flash.c
93
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;
|
||||
}
|
Loading…
Reference in New Issue