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 }