URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [flash/] [cortexm/] [stm32/] [current/] [src/] [stm32_flash.c] - Rev 863
Go to most recent revision | Compare with Previous | Blame | View Log
//========================================================================== // // stm32_flash.c // // STM32 internal flash driver // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 2008 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 // Software Foundation; either version 2 or (at your option) any later // version. // // eCos 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 General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): nickg // Date: 2008-09-22 // //####DESCRIPTIONEND#### // //========================================================================*/ #include <pkgconf/hal_cortexm_stm32.h> #include <pkgconf/devs_flash_stm32.h> #include <cyg/infra/cyg_type.h> #include <cyg/infra/cyg_ass.h> #include <cyg/infra/diag.h> #include <cyg/io/flash.h> #include <cyg/io/flash_dev.h> #include <cyg/hal/hal_arch.h> #include <cyg/hal/hal_intr.h> #include <cyg/hal/hal_cache.h> #include <cyg/hal/hal_io.h> #include <cyg/hal/hal_if.h> #include <string.h> #include <cyg/io/stm32_flash.h> #include CYGHWR_MEMORY_LAYOUT_H // ---------------------------------------------------------------------------- typedef cyg_uint16 STM32_TYPE; # define STM32_INTSCACHE_STATE int _saved_ints_ # define STM32_INTSCACHE_BEGIN() HAL_DISABLE_INTERRUPTS(_saved_ints_) # define STM32_INTSCACHE_SUSPEND() HAL_RESTORE_INTERRUPTS(_saved_ints_) # define STM32_INTSCACHE_RESUME() HAL_DISABLE_INTERRUPTS(_saved_ints_) # define STM32_INTSCACHE_END() HAL_RESTORE_INTERRUPTS(_saved_ints_) #define STM32_UNCACHED_ADDRESS(__x) ((STM32_TYPE *)(__x)) // ---------------------------------------------------------------------------- // Forward declarations for functions that need to be placed in RAM: 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"))); // ---------------------------------------------------------------------------- // Diagnostic routines. #if 0 #define stf_diag( __fmt, ... ) diag_printf("STF: %20s[%3d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ ); #define stf_dump_buf( __addr, __size ) diag_dump_buf( __addr, __size ) #else #define stf_diag( __fmt, ... ) #define stf_dump_buf( __addr, __size ) #endif // ---------------------------------------------------------------------------- // 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; // As stated in the errata sheet, the debug register can only be read in // debug mode and is therfore not accessible by user software. #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; #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 ); return CYG_FLASH_ERR_OK; } // ---------------------------------------------------------------------------- static size_t stm32_flash_query(struct cyg_flash_dev* dev, void* data, size_t len) { static char query[] = "STM32 Internal Flash"; memcpy( data, query, sizeof(query)); return sizeof(query); } // ---------------------------------------------------------------------------- // 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) { size_t offset = addr - dev->start; *block_start = dev->start + (offset & ~(dev->block_info[0].block_size-1)); *block_size = dev->block_info[0].block_size; } // ---------------------------------------------------------------------------- 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; cyg_uint32 cr; HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr ); if( cr & CYGHWR_HAL_STM32_RCC_CR_HSIRDY ) return 0; cr |= CYGHWR_HAL_STM32_RCC_CR_HSION; HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr ); while( cr & CYGHWR_HAL_STM32_RCC_CR_HSIRDY ) HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr ); return 1; } static void stm32_disable_hsi(void) { CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC; cyg_uint32 cr; HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr ); cr &= ~(CYGHWR_HAL_STM32_RCC_CR_HSION | CYGHWR_HAL_STM32_RCC_CR_HSIRDY); HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr ); } // ---------------------------------------------------------------------------- // Erase a single sector. There is no API support for chip-erase. The // generic code operates one sector at a time, invoking the driver for // each sector, so there is no opportunity inside the driver for // erasing multiple sectors in a single call. The address argument // points at the start of the sector. static int stm32_flash_hw_erase(cyg_flashaddr_t addr) { cyg_uint32 base = CYGHWR_HAL_STM32_FLASH; cyg_uint32 sr, cr = 0; cyg_uint32 timeout = 100000; 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; HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr ); do { HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); } while( (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY) && timeout-- > 0); HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, 0 ); 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. static int stm32_flash_hw_program( volatile STM32_TYPE* addr, const cyg_uint16* buf, cyg_uint32 count) { cyg_uint32 base = CYGHWR_HAL_STM32_FLASH; cyg_uint32 sr = 0, cr = 0; 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 ); } HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, 0 ); return sr; } // ---------------------------------------------------------------------------- // Erase a single block. The calling code will have supplied a pointer // aligned to a block boundary. static int stm32_flash_erase(struct cyg_flash_dev* dev, cyg_flashaddr_t dest) { int (*erase_fn)(cyg_uint32); cyg_flashaddr_t block_start; size_t block_size; int result; int hsi; STM32_INTSCACHE_STATE; stf_diag("dest %p\n", (void *) dest); 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); 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 ); hsi = stm32_enable_hsi(); STM32_INTSCACHE_BEGIN(); result = (*erase_fn)(block_start); result = stm32_flash_decode_error( result ); STM32_INTSCACHE_END(); if (hsi) stm32_disable_hsi(); return result; } // ---------------------------------------------------------------------------- // Write some data to the flash. The destination must be aligned to a // 16 bit boundary. Higher level code guarantees that the data will // not straddle a block boundary. 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); volatile STM32_TYPE* uncached; const cyg_uint16* data; size_t to_write; int result = CYG_FLASH_ERR_OK; int hsi; STM32_INTSCACHE_STATE; stf_diag("dest %p src %p len %p(%d)\n", (void *) dest, src, (void *) len, len); 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"); // Source and destination must be 16-bit aligned. if( (0 != ((CYG_ADDRESS)dest & 1)) || (0 != ((CYG_ADDRESS)src & 1)) ) return CYG_FLASH_ERR_INVALID; 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 ); hsi = stm32_enable_hsi(); STM32_INTSCACHE_BEGIN(); while (to_write > 0) { size_t this_write = (to_write < CYGNUM_DEVS_FLASH_STM32_V2_PROGRAM_BURST_SIZE) ? to_write : CYGNUM_DEVS_FLASH_STM32_V2_PROGRAM_BURST_SIZE; result = (*program_fn)(uncached, data, this_write); result = stm32_flash_decode_error( result ); if (result != CYG_FLASH_ERR_OK) { break; } to_write -= this_write; if (to_write > 0) { // There is still more to be written. The last write must have been a burst size uncached += this_write; data += this_write; STM32_INTSCACHE_SUSPEND(); STM32_INTSCACHE_RESUME(); } } STM32_INTSCACHE_END(); if (hsi) stm32_disable_hsi(); return result; } // ---------------------------------------------------------------------------- // Function table const CYG_FLASH_FUNS(cyg_stm32_flash_funs, &stm32_flash_init, &stm32_flash_query, &stm32_flash_erase, &stm32_flash_program, (int (*)(struct cyg_flash_dev*, const cyg_flashaddr_t, void*, size_t))0, cyg_flash_devfn_lock_nop, cyg_flash_devfn_unlock_nop); // ---------------------------------------------------------------------------- // End of stm32_flash.c
Go to most recent revision | Compare with Previous | Blame | View Log