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)