1 /*!
2  * @file        apm32f4xx_fmc.c
3  *
4  * @brief       This file provides all the FMC firmware functions
5  *
6  * @version     V1.0.2
7  *
8  * @date        2022-06-23
9  *
10  * @attention
11  *
12  *  Copyright (C) 2021-2022 Geehy Semiconductor
13  *
14  *  You may not use this file except in compliance with the
15  *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
16  *
17  *  The program is only for reference, which is distributed in the hope
18  *  that it will be usefull and instructional for customers to develop
19  *  their software. Unless required by applicable law or agreed to in
20  *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
21  *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
23  *  and limitations under the License.
24  */
25 
26 #include "apm32f4xx_fmc.h"
27 #include "apm32f4xx_rcm.h"
28 
29 /** @addtogroup APM32F4xx_StdPeriphDriver
30   @{
31 */
32 
33 /** @defgroup FMC_Driver
34   * @brief FMC driver modules
35   @{
36 */
37 
38 /** @defgroup FMC_Functions
39   @{
40 */
41 
42 /*!
43  * @brief     Configs the code latency value.
44  *
45  * @param     latency: the FMC Latency value.
46  *            This parameter can be one of the following values:
47  *            @arg FMC_LTNCY_0: FMC 0 Latency cycle
48  *            @arg FMC_LTNCY_1: FMC 1 Latency cycle
49  *            @arg FMC_LTNCY_2: FMC 2 Latency cycles
50  *            @arg FMC_LTNCY_3: FMC 3 Latency cycles
51  *            @arg FMC_LTNCY_4: FMC 4 Latency cycles
52  *            @arg FMC_LTNCY_5: FMC 5 Latency cycles
53  *            @arg FMC_LTNCY_6: FMC 6 Latency cycles
54  *            @arg FMC_LTNCY_7: FMC 7 Latency cycles
55  *
56  * @retval    None
57  */
FMC_ConfigLatency(FMC_LATENCY_T latency)58 void FMC_ConfigLatency(FMC_LATENCY_T latency)
59 {
60     *(__IO uint8_t *)ACCTRL_BYTE0_ADDRESS = (uint8_t)latency;
61 }
62 
63 /*!
64  * @brief     Enable the Prefetch Buffer.
65  *
66  * @param     None
67  *
68  * @retval    None
69  */
FMC_EnablePrefetchBuffer(void)70 void FMC_EnablePrefetchBuffer(void)
71 {
72     FMC->ACCTRL |= FMC_ACCTRL_PREFEN;
73 }
74 
75 /*!
76  * @brief     Disable the Prefetch Buffer.
77  *
78  * @param     None
79  *
80  * @retval    None
81  */
FMC_DisablePrefetchBuffer(void)82 void FMC_DisablePrefetchBuffer(void)
83 {
84     FMC->ACCTRL &= (~FMC_ACCTRL_PREFEN);
85 }
86 
87 /*!
88  * @brief     Enable the Instruction Cache feature.
89  *
90  * @param     None
91  *
92  * @retval    None
93  */
FMC_EnableInstructionCache(void)94 void FMC_EnableInstructionCache(void)
95 {
96     FMC->ACCTRL |= FMC_ACCTRL_ICACHEEN;
97 }
98 
99 /*!
100  * @brief     Disable the Instruction Cache feature.
101  *
102  * @param     None
103  *
104  * @retval    None
105  */
FMC_DisableInstructionCache(void)106 void FMC_DisableInstructionCache(void)
107 {
108     FMC->ACCTRL &= (~FMC_ACCTRL_ICACHEEN);
109 }
110 
111 /*!
112  * @brief     Enable the Data Cache feature.
113  *
114  * @param     None
115  *
116  * @retval    None
117  */
FMC_EnableDataCache(void)118 void FMC_EnableDataCache(void)
119 {
120     FMC->ACCTRL |= FMC_ACCTRL_DCACHEEN;
121 }
122 
123 /*!
124  * @brief     Disable the Data Cache feature.
125  *
126  * @param     None
127  *
128  * @retval    None
129  */
FMC_DisableDataCache(void)130 void FMC_DisableDataCache(void)
131 {
132     FMC->ACCTRL &= (~FMC_ACCTRL_DCACHEEN);
133 }
134 
135 /*!
136  * @brief     Reset the Instruction Cache feature.
137  *
138  * @param     None
139  *
140  * @retval    None
141  */
FMC_ResetInstructionCache(void)142 void FMC_ResetInstructionCache(void)
143 {
144     FMC->ACCTRL |= FMC_ACCTRL_ICACHERST;
145 }
146 
147 /*!
148  * @brief     Reset the Data Cache feature.
149  *
150  * @param     None
151  *
152  * @retval    None
153  */
FMC_ResetDataCache(void)154 void FMC_ResetDataCache(void)
155 {
156     FMC->ACCTRL |= FMC_ACCTRL_DCACHERST;
157 }
158 
159 /*!
160  * @brief     Unlocks the FMC control register access.
161  *
162  * @param     None
163  *
164  * @retval    None
165  */
FMC_Unlock(void)166 void FMC_Unlock(void)
167 {
168     if ((FMC->CTRL & FMC_CTRL_LOCK) != RESET)
169     {
170         FMC->KEY = FMC_KEY1;
171         FMC->KEY = FMC_KEY2;
172     }
173 }
174 
175 /*!
176  * @brief     Locks the FMC control register access.
177  *
178  * @param     None
179  *
180  * @retval    None
181  */
FMC_Lock(void)182 void FMC_Lock(void)
183 {
184     FMC->CTRL |= FMC_CTRL_LOCK;
185 }
186 
187 /*!
188  * @brief     Erases a specified FMC Sector.
189  *
190  * @param     sector: The Sector number to be erased.
191  *            This parameter can be a value between FMC_SECTOR_0 and FMC_SECTOR_11.
192  *
193  * @param     voltageRange: The device voltage range which defines the erase parallelism.
194  *            This parameter can be one of the following values:
195  *              @arg FMC_VOLTAGE_1: when the device voltage range is 1.8V to 2.1V,
196  *                                  the operation will be done by byte (8-bit)
197  *              @arg FMC_VOLTAGE_2: when the device voltage range is 2.1V to 2.7V,
198  *                                  the operation will be done by half word (16-bit)
199  *              @arg FMC_VOLTAGE_3: when the device voltage range is 2.7V to 3.6V,
200  *                                  the operation will be done by word (32-bit)
201  *              @arg FMC_VOLTAGE_4: when the device voltage range is 2.7V to 3.6V + External Vpp,
202  *                                  the operation will be done by double word (64-bit)
203  *
204  * @retval    FMC_STATUS_T: The returned value can be:
205  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
206  */
FMC_EraseSector(FMC_SECTOR_T sector,FMC_VOLTAGE_T voltageRange)207 FMC_STATUS_T FMC_EraseSector(FMC_SECTOR_T sector, FMC_VOLTAGE_T voltageRange)
208 {
209     uint32_t tmp_psize = 0x00;
210     FMC_STATUS_T status = FMC_COMPLETE;
211 
212     if (voltageRange == FMC_VOLTAGE_1)
213     {
214         tmp_psize = FMC_PSIZE_BYTE;
215     }
216     else if (voltageRange == FMC_VOLTAGE_2)
217     {
218         tmp_psize = FMC_PSIZE_HALF_WORD;
219     }
220     else if (voltageRange == FMC_VOLTAGE_3)
221     {
222         tmp_psize = FMC_PSIZE_WORD;
223     }
224     else if (voltageRange == FMC_VOLTAGE_4)
225     {
226         tmp_psize = FMC_PSIZE_DOUBLE_WORD;
227     }
228 
229     status = FMC_WaitForLastOperation();
230 
231     if (status == FMC_COMPLETE)
232     {
233         FMC->CTRL &= 0xFFFFFCFF;
234         FMC->CTRL |= tmp_psize;
235         FMC->CTRL &= 0xFFFFFF07;
236         FMC->CTRL |= FMC_CTRL_SERS | sector;
237         FMC->CTRL |= FMC_CTRL_START;
238         status = FMC_WaitForLastOperation();
239         FMC->CTRL &= (~FMC_CTRL_SERS);
240         FMC->CTRL &= 0xFFFFFF07;
241     }
242 
243     return status;
244 }
245 
246 /*!
247  * @brief     Clears all FMC Sectors.
248  *
249  * @param     voltageRange: The device voltage range which defines the erase parallelism.
250  *            This parameter can be one of the following values:
251  *              @arg FMC_VOLTAGE_1: when the device voltage range is 1.8V to 2.1V,
252  *                                  the operation will be done by byte (8-bit)
253  *              @arg FMC_VOLTAGE_2: when the device voltage range is 2.1V to 2.7V,
254  *                                  the operation will be done by half word (16-bit)
255  *              @arg FMC_VOLTAGE_3: when the device voltage range is 2.7V to 3.6V,
256  *                                  the operation will be done by word (32-bit)
257  *              @arg FMC_VOLTAGE_4: when the device voltage range is 2.7V to 3.6V + External Vpp,
258  *                                  the operation will be done by double word (64-bit)
259  *
260  * @retval    FMC_STATUS_T: The returned value can be:
261  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
262  */
FMC_EraseAllSectors(FMC_VOLTAGE_T voltageRange)263 FMC_STATUS_T FMC_EraseAllSectors(FMC_VOLTAGE_T voltageRange)
264 {
265     uint32_t tmp_psize = 0x00;
266     FMC_STATUS_T status = FMC_COMPLETE;
267     status = FMC_WaitForLastOperation();
268 
269     if (voltageRange == FMC_VOLTAGE_1)
270     {
271         tmp_psize = FMC_PSIZE_BYTE;
272     }
273     else if (voltageRange == FMC_VOLTAGE_2)
274     {
275         tmp_psize = FMC_PSIZE_HALF_WORD;
276     }
277     else if (voltageRange == FMC_VOLTAGE_3)
278     {
279         tmp_psize = FMC_PSIZE_WORD;
280     }
281     else if (voltageRange == FMC_VOLTAGE_4)
282     {
283         tmp_psize = FMC_PSIZE_DOUBLE_WORD;
284     }
285 
286     if (status == FMC_COMPLETE)
287     {
288         FMC->CTRL &= 0xFFFFFCFF;
289         FMC->CTRL |= tmp_psize;
290         FMC->CTRL |= FMC_CTRL_MERS;
291         FMC->CTRL |= FMC_CTRL_START;
292         status = FMC_WaitForLastOperation();
293         FMC->CTRL &= (~FMC_CTRL_MERS);
294     }
295 
296     return status;
297 }
298 
299 /*!
300  * @brief     Programs a double word (64-bit) at a specified address.
301  *
302  * @param     address:the address to be programmed.
303  *            ((address) >= 0x08000000) && ((address) <= 0x080FFFFF))
304  *            ((address) >= 0x1FFF7800) && ((address) <= 0x1FFF7A0F)))
305  *
306  * @param     data: the data to be programmed.
307  *
308  * @retval    FMC_STATUS_T: The returned value can be:
309  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
310  */
FMC_ProgramDoubleWord(uint32_t address,uint64_t data)311 FMC_STATUS_T FMC_ProgramDoubleWord(uint32_t address, uint64_t data)
312 {
313     FMC_STATUS_T status = FMC_COMPLETE;
314     status = FMC_WaitForLastOperation();
315 
316     if (status == FMC_COMPLETE)
317     {
318         FMC->CTRL &= 0xFFFFFCFF;
319         FMC->CTRL |= FMC_PSIZE_DOUBLE_WORD;
320         FMC->CTRL |= FMC_CTRL_PG;
321         *(__IO uint64_t *)address = data;
322         status = FMC_WaitForLastOperation();
323         FMC->CTRL &= (~FMC_CTRL_PG);
324     }
325 
326     return status;
327 }
328 
329 /*!
330  * @brief     Programs a word (32-bit) at a specified address.
331  *
332  * @param     address:the address to be programmed.
333  *            ((address) >= 0x08000000) && ((address) <= 0x080FFFFF))
334  *            ((address) >= 0x1FFF7800) && ((address) <= 0x1FFF7A0F)))
335  *
336  * @param     data: the data to be programmed.
337  *
338  * @retval    FMC_STATUS_T: The returned value can be:
339  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
340  */
341 
FMC_ProgramWord(uint32_t address,uint32_t data)342 FMC_STATUS_T FMC_ProgramWord(uint32_t address, uint32_t data)
343 {
344     FMC_STATUS_T status = FMC_COMPLETE;
345     status = FMC_WaitForLastOperation();
346 
347     if (status == FMC_COMPLETE)
348     {
349         FMC->CTRL &= 0xFFFFFCFF;
350         FMC->CTRL |= FMC_PSIZE_WORD;
351         FMC->CTRL |= FMC_CTRL_PG;
352         *(__IO uint32_t *)address = data;
353         status = FMC_WaitForLastOperation();
354         FMC->CTRL &= (~FMC_CTRL_PG);
355     }
356 
357     return status;
358 }
359 
360 /*!
361  * @brief     Programs a half word (16-bit) at a specified address.
362  *
363  * @param     address:the address to be programmed.
364  *            ((address) >= 0x08000000) && ((address) <= 0x080FFFFF))
365  *            ((address) >= 0x1FFF7800) && ((address) <= 0x1FFF7A0F)))
366  *
367  * @param     data: the data to be programmed.
368  *
369  * @retval    FMC_STATUS_T: The returned value can be:
370  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
371  */
FMC_ProgramHalfWord(uint32_t address,uint16_t data)372 FMC_STATUS_T FMC_ProgramHalfWord(uint32_t address, uint16_t data)
373 {
374     FMC_STATUS_T status = FMC_COMPLETE;
375     status = FMC_WaitForLastOperation();
376 
377     if (status == FMC_COMPLETE)
378     {
379         FMC->CTRL &= 0xFFFFFCFF;
380         FMC->CTRL |= FMC_PSIZE_HALF_WORD;
381         FMC->CTRL |= FMC_CTRL_PG;
382         *(__IO uint16_t *)address = data;
383         status = FMC_WaitForLastOperation();
384         FMC->CTRL &= (~FMC_CTRL_PG);
385     }
386 
387     return status;
388 }
389 
390 /*!
391  * @brief     Programs a byte (8-bit) at a specified address.
392  *
393  * @param     address:the address to be programmed.
394  *            ((address) >= 0x08000000) && ((address) <= 0x080FFFFF))
395  *            ((address) >= 0x1FFF7800) && ((address) <= 0x1FFF7A0F)))
396  *
397  * @param     data: the data to be programmed.
398  *
399  * @retval    FMC_STATUS_T: The returned value can be:
400  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
401  */
FMC_ProgramByte(uint32_t address,uint8_t data)402 FMC_STATUS_T FMC_ProgramByte(uint32_t address, uint8_t data)
403 {
404     FMC_STATUS_T status = FMC_COMPLETE;
405     status = FMC_WaitForLastOperation();
406 
407     if (status == FMC_COMPLETE)
408     {
409         FMC->CTRL &= 0xFFFFFCFF;
410         FMC->CTRL |= FMC_PSIZE_BYTE;
411         FMC->CTRL |= FMC_CTRL_PG;
412         *(__IO uint8_t *)address = data;
413         status = FMC_WaitForLastOperation();
414         FMC->CTRL &= (~FMC_CTRL_PG);
415     }
416 
417     return status;
418 }
419 
420 /*!
421  * @brief     Unlocks the option bytes block access
422  *
423  * @param     None
424  *
425  * @retval    None
426  */
FMC_UnlockOptionByte(void)427 void FMC_UnlockOptionByte(void)
428 {
429     if ((FMC->OPTCTRL & FMC_OPTCTRL_OPTLOCK) != RESET)
430     {
431         FMC->OPTKEY = FMC_OPT_KEY1;
432         FMC->OPTKEY = FMC_OPT_KEY2;
433     }
434 }
435 
436 /*!
437  * @brief     Locks the option bytes block access
438  *
439  * @param     None
440  *
441  * @retval    None
442  */
FMC_LockOptionByte(void)443 void FMC_LockOptionByte(void)
444 {
445     FMC->OPTCTRL |= FMC_OPTCTRL_OPTLOCK;
446 }
447 
448 /*!
449  * @brief     Enable the write protection of the desired sectors,
450  *            for the first 1 Mb of the FMC
451  *
452  * @param     wrp: specifies the sector(s) to be write protected or unprotected.
453  *            This parameter can be one of the following values:
454  *              @arg wrp: The value between FMC_OPT_WRP_SECTOR_0 and FMC_OPT_WRP_SECTOR_11
455  *              @arg FMC_OPT_WRP_SECTOR_All
456  *
457  * @retval    None
458  */
FMC_OPT_EnableWriteProtect(FMC_OPT_WRP_T wrp)459 void FMC_OPT_EnableWriteProtect(FMC_OPT_WRP_T wrp)
460 {
461     FMC_STATUS_T status = FMC_COMPLETE;
462     status = FMC_WaitForLastOperation();
463 
464     if (status == FMC_COMPLETE)
465     {
466         *(__IO uint16_t *)(OPTCTRL_BYTE2_ADDRESS) &= (~(uint16_t)wrp);
467     }
468 }
469 
470 /*!
471  * @brief     Disable the write protection of the desired sectors,
472  *            for the first 1 Mb of the FMC
473  *
474  * @param     wrp: Specifies the sector(s) to be write protected or unprotected.
475  *            This parameter can be one of the following values:
476  *              @arg wrp: The value between FMC_OPT_WRP_SECTOR_0 and FMC_OPT_WRP_SECTOR_11
477  *              @arg FMC_OPT_WRP_SECTOR_All
478  *
479  * @retval    None
480  */
FMC_OPT_DisableWriteProtect(FMC_OPT_WRP_T wrp)481 void FMC_OPT_DisableWriteProtect(FMC_OPT_WRP_T wrp)
482 {
483     FMC_STATUS_T status = FMC_COMPLETE;
484     status = FMC_WaitForLastOperation();
485 
486     if (status == FMC_COMPLETE)
487     {
488         *(__IO uint16_t *)(OPTCTRL_BYTE2_ADDRESS) |= (uint16_t)wrp;
489     }
490 }
491 /*!
492  * @brief     Sets the read protection level.
493  *
494  * @param     rdp: Specifies the read protection level.
495  *            This parameter can be one of the following values:
496  *              @arg FMC_OPT_RDP_LV0: No protection
497  *              @arg FMC_OPT_RDP_LV1: Read protection of the memory
498  *
499  * @retval    None
500  */
FMC_OPT_ConfigReadProtect(FMC_OPT_RDP_T rdp)501 void FMC_OPT_ConfigReadProtect(FMC_OPT_RDP_T rdp)
502 {
503     FMC_STATUS_T status = FMC_COMPLETE;
504     status = FMC_WaitForLastOperation();
505 
506     if (status == FMC_COMPLETE)
507     {
508         *(__IO uint8_t *)OPTCTRL_BYTE1_ADDRESS = rdp;
509     }
510 }
511 
512 /*!
513  * @brief     Programs the FMC User Option Byte: WDTSEL / RSTSTOP / RSTSTDB.
514  *
515  * @param     iwdt: Selects the IWDT mode
516  *            This parameter can be one of the following values:
517  *              @arg FMC_OPT_IWDT_SOFT: Software IWDT selected
518  *              @arg FMC_OPT_IWDT_HARD: Hardware IWDT selected
519  * @param     stop: Reset event when entering STOP mode.
520  *            This parameter  can be one of the following values:
521  *              @arg FMC_OPT_STOP_NORST: No reset generated when entering in STOP
522  *              @arg FMC_OPT_STOP_RST: Reset generated when entering in STOP
523  * @param     stdby: Reset event when entering Standby mode.
524  *            This parameter  can be one of the following values:
525  *              @arg FMC_OPT_STDBY_NORST: No reset generated when entering in STANDBY
526  *              @arg FMC_OPT_STDBY_RST: Reset generated when entering in STANDBY
527  *
528  * @retval    None
529  */
FMC_OPT_ConfigUser(FMC_OPT_IWDT_T iwdt,FMC_OPT_STOP_T stop,FMC_OPT_STDBY_T stdby)530 void FMC_OPT_ConfigUser(FMC_OPT_IWDT_T iwdt, FMC_OPT_STOP_T stop, FMC_OPT_STDBY_T stdby)
531 {
532     uint8_t option = 0xFF;
533     FMC_STATUS_T status = FMC_COMPLETE;
534     status = FMC_WaitForLastOperation();
535 
536     if (status == FMC_COMPLETE)
537     {
538         option = (uint8_t)((*(__IO uint8_t *)OPTCTRL_BYTE0_ADDRESS) & 0x0F);
539         *(__IO uint8_t *)OPTCTRL_BYTE0_ADDRESS = ((uint8_t)iwdt | stop | stdby | option);
540     }
541 }
542 
543 /*!
544  * @brief     Sets the Brownout Reset Level.
545  *
546  * @param     bor: specifies the Option Bytes BOR Reset Level.
547  *            This parameter can be one of the following values:
548  *              @arg FMC_OPT_BOR_LV3: Supply voltage ranges from 2.7 to 3.6 V
549  *              @arg FMC_OPT_BOR_LV2: Supply voltage ranges from 2.4 to 2.7 V
550  *              @arg FMC_OPT_BOR_LV1: Supply voltage ranges from 2.1 to 2.4 V
551  *              @arg FMC_OPT_BOR_OFF: Supply voltage ranges from 1.62 to 2.1 V
552  *
553  * @retval    None
554  */
FMC_OPT_ConfigBrownoutReset(FMC_OPT_BOR_T bor)555 void FMC_OPT_ConfigBrownoutReset(FMC_OPT_BOR_T bor)
556 {
557     *(__IO uint8_t *)(OPTCTRL_BYTE0_ADDRESS) &= (~(FMC_OPTCTRL_BORLVL));
558     *(__IO uint8_t *)(OPTCTRL_BYTE0_ADDRESS) |= bor;
559 }
560 
561 /*!
562  * @brief     Launch the option byte loading.
563  *
564  * @param     None
565  *
566  * @retval    FMC_STATUS_T: The returned value can be:
567  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
568  */
FMC_OPT_Launch(void)569 FMC_STATUS_T FMC_OPT_Launch(void)
570 {
571     FMC_STATUS_T status = FMC_COMPLETE;
572 
573     *(__IO uint8_t *)(OPTCTRL_BYTE0_ADDRESS) |= (uint32_t)FMC_OPTCTRL_OPTSTART;
574     status = FMC_WaitForLastOperation();
575 
576     return status;
577 }
578 
579 /*!
580  * @brief     Returns the FMC User Option Bytes values.
581  *
582  * @param     None
583  *
584  * @retval    The FMC User Option Bytes values: WDTSEL(Bit0), RSTSTOP(Bit1)
585  *            and RSTSTDBY(Bit2).
586  */
FMC_OPT_ReadUser(void)587 uint8_t FMC_OPT_ReadUser(void)
588 {
589     return (uint8_t)(FMC->OPTCTRL >> 5);
590 }
591 
592 /*!
593  * @brief     Returns the FMC Write Protection Option Bytes value.
594  *
595  * @param     None
596  *
597  * @retval    The FMC Write Protection Option Bytes value
598  */
FMC_OPT_ReadWriteProtect(void)599 uint16_t FMC_OPT_ReadWriteProtect(void)
600 {
601     return (*(__IO uint16_t *)(OPTCTRL_BYTE2_ADDRESS));
602 }
603 
604 /*!
605  * @brief     Returns the FMC Read Protection level.
606  *
607  * @param     None
608  *
609  * @retval    tmp: ReadOut Protection Status:
610  *                 - SET, when FMC_OPT_RDP_LV1 is set
611  *                 - RESET, when FMC_OPT_RDP_LV0 is set
612  */
FMC_OPT_ReadProtectLevel(void)613 uint8_t FMC_OPT_ReadProtectLevel(void)
614 {
615     uint8_t tmp = RESET;
616 
617     if ((*(__IO uint8_t *)((OPTCTRL_BYTE1_ADDRESS)) != (uint8_t)FMC_OPT_RDP_LV0))
618     {
619         tmp = SET;
620     }
621 
622     return tmp;
623 }
624 
625 /*!
626  * @brief     Returns the FMC BOR level.
627  *
628  * @param     None
629  *
630  * @retval    The FMC BOR level:
631  *              - FMC_OPT_BOR_LV1: Supply voltage ranges from 2.7 to 3.6 V
632  *              - FMC_OPT_BOR_LV1: Supply voltage ranges from 2.4 to 2.7 V
633  *              - FMC_OPT_BOR_LV1: Supply voltage ranges from 2.1 to 2.4 V
634  *              - FMC_OPT_BOR_OFF   : Supply voltage ranges from 1.62 to 2.1 V
635  */
FMC_OPT_ReadBrownoutReset(void)636 uint8_t FMC_OPT_ReadBrownoutReset(void)
637 {
638     return (uint8_t)(*(__IO uint8_t *)((OPTCTRL_BYTE0_ADDRESS)) & FMC_OPT_BOR_OFF);
639 }
640 
641 /*!
642  * @brief     Enables the specified FMC interrupts.
643  *
644  * @param     interrupt: Select the FMC interrupt sources
645  *                       This parameter can be any combination of the following values:
646  *                       @arg FMC_INT_ERR :  Error Interrupt
647  *                       @arg FMC_INT_OC  :  Operation Complete Interrupt
648  *
649  * @retval    None
650  */
FMC_EnableInterrupt(uint32_t interrupt)651 void FMC_EnableInterrupt(uint32_t interrupt)
652 {
653     if (interrupt == FMC_INT_ERR)
654     {
655         FMC->CTRL |= FMC_INT_ERR;
656     }
657     else
658     {
659         FMC->CTRL |= FMC_INT_OC;
660     }
661 }
662 
663 /*!
664  * @brief     Disable the specified FMC interrupts.
665  *
666  * @param     interrupt: Select the FMC interrupt sources
667  *                       This parameter can be any combination of the following values:
668  *                       @arg FMC_INT_ERR :  Error Interrupt
669  *                       @arg FMC_INT_OC  :  Operation Complete Interrupt
670  *
671  * @retval    None
672  */
FMC_DisableInterrupt(uint32_t interrupt)673 void FMC_DisableInterrupt(uint32_t interrupt)
674 {
675     if (interrupt == FMC_INT_ERR)
676     {
677         FMC->CTRL &= ~(uint32_t)FMC_INT_ERR;
678     }
679     else
680     {
681         FMC->CTRL &= ~(uint32_t)FMC_INT_OC;
682     }
683 }
684 
685 /*!
686  * @brief     Read the FMC flag
687  *
688  * @param     flag: specifies the FMC flag to check.
689  *            This parameter can be one of the following values:
690  *              @arg FMC_FLAG_ENDOP  : FMC End of Operation flag
691  *              @arg FMC_FLAG_ERROP  : FMC operation Error flag
692  *              @arg FMC_FLAG_ERRWRP : FMC Write protected error flag
693  *              @arg FMC_FLAG_ERRPGA : FMC Programming Alignment error flag
694  *              @arg FMC_FLAG_ERRPGP : FMC Programming Parallelism error flag
695  *              @arg FMC_FLAG_ERRPGS : FMC Programming Sequence error flag
696  *              @arg FMC_FLAG_BUSY   : FMC Busy flag
697  *
698  * @retval    SET or RESET.
699  */
FMC_ReadStatusFlag(FMC_FLAG_T flag)700 uint8_t FMC_ReadStatusFlag(FMC_FLAG_T flag)
701 {
702     uint8_t temp = RESET;
703 
704     if ((FMC->STS & flag) != (uint32_t)RESET)
705     {
706         temp = SET;
707     }
708 
709     return temp;
710 }
711 
712 /*!
713  * @brief     Clears the FMC flag.
714  *
715  * @param     flag: specifies the FMC flags to clear.
716  *            This parameter can be any combination of the following values:
717  *              @arg FMC_FLAG_ENDOP  : FMC End of Operation flag
718  *              @arg FMC_FLAG_ERROP  : FMC operation Error flag
719  *              @arg FMC_FLAG_ERRWRP : FMC Write protected error flag
720  *              @arg FMC_FLAG_ERRPGA : FMC Programming Alignment error flag
721  *              @arg FMC_FLAG_ERRPGP : FMC Programming Parallelism error flag
722  *              @arg FMC_FLAG_ERRPGS : FMC Programming Sequence error flag
723  *
724  * @retval    None
725  */
FMC_ClearStatusFlag(uint32_t flag)726 void FMC_ClearStatusFlag(uint32_t flag)
727 {
728     FMC->STS = flag;
729 }
730 
731 /*!
732  * @brief     Returns the FMC Status.
733  *
734  * @param     None
735  *
736  * @retval    FMC_STATUS_T: The returned value can be:
737  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
738  */
FMC_ReadStatus(void)739 FMC_STATUS_T FMC_ReadStatus(void)
740 {
741     FMC_STATUS_T status = FMC_COMPLETE;
742 
743     if ((FMC->STS & FMC_FLAG_BUSY) == FMC_FLAG_BUSY)
744     {
745         status = FMC_BUSY;
746     }
747     else if ((FMC->STS & FMC_FLAG_ERRWRP) != RESET)
748     {
749         status = FMC_ERROR_WRP;
750     }
751     else if ((FMC->STS & (uint32_t)0xE0) != RESET)
752     {
753         status = FMC_ERROR_PROGRAM;
754     }
755     else if ((FMC->STS & FMC_FLAG_ERROP) != RESET)
756     {
757         status = FMC_ERROR_OPERATION;
758     }
759     else
760     {
761         status = FMC_COMPLETE;
762     }
763 
764     return status;
765 }
766 
767 /*!
768  * @brief     Waits for a FMC operation to complete.
769  *
770  * @param     None
771  *
772  * @retval    FMC_STATUS_T: The returned value can be:
773  *            FMC_BUSY, FMC_ERROR_PROGRAM, FMC_ERROR_WRP, FMC_ERROR_OPERATION or FMC_COMPLETE.
774  */
FMC_WaitForLastOperation(void)775 FMC_STATUS_T FMC_WaitForLastOperation(void)
776 {
777     __IO FMC_STATUS_T status = FMC_COMPLETE;
778 
779     status = FMC_ReadStatus();
780 
781     while (status == FMC_BUSY)
782     {
783         status = FMC_ReadStatus();
784     }
785 
786     return status;
787 }
788 
789 /**@} end of group FMC_Functions */
790 /**@} end of group FMC_Driver */
791 /**@} end of group APM32F4xx_StdPeriphDriver */
792