dsPid33
|
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 }