Merge from kseries.
authorbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 19 Feb 2008 14:51:02 +0000 (14:51 +0000)
committerbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 19 Feb 2008 14:51:02 +0000 (14:51 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1141 38d2e660-2303-0410-9eaa-f027e97ec537

drv/dataflash.c
drv/dataflash.h

index 2f4f897ee0665133d6fb70f355fb722115d37efa..d9392f9aadb6db27088b7c5206417eaa54982c3a 100644 (file)
  *  \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 <asterix@develer.com>
+ * \author Francesco Sacchi <batt@develer.com>
  */
 
-
+#include "dataflash.h"
 #include <appconfig.h>
 
-#include <avr/io.h>
 #include <cfg/macros.h>
 #include <cfg/debug.h>
 #include <cfg/module.h>
 #include <drv/timer.h>
-#include <drv/spi.h>
-#include <drv/dataflash.h>
+#include <kern/kfile.h>
+
+#if CONFIG_KERNEL
+#include <kern/proc.h>
+#endif
 
-#include "hw_spi.h"
+#include <string.h>
 
-#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;
-
 }
-
index c49b9acd0a61fa257fc072991c178b129993930c..c77cf49669ea2058074390af13fe7adc56de510e 100644 (file)
@@ -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 <asterix@develer.com>
  */
 
 
 #include <kern/kfile.h>
 #include <cfg/compiler.h>
-#include <drv/spi.h>
-#include "hw_spi.h"
 
 #include <appconfig.h>
 
-#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 */