From adf4a56dc7329b8add0891e0ff11fca3f5add6f6 Mon Sep 17 00:00:00 2001 From: arighi Date: Tue, 27 Apr 2010 09:17:10 +0000 Subject: [PATCH] lm3s1968: internal flash memory driver. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3525 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/cortex-m3/drv/flash_lm3s.c | 267 ++++++++++++++++++++++++++ bertos/cpu/cortex-m3/drv/flash_lm3s.h | 91 +++++++++ 2 files changed, 358 insertions(+) create mode 100644 bertos/cpu/cortex-m3/drv/flash_lm3s.c create mode 100644 bertos/cpu/cortex-m3/drv/flash_lm3s.h diff --git a/bertos/cpu/cortex-m3/drv/flash_lm3s.c b/bertos/cpu/cortex-m3/drv/flash_lm3s.c new file mode 100644 index 00000000..33bdd348 --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/flash_lm3s.c @@ -0,0 +1,267 @@ +/** + * \file + * + * + * \brief LM3S1968 internal flash memory driver. + * + * \author Andrea Righi + */ + +#include +#include +#include +#include /* cpu_relax() */ +#include /* memcpy() */ +#include "cfg/log.h" +#include "flash_lm3s.h" + +static int flash_lm3s_erase_page(volatile uint32_t *addr) +{ + FLASH_FCMISC_R = FLASH_FCMISC_AMISC; + + FLASH_FMA_R = (uint32_t)addr; + FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; + + while (FLASH_FMC_R & FLASH_FMC_ERASE) + cpu_relax(); + if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS) + return -1; + return 0; +} + +static int flash_lm3s_write_word(volatile uint32_t *addr, uint32_t data) +{ + FLASH_FCMISC_R = FLASH_FCMISC_AMISC; + + FLASH_FMA_R = (uint32_t)addr; + FLASH_FMD_R = data; + FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; + + while (FLASH_FMC_R & FLASH_FMC_WRITE) + cpu_relax(); + if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS) + return -1; + return 0; +} + +static void _flash_lm3s_flush(FlashLM3S *fd) +{ + unsigned int i; + + if (!fd->page_dirty) + return; + LOG_INFO("Erase page %p\n", fd->curr_page); + flash_lm3s_erase_page(fd->curr_page); + LOG_INFO("Flush page %p\n", fd->curr_page); + for (i = 0; i < FLASH_PAGE_SIZE_BYTES / sizeof(uint32_t); i++) + flash_lm3s_write_word(&fd->curr_page[i], fd->page_buf[i]); + fd->page_dirty = false; +} + +static void flash_lm3s_load_page(FlashLM3S *fd, uint32_t *page) +{ + ASSERT(!((size_t)page % FLASH_PAGE_SIZE_BYTES)); + + if (page == fd->curr_page) + return; + + /* Flush old page */ + _flash_lm3s_flush(fd); + + /* Load a new page */ + memcpy(fd->page_buf, FLASH_BASE + (uint8_t *)page, FLASH_PAGE_SIZE_BYTES); + fd->curr_page = page; + LOG_INFO("Loaded page %p\n", fd->curr_page); +} + +/** + * Write program memory. + * Write \a size bytes from buffer \a _buf to file \a fd + * \note Write operations are not buffered. + */ +static size_t flash_lm3s_write(struct KFile *_fd, const void *_buf, size_t size) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + const uint8_t *buf =(const uint8_t *)_buf; + size_t total_write = 0; + size_t len; + + size = MIN((kfile_off_t)size, + (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE))); + + LOG_INFO("Writing at pos[%lx]\n", fd->fd.seek_pos); + while (size) + { + uint32_t *page = (uint32_t *)(fd->fd.seek_pos & + ~(FLASH_PAGE_SIZE_BYTES - 1)); + size_t offset = fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES; + + flash_lm3s_load_page(fd, page); + + len = MIN(size, FLASH_PAGE_SIZE_BYTES - offset); + + memcpy((uint8_t *)fd->page_buf + offset, buf, len); + fd->page_dirty = true; + + buf += len; + fd->fd.seek_pos += len; + size -= len; + total_write += len; + } + LOG_INFO("written %u bytes\n", total_write); + return total_write; +} + +/** + * Close file \a fd + */ +static int flash_lm3s_close(struct KFile *_fd) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + _flash_lm3s_flush(fd); + LOG_INFO("Flash file closed\n"); + return 0; +} + +/** + * Open flash file \a fd + */ +static void flash_lm3s_open(struct FlashLM3S *fd) +{ + fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE; + fd->fd.seek_pos = FLASH_BASE; + /* + * Set an invalid page to force the load of the next actually used page + * in cache. + */ + fd->curr_page = (uint32_t *)FLASH_BASE + FLASH_MEM_SIZE; + + fd->page_dirty = false; + LOG_INFO("Flash file opened\n"); +} + +/** + * Move \a fd file seek position of \a offset bytes from \a whence. + */ +static kfile_off_t flash_lm3s_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + kfile_off_t seek_pos; + + switch (whence) + { + case KSM_SEEK_SET: + seek_pos = FLASH_BASE; + break; + case KSM_SEEK_END: + seek_pos = fd->fd.size; + break; + case KSM_SEEK_CUR: + seek_pos = fd->fd.seek_pos; + break; + default: + ASSERT(0); + return EOF; + break; + } + if (seek_pos + offset > fd->fd.size) + LOG_ERR("seek outside EOF\n"); + fd->fd.seek_pos = seek_pos + offset; + + return fd->fd.seek_pos - FLASH_BASE; +} + +/** + * Reopen file \a fd + */ +static struct KFile *flash_lm3s_reopen(struct KFile *_fd) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + flash_lm3s_close(_fd); + flash_lm3s_open(fd); + + return _fd; +} + +/** + * Read from file \a fd \a size bytes and put it in buffer \a buf + * \return the number of bytes read. + */ +static size_t flash_lm3s_read(struct KFile *_fd, void *_buf, size_t size) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + uint8_t *buf =(uint8_t *)_buf, *addr; + + size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); + + LOG_INFO("Reading at pos[%lx]\n", fd->fd.seek_pos); + /* Check if we can get current cached page */ + if ((size_t)fd->fd.seek_pos / FLASH_PAGE_SIZE_BYTES == + (size_t)fd->curr_page) + addr = (uint8_t *)fd->curr_page + + fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES; + else + addr = (uint8_t *)fd->fd.seek_pos; + memcpy(buf, (uint8_t *)addr, size); + fd->fd.seek_pos += size; + + LOG_INFO("Read %u bytes\n", size); + return size; +} + +static int flash_lm3s_flush(struct KFile *_fd) +{ + FlashLM3S *fd = FLASHLM3S_CAST(_fd); + + _flash_lm3s_flush(fd); + return 0; +} + +/** + * Init module to perform write and read operation on internal + * flash memory. + */ +void flash_lm3sInit(FlashLM3S *fd) +{ + memset(fd, 0, sizeof(*fd)); + DB(fd->fd._type = KFT_FLASHLM3S); + + fd->fd.reopen = flash_lm3s_reopen; + fd->fd.close = flash_lm3s_close; + fd->fd.write = flash_lm3s_write; + fd->fd.read = flash_lm3s_read; + fd->fd.seek = flash_lm3s_seek; + fd->fd.flush = flash_lm3s_flush; + + FLASH_USECRL_R = CPU_FREQ / 1000000 - 1; + + flash_lm3s_open(fd); +} diff --git a/bertos/cpu/cortex-m3/drv/flash_lm3s.h b/bertos/cpu/cortex-m3/drv/flash_lm3s.h new file mode 100644 index 00000000..1830b996 --- /dev/null +++ b/bertos/cpu/cortex-m3/drv/flash_lm3s.h @@ -0,0 +1,91 @@ +/** + * \file + * + * + * \brief LM3S1968 internal flash memory driver. + * + * \author Andrea Righi + */ + +#ifndef FLASH_LM3S_H +#define FLASH_LM3S_H + +#include +#include + +/* Flash memory mapping */ +#define FLASH_MEM_SIZE 0x40000 //< 256KiB +#define FLASH_PAGE_SIZE_BYTES 0x400 //< 1KiB + +/** + * FlashLM3S KFile context structure. + */ +typedef struct FlashLM3S +{ + /** + * File descriptor. + */ + KFile fd; + + /** + * Flag for checking if current page is modified. + */ + bool page_dirty; + + /** + * Current buffered page. + */ + uint32_t *curr_page; + + /** + * Temporary buffer cointaing data block to + * write on flash. + */ + uint32_t page_buf[FLASH_PAGE_SIZE_BYTES / sizeof(uint32_t)]; +} FlashLM3S; + +/** + * ID for FlashLM3S + */ +#define KFT_FLASHLM3S MAKE_ID('F', 'L', '3', 'S') + +/** + * Convert + ASSERT from generic KFile to FlashLM3S structure. + */ +INLINE FlashLM3S * FLASHLM3S_CAST(KFile *fd) +{ + ASSERT(fd->_type == KFT_FLASHLM3S); + return (FlashLM3S *)fd; +} + +void flash_lm3sInit(FlashLM3S *fd); + +#endif /* FLASH_LM3S_H */ -- 2.25.1