//***************************************************************************** // // am_hal_flash.c //! @file //! //! @brief Functions for performing Flash operations. //! //! @addtogroup flash1 Flash //! @ingroup apollo1hal //! @{ // //***************************************************************************** //***************************************************************************** // // Copyright (c) 2020, Ambiq Micro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // Third party software included in this distribution is subject to the // additional license terms as defined in the /docs/licenses directory. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // This is part of revision 2.4.2 of the AmbiqSuite Development Package. // //***************************************************************************** #include #include #include "am_mcu_apollo.h" // // Look-up table // const g_am_hal_flash_t g_am_hal_flash = { // am_hal_flash_mass_erase ((int (*)(uint32_t, uint32_t)) 0x0800004d), // am_hal_flash_page_erase ((int (*)(uint32_t, uint32_t, uint32_t)) 0x08000051), // am_hal_flash_program_main ((int (*)(uint32_t, const uint32_t *, uint32_t *, uint32_t)) 0x08000055), // am_hal_flash_program_otp ((int (*)(uint32_t, uint32_t, const uint32_t *, uint32_t, uint32_t)) 0x08000059), // am_hal_flash_program_main_sram ((void (*)(void)) 0x0800005d), // am_hal_flash_program_otp_sram ((void (*)(void)) 0x08000061), // am_hal_flash_erase_main_pages_sram ((void (*)(void)) 0x08000065), // am_hal_flash_mass_erase_sram ((void (*)(void)) 0x08000069) }; // // Set up a very small function that will be guaranteed to be located in SRAM // which can be used to to retrieve data from OTP. // Make sure the function is word-aligned. // uint32_t SRAM_load_ui32[8 / 4] = { 0xBF006800, // 6800 ldr r0,[r0,#0] // BF00 nop 0xBF004770 // 4770 bx lr // BF00 nop }; //***************************************************************************** // //! @brief Implement an iterative spin loop. //! //! @param ui32Iterations - Number of iterations to delay. //! //! Use this function to implement a CPU busy waiting spin. For Apollo, this //! delay can be used for timing purposes since for Apollo, each iteration will //! take 3 cycles. //! //! @return None. // //***************************************************************************** #if (defined (__ARMCC_VERSION)) && (__ARMCC_VERSION < 6000000) __asm void am_hal_flash_delay(uint32_t ui32Iterations) { SUBS R0, #1 BNE am_hal_flash_delay BX LR } #elif (defined (__ARMCC_VERSION)) && (__ARMCC_VERSION >= 6000000) void __attribute__((naked)) am_hal_flash_delay(uint32_t ui32Iterations) { __asm(" subs r0, #1\n" " bne am_hal_flash_delay\n" " bx lr"); } #elif defined(__GNUC_STDC_INLINE__) void __attribute__((naked)) am_hal_flash_delay(uint32_t ui32Iterations) { __asm(" subs r0, #1\n" " bne am_hal_flash_delay\n" " bx lr"); } #elif defined(__IAR_SYSTEMS_ICC__) void am_hal_flash_delay(uint32_t ui32Iterations) { asm("SUBS R0, #1"); asm("BNE.N am_hal_flash_delay"); asm("BX LR"); } #else #error Compiler is unknown, please contact Ambiq support team #endif //***************************************************************************** // //! @brief Delays for a desired amount of cycles while also waiting for a //! status change. //! //! @param ui32usMaxDelay - Maximum number of ~1uS delay loops. //! @param ui32Address - Address of the register for the status change. //! @param ui32Mask - Mask for the status change. //! @param ui32Value - Target value for the status change. //! //! This function will delay for approximately the given number of microseconds //! while checking for a status change, exiting when either the given time has //! expired or the status change is detected. //! //! @returns 0 = timeout. //! 1 = status change detected. // //***************************************************************************** uint32_t am_hal_flash_delay_status_change(uint32_t ui32usMaxDelay, uint32_t ui32Address, uint32_t ui32Mask, uint32_t ui32Value) { while ( ui32usMaxDelay-- ) { // // Check the status // if ( ( AM_REGVAL(ui32Address) & ui32Mask ) == ui32Value ) { return 1; } // // Call the BOOTROM cycle function to delay for about 1 microsecond. // am_hal_flash_delay( FLASH_CYCLES_US(1) ); } return 0; } // am_hal_flash_delay_status_change() //***************************************************************************** // //! @brief This function performs a mass erase on a flash block. //! //! @param ui32Value - The flash program key. //! @param ui32FlashBlk - The flash block to erase. //! //! This function will erase the desired block of flash. //! //! @note Each flash block contains a maximum of 256kB. //! //! @return 0 for success, non-zero for failure. // //***************************************************************************** int am_hal_flash_mass_erase(uint32_t ui32Value, uint32_t ui32FlashBlk) { return g_am_hal_flash.am_hal_flash_mass_erase(ui32Value, ui32FlashBlk); } //***************************************************************************** // //! @brief This function performs a page erase on a flash block. //! //! @param ui32Value - The flash program key. //! @param ui32FlashBlk - The flash block to reference the page number with. //! @param ui32PageNum - The flash page offset into the selected block. //! //! This function will erase the desired flash page in the desired block of //! flash. //! //! @note For Apollo, each flash page is 2KB (or AM_HAL_FLASH_PAGE_SIZE). //! Each flash block (instance) contains a maximum of 128 pages //! (or AM_HAL_FLASH_BLOCK_PAGES). //! //! @note When given an absolute flash address, a couple of helpful macros can //! be utilized when calling this function. //! For example: //! am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, //! AM_HAL_FLASH_ADDR2BLOCK(ui32Addr), //! AM_HAL_FLASH_ADDR2PAGE(ui32Addr) ); //! //! @return 0 for success, non-zero for failure. // //***************************************************************************** int am_hal_flash_page_erase(uint32_t ui32Value, uint32_t ui32FlashBlk, uint32_t ui32PageNum) { return g_am_hal_flash.am_hal_flash_page_erase(ui32Value, ui32FlashBlk, ui32PageNum); } //***************************************************************************** // //! @brief This programs up to N bytes of the Main array on one flash block. //! //! @param ui32Value - The Program key. //! @param pui32Src - Pointer to word aligned array of data to program into //! the flash block. //! @param pui32Dst - Pointer to word aligned location to to begin programming //! the flash block. //! @param ui32NumWords - The Number of words to program. //! //! This function will program multiple words in the OTP block on flash //! block (instance) 0. //! //! @return 0 for success, non-zero for failure. // //***************************************************************************** int am_hal_flash_program_main(uint32_t ui32Value, const uint32_t *pui32Src, uint32_t *pui32Dst, uint32_t ui32NumWords) { return g_am_hal_flash.am_hal_flash_program_main(ui32Value, pui32Src, pui32Dst, ui32NumWords); } //***************************************************************************** // //! @brief This function programs multiple words in the OTP. //! //! @param ui32Value - The OTP key. //! @param ui32FlashBlk - The flash block where OTP lives (forced to block 0) //! @param *pui32Src - Pointer to word aligned array of data to program into //! the OTP block. //! @param ui32Offset - Word offset into OTP (offset of 0 is the first word). //! @param ui32NumWords - The Number of words to program. //! //! This function will program multiple words in the OTP block on flash //! block (instance) 0. //! //! @note Only the upper half of the OTP block can be written //! so 1 < ui32NumWords < 257. //! //! @return 0 for success, non-zero for failure. // //***************************************************************************** int am_hal_flash_program_otp(uint32_t ui32Value, uint32_t ui32FlashBlk, const uint32_t *pui32Src, uint32_t ui32Offset, uint32_t ui32NumWords) { return g_am_hal_flash.am_hal_flash_program_otp(ui32Value, 0, pui32Src, ui32Offset, ui32NumWords); } //***************************************************************************** // //! @brief This function programs multiple words in the OTP using SRAM as args. //! //! This function will program multiple words in the OTP block using SRAM as //! its arguments. This is helpful for tools/manufacturing. //! //! The SRAM addresses of interest are: //! //! 0x10000000 Offset in to OTP block, 0 <= Offset < 256 //! 0x10000004 Number of 32-bit words to program //! 0x10000008 OTP key //! 0x1000000C Debugger sets this to -1 and all return codes are >= 0 //! 0x10000010 First 32-bit word of data buffer to be programmed //! //! @note This routine spins when am_hal_flash_program_otp() returns and waits //! for the debugger surrogate in the parallel programmer. //! //! @return never returns, spins here waiting for debugger or debugger surrogate //! on the parallel programmer. // //***************************************************************************** void am_hal_flash_program_otp_sram(void) { g_am_hal_flash.am_hal_flash_program_otp_sram(); } //***************************************************************************** // //! @brief This function erases pages in the main array using SRAM as args. //! //! This function will erase multiple pages in the flash main array using SRAM //! as its arguments. This is helpful for tools/manufacturing. //! //! The SRAM addresses of interest are: //! //! 0x10000000 Flash block/instance number //! 0x10000004 Number of pages to erase (must be between 1 and 128 //! inclusive) //! 0x10000008 PROGRAM key //! 0x1000000C Debugger sets this to -1 and all return codes are >= 0 //! 0x10000010 Page number of the first flash page to erase. NOTE: these //! *HAVE* to be sequential (range 0 <= PageNumber <= 127) //! //! @note This routine spins when am_hal_flash_page_erase() returns and waits //! for the debugger surrogate in the parallel programmer. Before spinning it //! unconditional executes a break point instruction. //! //! @return never returns, spins here waiting for debugger or debugger surrogate //! on the parallel programmer. // //***************************************************************************** void am_hal_flash_erase_main_pages_sram(void) { g_am_hal_flash.am_hal_flash_erase_main_pages_sram(); } //***************************************************************************** // //! @brief This function mass erases a flash block with SRAM as args. //! //! This function will perform a mass erase on a flash block using SRAM as its //! arguments. This is helpful for tools/manufacturing. //! //! The SRAM addresses of interest are: //! //! 0x10000000 Pointer in to flash block. //! 0x10000004 PROGRAM key //! 0x10000008 Return code (Debugger sets this to -1 and all return //! codes are >= 0) //! //! @note This routine spins when am_hal_flash_mass_erase() returns and waits //! for the debugger surrogate in the parallel programmer. //! //! @return never returns, spins here waiting for debugger or debugger surrogate //! on the parallel programmer. // //***************************************************************************** void am_hal_flash_mass_erase_sram(void) { g_am_hal_flash.am_hal_flash_mass_erase_sram(); } //***************************************************************************** // //! @brief This function programs the main array using SRAM as args. //! //! This function will program the main array using SRAM as it arguments. This //! is helpful for tools/manufacturing. //! //! The SRAM addresses of interest are: //! //! 0x10000000 Pointer in to flash //! 0x10000004 Number of 32-bit words to program //! 0x10000008 PROGRAM key. //! 0x1000000C Debugger sets this to -1 and all return codes are >= 0 //! 0x10000010 First 32-bit word of data buffer to be programmed //! //! @note This routine spins when am_hal_flash_program_main() returns and waits //! for the debugger surrogate in the parallel programmer. Before spinning it //! unconditionally executes a break point instruction. //! //! @return never returns, spins here waiting for debugger or debugger surrogate //! on the parallel programmer. // //***************************************************************************** void am_hal_flash_program_main_sram(void) { g_am_hal_flash.am_hal_flash_program_main_sram(); } //***************************************************************************** // //! @brief Return ui32 value obtained from anywhere in D Code or System Bus //! //! @param ui32Address - return the value corresponding to this location in OTP //! //! Use this function to read a value from various peripheral locations //! that must be read from code running in SRAM. //! //! This function is not required to reside in SRAM as it calls a small //! function that does the actual read which is guaranteed to be in SRAM. //! //! @return the value found // //***************************************************************************** uint32_t am_hal_flash_load_ui32(uint32_t ui32Address) { // // Call the simple routine that has been set up in SRAM as an array. // First set up a function pointer to the array, being sure to set the // .T bit (Thumb bit, bit0) in the branch address, then use that // function ptr to call the SRAM function. // uint32_t SRAMCode = (uint32_t)SRAM_load_ui32 | 0x1; uint32_t (*pFunc)(uint32_t) = (uint32_t (*)(uint32_t))SRAMCode; return (*pFunc)(ui32Address); } //***************************************************************************** // // End Doxygen group. //! @} // //*****************************************************************************