1 /*!
2 \file gd32f4xx_fmc.c
3 \brief FMC driver
4
5 \version 2016-08-15, V1.0.0, firmware for GD32F4xx
6 \version 2018-12-12, V2.0.0, firmware for GD32F4xx
7 \version 2020-09-30, V2.1.0, firmware for GD32F4xx
8 \version 2022-03-09, V3.0.0, firmware for GD32F4xx
9 */
10
11 /*
12 Copyright (c) 2022, GigaDevice Semiconductor Inc.
13
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16
17 1. Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright notice,
20 this list of conditions and the following disclaimer in the documentation
21 and/or other materials provided with the distribution.
22 3. Neither the name of the copyright holder nor the names of its contributors
23 may be used to endorse or promote products derived from this software without
24 specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37
38
39 #include "gd32f4xx_fmc.h"
40
41 /*!
42 \brief set the wait state counter value
43 \param[in] wscnt: wait state counter value
44 only one parameter can be selected which is shown as below:
45 \arg WS_WSCNT_0: FMC 0 wait
46 \arg WS_WSCNT_1: FMC 1 wait
47 \arg WS_WSCNT_2: FMC 2 wait
48 \arg WS_WSCNT_3: FMC 3 wait
49 \arg WS_WSCNT_4: FMC 4 wait
50 \arg WS_WSCNT_5: FMC 5 wait
51 \arg WS_WSCNT_6: FMC 6 wait
52 \arg WS_WSCNT_7: FMC 7 wait
53 \arg WS_WSCNT_8: FMC 8 wait
54 \arg WS_WSCNT_9: FMC 9 wait
55 \arg WS_WSCNT_10: FMC 10 wait
56 \arg WS_WSCNT_11: FMC 11 wait
57 \arg WS_WSCNT_12: FMC 12 wait
58 \arg WS_WSCNT_13: FMC 13 wait
59 \arg WS_WSCNT_14: FMC 14 wait
60 \arg WS_WSCNT_15: FMC 15 wait
61 \param[out] none
62 \retval none
63 */
fmc_wscnt_set(uint32_t wscnt)64 void fmc_wscnt_set(uint32_t wscnt)
65 {
66 uint32_t reg;
67
68 reg = FMC_WS;
69 /* set the wait state counter value */
70 reg &= ~FMC_WC_WSCNT;
71 FMC_WS = (reg | wscnt);
72 }
73
74 /*!
75 \brief unlock the main FMC operation
76 \param[in] none
77 \param[out] none
78 \retval none
79 */
fmc_unlock(void)80 void fmc_unlock(void)
81 {
82 if((RESET != (FMC_CTL & FMC_CTL_LK))) {
83 /* write the FMC key */
84 FMC_KEY = UNLOCK_KEY0;
85 FMC_KEY = UNLOCK_KEY1;
86 }
87 }
88
89 /*!
90 \brief lock the main FMC operation
91 \param[in] none
92 \param[out] none
93 \retval none
94 */
fmc_lock(void)95 void fmc_lock(void)
96 {
97 /* set the LK bit*/
98 FMC_CTL |= FMC_CTL_LK;
99 }
100
101 #if defined (GD32F425) || defined (GD32F427) || defined (GD32F470)
102
103 /*!
104 \brief FMC erase page
105 \param[in] page_addr: the page address to be erased.
106 \param[out] none
107 \retval state of FMC
108 \arg FMC_READY: the operation has been completed
109 \arg FMC_BUSY: the operation is in progress
110 \arg FMC_RDDERR: read D-bus protection error
111 \arg FMC_PGSERR: program sequence error
112 \arg FMC_PGMERR: program size not match error
113 \arg FMC_WPERR: erase/program protection error
114 \arg FMC_OPERR: operation error
115 \arg FMC_TOERR: timeout error
116 */
fmc_page_erase(uint32_t page_addr)117 fmc_state_enum fmc_page_erase(uint32_t page_addr)
118 {
119 fmc_state_enum fmc_state = FMC_READY;
120
121 /* wait for the FMC ready */
122 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
123
124 if(FMC_READY == fmc_state) {
125 /* unlock */
126 FMC_PEKEY = UNLOCK_PE_KEY;
127
128 /* start page erase */
129 FMC_PECFG = FMC_PE_EN | page_addr;
130 FMC_CTL &= ~FMC_CTL_SN;
131 FMC_CTL |= FMC_CTL_SER;
132 FMC_CTL |= FMC_CTL_START;
133
134 /* wait for the FMC ready */
135 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
136
137 FMC_PECFG &= ~FMC_PE_EN;
138 FMC_CTL &= ~FMC_CTL_SER;
139 }
140
141 /* return the FMC state */
142 return fmc_state;
143 }
144
145 #endif
146
147 /*!
148 \brief erase sector
149 \param[in] fmc_sector: select the sector to erase
150 only one parameter can be selected which is shown as below:
151 \arg CTL_SECTOR_NUMBER_0: sector 0
152 \arg CTL_SECTOR_NUMBER_1: sector 1
153 \arg CTL_SECTOR_NUMBER_2: sector 2
154 \arg CTL_SECTOR_NUMBER_3: sector 3
155 \arg CTL_SECTOR_NUMBER_4: sector 4
156 \arg CTL_SECTOR_NUMBER_5: sector 5
157 \arg CTL_SECTOR_NUMBER_6: sector 6
158 \arg CTL_SECTOR_NUMBER_7: sector 7
159 \arg CTL_SECTOR_NUMBER_8: sector 8
160 \arg CTL_SECTOR_NUMBER_9: sector 9
161 \arg CTL_SECTOR_NUMBER_10: sector 10
162 \arg CTL_SECTOR_NUMBER_11: sector 11
163 \arg CTL_SECTOR_NUMBER_12: sector 12
164 \arg CTL_SECTOR_NUMBER_13: sector 13
165 \arg CTL_SECTOR_NUMBER_14: sector 14
166 \arg CTL_SECTOR_NUMBER_15: sector 15
167 \arg CTL_SECTOR_NUMBER_16: sector 16
168 \arg CTL_SECTOR_NUMBER_17: sector 17
169 \arg CTL_SECTOR_NUMBER_18: sector 18
170 \arg CTL_SECTOR_NUMBER_19: sector 19
171 \arg CTL_SECTOR_NUMBER_20: sector 20
172 \arg CTL_SECTOR_NUMBER_21: sector 21
173 \arg CTL_SECTOR_NUMBER_22: sector 22
174 \arg CTL_SECTOR_NUMBER_23: sector 23
175 \arg CTL_SECTOR_NUMBER_24: sector 24
176 \arg CTL_SECTOR_NUMBER_25: sector 25
177 \arg CTL_SECTOR_NUMBER_26: sector 26
178 \arg CTL_SECTOR_NUMBER_27: sector 27
179 \param[out] none
180 \retval state of FMC
181 \arg FMC_READY: the operation has been completed
182 \arg FMC_BUSY: the operation is in progress
183 \arg FMC_RDDERR: read D-bus protection error
184 \arg FMC_PGSERR: program sequence error
185 \arg FMC_PGMERR: program size not match error
186 \arg FMC_WPERR: erase/program protection error
187 \arg FMC_OPERR: operation error
188 \arg FMC_TOERR: timeout error
189 */
fmc_sector_erase(uint32_t fmc_sector)190 fmc_state_enum fmc_sector_erase(uint32_t fmc_sector)
191 {
192 fmc_state_enum fmc_state = FMC_READY;
193 /* wait for the FMC ready */
194 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
195
196 if(FMC_READY == fmc_state) {
197 /* start sector erase */
198 FMC_CTL &= ~FMC_CTL_SN;
199 FMC_CTL |= (FMC_CTL_SER | fmc_sector);
200 FMC_CTL |= FMC_CTL_START;
201
202 /* wait for the FMC ready */
203 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
204
205 /* reset the SER bit */
206 FMC_CTL &= (~FMC_CTL_SER);
207 FMC_CTL &= ~FMC_CTL_SN;
208 }
209
210 /* return the FMC state */
211 return fmc_state;
212 }
213
214 /*!
215 \brief erase whole chip
216 \param[in] none
217 \param[out] none
218 \retval state of FMC
219 \arg FMC_READY: the operation has been completed
220 \arg FMC_BUSY: the operation is in progress
221 \arg FMC_RDDERR: read D-bus protection error
222 \arg FMC_PGSERR: program sequence error
223 \arg FMC_PGMERR: program size not match error
224 \arg FMC_WPERR: erase/program protection error
225 \arg FMC_OPERR: operation error
226 \arg FMC_TOERR: timeout error
227 */
fmc_mass_erase(void)228 fmc_state_enum fmc_mass_erase(void)
229 {
230 fmc_state_enum fmc_state = FMC_READY;
231 /* wait for the FMC ready */
232 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
233
234 if(FMC_READY == fmc_state) {
235 /* start whole chip erase */
236 FMC_CTL |= (FMC_CTL_MER0 | FMC_CTL_MER1);
237 FMC_CTL |= FMC_CTL_START;
238
239 /* wait for the FMC ready */
240 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
241
242 /* reset the MER bits */
243 FMC_CTL &= ~(FMC_CTL_MER0 | FMC_CTL_MER1);
244 }
245
246 /* return the fmc state */
247 return fmc_state;
248 }
249
250 /*!
251 \brief erase all FMC sectors in bank0
252 \param[in] none
253 \param[out] none
254 \retval state of FMC
255 \arg FMC_READY: the operation has been completed
256 \arg FMC_BUSY: the operation is in progress
257 \arg FMC_RDDERR: read D-bus protection error
258 \arg FMC_PGSERR: program sequence error
259 \arg FMC_PGMERR: program size not match error
260 \arg FMC_WPERR: erase/program protection error
261 \arg FMC_OPERR: operation error
262 \arg FMC_TOERR: timeout error
263 */
fmc_bank0_erase(void)264 fmc_state_enum fmc_bank0_erase(void)
265 {
266 fmc_state_enum fmc_state = FMC_READY;
267 /* wait for the FMC ready */
268 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
269
270 if(FMC_READY == fmc_state) {
271 /* start FMC bank0 erase */
272 FMC_CTL |= FMC_CTL_MER0;
273 FMC_CTL |= FMC_CTL_START;
274
275 /* wait for the FMC ready */
276 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
277
278 /* reset the MER0 bit */
279 FMC_CTL &= (~FMC_CTL_MER0);
280 }
281
282 /* return the fmc state */
283 return fmc_state;
284 }
285
286 /*!
287 \brief erase all FMC sectors in bank1
288 \param[in] none
289 \param[out] none
290 \retval state of FMC
291 \arg FMC_READY: the operation has been completed
292 \arg FMC_BUSY: the operation is in progress
293 \arg FMC_RDDERR: read D-bus protection error
294 \arg FMC_PGSERR: program sequence error
295 \arg FMC_PGMERR: program size not match error
296 \arg FMC_WPERR: erase/program protection error
297 \arg FMC_OPERR: operation error
298 \arg FMC_TOERR: timeout error
299 */
fmc_bank1_erase(void)300 fmc_state_enum fmc_bank1_erase(void)
301 {
302 fmc_state_enum fmc_state = FMC_READY;
303 /* wait for the FMC ready */
304 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
305
306 if(FMC_READY == fmc_state) {
307 /* start FMC bank1 erase */
308 FMC_CTL |= FMC_CTL_MER1;
309 FMC_CTL |= FMC_CTL_START;
310
311 /* wait for the FMC ready */
312 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
313
314 /* reset the MER1 bit */
315 FMC_CTL &= (~FMC_CTL_MER1);
316 }
317
318 /* return the fmc state */
319 return fmc_state;
320 }
321
322 /*!
323 \brief program a word at the corresponding address
324 \param[in] address: address to program
325 \param[in] data: word to program(0x00000000 - 0xFFFFFFFF)
326 \param[out] none
327 \retval state of FMC
328 \arg FMC_READY: the operation has been completed
329 \arg FMC_BUSY: the operation is in progress
330 \arg FMC_RDDERR: read D-bus protection error
331 \arg FMC_PGSERR: program sequence error
332 \arg FMC_PGMERR: program size not match error
333 \arg FMC_WPERR: erase/program protection error
334 \arg FMC_OPERR: operation error
335 \arg FMC_TOERR: timeout error
336 */
fmc_word_program(uint32_t address,uint32_t data)337 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
338 {
339 fmc_state_enum fmc_state = FMC_READY;
340 /* wait for the FMC ready */
341 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
342
343 if(FMC_READY == fmc_state) {
344 /* set the PG bit to start program */
345 FMC_CTL &= ~FMC_CTL_PSZ;
346 FMC_CTL |= CTL_PSZ_WORD;
347 FMC_CTL |= FMC_CTL_PG;
348
349 REG32(address) = data;
350
351 /* wait for the FMC ready */
352 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
353
354 /* reset the PG bit */
355 FMC_CTL &= ~FMC_CTL_PG;
356 }
357
358 /* return the FMC state */
359 return fmc_state;
360 }
361
362 /*!
363 \brief program a half word at the corresponding address
364 \param[in] address: address to program
365 \param[in] data: halfword to program(0x0000 - 0xFFFF)
366 \param[out] none
367 \retval state of FMC
368 \arg FMC_READY: the operation has been completed
369 \arg FMC_BUSY: the operation is in progress
370 \arg FMC_RDDERR: read D-bus protection error
371 \arg FMC_PGSERR: program sequence error
372 \arg FMC_PGMERR: program size not match error
373 \arg FMC_WPERR: erase/program protection error
374 \arg FMC_OPERR: operation error
375 \arg FMC_TOERR: timeout error
376 */
fmc_halfword_program(uint32_t address,uint16_t data)377 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
378 {
379 fmc_state_enum fmc_state = FMC_READY;
380 /* wait for the FMC ready */
381 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
382
383 if(FMC_READY == fmc_state) {
384 /* set the PG bit to start program */
385 FMC_CTL &= ~FMC_CTL_PSZ;
386 FMC_CTL |= CTL_PSZ_HALF_WORD;
387 FMC_CTL |= FMC_CTL_PG;
388
389 REG16(address) = data;
390
391 /* wait for the FMC ready */
392 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
393
394 /* reset the PG bit */
395 FMC_CTL &= ~FMC_CTL_PG;
396 }
397
398 /* return the FMC state */
399 return fmc_state;
400 }
401
402 /*!
403 \brief program a byte at the corresponding address
404 \param[in] address: address to program
405 \param[in] data: byte to program(0x00 - 0xFF)
406 \param[out] none
407 \retval state of FMC
408 \arg FMC_READY: the operation has been completed
409 \arg FMC_BUSY: the operation is in progress
410 \arg FMC_RDDERR: read D-bus protection error
411 \arg FMC_PGSERR: program sequence error
412 \arg FMC_PGMERR: program size not match error
413 \arg FMC_WPERR: erase/program protection error
414 \arg FMC_OPERR: operation error
415 \arg FMC_TOERR: timeout error
416 */
fmc_byte_program(uint32_t address,uint8_t data)417 fmc_state_enum fmc_byte_program(uint32_t address, uint8_t data)
418 {
419 fmc_state_enum fmc_state = FMC_READY;
420 /* wait for the FMC ready */
421 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
422
423 if(FMC_READY == fmc_state) {
424 /* set the PG bit to start program */
425 FMC_CTL &= ~FMC_CTL_PSZ;
426 FMC_CTL |= CTL_PSZ_BYTE;
427 FMC_CTL |= FMC_CTL_PG;
428
429 REG8(address) = data;
430
431 /* wait for the FMC ready */
432 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
433
434 /* reset the PG bit */
435 FMC_CTL &= ~FMC_CTL_PG;
436 }
437
438 /* return the FMC state */
439 return fmc_state;
440 }
441
442 /*!
443 \brief unlock the option byte operation
444 \param[in] none
445 \param[out] none
446 \retval none
447 */
ob_unlock(void)448 void ob_unlock(void)
449 {
450 if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_OB_LK)) {
451 /* write the FMC key */
452 FMC_OBKEY = OB_UNLOCK_KEY0;
453 FMC_OBKEY = OB_UNLOCK_KEY1;
454 }
455 }
456
457 /*!
458 \brief lock the option byte operation
459 \param[in] none
460 \param[out] none
461 \retval none
462 */
ob_lock(void)463 void ob_lock(void)
464 {
465 /* reset the OB_LK bit */
466 FMC_OBCTL0 |= FMC_OBCTL0_OB_LK;
467 }
468
469 /*!
470 \brief send option byte change command
471 \param[in] none
472 \param[out] none
473 \retval none
474 */
ob_start(void)475 void ob_start(void)
476 {
477 /* set the OB_START bit in OBCTL0 register */
478 FMC_OBCTL0 |= FMC_OBCTL0_OB_START;
479 }
480
481 /*!
482 \brief erase option byte
483 \param[in] none
484 \param[out] none
485 \retval none
486 */
ob_erase(void)487 void ob_erase(void)
488 {
489 uint32_t reg, reg1;
490 fmc_state_enum fmc_state = FMC_READY;
491 /* wait for the FMC ready */
492 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
493 reg = FMC_OBCTL0;
494 reg1 = FMC_OBCTL1;
495
496 if(FMC_READY == fmc_state) {
497
498 /* reset the OB_FWDGT, OB_DEEPSLEEP and OB_STDBY, set according to ob_fwdgt ,ob_deepsleep and ob_stdby */
499 reg |= (FMC_OBCTL0_NWDG_HW | FMC_OBCTL0_NRST_DPSLP | FMC_OBCTL0_NRST_STDBY);
500 /* reset the BOR level */
501 reg |= FMC_OBCTL0_BOR_TH;
502 /* reset option byte boot bank value */
503 reg &= ~FMC_OBCTL0_BB;
504 /* reset option byte dbs value */
505 reg &= ~FMC_OBCTL0_DBS;
506
507 /* reset drp and wp value */
508 reg |= FMC_OBCTL0_WP0;
509 reg &= (~FMC_OBCTL0_DRP);
510 FMC_OBCTL0 = reg;
511
512 reg1 |= FMC_OBCTL1_WP1;
513 FMC_OBCTL1 = reg1;
514
515 FMC_OBCTL0 = reg;
516 }
517 }
518
519 /*!
520 \brief enable write protection
521 \param[in] ob_wp: specify sector to be write protected
522 one or more parameters can be selected which are shown as below:
523 \arg OB_WP_x(x=0..22):sector x(x = 0,1,2...22)
524 \arg OB_WP_23_27: sector23~27
525 \arg OB_WP_ALL: all sector
526 \param[out] none
527 \retval SUCCESS or ERROR
528 */
ob_write_protection_enable(uint32_t ob_wp)529 ErrStatus ob_write_protection_enable(uint32_t ob_wp)
530 {
531 uint32_t reg0 = FMC_OBCTL0;
532 uint32_t reg1 = FMC_OBCTL1;
533 fmc_state_enum fmc_state = FMC_READY;
534 if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_DRP)) {
535 return ERROR;
536 }
537 /* wait for the FMC ready */
538 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
539
540 if(FMC_READY == fmc_state) {
541 reg0 &= (~((uint32_t)ob_wp << 16U));
542 reg1 &= (~(ob_wp & 0xFFFF0000U));
543 FMC_OBCTL0 = reg0;
544 FMC_OBCTL1 = reg1;
545
546 return SUCCESS;
547 } else {
548 return ERROR;
549 }
550 }
551
552 /*!
553 \brief disable write protection
554 \param[in] ob_wp: specify sector to be write protected
555 one or more parameters can be selected which are shown as below:
556 \arg OB_WP_x(x=0..22):sector x(x = 0,1,2...22)
557 \arg OB_WP_23_27: sector23~27
558 \arg OB_WP_ALL: all sector
559 \param[out] none
560 \retval SUCCESS or ERROR
561 */
ob_write_protection_disable(uint32_t ob_wp)562 ErrStatus ob_write_protection_disable(uint32_t ob_wp)
563 {
564 uint32_t reg0 = FMC_OBCTL0;
565 uint32_t reg1 = FMC_OBCTL1;
566 fmc_state_enum fmc_state = FMC_READY;
567 if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_DRP)) {
568 return ERROR;
569 }
570 /* wait for the FMC ready */
571 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
572
573 if(FMC_READY == fmc_state) {
574 reg0 |= ((uint32_t)ob_wp << 16U);
575 reg1 |= (ob_wp & 0xFFFF0000U);
576 FMC_OBCTL0 = reg0;
577 FMC_OBCTL1 = reg1;
578
579 return SUCCESS;
580 } else {
581 return ERROR;
582 }
583 }
584
585 /*!
586 \brief enable erase/program protection and D-bus read protection
587 \param[in] ob_drp: enable the WPx bits used as erase/program protection and D-bus read protection of each sector
588 one or more parameters can be selected which are shown as below:
589 \arg OB_DRP_x(x=0..22): sector x(x = 0,1,2...22)
590 \arg OB_DRP_23_27: sector23~27
591 \arg OB_DRP_ALL: all sector
592 \param[out] none
593 \retval none
594 */
ob_drp_enable(uint32_t ob_drp)595 void ob_drp_enable(uint32_t ob_drp)
596 {
597 uint32_t reg0 = FMC_OBCTL0;
598 uint32_t reg1 = FMC_OBCTL1;
599 fmc_state_enum fmc_state = FMC_READY;
600 uint32_t drp_state = FMC_OBCTL0 & FMC_OBCTL0_DRP;
601 uint32_t wp0_state = FMC_OBCTL0 & FMC_OBCTL0_WP0;
602 uint32_t wp1_state = FMC_OBCTL1 & FMC_OBCTL1_WP1;
603
604 /* wait for the FMC ready */
605 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
606
607 if(FMC_READY == fmc_state) {
608 if(RESET == drp_state) {
609 reg0 &= ~FMC_OBCTL0_WP0;
610 reg1 &= ~FMC_OBCTL1_WP1;
611 }
612 reg0 |= ((uint32_t)ob_drp << 16U);
613 reg0 |= FMC_OBCTL0_DRP;
614 reg1 |= ((uint32_t)ob_drp & 0xFFFF0000U);
615
616 FMC_OBCTL0 = reg0;
617 FMC_OBCTL1 = reg1;
618 }
619 }
620
621 /*!
622 \brief disable erase/program protection and D-bus read protection
623 \param[in] ob_drp: disable the WPx bits used as erase/program protection and D-bus read protection of each sector
624 one or more parameters can be selected which are shown as below:
625 \arg OB_DRP_x(x=0..22): sector x(x = 0,1,2...22)
626 \arg OB_DRP_23_27: sector23~27
627 \arg OB_DRP_ALL: all sector
628 \param[out] none
629 \retval none
630 */
ob_drp_disable(void)631 void ob_drp_disable(void)
632 {
633 uint32_t reg0 = FMC_OBCTL0;
634 uint32_t reg1 = FMC_OBCTL1;
635 fmc_state_enum fmc_state = FMC_READY;
636 /* wait for the FMC ready */
637 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
638
639 if(FMC_READY == fmc_state) {
640 if(((uint8_t)(reg0 >> 8U)) == (uint8_t)FMC_NSPC) {
641 /* security protection should be set as low level protection before disable D-BUS read protection */
642 reg0 &= ~FMC_OBCTL0_SPC;
643 reg0 |= ((uint32_t)FMC_LSPC << 8U);
644 FMC_OBCTL0 = reg0;
645 /* set the OB_START bit in OBCTL0 register */
646 FMC_OBCTL0 |= FMC_OBCTL0_OB_START;
647 }
648
649 /* it is necessary to disable the security protection at the same time when D-BUS read protection is disabled */
650 reg0 &= ~FMC_OBCTL0_SPC;
651 reg0 |= ((uint32_t)FMC_NSPC << 8U);
652 reg0 |= FMC_OBCTL0_WP0;
653 reg0 &= (~FMC_OBCTL0_DRP);
654 FMC_OBCTL0 = reg0;
655
656 reg1 |= FMC_OBCTL1_WP1;
657 FMC_OBCTL1 = reg1;
658
659 }
660 }
661
662 /*!
663 \brief configure security protection level
664 \param[in] ob_spc: specify security protection level
665 only one parameter can be selected which is shown as below:
666 \arg FMC_NSPC: no security protection
667 \arg FMC_LSPC: low security protection
668 \arg FMC_HSPC: high security protection
669 \param[out] none
670 \retval none
671 */
ob_security_protection_config(uint8_t ob_spc)672 void ob_security_protection_config(uint8_t ob_spc)
673 {
674 fmc_state_enum fmc_state = FMC_READY;
675 /* wait for the FMC ready */
676 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
677
678 if(FMC_READY == fmc_state) {
679 uint32_t reg;
680
681 reg = FMC_OBCTL0;
682 /* reset the OBCTL0_SPC, set according to ob_spc */
683 reg &= ~FMC_OBCTL0_SPC;
684 reg |= ((uint32_t)ob_spc << 8U);
685 FMC_OBCTL0 = reg;
686 }
687 }
688
689 /*!
690 \brief program the FMC user option byte
691 \param[in] ob_fwdgt: option byte watchdog value
692 only one parameter can be selected which is shown as below:
693 \arg OB_FWDGT_SW: software free watchdog
694 \arg OB_FWDGT_HW: hardware free watchdog
695 \param[in] ob_deepsleep: option byte deepsleep reset value
696 only one parameter can be selected which is shown as below:
697 \arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
698 \arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
699 \param[in] ob_stdby:option byte standby reset value
700 only one parameter can be selected which is shown as below:
701 \arg OB_STDBY_NRST: no reset when entering standby mode
702 \arg OB_STDBY_RST: generate a reset instead of entering standby mode
703 \param[out] none
704 \retval none
705 */
ob_user_write(uint32_t ob_fwdgt,uint32_t ob_deepsleep,uint32_t ob_stdby)706 void ob_user_write(uint32_t ob_fwdgt, uint32_t ob_deepsleep, uint32_t ob_stdby)
707 {
708 fmc_state_enum fmc_state = FMC_READY;
709
710 /* wait for the FMC ready */
711 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
712
713 if(FMC_READY == fmc_state) {
714 uint32_t reg;
715
716 reg = FMC_OBCTL0;
717 /* reset the OB_FWDGT, OB_DEEPSLEEP and OB_STDBY, set according to ob_fwdgt ,ob_deepsleep and ob_stdby */
718 reg &= ~(FMC_OBCTL0_NWDG_HW | FMC_OBCTL0_NRST_DPSLP | FMC_OBCTL0_NRST_STDBY);
719 FMC_OBCTL0 = (reg | ob_fwdgt | ob_deepsleep | ob_stdby);
720 }
721 }
722
723 /*!
724 \brief program the option byte BOR threshold value
725 \param[in] ob_bor_th: user option byte
726 only one parameter can be selected which is shown as below:
727 \arg OB_BOR_TH_VALUE3: BOR threshold value 3
728 \arg OB_BOR_TH_VALUE2: BOR threshold value 2
729 \arg OB_BOR_TH_VALUE1: BOR threshold value 1
730 \arg OB_BOR_TH_OFF: no BOR function
731 \param[out] none
732 \retval none
733 */
ob_user_bor_threshold(uint32_t ob_bor_th)734 void ob_user_bor_threshold(uint32_t ob_bor_th)
735 {
736 uint32_t reg;
737
738 reg = FMC_OBCTL0;
739 /* set the BOR level */
740 reg &= ~FMC_OBCTL0_BOR_TH;
741 FMC_OBCTL0 = (reg | ob_bor_th);
742 }
743
744 /*!
745 \brief configure the option byte boot bank value
746 \param[in] boot_mode: specifies the option byte boot bank value
747 only one parameter can be selected which is shown as below:
748 \arg OB_BB_DISABLE: boot from bank0
749 \arg OB_BB_ENABLE: boot from bank1 or bank0 if bank1 is void
750 \param[out] none
751 \retval none
752 */
ob_boot_mode_config(uint32_t boot_mode)753 void ob_boot_mode_config(uint32_t boot_mode)
754 {
755 uint32_t reg;
756
757 reg = FMC_OBCTL0;
758 /* set option byte boot bank value */
759 reg &= ~FMC_OBCTL0_BB;
760 FMC_OBCTL0 = (reg | boot_mode);
761 }
762
763 /*!
764 \brief get the FMC user option byte
765 \param[in] none
766 \param[out] none
767 \retval the FMC user option byte values: ob_fwdgt(Bit0), ob_deepsleep(Bit1), ob_stdby(Bit2)
768 */
ob_user_get(void)769 uint8_t ob_user_get(void)
770 {
771 return (uint8_t)((uint8_t)(FMC_OBCTL0 >> 5U) & 0x07U);
772 }
773
774 /*!
775 \brief get the FMC option byte write protection
776 \param[in] none
777 \param[out] none
778 \retval the FMC write protection option byte value
779 */
ob_write_protection0_get(void)780 uint16_t ob_write_protection0_get(void)
781 {
782 /* return the FMC write protection option byte value */
783 return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16U)) & 0x0FFFU);
784 }
785
786 /*!
787 \brief get the FMC option byte write protection
788 \param[in] none
789 \param[out] none
790 \retval the FMC write protection option byte value
791 */
ob_write_protection1_get(void)792 uint16_t ob_write_protection1_get(void)
793 {
794 /* return the the FMC write protection option byte value */
795 return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16U)) & 0x0FFFU);
796 }
797
798 /*!
799 \brief get the FMC D-bus read protection protection
800 \param[in] none
801 \param[out] none
802 \retval the FMC erase/program protection and D-bus read protection option bytes value
803 */
ob_drp0_get(void)804 uint16_t ob_drp0_get(void)
805 {
806 /* return the FMC erase/program protection and D-bus read protection option bytes value */
807 if(FMC_OBCTL0 & FMC_OBCTL0_DRP) {
808 return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16U)) & 0x0FFFU);
809 } else {
810 return 0xF000U;
811 }
812 }
813
814 /*!
815 \brief get the FMC D-bus read protection protection
816 \param[in] none
817 \param[out] none
818 \retval the FMC erase/program protection and D-bus read protection option bytes value
819 */
ob_drp1_get(void)820 uint16_t ob_drp1_get(void)
821 {
822 /* return the FMC erase/program protection and D-bus read protection option bytes value */
823 if(FMC_OBCTL0 & FMC_OBCTL0_DRP) {
824 return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16U)) & 0x0FFFU);
825 } else {
826 return 0xF000U;
827 }
828 }
829
830 /*!
831 \brief get the FMC option byte security protection
832 \param[in] none
833 \param[out] none
834 \retval FlagStatus: SET or RESET
835 */
ob_spc_get(void)836 FlagStatus ob_spc_get(void)
837 {
838 FlagStatus spc_state = RESET;
839
840 if(((uint8_t)(FMC_OBCTL0 >> 8U)) != FMC_NSPC) {
841 spc_state = SET;
842 } else {
843 spc_state = RESET;
844 }
845 return spc_state;
846 }
847
848 /*!
849 \brief get the FMC option byte BOR threshold value
850 \param[in] none
851 \param[out] none
852 \retval the FMC BOR threshold value:OB_BOR_TH_OFF,OB_BOR_TH_VALUE1,OB_BOR_TH_VALUE2,OB_BOR_TH_VALUE3
853 */
ob_user_bor_threshold_get(void)854 uint8_t ob_user_bor_threshold_get(void)
855 {
856 /* return the FMC BOR threshold value */
857 return (uint8_t)((uint8_t)FMC_OBCTL0 & 0x0CU);
858 }
859
860 /*!
861 \brief get flag set or reset
862 \param[in] fmc_flag: check FMC flag
863 only one parameter can be selected which is shown as below:
864 \arg FMC_FLAG_BUSY: FMC busy flag bit
865 \arg FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
866 \arg FMC_FLAG_PGSERR: FMC program sequence error flag bit
867 \arg FMC_FLAG_PGMERR: FMC program size not match error flag bit
868 \arg FMC_FLAG_WPERR: FMC Erase/Program protection error flag bit
869 \arg FMC_FLAG_OPERR: FMC operation error flag bit
870 \arg FMC_FLAG_END: FMC end of operation flag bit
871 \param[out] none
872 \retval FlagStatus: SET or RESET
873 */
fmc_flag_get(uint32_t fmc_flag)874 FlagStatus fmc_flag_get(uint32_t fmc_flag)
875 {
876 if(FMC_STAT & fmc_flag) {
877 return SET;
878 }
879 /* return the state of corresponding FMC flag */
880 return RESET;
881 }
882
883 /*!
884 \brief clear the FMC pending flag
885 \param[in] FMC_flag: clear FMC flag
886 only one parameter can be selected which is shown as below:
887 \arg FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
888 \arg FMC_FLAG_PGSERR: FMC program sequence error flag bit
889 \arg FMC_FLAG_PGMERR: FMC program size not match error flag bit
890 \arg FMC_FLAG_WPERR: FMC erase/program protection error flag bit
891 \arg FMC_FLAG_OPERR: FMC operation error flag bit
892 \arg FMC_FLAG_END: FMC end of operation flag bit
893 \param[out] none
894 \retval none
895 */
fmc_flag_clear(uint32_t fmc_flag)896 void fmc_flag_clear(uint32_t fmc_flag)
897 {
898 /* clear the flags */
899 FMC_STAT = fmc_flag;
900 }
901
902 /*!
903 \brief enable FMC interrupt
904 \param[in] fmc_int: the FMC interrupt source
905 only one parameter can be selected which is shown as below:
906 \arg FMC_INT_END: enable FMC end of program interrupt
907 \arg FMC_INT_ERR: enable FMC error interrupt
908 \param[out] none
909 \retval none
910 */
fmc_interrupt_enable(uint32_t fmc_int)911 void fmc_interrupt_enable(uint32_t fmc_int)
912 {
913 FMC_CTL |= fmc_int;
914 }
915
916 /*!
917 \brief disable FMC interrupt
918 \param[in] fmc_int: the FMC interrupt source
919 only one parameter can be selected which is shown as below:
920 \arg FMC_INT_END: disable FMC end of program interrupt
921 \arg FMC_INT_ERR: disable FMC error interrupt
922 \param[out] none
923 \retval none
924 */
fmc_interrupt_disable(uint32_t fmc_int)925 void fmc_interrupt_disable(uint32_t fmc_int)
926 {
927 FMC_CTL &= ~(uint32_t)fmc_int;
928 }
929
930 /*!
931 \brief get FMC interrupt flag set or reset
932 \param[in] fmc_int_flag: FMC interrupt flag
933 only one parameter can be selected which is shown as below:
934 \arg FMC_INT_FLAG_RDDERR: FMC read D-bus protection error interrupt flag
935 \arg FMC_INT_FLAG_PGSERR: FMC program sequence error interrupt flag
936 \arg FMC_INT_FLAG_PGMERR: FMC program size not match error interrupt flag
937 \arg FMC_INT_FLAG_WPERR: FMC Erase/Program protection error interrupt flag
938 \arg FMC_INT_FLAG_OPERR: FMC operation error interrupt flag
939 \arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
940 \param[out] none
941 \retval FlagStatus: SET or RESET
942 */
fmc_interrupt_flag_get(uint32_t fmc_int_flag)943 FlagStatus fmc_interrupt_flag_get(uint32_t fmc_int_flag)
944 {
945 if(FMC_FLAG_END == fmc_int_flag) {
946 /* end of operation interrupt flag */
947 if(FMC_CTL & FMC_CTL_ENDIE) {
948 if(FMC_STAT & fmc_int_flag) {
949 return SET;
950 }
951 }
952 } else {
953 /* error interrupt flags */
954 if(FMC_CTL & FMC_CTL_ERRIE) {
955 if(FMC_STAT & fmc_int_flag) {
956 return SET;
957 }
958 }
959 }
960
961 return RESET;
962 }
963
964 /*!
965 \brief clear the FMC interrupt flag
966 \param[in] fmc_int_flag: FMC interrupt flag
967 only one parameter can be selected which is shown as below:
968 \arg FMC_INT_FLAG_RDDERR: FMC read D-bus protection error interrupt flag
969 \arg FMC_INT_FLAG_PGSERR: FMC program sequence error interrupt flag
970 \arg FMC_INT_FLAG_PGMERR: FMC program size not match error interrupt flag
971 \arg FMC_INT_FLAG_WPERR: FMC Erase/Program protection error interrupt flag
972 \arg FMC_INT_FLAG_OPERR: FMC operation error interrupt flag
973 \arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
974 \param[out] none
975 \retval none
976 */
fmc_interrupt_flag_clear(uint32_t fmc_int_flag)977 void fmc_interrupt_flag_clear(uint32_t fmc_int_flag)
978 {
979 /* clear the interrupt flag */
980 FMC_STAT = fmc_int_flag;
981 }
982
983 /*!
984 \brief get the FMC state
985 \param[in] none
986 \param[out] none
987 \retval state of FMC
988 \arg FMC_READY: the operation has been completed
989 \arg FMC_BUSY: the operation is in progress
990 \arg FMC_RDDERR: read D-bus protection error
991 \arg FMC_PGSERR: program sequence error
992 \arg FMC_PGMERR: program size not match error
993 \arg FMC_WPERR: erase/program protection error
994 \arg FMC_OPERR: operation error
995 */
fmc_state_get(void)996 fmc_state_enum fmc_state_get(void)
997 {
998 fmc_state_enum fmc_state = FMC_READY;
999 uint32_t temp_val = FMC_STAT;
1000
1001 if(RESET != (temp_val & FMC_FLAG_BUSY)) {
1002 fmc_state = FMC_BUSY;
1003 } else if(RESET != (temp_val & FMC_FLAG_RDDERR)) {
1004 fmc_state = FMC_RDDERR;
1005 } else if(RESET != (temp_val & FMC_FLAG_PGSERR)) {
1006 fmc_state = FMC_PGSERR;
1007 } else if(RESET != (temp_val & FMC_FLAG_PGMERR)) {
1008 fmc_state = FMC_PGMERR;
1009 } else if(RESET != (temp_val & FMC_FLAG_WPERR)) {
1010 fmc_state = FMC_WPERR;
1011 } else if(RESET != (temp_val & FMC_FLAG_OPERR)) {
1012 fmc_state = FMC_OPERR;
1013 } else {
1014 fmc_state = FMC_READY;
1015 }
1016
1017 /* return the FMC state */
1018 return fmc_state;
1019 }
1020
1021 /*!
1022 \brief check whether FMC is ready or not
1023 \param[in] none
1024 \param[out] none
1025 \retval state of FMC
1026 \arg FMC_READY: the operation has been completed
1027 \arg FMC_BUSY: the operation is in progress
1028 \arg FMC_RDDERR: read D-bus protection error
1029 \arg FMC_PGSERR: program sequence error
1030 \arg FMC_PGMERR: program size not match error
1031 \arg FMC_WPERR: erase/program protection error
1032 \arg FMC_OPERR: operation error
1033 \arg FMC_TOERR: timeout error
1034 */
fmc_ready_wait(uint32_t timeout)1035 fmc_state_enum fmc_ready_wait(uint32_t timeout)
1036 {
1037 fmc_state_enum fmc_state = FMC_BUSY;
1038
1039 /* wait for FMC ready */
1040 do {
1041 /* get FMC state */
1042 fmc_state = fmc_state_get();
1043 timeout--;
1044 } while((FMC_BUSY == fmc_state) && (0U != timeout));
1045
1046 if(0U == timeout) {
1047 fmc_state = FMC_TOERR;
1048 }
1049
1050 /* return the FMC state */
1051 return fmc_state;
1052 }
1053