dataflash.c

Go to the documentation of this file.
00001 
00041 #include "dataflash.h"
00042 #include <appconfig.h>
00043 
00044 #include <cfg/macros.h>
00045 #include <cfg/debug.h>
00046 #include <cfg/module.h>
00047 #include <drv/timer.h>
00048 #include <kern/kfile.h>
00049 
00050 #if CONFIG_KERNEL
00051 #include <kern/proc.h>
00052 #endif
00053 
00054 #include <string.h>
00055 
00059 static const DataflashInfo mem_info[] =
00060 {
00061     {
00062         /* AT45DB041B */
00063         .density_id = 0x07,
00064         .page_size = 264,
00065         .page_bits = 9,
00066         .page_cnt = 2048,
00067         .read_cmd = DFO_READ_FLASH_MEM_BYTE_B,
00068     },
00069     {
00070         /* AT45DB081D */
00071         .density_id = 0x09,
00072         .page_size = 264,
00073         .page_bits = 9,
00074         .page_cnt = 4096,
00075         .read_cmd = DFO_READ_FLASH_MEM_BYTE_D,
00076     },
00077     {
00078         /* AT45DB161D */
00079         .density_id = 0x0B,
00080         .page_size = 528,
00081         .page_bits = 10,
00082         .page_cnt = 4096,
00083         .read_cmd = DFO_READ_FLASH_MEM_BYTE_D,
00084     },
00085     /* Add other memories here */
00086 };
00087 
00088 STATIC_ASSERT(countof(mem_info) == DFT_CNT);
00089 
00094 INLINE void CS_TOGGLE(KFileDataflash *fd)
00095 {
00096     fd->setCS(false);
00097     fd->setCS(true);
00098 }
00099 
00105 static void send_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode)
00106 {
00107 
00108     /*
00109      * Make sure to toggle CS signal in order,
00110      * and reset dataflash command decoder.
00111      */
00112     CS_TOGGLE(fd);
00113 
00114 
00115     /*
00116      * To send one command to data flash memory, we send 4 byte.
00117      * First byte is opcode command, second and third byte are
00118      * page address, in last byte we write a byte page address.
00119      * (see datasheet for more detail).
00120      *
00121      * \note Generaly a defaul memory page size is more than 256 byte.
00122      *  In this case we need for addressing a byte in one page more than
00123      *  8 bit, so we put in fourth byte low part of address byte, and
00124      *  hight part of address byte in third byte togheter low par of page
00125      *  address.
00126      *
00127      */
00128 
00129     /*
00130      * Send opcode.
00131      */
00132     kfile_putc(opcode, fd->channel);
00133 
00134     /*
00135      *  Send page address.
00136      */
00137     kfile_putc((uint8_t)(page_addr >> (16 - mem_info[fd->dev].page_bits)), fd->channel);
00138     kfile_putc((uint8_t)((page_addr << (mem_info[fd->dev].page_bits - 8)) + (byte_addr >> 8)), fd->channel);
00139 
00140     /*
00141      * Send byte page address.
00142      */
00143     kfile_putc((uint8_t)byte_addr, fd->channel);
00144 }
00145 
00154 static void dataflash_reset(KFileDataflash *fd)
00155 {
00156     fd->setCS(false);
00157 
00158     if (fd->setReset)
00159     {
00160         fd->setReset(true);
00161         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
00162         fd->setReset(false);
00163         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
00164     }
00165 }
00166 
00167 
00171 static uint8_t dataflash_stat(KFileDataflash *fd)
00172 {
00173     /*
00174      * Make sure to toggle CS signal
00175      * and reset dataflash command decoder.
00176      */
00177     CS_TOGGLE(fd);
00178 
00179     kfile_putc(DFO_READ_STATUS, fd->channel);
00180 
00181     return kfile_getc(fd->channel);
00182 }
00183 
00184 
00190 static uint8_t dataflash_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode)
00191 {
00192     uint8_t stat;
00193 
00194     send_cmd(fd, page_addr, byte_addr, opcode);
00195 
00196     CS_TOGGLE(fd);
00197 
00198     /*
00199      * We chech data flash memory state, and wait until busy-flag
00200      * is high.
00201      */
00202     while (!(dataflash_stat(fd) & BUSY_BIT))
00203     {
00204         #if CONFIG_KERNEL
00205         proc_switch();
00206         #endif
00207     }
00208 
00209     stat = dataflash_stat(fd);
00210 
00211     kfile_flush(fd->channel); // Flush channel
00212     /*
00213      * Data flash has completed a bus cycle, so disable CS.
00214      */
00215     fd->setCS(false);
00216 
00217     return stat;
00218 }
00219 
00224 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)
00225 {
00226     send_cmd(fd, page_addr, byte_addr, opcode);
00227 
00228     if (opcode == DFO_READ_FLASH_MEM_BYTE_B)
00229     {
00230         /*
00231          * Send 24 don't care bits.
00232          */
00233         uint8_t dummy[] = { 0, 0, 0 };
00234         kfile_write(fd->channel, dummy, sizeof(dummy));
00235     }
00236 
00237     kfile_putc(0, fd->channel); //Send 8 don't care bit.
00238     kfile_read(fd->channel, block, len); //Read len bytes ad put in block buffer.
00239     kfile_flush(fd->channel); // Flush channel
00240     fd->setCS(false);
00241 }
00242 
00243 
00251 static void dataflash_writeBlock(KFileDataflash *fd, dataflash_offset_t offset, DataFlashOpcode opcode, const uint8_t *block, dataflash_size_t len)
00252 {
00253     ASSERT(offset + len <= mem_info[fd->dev].page_size);
00254 
00255     send_cmd(fd, 0x00, offset, opcode);
00256 
00257     kfile_write(fd->channel, block, len); //Write len bytes.
00258     kfile_flush(fd->channel); // Flush channel
00259 
00260     fd->setCS(false);
00261 }
00262 
00263 
00267 static void dataflash_loadPage(KFileDataflash *fd, dataflash_page_t page_addr)
00268 {
00269     dataflash_cmd(fd, page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1);
00270 }
00271 
00275 static int dataflash_flush(KFile *_fd)
00276 {
00277     KFileDataflash *fd = KFILEDATAFLASH(_fd);
00278     if (fd->page_dirty)
00279     {
00280         dataflash_cmd(fd, fd->current_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E);
00281 
00282         fd->page_dirty = false;
00283 
00284         kprintf("Flushing page <%ld>\n", fd->current_page);
00285     }
00286     return 0;
00287 }
00288 
00289 /* Kfile interface section */
00290 
00294 static int dataflash_close(struct KFile *_fd)
00295 {
00296     dataflash_flush(_fd);
00297     TRACE;
00298     return 0;
00299 }
00300 
00304 static KFile *dataflash_reopen(KFile *_fd)
00305 {
00306     KFileDataflash *fd = KFILEDATAFLASH(_fd);
00307     dataflash_close(_fd);
00308 
00309     fd->current_page = 0;
00310     fd->fd.seek_pos = 0;
00311 
00312     /* Load selected page from dataflash memory */
00313     dataflash_loadPage(fd, fd->current_page);
00314 
00315     TRACE;
00316     return &fd->fd;
00317 }
00318 
00319 
00332 static size_t dataflash_read(struct KFile *_fd, void *buf, size_t size)
00333 {
00334     KFileDataflash *fd = KFILEDATAFLASH(_fd);
00335 
00336     dataflash_offset_t byte_addr;
00337     dataflash_page_t page_addr;
00338     uint8_t *data = (uint8_t *)buf;
00339 
00340 
00341     ASSERT(fd->fd.seek_pos + size <= fd->fd.size);
00342     size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos);
00343 
00344     kprintf("Reading at pos[%lu]\n", fd->fd.seek_pos);
00345 
00346     /*
00347      * We select page and offest from absolute address.
00348      */
00349     page_addr = fd->fd.seek_pos / mem_info[fd->dev].page_size;
00350     byte_addr = fd->fd.seek_pos % mem_info[fd->dev].page_size;
00351 
00352     kprintf("[page-<%ld>, byte-<%ld>]", page_addr, byte_addr);
00353 
00354     /*
00355      * Flush current page in main memory if
00356      * we had been written a byte in memory
00357      */
00358     dataflash_flush(&fd->fd);
00359 
00360     /*
00361      * Read byte in main page data flash memory.
00362      */
00363     dataflash_readBlock(fd, page_addr, byte_addr, mem_info[fd->dev].read_cmd, data, size);
00364 
00365     fd->fd.seek_pos += size;
00366     kprintf("Read %ld bytes\n", size);
00367 
00368     return size;
00369 }
00370 
00382 static size_t dataflash_write(struct KFile *_fd, const void *_buf, size_t size)
00383 {
00384     KFileDataflash *fd = KFILEDATAFLASH(_fd);
00385 
00386     dataflash_offset_t offset;
00387     dataflash_page_t new_page;
00388     size_t total_write = 0;
00389 
00390     const uint8_t *data = (const uint8_t *) _buf;
00391 
00392     ASSERT(fd->fd.seek_pos + size <= fd->fd.size);
00393     size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos);
00394 
00395     kprintf("Writing at pos[%lu]\n", fd->fd.seek_pos);
00396 
00397     while (size)
00398     {
00399         /*
00400         * We select page and offest from absolute address.
00401         */
00402         new_page = fd->fd.seek_pos / mem_info[fd->dev].page_size;
00403         offset = fd->fd.seek_pos % mem_info[fd->dev].page_size;
00404 
00405 
00406         size_t wr_len = MIN(size, mem_info[fd->dev].page_size - offset);
00407 
00408         kprintf(" [page-<%ld>, byte-<%ld>]",new_page, offset);
00409 
00410         if (new_page != fd->current_page)
00411         {
00412             /* Flush current page in main memory*/
00413             dataflash_flush(&fd->fd);
00414             /* Load select page memory from data flash memory*/
00415             dataflash_loadPage(fd, new_page);
00416 
00417             fd->current_page = new_page;
00418             kprintf(" >> Load page: <%ld> ", new_page);
00419         }
00420         /*
00421         * Write byte in current page, and set true
00422         * page_dirty flag.
00423         */
00424         dataflash_writeBlock(fd, offset, DFO_WRITE_BUFF1, data, wr_len);
00425         fd->page_dirty = true;
00426 
00427         data += wr_len;
00428         fd->fd.seek_pos += wr_len;
00429         size -= wr_len;
00430         total_write += wr_len;
00431     }
00432 
00433     kprintf("written %lu bytes\n", total_write);
00434     return total_write;
00435 }
00436 
00437 MOD_DEFINE(dataflash);
00438 
00448 bool dataflash_init(KFileDataflash *fd, KFile *ch, DataflashType dev, dataflash_setCS_t *setCS, dataflash_setReset_t *setReset)
00449 {
00450     uint8_t stat;
00451 
00452     MOD_CHECK(hw_dataflash);
00453 
00454     ASSERT(fd);
00455     ASSERT(ch);
00456     ASSERT(setCS);
00457     ASSERT(dev < DFT_CNT);
00458 
00459     memset(fd, 0, sizeof(*fd));
00460     DB(fd->fd._type = KFT_DATAFLASH);
00461     fd->dev = dev;
00462     fd->channel = ch;
00463     fd->setReset = setReset;
00464     fd->setCS = setCS;
00465 
00466     // Setup data flash programming functions.
00467     fd->fd.reopen = dataflash_reopen;
00468     fd->fd.close = dataflash_close;
00469     fd->fd.read = dataflash_read;
00470     fd->fd.write = dataflash_write;
00471     fd->fd.seek = kfile_genericSeek;
00472     fd->fd.flush = dataflash_flush;
00473 
00474     dataflash_reset(fd);
00475 
00476     stat = dataflash_stat(fd);
00477 
00478     /*
00479      * 2,3,4,5 bits of 1 byte status register
00480      * indicate a device density of dataflash memory
00481      * (see datasheet for more detail.)
00482      */
00483     if (GET_ID_DESITY_DEVICE(stat) != mem_info[fd->dev].density_id)
00484         return false;
00485 
00486     fd->current_page = 0;
00487     fd->fd.seek_pos = 0;
00488     fd->fd.size = mem_info[fd->dev].page_size * mem_info[fd->dev].page_cnt;
00489 
00490     /* Load selected page from dataflash memory */
00491     dataflash_loadPage(fd, fd->current_page);
00492     MOD_INIT(dataflash);
00493     return true;
00494 }