Remove cvs logs.
[bertos.git] / drv / dataflash.c
index ddc9deb0cbbb710770afc8ff347fe0b4072b8803..e2d2e291161188e8c31c42df3e9f535d8253c568 100644 (file)
@@ -33,7 +33,7 @@
  *  \brief Function library for AT45DBXX Data Flash memory.
  *
  *
- * \version $Id: dflash.c 15379 2007-03-28 15:46:09Z asterix $
+ * \version $Id: dataflash.c 15379 2007-03-28 15:46:09Z asterix $
  * \author Daniele Basile <asterix@develer.com>
  */
 
 #include <cfg/module.h>
 #include <drv/timer.h>
 #include <drv/spi.h>
-#include <drv/dflash.h>
+#include <drv/dataflash.h>
 
 #include "hw_spi.h"
 
+
+/**
+ * Global variable for store current and previous data
+ * flash memory page address during operation of writing.
+ */
+static dataflash_t previous_page = 0;
+static bool page_modified = false;
+
+
 /**
  * Send a generic command to data flash memory.
  * This function send only 4 byte, for opcode, page address and
  * byte address.
  */
-static void send_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode)
+static void send_cmd(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode)
 {
 
        /*
         * Make sure to toggle CS signal in order,
-        * and reset dflash command decoder.
+        * and reset dataflash command decoder.
         *
-        * Note:
-        * #define CS_TOGGLE() \
-        *              CS_DISABLE(); \
-        *              CS_ENABLE(); \
+        * \note This is equivalent to CS_DISABLE() immediately followed by CS_ENABLE()
         */
        CS_TOGGLE();
 
@@ -82,7 +88,6 @@ static void send_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcod
         *  hight part of address byte in third byte togheter low par of page
         *  address.
         *
-        * \{
         */
 
        /*
@@ -92,18 +97,15 @@ static void send_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcod
 
        /*
         *  Send page address.
-        * \{
         */
-       spi_sendRecv((uint8_t)(page_addr >> (16 - DFLASH_PAGE_ADDRESS_BIT)));
-       spi_sendRecv((uint8_t)((page_addr << (DFLASH_PAGE_ADDRESS_BIT - 8)) + (byte_addr >> 8)));
-       /*\}*/
+       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)));
 
        /*
         * Send byte page address.
         */
        spi_sendRecv((uint8_t)byte_addr);
 
-       /* \} */
 
 }
 
@@ -114,7 +116,7 @@ static void send_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcod
  * with one pulse reset long about 10usec.
  *
  */
-static void dflash_reset(void)
+static void dataflash_reset(void)
 {
        CS_ENABLE();
        RESET_ENABLE();
@@ -125,13 +127,13 @@ static void dflash_reset(void)
 }
 
 /**
- * dflash init function.
+ * 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 dflash.h.
+ * density is the same wich define in dataflash.h.
  */
-MOD_DEFINE(dflash);
-static bool dflash_pin_init(void)
+MOD_DEFINE(dataflash);
+static bool dataflash_pin_init(void)
 {
        uint8_t stat;
 
@@ -143,20 +145,20 @@ static bool dflash_pin_init(void)
        RESET_OUT();
        WP_OUT();
 
-       dflash_reset();
+       dataflash_reset();
 
-       stat = dflash_stat();
+       stat = dataflash_stat();
 
-       MOD_INIT(dflash);
+       MOD_INIT(dataflash);
 
        /*
-        * 2,3,4,5 bit of 1 byte status register
-        * indicate a device density of dflash memory
+        * 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 == DFLASH_ID_DEVICE_DENSITY)
+       if(stat == DATAFLASH_ID_DEVICE_DENSITY)
                return true;
        else
                return false;
@@ -168,20 +170,25 @@ static bool dflash_pin_init(void)
  * Read status register of dataflah memory.
  *
  */
-static uint8_t dflash_stat(void)
+static uint8_t dataflash_stat(void)
 {
        uint8_t stat;
 
        /*
         * Make sure to toggle CS signal in order,
-        * and reset dflash command decoder.
-        * \{
+        * and reset dataflash command decoder.
         */
        CS_TOGGLE();
 
        stat = spi_sendRecv(DFO_READ_STATUS);
        stat = spi_sendRecv(0x00);
 
+       /*
+        * 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;
 }
 
@@ -191,21 +198,29 @@ static uint8_t dflash_stat(void)
  * return status register value.
  *
  */
-static uint8_t dflash_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode)
+static uint8_t dataflash_cmd(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode)
 {
 
+       uint8_t stat;
+
        send_cmd(page_addr, byte_addr, opcode);
 
-       CS_DISABLE();
-       CS_ENABLE();
+       CS_TOGGLE();
 
        /*
         * We chech data flash memory state, and wait until busy-flag
         * is hight.
         */
-       while(!(dflash_stat() & BUSY_BIT));
+       while(!(dataflash_stat() & BUSY_BIT));
 
-       return (dflash_stat());
+       stat = dataflash_stat();
+
+       /*
+        * Data flash has completed a bus cycle, so disable CS.
+        */
+       CS_DISABLE();
+
+       return (stat);
 
 }
 
@@ -213,29 +228,28 @@ static uint8_t dflash_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlash
  * Read one byte from main data flash memory or buffer data
  * flash memory.
  */
-static uint8_t dflash_read_byte(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode)
+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 == AT45DB041B
+#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
 
        spi_sendRecv(0x00);         //Send 8 don't care bit.
        data = spi_sendRecv(0x00);  //Read byte.
+
        CS_DISABLE();
 
        return data;
@@ -245,7 +259,7 @@ static uint8_t dflash_read_byte(dflashAddr_t page_addr, dflashAddr_t byte_addr,
  * Read \a len bytes from main data flash memory or buffer data
  * flash memory, and put it in \a *block.
  */
-static void dflash_read_block(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len)
+static void dataflash_read_block(dataflash_t page_addr, dataflashOffset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
 {
 
        send_cmd(page_addr, byte_addr, opcode);
@@ -254,12 +268,11 @@ static void dflash_read_block(dflashAddr_t page_addr, dflashAddr_t byte_addr, DF
        {
                /*
                 * Send 24 don't care bit.
-                * \{
                 */
                spi_sendRecv(0x00);
                spi_sendRecv(0x00);
                spi_sendRecv(0x00);
-               /* \} */
+
        }
 
        spi_sendRecv(0x00);   //Send 8 don't care bit.
@@ -278,7 +291,7 @@ static void dflash_read_block(dflashAddr_t page_addr, dflashAddr_t byte_addr, DF
  * 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.
  */
-static void dflash_write_block(dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len)
+static void dataflash_write_block(dataflashOffset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
 {
 
        send_cmd(0x00, byte_addr, opcode);
@@ -289,6 +302,30 @@ static void dflash_write_block(dflashAddr_t byte_addr, DFlashOpcode opcode, uint
 
 }
 
+
+/**
+ * Load selct page from dataflash memory to buffer.
+ */
+static void dataflash_loadPage(dataflash_t page_addr)
+{
+       dataflash_cmd(page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1);
+}
+
+/**
+ * Flush select page (stored in buffer) in data flash main memory page.
+ */
+void dataflash_flush(void)
+{
+       if (page_modified)
+       {
+               dataflash_cmd(previous_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E);
+
+               page_modified = false;
+
+               kprintf("\n::=> Flush page:... <%ld>\n", previous_page);
+       }
+}
+
 /* Kfile interface section */
 
 /**
@@ -296,45 +333,338 @@ static void dflash_write_block(dflashAddr_t byte_addr, DFlashOpcode opcode, uint
  * \a name and \a mode are unused, cause flash memory is
  * threated like one file.
  */
-static bool dflash_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode))
+static bool dataflash_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode))
 {
+       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 dflash_close(UNUSED_ARG(struct _KFile *,fd))
+static bool dataflash_close(UNUSED_ARG(struct _KFile *,fd))
 {
+       dataflash_flush();
+       kprintf("dataflash file closed\n");
+       return true;
 }
 
 /**
  * Move \a fd file seek position of \a offset bytes
  * from current position.
  */
-static int32_t dflash_seek(struct _KFile *fd, int32_t offset, KSeekMode whence)
+static int32_t dataflash_seek(struct _KFile *fd, kfile_off_t offset, KSeekMode whence)
 {
+       uint32_t seek_pos;
+
+       switch(whence)
+       {
+
+       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;
+
+       }
+
+       /* 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;
 }
 
 /**
- * Read from file \a fd \a size bytes and put it in buffer \a buf
+ * Read \a _buf lenght \a size byte from data flash 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
+ * directly from data flash main memory.
+ *
  * \return the number of bytes read.
  */
-static size_t dflash_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;
+
+
+       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);
+
+       /*
+        * 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;
+
+
+       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();
+
+       /*
+        * Read byte in main page data flash memory.
+        */
+       dataflash_read_block(page_addr, byte_addr, DFO_READ_FLASH_MEM_BYTE, data, size);
+
+       fd->seek_pos += size;
+       kprintf(" ::=> Read data: %02x\n",data);
+
+       return size;
+}
+
+/**
+ * Write \a _buf in data flash 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.
+ *
+ * \return the number of bytes write.
+ */
+static size_t dataflash_write(struct _KFile *fd, const void *_buf, size_t size)
+{
+
+       dataflashOffset_t byte_addr;
+       dataflashAddr_t current_page;
+
+       uint8_t *data = (uint8_t *) _buf;
+
+       ASSERT(fd->seek_pos + size <= fd->size);
+       size = MIN((uint32_t)size, fd->size - fd->seek_pos);
+
+       kprintf("Writing at pos[%u]\n", 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;
+
+
+               size_t wr_len = MIN(size, DATAFLASH_PAGE_SIZE - byte_addr);
+
+               kprintf(" [page-<%ld>, byte-<%ld>]",current_page, byte_addr);
+
+               if (current_page != previous_page)
+               {
+                       /* Flush current page in main memory*/
+                       dataflash_flush();
+                       /* Load select page memory from data flash memory*/
+                       dataflash_loadPage(current_page);
+
+                       previous_page = current_page;
+                       kprintf(" >> Load page: <%ld> ",current_page);
+               }
+               /*
+               * Write byte in current page, and set true
+               * page_modified flag.
+               */
+               dataflash_write_byte(byte_addr, DFO_WRITE_BUFF1, data);
+               page_modified = true;
+
+
+               data += wr_len;
+               fd->seek_pos += wr_len;
+               size -= wr_len;
+               total_write += wr_len;
+       }
+
+       kprintf("written %u bytes\n", total_write);
+       return total_write;
 }
 
 /**
  * Init data flash memory interface.
  */
-void dflash_init(struct _KFile *fd)
+void dataflash_init(struct _KFile *fd)
 {
        // Set up data flash programming functions.
-       fd->open = dflash_open;
-       fd->close = dflash_close;
-       fd->read = dflash_read;
-       fd->write = dflash_write;
-       fd->seek = dflash_seek;
+       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(dflash_pin_init());
-}
\ No newline at end of file
+       ASSERT(dataflash_pin_init());
+}
+
+/**
+ * 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.
+ */
+void dataflash_test(void)
+{
+       KFile fd;
+
+       dataflash_init(&fd);
+
+       uint8_t test_buf[] = "0123456789 Develer s.r.l.";
+       uint8_t cmp_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, SEEK_SET))
+               goto dataflash_test_end;
+
+       // Test flash write to address 0 (page 0)
+       tmp_len = fd->write(&fd, test_buf, len_tb)
+       if (len_tb != 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, 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, len_tb);
+       if (len_tb != 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, len_tb) == 0)
+       {
+               kprintf("Test 1: Readed test buf don't much!\n");
+               goto dataflash_test_end;
+       }
+
+       /*  TEST 2 */
+
+       // 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;
+
+       // Test flash write at the middle of memory
+       tmp_len = fd->write(&fd, test_buf, len_tb);
+       if (len_tb != tmp_len)
+       {
+               kprintf("Test 2: Wrong numer write bytes! expecteded [%d], write [%d]\n", tb_len, tmp_len);
+               goto dataflash_test_end;
+       }
+
+       // 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;
+
+       // Test flash read  at the middle of memory
+       tmp_len = fd->read(&fd, cmp_buf, len_tb);
+       if (len_tb != tmp_len)
+       {
+               kprintf("Test 2: 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, len_tb) == 0)
+       {
+               kprintf("Test 2: Readed test buf don't much!\n");
+               goto dataflash_test_end;
+       }
+       /*  TEST 3 */
+
+       // 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 write at the end of memory
+       tmp_len = fd->write(&fd, test_buf, len_tb);
+       if (len_tb != 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, len_tb);
+       if (len_tb != 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, len_tb) == 0)
+       {
+               kprintf("Test 3: Readed test buf don't much!\n");
+               goto dataflash_test_end;
+       }
+
+       kprintf("\n");
+
+       kprintf("\n====== Test end ===========================================================\n");
+       fd.close(&fd);
+       return true;
+
+dataflash_test_end:
+       fd.close(&fd);
+       return false;
+
+}
+