Mercurial > nand-ecoscentric
changeset 3220:ceb1113eb4bd
Add support for STM32 F2 / F4 processors.
| author | jlarmour |
|---|---|
| date | Sun, 01 Apr 2012 02:03:35 +0000 |
| parents | 43793d6f613a |
| children | a9a10d06a94b |
| files | packages/devs/flash/cortexm/stm32/current/ChangeLog packages/devs/flash/cortexm/stm32/current/cdl/flash_stm32.cdl packages/devs/flash/cortexm/stm32/current/include/stm32_flash.h packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c |
| diffstat | 4 files changed, 486 insertions(+), 108 deletions(-) [+] |
line wrap: on
line diff
--- 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 <jsmith@ecoscentric.com> + + * 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 <jsmith@ecoscentric.com> + + * 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 <jifl@eCosCentric.com> + + * 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 <nickg@ecoscentric.com> + + * src/stm32_flash.c (stm32_flash_init): Add tests for connectivity + line devices. + 2009-04-06 Simon Kallweit <simon.kallweit@intefo.ch> * src/stm32_flash.c: @@ -27,7 +57,7 @@ 2008-10-07 Nick Garnett <nickg@ecoscen // ####GPLCOPYRIGHTBEGIN#### // ------------------------------------------- // 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. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by
--- a/packages/devs/flash/cortexm/stm32/current/cdl/flash_stm32.cdl +++ b/packages/devs/flash/cortexm/stm32/current/cdl/flash_stm32.cdl @@ -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, 2011 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 @@ -83,6 +83,20 @@ cdl_package CYGPKG_DEVS_FLASH_STM32 { times but reduce overhead." } + cdl_option CYGNUM_DEVS_FLASH_STM32_PARALLELISM { + display "Program/erase parallelism" + flavor data + legal_values { 8 16 32 64 } + active_if { ((CYGHWR_HAL_CORTEXM_STM32_FAMILY == "F2") || (CYGHWR_HAL_CORTEXM_STM32_FAMILY == "F4")) } + default_value 32 + description " + The Flash interface of the STM32 F2 and F4 families can program or erase + multiple bits in one step. The maximum possible parallelism depends + on the supply voltage. The default value of this option (32) + corresponds to supply voltage of 2.7 - 3.6V, but another value + may be chosen if a different voltage is used." + } + cdl_component CYGPKG_DEVS_FLASH_STM32_OPTIONS { display "STM32 driver build options" flavor none
--- a/packages/devs/flash/cortexm/stm32/current/include/stm32_flash.h +++ b/packages/devs/flash/cortexm/stm32/current/include/stm32_flash.h @@ -10,7 +10,7 @@ // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2008 Free Software Foundation, Inc. +// Copyright (C) 2008, 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 @@ -48,15 +48,28 @@ // //========================================================================*/ +#include <pkgconf/hal_cortexm_stm32.h> +#include <cyg/infra/cyg_type.h> +#include <cyg/io/flash.h> +#include <cyg/io/flash_dev.h> + +#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
--- 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)
