legacy_flash_ops.c (6488B)
1 /* 2 * This software is experimental and a work in progress. 3 * Under no circumstances should these files be used in relation to any critical system(s). 4 * Use of these files is at your own risk. 5 * 6 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 7 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 8 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 9 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 11 * DEALINGS IN THE SOFTWARE. 12 * 13 * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and 14 * https://github.com/leaflabs/libmaple 15 * 16 * Modifications for QMK and STM32F303 by Yiancar 17 */ 18 19 #include <hal.h> 20 #include "legacy_flash_ops.h" 21 22 #if defined(STM32F1XX) 23 # define FLASH_SR_WRPERR FLASH_SR_WRPRTERR 24 #endif 25 26 #if defined(MCU_GD32V) 27 /* GigaDevice GD32VF103 is a STM32F103 clone at heart. */ 28 # include "gd32v_compatibility.h" 29 #endif 30 31 #if defined(STM32F4XX) 32 # define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR) 33 34 # define FLASH_KEY1 0x45670123U 35 # define FLASH_KEY2 0xCDEF89ABU 36 37 static uint8_t ADDR2PAGE(uint32_t Page_Address) { 38 switch (Page_Address) { 39 case 0x08000000 ... 0x08003FFF: 40 return 0; 41 case 0x08004000 ... 0x08007FFF: 42 return 1; 43 case 0x08008000 ... 0x0800BFFF: 44 return 2; 45 case 0x0800C000 ... 0x0800FFFF: 46 return 3; 47 } 48 49 // TODO: bad times... 50 return 7; 51 } 52 #endif 53 54 /* Delay definition */ 55 #define EraseTimeout ((uint32_t)0x00000FFF) 56 #define ProgramTimeout ((uint32_t)0x0000001F) 57 58 #define ASSERT(exp) (void)((0)) 59 60 /** 61 * @brief Inserts a time delay. 62 * @param None 63 * @retval None 64 */ 65 static void delay(void) { 66 __IO uint32_t i = 0; 67 for (i = 0xFF; i != 0; i--) { 68 } 69 } 70 71 /** 72 * @brief Returns the FLASH Status. 73 * @param None 74 * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, 75 * FLASH_ERROR_WRP or FLASH_COMPLETE 76 */ 77 FLASH_Status FLASH_GetStatus(void) { 78 if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) return FLASH_BUSY; 79 80 if ((FLASH->SR & FLASH_SR_PGERR) != 0) return FLASH_ERROR_PG; 81 82 if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP; 83 84 #if defined(FLASH_OBR_OPTERR) 85 if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT; 86 #endif 87 88 return FLASH_COMPLETE; 89 } 90 91 /** 92 * @brief Waits for a Flash operation to complete or a TIMEOUT to occur. 93 * @param Timeout: FLASH progamming Timeout 94 * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, 95 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 96 */ 97 FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { 98 FLASH_Status status; 99 100 /* Check for the Flash Status */ 101 status = FLASH_GetStatus(); 102 /* Wait for a Flash operation to complete or a TIMEOUT to occur */ 103 while ((status == FLASH_BUSY) && (Timeout != 0x00)) { 104 delay(); 105 status = FLASH_GetStatus(); 106 Timeout--; 107 } 108 if (Timeout == 0) status = FLASH_TIMEOUT; 109 /* Return the operation status */ 110 return status; 111 } 112 113 /** 114 * @brief Erases a specified FLASH page. 115 * @param Page_Address: The page address to be erased. 116 * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, 117 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 118 */ 119 FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { 120 FLASH_Status status = FLASH_COMPLETE; 121 /* Check the parameters */ 122 ASSERT(IS_FLASH_ADDRESS(Page_Address)); 123 /* Wait for last operation to be completed */ 124 status = FLASH_WaitForLastOperation(EraseTimeout); 125 126 if (status == FLASH_COMPLETE) { 127 /* if the previous operation is completed, proceed to erase the page */ 128 #if defined(FLASH_CR_SNB) 129 FLASH->CR &= ~FLASH_CR_SNB; 130 FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos); 131 #else 132 FLASH->CR |= FLASH_CR_PER; 133 FLASH->AR = Page_Address; 134 #endif 135 FLASH->CR |= FLASH_CR_STRT; 136 137 /* Wait for last operation to be completed */ 138 status = FLASH_WaitForLastOperation(EraseTimeout); 139 if (status != FLASH_TIMEOUT) { 140 /* if the erase operation is completed, disable the configured Bits */ 141 #if defined(FLASH_CR_SNB) 142 FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB); 143 #else 144 FLASH->CR &= ~FLASH_CR_PER; 145 #endif 146 } 147 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); 148 } 149 /* Return the Erase Status */ 150 return status; 151 } 152 153 /** 154 * @brief Programs a half word at a specified address. 155 * @param Address: specifies the address to be programmed. 156 * @param Data: specifies the data to be programmed. 157 * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, 158 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 159 */ 160 FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { 161 FLASH_Status status = FLASH_BAD_ADDRESS; 162 163 if (IS_FLASH_ADDRESS(Address)) { 164 /* Wait for last operation to be completed */ 165 status = FLASH_WaitForLastOperation(ProgramTimeout); 166 if (status == FLASH_COMPLETE) { 167 /* if the previous operation is completed, proceed to program the new data */ 168 169 #if defined(FLASH_CR_PSIZE) 170 FLASH->CR &= ~FLASH_CR_PSIZE; 171 FLASH->CR |= FLASH_CR_PSIZE_0; 172 #endif 173 FLASH->CR |= FLASH_CR_PG; 174 *(__IO uint16_t *)Address = Data; 175 /* Wait for last operation to be completed */ 176 status = FLASH_WaitForLastOperation(ProgramTimeout); 177 if (status != FLASH_TIMEOUT) { 178 /* if the program operation is completed, disable the PG Bit */ 179 FLASH->CR &= ~FLASH_CR_PG; 180 } 181 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); 182 } 183 } 184 return status; 185 } 186 187 /** 188 * @brief Unlocks the FLASH Program Erase Controller. 189 * @param None 190 * @retval None 191 */ 192 void FLASH_Unlock(void) { 193 if (FLASH->CR & FLASH_CR_LOCK) { 194 /* Authorize the FPEC Access */ 195 FLASH->KEYR = FLASH_KEY1; 196 FLASH->KEYR = FLASH_KEY2; 197 } 198 } 199 200 /** 201 * @brief Locks the FLASH Program Erase Controller. 202 * @param None 203 * @retval None 204 */ 205 void FLASH_Lock(void) { 206 /* Set the Lock Bit to lock the FPEC and the FCR */ 207 FLASH->CR |= FLASH_CR_LOCK; 208 }