From ec3166808afafa4cdae2f542253cd0a530e6ee79 Mon Sep 17 00:00:00 2001 From: asterix Date: Mon, 9 Aug 2010 17:15:26 +0000 Subject: [PATCH] Add embedded flash module for stm32. First refactor of emb flash using kblock. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4155 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_emb_flash.h | 58 ++++++ bertos/cpu/cortex-m3/drv/flash_cm3.h | 2 + bertos/cpu/cortex-m3/drv/flash_stm32.c | 276 +++++++++++++++++++++++++ bertos/cpu/cortex-m3/drv/flash_stm32.h | 50 +++++ bertos/cpu/cortex-m3/io/stm32_flash.h | 24 +++ bertos/cpu/cortex-m3/io/stm32_memmap.h | 62 +++++- bertos/drv/flash.h | 54 ++++- 7 files changed, 513 insertions(+), 13 deletions(-) create mode 100644 bertos/cfg/cfg_emb_flash.h create mode 100644 bertos/cpu/cortex-m3/drv/flash_stm32.c create mode 100644 bertos/cpu/cortex-m3/drv/flash_stm32.h diff --git a/bertos/cfg/cfg_emb_flash.h b/bertos/cfg/cfg_emb_flash.h new file mode 100644 index 00000000..48257ce8 --- /dev/null +++ b/bertos/cfg/cfg_emb_flash.h @@ -0,0 +1,58 @@ +/** + * \file + * + * + * \author Daniele Basile + * + * \brief Configuration file for embedded flash module. + */ + +#ifndef CFG_EMB_FLASH_H +#define CFG_EMB_FLASH_H + +/** + * Module logging level. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_level" + */ +#define CONFIG_FLASH_EMB_LOG_LEVEL LOG_LVL_INFO + +/** + * module logging format. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_format" + */ +#define CONFIG_FLASH_EMB_LOG_FORMAT LOG_FMT_TERSE + +#define CONFIG_FLASH_WR_TIMEOUT 100 + +#endif /* CFG_FLASH_AT91_H */ diff --git a/bertos/cpu/cortex-m3/drv/flash_cm3.h b/bertos/cpu/cortex-m3/drv/flash_cm3.h index bb7020b2..6b4bf11b 100644 --- a/bertos/cpu/cortex-m3/drv/flash_cm3.h +++ b/bertos/cpu/cortex-m3/drv/flash_cm3.h @@ -39,6 +39,8 @@ #if CPU_CM3_LM3S #include "flash_lm3s.h" +#elif CPU_CM3_STM32 + #include "flash_stm32.h" /*#elif Add other Cortex-M3 CPUs here */ #else #error Unknown CPU diff --git a/bertos/cpu/cortex-m3/drv/flash_stm32.c b/bertos/cpu/cortex-m3/drv/flash_stm32.c new file mode 100644 index 00000000..9d7e5974 --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/flash_stm32.c @@ -0,0 +1,276 @@ +/** + * \file + * + * + * \brief STM32F103xx internal flash memory driver. + * + * \author Daniele Basile + */ + +#include "flash_stm32.h" + +#include "cfg/cfg_emb_flash.h" + +// Define log settings for cfg/log.h +#define LOG_LEVEL CONFIG_FLASH_EMB_LOG_LEVEL +#define LOG_FORMAT CONFIG_FLASH_EMB_LOG_FORMAT +#include + +#include +#include + +#include +#include + +#include + +#include + +#define EMB_FLASH ((struct stm32_flash*)FLASH_R_BASE) + +#if CPU_CM3_STM32F103RB + #define EMB_FLASH_PAGE_SIZE 1024 +#else + #error Unknown CPU +#endif + + +struct FlashHardware +{ + uint8_t status; +}; + +INLINE bool flash_wait(struct KBlock *blk) +{ + Flash *fls = FLASH_CAST(blk); + ticks_t start = timer_clock(); + while (true) + { + if (!(EMB_FLASH->SR & FLASH_FLAG_BSY)) + break; + + if (EMB_FLASH->SR & FLASH_FLAG_PGERR) + { + fls->hw->status |= FLASH_NOT_ERASED; + LOG_ERR("flash not erased..\n"); + return false; + } + + if (EMB_FLASH->SR & FLASH_FLAG_WRPRTERR) + { + fls->hw->status |= FLASH_WR_PROTECT; + LOG_ERR("wr protect..\n"); + return false; + } + + if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT)) + { + fls->hw->status |= FLASH_WR_TIMEOUT; + LOG_ERR("Timeout..\n"); + return false; + } + + cpu_relax(); + } + + return true; +} + +static bool stm32_erasePage(struct KBlock *blk, uint32_t page_add) +{ + + EMB_FLASH->CR |= CR_PER_SET; + EMB_FLASH->AR = page_add; + EMB_FLASH->CR |= CR_STRT_SET; + + if (!flash_wait(blk)) + return false; + + EMB_FLASH->CR &= CR_PER_RESET; + + return true; +} + +static bool stm32_eraseAll(struct KBlock *blk) +{ + EMB_FLASH->CR |= CR_MER_SET; + EMB_FLASH->CR |= CR_STRT_SET; + + if (!flash_wait(blk)) + return false; + + EMB_FLASH->CR &= CR_MER_RESET; + + return true; +} + +static int stm32_flash_error(struct KBlock *blk) +{ + Flash *fls = FLASH_CAST(blk); + return fls->hw->status; +} + +static void stm32_flash_clearerror(struct KBlock *blk) +{ + Flash *fls = FLASH_CAST(blk); + fls->hw->status = 0; +} + +static size_t stm32_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size) +{ + memcpy(buf, (void *)(idx * blk->blk_size + offset), size); + + return size; +} + + +INLINE bool stm32_writeWord(struct KBlock *blk, uint32_t addr, uint16_t data) +{ + ASSERT(!(addr % 2)); + + EMB_FLASH->CR |= CR_PG_SET; + + *(reg16_t *)addr = data; + + if (!flash_wait(blk)) + return false; + + EMB_FLASH->CR &= CR_PG_RESET; + + return true; +} + +static size_t stm32_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size) +{ + if (!stm32_erasePage(blk, (idx * blk->blk_size))) + return 0; + + uint32_t addr = idx * blk->blk_size + offset; + const uint8_t *buf = (const uint8_t *)_buf; + size_t count = 0; + + if (addr % 2) + { + if (!stm32_writeWord(blk, addr - 1, (buf[0] << 8) | 0xFF)) + return count; + + buf++; + size--; + count++; + addr++; + } + + ASSERT(!(addr % 2)); + while (size) + { + uint16_t data; + size_t len; + if (size == 1) + { + data = 0xFF00 | *buf; + len = 1; + } + else + { + data = ((*buf + 1) << 8) | *buf; + len = 2; + } + + if (!stm32_writeWord(blk, addr, data)) + return count; + + buf += len; + size -= len; + count += len; + addr += len; + } + return count; +} + +static const KBlockVTable flash_stm32_buffered_vt = +{ + .readDirect = stm32_flash_readDirect, + .writeDirect = stm32_flash_writeDirect, + + .readBuf = kblock_swReadBuf, + .writeBuf = kblock_swWriteBuf, + .load = kblock_swLoad, + .store = kblock_swStore, + + .error = stm32_flash_error, + .clearerr = stm32_flash_clearerror, +}; + + + +static const KBlockVTable flash_stm32_unbuffered_vt = +{ + .readDirect = stm32_flash_readDirect, + .writeDirect = stm32_flash_writeDirect, + + .error = stm32_flash_error, + .clearerr = stm32_flash_clearerror, +}; + +static struct FlashHardware flash_stm32_hw; +static uint8_t flash_buf[EMB_FLASH_PAGE_SIZE]; + +static void common_init(Flash *fls) +{ + memset(fls, 0, sizeof(*fls)); + DB(fls->blk.priv.type = KBT_FLASH); + + EMB_FLASH->CR = 0; + + fls->hw = &flash_stm32_hw; + + fls->blk.blk_size = EMB_FLASH_PAGE_SIZE; + fls->blk.blk_cnt = (F_SIZE * 1024) / EMB_FLASH_PAGE_SIZE; + + /* Unlock flash memory for the FPEC Access */ + EMB_FLASH->KEYR = FLASH_KEY1; + EMB_FLASH->KEYR = FLASH_KEY2; +} + + +void flash_hw_init(Flash *fls) +{ + common_init(fls); + fls->blk.priv.vt = &flash_stm32_buffered_vt; + fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; + fls->blk.priv.buf = flash_buf; +} + +void flash_hw_initUnbuffered(Flash *fls) +{ + common_init(fls); + fls->blk.priv.vt = &flash_stm32_unbuffered_vt; +} diff --git a/bertos/cpu/cortex-m3/drv/flash_stm32.h b/bertos/cpu/cortex-m3/drv/flash_stm32.h new file mode 100644 index 00000000..5f475c94 --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/flash_stm32.h @@ -0,0 +1,50 @@ +/** + * \file + * + * + * \brief STM32F103xx internal flash memory driver. + * + * \author Daniele Basile + */ + +#ifndef FLASH_STM32_H +#define FLASH_STM32_H + + +/* Flash memory mapping */ +#define FLASH_MEM_SIZE 0x40000 //< 256KiB +#define FLASH_PAGE_SIZE_BYTES 0x400 //< 1KiB + + +#define FLASH_PAGE_SIZE FLASH_PAGE_SIZE_BYTES + + +#endif /* FLASH_STM32_H */ diff --git a/bertos/cpu/cortex-m3/io/stm32_flash.h b/bertos/cpu/cortex-m3/io/stm32_flash.h index 48896659..10c244af 100644 --- a/bertos/cpu/cortex-m3/io/stm32_flash.h +++ b/bertos/cpu/cortex-m3/io/stm32_flash.h @@ -36,8 +36,14 @@ #ifndef STM32_FLASH_H #define STM32_FLASH_H +#include + #include +/** Return the embedded flash size in kB */ +#define F_SIZE ((*(reg32_t *) 0x1FFFF7E0) & 0xFFFF) + + /* Flash Access Control Register bits */ #define ACR_LATENCY_MASK ((uint32_t)0x00000038) #define ACR_HLFCYA_MASK ((uint32_t)0xFFFFFFF7) @@ -149,4 +155,22 @@ #define FLASH_FLAG_WRPRTERR ((uint32_t)0x00000010) /* FLASH Write protected error flag */ #define FLASH_FLAG_OPTERR ((uint32_t)0x00000001) /* FLASH Option Byte error flag */ + + +/** + * Embbeded flash configuration registers structure + */ +struct stm32_flash +{ + reg32_t ACR; + reg32_t KEYR; + reg32_t OPTKEYR; + reg32_t SR; + reg32_t CR; + reg32_t AR; + reg32_t RESERVED; + reg32_t OBR; + reg32_t WRPR; +}; + #endif /* STM32_FLASH_H */ diff --git a/bertos/cpu/cortex-m3/io/stm32_memmap.h b/bertos/cpu/cortex-m3/io/stm32_memmap.h index a99577a1..b8317caf 100644 --- a/bertos/cpu/cortex-m3/io/stm32_memmap.h +++ b/bertos/cpu/cortex-m3/io/stm32_memmap.h @@ -57,17 +57,26 @@ #define TIM2_BASE (APB1PERIPH_BASE + 0x0000) #define TIM3_BASE (APB1PERIPH_BASE + 0x0400) #define TIM4_BASE (APB1PERIPH_BASE + 0x0800) +#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00) +#define TIM6_BASE (APB1PERIPH_BASE + 0x1000) +#define TIM7_BASE (APB1PERIPH_BASE + 0x1400) #define RTC_BASE (APB1PERIPH_BASE + 0x2800) #define WWDG_BASE (APB1PERIPH_BASE + 0x2C00) #define IWDG_BASE (APB1PERIPH_BASE + 0x3000) #define SPI2_BASE (APB1PERIPH_BASE + 0x3800) +#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00) #define USART2_BASE (APB1PERIPH_BASE + 0x4400) #define USART3_BASE (APB1PERIPH_BASE + 0x4800) +#define UART4_BASE (APB1PERIPH_BASE + 0x4C00) +#define UART5_BASE (APB1PERIPH_BASE + 0x5000) #define I2C1_BASE (APB1PERIPH_BASE + 0x5400) #define I2C2_BASE (APB1PERIPH_BASE + 0x5800) -#define CAN_BASE (APB1PERIPH_BASE + 0x6400) +#define CAN1_BASE (APB1PERIPH_BASE + 0x6400) +#define CAN2_BASE (APB1PERIPH_BASE + 0x6800) #define BKP_BASE (APB1PERIPH_BASE + 0x6C00) #define PWR_BASE (APB1PERIPH_BASE + 0x7000) +#define DAC_BASE (APB1PERIPH_BASE + 0x7400) +#define CEC_BASE (APB1PERIPH_BASE + 0x7800) #define AFIO_BASE (APB2PERIPH_BASE + 0x0000) #define EXTI_BASE (APB2PERIPH_BASE + 0x0400) @@ -76,21 +85,54 @@ #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) +#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) +#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) #define ADC1_BASE (APB2PERIPH_BASE + 0x2400) #define ADC2_BASE (APB2PERIPH_BASE + 0x2800) #define TIM1_BASE (APB2PERIPH_BASE + 0x2C00) #define SPI1_BASE (APB2PERIPH_BASE + 0x3000) +#define TIM8_BASE (APB2PERIPH_BASE + 0x3400) #define USART1_BASE (APB2PERIPH_BASE + 0x3800) +#define ADC3_BASE (APB2PERIPH_BASE + 0x3C00) +#define TIM15_BASE (APB2PERIPH_BASE + 0x4000) +#define TIM16_BASE (APB2PERIPH_BASE + 0x4400) +#define TIM17_BASE (APB2PERIPH_BASE + 0x4800) -#define DMA_BASE (AHBPERIPH_BASE + 0x0000) -#define DMA_CHANNEL1_BASE (AHBPERIPH_BASE + 0x0008) -#define DMA_CHANNEL2_BASE (AHBPERIPH_BASE + 0x001C) -#define DMA_CHANNEL3_BASE (AHBPERIPH_BASE + 0x0030) -#define DMA_CHANNEL4_BASE (AHBPERIPH_BASE + 0x0044) -#define DMA_CHANNEL5_BASE (AHBPERIPH_BASE + 0x0058) -#define DMA_CHANNEL6_BASE (AHBPERIPH_BASE + 0x006C) -#define DMA_CHANNEL7_BASE (AHBPERIPH_BASE + 0x0080) -#define RCC_BASE (AHBPERIPH_BASE + 0x1000) +#define SDIO_BASE (PERIPH_BASE + 0x18000) + + +#define DMA1_BASE (AHBPERIPH_BASE + 0X0000) +#define DMA1_CHANNEL1_BASE (AHBPERIPH_BASE + 0X0008) +#define DMA1_CHANNEL2_BASE (AHBPERIPH_BASE + 0X001C) +#define DMA1_CHANNEL3_BASE (AHBPERIPH_BASE + 0X0030) +#define DMA1_CHANNEL4_BASE (AHBPERIPH_BASE + 0X0044) +#define DMA1_CHANNEL5_BASE (AHBPERIPH_BASE + 0X0058) +#define DMA1_CHANNEL6_BASE (AHBPERIPH_BASE + 0X006C) +#define DMA1_CHANNEL7_BASE (AHBPERIPH_BASE + 0X0080) +#define DMA2_BASE (AHBPERIPH_BASE + 0X0400) +#define DMA2_CHANNEL1_BASE (AHBPERIPH_BASE + 0X0408) +#define DMA2_CHANNEL2_BASE (AHBPERIPH_BASE + 0X041C) +#define DMA2_CHANNEL3_BASE (AHBPERIPH_BASE + 0X0430) +#define DMA2_CHANNEL4_BASE (AHBPERIPH_BASE + 0X0444) +#define DMA2_CHANNEL5_BASE (AHBPERIPH_BASE + 0X0458) +#define RCC_BASE (AHBPERIPH_BASE + 0X1000) +#define CRC_BASE (AHBPERIPH_BASE + 0X3000) + +#define FLASH_R_BASE (AHBPERIPH_BASE + 0x2000) ///< Flash registers base address + +#define ETH_BASE (AHBPERIPH_BASE + 0x8000) +#define ETH_MAC_BASE (ETH_BASE) +#define ETH_MMC_BASE (ETH_BASE + 0x0100) +#define ETH_PTP_BASE (ETH_BASE + 0x0700) +#define ETH_DMA_BASE (ETH_BASE + 0x1000) + +#define FSMC_BANK1_R_BASE (FSMC_R_BASE + 0x0000) ///< FSMC Bank1 registers base address +#define FSMC_BANK1E_R_BASE (FSMC_R_BASE + 0x0104) ///< FSMC Bank1E registers base address +#define FSMC_BANK2_R_BASE (FSMC_R_BASE + 0x0060) ///< FSMC Bank2 registers base address +#define FSMC_BANK3_R_BASE (FSMC_R_BASE + 0x0080) ///< FSMC Bank3 registers base address +#define FSMC_BANK4_R_BASE (FSMC_R_BASE + 0x00A0) ///< FSMC Bank4 registers base address + +#define DBGMCU_BASE ((uint32_t)0xE0042000) ///< Debug MCU registers base address /* System Control Space memory map */ #define SCS_BASE (0xE000E000) diff --git a/bertos/drv/flash.h b/bertos/drv/flash.h index eda1e985..50962742 100644 --- a/bertos/drv/flash.h +++ b/bertos/drv/flash.h @@ -43,14 +43,61 @@ #define DRV_FLASH_H #include -#include +#include -#include CPU_HEADER(flash) +/* + * Embedded flash error flags + */ +#define FLASH_WR_OK 0 ///< Write ok. +#define FLASH_NOT_ERASED BV(1) ///< Flash memory was not erased before to write it. +#define FLASH_WR_PROTECT BV(2) ///< Write not allowed the flash memory was protected. +#define FLASH_WR_TIMEOUT BV(3) ///< + +struct FlashHardware; + +/** + * EmbFlash KFile context structure. + */ +typedef struct Flash +{ + KBlock blk; + struct FlashHardware *hw; +} Flash; /** -* EmbFlash KFile context structure. + * ID for FLASH + */ +#define KBT_FLASH MAKE_ID('F', 'L', 'A', 'S') + +/** +* Convert + ASSERT from generic KFile to Flash. */ +INLINE Flash *FLASH_CAST(KBlock *fls) +{ + ASSERT(fls->priv.type == KBT_FLASH); + return (Flash *)fls; +} + +void flash_hw_init(Flash *fls); +void flash_hw_initUnbuffered(Flash *fls); + +#include CPU_HEADER(flash) + +INLINE void flash_init(Flash *fls) +{ + flash_hw_init(fls); +} + +INLINE void flash_initUnbuffered(Flash *fls) +{ + flash_hw_initUnbuffered(fls); +} + +#if 0 +/** + * EmbFlash KFile context structure. + */ typedef struct Flash { /** @@ -103,6 +150,7 @@ INLINE void flash_init(Flash *fd) MOD_INIT(flash); } +#endif #endif /* DRV_FLASH_H */ -- 2.25.1