diff options
Diffstat (limited to 'platforms/chibios/flash_stm32.c')
| -rw-r--r-- | platforms/chibios/flash_stm32.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/platforms/chibios/flash_stm32.c b/platforms/chibios/flash_stm32.c new file mode 100644 index 000000000..72c41b8b7 --- /dev/null +++ b/platforms/chibios/flash_stm32.c | |||
| @@ -0,0 +1,208 @@ | |||
| 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 "flash_stm32.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 | } | ||
