1 /*!
2 \file gd32l23x_fmc.c
3 \brief FMC driver
4
5 \version 2021-08-04, V1.0.0, firmware for GD32L23x
6 */
7
8 /*
9 Copyright (c) 2021, GigaDevice Semiconductor Inc.
10
11 Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13
14 1. Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 3. Neither the name of the copyright holder nor the names of its contributors
20 may be used to endorse or promote products derived from this software without
21 specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34
35 #include "gd32l23x_fmc.h"
36
37 /* FMC mask */
38 #define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
39 #define HIGH_8BITS_MASK ((uint32_t)0x0000FF00U)
40 #define LOW_8BITS_MASK1 ((uint32_t)0x00FF0000U)
41 #define HIGH_8BITS_MASK1 ((uint32_t)0xFF000000U)
42 #define LOW_16BITS_MASK ((uint32_t)0x0000FFFFU)
43 #define HIGH_16BITS_MASK ((uint32_t)0xFFFF0000U)
44
45 /* USER of option bytes mask */
46 #define OB_USER_MASK ((uint8_t)0x18U)
47
48 /* default offset */
49 #define FMC_OBSTAT_USER_OFFSET 2U
50 #define FMC_OBSTAT_DATA_OFFSET 10U
51
52 /* return the FMC state */
53 static fmc_state_enum fmc_state_get(void);
54 /* check FMC ready or not */
55 static fmc_state_enum fmc_ready_wait(uint32_t timeout);
56
57 /*!
58 \brief unlock the main FMC operation
59 it is better to used in pairs with fmc_lock
60 \param[in] none
61 \param[out] none
62 \retval none
63 */
fmc_unlock(void)64 void fmc_unlock(void)
65 {
66 if(RESET != (FMC_CTL & FMC_CTL_LK)) {
67 /* write the FMC unlock key */
68 FMC_KEY = UNLOCK_KEY0;
69 FMC_KEY = UNLOCK_KEY1;
70 }
71 }
72
73 /*!
74 \brief lock the main FMC operation
75 it is better to used in pairs with fmc_unlock after an operation
76 \param[in] none
77 \param[out] none
78 \retval none
79 */
fmc_lock(void)80 void fmc_lock(void)
81 {
82 /* set the LK bit */
83 FMC_CTL |= FMC_CTL_LK;
84 }
85
86 /*!
87 \brief unlock operation of RUN_SLP bit in FMC_WS register
88 \param[in] none
89 \param[out] none
90 \retval none
91 */
fmc_slp_unlock(void)92 void fmc_slp_unlock(void)
93 {
94 /* write the FMC sleep or power-down mode unlock key */
95 FMC_SLPKEY = SLP_UNLOCK_KEY0;
96 FMC_SLPKEY = SLP_UNLOCK_KEY1;
97 }
98
99 /*!
100 \brief set the wait state
101 \param[in] wscnt: wait state
102 only one parameter can be selected which is shown as below:
103 \arg FMC_WAIT_STATE_0: 0 wait state added
104 \arg FMC_WAIT_STATE_1: 1 wait state added
105 \arg FMC_WAIT_STATE_2: 2 wait state added
106 \arg FMC_WAIT_STATE_3: 3 wait state added
107 \param[out] none
108 \retval none
109 */
fmc_wscnt_set(uint32_t wscnt)110 void fmc_wscnt_set(uint32_t wscnt)
111 {
112 uint32_t ws;
113
114 ws = FMC_WS;
115
116 /* set the wait state counter value */
117 ws &= ~FMC_WS_WSCNT;
118 FMC_WS = (ws | wscnt);
119 }
120
121 /*!
122 \brief enable pre-fetch
123 \param[in] none
124 \param[out] none
125 \retval none
126 */
fmc_prefetch_enable(void)127 void fmc_prefetch_enable(void)
128 {
129 FMC_WS |= FMC_WS_PFEN;
130 }
131
132 /*!
133 \brief disable pre-fetch
134 \param[in] none
135 \param[out] none
136 \retval none
137 */
fmc_prefetch_disable(void)138 void fmc_prefetch_disable(void)
139 {
140 FMC_WS &= ~FMC_WS_PFEN;
141 }
142
143 /*!
144 \brief enable low power
145 \param[in] none
146 \param[out] none
147 \retval none
148 */
fmc_low_power_enable(void)149 void fmc_low_power_enable(void)
150 {
151 FMC_WS |= FMC_WS_LVE;
152 }
153
154 /*!
155 \brief disable low power
156 \param[in] none
157 \param[out] none
158 \retval none
159 */
fmc_low_power_disable(void)160 void fmc_low_power_disable(void)
161 {
162 FMC_WS &= ~FMC_WS_LVE;
163 }
164
165 /*!
166 \brief flash enter sleep/power-down mode during MCU run/low-power run mode
167 \param[in] none
168 \param[out] none
169 \retval none
170 */
fmc_enter_slp_enable(void)171 void fmc_enter_slp_enable(void)
172 {
173 FMC_WS |= FMC_WS_RUN_SLP;
174 }
175
176 /*!
177 \brief flash enter IDLE mode during MCU run/low-power run mode
178 \param[in] none
179 \param[out] none
180 \retval none
181 */
fmc_enter_slp_disable(void)182 void fmc_enter_slp_disable(void)
183 {
184 FMC_WS &= ~FMC_WS_RUN_SLP;
185 }
186
187 /*!
188 \brief flash enter sleep mode when MCU enter deep-sleep mode or RUN_SLP bit is set
189 \param[in] none
190 \param[out] none
191 \retval none
192 */
fmc_enter_sleep_enable(void)193 void fmc_enter_sleep_enable(void)
194 {
195 FMC_WS |= FMC_WS_SLEEP_SLP;
196 }
197
198 /*!
199 \brief flash enter power-down mode when MCU enter deep-sleep mode or RUN_SLP bit is set
200 \param[in] none
201 \param[out] none
202 \retval none
203 */
fmc_enter_sleep_disable(void)204 void fmc_enter_sleep_disable(void)
205 {
206 FMC_WS &= ~FMC_WS_SLEEP_SLP;
207 }
208
209 /*!
210 \brief FMC erase page
211 \param[in] page_address: target page address
212 \param[out] none
213 \retval state of FMC, refer to fmc_state_enum
214 */
fmc_page_erase(uint32_t page_address)215 fmc_state_enum fmc_page_erase(uint32_t page_address)
216 {
217 fmc_state_enum fmc_state;
218
219 /* wait for the FMC ready */
220 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
221
222 if(FMC_READY == fmc_state) {
223 /* start page erase */
224 FMC_CTL |= FMC_CTL_PER;
225 FMC_ADDR = page_address;
226 FMC_CTL |= FMC_CTL_START;
227 /* wait for the FMC ready */
228 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
229 /* reset the PER bit */
230 FMC_CTL &= ~FMC_CTL_PER;
231 }
232 /* return the FMC state */
233 return fmc_state;
234 }
235
236 /*!
237 \brief FMC erase whole chip
238 \param[in] none
239 \param[out] none
240 \retval state of FMC, refer to fmc_state_enum
241 */
fmc_mass_erase(void)242 fmc_state_enum fmc_mass_erase(void)
243 {
244 fmc_state_enum fmc_state;
245
246 /* wait for the FMC ready */
247 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
248
249 if(FMC_READY == fmc_state) {
250 /* start chip erase */
251 FMC_CTL |= FMC_CTL_MER;
252 FMC_CTL |= FMC_CTL_START;
253 /* wait for the FMC ready */
254 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
255 /* reset the MER bit */
256 FMC_CTL &= ~FMC_CTL_MER;
257 }
258 /* return the FMC state */
259 return fmc_state;
260 }
261
262 /*!
263 \brief FMC program a word at the corresponding address
264 \param[in] address: address to program
265 \param[in] data: word to program
266 \param[out] none
267 \retval state of FMC, refer to fmc_state_enum
268 */
fmc_word_program(uint32_t address,uint32_t data)269 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
270 {
271 fmc_state_enum fmc_state;
272
273 /* wait for the FMC ready */
274 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
275
276 if(FMC_READY == fmc_state) {
277 /* set the PG bit to start program */
278 FMC_CTL |= FMC_CTL_PG;
279 REG32(address) = data;
280 /* wait for the FMC ready */
281 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
282 /* reset the PG bit */
283 FMC_CTL &= ~FMC_CTL_PG;
284 }
285 /* return the FMC state */
286 return fmc_state;
287 }
288
289 /*!
290 \brief FMC fast program one row data (32 double-word) starting at the corresponding address
291 \param[in] address: starting address to program
292 \param[in] data: data buffer to program
293 \param[out] none
294 \retval state of FMC, refer to fmc_state_enum
295 */
fmc_fast_program(uint32_t address,uint64_t data[])296 fmc_state_enum fmc_fast_program(uint32_t address, uint64_t data[])
297 {
298 char index;
299 fmc_state_enum fmc_state;
300
301 /* wait for the FMC ready */
302 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
303
304 if(FMC_READY == fmc_state) {
305 /* set the FSTPG bit to start fast program */
306 FMC_CTL |= FMC_CTL_FSTPG;
307
308 /* program the row data */
309 for(index = 0U; index < DOUBLE_WORDS_CNT_IN_ROW; index++) {
310 REG64(address) = data[index];
311 address += 8U;
312 }
313
314 /* wait for the FMC ready */
315 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
316
317 /* reset the FSTPG bit */
318 FMC_CTL &= ~FMC_CTL_FSTPG;
319 }
320
321 /* return the FMC state */
322 return fmc_state;
323 }
324
325 /*!
326 \brief unlock the option bytes operation
327 it is better to used in pairs with ob_lock
328 \param[in] none
329 \param[out] none
330 \retval none
331 */
ob_unlock(void)332 void ob_unlock(void)
333 {
334 if(RESET == (FMC_CTL & FMC_CTL_OBWEN)) {
335 /* write the FMC ob unlock key */
336 FMC_OBKEY = UNLOCK_KEY0;
337 FMC_OBKEY = UNLOCK_KEY1;
338 }
339 }
340
341 /*!
342 \brief lock the option bytes operation
343 it is better to used in pairs with ob_unlock after an operation
344 \param[in] none
345 \param[out] none
346 \retval none
347 */
ob_lock(void)348 void ob_lock(void)
349 {
350 /* reset the OBWEN bit */
351 FMC_CTL &= ~FMC_CTL_OBWEN;
352 }
353
354 /*!
355 \brief erase the option bytes
356 programmer must ensure FMC & option bytes are both unlocked before calling this function
357 \param[in] none
358 \param[out] none
359 \retval state of FMC, refer to fmc_state_enum
360 */
ob_erase(void)361 fmc_state_enum ob_erase(void)
362 {
363 uint32_t temp_spc;
364 fmc_state_enum fmc_state;
365
366 /* wait for the FMC ready */
367 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
368
369 temp_spc = OB_SPC_USER;
370
371 /* check the option bytes security protection value */
372 if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))) {
373 fmc_state = FMC_OB_HSPC;
374 }
375
376 if(FMC_READY == fmc_state) {
377 /* start erase the option bytes */
378 FMC_CTL |= FMC_CTL_OBER;
379 FMC_CTL |= FMC_CTL_START;
380
381 /* wait for the FMC ready */
382 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
383
384 if(FMC_READY == fmc_state) {
385 /* reset the OBER bit and enable the option bytes programming */
386 FMC_CTL &= ~FMC_CTL_OBER;
387 /* set the OBPG bit */
388 FMC_CTL |= FMC_CTL_OBPG;
389 /* restore the last get option bytes security protection code */
390 OB_SPC_USER = (temp_spc & LOW_8BITS_MASK) | LOW_8BITS_MASK1;
391 /* wait for the FMC ready */
392 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
393
394 /* reset the OBPG bit */
395 FMC_CTL &= ~FMC_CTL_OBPG;
396 } else {
397 /* reset the OBER bit */
398 FMC_CTL &= ~FMC_CTL_OBER;
399 }
400 }
401 /* return the FMC state */
402 return fmc_state;
403 }
404
405 /*!
406 \brief enable write protection
407 programmer must ensure FMC & option bytes are both unlocked before calling this function
408 \param[in] ob_wp: specify sector to be write protected
409 only one parameter can be selected which are shown as below:
410 \arg OB_WP_NONE: disable all write protection
411 \arg OB_WP_x(x=0..31): write protect specify sector
412 \arg OB_WP_ALL: write protect all sector
413 \param[out] none
414 \retval state of FMC, refer to fmc_state_enum
415 */
ob_write_protection_enable(uint32_t ob_wp)416 fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
417 {
418 uint32_t temp_spc;
419 uint8_t i;
420 uint32_t op_byte[4];
421
422 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
423
424 temp_spc = OB_SPC_USER;
425
426 /* check the option bytes security protection value */
427 if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))) {
428 fmc_state = FMC_OB_HSPC;
429 }
430
431 for(i = 0U; i < 4U; i++) {
432 op_byte[i] = OP_BYTE(i);
433 }
434
435 ob_wp = (uint32_t)(~ob_wp);
436 op_byte[2] = (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
437 op_byte[3] = ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
438
439 if(FMC_READY == fmc_state) {
440 /* start erase the option byte */
441 FMC_CTL |= FMC_CTL_OBER;
442 FMC_CTL |= FMC_CTL_START;
443
444 /* wait for the FMC ready */
445 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
446
447 if(FMC_READY == fmc_state) {
448 /* reset the OBER bit and enable the option bytes programming */
449 FMC_CTL &= ~FMC_CTL_OBER;
450 FMC_CTL |= FMC_CTL_OBPG;
451
452 for(i = 0U; i < 4U; i++) {
453 OP_BYTE(i) = op_byte[i];
454 /* wait for the FMC ready */
455 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
456 if(FMC_READY != fmc_state) {
457 break;
458 }
459 }
460 /* reset the OBPG bit */
461 FMC_CTL &= ~FMC_CTL_OBPG;
462 } else {
463 /* reset the OBER bit */
464 FMC_CTL &= ~FMC_CTL_OBER;
465 }
466 }
467
468 /* return the FMC state */
469 return fmc_state;
470 }
471
472 /*!
473 \brief configure security protection
474 programmer must ensure FMC & option bytes are both unlocked before calling this function
475 \param[in] ob_spc: specify security protection
476 only one parameter can be selected which is shown as below:
477 \arg FMC_NSPC: no security protection
478 \arg FMC_LSPC: low security protection
479 \arg FMC_HSPC: high security protection
480 \param[out] none
481 \retval state of FMC, refer to fmc_state_enum
482 */
ob_security_protection_config(uint8_t ob_spc)483 fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
484 {
485 uint32_t temp_spc;
486 uint8_t i;
487 uint32_t op_byte[4];
488
489 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
490
491 temp_spc = OB_SPC_USER & LOW_16BITS_MASK;
492
493 /* check the option bytes security protection value */
494 if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))) {
495 fmc_state = FMC_OB_HSPC;
496 }
497
498 for(i = 0U; i < 4U; i++) {
499 op_byte[i] = OP_BYTE(i);
500 }
501 op_byte[0] = ((uint32_t)(ob_spc)) | ((op_byte[0] & HIGH_16BITS_MASK));
502
503 if(FMC_READY == fmc_state) {
504 /* start erase the option bytes */
505 FMC_CTL |= FMC_CTL_OBER;
506 FMC_CTL |= FMC_CTL_START;
507
508 /* wait for the FMC ready */
509 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
510
511 if(FMC_READY == fmc_state) {
512 /* reset the OBER bit and enable the option bytes programming */
513 FMC_CTL &= ~FMC_CTL_OBER;
514 FMC_CTL |= FMC_CTL_OBPG;
515
516 for(i = 0U; i < 4U; i++) {
517 OP_BYTE(i) = op_byte[i];
518 /* wait for the FMC ready */
519 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
520 if(FMC_READY != fmc_state) {
521 break;
522 }
523 }
524
525 /* reset the OBPG bit */
526 FMC_CTL &= ~FMC_CTL_OBPG;
527 } else {
528 /* reset the OBER bit */
529 FMC_CTL &= ~FMC_CTL_OBER;
530 }
531 }
532
533 /* return the FMC state */
534 return fmc_state;
535 }
536
537 /*!
538 \brief program option bytes USER
539 programmer must ensure FMC & option bytes are both unlocked before calling this function
540 \param[in] ob_fwdgt: option bytes free watchdog value
541 only one parameter can be selected which is shown as below:
542 \arg OB_FWDGT_SW: software free watchdog
543 \arg OB_FWDGT_HW: hardware free watchdog
544 \param[in] ob_deepsleep: option bytes deepsleep reset value
545 only one parameter can be selected which is shown as below:
546 \arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
547 \arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
548 \param[in] ob_stdby:option bytes standby reset value
549 only one parameter can be selected which is shown as below:
550 \arg OB_STDBY_NRST: no reset when entering standby mode
551 \arg OB_STDBY_RST: generate a reset instead of entering standby mode
552 \param[in] ob_bor_th: option bytes BOR threshold value
553 only one parameter can be selected which is shown as below:
554 \arg OB_BOR_TH_VALUE4: BOR threshold value 3
555 \arg OB_BOR_TH_VALUE3: BOR threshold value 3
556 \arg OB_BOR_TH_VALUE2: BOR threshold value 2
557 \arg OB_BOR_TH_VALUE1: BOR threshold value 1
558 \arg OB_BOR_TH_VALUE0: BOR threshold value 0
559 \param[out] none
560 \retval state of FMC, refer to fmc_state_enum
561 */
ob_user_write(uint8_t ob_fwdgt,uint8_t ob_deepsleep,uint8_t ob_stdby,uint8_t ob_bor_th)562 fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby, uint8_t ob_bor_th)
563 {
564 uint32_t temp_spc;
565 uint8_t temp;
566 uint8_t i;
567 uint32_t op_byte[4];
568
569 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
570
571 temp_spc = OB_SPC_USER;
572
573 /* check the option bytes security protection value */
574 if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))) {
575 fmc_state = FMC_OB_HSPC;
576 }
577
578 for(i = 0U; i < 4U; i++) {
579 op_byte[i] = OP_BYTE(i);
580 }
581 temp = ((uint8_t)((uint8_t)((uint8_t)((uint8_t)(ob_fwdgt) | ob_deepsleep) | ob_stdby) | ob_bor_th) | (OB_USER_MASK));
582 op_byte[0] = ((uint32_t)(temp) << 16U) | ((op_byte[0] & LOW_16BITS_MASK));
583
584 if(FMC_READY == fmc_state) {
585 /* start erase the option bytes */
586 FMC_CTL |= FMC_CTL_OBER;
587 FMC_CTL |= FMC_CTL_START;
588 /* wait for the FMC ready */
589 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
590 if(FMC_READY == fmc_state) {
591 /* reset the OBER bit and enable the option bytes programming */
592 FMC_CTL &= ~FMC_CTL_OBER;
593 FMC_CTL |= FMC_CTL_OBPG;
594
595 for(i = 0U; i < 4U; i++) {
596 OP_BYTE(i) = op_byte[i];
597 /* wait for the FMC ready */
598 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
599 if(FMC_READY != fmc_state) {
600 break;
601 }
602 }
603
604 /* reset the OBPG bit */
605 FMC_CTL &= ~FMC_CTL_OBPG;
606 } else {
607 /* reset the OBER bit */
608 FMC_CTL &= ~FMC_CTL_OBER;
609 }
610 }
611 /* return the FMC state */
612 return fmc_state;
613 }
614
615 /*!
616 \brief program option bytes DATA
617 \param[in] data: the data to be programmed
618 \param[out] none
619 \retval state of FMC, refer to fmc_state_enum
620 */
ob_data_program(uint16_t ob_data)621 fmc_state_enum ob_data_program(uint16_t ob_data)
622 {
623 uint8_t i;
624 uint32_t temp_spc;
625 uint32_t op_byte[4];
626
627 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
628
629 temp_spc = OB_SPC_USER;
630
631 /* check the option bytes security protection value */
632 if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))) {
633 fmc_state = FMC_OB_HSPC;
634 }
635
636 for(i = 0U; i < 4U; i++) {
637 op_byte[i] = OP_BYTE(i);
638 }
639 op_byte[1] = (uint32_t)((ob_data & LOW_8BITS_MASK) | ((ob_data & HIGH_8BITS_MASK) << 8));
640
641 if(FMC_READY == fmc_state) {
642 /* start erase the option bytes */
643 FMC_CTL |= FMC_CTL_OBER;
644 FMC_CTL |= FMC_CTL_START;
645
646 /* wait for the FMC ready */
647 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
648
649 if(FMC_READY == fmc_state) {
650 /* reset the OBER bit and enable the option bytes programming */
651 FMC_CTL &= ~FMC_CTL_OBER;
652 FMC_CTL |= FMC_CTL_OBPG;
653
654 for(i = 0U; i < 4U; i++) {
655 OP_BYTE(i) = op_byte[i];
656 /* wait for the FMC ready */
657 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
658 if(FMC_READY != fmc_state) {
659 break;
660 }
661 }
662 /* reset the OBPG bit */
663 FMC_CTL &= ~FMC_CTL_OBPG;
664 } else {
665 /* reset the OBER bit */
666 FMC_CTL &= ~FMC_CTL_OBER;
667 }
668 }
669
670 /* return the FMC state */
671 return fmc_state;
672 }
673
674 /*!
675 \brief get the value of option bytes USER
676 \param[in] none
677 \param[out] none
678 \retval the option bytes USER value
679 */
ob_user_get(void)680 uint8_t ob_user_get(void)
681 {
682 /* return the FMC user option bytes value */
683 return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
684 }
685
686 /*!
687 \brief get the value of option bytes DATA
688 \param[in] none
689 \param[out] none
690 \retval the option bytes DATA value
691 */
ob_data_get(void)692 uint16_t ob_data_get(void)
693 {
694 return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
695 }
696
697 /*!
698 \brief get the value of option bytes write protection
699 \param[in] none
700 \param[out] none
701 \retval the write protection option bytes value
702 */
ob_write_protection_get(void)703 uint32_t ob_write_protection_get(void)
704 {
705 /* return the FMC write protection option bytes value */
706 return FMC_WP;
707 }
708
709 /*!
710 \brief get the FMC option bytes security protection state
711 \param[in] none
712 \param[out] none
713 \retval FlagStatus: SET or RESET
714 */
ob_security_protection_flag_get(void)715 FlagStatus ob_security_protection_flag_get(void)
716 {
717 FlagStatus spc_state = RESET;
718
719 if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)) {
720 spc_state = SET;
721 } else {
722 spc_state = RESET;
723 }
724 return spc_state;
725 }
726
727 /*!
728 \brief get FMC flag status
729 \param[in] flag: FMC flag
730 only one parameter can be selected which is shown as below:
731 \arg FMC_FLAG_BUSY: FMC busy flag
732 \arg FMC_FLAG_PGERR: FMC program error flag
733 \arg FMC_FLAG_PGAERR: FMC program alignment error flag
734 \arg FMC_FLAG_WPERR: FMC erase/program protection error flag
735 \arg FMC_FLAG_END: FMC end of operation flag
736 \arg FMC_FLAG_SLP: FMC sleep or power down flag
737 \param[out] none
738 \retval FlagStatus: SET or RESET
739 */
fmc_flag_get(uint32_t flag)740 FlagStatus fmc_flag_get(uint32_t flag)
741 {
742 FlagStatus status = RESET;
743
744 if(FMC_STAT & flag) {
745 status = SET;
746 }
747 /* return the state of corresponding FMC flag */
748 return status;
749 }
750
751 /*!
752 \brief clear the FMC flag
753 \param[in] flag: FMC flag
754 only one parameter can be selected which is shown as below:
755 \arg FMC_FLAG_PGERR: FMC program error flag
756 \arg FMC_FLAG_PGAERR: FMC program alignment error flag
757 \arg FMC_FLAG_WPERR: FMC erase/program protection error flag
758 \arg FMC_FLAG_END: FMC end of operation flag
759 \arg FMC_FLAG_SLP: FMC sleep or power down flag
760 \param[out] none
761 \retval none
762 */
fmc_flag_clear(uint32_t flag)763 void fmc_flag_clear(uint32_t flag)
764 {
765 /* clear the flags */
766 FMC_STAT = flag;
767 }
768
769 /*!
770 \brief enable FMC interrupt
771 \param[in] interrupt: the FMC interrupt
772 only one parameter can be selected which is shown as below:
773 \arg FMC_INT_END: FMC end of operation interrupt
774 \arg FMC_INT_ERR: FMC error interrupt
775 \param[out] none
776 \retval none
777 */
fmc_interrupt_enable(uint32_t interrupt)778 void fmc_interrupt_enable(uint32_t interrupt)
779 {
780 FMC_CTL |= interrupt;
781 }
782
783 /*!
784 \brief disable FMC interrupt
785 \param[in] interrupt: the FMC interrupt
786 only one parameter can be selected which is shown as below:
787 \arg FMC_INT_END: FMC end of operation interrupt
788 \arg FMC_INT_ERR: FMC error interrupt
789 \param[out] none
790 \retval none
791 */
fmc_interrupt_disable(uint32_t interrupt)792 void fmc_interrupt_disable(uint32_t interrupt)
793 {
794 FMC_CTL &= ~(uint32_t)interrupt;
795 }
796
797 /*!
798 \brief get FMC interrupt flag
799 \param[in] flag: FMC interrupt flag
800 only one parameter can be selected which is shown as below:
801 \arg FMC_INT_FLAG_PGERR: FMC program operation error interrupt flag
802 \arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
803 \arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
804 \arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
805 \param[out] none
806 \retval FlagStatus: SET or RESET
807 */
fmc_interrupt_flag_get(uint32_t flag)808 FlagStatus fmc_interrupt_flag_get(uint32_t flag)
809 {
810 FlagStatus status = RESET;
811
812 if(FMC_STAT & flag) {
813 status = SET;
814 }
815 /* return the state of corresponding FMC flag */
816 return status;
817 }
818
819 /*!
820 \brief clear FMC interrupt flag
821 \param[in] flag: FMC interrupt flag
822 one or more parameters can be selected which is shown as below:
823 \arg FMC_INT_FLAG_PGERR: FMC program operation error interrupt flag
824 \arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
825 \arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
826 \arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
827 \param[out] none
828 \retval none
829 */
fmc_interrupt_flag_clear(uint32_t flag)830 void fmc_interrupt_flag_clear(uint32_t flag)
831 {
832 /* clear the flag */
833 FMC_STAT = flag;
834 }
835
836 /*!
837 \brief get the FMC state
838 \param[in] none
839 \param[out] none
840 \retval state of FMC, refer to fmc_state_enum
841 */
fmc_state_get(void)842 static fmc_state_enum fmc_state_get(void)
843 {
844 fmc_state_enum fmc_state = FMC_READY;
845
846 if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)) {
847 fmc_state = FMC_BUSY;
848 } else {
849 if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)) {
850 fmc_state = FMC_WPERR;
851 } else {
852 if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGERR))) {
853 fmc_state = FMC_PGERR;
854 } else {
855 if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGAERR))) {
856 fmc_state = FMC_PGAERR;
857 } else {
858 if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_FSTAT))) {
859 fmc_state = FMC_SLP;
860 }
861 }
862 }
863 }
864 }
865 /* return the FMC state */
866 return fmc_state;
867 }
868
869 /*!
870 \brief check whether FMC is ready or not
871 \param[in] timeout: timeout count
872 \param[out] none
873 \retval state of FMC, refer to fmc_state_enum
874 */
fmc_ready_wait(uint32_t timeout)875 static fmc_state_enum fmc_ready_wait(uint32_t timeout)
876 {
877 fmc_state_enum fmc_state = FMC_BUSY;
878
879 /* wait for FMC ready */
880 do {
881 /* get FMC state */
882 fmc_state = fmc_state_get();
883 timeout--;
884 } while((FMC_BUSY == fmc_state) && (0x00U != timeout));
885
886 if(FMC_BUSY == fmc_state) {
887 fmc_state = FMC_TOERR;
888 }
889 /* return the FMC state */
890 return fmc_state;
891 }
892