#include "inc/freeEMS.h"
#include "inc/flashWrite.h"
#include "inc/flashBurn.h"
#include "inc/commsISRs.h"
#include "inc/commsCore.h"
#include <string.h>
Go to the source code of this file.
Defines | |
#define | FLASHWRITE_C |
Functions | |
unsigned short | eraseSector (unsigned char PPage, unsigned short *flashAddr) |
Erases a sector of flash memory. | |
unsigned short | writeBlock (blockDetails *details, void *buffer) |
Writes a block of memory to flash. | |
unsigned short | writeSector (unsigned char RPage, unsigned short *RAMSourceAddress, unsigned char PPage, unsigned short *flashDestinationAddress) |
Writes a sector from memory to a sector in flash. | |
unsigned short | writeWord (unsigned short *flashDestination, unsigned short data) |
Program Command. |
This file contains all functions that operate directly or indirectly and only on flash memory. They are used for erasing data from and reprogramming data to the embedded flash non-volatile storage area.
Definition in file flashWrite.c.
#define FLASHWRITE_C |
Definition at line 38 of file flashWrite.c.
unsigned short eraseSector | ( | unsigned char | PPage, | |
unsigned short * | flashAddr | |||
) |
Erases a sector of flash memory.
This will erase a 1k sector in flash. Write 0xFFFF to the starting sector to be erased, 0xFFFF will be written regardless. Register the flash sector erase command(0x40) and call StackBurner();. If you try to erase a protected sector you will get PVIOL in the FSTAT register.
PPage | the flash page the sector is in | |
flashAddr | the start address of the sector |
Definition at line 63 of file flashWrite.c.
References ACCERR, addressNotSectorAligned, FCMD, flashSectorSize, FSTAT, PPAGE, PVIOL, SECTOR_ERASE, and StackBurner().
Referenced by decodePacketAndRespond(), and writeSector().
00063 { 00064 00065 if (((unsigned short)flashAddr % flashSectorSize) != 0){ 00066 return addressNotSectorAligned; 00067 } 00068 unsigned char currentPage = PPAGE; 00069 PPAGE = PPage; 00070 FSTAT = (PVIOL|ACCERR); /* clear any errors */ 00071 (*flashAddr) = 0xFFFF; /* Dummy data to first word of page to be erased it will write FFFF regardless with the erase command*/ 00072 PPAGE = currentPage; 00073 FCMD = SECTOR_ERASE; /* set the flash command register mode to ERASE */ 00074 StackBurner(); //PPAGE loaded into Register B, PPAGE is set with Reg B in StackBurn asm file 00075 //TODO add return for accerr and pviol error bits 00076 00077 return 0; 00078 }
unsigned short writeBlock | ( | blockDetails * | details, | |
void * | buffer | |||
) |
Writes a block of memory to flash.
The block size must either be under 1024, or an exact multiple of 1024. Additionally, if under 1024 the destination should be within a single flash sector, and if a multiple of 1024, the destination should be sector aligned.
Because the ram version will be in an arbitrary place we need to base our positioning from the flash location. Firstly we need to ensure that it doesn't cross any sector boundaries. Then we need to find the address of the sector to be burned to. We also need to determine if there are 2 or 3 chunks of memory to be copied to the buffer, three cases exist for that :
| From Flash | From RAM | From flash | | From Flash | From RAM | | From RAM | From Flash |
details | contains the RAM address and page to be read from, the flash address and page to be burned to and the size to be read. | |
buffer | is a pointer to a block of RAM at least 1024 bytes long used to allow small chunks to be burned independently. |
Definition at line 107 of file flashWrite.c.
References blockDetails::FlashAddress, blockDetails::FlashPage, flashSectorSize, flashSectorSizeInWords, PPAGE, blockDetails::RAMAddress, blockDetails::RAMPage, RPAGE, blockDetails::size, sizeNotMultipleOfSectorSize, sizeOfBlockToBurnIsZero, smallBlockCrossesSectorBoundary, and writeSector().
Referenced by decodePacketAndRespond().
00107 { 00108 unsigned char sectors; 00109 unsigned char RAMPage; 00110 /* FlashPage is always the one provided and is just used as is. */ 00111 unsigned short* RAMAddress; 00112 unsigned short* FlashAddress; 00113 00114 /* Check that the size isn't zero... */ 00115 if(details->size == 0){ 00116 return sizeOfBlockToBurnIsZero; 00117 }else if(details->size < 1024){ 00118 unsigned short chunkFlashAddress = (unsigned short)details->FlashAddress; 00119 /* Get the offset from the start of the sector */ 00120 unsigned short offset = chunkFlashAddress % flashSectorSize; 00121 00122 /* Check for flash sector boundary crossing */ 00123 if((offset + details->size) > 1024){ 00124 return smallBlockCrossesSectorBoundary; 00125 } 00126 00127 /* Configure the final burn variables */ 00128 sectors = 1; /* By definition if we are in this code there is only one */ 00129 RAMPage = RPAGE; /* The buffer is always in linear RAM region */ 00130 RAMAddress = buffer; /* Save the buffer start address */ 00131 FlashAddress = (unsigned short*)(chunkFlashAddress - offset); /* Get the start of the flash sector */ 00132 00133 /* Possibly three parts to copy to the buffer, copy only what is required */ 00134 00135 /* Save the PPAGE value and set the flash page */ 00136 unsigned char oldFlashPage = PPAGE; 00137 PPAGE = details->FlashPage; 00138 00139 /* If the chunk doesn't start at the beginning of the sector, copy the first area from flash */ 00140 if(offset != 0){ 00141 memcpy(buffer, FlashAddress, offset); 00142 buffer += offset; 00143 } 00144 00145 /* Copy the middle section up regardless */ 00146 unsigned char oldRAMPage = RPAGE; 00147 RPAGE = details->RAMPage; 00148 memcpy(buffer, details->RAMAddress, details->size); 00149 buffer += details->size; 00150 RPAGE = oldRAMPage; 00151 00152 /* If the chunk doesn't end at the end of the sector, copy the last are from flash */ 00153 if((offset + details->size) < 1024){ 00154 void* chunkFlashEndAddress = details->FlashAddress + details->size; 00155 memcpy(buffer, chunkFlashEndAddress, (1024 - (offset + details->size))); 00156 } 00157 00158 /* Restore the PPAGE value back */ 00159 PPAGE = oldFlashPage; 00160 } else { 00161 /* If not smaller than 1024, check size is product of sector size */ 00162 if((details->size % flashSectorSize) != 0){ 00163 return sizeNotMultipleOfSectorSize; 00164 } 00165 00166 /* Set the variables to what they would have been before */ 00167 sectors = details->size / flashSectorSize; 00168 RAMPage = details->RAMPage; 00169 RAMAddress = (unsigned short*)details->RAMAddress; 00170 FlashAddress = (unsigned short*)details->FlashAddress; 00171 } 00172 00173 unsigned char i; 00174 for(i=0;i<sectors;i++){ 00175 unsigned short errorID = writeSector(RAMPage, RAMAddress, details->FlashPage, FlashAddress); 00176 if(errorID != 0){ 00177 return errorID; 00178 } 00179 /* Incrementing a pointer is done by blocks the size of the type, hence 512 per sector here */ 00180 RAMAddress += flashSectorSizeInWords; 00181 FlashAddress += flashSectorSizeInWords; 00182 } 00183 return 0; 00184 }
unsigned short writeSector | ( | unsigned char | RPage, | |
unsigned short * | RAMSourceAddress, | |||
unsigned char | PPage, | |||
unsigned short * | flashDestinationAddress | |||
) |
Writes a sector from memory to a sector in flash.
Uses writeWord to write a 1k block from sourceAddress(RAM) to flashDestinationAddress, one word at a time. Give it the starting memory address and the destination flash address. Both addresses will be incremented by 1 word after a successful writeWord, until the whole 1024 byte sector has been written. Before any writing occurs eraseSector is called to make sure the destination is blank.
RPage | the page of RAM the RAMSourceAddress is located | |
RAMSourceAddress | the address of the source data | |
PPage | the page of flash where your flashDestinationAddress is located | |
flashDestinationAddress | where your data will be written to in flash |
Definition at line 205 of file flashWrite.c.
References addressNotFlashRegion, addressNotSectorAligned, eraseSector(), flashSectorSize, flashSectorSizeInWords, PPAGE, RPAGE, and writeWord().
Referenced by decodePacketAndRespond(), and writeBlock().
00205 { 00206 00207 if(((unsigned short)flashDestinationAddress % flashSectorSize) != 0){ 00208 return addressNotSectorAligned; 00209 } 00210 00211 if(((unsigned short)flashDestinationAddress) < 0x4000){ 00212 return addressNotFlashRegion; 00213 } 00214 00216 eraseSector((unsigned char)PPage, (unsigned short*)flashDestinationAddress); /* First Erase our destination block */ 00217 00218 unsigned short wordCount = flashSectorSizeInWords; 00219 00220 /* Save pages */ 00221 unsigned char currentRPage = RPAGE; 00222 unsigned char currentPPage = PPAGE; 00223 00224 /* Switch pages */ 00225 RPAGE = RPage; 00226 PPAGE = PPage; 00227 00228 while (wordCount > 0) 00229 { 00230 unsigned short sourceData = *RAMSourceAddress; /*Convert the RAMAddr to data(dereference) */ 00231 unsigned short errorID = writeWord(flashDestinationAddress, sourceData); 00232 if(errorID != 0){ 00233 return errorID; 00234 } 00235 RAMSourceAddress++; 00236 flashDestinationAddress++; 00237 wordCount--; /* Decrement our word counter */ 00238 } 00239 00240 /* Restore pages */ 00241 RPAGE = currentRPage; 00242 PPAGE = currentPPage; 00243 return 0; 00244 }
unsigned short writeWord | ( | unsigned short * | flashDestination, | |
unsigned short | data | |||
) |
Program Command.
This will write 1 word to an empty(0xFFFF) flash address. If you try to write to an address containing data(not 0xFFFF),an error will register at FSTAT. The embedded algorithm works like this, just write to the desired flash address as you would any other writable address. Then register the program command(0x20) at FCDM, the rest is handled by StackBurner();
flashDestination | where you want to write your data | |
data | the data you are going to write |
Definition at line 264 of file flashWrite.c.
References ACCERR, addressNotWordAligned, FCMD, FSTAT, PVIOL, StackBurner(), and WORD_PROGRAM.
Referenced by writeSector().
00264 { 00265 if((unsigned short)flashDestination & 0x0001){ 00266 return addressNotWordAligned; 00267 } 00268 00269 FSTAT=(ACCERR | PVIOL); 00270 *flashDestination = data; 00271 FCMD = WORD_PROGRAM; //Load Flash Command Register With Word_Program mask 00272 StackBurner(); 00273 00274 return 0; 00275 }