dsPid33
src/DEE Emulation 16-bit.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *
00003 *   Emulating Data EEPROM for PIC24 Microcontrollers and
00004 *           dsPIC Digital Signal Controllers
00005 *
00006 * This application note provides a standard interface to an efficient
00007 * Data EEPROM emulation algorithm and uses available program memory. 
00008 * It is designed for Microchip Technology 16-bit PIC and dsPIC J devices 
00009 * which currently include PIC24F, PIC24H and dsPIC33 products. The
00010 * project is initially configured to use PIC24FJ128GA010 on the Explorer
00011 * 16 Development Board. To use different device, simply select new device
00012 * in MPLAB, replace C30 linker script and rebuild.
00013 * User must select number pages of program memory, erase/write limit and 
00014 * emulated DEE size. These are defined in "DEE Emulation 16-bit.h".
00015 * At build-time, the linker reserves pages in the next available 
00016 * locations in program memory. Compiler error occurs if more than 255 
00017 * DEE locations are declared, less than 2 pages of program memory is 
00018 * reserved, greater than 65,535 erase/write cycles specified or if 
00019 * insufficient program memory is available. 
00020 * Call initialization routine and clear status flags before attempting 
00021 * any other DEE operation.
00022 *
00023 *************************************************************************
00024 * FileName:     DEE Emulation 16-bit.c
00025 * Dependencies: Flash Operations.s
00026 *               DEE Emulation 16-bit.h
00027 * Compiler:     MPLAB C30, v2.01 or higher
00028 * Company:      Microchip Technology, Inc.
00029 *
00030 * Software License Agreement
00031 *
00032 * Copyright � 2007 Microchip Technology Inc. All rights reserved.
00033 *
00034 * Microchip licenses to you the right to use, modify, copy and distribute
00035 * Software only when embedded on a Microchip microcontroller or digital
00036 * signal controller, which is integrated into your product or third party
00037 * product (pursuant to the sublicense terms in the accompanying license
00038 * agreement).
00039 *
00040 * You should refer to the license agreement accompanying this Software for
00041 * additional information regarding your rights and obligations.
00042 *
00043 * SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
00044 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY
00045 * WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A
00046 * PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE
00047 * LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY,
00048 * CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY
00049 * DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY
00050 * INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST
00051 * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY,
00052 * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO
00053 * ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
00054 *
00055 * Author            Date        Comment
00056 *************************************************************************
00057 * D. Otten          2007/05/01  Version 1.0.0 - Initial Release
00058 * D. Otten          2007/05/15  Version 1.0.1 - First publication release
00059 * Pradeep Budagutta 2008/04/02  Version 1.1.0 - Multi EEPROM banks included
00060 * Pradeep Budagutta 2008/05/05  Version 1.1.1 - TBLPAG page boundary problem solved
00061 ************************************************************************/
00062 
00063 #if defined (__dsPIC33F__)
00064     #include <p33Fxxxx.h>
00065 #elif defined (__PIC24H__)
00066     #include <p24Hxxxx.h>
00067 #elif defined (__PIC24F__)
00068     #include <p24Fxxxx.h>
00069 #else
00070     #error Selected processor not supported
00071 #endif
00072 
00073 #include "DEE Emulation 16-bit.h"
00074 
00075 // User constant validation
00076 #if DATA_EE_BANKS == 0
00077     #error Minimum data EE banks is 1
00078 #endif
00079 
00080 #if DATA_EE_SIZE > 255
00081     #error Maximum data EE size is 255
00082 #endif
00083 
00084 #if NUM_DATA_EE_PAGES < 2
00085     #error Minimum number of program memory pages is 2
00086 #endif
00087 
00088 #if ERASE_WRITE_CYCLE_MAX > 65535
00089     #error Maximum number of erase/write cycles is 65,535
00090 #endif
00091 
00092 
00093 DATA_EE_FLAGS dataEEFlags;
00094 
00095 //Data EE info stored in PM in following format
00096 //  Status in first two locations of PM page,
00097 //  8-bit DEE Address (odd address, low byte) 16-bit DEE data (even address)
00098 unsigned char emulationPages[DATA_EE_BANKS * NUM_DATA_EE_PAGES][NUMBER_OF_INSTRUCTIONS_IN_PAGE * 2]
00099     __attribute__ ((space(psv), aligned(NUMBER_OF_INSTRUCTIONS_IN_PAGE * 2), noload));
00100 
00101 #define DEE_BANK_SIZE (sizeof(emulationPages[0])*NUM_DATA_EE_PAGES)
00102 #define DEE_PAGE_SIZE (sizeof(emulationPages[0]))
00103 
00104 #define DEE_PAGE_TBL(bank, page) ((__builtin_tbladdress(&emulationPages) + (DEE_BANK_SIZE * (bank)) + (DEE_PAGE_SIZE * (page))) >> 16)
00105 #define DEE_PAGE_OFFSET(bank, page) ((__builtin_tbladdress(&emulationPages) + (DEE_BANK_SIZE * (bank)) + (DEE_PAGE_SIZE * (page))) & 0xFFFF)
00106 
00107 /************************************************************************
00108 UnlockWrite
00109 
00110 This routine saves the current CPU priority and sets it the highest
00111 user level of 7. It calls an assembly routine to perform an unlock
00112 sequence and sets the WR bit in NVMCON. The WR bit is polled until it
00113 clears indicating the flash operation is complete. The previous CPU
00114 priority is restored.
00115 
00116 Parameters:             None
00117 Return:                 None
00118 Side Effects:   None
00119 ************************************************************************/
00120 void UnlockWrite(void)
00121 {
00122     unsigned int sh_SR;
00123 
00124     SET_AND_SAVE_CPU_IPL(sh_SR, 7);
00125 
00126     UnlockPM();
00127 
00128     RESTORE_CPU_IPL(sh_SR);
00129 
00130     return;
00131 }
00132 
00133 /************************************************************************
00134 GetPageStatus
00135 
00136 This routine returns the page status for the selected page for the
00137 selected field. The return value is right shifted into LSb position.
00138 
00139 Parameters:             Page number, Status Field
00140 Return:                 Right justified bit value representing selected Status
00141                 Field value
00142 Side Effects:   None
00143 ************************************************************************/
00144 int GetPageStatus(unsigned char bank, unsigned char page, unsigned char field)
00145 {
00146     unsigned int statusOffset;
00147     unsigned char statusByte;
00148     unsigned char status;
00149     int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00150 
00151     savedTBLPAG = TBLPAG;
00152 
00153     // Point to proper TBLPAG and offset
00154     TBLPAG = DEE_PAGE_TBL(bank, page);
00155     statusOffset = DEE_PAGE_OFFSET(bank, page);
00156 
00157     statusByte = (ReadPMHigh(statusOffset) & 0xFF);
00158 
00159     switch(field)
00160     {
00161         case STATUS_AVAILABLE:
00162             status = ((statusByte & 4) >> 2);
00163             break;
00164         case STATUS_CURRENT:
00165             status = ((statusByte & 8) >> 3);
00166             break;
00167         case STATUS_EXPIRED:
00168             status = ((statusByte & 16) >> 4);
00169             break;
00170         default:
00171             status = 0;
00172             break;
00173     }
00174 
00175     TBLPAG = savedTBLPAG;
00176 
00177     return(status);
00178 }
00179 
00180 /************************************************************************
00181 ErasePage
00182 
00183 This routine erases the selected page.
00184 
00185 Parameters:             Page number
00186 Return:                 None
00187 Side Effects:   Loads NVCOM with erase opcode
00188 ************************************************************************/
00189 void ErasePage(unsigned char bank, unsigned char page)
00190 {
00191     unsigned int pmOffset;           //Current array (page) offset of selected element (PM 16-bit word)
00192     int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00193 
00194     savedTBLPAG = TBLPAG;
00195 
00196     // Point to proper TBLPAG and offset
00197     TBLPAG = DEE_PAGE_TBL(bank, page);
00198 
00199     NVMCON = ERASE;
00200 
00201     pmOffset = DEE_PAGE_OFFSET(bank, page);
00202 
00203     WritePMLow(pmOffset, pmOffset);
00204 
00205     UnlockWrite();
00206 
00207     TBLPAG = savedTBLPAG;
00208 
00209     return;
00210 }
00211 
00212 /************************************************************************
00213 GetNextAvailCount
00214 
00215 This routine finds the active page and performs a backward search to find
00216 the first available location. The available location is determined by
00217 reading an LSB (odd address) with 0xFF. The returned value can be added
00218 to the first address in page to compute the available address. A return
00219 value of 0 means the entire page was filled which is an error condition.
00220 This routine can be called by the user to determine how full the current
00221 page is prior to a pack.
00222 
00223 Parameters:             None
00224 Return:                 Page offset to next available location
00225 Side Effects:   None
00226 ************************************************************************/
00227 unsigned int GetNextAvailCount(unsigned char bank)
00228 {
00229     int i = 0;
00230     int currentPage;        //Array row (PM page) of active DEE page
00231     unsigned char dataEEval;
00232     unsigned int pmOffset;           //Current array (page) offset of selected element (PM 16-bit word)
00233     int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00234 
00235     savedTBLPAG = TBLPAG;
00236 
00237     // Find the active page.
00238     for (currentPage = 0;
00239          (currentPage < NUM_DATA_EE_PAGES) &&
00240          (GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_NOT_CURRENT);
00241          currentPage++) {}
00242 
00243     TBLPAG = DEE_PAGE_TBL(bank, currentPage);
00244     pmOffset = DEE_PAGE_OFFSET(bank, currentPage);
00245 
00246     do
00247     {
00248         i+=2;
00249         pmOffset += 2;
00250 
00251         dataEEval = (ReadPMHigh(pmOffset) & 0xFF);
00252     }
00253     while ((i<NUMBER_OF_INSTRUCTIONS_IN_PAGE * 2) && (dataEEval != 0xFF));
00254 
00255     if(i == NUMBER_OF_INSTRUCTIONS_IN_PAGE * 2)
00256     {
00257         i = 0;  //Error - No available locations
00258     }
00259 
00260     TBLPAG = savedTBLPAG;
00261 
00262     return(i);
00263 }
00264 
00265 /************************************************************************
00266 PackEE
00267 
00268 This routine finds the active page and an unexpired packed page. The most
00269 recent data EEPROM values are located for each address using ReadEE
00270 function and written into write latches. Page status is read from active
00271 page and erase/write count is incremented if page 0 is packed. After all
00272 information is programmed and verified, the current page is erased. The
00273 packed page becomes the active page. This function can be called at any-
00274 time by the user to schedule the CPU stall.
00275 
00276 Parameters:             None
00277 Return:                 Status value (0 for pass)
00278 Side Effects:   Generates CPU stall during program/erase operations and
00279                 overwrites program memory write latches. Data EE flags
00280                 may be updated
00281 ************************************************************************/
00282 int PackEE(unsigned char bank)
00283 {
00284     int currentPage;        //Array row (PM page) of active DEE page
00285     int packedPage;         //Array row (PM page) of packed page
00286     int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00287     int currentOffset;      //Current page offset
00288     int packedOffset;       //Packed page offset
00289     int i;
00290     unsigned char latchAddr;
00291     unsigned int latchData;
00292     unsigned char dataEEFlags_sh;
00293 
00294     savedTBLPAG = TBLPAG;
00295 
00296     // Find the active page.
00297     for (currentPage = 0;
00298          (currentPage < NUM_DATA_EE_PAGES) &&
00299          (GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_NOT_CURRENT);
00300          currentPage++) {}
00301 
00302 
00303     if (currentPage == NUM_DATA_EE_PAGES)
00304     {
00305         TBLPAG = savedTBLPAG;
00306         SetPagePackBeforeInit(1);
00307         return(3);      // Error - no active page
00308     }
00309     else
00310     {
00311         // Find the next unexpired page to use
00312         packedPage = currentPage + 1;
00313         if (packedPage == NUM_DATA_EE_PAGES)
00314         {
00315             packedPage = 0;
00316         }
00317         while(GetPageStatus(bank, packedPage, STATUS_EXPIRED) == PAGE_EXPIRED)
00318         {
00319             packedPage++;
00320             if (packedPage == NUM_DATA_EE_PAGES)
00321             {
00322                 packedPage = 0;
00323             }
00324             if(packedPage == currentPage)
00325             {
00326                 TBLPAG = savedTBLPAG;
00327                 SetPageExpiredPage(1);
00328                 return(1);      // Error - all pages expired
00329             }
00330         }
00331     }
00332 
00333     // Point to first location in packed page
00334     TBLPAG = DEE_PAGE_TBL(bank, packedPage);
00335     packedOffset = DEE_PAGE_OFFSET(bank, packedPage);
00336 
00337     if(GetNextAvailCount(bank))
00338     {
00339         SetPagePackBeforePageFull(1);           // Pack called before the page was full
00340     }
00341 
00342     dataEEFlags_sh = dataEEFlags.val;
00343     SetaddrNotFound(0);                 // Initialize flag
00344     i = 0;
00345     NVMCON = PROGRAM_ROW;
00346 
00347     WritePMLow(0xFFFF, packedOffset);
00348     WritePMHigh(0xFF, packedOffset);
00349     packedOffset += 2;
00350 
00351     latchAddr = 0;
00352     i++;
00353 
00354     do
00355     {
00356         while((latchAddr != DATA_EE_SIZE) && (i < NUMBER_OF_INSTRUCTIONS_IN_ROW))
00357         {
00358             latchData = DataEERead((255 * bank) + latchAddr);
00359             if(GetaddrNotFound())       //if address is unwritten, skip to next address
00360             {
00361                 SetaddrNotFound(0);
00362             }
00363             else
00364             {
00365                 WritePMLow(latchData, packedOffset);
00366                 WritePMHigh(latchAddr, packedOffset);
00367                 packedOffset += 2;
00368                 i++;
00369             }
00370             latchAddr++;
00371             while((latchAddr == DATA_EE_SIZE) && (i < NUMBER_OF_INSTRUCTIONS_IN_ROW))
00372             {
00373                 WritePMLow(0xFFFF, packedOffset);
00374                 WritePMHigh(0xFF, packedOffset);
00375                 packedOffset += 2;
00376                 i++;
00377             }
00378         }
00379         UnlockWrite();
00380         i = 0;
00381     }
00382     while(latchAddr != DATA_EE_SIZE);
00383 
00384     dataEEFlags.val = dataEEFlags_sh;   //Restore status flags
00385 
00386     //Verify data was written correctly into packed page
00387 
00388     // Point to first location after status
00389     TBLPAG = DEE_PAGE_TBL(bank, packedPage);
00390     packedOffset = DEE_PAGE_OFFSET(bank, packedPage) + 2;
00391 
00392     latchAddr = ReadPMHigh(packedOffset++);
00393     latchData = ReadPMLow(packedOffset++);
00394 
00395     while(latchAddr != 0xFF)
00396     {
00397         if(DataEERead((255 * bank) + latchAddr) != latchData)
00398         {
00399             TBLPAG = savedTBLPAG;
00400             SetPageWriteError(1);
00401             return(7);          //Error - data does not match
00402         }
00403        latchAddr = ReadPMHigh(packedOffset++);
00404        latchData = ReadPMLow(packedOffset++);
00405     }
00406 
00407 
00408     //Program page status
00409     currentOffset = DEE_PAGE_OFFSET(bank, currentPage);
00410     packedOffset = DEE_PAGE_OFFSET(bank, packedPage);
00411 
00412     // Point to proper TBLPAG
00413     TBLPAG = DEE_PAGE_TBL(bank, currentPage);
00414     latchData = ReadPMLow(currentOffset);
00415     latchAddr = ReadPMHigh(currentOffset);
00416     if(packedPage == 0)
00417     {
00418         latchData++;        //Increment E/W counter
00419     }
00420 
00421     if (latchData >= ERASE_WRITE_CYCLE_MAX - 1)
00422     {
00423         SetPageExpiredPage(1);
00424         latchAddr &= 0b11101111;
00425     }
00426 
00427     // Point to proper TBLPAG
00428     TBLPAG = DEE_PAGE_TBL(bank, packedPage);
00429     WritePMHigh(latchAddr, packedOffset);
00430     WritePMLow(latchData, packedOffset);
00431 
00432     NVMCON = PROGRAM_WORD;
00433     UnlockWrite();
00434 
00435     if((latchAddr != ReadPMHigh(packedOffset)) ||
00436         (latchData != ReadPMLow(packedOffset)))
00437     {
00438         TBLPAG = savedTBLPAG;
00439         SetPageWriteError(1);
00440         return(7);
00441     }
00442 
00443     //Erase active page
00444     ErasePage(bank, currentPage);
00445 
00446     TBLPAG = savedTBLPAG;
00447     return(GetPageExpiredPage());
00448 }
00449 
00450 /************************************************************************
00451 DataEEInit
00452 
00453 This routine finds an unexpired page to become an active page. It then
00454 counts the number of active pages. If no active pages are found, the
00455 first unexpired page is initialized for emulation. If one active page is
00456 found, it is assumes a reset occurred and the function does nothing. If
00457 two active pages are found, it is assumes a reset occurred during a pack.
00458 The second page is erased and a pack is called. If three, an error code
00459 is returned as the allocated memory is assumed to be corrupted. This
00460 function must be called prior to any other operation.
00461 
00462 Parameters:             None
00463 Return:                 Status value (0 for pass)
00464 Side Effects:   Data EE flags may be updated.
00465 ************************************************************************/
00466 unsigned char DataEEInit(void)
00467 {
00468     unsigned char pageCnt;
00469     unsigned char erasePage;
00470     unsigned int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00471     unsigned int currentPage;
00472     unsigned int statusOffset;
00473     int packedPage;         //Array row (PM page) of packed page
00474     unsigned char bank;
00475 
00476     savedTBLPAG = TBLPAG;
00477 
00478     // Point the table page pointer to the emulation pages
00479     TBLPAG = DEE_PAGE_TBL(0, 0);
00480 
00481     for(bank = 0; bank < DATA_EE_BANKS; bank++)
00482     {
00483         pageCnt = 0;
00484         erasePage = 0;
00485         packedPage = 0;
00486 
00487         // Find unexpired page
00488         for (currentPage = 0;
00489             (currentPage < NUM_DATA_EE_PAGES) &&
00490             (GetPageStatus(bank, currentPage, STATUS_EXPIRED) == PAGE_EXPIRED);
00491             currentPage++) {}
00492 
00493         if (currentPage == NUM_DATA_EE_PAGES)
00494         {
00495             TBLPAG = savedTBLPAG;
00496             SetPageExpiredPage(1);
00497             return(1);     // Error - All pages expired
00498         }
00499 
00500         // Count active page(s).
00501         for (currentPage = 0; currentPage < NUM_DATA_EE_PAGES; currentPage++)
00502         {
00503             if(GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_CURRENT)
00504             {
00505                 pageCnt++;
00506             }
00507         }
00508 
00509         //If no active pages found, initialize page 0
00510         if(pageCnt == 0)
00511         {
00512             ErasePage(bank, 0);
00513 
00514             // Point to proper TBLPAG and offset
00515             TBLPAG = DEE_PAGE_TBL(bank, 0);
00516             statusOffset = DEE_PAGE_OFFSET(bank, 0);
00517 
00518             NVMCON = PROGRAM_WORD;
00519 
00520             WritePMLow(0, statusOffset);    //New page: unavailable, active, reset count
00521             WritePMHigh(0xF3, statusOffset);
00522             UnlockWrite();
00523 
00524             TBLPAG = savedTBLPAG;
00525             continue;
00526         }
00527         //If one active page, do nothing
00528         else if(pageCnt == 1)
00529         {
00530             TBLPAG = savedTBLPAG;
00531             continue;
00532         }
00533         //If two active pages, erase second and repack first
00534         else if(pageCnt == 2)
00535         {
00536             if((GetPageStatus(bank, NUM_DATA_EE_PAGES - 1, STATUS_CURRENT) == PAGE_CURRENT) &&
00537                 (GetPageStatus(bank, 0, STATUS_CURRENT) == PAGE_CURRENT))
00538             {
00539                 currentPage = NUM_DATA_EE_PAGES - 1;
00540                 erasePage = 0;
00541             }
00542             else
00543             {
00544                 currentPage = 0;
00545                 while((GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_NOT_CURRENT) &&
00546                     (currentPage < NUM_DATA_EE_PAGES))
00547                 {
00548                     currentPage++;
00549                 }
00550                 erasePage = currentPage + 1;
00551                 if (erasePage == NUM_DATA_EE_PAGES)
00552                 {
00553                     erasePage = 0;
00554                 }
00555             }
00556             ErasePage(bank, erasePage);
00557 
00558             if(!GetNextAvailCount(bank))
00559             {
00560                 PackEE(bank);
00561             }
00562             TBLPAG = savedTBLPAG;
00563             continue;
00564         }
00565         else
00566         {
00567             TBLPAG = savedTBLPAG;
00568             SetPageCorruptStatus(1);
00569             return(6);
00570         }
00571     }
00572     return(0);
00573 }
00574 
00575 /************************************************************************
00576 DataEERead
00577 
00578 This routine verifies the address is valid. If not, the Illegal Address
00579 flag is set and 0xFFFF is returned. It then finds the active page. If an
00580 active page can not be found, the Page Corrupt status bit is set and
00581 0xFFFF is returned. A reverse search of the active page attempts to find
00582 the matching address in the program memory MSB (odd address). If a match
00583 is found, the corresponding data EEPROM data (even address) is returned,
00584 otherwise 0xFFFF is returned. This function can be called by the user.
00585 
00586 Parameters:             Data EE address
00587 Return:                 Data EE data or 0xFFFF if address not found
00588 Side Effects:   Data EE flags may be updated.
00589 ************************************************************************/
00590 unsigned int DataEERead(unsigned int addr)
00591 {
00592     unsigned int savedTBLPAG; // Context save of TBLPAG value. Current 
00593                                                   // and packed page are on same page.
00594     unsigned int currentPage;
00595     unsigned int pmOffset;   // Current array (page) offset of selected 
00596                                                  // element (PM 16-bit word)
00597     unsigned int latch;
00598     unsigned int i;
00599     unsigned char bank;
00600 
00601     if(addr >= DATA_EE_TOTAL_SIZE)
00602     {
00603         SetPageIllegalAddress(1);
00604         return(0xFFFF);
00605     }
00606 
00607     bank = addr / DATA_EE_SIZE;
00608 
00609     savedTBLPAG = TBLPAG;
00610 
00611     // Find the active page.
00612     for (currentPage = 0;
00613          (currentPage < NUM_DATA_EE_PAGES) &&
00614          (GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_NOT_CURRENT);
00615          currentPage++) {}
00616 
00617     if (currentPage == NUM_DATA_EE_PAGES)
00618     {
00619         TBLPAG = savedTBLPAG;
00620         SetPageCorruptStatus(1);
00621         return(0xFFFF);     // Error - no active page
00622     }
00623 
00624     // Point to proper TBLPAG and offset
00625     TBLPAG = DEE_PAGE_TBL(bank, currentPage);
00626     pmOffset = DEE_PAGE_OFFSET(bank, (currentPage + 1)) - 2;
00627 
00628     i=NUMBER_OF_INSTRUCTIONS_IN_PAGE;
00629 
00630     do
00631     {
00632         latch = ReadPMHigh(pmOffset);
00633         pmOffset -= 2;
00634 
00635         i--;
00636     }
00637     while((i > 0) && (latch != (addr % DATA_EE_SIZE)));
00638 
00639     if(!i)
00640     {
00641         SetaddrNotFound(1);
00642         TBLPAG = savedTBLPAG;
00643         return(0xFFFF);
00644     }
00645 
00646     pmOffset += 2;
00647     latch = ReadPMLow(pmOffset);
00648 
00649     TBLPAG = savedTBLPAG;
00650     return(latch);
00651 }
00652 
00653 /************************************************************************
00654 DataEEWrite
00655 
00656 This routine verifies the address is valid. If not, the Illegal Address
00657 flag is set and an error code is returned. It then finds the active page.
00658 If an active page can not be found, the Page Corrupt status bit is set
00659 and an error code is returned. A read is performed, if the data was not
00660 changed, the function exits. If the last location is programmed, the Pack
00661 Skipped error flag is set (one location should always be available). The
00662 data EE information (MSB = address, LSW = data) is programmed and
00663 verified. If the verify fails, the Write Error flag is set. If the write
00664 went into the last location of the page, pack is called. This function
00665 can be called by the user.
00666 
00667 Parameters:             Data EE address and data
00668 Return:                 Pass or fail status (0 = Pass)
00669 Side Effects:   Data EE flags may be updated. CPU stall occurs for flash
00670                 programming. Pack may be generated.
00671 ************************************************************************/
00672 unsigned char DataEEWrite(unsigned int data, unsigned int addr)
00673 {
00674     int savedTBLPAG;        //Context save of TBLPAG value. Current and packed page are on same page.
00675     int currentPage;
00676     int pmOffset;           //Current array (page) offset of selected element (PM 16-bit word)
00677     unsigned int nextLoc;
00678     volatile unsigned char latch;
00679     unsigned char dataEEFlags_sh;
00680     unsigned int bank;
00681 
00682     if(addr >= DATA_EE_TOTAL_SIZE)
00683     {
00684         SetPageIllegalAddress(1);
00685         return(5);
00686     }
00687 
00688     bank = addr / DATA_EE_SIZE;
00689 
00690     savedTBLPAG = TBLPAG;
00691     NVMCON = PROGRAM_WORD;
00692 
00693     // Find the active page.
00694     for (currentPage = 0;
00695          (currentPage < NUM_DATA_EE_PAGES) &&
00696          (GetPageStatus(bank, currentPage, STATUS_CURRENT) == PAGE_NOT_CURRENT);
00697          currentPage++) {}
00698 
00699     if (currentPage == NUM_DATA_EE_PAGES)
00700     {
00701         TBLPAG = savedTBLPAG;
00702         SetPageCorruptStatus(1);
00703         return(6);      // Error - no active page
00704     }
00705 
00706     // Point to proper TBLPAG and offset
00707     TBLPAG = DEE_PAGE_TBL(bank, currentPage);
00708     pmOffset = DEE_PAGE_OFFSET(bank, currentPage);
00709 
00710     dataEEFlags_sh = dataEEFlags.val;
00711 
00712     //Do not write data if it did not change
00713     if(DataEERead(addr) == data)
00714     {
00715         TBLPAG = savedTBLPAG;
00716         dataEEFlags.val = dataEEFlags_sh;
00717         return(0);
00718     }
00719 
00720     dataEEFlags.val = dataEEFlags_sh;       //Restore status flags
00721     nextLoc = GetNextAvailCount(bank);
00722 
00723     if(!nextLoc)
00724     {
00725         TBLPAG = savedTBLPAG;
00726         SetPagePackSkipped(1);
00727         return(4);  //Error - Number of writes exceeds page size
00728     }
00729 
00730     pmOffset = pmOffset + nextLoc;
00731 
00732     WritePMLow(data, pmOffset);
00733     WritePMHigh((addr % DATA_EE_SIZE), pmOffset);
00734 
00735     UnlockWrite();
00736 
00737     Nop();
00738     Nop();
00739 
00740     latch = (ReadPMLow(pmOffset) & 0xFF);
00741 
00742     if(latch != (data & 0xFF))
00743     {
00744         TBLPAG = savedTBLPAG;
00745         SetPageWriteError(1);
00746         return(7);  //Error - RAM does not match PM
00747     }
00748 
00749     latch = (ReadPMHigh(pmOffset) & 0xFF);
00750 
00751     if(latch != (addr % DATA_EE_SIZE))
00752     {
00753         TBLPAG = savedTBLPAG;
00754         SetPageWriteError(1);
00755         return(7);  //Error - RAM does not match PM
00756     }
00757 
00758     pmOffset += 1;
00759     latch = ((ReadPMLow(pmOffset) >> 8) & 0xFF);
00760 
00761     if(latch != ((data >> 8) & 0xFF))
00762     {
00763         TBLPAG = savedTBLPAG;
00764         SetPageWriteError(1);
00765         return(7);  //Error - RAM does not match PM
00766     }
00767 
00768     //Pack if page is full
00769     if ((nextLoc + 2) == ((NUMBER_OF_INSTRUCTIONS_IN_PAGE) * 2))
00770     {
00771         PackEE(bank);
00772     }
00773 
00774     TBLPAG = savedTBLPAG;
00775 
00776     return(0);
00777 }
 All Data Structures Files Functions Variables Defines