X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=drv%2Fdataflash.c;h=e2d2e291161188e8c31c42df3e9f535d8253c568;hb=941529ddc4cddd04f69d38c0929ec00fe93aadef;hp=ddc9deb0cbbb710770afc8ff347fe0b4072b8803;hpb=0610a6395e21f7601708c552ca088d6ccfc21bfd;p=bertos.git diff --git a/drv/dataflash.c b/drv/dataflash.c index ddc9deb0..e2d2e291 100644 --- a/drv/dataflash.c +++ b/drv/dataflash.c @@ -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 */ @@ -46,26 +46,32 @@ #include #include #include -#include +#include #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; + +} +