From: batt Date: Tue, 19 Feb 2008 14:51:02 +0000 (+0000) Subject: Merge from kseries. X-Git-Tag: 1.0.0~111 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=a9d3f75c43f780fb980fee20530d7d60a728c4d4;p=bertos.git Merge from kseries. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1141 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/drv/dataflash.c b/drv/dataflash.c index 2f4f897e..d9392f9a 100644 --- a/drv/dataflash.c +++ b/drv/dataflash.c @@ -33,47 +33,83 @@ * \brief Function library for AT45DBXX Data Flash memory. * * - * \version $Id: dataflash.c 15379 2007-03-28 15:46:09Z asterix $ + * \version $Id: dataflash.c 20677 2008-02-19 14:29:52Z batt $ * \author Daniele Basile + * \author Francesco Sacchi */ - +#include "dataflash.h" #include -#include #include #include #include #include -#include -#include +#include + +#if CONFIG_KERNEL +#include +#endif -#include "hw_spi.h" +#include -#warning This driver must be test before use! /** - * Global variable for store current and previous data - * flash memory page address during operation of writing. + * Array used to describe dataflash memory devices currently supported. */ -static dataflash_t previous_page = 0; -static bool page_modified = false; +static const DataflashInfo mem_info[] = +{ + { + /* AT45DB041B */ + .density_id = 0x07, + .page_size = 264, + .page_bits = 9, + .page_cnt = 2048, + .read_cmd = DFO_READ_FLASH_MEM_BYTE_B, + }, + { + /* AT45DB081D */ + .density_id = 0x09, + .page_size = 264, + .page_bits = 9, + .page_cnt = 4096, + .read_cmd = DFO_READ_FLASH_MEM_BYTE_D, + }, + { + /* AT45DB161D */ + .density_id = 0x0B, + .page_size = 528, + .page_bits = 10, + .page_cnt = 4096, + .read_cmd = DFO_READ_FLASH_MEM_BYTE_D, + }, + /* Add other memories here */ +}; + +STATIC_ASSERT(countof(mem_info) == DFT_CNT); +/** + * Macro that toggle CS of dataflash. + * \note This is equivalent to fd->setCS(false) immediately followed by fd->setCS(true). + */ +INLINE void CS_TOGGLE(KFileDataflash *fd) +{ + fd->setCS(false); + fd->setCS(true); +} /** - * Send a generic command to data flash memory. - * This function send only 4 byte, for opcode, page address and + * Send a generic command to dataflash memory. + * This function send only 4 byte: opcode, page address and * byte address. */ -static void send_cmd(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode) +static void send_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode) { /* * Make sure to toggle CS signal in order, * and reset dataflash command decoder. - * - * \note This is equivalent to CS_DISABLE() immediately followed by CS_ENABLE() */ - CS_TOGGLE(); + CS_TOGGLE(fd); /* @@ -93,103 +129,56 @@ static void send_cmd(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFla /* * Send opcode. */ - spi_sendRecv(opcode); + kfile_putc(opcode, fd->channel); /* * Send page address. */ - spi_sendRecv((uint8_t)(page_addr >> (16 - DATAFLASH_PAGE_ADDRESS_BIT))); - spi_sendRecv((uint8_t)((page_addr << (DATAFLASH_PAGE_ADDRESS_BIT - 8)) + (byte_addr >> 8))); + kfile_putc((uint8_t)(page_addr >> (16 - mem_info[fd->dev].page_bits)), fd->channel); + kfile_putc((uint8_t)((page_addr << (mem_info[fd->dev].page_bits - 8)) + (byte_addr >> 8)), fd->channel); /* * Send byte page address. */ - spi_sendRecv((uint8_t)byte_addr); - - + kfile_putc((uint8_t)byte_addr, fd->channel); } /** * Reset dataflash memory function. * - * This function reset data flash memory + * If \a fd->setReset function is not NULL, + * this function resets data flash memory * with one pulse reset long about 10usec. * */ -static void dataflash_reset(void) -{ - CS_ENABLE(); - RESET_ENABLE(); - timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); - CS_DISABLE(); - RESET_DISABLE(); - timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); -} - -/** - * dataflash init function. - * This function initialize a micro pin and - * SPI driver, and test if data flash memory - * density is the same wich define in dataflash.h. - */ -MOD_DEFINE(dataflash); -static bool dataflash_pin_init(void) +static void dataflash_reset(KFileDataflash *fd) { - uint8_t stat; - - MOD_CHECK(spi); - - RESET_DISABLE(); - WRITE_ENABLE(); //pilot wp pin. - - RESET_OUT(); - WP_OUT(); - - dataflash_reset(); - - stat = dataflash_stat(); - - MOD_INIT(dataflash); - - /* - * 2,3,4,5 bits of 1 byte status register - * indicate a device density of dataflash memory - * (see datasheet for more detail.) - */ - GET_ID_DESITY_DEVICE(stat); - - if(stat == DATAFLASH_ID_DEVICE_DENSITY) - return true; - else - return false; + fd->setCS(false); + if (fd->setReset) + { + fd->setReset(true); + timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); + fd->setReset(false); + timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); + } } /** * Read status register of dataflah memory. - * */ -static uint8_t dataflash_stat(void) +static uint8_t dataflash_stat(KFileDataflash *fd) { - uint8_t stat; - /* - * Make sure to toggle CS signal in order, + * Make sure to toggle CS signal * and reset dataflash command decoder. */ - CS_TOGGLE(); + CS_TOGGLE(fd); - stat = spi_sendRecv(DFO_READ_STATUS); - stat = spi_sendRecv(0x00); + kfile_putc(DFO_READ_STATUS, fd->channel); - /* - * Note: this function could be call one more time - * to check register status (es. check if memory has been - * teminate one operation), and so we don't disable CS to - * allow fast reading of register status. - */ - return stat; + return kfile_getc(fd->channel); } @@ -198,473 +187,308 @@ static uint8_t dataflash_stat(void) * return status register value. * */ -static uint8_t dataflash_cmd(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode) +static uint8_t dataflash_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode) { - uint8_t stat; - send_cmd(page_addr, byte_addr, opcode); + send_cmd(fd, page_addr, byte_addr, opcode); - CS_TOGGLE(); + CS_TOGGLE(fd); /* * We chech data flash memory state, and wait until busy-flag - * is hight. + * is high. */ - while(!(dataflash_stat() & BUSY_BIT)); + while (!(dataflash_stat(fd) & BUSY_BIT)) + { + #if CONFIG_KERNEL + proc_switch(); + #endif + } - stat = dataflash_stat(); + stat = dataflash_stat(fd); + kfile_flush(fd->channel); // Flush channel /* * Data flash has completed a bus cycle, so disable CS. */ - CS_DISABLE(); - - return (stat); - -} - -/** - * Read one byte from main data flash memory or buffer data - * flash memory. - */ -static uint8_t dataflash_read_byte(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode) -{ - uint8_t data; - - send_cmd(page_addr, byte_addr, opcode); - -#if CONFIG_DATA_FLASH == DATAFLASH_AT45DB041B - if(opcode == DFO_READ_FLASH_MEM_BYTE) - { - /* - * Send 24 don't care bit. - */ - spi_sendRecv(0x00); - spi_sendRecv(0x00); - spi_sendRecv(0x00); - - } -#endif + fd->setCS(false); - spi_sendRecv(0x00); //Send 8 don't care bit. - data = spi_sendRecv(0x00); //Read byte. - - CS_DISABLE(); - - return data; + return stat; } /** * Read \a len bytes from main data flash memory or buffer data * flash memory, and put it in \a *block. */ -static void dataflash_read_block(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len) +static void dataflash_readBlock(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflash_size_t len) { + send_cmd(fd, page_addr, byte_addr, opcode); - send_cmd(page_addr, byte_addr, opcode); - - if(opcode == DFO_READ_FLASH_MEM_BYTE) + if (opcode == DFO_READ_FLASH_MEM_BYTE_B) { /* - * Send 24 don't care bit. + * Send 24 don't care bits. */ - spi_sendRecv(0x00); - spi_sendRecv(0x00); - spi_sendRecv(0x00); - + uint8_t dummy[] = { 0, 0, 0 }; + kfile_write(fd->channel, dummy, sizeof(dummy)); } - spi_sendRecv(0x00); //Send 8 don't care bit. - spi_read(block, len); //Read len bytes ad put in block buffer. - - - CS_DISABLE(); - + kfile_putc(0, fd->channel); //Send 8 don't care bit. + kfile_read(fd->channel, block, len); //Read len bytes ad put in block buffer. + kfile_flush(fd->channel); // Flush channel + fd->setCS(false); } /** - * Write \a len bytes in buffer buffer data flash memory. + * Write \a len bytes in dataflash memory buffer. * - * \note Isn't possible to write bytes directly in main memory data - * flash. To perform write in main memory you must before write in buffer - * data flash memory, an then send command to write page in main memory. + * \note Is not possible to write directly in dataflash main memory. + * To perform a write in main memory you must first write in dataflash buffer + * memory and then send a command to write the page in main memory. */ -static void dataflash_write_block(dataflashOffset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len) +static void dataflash_writeBlock(KFileDataflash *fd, dataflash_offset_t offset, DataFlashOpcode opcode, const uint8_t *block, dataflash_size_t len) { + ASSERT(offset + len <= mem_info[fd->dev].page_size); - send_cmd(0x00, byte_addr, opcode); - - spi_write(block, len); //Write len bytes. + send_cmd(fd, 0x00, offset, opcode); - CS_DISABLE(); + kfile_write(fd->channel, block, len); //Write len bytes. + kfile_flush(fd->channel); // Flush channel + fd->setCS(false); } /** * Load selct page from dataflash memory to buffer. */ -static void dataflash_loadPage(dataflash_t page_addr) +static void dataflash_loadPage(KFileDataflash *fd, dataflash_page_t page_addr) { - dataflash_cmd(page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1); + dataflash_cmd(fd, page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1); } /** * Flush select page (stored in buffer) in data flash main memory page. */ -void dataflash_flush(void) +static int dataflash_flush(KFile *_fd) { - if (page_modified) + KFileDataflash *fd = KFILEDATAFLASH(_fd); + if (fd->page_dirty) { - dataflash_cmd(previous_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E); + dataflash_cmd(fd, fd->current_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E); - page_modified = false; + fd->page_dirty = false; - kprintf("\n::=> Flush page:... <%ld>\n", previous_page); + kprintf("Flushing page <%ld>\n", fd->current_page); } + return 0; } /* Kfile interface section */ /** - * Open data flash file \a fd - * \a name and \a mode are unused, cause flash memory is - * threated like one file. + * Close file \a fd. */ -static bool dataflash_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode)) +static int dataflash_close(struct KFile *_fd) { - MOD_CHECK(dataflash); - - previous_page = 0; - fd->seek_pos = 0; - fd->size = (dataflashAddr_t)DATAFLASH_PAGE_SIZE * (dataflashAddr_t)DATAFLASH_NUM_PAGE; - - /* Load select page memory from data flash memory*/ - dataflash_loadPage(previous_page); - - kprintf("dataflash file opened\n"); - return true; -} - -/** - * Close file \a fd - */ -static bool dataflash_close(UNUSED_ARG(struct _KFile *,fd)) -{ - dataflash_flush(); - kprintf("dataflash file closed\n"); - return true; + dataflash_flush(_fd); + TRACE; + return 0; } /** - * Move \a fd file seek position of \a offset bytes - * from current position. + * Reopen dataflash file \a fd. */ -static int32_t dataflash_seek(struct _KFile *fd, kfile_off_t offset, KSeekMode whence) +static KFile *dataflash_reopen(KFile *_fd) { - uint32_t seek_pos; + KFileDataflash *fd = KFILEDATAFLASH(_fd); + dataflash_close(_fd); - switch(whence) - { + fd->current_page = 0; + fd->fd.seek_pos = 0; - case KSM_SEEK_SET: - seek_pos = 0; - break; - case KSM_SEEK_END: - seek_pos = fd->size - 1; - break; - case KSM_SEEK_CUR: - seek_pos = fd->seek_pos; - break; - default: - ASSERT(0); - return -1; - break; + /* Load selected page from dataflash memory */ + dataflash_loadPage(fd, fd->current_page); - } - - /* Bound check */ - if (seek_pos + offset > fd->size) - { - ASSERT(0); - return -1; - } - - fd->seek_pos = seek_pos + offset; - kprintf("Flash seek to [%u]\n", fd->seek_pos); - - return fd->seek_pos; + TRACE; + return &fd->fd; } + /** - * Read \a _buf lenght \a size byte from data flash memmory. + * Read in \a buf \a size bytes from dataflash memmory. * - * \note For read in data flash memory, we - * check flag page_modified, if is true (that mean - * we had been written a byte in buffer memory) we - * flush current page in data flash main memory, and - * then read byte from memory, else we read byte + * \note For reading data flash memory, we + * check flag page_dirty, if is true (that mean + * we have written a byte in buffer memory) we + * flush current page in main memory and + * then read from memory, else we read byte * directly from data flash main memory. * * \return the number of bytes read. */ -static size_t dataflash_read(struct _KFile *fd, void *buf, size_t size) +static size_t dataflash_read(struct KFile *_fd, void *buf, size_t size) { - dataflashOffset_t byte_addr; - dataflashAddr_t page_addr; - uin8_t *data = (uint8_t *)buf; + KFileDataflash *fd = KFILEDATAFLASH(_fd); + dataflash_offset_t byte_addr; + dataflash_page_t page_addr; + uint8_t *data = (uint8_t *)buf; - ASSERT(fd->seek_pos + size <= fd->size); - size = MIN((uint32_t)size, fd->size - fd->seek_pos); - kprintf("Reading at pos[%u]\n", fd->seek_pos); + ASSERT(fd->fd.seek_pos + size <= fd->fd.size); + size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos); + + kprintf("Reading at pos[%lu]\n", fd->fd.seek_pos); /* * We select page and offest from absolute address. */ - page_addr = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE; - byte_addr = fd->seek_pos % (dataflashOffset_t)DATAFLASH_PAGE_SIZE; - + page_addr = fd->fd.seek_pos / mem_info[fd->dev].page_size; + byte_addr = fd->fd.seek_pos % mem_info[fd->dev].page_size; - kprintf(" [page-<%ld>, byte-<%ld>]", page_addr, byte_addr); + kprintf("[page-<%ld>, byte-<%ld>]", page_addr, byte_addr); /* * Flush current page in main memory if * we had been written a byte in memory */ - dataflash_flush(); + dataflash_flush(&fd->fd); /* * Read byte in main page data flash memory. */ - dataflash_read_block(page_addr, byte_addr, DFO_READ_FLASH_MEM_BYTE, data, size); + dataflash_readBlock(fd, page_addr, byte_addr, mem_info[fd->dev].read_cmd, data, size); - fd->seek_pos += size; - kprintf(" ::=> Read data: %02x\n",data); + fd->fd.seek_pos += size; + kprintf("Read %ld bytes\n", size); return size; } /** - * Write \a _buf in data flash memory + * Write \a _buf in dataflash memory * - * \note For write \a _buf in data flash memory, we must - * before write in buffer data flash memory, and at end of write, - * we put page in data flash main memory. If we write in two - * different page, we put in main memory current page and reload - * page witch we want write. + * \note For writing \a _buf in dataflash memory, we must + * first write in buffer data flash memory. At the end of write, + * we can put page in dataflash main memory. + * If we write in two contiguous pages, we put in main memory current + * page and then reload the page which we want to write. * * \return the number of bytes write. */ -static size_t dataflash_write(struct _KFile *fd, const void *_buf, size_t size) +static size_t dataflash_write(struct KFile *_fd, const void *_buf, size_t size) { + KFileDataflash *fd = KFILEDATAFLASH(_fd); - dataflashOffset_t byte_addr; - dataflashAddr_t current_page; + dataflash_offset_t offset; + dataflash_page_t new_page; + size_t total_write = 0; - uint8_t *data = (uint8_t *) _buf; + const uint8_t *data = (const uint8_t *) _buf; - ASSERT(fd->seek_pos + size <= fd->size); - size = MIN((uint32_t)size, fd->size - fd->seek_pos); + ASSERT(fd->fd.seek_pos + size <= fd->fd.size); + size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos); - kprintf("Writing at pos[%u]\n", fd->seek_pos); + kprintf("Writing at pos[%lu]\n", fd->fd.seek_pos); while (size) { /* * We select page and offest from absolute address. */ - current_page = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE; - byte_addr = fd->seek_pos % (dataflashOffset_t)DATAFLASH_PAGE_SIZE; + new_page = fd->fd.seek_pos / mem_info[fd->dev].page_size; + offset = fd->fd.seek_pos % mem_info[fd->dev].page_size; - size_t wr_len = MIN(size, DATAFLASH_PAGE_SIZE - byte_addr); + size_t wr_len = MIN(size, mem_info[fd->dev].page_size - offset); - kprintf(" [page-<%ld>, byte-<%ld>]",current_page, byte_addr); + kprintf(" [page-<%ld>, byte-<%ld>]",new_page, offset); - if (current_page != previous_page) + if (new_page != fd->current_page) { /* Flush current page in main memory*/ - dataflash_flush(); + dataflash_flush(&fd->fd); /* Load select page memory from data flash memory*/ - dataflash_loadPage(current_page); + dataflash_loadPage(fd, new_page); - previous_page = current_page; - kprintf(" >> Load page: <%ld> ",current_page); + fd->current_page = new_page; + kprintf(" >> Load page: <%ld> ", new_page); } /* * Write byte in current page, and set true - * page_modified flag. + * page_dirty flag. */ - dataflash_write_byte(byte_addr, DFO_WRITE_BUFF1, data); - page_modified = true; - + dataflash_writeBlock(fd, offset, DFO_WRITE_BUFF1, data, wr_len); + fd->page_dirty = true; data += wr_len; - fd->seek_pos += wr_len; + fd->fd.seek_pos += wr_len; size -= wr_len; total_write += wr_len; } - kprintf("written %u bytes\n", total_write); + kprintf("written %lu bytes\n", total_write); return total_write; } -/** - * Init data flash memory interface. - */ -void dataflash_init(struct _KFile *fd) -{ - // Set up data flash programming functions. - fd->open = dataflash_open; - fd->close = dataflash_close; - fd->read = dataflash_read; - fd->write = dataflash_write; - fd->seek = dataflash_seek; - - // Init data flash memory and micro pin. - ASSERT(dataflash_pin_init()); -} +MOD_DEFINE(dataflash); /** - * Test function for dataflash. - * - * This function test check low level driver for - * AT45xx (see dataflash.h for more info) data flash memory. - * We write a string in memory in some page ad read it. + * Dataflash init function. + * This function initialize \a fd with SPI channel \a ch and test if data flash memory + * density is the same specified by device \a dev. + * \a setCS is a callback used to set/reset CS line. + * \a setReset is a callback used to set/reset the dataflash (can be NULL if reset is unconnected) + * \return true if ok, false if memory density read from dataflash is not compliant with the + * configured one. */ -void dataflash_test(void) +bool dataflash_init(KFileDataflash *fd, KFile *ch, DataflashType dev, dataflash_setCS_t *setCS, dataflash_setReset_t *setReset) { - KFile fd; - - dataflash_init(&fd); - - uint8_t test_buf[] = "0123456789 Develer s.r.l."; - uint8_t cmp_buf[sizeof(test_buf)]; - - int tb_len = sizeof(test_buf); - int tmp_len = 0; - - kprintf("\n======= Data Flash test function =========================================\n"); - kprintf("\nThe string test is: %s\n\n", test_buf); - - fd.open(&fd, NULL, 0); - - /* TEST 1 */ - - // Seek to addr 0 - if (!fd.seek(&fd, 0, KSM_SEEK_SET)) - goto dataflash_test_end; - - // Test flash write to address 0 (page 0) - tmp_len = fd.write(&fd, test_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 1: Wrong numer write bytes! expecteded [%d], write [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } - - // Seek to addr 0 - if (fd.seek(&fd, 0, KSM_SEEK_SET) != 0) - goto dataflash_test_end; - tmp_len = 0; - - // Test flash read to address 0 (page 0) - tmp_len = fd.read(&fd, cmp_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 1: Wrong numer read bytes! expecteded [%d], read [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } - - // Compare if they are equal - if ((memcmp(cmp_buf,test_buf, tb_len) == 0)) - { - kprintf("Test 1: Readed test buf don't much!\n"); - goto dataflash_test_end; - } - - /* TEST 2 */ + uint8_t stat; - // Go to middle address memory. - if (!fd.seek(&fd, (((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) / 2), SEEK_CUR)) - goto dataflash_test_end; - tmp_len = 0; + MOD_CHECK(dataflash_hw); - // Test flash write at the middle of memory - tmp_len = fd.write(&fd, test_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 2: Wrong numer write bytes! expecteded [%d], write [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } + ASSERT(fd); + ASSERT(ch); + ASSERT(setCS); + ASSERT(dev < DFT_CNT); - // Go to middle address memory. - if (!fd.seek(&fd, (((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) / 2), SEEK_CUR)) - goto dataflash_test_end; - tmp_len = 0; + memset(fd, 0, sizeof(*fd)); + DB(fd->fd._type = KFT_DATAFLASH); + fd->dev = dev; + fd->channel = ch; + fd->setReset = setReset; + fd->setCS = setCS; - // Test flash read at the middle of memory - tmp_len = fd.read(&fd, cmp_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 2: Wrong numer read bytes! expecteded [%d], read [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } + // Setup data flash programming functions. + fd->fd.reopen = dataflash_reopen; + fd->fd.close = dataflash_close; + fd->fd.read = dataflash_read; + fd->fd.write = dataflash_write; + fd->fd.seek = kfile_genericSeek; + fd->fd.flush = dataflash_flush; - // Compare if they are equal - if ((memcmp(cmp_buf,test_buf, tb_len) == 0)) - { - kprintf("Test 2: Readed test buf don't much!\n"); - goto dataflash_test_end; - } - /* TEST 3 */ + dataflash_reset(fd); - // Go to end of data flash. - if(!fd.seek(&fd, ((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) - len_tb, SEEK_END)) - goto dataflash_test_end; - tmp_len = 0; + stat = dataflash_stat(fd); - // Test flash write at the end of memory - tmp_len = fd.write(&fd, test_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 3: Wrong numer write bytes! expecteded [%d], write [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } - - // Go to end of data flash. - if(!fd.seek(&fd, ((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) - len_tb, SEEK_END)) - goto dataflash_test_end; - tmp_len = 0 - - // Test flash read at the end of memory - tmp_len = fd.read(&fd, cmp_buf, tb_len); - if (tb_len != tmp_len) - { - kprintf("Test 3: Wrong numer read bytes! expecteded [%d], read [%d]\n", tb_len, tmp_len); - goto dataflash_test_end; - } - - // Compare if they are equal - if ((memcmp(cmp_buf,test_buf, tb_len) == 0)) - { - kprintf("Test 3: Readed test buf don't much!\n"); - goto dataflash_test_end; - } + /* + * 2,3,4,5 bits of 1 byte status register + * indicate a device density of dataflash memory + * (see datasheet for more detail.) + */ + if (GET_ID_DESITY_DEVICE(stat) != mem_info[fd->dev].density_id) + return false; - kprintf("\n"); + fd->current_page = 0; + fd->fd.seek_pos = 0; + fd->fd.size = mem_info[fd->dev].page_size * mem_info[fd->dev].page_cnt; - kprintf("\n====== Test end ===========================================================\n"); - fd.close(&fd); + /* Load selected page from dataflash memory */ + dataflash_loadPage(fd, fd->current_page); + MOD_INIT(dataflash); return true; - -dataflash_test_end: - fd.close(&fd); - return false; - } - diff --git a/drv/dataflash.h b/drv/dataflash.h index c49b9acd..c77cf496 100644 --- a/drv/dataflash.h +++ b/drv/dataflash.h @@ -33,7 +33,7 @@ * \brief Function library for AT45DB081D Flash memory. * * - * \version $Id: dflash.h 15402 2007-04-10 09:10:56Z asterix $ + * \version $Id: dataflash.h 20677 2008-02-19 14:29:52Z batt $ * \author Daniele Basile */ @@ -43,127 +43,87 @@ #include #include -#include -#include "hw_spi.h" #include -#warning This driver must be test before use! /** - * Type definition for dflash memory. + * Type definitions for dflash memory. + * \{ */ -typedef uint32_t dataflashAddr_t; -typedef uint32_t dataflashOffset_t; -typedef uint32_t dataflashSize_t; - -#define RESET_PULSE_WIDTH 10 // Width of reset pulse in usec. -#define BUSY_BIT 0x80 // Select a busy bit in status register. -#define CMP_BIT 0x40 // Select a compare bit in status register. +typedef uint32_t dataflash_page_t; +typedef uint32_t dataflash_offset_t; +typedef uint32_t dataflash_size_t; +/*\}*/ /** - * Select 2,3,4,5 bits of status register, those - * bits indicate a id of density device (see datasheet for - * more detail). + * */ -#define GET_ID_DESITY_DEVICE(reg_stat)\ - do {\ - reg_stat &= 0x3C;\ - reg_stat >>= 2;\ - } while (0) +typedef void (dataflash_setReset_t)(bool); +typedef void (dataflash_setCS_t)(bool); /** - * Pin definition. + * Memory definitions. * - * \note RESET and WP are asserted when logic - * level is low. - * \{ + * List of supported memory devices by this drive. + * Every time we call dataflash_init() we check device id to + * ensure we choose the right memory configuration. + * (see dataflash.c for more details). */ -#define RESET PC0 ///< Connect to RESET pin of flash memory -#define WP PC1 ///< Connect to WP pin of flash memory -#define DATAFLASH_PORT PORTC ///< Micro pin PORT register. -#define DATAFLASH_PIN PINC ///< Micro pin PIN register. -#define DATAFLASH_DDR DDRC ///< Micro pin DDR register. -/* \} */ +typedef enum DataflashType +{ + DFT_AT45DB041B, + DFT_AT45DB081D, + DFT_AT45DB161D, + DFT_CNT +} DataflashType; + /** - * Pin logic level. - * - * \{ + * Dataflash KFile context structure. */ -#define RESET_LOW() do { DATAFLASHs_PORT &= ~BV(RESET); } while(0) -#define RESET_HIGH() do { DATAFLASH_PORT |= BV(RESET); } while(0) -#define WP_LOW() do { DATAFLASH_PORT &= ~BV(WP); } while(0) -#define WP_HIGH() do { DATAFLASH_PORT |= BV(WP); } while(0) -/* \} */ +typedef struct KFileDataflash +{ + KFile fd; ///< File descriptor. + KFile *channel; ///< Dataflash comm channel (usually SPI). + DataflashType dev; ///< Memory device type; + dataflash_page_t current_page; ///< Current loaded dataflash page. + bool page_dirty; ///< True if current_page is dirty (needs to be flushed). + dataflash_setReset_t *setReset; ///< Callback used to set reset pin of dataflash. + dataflash_setCS_t *setCS; ///< Callback used to set CS pin of dataflash. +} KFileDataflash; /** - * Commands pin. - * - * \note To reset flash memory it needs a pulse - * long about 10 usec. To do this we insert a - * for cycle. - * - * \{ + * Convert + ASSERT from generic KFile to KFileDataflash. */ -#define RESET_OUT() do { DATAFLASH_DDR |= BV(RESET); } while(0) -#define WP_OUT() do { DATAFLASH_DDR |= BV(WP); } while(0) -#define WRITE_ENABLE() WP_HIGH() -#define WRITE_DISABLE() WP_LOW() -#define RESET_ENABLE() RESET_LOW() -#define RESET_DISABLE() RESET_HIGH() -/* \} */ +INLINE KFileDataflash * KFILEDATAFLASH(KFile *fd) +{ + ASSERT(fd->_type == KFT_DATAFLASH); + return (KFileDataflash *)fd; +} +#define RESET_PULSE_WIDTH 10 ///< Width of reset pulse in usec. +#define BUSY_BIT 0x80 ///< Select a busy bit in status register. +#define CMP_BIT 0x40 ///< Select a compare bit in status register. /** - * Memory definition. - * - * \note Below are defined valid flash memory support to - * this drive. Every time we call dataflash_init() function we check - * if memory defined are right (see dataflash.c form more detail). - * \{ + * Select bits 2-5 of status register. These + * bits indicate device density (see datasheet for + * more details). */ -#define DATAFLASH_AT45DB041B 1 -#define DATAFLASH_AT45DB081D 2 -#define DATAFLASH_AT45DB161D 3 - -#if CONFIG_DATA_FLASH == DATAFLASH_AT45DB161D - #define DATAFLASH_ID_DEVICE_DENSITY 0xb ///< This indicate AT45DB161D data flah memory. - #define DATAFLASH_PAGE_SIZE 528 ///< Number of byte in one page. - #define DATAFLASH_PAGE_ADDRESS_BIT 10 ///< Number bit for addressing one page. - #define DATAFLASH_NUM_PAGE 4096 ///< Number page in data flash memory. -#elif CONFIG_DATA_FLASH == DATAFLASH_AT45DB081D - #define DATAFLASH_ID_DEVICE_DENSITY 0x9 ///< This indicate AT45DB081D data flah memory. - #define DATAFLASH_PAGE_SIZE 264 ///< Number of byte in one page. - #define DATAFLASH_PAGE_ADDRESS_BIT 9 ///< Number bit for addressing one page. - #define DATAFLASH_NUM_PAGE 4096 ///< Number page in data flash memory. -#elif CONFIG_DATA_FLASH == DATAFLASH_AT45DB041B - #define DATAFLASH_ID_DEVICE_DENSITY 0x7 ///< This indicate AT45DB041B data flah memory. - #define DATAFLASH_PAGE_SIZE 264 ///< Number of byte in one page. - #define DATAFLASH_PAGE_ADDRESS_BIT 9 ///< Number bit for addressing one page. - #define DATAFLASH_NUM_PAGE 2048 ///< Number page in data flash memory. -#else - #error Nothing memory defined in CONFIG_DATA_FLASH are support. -#endif -/* \} */ - +#define GET_ID_DESITY_DEVICE(reg_stat) (((reg_stat) & 0x3C) >> 2) /** * Data flash opcode commands. */ -typedef enum { +typedef enum DataFlashOpcode { /** - * Read commands data flash. + * Dataflash read commands. * \{ */ + DFO_READ_FLASH_MEM_BYTE_D = 0x0B, ///< Continuos array read for D type memories. + DFO_READ_FLASH_MEM_BYTE_B = 0xE8, ///< Continuos array read for B type memories. -#if CONFIG_DATA_FLASH == DATAFLASH_AT45DB081D || CONFIG_DATA_FLASH == AT45DB161D - DFO_READ_FLASH_MEM_BYTE = 0x0B, ///< Continuos array read. -#elif CONFIG_DATA_FLASH == DATAFLASH_AT45DB041B - DFO_READ_FLASH_MEM_BYTE = 0xE8, ///< Continuos array read. -#else - #error No supported memory defined in CONFIG_DATA_FLASH. -#endif DFO_READ_FLASH_MEM = 0xD2, ///< Main memory page read. DFO_READ_BUFF1 = 0xD4, ///< SRAM buffer 1 read. DFO_READ_BUFF2 = 0xD6, ///< SRAM buffer 2 read. @@ -175,36 +135,48 @@ typedef enum { */ DFO_WRITE_BUFF1 = 0x84, ///< SRAM buffer 1 write. DFO_WRITE_BUFF2 = 0x87, ///< SRAM buffer 2 write. - DFO_WRITE_BUFF1_TO_MEM_E = 0x83, ///< Buffer 1 to main memory page program with build-in erase. - DFO_WRITE_BUFF2_TO_MEM_E = 0x86, ///< Buffer 2 to main memory page program with build-in erase. - DFO_WRITE_BUFF1_TO_MEM = 0x88, ///< Buffer 1 to main memory page program without build-in erase. - DFO_WRITE_BUFF2_TO_MEM = 0x89, ///< Buffer 2 to main memory page program without build-in erase. + DFO_WRITE_BUFF1_TO_MEM_E = 0x83, ///< Buffer 1 to main memory page program with built-in erase. + DFO_WRITE_BUFF2_TO_MEM_E = 0x86, ///< Buffer 2 to main memory page program with built-in erase. + DFO_WRITE_BUFF1_TO_MEM = 0x88, ///< Buffer 1 to main memory page program without built-in erase. + DFO_WRITE_BUFF2_TO_MEM = 0x89, ///< Buffer 2 to main memory page program without built-in erase. DFO_ERASE_PAGE = 0x81, ///< Erase page. DFO_ERASE_BLOCK = 0x50, ///< Erase block. DFO_ERASE_SECTOR = 0x7C, ///< Erase sector. - DFO_WRITE_MEM_TR_BUFF1 = 0x82, ///< Write main memory page program through buffer 1. - DFO_WRITE_MEM_TR_BUFF2 = 0x85, ///< Write main memory page program through buffer 2. + DFO_WRITE_MEM_TR_BUFF1 = 0x82, ///< Write main memory page through buffer 1. + DFO_WRITE_MEM_TR_BUFF2 = 0x85, ///< Write main memory page through buffer 2. /* \}*/ /** - * Additional commands data flash. + * Additional dataflash commands. * \{ */ - DFO_MOV_MEM_TO_BUFF1 = 0x53, ///< Main mmemory to buffer 1 transfer. - DFO_MOV_MEM_TO_BUFF2 = 0x55, ///< Main mmemory to buffer 2 transfer. - DFO_CMP_MEM_TO_BUFF1 = 0x60, ///< Main mmemory to buffer 1 compare. - DFO_CMP_MEM_TO_BUFF2 = 0x61, ///< Main mmemory to buffer 2 compare. + DFO_MOV_MEM_TO_BUFF1 = 0x53, ///< Transfer main mmemory to buffer 1. + DFO_MOV_MEM_TO_BUFF2 = 0x55, ///< Transfer main mmemory to buffer 2. + DFO_CMP_MEM_TO_BUFF1 = 0x60, ///< Compare main mmemory with buffer 1. + DFO_CMP_MEM_TO_BUFF2 = 0x61, ///< Compare main mmemory with buffer 2. DFO_ARW_MEM_TR_BUFF1 = 0x58, ///< Auto page rewrite through buffer 1. DFO_ARW_MEM_TR_BUFF2 = 0x59, ///< Auto page rewrite through buffer 2 DFO_PWR_DOWN = 0xB9, ///< Deep power-down. DFO_RESUME_PWR_DOWN = 0xAB, ///< Resume from deep power-down. - DFO_READ_STATUS = 0xD7, ///< Status register read. - DFO_ID_DEV = 0x9F ///< Manufacturer and device ID read. + DFO_READ_STATUS = 0xD7, ///< Read status register. + DFO_ID_DEV = 0x9F ///< Read manufacturer and device ID. /* \}*/ } DataFlashOpcode; -void dataflash_init(struct _KFile *fd); -void dataflash_test(void); -#endif /* DRV_DATAFLASH_H */ +/** + * Structure used to describe a dataflash memory. + */ +typedef struct DataflashInfo +{ + uint8_t density_id; ///< Density id, used to check memory type. + dataflash_size_t page_size; ///< Page size, in bytes. + uint8_t page_bits; ///< Number of bits needed to access a page. + uint16_t page_cnt; ///< Number of pages on memory. + DataFlashOpcode read_cmd; ///< Command to be used to perform a continuous array. +} DataflashInfo; + +bool dataflash_init(KFileDataflash *fd, KFile *ch, DataflashType type, dataflash_setCS_t *setCS, dataflash_setReset_t *setReset); + +#endif /* DRV_DATAFLASH_H */