BeRTOS
|
00001 00038 #include "dataflash.h" 00039 00040 #include "cfg/cfg_dataflash.h" 00041 #include <cfg/macros.h> 00042 #include <cfg/debug.h> 00043 #include <cfg/module.h> 00044 00045 // Define logging setting (for cfg/log.h module). 00046 #define LOG_LEVEL DATAFLASH_LOG_LEVEL 00047 #define LOG_FORMAT DATAFLASH_LOG_FORMAT 00048 #include <cfg/log.h> 00049 00050 #include <drv/timer.h> 00051 00052 #include <fs/battfs.h> 00053 00054 #include <io/kfile.h> 00055 00056 #include <cpu/power.h> /* cpu_relax() */ 00057 00058 #include <string.h> 00059 00063 static const DataflashInfo mem_info[] = 00064 { 00065 { 00066 /* AT45DB041B */ 00067 .density_id = 0x07, 00068 .page_size = 264, 00069 .page_bits = 9, 00070 .page_cnt = 2048, 00071 .read_cmd = DFO_READ_FLASH_MEM_BYTE_B, 00072 }, 00073 { 00074 /* AT45DB081D */ 00075 .density_id = 0x09, 00076 .page_size = 264, 00077 .page_bits = 9, 00078 .page_cnt = 4096, 00079 .read_cmd = DFO_READ_FLASH_MEM_BYTE_D, 00080 }, 00081 { 00082 /* AT45DB161D */ 00083 .density_id = 0x0B, 00084 .page_size = 528, 00085 .page_bits = 10, 00086 .page_cnt = 4096, 00087 .read_cmd = DFO_READ_FLASH_MEM_BYTE_D, 00088 }, 00089 { 00090 /* AT45DB642D */ 00091 .density_id = 0x0F, 00092 .page_size = 1056, 00093 .page_bits = 11, 00094 .page_cnt = 8192, 00095 .read_cmd = DFO_READ_FLASH_MEM_BYTE_D, 00096 }, 00097 /* Add other memories here */ 00098 }; 00099 00100 STATIC_ASSERT(countof(mem_info) == DFT_CNT); 00101 00106 INLINE void CS_TOGGLE(DataFlash *fd) 00107 { 00108 fd->setCS(false); 00109 fd->setCS(true); 00110 } 00111 00117 static void send_cmd(DataFlash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode) 00118 { 00119 00120 /* 00121 * Make sure to toggle CS signal in order, 00122 * and reset dataflash command decoder. 00123 */ 00124 CS_TOGGLE(fd); 00125 00126 00127 /* 00128 * To send one command to data flash memory, we send 4 byte. 00129 * First byte is opcode command, second and third byte are 00130 * page address, in last byte we write a byte page address. 00131 * (see datasheet for more detail). 00132 * 00133 * \note Generally a default memory page size is more than 256 byte. 00134 * In this case we need for addressing a byte in one page more than 00135 * 8 bit, so we put in fourth byte low part of address byte, and 00136 * hight part of address byte in third byte togheter low par of page 00137 * address. 00138 * 00139 */ 00140 00141 /* 00142 * Send opcode. 00143 */ 00144 kfile_putc(opcode, fd->channel); 00145 00146 /* 00147 * Send page address. 00148 */ 00149 kfile_putc((uint8_t)(page_addr >> (16 - mem_info[fd->dev].page_bits)), fd->channel); 00150 kfile_putc((uint8_t)((page_addr << (mem_info[fd->dev].page_bits - 8)) + (byte_addr >> 8)), fd->channel); 00151 00152 /* 00153 * Send byte page address. 00154 */ 00155 kfile_putc((uint8_t)byte_addr, fd->channel); 00156 } 00157 00166 static void dataflash_reset(DataFlash *fd) 00167 { 00168 fd->setCS(false); 00169 00170 if (fd->setReset) 00171 { 00172 fd->setReset(true); 00173 timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); 00174 fd->setReset(false); 00175 timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); 00176 } 00177 } 00178 00179 00183 static uint8_t dataflash_stat(DataFlash *fd) 00184 { 00185 /* 00186 * Make sure to toggle CS signal 00187 * and reset dataflash command decoder. 00188 */ 00189 CS_TOGGLE(fd); 00190 kfile_putc(DFO_READ_STATUS, fd->channel); 00191 return kfile_getc(fd->channel); 00192 } 00193 00194 00200 static uint8_t dataflash_cmd(DataFlash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode) 00201 { 00202 uint8_t stat; 00203 00204 send_cmd(fd, page_addr, byte_addr, opcode); 00205 00206 CS_TOGGLE(fd); 00207 00208 /* 00209 * We chech data flash memory state, and wait until busy-flag 00210 * is high. 00211 */ 00212 while (!(dataflash_stat(fd) & BUSY_BIT)) 00213 cpu_relax(); 00214 00215 stat = dataflash_stat(fd); 00216 00217 kfile_flush(fd->channel); // Flush channel 00218 /* 00219 * Data flash has completed a bus cycle, so disable CS. 00220 */ 00221 fd->setCS(false); 00222 00223 return stat; 00224 } 00225 00230 static void dataflash_readBlock(DataFlash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, uint8_t *block, dataflash_size_t len) 00231 { 00232 DataFlashOpcode opcode = mem_info[fd->dev].read_cmd; 00233 send_cmd(fd, page_addr, byte_addr, opcode); 00234 00235 if (opcode == DFO_READ_FLASH_MEM_BYTE_B) 00236 { 00237 /* 00238 * Send 24 don't care bits. 00239 */ 00240 uint8_t dummy[] = { 0, 0, 0 }; 00241 kfile_write(fd->channel, dummy, sizeof(dummy)); 00242 } 00243 00244 kfile_putc(0, fd->channel); //Send 8 don't care bit. 00245 kfile_read(fd->channel, block, len); //Read len bytes ad put in block buffer. 00246 kfile_flush(fd->channel); // Flush channel 00247 fd->setCS(false); 00248 } 00249 00250 00258 static void dataflash_writeBlock(DataFlash *fd, dataflash_offset_t offset, const uint8_t *block, dataflash_size_t len) 00259 { 00260 ASSERT(offset + len <= mem_info[fd->dev].page_size); 00261 00262 send_cmd(fd, 0x00, offset, DFO_WRITE_BUFF1); 00263 00264 kfile_write(fd->channel, block, len); //Write len bytes. 00265 kfile_flush(fd->channel); // Flush channel 00266 00267 fd->setCS(false); 00268 } 00269 00270 00274 static void dataflash_loadPage(DataFlash *fd, dataflash_page_t page_addr) 00275 { 00276 dataflash_cmd(fd, page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1); 00277 } 00278 00279 /* Battfs disk interface section */ 00280 #if 0 00281 static size_t dataflash_disk_page_read(struct BattFsSuper *d, pgcnt_t page, pgaddr_t addr, void *buf, size_t len) 00282 { 00283 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00284 dataflash_readBlock(fd, page, addr, buf, len); 00285 return len; 00286 } 00287 00288 static bool dataflash_disk_page_load(struct BattFsSuper *d, pgcnt_t page) 00289 { 00290 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00291 dataflash_loadPage(fd, page); 00292 return true; 00293 } 00294 00295 static size_t dataflash_disk_buffer_write(struct BattFsSuper *d, pgaddr_t addr, const void *buf, size_t len) 00296 { 00297 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00298 dataflash_writeBlock(fd, addr, buf, len); 00299 return len; 00300 } 00301 00302 static size_t dataflash_disk_buffer_read(struct BattFsSuper *d, pgaddr_t addr, void *buf, size_t len) 00303 { 00304 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00305 ASSERT(addr + len <= mem_info[fd->dev].page_size); 00306 00307 CS_TOGGLE(fd); 00308 00309 kfile_putc(DFO_READ_BUFF1, fd->channel); 00310 00311 uint32_t byte_addr = addr; 00312 00313 kfile_putc((byte_addr >> 16) & 0xff, fd->channel); 00314 kfile_putc((byte_addr >> 8) & 0xff, fd->channel); 00315 kfile_putc(byte_addr & 0xff, fd->channel); 00316 00317 /* Send additional don't care byte to start read operation */ 00318 kfile_putc(0, fd->channel); 00319 00320 kfile_read(fd->channel, buf, len); //Read len bytes ad put in buffer. 00321 kfile_flush(fd->channel); // Flush channel 00322 fd->setCS(false); 00323 return len; 00324 } 00325 00326 static bool dataflash_disk_page_save(struct BattFsSuper *d, pgcnt_t page) 00327 { 00328 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00329 dataflash_cmd(fd, page, 0x00, DFO_WRITE_BUFF1_TO_MEM); 00330 return true; 00331 } 00332 00333 static bool dataflash_disk_page_erase(struct BattFsSuper *d, pgcnt_t page) 00334 { 00335 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00336 dataflash_cmd(fd, page, 0x00, DFO_ERASE_PAGE); 00337 return true; 00338 } 00339 00340 static int dataflash_close(struct KFile *_fd); 00341 00342 static bool dataflash_disk_close(struct BattFsSuper *d) 00343 { 00344 DataFlash *fd = DATAFLASH_CAST((KFile *)d->disk_ctx); 00345 return dataflash_close(&fd->fd) == 0; 00346 } 00347 00348 bool dataflash_diskInit(struct BattFsSuper *d, DataFlash *fd, pgcnt_t *page_array) 00349 { 00350 ASSERT(d); 00351 ASSERT(fd); 00352 d->read = dataflash_disk_page_read; 00353 d->load = dataflash_disk_page_load; 00354 d->bufferWrite = dataflash_disk_buffer_write; 00355 d->bufferRead = dataflash_disk_buffer_read; 00356 d->save = dataflash_disk_page_save; 00357 d->erase = dataflash_disk_page_erase; 00358 d->close = dataflash_disk_close; 00359 d->disk_ctx = fd; 00360 d->page_size = mem_info[fd->dev].page_size; 00361 d->page_count = mem_info[fd->dev].page_cnt; 00362 ASSERT(page_array); 00363 d->page_array = page_array; 00364 return d->page_array && fd; 00365 } 00366 #endif 00367 00368 /* Kfile interface section */ 00369 00373 static int dataflash_flush(KFile *_fd) 00374 { 00375 DataFlash *fd = DATAFLASH_CAST(_fd); 00376 if (fd->page_dirty) 00377 { 00378 dataflash_cmd(fd, fd->current_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E); 00379 00380 fd->page_dirty = false; 00381 00382 LOG_INFO("Flushing page {%ld}\n", fd->current_page); 00383 } 00384 return 0; 00385 } 00386 00387 00391 static int dataflash_close(struct KFile *_fd) 00392 { 00393 dataflash_flush(_fd); 00394 LOG_INFO("Close.\n"); 00395 return 0; 00396 } 00397 00401 static KFile *dataflash_reopen(KFile *_fd) 00402 { 00403 DataFlash *fd = DATAFLASH_CAST(_fd); 00404 dataflash_close(_fd); 00405 00406 fd->current_page = 0; 00407 fd->fd.seek_pos = 0; 00408 00409 /* Load selected page from dataflash memory */ 00410 dataflash_loadPage(fd, fd->current_page); 00411 00412 LOG_INFO("Reopen.\n"); 00413 return &fd->fd; 00414 } 00415 00416 00429 static size_t dataflash_read(struct KFile *_fd, void *buf, size_t size) 00430 { 00431 DataFlash *fd = DATAFLASH_CAST(_fd); 00432 00433 dataflash_offset_t byte_addr; 00434 dataflash_page_t page_addr; 00435 uint8_t *data = (uint8_t *)buf; 00436 00437 00438 ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size); 00439 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); 00440 00441 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos); 00442 00443 /* 00444 * We select page and offest from absolute address. 00445 */ 00446 page_addr = fd->fd.seek_pos / mem_info[fd->dev].page_size; 00447 byte_addr = fd->fd.seek_pos % mem_info[fd->dev].page_size; 00448 00449 LOG_INFO("[page-{%ld}, byte-{%ld}]\n", page_addr, byte_addr); 00450 00451 /* 00452 * Flush current page in main memory if 00453 * we had been written a byte in memory 00454 */ 00455 dataflash_flush(&fd->fd); 00456 00457 /* 00458 * Read byte in main page data flash memory. 00459 */ 00460 dataflash_readBlock(fd, page_addr, byte_addr, data, size); 00461 00462 fd->fd.seek_pos += size; 00463 LOG_INFO("Read %ld bytes\n", (long int)size); 00464 00465 return size; 00466 } 00467 00479 static size_t dataflash_write(struct KFile *_fd, const void *_buf, size_t size) 00480 { 00481 DataFlash *fd = DATAFLASH_CAST(_fd); 00482 00483 dataflash_offset_t offset; 00484 dataflash_page_t new_page; 00485 size_t total_write = 0; 00486 00487 const uint8_t *data = (const uint8_t *) _buf; 00488 00489 ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size); 00490 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); 00491 00492 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos); 00493 00494 while (size) 00495 { 00496 /* 00497 * We select page and offest from absolute address. 00498 */ 00499 new_page = fd->fd.seek_pos / mem_info[fd->dev].page_size; 00500 offset = fd->fd.seek_pos % mem_info[fd->dev].page_size; 00501 00502 00503 size_t wr_len = MIN((dataflash_size_t)size, mem_info[fd->dev].page_size - offset); 00504 00505 LOG_INFO("[page-{%ld}, byte-{%ld}]\n",new_page, offset); 00506 00507 if (new_page != fd->current_page) 00508 { 00509 /* Flush current page in main memory*/ 00510 dataflash_flush(&fd->fd); 00511 /* Load select page memory from data flash memory*/ 00512 dataflash_loadPage(fd, new_page); 00513 00514 fd->current_page = new_page; 00515 LOG_INFO(" >> Load page: {%ld}\n", new_page); 00516 } 00517 /* 00518 * Write byte in current page, and set true 00519 * page_dirty flag. 00520 */ 00521 dataflash_writeBlock(fd, offset, data, wr_len); 00522 fd->page_dirty = true; 00523 00524 data += wr_len; 00525 fd->fd.seek_pos += wr_len; 00526 size -= wr_len; 00527 total_write += wr_len; 00528 } 00529 00530 LOG_INFO("written %lu bytes\n", (long unsigned)total_write); 00531 return total_write; 00532 } 00533 00534 MOD_DEFINE(dataflash); 00535 00545 bool dataflash_init(DataFlash *fd, KFile *ch, DataflashType dev, dataflash_setCS_t *setCS, dataflash_setReset_t *setReset) 00546 { 00547 uint8_t stat; 00548 00549 MOD_CHECK(hw_dataflash); 00550 00551 ASSERT(fd); 00552 ASSERT(ch); 00553 ASSERT(setCS); 00554 ASSERT(dev < DFT_CNT); 00555 00556 memset(fd, 0, sizeof(*fd)); 00557 DB(fd->fd._type = KFT_DATAFLASH); 00558 fd->dev = dev; 00559 fd->channel = ch; 00560 fd->setReset = setReset; 00561 fd->setCS = setCS; 00562 00563 // Setup data flash programming functions. 00564 fd->fd.reopen = dataflash_reopen; 00565 fd->fd.close = dataflash_close; 00566 fd->fd.read = dataflash_read; 00567 fd->fd.write = dataflash_write; 00568 fd->fd.seek = kfile_genericSeek; 00569 fd->fd.flush = dataflash_flush; 00570 00571 dataflash_reset(fd); 00572 stat = dataflash_stat(fd); 00573 00574 /* 00575 * 2,3,4,5 bits of 1 byte status register 00576 * indicate a device density of dataflash memory 00577 * (see datasheet for more detail.) 00578 */ 00579 if (GET_ID_DESITY_DEVICE(stat) != mem_info[fd->dev].density_id) 00580 return false; 00581 00582 fd->current_page = 0; 00583 fd->fd.seek_pos = 0; 00584 fd->fd.size = mem_info[fd->dev].page_size * mem_info[fd->dev].page_cnt; 00585 00586 /* Load selected page from dataflash memory */ 00587 dataflash_loadPage(fd, fd->current_page); 00588 MOD_INIT(dataflash); 00589 return true; 00590 }