diff --git a/include/libopencm3/stm32/f7/flash.h b/include/libopencm3/stm32/f7/flash.h index f75fc525..61d3a337 100644 --- a/include/libopencm3/stm32/f7/flash.h +++ b/include/libopencm3/stm32/f7/flash.h @@ -1,19 +1,23 @@ -/** @defgroup flash_defines FLASH Defines - * - * @ingroup STM32F7xx_defines - * - * @brief Defined Constants and Types for the STM32F7xx FLASH Memory - * - * @version 1.0.0 - * - * @date 14 January 2014 - * - * LGPL License Terms @ref lgpl_license - */ +#ifndef LIBOPENCM3_FLASH_H +#define LIBOPENCM3_FLASH_H +/** @addtogroup flash_defines + * + * @author @htmlonly © @endhtmlonly 2017 + * Matthew Lai + * @author @htmlonly © @endhtmlonly 2010 + * Thomas Otto + * @author @htmlonly © @endhtmlonly 2010 + * Mark Butler + * + */ /* * This file is part of the libopencm3 project. * + * Copyright (C) 2017 Matthew Lai + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -28,10 +32,156 @@ * along with this library. If not, see . */ -#ifndef LIBOPENCM3_FLASH_H -#define LIBOPENCM3_FLASH_H +/* + * For details see: + * PM0081 Programming manual: STM32F40xxx and STM32F41xxx Flash programming + * September 2011, Doc ID 018520 Rev 1 + * https://github.com/libopencm3/libopencm3-archive/blob/master/st_micro/DM00023388.pdf + */ -#include +/* + * Differences between F7 and F4: + * 1. icache and dcache are now combined into a unified ART cache. The CPU has + * its own d/i-caches, but those are unrelated to this. They are on the + * AXIM bus. + * 2. There's an OPTCR1 is now used for boot addresses. Write protect bits + * are in OPTCR. Why does F4 have 2 copies of nWRP? + * 3. Latency field in FLASH_ACR is now 4 bits. Some CPU frequencies supported + * by F7 require more than 7 wait states. + * 4. FLASH_SR_PGSERR (programming sequence error) is now FLASH_SR_ERSERR ( + * erase sequence error). + * 5. FLASH_SR_BSY field is now read-only. Seems to also be read-only in F4? + * Why did we have a clear busy flag function? + * 6. There are now two watchdogs - IWDG (independent watchdog) and WWDG ( + * window watchdog). + */ + +/**@{*/ +/* --- FLASH registers ----------------------------------------------------- */ + +#define FLASH_ACR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x00) +#define FLASH_KEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x04) +#define FLASH_OPTKEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x08) +#define FLASH_SR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x0C) +#define FLASH_CR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x10) +#define FLASH_OPTCR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x14) +#define FLASH_OPTCR1 MMIO32(FLASH_MEM_INTERFACE_BASE + 0x18) + +/* --- FLASH Keys -----------------------------------------------------------*/ + +#define FLASH_KEYR_KEY1 0x45670123UL +#define FLASH_KEYR_KEY2 0xcdef89abUL +#define FLASH_OPTKEYR_KEY1 0x08192a3bUL +#define FLASH_OPTKEYR_KEY2 0x4c5d6e7fUL + +/* --- FLASH_ACR values ---------------------------------------------------- */ + +#define FLASH_ACR_ARTRST (1 << 11) +#define FLASH_ACR_ARTEN (1 << 9) +#define FLASH_ACR_PRFTEN (1 << 8) + +#define FLASH_ACR_LATENCY_MASK 0x0f + +/* --- FLASH_SR values ----------------------------------------------------- */ + +#define FLASH_SR_BSY (1 << 16) +#define FLASH_SR_ERSERR (1 << 7) +#define FLASH_SR_PGPERR (1 << 6) +#define FLASH_SR_PGAERR (1 << 5) +#define FLASH_SR_WRPERR (1 << 4) +#define FLASH_SR_OPERR (1 << 1) +#define FLASH_SR_EOP (1 << 0) + +/* --- FLASH_CR values ----------------------------------------------------- */ + +#define FLASH_CR_LOCK (1 << 31) +#define FLASH_CR_ERRIE (1 << 25) +#define FLASH_CR_EOPIE (1 << 24) +#define FLASH_CR_STRT (1 << 16) + +#define FLASH_CR_PROGRAM_MASK 0x3 +#define FLASH_CR_PROGRAM_SHIFT 8 +/** @defgroup flash_cr_program_width Flash programming width +@ingroup flash_group +@{*/ +#define FLASH_CR_PROGRAM_X8 0 +#define FLASH_CR_PROGRAM_X16 1 +#define FLASH_CR_PROGRAM_X32 2 +#define FLASH_CR_PROGRAM_X64 3 +/**@}*/ + +#define FLASH_CR_SNB_SHIFT 3 +#define FLASH_CR_SNB_MASK 0x1f + +#define FLASH_CR_MER (1 << 2) +#define FLASH_CR_SER (1 << 1) +#define FLASH_CR_PG (1 << 0) + +/* --- FLASH_OPTCR values -------------------------------------------------- */ + +#define FLASH_OPTCR_IWDG_STOP (1 << 31) +#define FLASH_OPTCR_IWDG_STDBY (1 << 30) + +#define FLASH_OPTCR_NWRP_SHIFT 16 +#define FLASH_OPTCR_NWRP_MASK 0xff + +#define FLASH_OPTCR_RDP_SHIFT 8 +#define FLASH_OPTCR_RDP_MASK 0xff + +#define FLASH_OPTCR_NRST_STDBY (1 << 7) +#define FLASH_OPTCR_NRST_STOP (1 << 6) +#define FLASH_OPTCR_IWDG_SW (1 << 5) +#define FLASH_OPTCR_WWDG_SW (1 << 4) + +#define FLASH_OPTCR_BOR_LEV_MASK 3 +#define FLASH_OPTCR_BOR_LEV_SHIFT 2 +#define FLASH_OPTCR_BOR_LEV_3 0x00 +#define FLASH_OPTCR_BOR_LEV_2 0x01 +#define FLASH_OPTCR_BOR_LEV_1 0x02 +#define FLASH_OPTCR_BOR_OFF 0x03 + +#define FLASH_OPTCR_OPTSTRT (1 << 1) +#define FLASH_OPTCR_OPTLOCK (1 << 0) + +/* --- FLASH_OPTCR1 values ------------------------------------------------- */ +#define FLASH_OPTCR1_BOOT_ADD1_MASK 0xffff +#define FLASH_OPTCR1_BOOT_ADD1_SHIFT 16 +#define FLASH_OPTCR1_BOOT_ADD0_MASK 0xffff +#define FLASH_OPTCR1_BOOT_ADD0_SHIFT 0 + +/* --- Function prototypes ------------------------------------------------- */ + +BEGIN_DECLS + +void flash_set_ws(uint32_t ws); +void flash_unlock(void); +void flash_lock(void); +void flash_clear_pgperr_flag(void); +void flash_clear_eop_flag(void); +void flash_wait_for_last_operation(void); + +void flash_unlock_option_bytes(void); +void flash_lock_option_bytes(void); +void flash_clear_erserr_flag(void); +void flash_clear_wrperr_flag(void); +void flash_clear_pgaerr_flag(void); +void flash_art_enable(void); +void flash_art_disable(void); +void flash_prefetch_enable(void); +void flash_prefetch_disable(void); +void flash_art_reset(void); +void flash_clear_status_flags(void); +void flash_erase_all_sectors(uint32_t program_size); +void flash_erase_sector(uint8_t sector, uint32_t program_size); +void flash_program_double_word(uint32_t address, uint64_t data); +void flash_program_word(uint32_t address, uint32_t data); +void flash_program_half_word(uint32_t address, uint16_t data); +void flash_program_byte(uint32_t address, uint8_t data); +void flash_program(uint32_t address, uint8_t *data, uint32_t len); +void flash_program_option_bytes(uint32_t data); + +END_DECLS +/**@}*/ #endif diff --git a/include/libopencm3/stm32/f7/rcc.h b/include/libopencm3/stm32/f7/rcc.h index 9b2fad67..ee2fb0bb 100644 --- a/include/libopencm3/stm32/f7/rcc.h +++ b/include/libopencm3/stm32/f7/rcc.h @@ -615,7 +615,7 @@ struct rcc_clock_scale { uint16_t plln; uint8_t pllp; uint8_t pllq; - uint32_t flash_config; + uint32_t flash_waitstates; uint8_t hpre; uint8_t ppre1; uint8_t ppre2; diff --git a/lib/stm32/f7/Makefile b/lib/stm32/f7/Makefile index 35efba6e..7e969269 100644 --- a/lib/stm32/f7/Makefile +++ b/lib/stm32/f7/Makefile @@ -42,9 +42,10 @@ TGT_CFLAGS += $(STANDARD_FLAGS) ARFLAGS = rcs -OBJS = pwr.o rcc.o gpio.o gpio_common_all.o gpio_common_f0234.o +OBJS = flash.o pwr.o rcc.o +OBJS += gpio.o gpio_common_all.o gpio_common_f0234.o -OBJS += rcc_common_all.o flash_common_f234.o flash_common_f24.o +OBJS += rcc_common_all.o OBJS += rng_common_v1.o diff --git a/lib/stm32/f7/flash.c b/lib/stm32/f7/flash.c new file mode 100644 index 00000000..e0e47d45 --- /dev/null +++ b/lib/stm32/f7/flash.c @@ -0,0 +1,479 @@ +/** @addtogroup flash_file + * + */ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2017 Matthew Lai @m@matthewlai.ca> + * Copyright (C) 2010 Thomas Otto + * Copyright (C) 2010 Mark Butler + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Program Parallelism Size + +Set the programming word width. Note carefully the power supply voltage +restrictions under which the different word sizes may be used. See the +programming manual for more information. +@param[in] psize The programming word width one of: @ref flash_cr_program_width +*/ + +static inline void flash_set_program_size(uint32_t psize) +{ + FLASH_CR &= ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT); + FLASH_CR |= psize << FLASH_CR_PROGRAM_SHIFT; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Issue Pipeline Stall + +Issue a pipeline stall to make sure all write operations completed. + +RM0385: After performing a data write operation and before polling the BSY bit +to be cleared, the software can issue a DSB instruction to guarantee the +completion of a previous data write operation. + +*/ + +static inline void flash_pipeline_stall(void) +{ + __asm__ volatile("dsb":::"memory"); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Set the Number of Wait States + +Used to match the system clock to the FLASH memory access time. See the +programming manual for more information on clock speed ranges. The latency must +be changed to the appropriate value before any increase in clock +speed, or after any decrease in clock speed. + +@param[in] ws values from @ref flash_latency. +*/ +void flash_set_ws(uint32_t ws) +{ + uint32_t reg32; + + reg32 = FLASH_ACR; + reg32 &= ~(FLASH_ACR_LATENCY_MASK); + reg32 |= ws; + FLASH_ACR = reg32; + + /* Wait until the new wait states take effect. + * RM0385: Check that the new number of wait states is taken into + * account to access the Flash memory by reading the FLASH_ACR register. + */ + while ((FLASH_ACR & FLASH_ACR_LATENCY_MASK) != ws); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Flash Program and Erase Controller + +This enables write access to the Flash memory. It is locked by default on +reset. +*/ + +void flash_unlock(void) +{ + /* Clear the unlock sequence state. */ + FLASH_CR |= FLASH_CR_LOCK; + + /* Authorize the FPEC access. */ + FLASH_KEYR = FLASH_KEYR_KEY1; + FLASH_KEYR = FLASH_KEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Flash Program and Erase Controller + +Used to prevent spurious writes to FLASH. +*/ + +void flash_lock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Error Status Flag + +*/ + +void flash_clear_pgperr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGPERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the End of Operation Status Flag + +*/ + +void flash_clear_eop_flag(void) +{ + FLASH_SR |= FLASH_SR_EOP; +} + + +/*---------------------------------------------------------------------------*/ +/** @brief Wait until Last Operation has Ended + +This loops indefinitely until an operation (write or erase) has completed by +testing the busy flag. +*/ + +void flash_wait_for_last_operation(void) +{ + flash_pipeline_stall(); + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Unlock the Option Byte Access + +This enables write access to the option bytes. It is locked by default on +reset. +*/ + +void flash_unlock_option_bytes(void) +{ + /* Clear the unlock state. */ + FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK; + + /* Unlock option bytes. */ + FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1; + FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Lock the Option Byte Access + +This disables write access to the option bytes. It is locked by default on +reset. +*/ + +void flash_lock_option_bytes(void) +{ + FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Erase Sequence Error Flag + +This flag is set when an erase operation is performed with control register has +not been correctly set. +*/ + +void flash_clear_erserr_flag(void) +{ + FLASH_SR |= FLASH_SR_ERSERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Programming Alignment Error Flag + +*/ + +void flash_clear_pgaerr_flag(void) +{ + FLASH_SR |= FLASH_SR_PGAERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear the Write Protect Error Flag + +*/ + +void flash_clear_wrperr_flag(void) +{ + FLASH_SR |= FLASH_SR_WRPERR; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the ART Cache + +*/ + +void flash_art_enable(void) +{ + FLASH_ACR |= FLASH_ACR_ARTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Enable the FLASH Prefetch Buffer + +This buffer is used for instruction fetches and is enabled by default after +reset. + +Note carefully the clock restrictions under which the prefetch buffer may be +enabled or disabled. Changes are normally made while the clock is running in +the power-on low frequency mode before being set to a higher speed mode. +See the reference manual for details. +*/ + +void flash_prefetch_enable(void) +{ + FLASH_ACR |= FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Disable the FLASH Prefetch Buffer + +Note carefully the clock restrictions under which the prefetch buffer may be +set to disabled. See the reference manual for details. +*/ + +void flash_prefetch_disable(void) +{ + FLASH_ACR &= ~FLASH_ACR_PRFTEN; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Reset the ART Cache + +The ART cache must be disabled for this to have effect. +*/ + +void flash_art_reset(void) +{ + FLASH_ACR |= FLASH_ACR_ARTRST; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Clear All Status Flags + +Program error, end of operation, write protect error. +*/ + +void flash_clear_status_flags(void) +{ + flash_clear_erserr_flag(); + flash_clear_pgaerr_flag(); + flash_clear_wrperr_flag(); + flash_clear_pgperr_flag(); + flash_clear_eop_flag(); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase All FLASH + +This performs all operations necessary to erase all sectors in the FLASH +memory. + +@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit) +*/ + +void flash_erase_all_sectors(uint32_t program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */ + FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */ + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Erase a Sector of FLASH + +This performs all operations necessary to erase a sector in FLASH memory. +The page should be checked to ensure that it was properly erased. A sector must +first be fully erased before attempting to program it. + +See the reference manual or the FLASH programming manual for details. + +@param[in] sector (0 - 11 for some parts, 0-23 on others) +@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit) +*/ + +void flash_erase_sector(uint8_t sector, uint32_t program_size) +{ + flash_wait_for_last_operation(); + flash_set_program_size(program_size); + + FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT); + FLASH_CR |= (sector & FLASH_CR_SNB_MASK) << FLASH_CR_SNB_SHIFT; + FLASH_CR |= FLASH_CR_SER; + FLASH_CR |= FLASH_CR_STRT; + + flash_wait_for_last_operation(); + FLASH_CR &= ~FLASH_CR_SER; + FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT); +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a 64 bit Word to FLASH + +This performs all operations necessary to program a 64 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] address Starting address in Flash. +@param[in] data Double word to write +*/ + +void flash_program_double_word(uint32_t address, uint64_t data) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X64); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_CR_PG; + + /* Program the double_word. */ + MMIO64(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a 32 bit Word to FLASH + +This performs all operations necessary to program a 32 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] address Starting address in Flash. +@param[in] data word to write +*/ + +void flash_program_word(uint32_t address, uint32_t data) +{ + /* Ensure that all flash operations are complete. */ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X32); + + /* Enable writes to flash. */ + FLASH_CR |= FLASH_CR_PG; + + /* Program the word. */ + MMIO32(address) = data; + + /* Wait for the write to complete. */ + flash_wait_for_last_operation(); + + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Half Word to FLASH + +This performs all operations necessary to program a 16 bit word to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] address Starting address in Flash. +@param[in] data half word to write +*/ + +void flash_program_half_word(uint32_t address, uint16_t data) +{ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X16); + + FLASH_CR |= FLASH_CR_PG; + + MMIO16(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program an 8 bit Byte to FLASH + +This performs all operations necessary to program an 8 bit byte to FLASH memory. +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] address Starting address in Flash. +@param[in] data byte to write +*/ + +void flash_program_byte(uint32_t address, uint8_t data) +{ + flash_wait_for_last_operation(); + flash_set_program_size(FLASH_CR_PROGRAM_X8); + + FLASH_CR |= FLASH_CR_PG; + + MMIO8(address) = data; + + flash_wait_for_last_operation(); + + FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */ +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program a Data Block to FLASH + +This programs an arbitrary length data block to FLASH memory. All the addresses +written to must have been erased (by calling flash_erase_sector). +The program error flag should be checked separately for the event that memory +was not properly erased. + +@param[in] address Starting address in Flash. +@param[in] data Pointer to start of data block. +@param[in] len Length of data block. +*/ + +void flash_program(uint32_t address, uint8_t *data, uint32_t len) +{ + /* TODO: Use dword and word size program operations where possible for + * turbo speed. + */ + uint32_t i; + for (i = 0; i < len; i++) { + flash_program_byte(address+i, data[i]); + } +} + +/*---------------------------------------------------------------------------*/ +/** @brief Program the Option Bytes + +This performs all operations necessary to program the option bytes. +The option bytes do not need to be erased first. + +@param[in] data value to be programmed. +*/ + +void flash_program_option_bytes(uint32_t data) +{ + flash_wait_for_last_operation(); + + if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) { + flash_unlock_option_bytes(); + } + + FLASH_OPTCR = data & ~0x3; + FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */ + flash_wait_for_last_operation(); +} +/**@}*/ diff --git a/lib/stm32/f7/rcc.c b/lib/stm32/f7/rcc.c index 4ef198e8..1ba55b03 100644 --- a/lib/stm32/f7/rcc.c +++ b/lib/stm32/f7/rcc.c @@ -13,13 +13,12 @@ const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = { .plln = 432, .pllp = 2, .pllq = 9, - .flash_config = FLASH_ACR_ICEN | FLASH_ACR_DCEN | - FLASH_ACR_LATENCY_7WS, .hpre = RCC_CFGR_HPRE_DIV_NONE, .ppre1 = RCC_CFGR_PPRE_DIV_4, .ppre2 = RCC_CFGR_PPRE_DIV_2, .vos_scale = PWR_SCALE1, .overdrive = 1, + .flash_waitstates = 7, .apb1_frequency = 108000000, .apb2_frequency = 216000000, }, @@ -328,7 +327,9 @@ void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock) rcc_wait_for_osc_ready(RCC_PLL); /* Configure flash settings. */ - flash_set_ws(clock->flash_config); + flash_set_ws(clock->flash_waitstates); + flash_art_enable(); + flash_prefetch_enable(); /* Select PLL as SYSCLK source. */ rcc_set_sysclk_source(RCC_CFGR_SW_PLL);