00001 /* flashWrite.c 00002 00003 Copyright 2008 Sean Keys 00004 00005 This file is part of the FreeEMS project. 00006 00007 FreeEMS software is free software: you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation, either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 FreeEMS software is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with any FreeEMS software. If not, see <http://www.gnu.org/licenses/>. 00019 00020 We ask that if you make any changes to this file you send them upstream to us at admin@diyefi.org 00021 00022 Thank you for choosing FreeEMS to run your engine! */ 00023 00024 #define FLASHWRITE_C 00025 #include "inc/freeEMS.h" 00026 #include "inc/flashWrite.h" 00027 #include "inc/flashBurn.h" 00028 #include "inc/commsISRs.h" 00029 00030 00031 00032 00033 /**************************************************************************************************************/ 00034 /* 27.4.2.4 Sector Erase Command 00035 00036 The sector erase operation will erase all addresses in a 1 Kbyte sector of Flash memory using an embedded 00037 algorithm. 00038 00039 An example flow to execute the sector erase operation is shown in Figure 27-29. The sector erase 00040 command write sequence is as follows: 00041 00042 1. Write to a Flash block address to start the command write sequence for the sector erase command. 00043 The Flash address written determines the sector to be erased while global address bits [9:0] and the 00044 data written are ignored. Multiple Flash sectors can be simultaneously erased by writing to the 00045 same relative address in each Flash block. 00046 00047 2. Write the sector erase command, 0x40, to the FCMD register. 00048 00049 3. Clear the CBEIF flag in the FSTAT register by writing a 1 to CBEIF to launch the sector erase 00050 command. 00051 00052 If a Flash sector to be erased is in a protected area of the Flash block, the PVIOL flag in the FSTAT register 00053 will set and the sector erase command will not launch. Once the sector erase command has successfully 00054 launched, the CCIF flag in the FSTAT register will set after the sector erase operation has completed unless 00055 a new command write sequence has been buffered. */ 00056 unsigned short eraseSector(unsigned char PPage, unsigned short *flashAddr){ 00057 00058 if (((unsigned short)flashAddr % flashSectorSize) != 0){ 00059 return addressNotSectorAligned; 00060 } 00061 unsigned char currentPage = PPAGE; 00062 PPAGE = PPage; 00063 FSTAT = (PVIOL|ACCERR); /* clear any errors */ 00064 (*flashAddr) = 0xFFFF; /* Dummy data to first word of page to be erased it will write FFFF regardless with the erase command*/ 00065 PPAGE = currentPage; 00066 FCMD = SECTOR_ERASE; /* set the flash command register mode to ERASE */ 00067 StackBurner(); //PPAGE loaded into Register B, PPAGE is set with Reg B in StackBurn asm file 00068 //TODO add return for accerr and pviol error bits 00069 00070 return 0; 00071 } 00072 00073 00074 /* TODO for 0.0.19 00075 * 00076 * To be called from replace block of flash and ram to flash serial functions : 00077 * 00078 * create some sort of function to copy the flash sector up into 00079 * the serial rx buffer in the high end and then over write with 00080 * the small piece defined either from incoming data, or from its 00081 * memory location. Then just call burn in the normal way. 00082 * 00083 * function could take : 00084 * pointer to the buffer region (must be 1024 long or more) 00085 * rpage, address, length of data to be persisted 00086 * ppage, address of the sector to retrieve the rest of the data from 00087 * pointer to the details object we want to use for the following call : 00088 */ 00089 00090 00091 /* Pass in anything you like and it will error if it can't handle it. */ 00092 /* Note : Limited to 63k per write!! (obviously) */ 00093 /* TODO buffer, copy and do smaller regions by supplementing with data read from the block in question. TODO see above ^ */ 00094 unsigned short writeBlock(unsigned char RPage, unsigned short* RAMSourceAddress, unsigned char PPage, unsigned short* flashDestinationAddr, unsigned short size){ 00095 00096 if(((size % flashSectorSize) != 0) || (size == 0)){ 00097 return sizeNotMultipleOfSectorSize; 00098 } 00099 00100 unsigned char sectors = size / flashSectorSize; 00101 unsigned char i; 00102 for(i=0;i<sectors;i++){ 00103 unsigned short errorID = writeSector(RPage, RAMSourceAddress, PPage, flashDestinationAddr); 00104 if(errorID != 0){ 00105 return errorID; 00106 } 00107 /* Incrementing a pointer is done by blocks the size of the type, hence 512 per sector here */ 00108 flashDestinationAddr += flashSectorSizeInWords; 00109 RAMSourceAddress += flashSectorSizeInWords; 00110 } 00111 return 0; 00112 } 00113 00114 /******************************************************************************* 00115 * writeSector will use writeWord to write a 1k block from sourceAddress(RAM) to flashDestinationAddress. 00116 * Give it the starting memory address and the destination flash address. 00117 * Both addresses will be incremented by 1 word after a successful writeWord, 00118 * until the whole 1024 byte sector has been written. Before any writing occurs 00119 * eraseSector is called to make sure the destination is blank. */ 00120 unsigned short writeSector(unsigned char RPage, unsigned short* RAMSourceAddress, unsigned char PPage , unsigned short* flashDestinationAddress){ 00121 00122 if (((unsigned short)flashDestinationAddress % flashSectorSize) != 0){ 00123 return addressNotSectorAligned; 00124 } 00125 00126 if(((unsigned short)flashDestinationAddress) < 0x4000){ 00127 return addressNotFlashRegion; 00128 } 00129 00130 //TODO Decide if we need to disable interrupts since we are manually setting Flash/RAM pages. 00131 eraseSector((unsigned char)PPage, (unsigned short*)flashDestinationAddress); /* First Erase our destination block */ 00132 00133 unsigned short wordCount = flashSectorSizeInWords; 00134 00135 /* Save pages */ 00136 unsigned char currentRPage = RPAGE; 00137 unsigned char currentPPage = PPAGE; 00138 00139 /* Switch pages */ 00140 RPAGE = RPage; 00141 PPAGE = PPage; 00142 00143 while (wordCount > 0) 00144 { 00145 unsigned short sourceData = *RAMSourceAddress; /*Convert the RAMAddr to data(dereference) */ 00146 unsigned short errorID = writeWord(flashDestinationAddress, sourceData); 00147 if(errorID != 0){ 00148 return errorID; 00149 } 00150 RAMSourceAddress++; 00151 flashDestinationAddress++; 00152 wordCount--; /* Decrement our word counter */ 00153 } 00154 00155 /* Restore pages */ 00156 RPAGE = currentRPage; 00157 PPAGE = currentPPage; 00158 return 0; 00159 } 00160 /* 27.4.2.3 Program Command 00161 00162 The program operation will program a previously erased word in the Flash memory using an embedded 00163 algorithm. 00164 00165 An example flow to execute the program operation is shown in Figure 27-28. The program command write 00166 sequence is as follows: 00167 00168 1. Write to a Flash block address to start the command write sequence for the program command. The 00169 data written will be programmed to the address written. Multiple Flash blocks can be 00170 simultaneously programmed by writing to the same relative address in each Flash block. 00171 00172 2. Write the program command, 0x20, to the FCMD register. 00173 00174 3. Clear the CBEIF flag in the FSTAT register by writing a 1 to CBEIF to launch the program 00175 command. 00176 00177 If a word to be programmed is in a protected area of the Flash block, the PVIOL flag in the FSTAT register 00178 will set and the program command will not launch. Once the program command has successfully launched, 00179 the CCIF flag in the FSTAT register will set after the program operation has completed unless a new 00180 command write sequence has been buffered. By executing a new program command write sequence on 00181 sequential words after the CBEIF flag in the FSTAT register has been set, up to 55% faster programming 00182 time per word can be effectively achieved than by waiting for the CCIF flag to set after each program 00183 operation.*/ 00184 unsigned short writeWord(unsigned short* flashDestination, unsigned short data){ 00185 if ((unsigned short)flashDestination & 0x0001){ 00186 return addressNotWordAligned; 00187 } 00188 00189 FSTAT=(ACCERR | PVIOL); 00190 *flashDestination = data; 00191 FCMD = WORD_PROGRAM; //Load Flash Command Register With Word_Program mask 00192 StackBurner(); 00193 00194 return 0; 00195 }