/** * \brief Computes the lock range associated with the given address range. * * \param dwStart Start address of lock range. * \param dwEnd End address of lock range. * \param pdwActualStart Actual start address of lock range. * \param pdwActualEnd Actual end address of lock range. */ static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) { Efc* pStartEfc ; Efc* pEndEfc ; uint16_t wStartPage ; uint16_t wEndPage ; uint16_t wNumPagesInRegion ; uint16_t wActualStartPage ; uint16_t wActualEndPage ; /* Convert start and end address in page numbers */ EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ; EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ; /* Find out the first page of the first region to lock */ wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ; wActualEndPage = wEndPage ; if ( (wEndPage % wNumPagesInRegion) != 0 ) { wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ; } /* Store actual page numbers */ EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ; EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ; TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", (unsigned int)*pdwActualStart, (unsigned int)*pdwActualEnd ) ; }
//------------------------------------------------------------------------------ /// Computes the lock range associated with the given address range. /// \param start Start address of lock range. /// \param end End address of lock range. /// \param pActualStart Actual start address of lock range. /// \param pActualEnd Actual end address of lock range. //------------------------------------------------------------------------------ static void ComputeLockRange( unsigned int start, unsigned int end, unsigned int *pActualStart, unsigned int *pActualEnd) { AT91S_EFC *pStartEfc, *pEndEfc; unsigned short startPage, endPage; unsigned short numPagesInRegion; unsigned short actualStartPage, actualEndPage; // Convert start and end address in page numbers EFC_TranslateAddress(start, &pStartEfc, &startPage, 0); EFC_TranslateAddress(end, &pEndEfc, &endPage, 0); // Find out the first page of the first region to lock numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE; actualStartPage = startPage - (startPage % numPagesInRegion); actualEndPage = endPage; if ((endPage % numPagesInRegion) != 0) { actualEndPage += numPagesInRegion - (endPage % numPagesInRegion); } // Store actual page numbers EFC_ComputeAddress(pStartEfc, actualStartPage, 0, pActualStart); EFC_ComputeAddress(pEndEfc, actualEndPage, 0, pActualEnd); //TRACE_DEBUG("Actual lock range is 0x%06X - 0x%06X\n\r", *pActualStart, *pActualEnd); }
/** * \brief Computes the lock range associated with the given address range. * * \param dwStart Start address of lock range. * \param dwEnd End address of lock range. * \param pdwActualStart Actual start address of lock range. * \param pdwActualEnd Actual end address of lock range. */ static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) { const uint32_t IFLASH_PAGE_SIZE = IS_SAM3() ? IFLASH_PAGE_SIZE_SAM3 : IFLASH_PAGE_SIZE_SAM4; const uint32_t IFLASH_NB_OF_PAGES = IS_SAM3() ? IFLASH_NB_OF_PAGES_SAM3 : IFLASH_NB_OF_PAGES_SAM4; const uint32_t IFLASH_LOCK_REGION_SIZE = IS_SAM3() ? IFLASH_LOCK_REGION_SIZE_SAM3 : IFLASH_LOCK_REGION_SIZE_SAM4; Efc* pStartEfc ; Efc* pEndEfc ; uint16_t wStartPage ; uint16_t wEndPage ; uint16_t wNumPagesInRegion ; uint16_t wActualStartPage ; uint16_t wActualEndPage ; // Convert start and end address in page numbers EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ; EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ; // Find out the first page of the first region to lock wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ; wActualEndPage = wEndPage ; wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ; if ( wActualEndPage > IFLASH_NB_OF_PAGES ) { wActualEndPage = IFLASH_NB_OF_PAGES; } // Store actual page numbers EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ; EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ; TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ; }
/** * \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; }
//------------------------------------------------------------------------------ /// 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; }
/** * \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 ; }