]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/chibios/flash_stm32.c
STM32 EEPROM Emulation (#3741)
[qmk_firmware.git] / tmk_core / common / chibios / flash_stm32.c
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 #define STM32F303xC
20
21 #include "stm32f3xx.h"
22 #include "flash_stm32.h"
23
24 #define FLASH_KEY1          ((uint32_t)0x45670123)
25 #define FLASH_KEY2          ((uint32_t)0xCDEF89AB)
26
27 /* Delay definition */
28 #define EraseTimeout        ((uint32_t)0x00000FFF)
29 #define ProgramTimeout      ((uint32_t)0x0000001F)
30
31 #define ASSERT(exp) (void)((0))
32
33 /**
34   * @brief  Inserts a time delay.
35   * @param  None
36   * @retval None
37   */
38 static void delay(void)
39 {
40     __IO uint32_t i = 0;
41     for(i = 0xFF; i != 0; i--) { }
42 }
43
44 /**
45   * @brief  Returns the FLASH Status.
46   * @param  None
47   * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
48   *   FLASH_ERROR_WRP or FLASH_COMPLETE
49   */
50 FLASH_Status FLASH_GetStatus(void)
51 {
52     if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY)
53         return FLASH_BUSY;
54
55     if ((FLASH->SR & FLASH_SR_PGERR) != 0)
56         return FLASH_ERROR_PG;
57
58     if ((FLASH->SR & FLASH_SR_WRPERR) != 0 )
59         return FLASH_ERROR_WRP;
60
61     if ((FLASH->SR & FLASH_OBR_OPTERR) != 0 )
62         return FLASH_ERROR_OPT;
63
64     return FLASH_COMPLETE;
65 }
66
67 /**
68   * @brief  Waits for a Flash operation to complete or a TIMEOUT to occur.
69   * @param  Timeout: FLASH progamming Timeout
70   * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
71   *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
72   */
73 FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
74
75     FLASH_Status status;
76
77     /* Check for the Flash Status */
78     status = FLASH_GetStatus();
79     /* Wait for a Flash operation to complete or a TIMEOUT to occur */
80     while ((status == FLASH_BUSY) && (Timeout != 0x00))
81     {
82         delay();
83         status = FLASH_GetStatus();
84         Timeout--;
85     }
86     if (Timeout == 0)
87         status = FLASH_TIMEOUT;
88     /* Return the operation status */
89     return status;
90 }
91
92 /**
93   * @brief  Erases a specified FLASH page.
94   * @param  Page_Address: The page address to be erased.
95   * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
96   *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
97   */
98 FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
99 {
100     FLASH_Status status = FLASH_COMPLETE;
101     /* Check the parameters */
102     ASSERT(IS_FLASH_ADDRESS(Page_Address));
103     /* Wait for last operation to be completed */
104     status = FLASH_WaitForLastOperation(EraseTimeout);
105   
106     if(status == FLASH_COMPLETE)
107     {
108         /* if the previous operation is completed, proceed to erase the page */
109         FLASH->CR |= FLASH_CR_PER;
110         FLASH->AR = Page_Address;
111         FLASH->CR |= FLASH_CR_STRT;
112
113         /* Wait for last operation to be completed */
114         status = FLASH_WaitForLastOperation(EraseTimeout);
115         if(status != FLASH_TIMEOUT)
116         {
117             /* if the erase operation is completed, disable the PER Bit */
118             FLASH->CR &= ~FLASH_CR_PER;
119         }
120         FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
121     }
122     /* Return the Erase Status */
123     return status;
124 }
125
126 /**
127   * @brief  Programs a half word at a specified address.
128   * @param  Address: specifies the address to be programmed.
129   * @param  Data: specifies the data to be programmed.
130   * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
131   *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 
132   */
133 FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
134 {
135     FLASH_Status status = FLASH_BAD_ADDRESS;
136
137     if (IS_FLASH_ADDRESS(Address))
138     {
139         /* Wait for last operation to be completed */
140         status = FLASH_WaitForLastOperation(ProgramTimeout);
141         if(status == FLASH_COMPLETE)
142         {
143             /* if the previous operation is completed, proceed to program the new data */
144             FLASH->CR |= FLASH_CR_PG;
145             *(__IO uint16_t*)Address = Data;
146             /* Wait for last operation to be completed */
147             status = FLASH_WaitForLastOperation(ProgramTimeout);
148             if(status != FLASH_TIMEOUT)
149             {
150                 /* if the program operation is completed, disable the PG Bit */
151                 FLASH->CR &= ~FLASH_CR_PG;
152             }
153             FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
154         }
155     }
156     return status;
157 }
158
159 /**
160   * @brief  Unlocks the FLASH Program Erase Controller.
161   * @param  None
162   * @retval None
163   */
164 void FLASH_Unlock(void)
165 {
166     /* Authorize the FPEC Access */
167     FLASH->KEYR = FLASH_KEY1;
168     FLASH->KEYR = FLASH_KEY2;
169 }
170
171 /**
172   * @brief  Locks the FLASH Program Erase Controller.
173   * @param  None
174   * @retval None
175   */
176 void FLASH_Lock(void)
177 {
178     /* Set the Lock Bit to lock the FPEC and the FCR */
179     FLASH->CR |= FLASH_CR_LOCK;
180 }