1 /*!
2 \file gd32f403_fmc.c
3 \brief FMC driver
4
5 \version 2017-02-10, V1.0.0, firmware for GD32F403
6 \version 2018-12-25, V2.0.0, firmware for GD32F403
7 \version 2020-09-30, V2.1.0, firmware for GD32F403
8 */
9
10 /*
11 Copyright (c) 2020, GigaDevice Semiconductor Inc.
12
13 Redistribution and use in source and binary forms, with or without modification,
14 are permitted provided that the following conditions are met:
15
16 1. Redistributions of source code must retain the above copyright notice, this
17 list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright notice,
19 this list of conditions and the following disclaimer in the documentation
20 and/or other materials provided with the distribution.
21 3. Neither the name of the copyright holder nor the names of its contributors
22 may be used to endorse or promote products derived from this software without
23 specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 OF SUCH DAMAGE.
35 */
36
37 #include "gd32f403_fmc.h"
38
39 /*!
40 \brief set the wait state counter value
41 \param[in] wscnt:wait state counter value
42 \arg WS_WSCNT_0: FMC 0 wait
43 \arg WS_WSCNT_1: FMC 1 wait
44 \arg WS_WSCNT_2: FMC 2 wait
45 \param[out] none
46 \retval none
47 */
fmc_wscnt_set(uint32_t wscnt)48 void fmc_wscnt_set(uint32_t wscnt)
49 {
50 uint32_t reg;
51
52 reg = FMC_WS;
53 /* set the wait state counter value */
54 reg &= ~FMC_WS_WSCNT;
55 FMC_WS = (reg | wscnt);
56 }
57
58 /*!
59 \brief unlock the main FMC operation
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_CTL0 & FMC_CTL0_LK))){
67 /* write the FMC unlock key */
68 FMC_KEY0 = UNLOCK_KEY0;
69 FMC_KEY0 = UNLOCK_KEY1;
70 }
71 if(FMC_BANK0_SIZE < FMC_SIZE){
72 /* write the FMC unlock key */
73 if(RESET != (FMC_CTL1 & FMC_CTL1_LK)){
74 FMC_KEY1 = UNLOCK_KEY0;
75 FMC_KEY1 = UNLOCK_KEY1;
76 }
77 }
78 }
79
80 /*!
81 \brief unlock the FMC bank0 operation
82 this function can be used for all GD32F403 devices.
83 for GD32F403 with flash more than 512KB, this function unlocks bank0.
84 for GD32F403 with flash no more than 512KB and it is equivalent to fmc_unlock function.
85 \param[in] none
86 \param[out] none
87 \retval none
88 */
fmc_bank0_unlock(void)89 void fmc_bank0_unlock(void)
90 {
91 if((RESET != (FMC_CTL0 & FMC_CTL0_LK))){
92 /* write the FMC unlock key */
93 FMC_KEY0 = UNLOCK_KEY0;
94 FMC_KEY0 = UNLOCK_KEY1;
95 }
96 }
97
98 /*!
99 \brief unlock the FMC bank1 operation
100 this function can be used for GD32F403 with flash more than 512KB.
101 \param[in] none
102 \param[out] none
103 \retval none
104 */
fmc_bank1_unlock(void)105 void fmc_bank1_unlock(void)
106 {
107 if((RESET != (FMC_CTL1 & FMC_CTL1_LK))){
108 /* write the FMC unlock key */
109 FMC_KEY1 = UNLOCK_KEY0;
110 FMC_KEY1 = UNLOCK_KEY1;
111 }
112 }
113
114 /*!
115 \brief lock the main FMC operation
116 \param[in] none
117 \param[out] none
118 \retval none
119 */
fmc_lock(void)120 void fmc_lock(void)
121 {
122 /* set the LK bit */
123 FMC_CTL0 |= FMC_CTL0_LK;
124
125 if(FMC_BANK0_SIZE < FMC_SIZE){
126 /* set the LK bit */
127 FMC_CTL1 |= FMC_CTL1_LK;
128 }
129 }
130
131 /*!
132 \brief lock the FMC bank0 operation
133 this function can be used for all GD32F403 devices.
134 for GD32F403 with flash more than 512KB, this function locks bank0.
135 for GD32F403 with flash no more than 512KB and it is equivalent to fmc_lock function.
136 \param[in] none
137 \param[out] none
138 \retval none
139 */
fmc_bank0_lock(void)140 void fmc_bank0_lock(void)
141 {
142 /* set the LK bit*/
143 FMC_CTL0 |= FMC_CTL0_LK;
144 }
145
146 /*!
147 \brief lock the FMC bank1 operation
148 this function can be used for GD32F403 with flash more than 512KB.
149 \param[in] none
150 \param[out] none
151 \retval none
152 */
fmc_bank1_lock(void)153 void fmc_bank1_lock(void)
154 {
155 /* set the LK bit*/
156 FMC_CTL1 |= FMC_CTL1_LK;
157 }
158
159 /*!
160 \brief erase page
161 \param[in] page_address: the page address to be erased.
162 \param[out] none
163 \retval state of FMC, refer to fmc_state_enum
164 */
fmc_page_erase(uint32_t page_address)165 fmc_state_enum fmc_page_erase(uint32_t page_address)
166 {
167 fmc_state_enum fmc_state;
168
169 if(FMC_BANK0_SIZE < FMC_SIZE){
170 if(FMC_BANK0_END_ADDRESS > page_address){
171 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
172 /* if the last operation is completed, start page erase */
173 if(FMC_READY == fmc_state){
174 FMC_CTL0 |= FMC_CTL0_PER;
175 FMC_ADDR0 = page_address;
176 FMC_CTL0 |= FMC_CTL0_START;
177 /* wait for the FMC ready */
178 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
179 /* reset the PER bit */
180 FMC_CTL0 &= ~FMC_CTL0_PER;
181 }
182 }else{
183 /* wait for the FMC ready */
184 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
185 /* if the last operation is completed, start page erase */
186 if(FMC_READY == fmc_state){
187 FMC_CTL1 |= FMC_CTL1_PER;
188 FMC_ADDR1 = page_address;
189 if(FMC_OBSTAT & FMC_OBSTAT_SPC){
190 FMC_ADDR0 = page_address;
191 }
192 FMC_CTL1 |= FMC_CTL1_START;
193 /* wait for the FMC ready */
194 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
195 /* reset the PER bit */
196 FMC_CTL1 &= ~FMC_CTL1_PER;
197 }
198 }
199 }else{
200 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
201 /* if the last operation is completed, start page erase */
202 if(FMC_READY == fmc_state){
203 FMC_CTL0 |= FMC_CTL0_PER;
204 FMC_ADDR0 = page_address;
205 FMC_CTL0 |= FMC_CTL0_START;
206 /* wait for the FMC ready */
207 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
208 /* reset the PER bit */
209 FMC_CTL0 &= ~FMC_CTL0_PER;
210 }
211 }
212 /* return the FMC state */
213 return fmc_state;
214 }
215
216 /*!
217 \brief erase whole chip
218 \param[in] none
219 \param[out] none
220 \retval state of FMC, refer to fmc_state_enum
221 */
fmc_mass_erase(void)222 fmc_state_enum fmc_mass_erase(void)
223 {
224 fmc_state_enum fmc_state;
225 if(FMC_BANK0_SIZE < FMC_SIZE){
226 /* wait for the FMC ready */
227 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
228 if(FMC_READY == fmc_state){
229 /* start whole chip erase */
230 FMC_CTL0 |= FMC_CTL0_MER;
231 FMC_CTL0 |= FMC_CTL0_START;
232 /* wait for the FMC ready */
233 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
234 /* reset the MER bit */
235 FMC_CTL0 &= ~FMC_CTL0_MER;
236 }
237 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
238 if(FMC_READY == fmc_state){
239 /* start whole chip erase */
240 FMC_CTL1 |= FMC_CTL1_MER;
241 FMC_CTL1 |= FMC_CTL1_START;
242 /* wait for the FMC ready */
243 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
244 /* reset the MER bit */
245 FMC_CTL1 &= ~FMC_CTL1_MER;
246 }
247 }else{
248 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
249
250 if(FMC_READY == fmc_state){
251 /* start whole chip erase */
252 FMC_CTL0 |= FMC_CTL0_MER;
253 FMC_CTL0 |= FMC_CTL0_START;
254 /* wait for the FMC ready */
255 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
256 /* reset the MER bit */
257 FMC_CTL0 &= ~FMC_CTL0_MER;
258 }
259 }
260 /* return the FMC state */
261 return fmc_state;
262 }
263
264 /*!
265 \brief erase bank0
266 \param[in] none
267 \param[out] none
268 \retval state of FMC, refer to fmc_state_enum
269 */
fmc_bank0_erase(void)270 fmc_state_enum fmc_bank0_erase(void)
271 {
272 fmc_state_enum fmc_state = FMC_READY;
273 /* wait for the FMC ready */
274 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
275
276 if(FMC_READY == fmc_state){
277 /* start FMC bank0 erase */
278 FMC_CTL0 |= FMC_CTL0_MER;
279 FMC_CTL0 |= FMC_CTL0_START;
280 /* wait for the FMC ready */
281 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
282 /* reset the MER bit */
283 FMC_CTL0 &= ~FMC_CTL0_MER;
284 }
285 /* return the fmc state */
286 return fmc_state;
287 }
288
289 /*!
290 \brief erase bank1
291 \param[in] none
292 \param[out] none
293 \retval state of FMC, refer to fmc_state_enum
294 */
fmc_bank1_erase(void)295 fmc_state_enum fmc_bank1_erase(void)
296 {
297 fmc_state_enum fmc_state = FMC_READY;
298 /* wait for the FMC ready */
299 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
300
301 if(FMC_READY == fmc_state){
302 /* start FMC bank1 erase */
303 FMC_CTL1 |= FMC_CTL1_MER;
304 FMC_CTL1 |= FMC_CTL1_START;
305 /* wait for the FMC ready */
306 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
307 /* reset the MER bit */
308 FMC_CTL1 &= ~FMC_CTL1_MER;
309 }
310 /* return the fmc state */
311 return fmc_state;
312 }
313
314 /*!
315 \brief program a word at the corresponding address
316 \param[in] address: address to program
317 \param[in] data: word to program
318 \param[out] none
319 \retval state of FMC, refer to fmc_state_enum
320 */
fmc_word_program(uint32_t address,uint32_t data)321 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
322 {
323 fmc_state_enum fmc_state = FMC_READY;
324 if(FMC_BANK0_SIZE < FMC_SIZE){
325 if(FMC_BANK0_END_ADDRESS > address){
326 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
327
328 if(FMC_READY == fmc_state){
329 /* set the PG bit to start program */
330 FMC_CTL0 |= FMC_CTL0_PG;
331 REG32(address) = data;
332 /* wait for the FMC ready */
333 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
334 /* reset the PG bit */
335 FMC_CTL0 &= ~FMC_CTL0_PG;
336 }
337 }else{
338 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
339
340 if(FMC_READY == fmc_state){
341 /* set the PG bit to start program */
342 FMC_CTL1 |= FMC_CTL1_PG;
343 REG32(address) = data;
344 /* wait for the FMC ready */
345 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
346 /* reset the PG bit */
347 FMC_CTL1 &= ~FMC_CTL1_PG;
348 }
349 }
350 }else{
351 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
352
353 if(FMC_READY == fmc_state){
354 /* set the PG bit to start program */
355 FMC_CTL0 |= FMC_CTL0_PG;
356 REG32(address) = data;
357 /* wait for the FMC ready */
358 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
359 /* reset the PG bit */
360 FMC_CTL0 &= ~FMC_CTL0_PG;
361 }
362 }
363 /* return the FMC state */
364 return fmc_state;
365 }
366
367 /*!
368 \brief program a half word at the corresponding address
369 \param[in] address: address to program
370 \param[in] data: halfword to program
371 \param[out] none
372 \retval state of FMC, refer to fmc_state_enum
373 */
fmc_halfword_program(uint32_t address,uint16_t data)374 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
375 {
376 fmc_state_enum fmc_state = FMC_READY;
377 if(FMC_BANK0_SIZE < FMC_SIZE){
378 if(FMC_BANK0_END_ADDRESS > address){
379 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
380
381 if(FMC_READY == fmc_state){
382 /* set the PG bit to start program */
383 FMC_CTL0 |= FMC_CTL0_PG;
384 REG16(address) = data;
385 /* wait for the FMC ready */
386 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
387 /* reset the PG bit */
388 FMC_CTL0 &= ~FMC_CTL0_PG;
389 }
390 }else{
391 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
392
393 if(FMC_READY == fmc_state){
394 /* set the PG bit to start program */
395 FMC_CTL1 |= FMC_CTL1_PG;
396 REG16(address) = data;
397 /* wait for the FMC ready */
398 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
399 /* reset the PG bit */
400 FMC_CTL1 &= ~FMC_CTL1_PG;
401 }
402 }
403 }else{
404 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
405
406 if(FMC_READY == fmc_state){
407 /* set the PG bit to start program */
408 FMC_CTL0 |= FMC_CTL0_PG;
409 REG16(address) = data;
410 /* wait for the FMC ready */
411 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
412 /* reset the PG bit */
413 FMC_CTL0 &= ~FMC_CTL0_PG;
414 }
415 }
416 /* return the FMC state */
417 return fmc_state;
418 }
419
420 /*!
421 \brief program a word at the corresponding address without erasing
422 \param[in] address: address to program
423 \param[in] data: word to program
424 \param[out] none
425 \retval fmc_state
426 */
fmc_word_reprogram(uint32_t address,uint32_t data)427 fmc_state_enum fmc_word_reprogram(uint32_t address, uint32_t data)
428 {
429 fmc_state_enum fmc_state = FMC_READY;
430 if(FMC_BANK0_SIZE < FMC_SIZE){
431 if(FMC_BANK0_END_ADDRESS > address){
432 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
433 FMC_WSEN |= FMC_WSEN_BPEN;
434 if(FMC_READY == fmc_state){
435 /* set the PG bit to start program */
436 FMC_CTL0 |= FMC_CTL0_PG;
437 REG32(address) = data;
438 /* wait for the FMC ready */
439 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
440 /* reset the PG bit */
441 FMC_CTL0 &= ~FMC_CTL0_PG;
442 }
443 }else{
444 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
445 FMC_WSEN |= FMC_WSEN_BPEN;
446 if(FMC_READY == fmc_state){
447 /* set the PG bit to start program */
448 FMC_CTL1 |= FMC_CTL1_PG;
449 REG32(address) = data;
450 /* wait for the FMC ready */
451 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
452 /* reset the PG bit */
453 FMC_CTL1 &= ~FMC_CTL1_PG;
454 }
455 }
456 }else{
457 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
458 FMC_WSEN |= FMC_WSEN_BPEN;
459 if(FMC_READY == fmc_state){
460 /* set the PG bit to start program */
461 FMC_CTL0 |= FMC_CTL0_PG;
462 REG32(address) = data;
463 /* wait for the FMC ready */
464 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
465 /* reset the PG bit */
466 FMC_CTL0 &= ~FMC_CTL0_PG;
467 }
468 }
469 /* return the FMC state */
470 return fmc_state;
471 }
472
473 /*!
474 \brief unlock the option byte operation
475 \param[in] none
476 \param[out] none
477 \retval none
478 */
ob_unlock(void)479 void ob_unlock(void)
480 {
481 if(RESET == (FMC_CTL0 & FMC_CTL0_OBWEN)){
482 /* write the FMC key */
483 FMC_OBKEY = UNLOCK_KEY0;
484 FMC_OBKEY = UNLOCK_KEY1;
485 }
486 }
487
488 /*!
489 \brief lock the option byte operation
490 \param[in] none
491 \param[out] none
492 \retval none
493 */
ob_lock(void)494 void ob_lock(void)
495 {
496 /* reset the OBWEN bit */
497 FMC_CTL0 &= ~FMC_CTL0_OBWEN;
498 }
499
500 /*!
501 \brief erase the FMC option byte
502 unlock the FMC_CTL0 and option byte before calling this function
503 \param[in] none
504 \param[out] none
505 \retval state of FMC, refer to fmc_state_enum
506 */
ob_erase(void)507 fmc_state_enum ob_erase(void)
508 {
509 uint16_t temp_spc = FMC_NSPC;
510
511 fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
512
513 /* check the option byte security protection value */
514 if(RESET != ob_spc_get()){
515 temp_spc = FMC_USPC;
516 }
517
518 if(FMC_READY == fmc_state){
519
520 /* start erase the option byte */
521 FMC_CTL0 |= FMC_CTL0_OBER;
522 FMC_CTL0 |= FMC_CTL0_START;
523
524 /* wait for the FMC ready */
525 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
526
527 if(FMC_READY == fmc_state){
528 /* reset the OBER bit */
529 FMC_CTL0 &= ~FMC_CTL0_OBER;
530 /* set the OBPG bit */
531 FMC_CTL0 |= FMC_CTL0_OBPG;
532 /* no security protection */
533 OB_SPC = (uint16_t)temp_spc;
534 /* wait for the FMC ready */
535 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
536 if(FMC_TOERR != fmc_state){
537 /* reset the OBPG bit */
538 FMC_CTL0 &= ~FMC_CTL0_OBPG;
539 }
540 }else{
541 if(FMC_TOERR != fmc_state){
542 /* reset the OBPG bit */
543 FMC_CTL0 &= ~FMC_CTL0_OBPG;
544 }
545 }
546 }
547 /* return the FMC state */
548 return fmc_state;
549 }
550
551 /*!
552 \brief enable write protection
553 \param[in] ob_wp: specify sector to be write protected
554 \arg OB_WPx(x=0..31): write protect specify sector
555 \arg OB_WP_ALL: write protect all sector
556 \param[out] none
557 \retval state of FMC, refer to fmc_state_enum
558 */
ob_write_protection_enable(uint32_t ob_wp)559 fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
560 {
561 uint16_t temp_wp0, temp_wp1, temp_wp2, temp_wp3;
562
563 fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
564
565 ob_wp = (uint32_t)(~ob_wp);
566 temp_wp0 = (uint16_t)(ob_wp & OB_WP0_WP0);
567 temp_wp1 = (uint16_t)((ob_wp & OB_WP1_WP1) >> 8U);
568 temp_wp2 = (uint16_t)((ob_wp & OB_WP2_WP2) >> 16U);
569 temp_wp3 = (uint16_t)((ob_wp & OB_WP3_WP3) >> 24U);
570
571 if(FMC_READY == fmc_state){
572
573 /* set the OBPG bit*/
574 FMC_CTL0 |= FMC_CTL0_OBPG;
575
576 if(0xFFU != temp_wp0){
577 OB_WP0 = temp_wp0;
578
579 /* wait for the FMC ready */
580 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
581 }
582 if((FMC_READY == fmc_state) && (0xFFU != temp_wp1)){
583 OB_WP1 = temp_wp1;
584
585 /* wait for the FMC ready */
586 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
587 }
588 if((FMC_READY == fmc_state) && (0xFFU != temp_wp2)){
589 OB_WP2 = temp_wp2;
590
591 /* wait for the FMC ready */
592 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
593 }
594 if((FMC_READY == fmc_state) && (0xFFU != temp_wp3)){
595 OB_WP3 = temp_wp3;
596
597 /* wait for the FMC ready */
598 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
599 }
600 if(FMC_TOERR != fmc_state){
601 /* reset the OBPG bit */
602 FMC_CTL0 &= ~FMC_CTL0_OBPG;
603 }
604 }
605 /* return the FMC state */
606 return fmc_state;
607 }
608
609 /*!
610 \brief configure security protection
611 \param[in] ob_spc: specify security protection
612 \arg FMC_NSPC: no security protection
613 \arg FMC_USPC: under security protection
614 \param[out] none
615 \retval state of FMC, refer to fmc_state_enum
616 */
ob_security_protection_config(uint8_t ob_spc)617 fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
618 {
619 fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
620
621 if(FMC_READY == fmc_state){
622 FMC_CTL0 |= FMC_CTL0_OBER;
623 FMC_CTL0 |= FMC_CTL0_START;
624
625 /* wait for the FMC ready */
626 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
627
628 if(FMC_READY == fmc_state){
629 /* reset the OBER bit */
630 FMC_CTL0 &= ~FMC_CTL0_OBER;
631
632 /* start the option byte program */
633 FMC_CTL0 |= FMC_CTL0_OBPG;
634
635 OB_SPC = (uint16_t)ob_spc;
636
637 /* wait for the FMC ready */
638 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
639
640 if(FMC_TOERR != fmc_state){
641 /* reset the OBPG bit */
642 FMC_CTL0 &= ~FMC_CTL0_OBPG;
643 }
644 }else{
645 if(FMC_TOERR != fmc_state){
646 /* reset the OBER bit */
647 FMC_CTL0 &= ~FMC_CTL0_OBER;
648 }
649 }
650 }
651 /* return the FMC state */
652 return fmc_state;
653 }
654
655 /*!
656 \brief program the FMC user option byte
657 \param[in] ob_fwdgt: option byte watchdog value
658 \arg OB_FWDGT_SW: software free watchdog
659 \arg OB_FWDGT_HW: hardware free watchdog
660 \param[in] ob_deepsleep: option byte deepsleep reset value
661 \arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
662 \arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
663 \param[in] ob_stdby:option byte standby reset value
664 \arg OB_STDBY_NRST: no reset when entering standby mode
665 \arg OB_STDBY_RST: generate a reset instead of entering standby mode
666 \param[in] ob_boot: specifies the option byte boot bank value
667 \arg OB_BOOT_B0: boot from bank0
668 \arg OB_BOOT_B1: boot from bank1 or bank0 if bank1 is void
669 \param[out] none
670 \retval state of FMC, refer to fmc_state_enum
671 */
ob_user_write(uint8_t ob_fwdgt,uint8_t ob_deepsleep,uint8_t ob_stdby,uint8_t ob_boot)672 fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby, uint8_t ob_boot)
673 {
674 fmc_state_enum fmc_state = FMC_READY;
675 uint8_t temp;
676
677 /* wait for the FMC ready */
678 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
679
680 if(FMC_READY == fmc_state){
681 /* set the OBPG bit*/
682 FMC_CTL0 |= FMC_CTL0_OBPG;
683
684 temp = ((uint8_t)((uint8_t)((uint8_t)(ob_boot | ob_fwdgt) | ob_deepsleep) | ob_stdby) | OB_USER_MASK);
685 OB_USER = (uint16_t)temp;
686
687 /* wait for the FMC ready */
688 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
689
690 if(FMC_TOERR != fmc_state){
691 /* reset the OBPG bit */
692 FMC_CTL0 &= ~FMC_CTL0_OBPG;
693 }
694 }
695 /* return the FMC state */
696 return fmc_state;
697 }
698
699 /*!
700 \brief program option bytes data
701 \param[in] address: the option bytes address to be programmed
702 \param[in] data: the byte to be programmed
703 \param[out] none
704 \retval state of FMC, refer to fmc_state_enum
705 */
ob_data_program(uint32_t address,uint8_t data)706 fmc_state_enum ob_data_program(uint32_t address, uint8_t data)
707 {
708 fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
709
710 if(FMC_READY == fmc_state){
711 /* set the OBPG bit */
712 FMC_CTL0 |= FMC_CTL0_OBPG;
713 REG16(address) = data;
714
715 /* wait for the FMC ready */
716 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
717
718 if(FMC_TOERR != fmc_state){
719 /* reset the OBPG bit */
720 FMC_CTL0 &= ~FMC_CTL0_OBPG;
721 }
722 }
723 /* return the FMC state */
724 return fmc_state;
725 }
726
727 /*!
728 \brief get the FMC user option byte
729 \param[in] none
730 \param[out] none
731 \retval the FMC user option byte values
732 */
ob_user_get(void)733 uint8_t ob_user_get(void)
734 {
735 /* return the FMC user option byte value */
736 return (uint8_t)(FMC_OBSTAT >> 2U);
737 }
738
739 /*!
740 \brief get OB_DATA in register FMC_OBSTAT
741 \param[in] none
742 \param[out] none
743 \retval ob_data
744 */
ob_data_get(void)745 uint16_t ob_data_get(void)
746 {
747 return (uint16_t)(FMC_OBSTAT >> 10U);
748 }
749
750 /*!
751 \brief get the FMC option byte write protection
752 \param[in] none
753 \param[out] none
754 \retval the FMC write protection option byte value
755 */
ob_write_protection_get(void)756 uint32_t ob_write_protection_get(void)
757 {
758 /* return the FMC write protection option byte value */
759 return FMC_WP;
760 }
761
762 /*!
763 \brief get the FMC option byte security protection
764 \param[in] none
765 \param[out] none
766 \retval FlagStatus: SET or RESET
767 */
ob_spc_get(void)768 FlagStatus ob_spc_get(void)
769 {
770 FlagStatus spc_state = RESET;
771
772 if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
773 spc_state = SET;
774 }else{
775 spc_state = RESET;
776 }
777 return spc_state;
778 }
779
780 /*!
781 \brief enable FMC interrupt
782 \param[in] interrupt: the FMC interrupt source
783 \arg FMC_INT_BANK0_END: FMC bank0 end of program interrupt
784 \arg FMC_INT_BANK0_ERR: FMC bank0 error interrupt
785 \arg FMC_INT_BANK1_END: FMC bank1 end of program interrupt
786 \arg FMC_INT_BANK1_ERR: FMC bank1 error interrupt
787 \param[out] none
788 \retval none
789 */
fmc_interrupt_enable(uint32_t interrupt)790 void fmc_interrupt_enable(uint32_t interrupt)
791 {
792 FMC_REG_VAL(interrupt) |= BIT(FMC_BIT_POS(interrupt));
793 }
794
795 /*!
796 \brief disable FMC interrupt
797 \param[in] interrupt: the FMC interrupt source
798 \arg FMC_INT_BANK0_END: FMC bank0 end of program interrupt
799 \arg FMC_INT_BANK0_ERR: FMC bank0 error interrupt
800 \arg FMC_INT_BANK1_END: FMC bank1 end of program interrupt
801 \arg FMC_INT_BANK1_ERR: FMC bank1 error interrupt
802 \param[out] none
803 \retval none
804 */
fmc_interrupt_disable(uint32_t interrupt)805 void fmc_interrupt_disable(uint32_t interrupt)
806 {
807 FMC_REG_VAL(interrupt) &= ~BIT(FMC_BIT_POS(interrupt));
808 }
809
810 /*!
811 \brief check flag is set or not
812 \param[in] flag: check FMC flag
813 only one parameter can be selected which is shown as below:
814 \arg FMC_FLAG_BANK0_BUSY: FMC bank0 busy flag bit
815 \arg FMC_FLAG_BANK0_PGERR: FMC bank0 operation error flag bit
816 \arg FMC_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error flag bit
817 \arg FMC_FLAG_BANK0_END: FMC bank0 end of operation flag bit
818 \arg FMC_FLAG_OBERR: FMC option bytes read error flag bit
819 \arg FMC_FLAG_BANK1_BUSY: FMC bank1 busy flag bit
820 \arg FMC_FLAG_BANK1_PGERR: FMC bank1 operation error flag bit
821 \arg FMC_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error flag bit
822 \arg FMC_FLAG_BANK1_END: FMC bank1 end of operation flag bit
823 \param[out] none
824 \retval FlagStatus: SET or RESET
825 */
fmc_flag_get(uint32_t flag)826 FlagStatus fmc_flag_get(uint32_t flag)
827 {
828 if(RESET != (FMC_REG_VAL(flag) & BIT(FMC_BIT_POS(flag)))){
829 return SET;
830 }else{
831 return RESET;
832 }
833 }
834
835 /*!
836 \brief clear the FMC flag
837 \param[in] flag: clear FMC flag
838 only one parameter can be selected which is shown as below:
839 \arg FMC_FLAG_BANK0_PGERR: FMC bank0 operation error flag bit
840 \arg FMC_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error flag bit
841 \arg FMC_FLAG_BANK0_END: FMC bank0 end of operation flag bit
842 \arg FMC_FLAG_BANK1_PGERR: FMC bank1 operation error flag bit
843 \arg FMC_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error flag bit
844 \arg FMC_FLAG_BANK1_END: FMC bank1 end of operation flag bit
845 \param[out] none
846 \retval none
847 */
fmc_flag_clear(uint32_t flag)848 void fmc_flag_clear(uint32_t flag)
849 {
850 FMC_REG_VAL(flag) |= BIT(FMC_BIT_POS(flag));
851 }
852
853 /*!
854 \brief get FMC interrupt flag state
855 \param[in] flag: FMC interrupt flags, refer to fmc_interrupt_flag_enum
856 only one parameter can be selected which is shown as below:
857 \arg FMC_INT_FLAG_BANK0_PGERR: FMC bank0 operation error interrupt flag bit
858 \arg FMC_INT_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error interrupt flag bit
859 \arg FMC_INT_FLAG_BANK0_END: FMC bank0 end of operation interrupt flag bit
860 \arg FMC_INT_FLAG_BANK1_PGERR: FMC bank1 operation error interrupt flag bit
861 \arg FMC_INT_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error interrupt flag bit
862 \arg FMC_INT_FLAG_BANK1_END: FMC bank1 end of operation interrupt flag bit
863 \param[out] none
864 \retval FlagStatus: SET or RESET
865 */
fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)866 FlagStatus fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)
867 {
868 FlagStatus ret1 = RESET;
869 FlagStatus ret2 = RESET;
870
871 if(FMC_STAT0_REG_OFFSET == FMC_REG_OFFSET_GET(flag)){
872 /* get the staus of interrupt flag */
873 ret1 = (FlagStatus)(FMC_REG_VALS(flag) & BIT(FMC_BIT_POS0(flag)));
874 /* get the staus of interrupt enale bit */
875 ret2 = (FlagStatus)(FMC_CTL0 & BIT(FMC_BIT_POS1(flag)));
876 }else{
877 /* get the staus of interrupt flag */
878 ret1 = (FlagStatus)(FMC_REG_VALS(flag) & BIT(FMC_BIT_POS0(flag)));
879 /* get the staus of interrupt enale bit */
880 ret2 = (FlagStatus)(FMC_CTL1 & BIT(FMC_BIT_POS1(flag)));
881 }
882
883 if(ret1 && ret2){
884 return SET;
885 }else{
886 return RESET;
887 }
888 }
889
890 /*!
891 \brief clear FMC interrupt flag state
892 \param[in] flag: FMC interrupt flags, refer to can_interrupt_flag_enum
893 only one parameter can be selected which is shown as below:
894 \arg FMC_INT_FLAG_BANK0_PGERR: FMC bank0 operation error interrupt flag bit
895 \arg FMC_INT_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error interrupt flag bit
896 \arg FMC_INT_FLAG_BANK0_END: FMC bank0 end of operation interrupt flag bit
897 \arg FMC_INT_FLAG_BANK1_PGERR: FMC bank1 operation error interrupt flag bit
898 \arg FMC_INT_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error interrupt flag bit
899 \arg FMC_INT_FLAG_BANK1_END: FMC bank1 end of operation interrupt flag bit
900 \param[out] none
901 \retval none
902 */
fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)903 void fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)
904 {
905 FMC_REG_VALS(flag) |= BIT(FMC_BIT_POS0(flag));
906 }
907
908 /*!
909 \brief get the FMC bank0 state
910 \param[in] none
911 \param[out] none
912 \retval state of FMC, refer to fmc_state_enum
913 */
fmc_bank0_state_get(void)914 fmc_state_enum fmc_bank0_state_get(void)
915 {
916 fmc_state_enum fmc_state = FMC_READY;
917
918 if((uint32_t)0x00U != (FMC_STAT0 & FMC_STAT0_BUSY)){
919 fmc_state = FMC_BUSY;
920 }else{
921 if((uint32_t)0x00U != (FMC_STAT0 & FMC_STAT0_WPERR)){
922 fmc_state = FMC_WPERR;
923 }else{
924 if((uint32_t)0x00U != (FMC_STAT0 & (FMC_STAT0_PGERR))){
925 fmc_state = FMC_PGERR;
926 }
927 }
928 }
929 /* return the FMC state */
930 return fmc_state;
931 }
932
933 /*!
934 \brief get the FMC bank1 state
935 \param[in] none
936 \param[out] none
937 \retval state of FMC, refer to fmc_state_enum
938 */
fmc_bank1_state_get(void)939 fmc_state_enum fmc_bank1_state_get(void)
940 {
941 fmc_state_enum fmc_state = FMC_READY;
942
943 if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_BUSY)){
944 fmc_state = FMC_BUSY;
945 }else{
946 if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_WPERR)){
947 fmc_state = FMC_WPERR;
948 }else{
949 if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_PGERR)){
950 fmc_state = FMC_PGERR;
951 }
952 }
953 }
954
955 /* return the FMC state */
956 return fmc_state;
957 }
958
959 /*!
960 \brief check whether FMC bank0 is ready or not
961 \param[in] timeout: count of loop
962 \param[out] none
963 \retval state of FMC, refer to fmc_state_enum
964 */
fmc_bank0_ready_wait(uint32_t timeout)965 fmc_state_enum fmc_bank0_ready_wait(uint32_t timeout)
966 {
967 fmc_state_enum fmc_state = FMC_BUSY;
968
969 /* wait for FMC ready */
970 do{
971 /* get FMC state */
972 fmc_state = fmc_bank0_state_get();
973 timeout--;
974 }while((FMC_BUSY == fmc_state) && (0x00U != timeout));
975
976 if(FMC_BUSY == fmc_state){
977 fmc_state = FMC_TOERR;
978 }
979 /* return the FMC state */
980 return fmc_state;
981 }
982
983 /*!
984 \brief check whether FMC bank1 is ready or not
985 \param[in] timeout: count of loop
986 \param[out] none
987 \retval state of FMC, refer to fmc_state_enum
988 */
fmc_bank1_ready_wait(uint32_t timeout)989 fmc_state_enum fmc_bank1_ready_wait(uint32_t timeout)
990 {
991 fmc_state_enum fmc_state = FMC_BUSY;
992
993 /* wait for FMC ready */
994 do{
995 /* get FMC state */
996 fmc_state = fmc_bank1_state_get();
997 timeout--;
998 }while((FMC_BUSY == fmc_state) && (0x00U != timeout));
999
1000 if(FMC_BUSY == fmc_state){
1001 fmc_state = FMC_TOERR;
1002 }
1003 /* return the FMC state */
1004 return fmc_state;
1005 }
1006