//------------------------------------------------------------------------------ /// Unlocks all the regions in the given address range. The actual unlock range is /// reported through two output parameters. /// Returns 0 if successful; otherwise returns an error code. /// \param start Start address of unlock range. /// \param end End address of unlock range. /// \param pActualStart Start address of the actual unlock range (optional). /// \param pActualEnd End address of the actual unlock range (optional). //------------------------------------------------------------------------------ unsigned char FLASHD_Unlock( unsigned int start, unsigned int end, unsigned int *pActualStart, unsigned int *pActualEnd) { AT91S_EFC *pStartEfc, *pEndEfc, *pEfc; unsigned int actualStart, actualEnd; unsigned short startPage, endPage; unsigned char error; unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE; // Compute actual unlock range and store it ComputeLockRange(start, end, &actualStart, &actualEnd); if (pActualStart) { *pActualStart = actualStart; } if (pActualEnd) { *pActualEnd = actualEnd; } // Compute page numbers EFC_TranslateAddress(&pStartEfc, actualStart, &startPage, 0); EFC_TranslateAddress(&pEndEfc, actualEnd, &endPage, 0); // Unlock all pages // If there is an EFC crossover, unlock all pages from first EFC #if defined(AT91C_BASE_EFC1) if (pStartEfc != pEndEfc) { while (startPage < (AT91C_IFLASH_NB_OF_PAGES / 2)) { error = EFC_PerformCommand(pStartEfc, AT91C_MC_FCMD_UNLOCK, startPage); if (error) { return error; } startPage += numPagesInRegion; } startPage = 0; } #endif pEfc = pEndEfc; // Unlock remaining pages while (startPage < endPage) { error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_UNLOCK, startPage); if (error) { return error; } startPage += numPagesInRegion; } return 0; }
//------------------------------------------------------------------------------ /// Erases the entire flash. /// Returns 0 if successful; otherwise returns an error code. //------------------------------------------------------------------------------ unsigned char FLASHD_Erase(void) { unsigned char error; error = EFC_PerformCommand(AT91C_BASE_EFC0, AT91C_MC_FCMD_ERASE_ALL, 0); #ifdef AT91C_BASE_EFC1 if (error) { return error; } error = EFC_PerformCommand(AT91C_BASE_EFC1, AT91C_MC_FCMD_ERASE_ALL, 0); #endif return error; }
/** * \brief Read the unique ID. * * \param uniqueID pointer on a 4bytes char containing the unique ID value. * \returns 0 if successful; otherwise returns an error code. */ extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) { uint32_t dwError ; assert( pdwUniqueID != NULL ) ; pdwUniqueID[0] = 0 ; pdwUniqueID[1] = 0 ; pdwUniqueID[2] = 0 ; pdwUniqueID[3] = 0 ; EFC_StartCommand( EFC, EFC_FCMD_STUI, 0 ) ; pdwUniqueID[0] = *(uint32_t*) IFLASH_ADDR; pdwUniqueID[1] = *(uint32_t*)(IFLASH_ADDR + 4) ; pdwUniqueID[2] = *(uint32_t*)(IFLASH_ADDR + 8) ; pdwUniqueID[3] = *(uint32_t*)(IFLASH_ADDR + 12) ; dwError = EFC_PerformCommand( EFC, EFC_FCMD_SPUI, 0, _dwUseIAP ) ; if ( dwError ) { return dwError ; } return 0 ; }
/** * \brief Unlocks all the regions in the given address range. The actual unlock range is * reported through two output parameters. * \param start Start address of unlock range. * \param end End address of unlock range. * \param pActualStart Start address of the actual unlock range (optional). * \param pActualEnd End address of the actual unlock range (optional). * \return 0 if successful, otherwise returns an error code. */ extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd ) { Efc* pEfc ; uint32_t actualStart, actualEnd ; uint16_t startPage, endPage ; uint32_t dwError ; uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; /* Compute actual unlock range and store it */ ComputeLockRange(start, end, &actualStart, &actualEnd); if ( pActualStart != NULL ) { *pActualStart = actualStart ; } if ( pActualEnd != NULL ) { *pActualEnd = actualEnd ; } /* Compute page numbers */ EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ; EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ; /* Unlock all pages */ while ( startPage < endPage ) { dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ; if ( dwError ) { return dwError ; } startPage += numPagesInRegion ; } return 0 ; }
//------------------------------------------------------------------------------ /// Erases the entire flash. /// Returns 0 if successful; otherwise returns an error code. //------------------------------------------------------------------------------ unsigned char FLASHD_Erase(unsigned int address) { AT91S_EFC *pEfc; unsigned short page; unsigned short offset; unsigned char error; #ifdef AT91C_BASE_EFC1 // Convert wrapped address to physical address. address &= 0x19FFFF; SANITY_CHECK((address >=AT91C_IFLASH) || (address >=AT91C_IFLASH1)); // Check EFC crossover 2 bank if (address >=AT91C_IFLASH1) { SANITY_CHECK(address <= (AT91C_IFLASH1 + AT91C_IFLASH1_SIZE)); } else { SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE)); } #else SANITY_CHECK((address >=AT91C_IFLASH) || (address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE))); #endif // Translate write address EFC_TranslateAddress(&pEfc, address, &page, &offset); error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_EA, 0); return error; }
//------------------------------------------------------------------------------ /// Erases the entire flash. /// Returns 0 if successful; otherwise returns an error code. //------------------------------------------------------------------------------ unsigned char FLASHD_Erase(void) { unsigned char error; error = EFC_PerformCommand(AT91C_EFC_FCMD_EA, 0); return error; }
//------------------------------------------------------------------------------ /// Set Security Bit Command (SSB). /// Returns 0 if successful; otherwise returns an error code. //------------------------------------------------------------------------------ unsigned char FLASHD_SetSecurityBit(void) { AT91S_EFC *pEfc = AT91C_BASE_EFC0; if( FLASHD_IsSecurityBitSet() == 0) { return EFC_PerformCommand(pEfc, AT91C_MC_FCMD_SET_SECURITY, 0); } else { return 0; } }
//------------------------------------------------------------------------------ /// Returns the number of locked regions inside the given address range. /// \param start Start address of range. /// \param end End address of range. //------------------------------------------------------------------------------ unsigned char FLASHD_IsLocked(unsigned int start, unsigned int end) { AT91S_EFC *pEfc; unsigned short startPage, endPage; unsigned char startRegion, endRegion; unsigned int numPagesInRegion; unsigned int status; unsigned char error; unsigned int numLockedRegions = 0; SANITY_CHECK(end >= start); #ifdef AT91C_BASE_EFC1 // Convert wrapped address to physical address. start &= 0x19FFFF; end &= 0x19FFFF; // Check EFC crossover 2 bank SANITY_CHECK(((start >=AT91C_IFLASH) && (end <= AT91C_IFLASH + AT91C_IFLASH_SIZE)) || ((start >=AT91C_IFLASH1) && (end <= AT91C_IFLASH1 + AT91C_IFLASH1_SIZE))); #else SANITY_CHECK((start >=AT91C_IFLASH) && (end <= AT91C_IFLASH + AT91C_IFLASH_SIZE)); #endif // Compute page numbers EFC_TranslateAddress(&pEfc, start, &startPage, 0); EFC_TranslateAddress(0, end, &endPage, 0); // Compute region numbers numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE; startRegion = startPage / numPagesInRegion; endRegion = endPage / numPagesInRegion; if ((endPage % numPagesInRegion) != 0) { endRegion++; } // Retrieve lock status error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_GLB, 0); ASSERT(!error, "-F- Error while trying to fetch lock bits status (0x%02X)\r\n", error); status = EFC_GetResult(pEfc); // Check status of each involved region while (startRegion < endRegion) { if ((status & (1 << startRegion)) != 0) { numLockedRegions++; } startRegion++; } return numLockedRegions; }
//------------------------------------------------------------------------------ /// Sets the selected GPNVM bit. /// Returns 0 if successful; otherwise returns an error code. /// \param gpnvm GPNVM index. //------------------------------------------------------------------------------ unsigned char FLASHD_SetGPNVM(unsigned char gpnvm) { SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS); if (!FLASHD_IsGPNVMSet(gpnvm)) { return EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_SFB, gpnvm); } else { return 0; } }
/** * \brief Clears the selected GPNVM bit. * * \param gpnvm GPNVM bit index. * \returns 0 if successful; otherwise returns an error code. */ extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM ) { assert( ucGPNVM < GPNVM_NUM_MAX ) ; if ( FLASHD_IsGPNVMSet( ucGPNVM ) ) { return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ; } else { return 0 ; } }
//------------------------------------------------------------------------------ /// Clears the selected GPNVM bit. /// Returns 0 if successful; otherwise returns an error code. /// \param gpnvm GPNVM index. //------------------------------------------------------------------------------ unsigned char FLASHD_ClearGPNVM(unsigned char gpnvm) { SANITY_CHECK(gpnvm < EFC_NUM_GPNVMS); if (FLASHD_IsGPNVMSet(gpnvm)) { return EFC_PerformCommand(AT91C_EFC_FCMD_CFB, gpnvm); } else { return 0; } }
/** * \brief Sets the selected GPNVM bit. * * \param gpnvm GPNVM bit index. * \returns 0 if successful; otherwise returns an error code. */ extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM ) { assert( ucGPNVM < 3 ) ; if ( !FLASHD_IsGPNVMSet( ucGPNVM ) ) { return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ; } else { return 0 ; } }
/** * \brief Erases flash by sector. * * \param dwAddress Start address of be erased sector. * * \return 0 if successful; otherwise returns an error code. */ extern uint32_t FLASHD_EraseSector( uint32_t dwAddress ) { Efc* pEfc ; uint16_t wPage ; uint16_t wOffset ; uint32_t dwError ; assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ; /* Translate write address */ EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ; dwError = EFC_PerformCommand( pEfc, EFC_FCMD_ES, wPage, _dwUseIAP ) ; return dwError ; }
//------------------------------------------------------------------------------ /// Erases the entire flash. /// Returns 0 if successful; otherwise returns an error code. //------------------------------------------------------------------------------ unsigned char FLASHD_Erase(unsigned int address) { AT91S_EFC *pEfc; unsigned short page; unsigned short offset; unsigned char error; SANITY_CHECK((address >=AT91C_IFLASH) || (address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE))); // Translate write address EFC_TranslateAddress(&pEfc, address, &page, &offset); error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_ERASE_ALL, 0); return error; }
/** * \brief Returns the number of locked regions inside the given address range. * * \param start Start address of range * \param end End address of range. */ extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end ) { uint32_t i, j; Efc *pEfc ; uint16_t startPage, endPage ; uint8_t startRegion, endRegion ; uint32_t numPagesInRegion ; uint32_t status[IFLASH_NB_OF_LOCK_BITS / 32u] ; uint32_t numLockedRegions = 0 ; assert( end >= start ) ; assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ; /* Compute page numbers */ EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ; EFC_TranslateAddress( 0, end, &endPage, 0 ) ; /* Compute region numbers */ numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; startRegion = startPage / numPagesInRegion ; endRegion = endPage / numPagesInRegion ; if ((endPage % numPagesInRegion) != 0) { endRegion++ ; } /* Retrieve lock status */ EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ; for (i = 0; i < (IFLASH_NB_OF_LOCK_BITS / 32u); i++) { status[i] = EFC_GetResult( pEfc ) ; } /* Check status of each involved region */ while ( startRegion < endRegion ) { i = startRegion / 32u; j = startRegion % 32u; if ( (status[i] & (1 << j)) != 0 ) { numLockedRegions++ ; } startRegion++ ; } return numLockedRegions ; }
/** * \brief Erases flash by pages. * * \param dwAddress Start address of be erased pages. * \param dwPageNum Number of pages to be erased with EPA command (4, 8, 16, 32) * * \return 0 if successful; otherwise returns an error code. */ extern uint32_t FLASHD_ErasePages( uint32_t dwAddress, uint32_t dwPageNum ) { Efc* pEfc ; uint16_t wPage ; uint16_t wOffset ; uint32_t dwError ; static uint32_t dwFarg ; assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ; /* Translate write address */ EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ; /* Get FARG field for EPA command: * The first page to be erased is specified in the FARG[15:2] field of * the MC_FCR register. The first page number must be modulo 4, 8,16 or 32 * according to the number of pages to erase at the same time. * * The 2 lowest bits of the FARG field define the number of pages to * be erased (FARG[1:0]). */ if (dwPageNum == 32) { wPage &= ~(32u - 1u); dwFarg = (wPage << 2) | 3; /* 32 pages */ } else if (dwPageNum == 16) { wPage &= ~(16u - 1u); dwFarg = (wPage << 2) | 2; /* 16 pages */ } else if (dwPageNum == 8) { wPage &= ~(8u - 1u); dwFarg = (wPage << 2) | 1; /* 8 pages */ } else { wPage &= ~(4u - 1u); dwFarg = (wPage << 2) | 0; /* 4 pages */ } dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EPA, dwFarg, _dwUseIAP ) ; return dwError ; }
/** * \brief Returns the number of locked regions inside the given address range. * * \param start Start address of range * \param end End address of range. */ extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end ) { const uint32_t IFLASH_PAGE_SIZE = IS_SAM3() ? IFLASH_PAGE_SIZE_SAM3 : IFLASH_PAGE_SIZE_SAM4; const uint32_t IFLASH_LOCK_REGION_SIZE = IS_SAM3() ? IFLASH_LOCK_REGION_SIZE_SAM3 : IFLASH_LOCK_REGION_SIZE_SAM4; Efc *pEfc ; uint16_t startPage, endPage ; uint8_t startRegion, endRegion ; uint32_t numPagesInRegion ; uint32_t status ; __attribute__((unused)) uint32_t dwError ; uint32_t numLockedRegions = 0 ; assert( end >= start ) ; assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ; // Compute page numbers EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ; EFC_TranslateAddress( 0, end, &endPage, 0 ) ; // Compute region numbers numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; startRegion = startPage / numPagesInRegion ; endRegion = endPage / numPagesInRegion ; if ((endPage % numPagesInRegion) != 0) { endRegion++ ; } // Retrieve lock status dwError = EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ; assert( !dwError ) ; status = EFC_GetResult( pEfc ) ; // Check status of each involved region while ( startRegion < endRegion ) { if ( (status & (1 << startRegion)) != 0 ) { numLockedRegions++ ; } startRegion++ ; } return numLockedRegions ; }
/** * \brief Check if the given GPNVM bit is set or not. * * \param gpnvm GPNVM bit index. * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0. */ extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM ) { uint32_t dwStatus ; assert( ucGPNVM < GPNVM_NUM_MAX ) ; /* Get GPNVMs status */ EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ; dwStatus = EFC_GetResult( EFC ) ; /* Check if GPNVM is set */ if ( (dwStatus & (1 << ucGPNVM)) != 0 ) { return 1 ; } else { return 0 ; } }
//------------------------------------------------------------------------------ /// Unlocks all the regions in the given address range. The actual unlock range is /// reported through two output parameters. /// Returns 0 if successful; otherwise returns an error code. /// \param start Start address of unlock range. /// \param end End address of unlock range. /// \param pActualStart Start address of the actual unlock range (optional). /// \param pActualEnd End address of the actual unlock range (optional). //------------------------------------------------------------------------------ unsigned char FLASHD_Unlock( unsigned int start, unsigned int end, unsigned int *pActualStart, unsigned int *pActualEnd) { AT91S_EFC *pEfc; unsigned int actualStart, actualEnd; unsigned short startPage, endPage; unsigned char error; unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE; // Compute actual unlock range and store it ComputeLockRange(start, end, &actualStart, &actualEnd); if (pActualStart) { *pActualStart = actualStart; } if (pActualEnd) { *pActualEnd = actualEnd; } // Compute page numbers EFC_TranslateAddress(&pEfc, actualStart, &startPage, 0); EFC_TranslateAddress(0, actualEnd, &endPage, 0); // Unlock all pages while (startPage < endPage) { error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_CLB, startPage); if (error) { return error; } startPage += numPagesInRegion; } return 0; }
//------------------------------------------------------------------------------ /// Returns the number of locked regions inside the given address range. /// \param start Start address of range. /// \param end End address of range. //------------------------------------------------------------------------------ unsigned char FLASHD_IsLocked(unsigned int start, unsigned int end) { unsigned short startPage, endPage; unsigned char startRegion, endRegion; unsigned int numPagesInRegion; unsigned int status; unsigned char error; unsigned int numLockedRegions = 0; // Compute page numbers EFC_TranslateAddress(start, &startPage, 0); EFC_TranslateAddress(end, &endPage, 0); // Compute region numbers numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE; startRegion = startPage / numPagesInRegion; endRegion = endPage / numPagesInRegion; if ((endPage % numPagesInRegion) != 0) { endRegion++; } // Retrieve lock status error = EFC_PerformCommand(AT91C_EFC_FCMD_GLB, 0); ASSERT(!error, "-F- Error while trying to fetch lock bits status (0x%02X)\n\r", error); status = EFC_GetResult(); // Check status of each involved region while (startRegion < endRegion) { if ((status & (1 << startRegion)) != 0) { numLockedRegions++; } startRegion++; } return numLockedRegions; }
/** * \brief Check if the given GPNVM bit is set or not. * * \param gpnvm GPNVM bit index. * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0. */ extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM ) { __attribute__((unused)) uint32_t dwError ; uint32_t dwStatus ; assert( ucGPNVM < 2 ) ; /* Get GPNVMs status */ dwError = EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ; assert( !dwError ) ; dwStatus = EFC_GetResult( EFC ) ; /* Check if GPNVM is set */ if ( (dwStatus & (1 << ucGPNVM)) != 0 ) { return 1 ; } else { return 0 ; } }
//------------------------------------------------------------------------------ /// Returns 1 if the given GPNVM bit is currently set; otherwise returns 0. /// \param gpnvm GPNVM bit index. //------------------------------------------------------------------------------ unsigned char FLASHD_IsGPNVMSet(unsigned char gpnvm) { unsigned char error; unsigned int status; SANITY_CHECK(gpnvm < EFC_NUM_GPNVMS); // Get GPNVMs status error = EFC_PerformCommand(AT91C_EFC_FCMD_GFB, 0); ASSERT(!error, "-F- Error while trying to fetch GPNVMs status (0x%02X)\n\r", error); status = EFC_GetResult(); // Check if GPNVM is set if ((status & (1 << gpnvm)) != 0) { return 1; } else { return 0; } }
unsigned char FLASHD_ReadUniqueID (unsigned long * uniqueID) { unsigned char error; SANITY_CHECK(uniqueID != NULL); uniqueID[0] = 0; uniqueID[1] = 0; uniqueID[2] = 0; uniqueID[3] = 0; EFC_StartCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_STUI, 0); uniqueID[0] = *(unsigned int *)AT91C_IFLASH; uniqueID[1] = *(unsigned int *)(AT91C_IFLASH + 4); uniqueID[2] = *(unsigned int *)(AT91C_IFLASH + 8); uniqueID[3] = *(unsigned int *)(AT91C_IFLASH + 12); error = EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_SPUI, 0); if (error) return error; return 0; }
//------------------------------------------------------------------------------ /// Clears the selected GPNVM bit. /// Returns 0 if successful; otherwise returns an error code. /// \param gpnvm GPNVM index. //------------------------------------------------------------------------------ unsigned char FLASHD_ClearGPNVM(unsigned char gpnvm) { AT91S_EFC *pEfc = AT91C_BASE_EFC0; //SANITY_CHECK(gpnvm < EFC_NUM_GPNVMS); if (FLASHD_IsGPNVMSet(gpnvm)) { #ifdef AT91C_BASE_EFC1 // GPNVM in EFC1 if (gpnvm >= 8) { pEfc = AT91C_BASE_EFC1; gpnvm -= 8; } #endif return EFC_PerformCommand(pEfc, AT91C_MC_FCMD_CLR_GP_NVM, gpnvm); } else { return 0; } }
/** * \brief Writes a data buffer in the internal flash * * \note This function works in polling mode, and thus only returns when the * data has been effectively written. * \param address Write address. * \param pBuffer Data buffer. * \param size Size of data buffer in bytes. * \return 0 if successful, otherwise returns an error code. */ extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) { Efc* pEfc ; uint16_t page ; uint16_t offset ; uint32_t writeSize ; uint32_t pageAddress ; uint16_t padding ; uint32_t dwError ; uint32_t dwIdx ; uint32_t *pAlignedDestination ; uint8_t *pucPageBuffer = (uint8_t *)_pdwPageBuffer; assert( pvBuffer ) ; assert( dwAddress >=IFLASH_ADDR ) ; assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ; /* Translate write address */ EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ; /* Write all pages */ while ( dwSize > 0 ) { /* Copy data in temporary buffer to avoid alignment problems */ writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ; EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ; padding = IFLASH_PAGE_SIZE - offset - writeSize ; /* Pre-buffer data */ memcpy( pucPageBuffer, (void *) pageAddress, offset); /* Buffer data */ memcpy( pucPageBuffer + offset, pvBuffer, writeSize); /* Post-buffer data */ memcpy( pucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); /* Write page * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption */ pAlignedDestination = (uint32_t*)pageAddress ; for (dwIdx = 0; dwIdx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); ++ dwIdx) { *pAlignedDestination++ = _pdwPageBuffer[dwIdx]; } /* Note for sam3s16 and sam4s: * It is not possible to use Erase and write Command (EWP) on all Flash (this * command is available on the First 2 Small Sector, 16K Bytes). For the next * block, Erase them first then use Write page command. */ /* Send writing command */ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_WP, page, _dwUseIAP ) ; if ( dwError ) { return dwError ; } /* Progression */ pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ; dwSize -= writeSize ; page++; offset = 0; } return 0 ; }
//------------------------------------------------------------------------------ /// Writes a data buffer in the internal flash. This function works in polling /// mode, and thus only returns when the data has been effectively written. /// Returns 0 if successful; otherwise returns an error code. /// \param address Write address. /// \param pBuffer Data buffer. /// \param size Size of data buffer in bytes. //------------------------------------------------------------------------------ unsigned char FLASHD_Write( unsigned int address, const void *pBuffer, unsigned int size) { AT91S_EFC *pEfc; unsigned short page; unsigned short offset; unsigned int writeSize; unsigned int pageAddress; unsigned short padding; unsigned char error; unsigned int sizeTmp; unsigned int *pAlignedDestination; unsigned int *pAlignedSource; ////SANITY_CHECK(address >= (unsigned int)AT91C_IFLASH); ////SANITY_CHECK(pBuffer); ////SANITY_CHECK((address + size) <= (unsigned int)(AT91C_IFLASH + AT91C_IFLASH_SIZE)); #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); // Translate write address EFC_TranslateAddress(address, &pEfc, &page, &offset); // Write all pages while (size > 0) { // Copy data in temporary buffer to avoid alignment problems writeSize = min(AT91C_IFLASH_PAGE_SIZE - offset, size); EFC_ComputeAddress(pEfc, page, 0, &pageAddress); padding = AT91C_IFLASH_PAGE_SIZE - offset - writeSize; // Pre-buffer data (mask with 0xFF) memcpy(pPageBuffer, (void *) pageAddress, offset); // Buffer data memcpy(pPageBuffer + offset, pBuffer, writeSize); // Post-buffer data memcpy(pPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); // Write page // Writing 8-bit and 16-bit data is not allowed // and may lead to unpredictable data corruption #ifdef EFC_EVEN_ODD_PROG // Write even words first with auto erase pAlignedDestination = (unsigned int*)pageAddress; pAlignedSource = (unsigned int*)pPageBuffer; sizeTmp = AT91C_IFLASH_PAGE_SIZE; while (sizeTmp >= 4) { *pAlignedDestination = *pAlignedSource; pAlignedDestination += 2; pAlignedSource += 2; sizeTmp -= 8; } // Send writing command error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page); if (error) { OS_EXIT_CRITICAL(); return error; } // Then write odd words without auto erase EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC0, 0); #ifdef AT91C_BASE_EFC1 EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC1, 0); #endif pAlignedDestination = (unsigned int*)pageAddress + 1; pAlignedSource = (unsigned int*)pPageBuffer + 1; sizeTmp = AT91C_IFLASH_PAGE_SIZE; while (sizeTmp >= 4) { *pAlignedDestination = *pAlignedSource; pAlignedDestination += 2; pAlignedSource += 2; sizeTmp -= 8; } // Send writing command error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page); if (error) { OS_EXIT_CRITICAL(); return error; } EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC0, 1); #ifdef AT91C_BASE_EFC1 EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC1, 1); #endif #else pAlignedDestination = (unsigned int*)pageAddress; pAlignedSource = (unsigned int*)pPageBuffer; sizeTmp = AT91C_IFLASH_PAGE_SIZE; while (sizeTmp >= 4) { *pAlignedDestination++ = *pAlignedSource++; sizeTmp -= 4; } // Send writing command error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page); if (error) { OS_EXIT_CRITICAL(); return error; } #endif // Progression address += AT91C_IFLASH_PAGE_SIZE; pBuffer = (void *) ((unsigned int) pBuffer + writeSize); size -= writeSize; page++; offset = 0; #if defined(AT91C_BASE_EFC1) // Handle EFC crossover if ((pEfc == AT91C_BASE_EFC0) && (page >= (AT91C_IFLASH_NB_OF_PAGES / 2))) { pEfc = AT91C_BASE_EFC1; page = 0; } #endif } //while end OS_EXIT_CRITICAL(); return 0; }
/** * \brief Writes a data buffer in the internal flash * * \note This function works in polling mode, and thus only returns when the * data has been effectively written. * \param address Write address. * \param pBuffer Data buffer. * \param size Size of data buffer in bytes. * \return 0 if successful, otherwise returns an error code. */ extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) { const uint32_t IFLASH_PAGE_SIZE = IS_SAM3() ? IFLASH_PAGE_SIZE_SAM3 : IFLASH_PAGE_SIZE_SAM4; Efc* pEfc ; uint16_t page ; uint16_t offset ; uint32_t writeSize ; uint32_t pageAddress ; uint16_t padding ; uint32_t dwError ; uint32_t sizeTmp ; uint32_t *pAlignedDestination ; uint32_t *pAlignedSource ; assert( pvBuffer ) ; assert( dwAddress >=IFLASH_ADDR ) ; assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ; /* Translate write address */ EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ; /* Write all pages */ while ( dwSize > 0 ) { /* Copy data in temporary buffer to avoid alignment problems */ writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ; EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ; padding = IFLASH_PAGE_SIZE - offset - writeSize ; /* Pre-buffer data */ memcpy( _aucPageBuffer, (void *) pageAddress, offset); /* Buffer data */ memcpy( _aucPageBuffer + offset, pvBuffer, writeSize); /* Post-buffer data */ memcpy( _aucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); /* Write page * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption */ pAlignedDestination = (uint32_t*)pageAddress ; pAlignedSource = (uint32_t*)_adwPageBuffer ; sizeTmp = IFLASH_PAGE_SIZE ; while ( sizeTmp >= 4 ) { *pAlignedDestination++ = *pAlignedSource++; sizeTmp -= 4; } // On SAM3 we do erase and write page here. // On SAM4 we can't use EWP, we erased pages before, we only use WP here. // First 2*8kb on SAM4 can use EWP. if(IS_SAM3() || (page < 32)) { dwError = EFC_PerformCommand(pEfc, EFC_FCMD_EWP, page, _dwUseIAP); } else { dwError = EFC_PerformCommand(pEfc, EFC_FCMD_WP, page, _dwUseIAP); } if (dwError) { return dwError; } /* Progression */ dwAddress += IFLASH_PAGE_SIZE ; pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ; dwSize -= writeSize ; page++; offset = 0; } return 0 ; }
//------------------------------------------------------------------------------ /// Writes a data buffer in the internal flash. This function works in polling /// mode, and thus only returns when the data has been effectively written. /// Returns 0 if successful; otherwise returns an error code. /// \param address Write address. /// \param pBuffer Data buffer. /// \param size Size of data buffer in bytes. //------------------------------------------------------------------------------ unsigned char FLASHD_Write( unsigned int address, const void *pBuffer, unsigned int size) { unsigned short page; unsigned short offset; unsigned int writeSize; unsigned int pageAddress; unsigned short padding; unsigned char error; unsigned int sizeTmp; unsigned int *pAlignedDestination; unsigned int *pAlignedSource; SANITY_CHECK(address >= AT91C_IFLASH); SANITY_CHECK(pBuffer); SANITY_CHECK((address + size) <= (AT91C_IFLASH + AT91C_IFLASH_SIZE)); // Translate write address EFC_TranslateAddress(address, &page, &offset); // Write all pages while (size > 0) { // Copy data in temporary buffer to avoid alignment problems writeSize = min(AT91C_IFLASH_PAGE_SIZE - offset, size); EFC_ComputeAddress(page, 0, &pageAddress); padding = AT91C_IFLASH_PAGE_SIZE - offset - writeSize; // Pre-buffer data memcpy(pPageBuffer, (void *) pageAddress, offset); // Buffer data memcpy(pPageBuffer + offset, pBuffer, writeSize); // Post-buffer data memcpy(pPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); // Write page // Writing 8-bit and 16-bit data is not allowed // and may lead to unpredictable data corruption pAlignedDestination = (unsigned int*)pageAddress; pAlignedSource = (unsigned int*)pPageBuffer; sizeTmp = AT91C_IFLASH_PAGE_SIZE; while (sizeTmp >= 4) { *pAlignedDestination++ = *pAlignedSource++; sizeTmp -= 4; } // Send writing command error = EFC_PerformCommand(AT91C_EFC_FCMD_EWP, page); if (error) { return error; } // Progression address += AT91C_IFLASH_PAGE_SIZE; pBuffer = (void *) ((unsigned int) pBuffer + writeSize); size -= writeSize; page++; offset = 0; } return 0; }