# HG changeset patch # User jlarmour # Date 1333245815 0 # Node ID ceb1113eb4bd41c1ca3215fc00392cd5384d9147 # Parent 43793d6f613ae570d30379c6bddce2a6053251a9 Add support for STM32 F2 / F4 processors. diff --git a/packages/devs/flash/cortexm/stm32/current/ChangeLog b/packages/devs/flash/cortexm/stm32/current/ChangeLog --- a/packages/devs/flash/cortexm/stm32/current/ChangeLog +++ b/packages/devs/flash/cortexm/stm32/current/ChangeLog @@ -1,3 +1,33 @@ +2012-03-15 James Smith + + * src/stm32_flash.c: Add support for F4 family devices, and + explicit flash size support for specific F4xxx[EG] devices. + + * include/stm32_flash.h: + * cdl/flash_stm32.cdl (CYGNUM_DEVS_FLASH_STM32_PARALLELISM): + Support for F4 devices. + +2012-02-29 James Smith + + * src/stm32_flash.c (stm32_flash_hw_program): Compilation fixes to + use renamed WAIT_FOR_FLASH_NOT_BUSY macro and to add missing + semi-colon + +2011-12-15 Jonathan Larmour + + * cdl/flash_stm32.cdl (CYGNUM_DEVS_FLASH_STM32_PARALLELISM): New + option. Configures program/erase width on F2 processors. + * include/stm32_flash.h: Make private device driver data const - it + doesn't change so shouldn't be in RAM. Support multiple flash regions + for F2. + * src/stm32_flash.c: Substantial changes to support F2 processors. + Also improve error checking, timeout detection and general robustness. + +2009-07-03 Nick Garnett + + * src/stm32_flash.c (stm32_flash_init): Add tests for connectivity + line devices. + 2009-04-06 Simon Kallweit * src/stm32_flash.c: @@ -27,7 +57,7 @@ 2008-10-07 Nick Garnett +#include +#include +#include + +#if defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_F1) +# define STM32_FLASH_MAXBLOCKINFOS 1 +#elif defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_HIPERFORMANCE) +# define STM32_FLASH_MAXBLOCKINFOS 3 +#endif + // The driver-specific data, pointed at by the priv field in a // a cyg_flash_dev structure. typedef struct cyg_stm32_dev { - cyg_flash_block_info_t block_info[1]; - + cyg_flash_block_info_t block_info[STM32_FLASH_MAXBLOCKINFOS]; } cyg_stm32_flash_dev; +// The instantiation of that data. +__externC const cyg_stm32_flash_dev hal_stm32_flash_priv; + //========================================================================*/ // Exported function pointers. @@ -65,4 +78,4 @@ typedef struct cyg_stm32_dev //========================================================================*/ #endif // CYGONCE_DEVS_FLASH_STM32_H -// End +// End of stm32_flash.h diff --git a/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c b/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c --- a/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c +++ b/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c @@ -8,7 +8,7 @@ // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2008 Free Software Foundation, Inc. +// Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -68,9 +68,43 @@ #include CYGHWR_MEMORY_LAYOUT_H +// Does this look like an F1 or F2/F4 device? It makes a difference to sizing and operation. +#if defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_F1) +# define F1STYLE 1 +#elif defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_HIPERFORMANCE) +# define F2STYLE 1 +#endif + +// ---------------------------------------------------------------------------- + +#if defined(F1STYLE) +typedef cyg_uint16 STM32_TYPE; +#elif defined(F2STYLE) +// F2/F4's alignment requirements depend on parallelism config, so we treat as +// bytes for now. +typedef cyg_uint8 STM32_TYPE; +#endif + // ---------------------------------------------------------------------------- -typedef cyg_uint16 STM32_TYPE; +// How many loops before we consider this a timeout. +#define STM32_FLASH_TIMEOUT 1000000 + +// A quick helper macro to avoid repetition. +#define WAIT_FOR_FLASH_NOT_BUSY(_timeout_) \ + CYG_MACRO_START \ + (_timeout_) = STM32_FLASH_TIMEOUT; \ + do { \ + HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); \ + } while( (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY) && (_timeout_)-- > 0 ); \ + CYG_MACRO_END + +// ---------------------------------------------------------------------------- + +// Note that although the F2/F4 parts need special treatment for the Flash's +// built-in icache and dcache, that doesn't matter for suspend/resume +// because no-one should expect any part of the Flash in the area being +// erased/programmed to be any particular value. # define STM32_INTSCACHE_STATE int _saved_ints_ # define STM32_INTSCACHE_BEGIN() HAL_DISABLE_INTERRUPTS(_saved_ints_) @@ -85,8 +119,8 @@ typedef cyg_uint16 STM32_TYPE; static int stm32_enable_hsi(void); static void stm32_disable_hsi(void); -static int stm32_flash_hw_erase(cyg_flashaddr_t addr) __attribute__((section (".2ram.stm32_flash_hw_erase"))); -static int stm32_flash_hw_program( volatile STM32_TYPE* addr, const cyg_uint16* buf, cyg_uint32 count) __attribute__((section (".2ram.stm32_flash_hw_program"))); +static int stm32_flash_hw_erase(cyg_flashaddr_t addr, cyg_uint16 block_num) __attribute__((section (".2ram.stm32_flash_hw_erase"))); +static int stm32_flash_hw_program( volatile STM32_TYPE* addr, const STM32_TYPE *buf, cyg_uint32 count) __attribute__((section (".2ram.stm32_flash_hw_program"))); // ---------------------------------------------------------------------------- // Diagnostic routines. @@ -100,66 +134,203 @@ static int stm32_flash_hw_program( volat #endif // ---------------------------------------------------------------------------- +// Select Flash geometry + +#if defined(CYGHWR_HAL_CORTEXM_STM32_F103RC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103VC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103ZC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F105RC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F105RC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F105VC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F107VC) + + // High-density device with 256K flash (2K blocks) +#define STM32_FLASH_SIZE 0x40000 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RD) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103VD) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103ZD) + + // High-density device with 384K flash (2K blocks) +#define STM32_FLASH_SIZE 0x60000 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103VE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F103ZE) + + // High-density device with 512K flash (2K blocks) +#define STM32_FLASH_SIZE 0x80000 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RB) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205VB) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205ZB) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207VB) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207ZB) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207IB) +// 128K +#define STM32_FLASH_SIZE (128*1024) +#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 } } } // guesswork at present - documentation is elusive +#define STM32_FLASH_NUM_BLOCK_INFOS 2 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205VC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205ZC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207VC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207ZC) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207IC) +// 256K +#define STM32_FLASH_SIZE (256*1024) +#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 1 } } } // guesswork at present - documentation is elusive +#define STM32_FLASH_NUM_BLOCK_INFOS 3 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205VE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205ZE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207VE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207ZE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207IE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407IE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407VE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407ZE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417IE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417VE) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417ZE) +// 512K +#define STM32_FLASH_SIZE (512*1024) +#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 3 } } } // guesswork at present - documentation is elusive +#define STM32_FLASH_NUM_BLOCK_INFOS 3 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RF) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205VF) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205ZF) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207VF) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207ZF) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207IF) +// 768K +#define STM32_FLASH_SIZE (768*1024) +#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 5 } } } // guesswork at present - documentation is elusive +#define STM32_FLASH_NUM_BLOCK_INFOS 3 + +#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205VG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F205ZG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207VG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207ZG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F207IG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F405RG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F405VG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F405ZG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407IG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407VG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F407ZG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417IG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417VG) || \ + defined(CYGHWR_HAL_CORTEXM_STM32_F417ZG) + +// 1024K +#define STM32_FLASH_SIZE (1024*1024) +#define STM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 7 } } } +#define STM32_FLASH_NUM_BLOCK_INFOS 3 + +#else +#error Unknown STM32 microprocessor variant. +#endif + +#ifdef F1STYLE +// Always 2K blocks +#define STM32_FLASH_BLOCK_SIZE 0x800 +#endif + +// If there's just one block size, it's straightforward. +#if defined(STM32_FLASH_BLOCK_SIZE) +const cyg_stm32_flash_dev hal_stm32_flash_priv = { { STM32_FLASH_BLOCK_SIZE, STM32_FLASH_SIZE / STM32_FLASH_BLOCK_SIZE } }; +#elif defined(STM32_FLASH_BLOCK_INFO) +const cyg_stm32_flash_dev hal_stm32_flash_priv = STM32_FLASH_BLOCK_INFO; +#else +# error Incomplete STM32 variant details. It needs filling in. +#endif + +// ---------------------------------------------------------------------------- + +#ifdef CYGNUM_DEVS_FLASH_STM32_PARALLELISM +# define CR_PSIZE_MAX CYGHWR_HAL_STM32_FLASH_CR_PSIZE(CYGNUM_DEVS_FLASH_STM32_PARALLELISM) +# define PARALLEL_BYTES (CYGNUM_DEVS_FLASH_STM32_PARALLELISM/8) +# define PARALLEL_ALIGN_MASK (PARALLEL_BYTES - 1) +#endif + +// ---------------------------------------------------------------------------- +// Translate our error values into eCos flash driver error values + +// Some little helper macros for this function to make it shorter/simpler +#define _SRBIT(_x_) CYGHWR_HAL_STM32_FLASH_SR_##_x_ +#define _FERR(_x_) CYG_FLASH_ERR_##_x_ +#define DECODE_SR_ERROR(_srbit_, _code_) if ( sr & _SRBIT(_srbit_) ) result = _FERR(_code_) + +static int +stm32_flash_decode_error( int sr ) +{ + int result = CYG_FLASH_ERR_OK; + + // -1 can never be a valid sr value so we use it to indicate a timeout + if ( -1 == sr ) + return CYG_FLASH_ERR_DRV_TIMEOUT; + +#if defined(F1STYLE) + DECODE_SR_ERROR( PGERR, PROGRAM ); + DECODE_SR_ERROR( WRPRTERR, PROTECT ); +#elif defined(F2STYLE) + // OPERR is probably unnecessary really, but just in case. + // Do it before others though so they can override with a better value. + DECODE_SR_ERROR( OPERR, HWR ); + DECODE_SR_ERROR( WRPERR, PROTECT ); + DECODE_SR_ERROR( PGAERR, INVALID ); + DECODE_SR_ERROR( PGPERR, PROTOCOL ); + DECODE_SR_ERROR( PGSERR, PROTOCOL ); +#endif + return result; +} + +static void stm32_flash_clear_sr_err(void) +{ + cyg_uint32 sr; +#if defined(F1STYLE) + sr = CYGHWR_HAL_STM32_FLASH_SR_PGERR | CYGHWR_HAL_STM32_FLASH_SR_WRPRTERR; +#elif defined(F2STYLE) + sr = CYGHWR_HAL_STM32_FLASH_SR_OPERR | + CYGHWR_HAL_STM32_FLASH_SR_WRPERR | + CYGHWR_HAL_STM32_FLASH_SR_PGAERR | + CYGHWR_HAL_STM32_FLASH_SR_PGPERR | + CYGHWR_HAL_STM32_FLASH_SR_PGSERR; +#endif + HAL_WRITE_UINT32( CYGHWR_HAL_STM32_FLASH + CYGHWR_HAL_STM32_FLASH_SR, sr ); +} + +// ---------------------------------------------------------------------------- // Initialize the flash. static int stm32_flash_init(struct cyg_flash_dev* dev) { - cyg_stm32_flash_dev *stm32_dev = (cyg_stm32_flash_dev *)dev->priv; - CYG_ADDRESS base = CYGHWR_HAL_STM32_FLASH; - cyg_uint32 flash_size, block_size = 0; - // Set up the block info entries. - dev->block_info = &stm32_dev->block_info[0]; - dev->num_block_infos = 1; + dev->block_info = &hal_stm32_flash_priv.block_info[0]; +#if defined(STM32_FLASH_NUM_BLOCK_INFOS) + dev->num_block_infos = STM32_FLASH_NUM_BLOCK_INFOS; +#else + dev->num_block_infos = sizeof(hal_stm32_flash_priv.block_info) / sizeof(hal_stm32_flash_priv.block_info[0]); +#endif // As stated in the errata sheet, the debug register can only be read in - // debug mode and is therfore not accessible by user software. + // debug mode and is therefore not accessible by user software. + + // Set end address + dev->end = dev->start + STM32_FLASH_SIZE - 1; -#if defined(CYGHWR_HAL_CORTEXM_STM32_F103RC) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103VC) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103ZC) - - // High-density device with 256K flash (2K blocks) - flash_size = 0x40000; - block_size = 0x800; - -#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RD) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103VD) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103ZD) - - // High-density device with 384K flash (2K blocks) - flash_size = 0x60000; - block_size = 0x800; - -#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RE) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103VE) || \ - defined(CYGHWR_HAL_CORTEXM_STM32_F103ZE) - - // High-density device with 512K flash (2K blocks) - flash_size = 0x80000; - block_size = 0x800; + stf_diag("block_size %d size %08x end %08x\n", dev->block_info[0].block_size, STM32_FLASH_SIZE, dev->end ); -#else - -#error Unknown STM32 microprocessor variant. - -#endif - - stm32_dev->block_info[0].blocks = flash_size/block_size; - stm32_dev->block_info[0].block_size = block_size; - - // Set end address - dev->end = dev->start+flash_size-1; - - stf_diag("block_size %d size %08x end %08x\n", block_size, flash_size, dev->end ); - - // Unlock the flash control registers - - HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY1 ); - HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY2 ); + // Ensure there's nothing hanging over from before us. + stm32_flash_clear_sr_err(); return CYG_FLASH_ERR_OK; } @@ -178,31 +349,46 @@ stm32_flash_query(struct cyg_flash_dev* // Get info about the current block, i.e. base and size. static void -stm32_flash_get_block_info(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr, cyg_flashaddr_t* block_start, size_t* block_size) +stm32_flash_get_block_info(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr, cyg_flashaddr_t* block_start, + size_t* block_size, cyg_uint16 *block_num) { size_t offset = addr - dev->start; + cyg_ucount8 i; + cyg_uint32 bi_size_passed = 0; + cyg_uint16 blocks_passed = 0; - *block_start = dev->start + (offset & ~(dev->block_info[0].block_size-1)); - *block_size = dev->block_info[0].block_size; + // This loop has the termination condition commented out to silence a + // warning. It should never be reached anyway, so that's fine, although + // that is checked with an assert. + + for ( i=0; /* i < dev->num_block_info */ ; i++ ) +{ + const cyg_flash_block_info_t *bi = &dev->block_info[i]; + cyg_uint32 bi_size = bi->blocks * bi->block_size; + + CYG_ASSERTC( i < dev->num_block_infos ); + + if ( offset < bi_size) + { + *block_start = dev->start + bi_size_passed + (offset & ~(bi->block_size-1)); + *block_size = bi->block_size; + while (offset >= bi->block_size) + { + offset -= bi->block_size; + blocks_passed++; +} + *block_num = blocks_passed; + break; + } + bi_size_passed += bi_size; + offset -= bi_size; + blocks_passed += bi->blocks; + } } // ---------------------------------------------------------------------------- static int -stm32_flash_decode_error( int sr ) -{ - int result = CYG_FLASH_ERR_OK; - - if( sr & CYGHWR_HAL_STM32_FLASH_SR_PGERR ) - result = CYG_FLASH_ERR_PROGRAM; - - if( sr & CYGHWR_HAL_STM32_FLASH_SR_WRPRTERR ) - result = CYG_FLASH_ERR_PROTECT; - - return result; -} - -static int stm32_enable_hsi(void) { CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC; @@ -239,61 +425,191 @@ stm32_disable_hsi(void) // points at the start of the sector. static int -stm32_flash_hw_erase(cyg_flashaddr_t addr) +stm32_flash_hw_erase(cyg_flashaddr_t addr, cyg_uint16 block_num) { cyg_uint32 base = CYGHWR_HAL_STM32_FLASH; - cyg_uint32 sr, cr = 0; - cyg_uint32 timeout = 100000; + cyg_uint32 sr, cr; + cyg_uint32 timeout; - cr |= CYGHWR_HAL_STM32_FLASH_CR_PER; +#ifdef CYGDBG_USE_ASSERTS + HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); + CYG_ASSERT( 0 == (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY), + "Flash busy at start of erase, but it shouldn't be" ); +#endif + + // Unlock the flash control registers + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY1 ); + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY2 ); + +#if defined(F1STYLE) + cr = CYGHWR_HAL_STM32_FLASH_CR_PER; HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_AR, addr ); + cr |= CYGHWR_HAL_STM32_FLASH_CR_STRT; +#elif defined(F2STYLE) + cr = CYGHWR_HAL_STM32_FLASH_CR_SER | + CR_PSIZE_MAX | + CYGHWR_HAL_STM32_FLASH_CR_SNB(block_num) | + CYGHWR_HAL_STM32_FLASH_CR_STRT; +#endif - HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_AR, addr ); - - cr |= CYGHWR_HAL_STM32_FLASH_CR_STRT; HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); - do + WAIT_FOR_FLASH_NOT_BUSY( timeout ); + + // Lock CR again (and clear other bits) + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, CYGHWR_HAL_STM32_FLASH_CR_LOCK ); + +#ifdef F2STYLE + // For F2 parts, we need to disable and reset the icache and dcache in the ACR. { - HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); - } while( (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY) && timeout-- > 0); + cyg_uint32 acr; - HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, 0 ); + HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // disable + acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN); + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // reset + acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // re-enable + acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST); + acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + } +#endif + + if (0 == timeout) + return -1; return sr; } // ---------------------------------------------------------------------------- -// Write data to flash, using individual word writes. The destination -// address will be aligned in a way suitable for the bus. The source -// address need not be aligned. The count is in STM32_TYPE's, not in -// bytes. +// Write data to flash, using individual word writes on F1, or something more +// complicated on F2. On F1, the destination address will be aligned in a way suitable +// for the bus. The source address need not be aligned. The count is in STM32_TYPE's on +// F1, bytes on F2. static int -stm32_flash_hw_program( volatile STM32_TYPE* addr, const cyg_uint16* buf, cyg_uint32 count) +stm32_flash_hw_program( volatile STM32_TYPE* addr, const STM32_TYPE* buf, cyg_uint32 count) { cyg_uint32 base = CYGHWR_HAL_STM32_FLASH; cyg_uint32 sr = 0, cr = 0; + cyg_uint32 timeout = 1; // Have to set timeout to non-zero to avoid confusing tests later. +#ifdef CYGDBG_USE_ASSERTS + HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); + CYG_ASSERT( 0 == (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY), + "Flash busy at start of program, but it shouldn't be" ); +#endif + + // Unlock the flash control registers + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY1 ); + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY2 ); + +#if defined(F1STYLE) cr |= CYGHWR_HAL_STM32_FLASH_CR_PG; HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); while( count-- ) { - cyg_uint32 timeout = 100000; - HAL_WRITE_UINT16( addr, *buf ); - addr++; buf++; - do - { - HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); - } while( (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY) && timeout-- > 0 ); + WAIT_FOR_FLASH_NOT_BUSY(timeout); + if ( 0 == timeout ) + break; } - HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, 0 ); + +#elif defined(F2STYLE) + // F2 is more complicated because the alignment depends on the parallelism. + // So we "simplify" by writing bytes until we've reached the desired alignment. + + { + CYG_ADDRESS addr_max = (CYG_ADDRESS)addr + PARALLEL_ALIGN_MASK; + addr_max &= ~PARALLEL_ALIGN_MASK; + + byte_write: + cr = CYGHWR_HAL_STM32_FLASH_CR_PG | CYGHWR_HAL_STM32_FLASH_CR_PSIZE_8; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); + + while (count && ((CYG_ADDRESS)addr < addr_max)) + { + HAL_WRITE_UINT8( addr, *buf ); + addr++; + buf++; + count--; + WAIT_FOR_FLASH_NOT_BUSY(timeout); + if (0 == timeout) + break; + } + + if ( count && timeout ) + { + // Now we should be aligned to the required parallelism boundary + // But we have to make sure we stop at an aligned addr too. + addr_max += count; + addr_max &= ~PARALLEL_ALIGN_MASK; + + cr = CYGHWR_HAL_STM32_FLASH_CR_PG | CR_PSIZE_MAX; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); + while ((CYG_ADDRESS)addr < addr_max) + { +#if (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 8) + HAL_WRITE_UINT8( addr, *buf ); +#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 16) + cyg_uint16 wbuf = *(cyg_uint16*)buf; + HAL_WRITE_UINT16( addr, wbuf ); +#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 32) + cyg_uint32 wbuf = *(cyg_uint32*)buf; + HAL_WRITE_UINT32( addr, wbuf ); +#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 64) + cyg_uint64 wbuf = *(cyg_uint64*)buf; + HAL_WRITE_UINT64( addr, wbuf ); +#endif + addr += PARALLEL_BYTES; + buf += PARALLEL_BYTES; + count -= PARALLEL_BYTES; + WAIT_FOR_FLASH_NOT_BUSY(timeout); + if (0 == timeout) + break; + } // while + } // if + + if ( count && timeout ) + { + // Still have some bytes left to write. Take a shortcut with goto, to save code. + addr_max = (CYG_ADDRESS)addr+count; + goto byte_write; + } // if + } + + // For F2 parts, we need to disable and reset the icache and dcache in the ACR. + { + cyg_uint32 acr; + + HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // disable + acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN); + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // reset + acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + // re-enable + acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST); + acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN; + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr ); + } +#endif // elif defined(F2STYLE) + + // Lock CR again (and clear other bits) + HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, CYGHWR_HAL_STM32_FLASH_CR_LOCK ); + + if (0 == timeout) + return -1; return sr; } @@ -305,9 +621,10 @@ stm32_flash_hw_program( volatile STM32_T static int stm32_flash_erase(struct cyg_flash_dev* dev, cyg_flashaddr_t dest) { - int (*erase_fn)(cyg_uint32); + int (*erase_fn)(cyg_uint32, cyg_uint16); cyg_flashaddr_t block_start; size_t block_size; + cyg_uint16 block_num; int result; int hsi; STM32_INTSCACHE_STATE; @@ -316,18 +633,19 @@ stm32_flash_erase(struct cyg_flash_dev* CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required"); CYG_ASSERT((dest >= dev->start) && (dest <= dev->end), "flash address out of device range"); - stm32_flash_get_block_info(dev, dest, &block_start, &block_size); + stm32_flash_get_block_info(dev, dest, &block_start, &block_size, &block_num); stf_diag("block_start %p block_size %d\n", (void *) block_start, block_size); CYG_ASSERT(dest == block_start, "erase address should be the start of a flash block"); - erase_fn = (int (*)(cyg_uint32)) cyg_flash_anonymizer( & stm32_flash_hw_erase ); + erase_fn = (int (*)(cyg_uint32, cyg_uint16)) cyg_flash_anonymizer( & stm32_flash_hw_erase ); hsi = stm32_enable_hsi(); STM32_INTSCACHE_BEGIN(); - result = (*erase_fn)(block_start); + result = (*erase_fn)(block_start, block_num); result = stm32_flash_decode_error( result ); + stm32_flash_clear_sr_err(); STM32_INTSCACHE_END(); @@ -345,9 +663,9 @@ stm32_flash_erase(struct cyg_flash_dev* int stm32_flash_program(struct cyg_flash_dev* dev, cyg_flashaddr_t dest, const void* src, size_t len) { - int (*program_fn)(volatile STM32_TYPE*, const cyg_uint16*, cyg_uint32); + int (*program_fn)(volatile STM32_TYPE*, const STM32_TYPE*, cyg_uint32); volatile STM32_TYPE* uncached; - const cyg_uint16* data; + const STM32_TYPE* data; size_t to_write; int result = CYG_FLASH_ERR_OK; int hsi; @@ -358,15 +676,17 @@ stm32_flash_program(struct cyg_flash_dev CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required"); CYG_ASSERT((dest >= dev->start) && ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range"); +#ifdef F1STYLE // Source and destination must be 16-bit aligned. if( (0 != ((CYG_ADDRESS)dest & 1)) || (0 != ((CYG_ADDRESS)src & 1)) ) return CYG_FLASH_ERR_INVALID; +#endif uncached = STM32_UNCACHED_ADDRESS(dest); - data = (const cyg_uint16*) src; - to_write = len / sizeof(STM32_TYPE); // Number of words, not bytes - program_fn = (int (*)(volatile STM32_TYPE*, const cyg_uint16*, cyg_uint32)) cyg_flash_anonymizer( & stm32_flash_hw_program ); + data = (const STM32_TYPE*) src; + to_write = len / sizeof(STM32_TYPE); // For F1: Number of words, not bytes. For F2: STM32_TYPE is a byte. + program_fn = (int (*)(volatile STM32_TYPE*, const STM32_TYPE*, cyg_uint32)) cyg_flash_anonymizer( & stm32_flash_hw_program ); hsi = stm32_enable_hsi(); @@ -393,6 +713,7 @@ stm32_flash_program(struct cyg_flash_dev STM32_INTSCACHE_RESUME(); } } + stm32_flash_clear_sr_err(); STM32_INTSCACHE_END(); if (hsi)