📄 at45dbp.nc
字号:
// $Id: At45dbP.nc,v 1.7 2008/06/11 00:46:23 razvanm Exp $/* * "Copyright (c) 2000-2003 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * * Copyright (c) 2002-2005 Intel Corporation * All rights reserved. * * This file is distributed under the terms in the attached INTEL-LICENSE * file. If you do not find these files, copies can be found by writing to * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, * 94704. Attention: Intel License Inquiry. */#include "crc.h"#include "At45db.h"#include "Timer.h"/** * Private componenent for the Atmel's AT45DB HAL. * * @author David Gay */module At45dbP { provides { interface Init; interface At45db; } uses { interface HplAt45db; interface BusyWait<TMicro, uint16_t>; }}implementation{#define CHECKARGS#if 0 uint8_t work[20]; uint8_t woffset; void wdbg(uint8_t x) { work[woffset++] = x; if (woffset == sizeof work) woffset = 0; }#else#define wdbg(n)#endif enum { // requests IDLE, R_READ, R_READCRC, R_WRITE, R_ERASE, R_COPY, R_SYNC, R_SYNCALL, R_FLUSH, R_FLUSHALL, BROKEN // Write failed. Fail all subsequent requests. }; uint8_t request; at45pageoffset_t reqOffset, reqBytes; uint8_t * COUNT_NOK(reqBytes) reqBuf; at45page_t reqPage; enum { P_READ, P_READCRC, P_WRITE, P_FLUSH, P_FILL, P_ERASE, P_COMPARE, P_COMPARE_CHECK }; struct { at45page_t page; bool busy : 1; bool clean : 1; bool erased : 1; uint8_t unchecked : 2; } buffer[2]; uint8_t selected; // buffer used by the current op uint8_t checking; bool flashBusy; // Select a command for the current buffer#define OPN(n, name) ((n) ? name ## 1 : name ## 2)#define OP(name) OPN(selected, name) command error_t Init.init() { request = IDLE; flashBusy = TRUE; // pretend we're on an invalid non-existent page buffer[0].page = buffer[1].page = AT45_MAX_PAGES; buffer[0].busy = buffer[1].busy = FALSE; buffer[0].clean = buffer[1].clean = TRUE; buffer[0].unchecked = buffer[1].unchecked = 0; buffer[0].erased = buffer[1].erased = FALSE; return SUCCESS; } void flashIdle() { flashBusy = buffer[0].busy = buffer[1].busy = FALSE; } void requestDone(error_t result, uint16_t computedCrc, uint8_t newState); void handleRWRequest(); task void taskSuccess() { requestDone(SUCCESS, 0, IDLE); } task void taskFail() { requestDone(FAIL, 0, IDLE); } void checkBuffer(uint8_t buf) { if (flashBusy) { call HplAt45db.waitIdle(); return; } call HplAt45db.compare(OPN(buf, AT45_C_COMPARE_BUFFER), buffer[buf].page); checking = buf; } void flushBuffer() { if (flashBusy) { call HplAt45db.waitIdle(); return; } call HplAt45db.flush(buffer[selected].erased ? OP(AT45_C_QFLUSH_BUFFER) : OP(AT45_C_FLUSH_BUFFER), buffer[selected].page); } event void HplAt45db.waitIdleDone() { flashIdle(); // Eager compare - this steals the current command#if 0 if ((buffer[0].unchecked || buffer[1].unchecked) && cmdPhase != P_COMPARE) checkBuffer(buffer[0].unchecked ? 0 : 1); else#endif handleRWRequest(); } event void HplAt45db.waitCompareDone(bool ok) { flashIdle(); if (ok) buffer[checking].unchecked = 0; else if (buffer[checking].unchecked < 2) buffer[checking].clean = FALSE; else { requestDone(FAIL, 0, BROKEN); return; } handleRWRequest(); } event void HplAt45db.readDone() { requestDone(SUCCESS, 0, IDLE); } event void HplAt45db.writeDone() { buffer[selected].clean = FALSE; buffer[selected].unchecked = 0; requestDone(SUCCESS, 0, IDLE); } event void HplAt45db.crcDone(uint16_t crc) { requestDone(SUCCESS, crc, IDLE); } event void HplAt45db.flushDone() { flashBusy = TRUE; buffer[selected].clean = buffer[selected].busy = TRUE; buffer[selected].unchecked++; buffer[selected].erased = FALSE; handleRWRequest(); } event void HplAt45db.compareDone() { flashBusy = TRUE; buffer[checking].busy = TRUE; // The 10us wait makes old mica motes (Atmega 103) happy, for // some mysterious reason (w/o this wait, the first compare // always fails, even though the compare after the rewrite // succeeds...) call BusyWait.wait(10); call HplAt45db.waitCompare(); } event void HplAt45db.fillDone() { flashBusy = TRUE; buffer[selected].page = reqPage; buffer[selected].clean = buffer[selected].busy = TRUE; buffer[selected].erased = FALSE; handleRWRequest(); } event void HplAt45db.eraseDone() { flashBusy = TRUE; // The buffer contains garbage, but we don't care about the state // of bits on this page anyway (if we do, we'll perform a // subsequent write) buffer[selected].page = reqPage; buffer[selected].clean = TRUE; buffer[selected].erased = TRUE; requestDone(SUCCESS, 0, IDLE); } void syncOrFlushAll(uint8_t newReq); void handleRWRequest() { if (reqPage == buffer[selected].page) switch (request) { case R_ERASE: switch (reqOffset) { case AT45_ERASE: if (flashBusy) call HplAt45db.waitIdle(); else call HplAt45db.erase(AT45_C_ERASE_PAGE, reqPage); break; case AT45_PREVIOUSLY_ERASED: // We believe the user... buffer[selected].erased = TRUE; /* Fallthrough */ case AT45_DONT_ERASE: // The buffer contains garbage, but we don't care about the state // of bits on this page anyway (if we do, we'll perform a // subsequent write) buffer[selected].clean = TRUE; requestDone(SUCCESS, 0, IDLE); break; } break; case R_COPY: if (!buffer[selected].clean) // flush any modifications flushBuffer(); else { // Just redesignate as destination page, and mark it dirty. // It will eventually be flushed, completing the copy. buffer[selected].page = reqOffset; buffer[selected].clean = FALSE; post taskSuccess(); } break; case R_SYNC: case R_SYNCALL: if (buffer[selected].clean && buffer[selected].unchecked) { checkBuffer(selected); return; } /* fall through */ case R_FLUSH: case R_FLUSHALL: if (!buffer[selected].clean) flushBuffer(); else if (request == R_FLUSH || request == R_SYNC) post taskSuccess(); else { // Check for more dirty pages uint8_t oreq = request; request = IDLE; syncOrFlushAll(oreq); } break; case R_READ: if (buffer[selected].busy) call HplAt45db.waitIdle(); else call HplAt45db.readBuffer(OP(AT45_C_READ_BUFFER), reqOffset, reqBuf, reqBytes); break; case R_READCRC: if (buffer[selected].busy) call HplAt45db.waitIdle(); else /* Hack: baseCrc was stored in reqBuf */ call HplAt45db.crc(OP(AT45_C_READ_BUFFER), 0, reqOffset, reqBytes, (uint16_t)reqBuf); break; case R_WRITE: if (buffer[selected].busy) call HplAt45db.waitIdle(); else call HplAt45db.write(OP(AT45_C_WRITE_BUFFER), 0, reqOffset, reqBuf, reqBytes); break; } else if (!buffer[selected].clean) flushBuffer(); else if (buffer[selected].unchecked) checkBuffer(selected); else { // just get the new page (except for erase) if (request == R_ERASE) { buffer[selected].page = reqPage; handleRWRequest(); } else if (flashBusy) call HplAt45db.waitIdle(); else call HplAt45db.fill(OP(AT45_C_FILL_BUFFER), reqPage); } } void requestDone(error_t result, uint16_t computedCrc, uint8_t newState) { uint8_t orequest = request; request = newState; switch (orequest) { case R_READ: signal At45db.readDone(result); break; case R_READCRC: signal At45db.computeCrcDone(result, computedCrc); break; case R_WRITE: signal At45db.writeDone(result); break; case R_SYNC: case R_SYNCALL: signal At45db.syncDone(result); break; case R_FLUSH: case R_FLUSHALL: signal At45db.flushDone(result); break; case R_ERASE: signal At45db.eraseDone(result); break; case R_COPY: signal At45db.copyPageDone(result); break; } } void newRequest(uint8_t req, at45page_t page, at45pageoffset_t offset, void * COUNT_NOK(n) reqdata, at45pageoffset_t n) { request = req; reqBuf = reqdata; reqBytes = n; reqPage = page; reqOffset = offset; if (page == buffer[0].page) selected = 0; else if (page == buffer[1].page) selected = 1; else selected = !selected; // LRU with 2 buffers...#ifdef CHECKARGS if (page >= AT45_MAX_PAGES || offset >= AT45_PAGE_SIZE || n > AT45_PAGE_SIZE || offset + n > AT45_PAGE_SIZE) post taskFail(); else#endif handleRWRequest(); } command void At45db.read(at45page_t page, at45pageoffset_t offset, void *reqdata, at45pageoffset_t n) { newRequest(R_READ, page, offset, reqdata, n); } command void At45db.computeCrc(at45page_t page, at45pageoffset_t offset, at45pageoffset_t n, uint16_t baseCrc) { /* This is a hack (store crc in reqBuf), but it saves 2 bytes of RAM */ reqBuf = TCAST(uint8_t * COUNT(baseCrc), baseCrc); newRequest(R_READCRC, page, offset, reqBuf, n); } command void At45db.write(at45page_t page, at45pageoffset_t offset, void *reqdata, at45pageoffset_t n) { newRequest(R_WRITE, page, offset, reqdata, n); } command void At45db.erase(at45page_t page, uint8_t eraseKind) { newRequest(R_ERASE, page, eraseKind, NULL, 0); } command void At45db.copyPage(at45page_t from, at45page_t to) { /* Assumes at45pageoffset_t can hold an at45page_t. A little icky */ newRequest(R_COPY, from, to, NULL, 0); } void syncOrFlush(at45page_t page, uint8_t newReq) { request = newReq; if (buffer[0].page == page) selected = 0; else if (buffer[1].page == page) selected = 1; else { post taskSuccess(); return; } buffer[selected].unchecked = 0; handleRWRequest(); } command void At45db.sync(at45page_t page) { syncOrFlush(page, R_SYNC); } command void At45db.flush(at45page_t page) { syncOrFlush(page, R_FLUSH); } void syncOrFlushAll(uint8_t newReq) { request = newReq; if (!buffer[0].clean) selected = 0; else if (!buffer[1].clean) selected = 1; else { post taskSuccess(); return; } buffer[selected].unchecked = 0; handleRWRequest(); } command void At45db.syncAll() { syncOrFlushAll(R_SYNCALL); } command void At45db.flushAll() { syncOrFlushAll(R_FLUSHALL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -