Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

at91flash.c

Go to the documentation of this file.
00001 /*! \file at91flash.c \brief Internal FLASH Write Routines for Atmel AT91. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'at91flash.c'
00005 // Title        : Internal FLASH Write Routines for Atmel AT91
00006 // Author       : Pascal Stang - Copyright (C) 2006
00007 // Created      : 9/20/2006
00008 // Revised      : 9/25/2006
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AT91 series
00011 // Editor Tabs  : 4
00012 //
00013 // This code is distributed under the GNU Public License
00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00015 //
00016 //*****************************************************************************
00017 
00018 // system includes
00019 #include "global.h"
00020 #include "at91sam7s256.h"
00021 
00022 // local includes
00023 #include "at91flash.h"
00024 
00025 void at91flashInit(void)
00026 {
00027     // set cycles-per-microsecond
00028     //  as per datasheet,
00029     //  - NVM bits require a setting of F_CPU/1000
00030     //  - general flash write requires a setting of 1.5*F_CPU/1000
00031     // (here we're extra conservative setting clock cycles equal to 2us)
00032     AT91C_BASE_MC->MC_FMR = (((F_CPU*2/1000)<<16) & AT91C_MC_FMCN);
00033 }
00034 
00035 void at91flashWrite(uint32_t flashaddr, uint8_t* buffer, uint32_t len)
00036 {
00037     int wrlen;
00038 
00039     // do automatic multi-page writes
00040     while(len)
00041     {
00042         // determine how many bytes to write
00043         wrlen = (len<AT91C_IFLASH_PAGE_SIZE)?(len):(AT91C_IFLASH_PAGE_SIZE);
00044         // write page
00045         at91flashWritePage(flashaddr, buffer, wrlen);
00046         // increment pointers
00047         flashaddr += wrlen;
00048         buffer += wrlen;
00049         // decrement remaining buffer size
00050         len -= wrlen;
00051     }
00052 }
00053 
00054 void at91flashWritePage(uint32_t flashaddr, uint8_t* buffer, uint32_t len)
00055 {
00056     int pageword;
00057     unsigned long* wrptr = (unsigned long*)flashaddr;
00058     
00059     // do write cycle
00060     // copy data to flash location
00061     for(pageword=0; pageword<(len/4); pageword++)
00062     {
00063         // do the copy byte-wise because incoming buffer might not be word-aligned
00064         // NOTE: assuming little-endian source
00065         *wrptr++ = (buffer[3]<<24) | (buffer[2]<<16) | (buffer[1]<<8) | (buffer[0]<<0);
00066         buffer+=4;
00067     }
00068     // if the flash address does not begin on page boundary, then we do partial-page programming
00069     if( flashaddr & (AT91C_IFLASH_PAGE_SIZE-1) )
00070         AT91C_BASE_MC->MC_FMR |= AT91C_MC_NEBP;
00071     else
00072         AT91C_BASE_MC->MC_FMR &= ~AT91C_MC_NEBP;
00073     // write flash
00074     AT91C_BASE_MC->MC_FCR = (0x5A<<24) | (((flashaddr/AT91C_IFLASH_PAGE_SIZE)<<8)&AT91C_MC_PAGEN) | AT91C_MC_FCMD_START_PROG;
00075     // wait for flash done/ready
00076     while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY));
00077 }
00078 
00079 void at91flashErase(void)
00080 {
00081     // erase flash
00082     AT91C_BASE_MC->MC_FCR = (0x5A<<24) | AT91C_MC_FCMD_ERASE_ALL;
00083     // wait for flash done/ready
00084     while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY));
00085 }
00086 
00087 int at91flashGetLock(uint32_t flashaddr)
00088 {
00089     // mask flashaddr to size of flash
00090     flashaddr &= (AT91C_IFLASH_SIZE-1);
00091     // determine the lock state of a flash address/page
00092     if( AT91C_BASE_MC->MC_FSR & (1<<(16+(flashaddr/AT91C_IFLASH_LOCK_REGION_SIZE))) )
00093         return 1;   // region is locked
00094     else
00095         return 0;   // region is not locked
00096 }
00097 
00098 void at91flashSetLock(uint32_t flashaddr, int lockstate)
00099 {
00100     // set the lock state of a flash address/page
00101     
00102     // mask flashaddr to size of flash
00103     flashaddr &= (AT91C_IFLASH_SIZE-1);
00104     // since lock bits have a small lifetime (100 programming cycles),
00105     // check to see if lock bit is already set to requested state
00106     if( at91flashGetLock(flashaddr) == lockstate)
00107         return;     // lock bit is already set as desired
00108     // program the lock bit
00109     if(lockstate)
00110         AT91C_BASE_MC->MC_FCR = (0x5A<<24) | (((flashaddr/AT91C_IFLASH_PAGE_SIZE)<<8)&AT91C_MC_PAGEN) | AT91C_MC_FCMD_LOCK;
00111     else
00112         AT91C_BASE_MC->MC_FCR = (0x5A<<24) | (((flashaddr/AT91C_IFLASH_PAGE_SIZE)<<8)&AT91C_MC_PAGEN) | AT91C_MC_FCMD_UNLOCK;
00113     // wait for flash done/ready
00114     while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY));
00115 }

Generated on Mon Nov 6 23:36:58 2006 for Procyon ARMlib by  doxygen 1.4.2