//////////////////////////////////////////////////////////////////////////////// /// @file hal_flash.c /// @author AE TEAM /// @brief THIS FILE PROVIDES ALL THE FLASH FIRMWARE FUNCTIONS. //////////////////////////////////////////////////////////////////////////////// /// @attention /// /// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE /// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE /// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR /// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH /// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN /// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS. /// ///

© COPYRIGHT MINDMOTION

//////////////////////////////////////////////////////////////////////////////// // Define to prevent recursive inclusion #define _HAL_FLASH_C_ // Files includes #include "hal_flash.h" //////////////////////////////////////////////////////////////////////////////// /// @addtogroup MM32_Hardware_Abstract_Layer /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup FLASH_HAL /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup FLASH_Exported_Functions /// @{ //////////////////////////////////////////////////////////////////////////////// /// @brief Sets the code latency value. /// @note This function can be used for all MM32 devices. /// @param latency: specifies the FLASH Latency value. /// This parameter can be one of the following values: /// @arg FLASH_Latency_0: FLASH Zero Latency cycle /// @arg FLASH_Latency_1: FLASH One Latency cycle /// @arg FLASH_Latency_2: FLASH Two Latency cycles /// @arg FLASH_Latency_3: FLASH Three Latency cycles /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_SetLatency(FLASH_Latency_TypeDef latency) { FLASH->ACR = (FLASH->ACR & (~FLASH_ACR_LATENCY)) | latency; } //////////////////////////////////////////////////////////////////////////////// /// @brief Enables or disables the Half cycle flash access. /// @note This function can be used for all MM32 devices. /// @param half_cycle_access: specifies the FLASH Half cycle Access mode. /// This parameter can be one of the following values: /// @arg FLASH_HalfCycleAccess_Enable: FLASH Half Cycle Enable /// @arg FLASH_HalfCycleAccess_Disable: FLASH Half Cycle Disable /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_HalfCycleAccessCmd(FLASH_HalfCycleAccess_TypeDef half_cycle_access) { FLASH->ACR &= ~FLASH_ACR_HLFCYA; FLASH->ACR |= half_cycle_access; } //////////////////////////////////////////////////////////////////////////////// /// @brief Enables or disables the Prefetch Buffer. /// @note This function can be used for all MM32 devices. /// @param prefetch_buffer: specifies the Prefetch buffer status. /// This parameter can be one of the following values: /// @arg FLASH_PrefetchBuffer_Enable: FLASH Prefetch Buffer Enable /// @arg FLASH_PrefetchBuffer_Disable: FLASH Prefetch Buffer Disable /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_TypeDef prefetch_buffer) { FLASH->ACR &= ~FLASH_ACR_PRFTBE; FLASH->ACR |= prefetch_buffer; } //////////////////////////////////////////////////////////////////////////////// /// @brief Locks the FLASH Program Erase Controller. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_Lock(void) { FLASH->CR |= FLASH_CR_LOCK; } //////////////////////////////////////////////////////////////////////////////// /// @brief Unlocks the FLASH Program Erase Controller. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_Unlock() { FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; } //////////////////////////////////////////////////////////////////////////////// /// @brief Enable to program the FLASH Option Byte. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_OPTB_Enable(void) { FLASH->OPTKEYR = FLASH_KEY1; FLASH->OPTKEYR = FLASH_KEY2; } //////////////////////////////////////////////////////////////////////////////// /// @brief Erases a specified FLASH page. /// @note This function can be used for all MM32 devices. /// @param page_address: The page address to be erased. /// @retval FLASH Status: The returned value can be: FLASH_BUSY, /// FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ErasePage(u32 page_address) { FLASH->CR |= FLASH_CR_PER; FLASH->AR = page_address; FLASH->CR |= FLASH_CR_STRT; return FLASH_WaitForLastOperation(EraseTimeout); } //////////////////////////////////////////////////////////////////////////////// /// @brief Erases all FLASH pages. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_EraseAllPages() { FLASH->AR = FLASH_BASE; FLASH->CR |= (FLASH_CR_MER | FLASH_CR_STRT); return FLASH_WaitForLastOperation(EraseTimeout); } //////////////////////////////////////////////////////////////////////////////// /// @brief Erases the FLASH option bytes. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_EraseOptionBytes() { FLASH_OPTB_Enable(); FLASH->AR = OB_BASE; FLASH->CR |= (FLASH_CR_OPTER | FLASH_CR_STRT); return FLASH_WaitForLastOperation(EraseTimeout); } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a half word at a specified address. /// @note This function can be used for all MM32 devices. /// @param address: specifies the address to be programmed. /// @param data: specifies the data to be programmed. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ProgramHalfWord(u32 address, u16 data) { FLASH->CR |= FLASH_CR_PG; *(vu16*)address = data; return FLASH_WaitForLastOperation(ProgramTimeout); } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a word at a specified address. /// @note This function can be used for all MM32 devices. /// @param address: specifies the address to be programmed. /// @param data: specifies the data to be programmed. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ProgramWord(u32 address, u32 data) { FLASH_Status ret = FLASH_ProgramHalfWord(address, data); if (ret == FLASH_COMPLETE) { ret = FLASH_ProgramHalfWord(address + 2, data >> 16); } return ret; } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a byte at a specified Option Byte Data address. /// @note This function can be used for all MM32 devices. /// @param address: specifies the address to be programmed. /// This parameter can be 0x1FFFF804 or 0x1FFFF806. /// @param data: specifies the data to be programmed. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ProgramOptionByteData(u32 address, u8 data) { FLASH_Status ret; __IO u16 temp; FLASH_OPTB_Enable(); FLASH->CR |= FLASH_CR_OPTPG; temp = (u16)(~data); temp = (temp << 8) & 0xFF00; temp = temp | (u16)data; address = address & (~0x1); *(vu16*)address = temp; ret = FLASH_WaitForLastOperation(ProgramTimeout); return ret; } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a half word at a specified Option Byte Data address. /// @note This function can be used for all MM32 devices. /// @param address: specifies the address to be programmed. /// This parameter can be 0x1FFFF804 or 0x1FFFF806. /// @param data: specifies the data to be programmed. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ProgramOptionHalfWord(u32 address, u16 data) { FLASH_Status ret; FLASH_OPTB_Enable(); FLASH->CR |= FLASH_CR_OPTPG; *(vu16*)address = data; ret = FLASH_WaitForLastOperation(ProgramTimeout); return ret; } //////////////////////////////////////////////////////////////////////////////// /// @brief Read protection for the specified address /// @note This function can be used for all MM32 devices. /// @retval None. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_ProgramProtect(u32 address, u16 data) { return FLASH_ProgramOptionHalfWord(address, data); // FLASH_Status ret; // ret = FLASH_ProgramOptionHalfWord(address, 0x7F80); // // if (ret == FLASH_COMPLETE) { // ret = FLASH_ProgramOptionHalfWord(address + 2, 0xFF00); // } // return ret; } //////////////////////////////////////////////////////////////////////////////// /// @brief Write protection for the specified address /// @note This function can be used for all MM32 devices. /// @param page: specifies the address of the pages to be write /// protected. /// This parameter is (0x01 << ((Absolute address - 0x08000000)/0x1000)) /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_EnableWriteProtection(u32 page) { FLASH_Status ret; u8 i; for (i = 0; i < 4; i++) { ret = FLASH_ProgramOptionHalfWord((OB_BASE + 8 + i * 2), ~(page >> (i * 8))); if (ret != FLASH_COMPLETE) { break; } } return ret; } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_STDBY. /// @note This function can be used for all MM32 devices. /// @param ob_iwdg: Selects the IWDG mode /// @param ob_stop: Reset event when entering STOP mode. /// @param standby: Reset event when entering Standby mode. /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_UserOptionByteConfig(OB_IWDG_TypeDef ob_iwdg, OB_STOP_TypeDef ob_stop, OB_STDBY_TypeDef standby) { FLASH_OPTB_Enable(); FLASH->CR |= FLASH_CR_OPTPG; OB->USER = ob_iwdg; OB->USER |= ob_stop; OB->USER |= standby; OB->USER |= 0xF8; // OB->USER = iwdg | stop | stdby | 0xF8; return FLASH_WaitForLastOperation(ProgramTimeout); } //////////////////////////////////////////////////////////////////////////////// /// @brief Returns the FLASH User Option Bytes values. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval The FLASH User Option Bytes values:IWDG_SW(Bit0), RST_STOP(Bit1) /// and RST_STDBY(Bit2). //////////////////////////////////////////////////////////////////////////////// u32 FLASH_GetUserOptionByte() { return (FLASH->OBR >> 2); } //////////////////////////////////////////////////////////////////////////////// /// @brief Returns the FLASH Write Protection Option Bytes Register value. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval The FLASH Write Protection Option Bytes Register value. //////////////////////////////////////////////////////////////////////////////// u32 FLASH_GetWriteProtectionOptionByte() { return (FLASH->WRPR); } //////////////////////////////////////////////////////////////////////////////// /// @brief Checks whether the FLASH Prefetch Buffer status is set or not. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval FLASH Prefetch Buffer Status (SET or RESET). //////////////////////////////////////////////////////////////////////////////// FlagStatus FLASH_GetPrefetchBufferStatus(void) { return (FLASH->ACR & FLASH_ACR_PRFTBS) ? SET : RESET; } //////////////////////////////////////////////////////////////////////////////// /// @brief Enables or disables the specified FLASH interrupts. /// @note This function can be used for all MM32 devices. /// @param interrupt: specifies the FLASH interrupt sources to be enabled or /// disabled. /// @param state: new state of the specified Flash interrupts. /// This parameter can be: ENABLE or DISABLE. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_ITConfig(FLASH_IT_TypeDef interrupt, FunctionalState state) { (state) ? (FLASH->CR |= interrupt) : (FLASH->CR &= ~interrupt); } //////////////////////////////////////////////////////////////////////////////// /// @brief Checks whether the specified FLASH flag is set or not. /// @note This function can be used for all MM32 devices. /// @param flag: specifies the FLASH flags to clear. /// This parameter can be one of the following values: /// @arg FLASH_FLAG_BSY: FLASH Busy flag /// @arg FLASH_FLAG_PGERR: FLASH Program error flag /// @arg FLASH_FLAG_WRPRTERR: FLASH Write protected error flag /// @arg FLASH_FLAG_EOP: FLASH End of Operation flag /// @arg FLASH_FLAG_OPTERR: FLASH Option Byte error flag /// @retval The new state of FLASH_FLAG (SET or RESET). //////////////////////////////////////////////////////////////////////////////// FlagStatus FLASH_GetFlagStatus(u16 flag) { return ((flag == FLASH_FLAG_OPTERR) ? (FLASH->OBR & FLASH_FLAG_OPTERR) : (FLASH->SR & flag)) ? SET : RESET; } //////////////////////////////////////////////////////////////////////////////// /// @brief Clears the FLASH's pending flags. /// @note This function can be used for all MM32 devices. /// @param flag: specifies the FLASH flags to clear. /// This parameter can be any combination of the following values: /// @arg FLASH_FLAG_PGERR: FLASH Program error flag /// @arg FLASH_FLAG_WRPRTERR: FLASH Write protected error flag /// @arg FLASH_FLAG_EOP: FLASH End of Operation flag /// @retval None. //////////////////////////////////////////////////////////////////////////////// void FLASH_ClearFlag(u16 flag) { FLASH->SR = flag; } //////////////////////////////////////////////////////////////////////////////// /// @brief Returns the FLASH Status. /// @note This function can be used for all MM32 devices. /// @param None. /// @retval FLASH Status: The returned value can be: FLASH_BUSY, /// FLASH_ERROR_PG, FLASH_ERROR_WRP or FLASH_COMPLETE. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_GetStatus() { return (FLASH_Status)((FLASH->SR & FLASH_FLAG_BSY)) ? FLASH_BUSY : ((FLASH->SR & FLASH_FLAG_PGERR) ? FLASH_ERROR_PG : ((FLASH->SR & FLASH_FLAG_WRPRTERR) ? FLASH_ERROR_WRP : FLASH_COMPLETE)); } //////////////////////////////////////////////////////////////////////////////// /// @brief Waits for a Flash operation to complete or a TIMEOUT to occur. /// @note This function can be used for all MM32 devices /// @param time_out: FLASH programming time_out /// @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, /// FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. //////////////////////////////////////////////////////////////////////////////// FLASH_Status FLASH_WaitForLastOperation(u32 time_out) { u32 i; FLASH_Status ret; do { ret = FLASH_GetStatus(); time_out--; for (i = 0xFF; i != 0; i--) ; } while ((ret == FLASH_BUSY) && (time_out != 0x00)); FLASH->CR = 0; FLASH->SR = FLASH_SR_EOP | FLASH_SR_WRPRTERR | FLASH_SR_PGERR; return (FLASH_Status)((time_out == 0x00) ? FLASH_TIMEOUT : ret); } //////////////////////////////////////////////////////////////////////////////// /// @brief Erases a specified FLASH page. /// @note This function can be used for all MM32 devices. /// @param Page_Address: The page address to be erased. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void exFLASH_EraseEE(u32 page_address) { FLASH_Unlock(); FLASH_ErasePage(page_address); FLASH_Lock(); } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a buffer at a specified address. /// @note This function can be used for all MM32 devices. /// @param *buf: the pointer of the buffer to be programmed. /// @param addr: specifies the address to be programmed. /// @param len: the number of bytes in the buffer. /// This parameter can only be even. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void exFLASH_ProgramEE(u16* buf, u32 addr, u16 len) { u16 i; FLASH_Unlock(); for (i = 0; i < len / 2; i++) { FLASH_ProgramHalfWord(addr, *buf); addr += 2; buf++; } FLASH_Lock(); } //////////////////////////////////////////////////////////////////////////////// /// @brief Determine if the data that at the ptr address with the length is len /// is empty. /// @note This function can be used for all MM32 devices. /// @param *ptr: the pointer of the starting address. /// @param len: the number of bytes. /// This parameter can only be even. /// @retval 1 presents the data is empty, /// 0 presents the data has been written. //////////////////////////////////////////////////////////////////////////////// u8 exFLASH_FindEmpty(u16* ptr, u16 len) { u16 i; for (i = 0; i < (len / 2); i++) { if (*(ptr + i) != 0xffff) return 0; } return 1; } //////////////////////////////////////////////////////////////////////////////// /// @brief Locate the writable area on the specified address. /// @note This function can be used for all MM32 devices. /// @param page_address: specifies the beginning of the EEprom. /// The EEprom can be some continuously pages in the flash. /// @param len: the number of bytes to be written. /// This parameter can only be even. /// @retval the pointer of the starting address. //////////////////////////////////////////////////////////////////////////////// void* exFLASH_Locate(u32 page_address, u16 len) { u16 i; u16* ptr = (u16*)page_address; for (i = 0; i < (0x0800 / len); i++) { if (exFLASH_FindEmpty(ptr, len)) { if (i == 0) return 0; break; } ptr += len / 2; } return ptr; } //////////////////////////////////////////////////////////////////////////////// /// @brief Programs a buffer at a specified address. /// @note This function can be used for all MM32 devices. /// @param *buf: the pointer of the buffer to be programmed. /// @param page_address: specifies the beginning of the EEprom. /// The EEprom can be some continuously pages in the flash. /// @param len: the number of bytes in the buffer. /// This parameter can only be even. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void exFLASH_WriteEE(u16* buf, u32 page_address, u16 len) { u16* ptr = exFLASH_Locate(page_address, len); if (ptr == 0) { exFLASH_EraseEE(page_address + 0x000); exFLASH_EraseEE(page_address + 0x400); exFLASH_ProgramEE(buf, page_address, len); } else { if (ptr == (u16*)(page_address + ((0x0400 / len) - 1) * len)) { exFLASH_EraseEE(page_address + 0x400); exFLASH_ProgramEE(buf, (u32)ptr, len); } else if (ptr == (u16*)(page_address + 0x0800)) { exFLASH_EraseEE(page_address + 0x000); exFLASH_ProgramEE(buf, (u32)page_address, len); } else { exFLASH_ProgramEE(buf, (u32)ptr, len); } } } //////////////////////////////////////////////////////////////////////////////// /// @brief Read the beginning address of the last written data. /// @note This function can be used for all MM32 devices. /// @param page_address: specifies the beginning of the EEprom. /// The EEprom can be some continuously pages in the flash. /// @param len: the number of bytes have been written. /// This parameter can only be even. /// @retval the beginning address of the last written data. /// 0 presents that this is the first time to use this as EEprom. //////////////////////////////////////////////////////////////////////////////// void* exFLASH_ReadEE(u32 page_address, u16 len) { u16* ptr = exFLASH_Locate(page_address, len); return (ptr == 0) ? 0 : (ptr - len / 2); } /// @} /// @} /// @}