1 /**
2   *********************************************************************************
3   *
4   * @file    utils.c
5   * @brief   This file contains the Utilities functions/types for the driver.
6   *
7   * @version V1.1
8   * @date    13 Apr 2021
9   * @author  AE Team
10   * @note
11   *          Change Logs:
12   *          Date            Author          Notes
13   *          07 Nov 2019     AE Team         The first version
14   *          13 Apr 2021     AE Team         Add API: sys_config()
15   *
16   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
17   *
18   * SPDX-License-Identifier: Apache-2.0
19   *
20   * Licensed under the Apache License, Version 2.0 (the License); you may
21   * not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   * www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
28   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   **********************************************************************************
32   */
33 
34 #include <string.h>
35 #include "ald_conf.h"
36 
37 /** @defgroup ES32FXXX_ALD EASTSOFT ES32F3xx ALD
38   * @brief Shanghai Eastsoft Microelectronics Cortex-M Chip Abstraction Layer Driver(ALD)
39   * @{
40   */
41 
42 /** @defgroup UTILS Utils
43   * @brief Utils module driver
44   * @{
45   */
46 
47 /** @defgroup ALD_Private_Constants Private Constants
48   * @brief ALD Private Constants
49   * @{
50   */
51 
52 /**
53   * @brief ALD version number
54   */
55 #define __ALD_VERSION_MAIN	(0x01) /**< [31:24] main version */
56 #define __ALD_VERSION_SUB1	(0x00) /**< [23:16] sub1 version */
57 #define __ALD_VERSION_SUB2	(0x00) /**< [15:8]  sub2 version */
58 #define __ALD_VERSION_RC	(0x00) /**< [7:0]  release candidate */
59 #define __ALD_VERSION		((__ALD_VERSION_MAIN << 24) | \
60                                  (__ALD_VERSION_SUB1 << 16) | \
61                                  (__ALD_VERSION_SUB2 << 8 ) | \
62                                  (__ALD_VERSION_RC))
63 /**
64   * @}
65   */
66 
67 /** @defgroup ALD_Private_Variables Private Variables
68   * @{
69   */
70 /** @brief lib_tick: Increase by one millisecond
71   */
72 static __IO uint32_t lib_tick;
73 uint32_t __systick_interval = SYSTICK_INTERVAL_1MS;
74 /**
75   * @}
76   */
77 
78 
79 /** @defgroup ALD_Public_Functions Public Functions
80   * @{
81   */
82 
83 /** @defgroup ALD_Public_Functions_Group1 Initialization Function
84   * @brief    Initialization functions
85   *
86   * @verbatim
87  ===============================================================================
88               ##### Initialization functions #####
89  ===============================================================================
90    [..]  This section provides functions allowing to:
91       (+) Initializes interface, the NVIC allocation and initial clock
92           configuration. It initializes the source of time base also when timeout
93           is needed and the backup domain when enabled.
94       (+) Configure The time base source to have 1ms time base with a dedicated
95           Tick interrupt priority.
96         (++) Systick timer is used by default as source of time base, but user
97              can eventually implement his proper time base source (a general purpose
98              timer for example or other time source), keeping in mind that Time base
99              duration should be kept 1ms.
100         (++) Time base configuration function (ald_tick_init()) is called automatically
101              at the beginning of the program after reset by ald_cmu_init() or at
102 	     any time when clock is configured.
103         (++) Source of time base is configured  to generate interrupts at regular
104              time intervals. Care must be taken if ald_delay_ms() is called from a
105              peripheral ISR process, the Tick interrupt line must have higher priority
106             (numerically lower) than the peripheral interrupt. Otherwise the caller
107             ISR process will be blocked.
108        (++) functions affecting time base configurations are declared as __weak
109              to make  override possible  in case of other implementations in user file.
110       (+) Configure the interval of Systick interrupt.
111 
112     @endverbatim
113   * @{
114   */
115 
116 /**
117   * @brief  This function Configures time base source, NVIC and DMA.
118   * @note   This function is called at the beginning of program after reset and before
119   *         the clock configuration.
120   * @note   The time base configuration is based on MSI clock when exiting from Reset.
121   *         Once done, time base tick start incrementing.
122   *         In the default implementation, Systick is used as source of time base.
123   *         The tick variable is incremented each 1ms in its ISR.
124   * @retval None
125   */
ald_cmu_init(void)126 void ald_cmu_init(void)
127 {
128 	NVIC_SetPriorityGrouping(NVIC_PRIORITY_GROUP_2);
129 	ald_cmu_clock_config_default();
130 	ald_tick_init(TICK_INT_PRIORITY);
131 #ifdef ALD_DMA
132 	ald_cmu_perh_clock_config(CMU_PERH_DMA, ENABLE);
133 	ald_dma_init(DMA0);
134 #endif
135 	return;
136 }
137 
138 /**
139   * @brief  This function configures the source of the time base.
140   *         The time source is configured to have 1ms time base with a dedicated
141   *         Tick interrupt priority.
142   * @note   In the default implementation, SysTick timer is the source of time base.
143   *         It is used to generate interrupts at regular time intervals.
144   *         Care must be taken if ald_delay_ms() is called from a peripheral ISR process,
145   *         The SysTick interrupt must have higher priority (numerically lower)
146   *         than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
147   *         The function is declared as __weak to be overwritten in case of other
148   *         implementation in user file.
149   * @param  prio: Tick interrupt priority.
150   * @retval None
151   */
ald_tick_init(uint32_t prio)152 __weak void ald_tick_init(uint32_t prio)
153 {
154 	/* Configure the SysTick IRQ */
155 	SysTick_Config(ald_cmu_get_sys_clock() / SYSTICK_INTERVAL_1MS);
156 	NVIC_SetPriority(SysTick_IRQn, prio);
157 
158 	return;
159 }
160 
161 /**
162   * @brief  Selects the interval of systick interrupt.
163   * @param  value: The value of interval:
164   *           @arg @ref SYSTICK_INTERVAL_1MS    1 millisecond
165   *           @arg @ref SYSTICK_INTERVAL_10MS   10 milliseconds
166   *           @arg @ref SYSTICK_INTERVAL_100MS  100 milliseconds
167   *           @arg @ref SYSTICK_INTERVAL_1000MS 1 second
168   * @retval None
169   */
ald_systick_interval_select(systick_interval_t value)170 void ald_systick_interval_select(systick_interval_t value)
171 {
172 	assert_param(IS_SYSTICK_INTERVAL(value));
173 
174 	if (value == 0) return;
175 
176 	SysTick_Config(ald_cmu_get_sys_clock() / value);
177 	__systick_interval = value;
178 
179 	if (TICK_INT_PRIORITY != 15)
180 		NVIC_SetPriority(SysTick_IRQn, TICK_INT_PRIORITY);
181 
182 	return;
183 }
184 /**
185   * @}
186   */
187 
188 /** @defgroup ALD_Public_Functions_Group2 Control functions
189   * @brief    Control functions
190   *
191   * @verbatim
192  ===============================================================================
193                       ##### Control functions #####
194  ===============================================================================
195     [..]  This section provides functions allowing to:
196       (+) Provide a tick value in millisecond
197       (+) Provide a blocking delay in millisecond
198       (+) Suspend the time base source interrupt
199       (+) Resume the time base source interrupt
200       (+) Get the ALD version
201       (+) Waiting for flag
202       (+) Configure the interrupt
203       (+) Provide system tick value
204       (+) Initialize core timestamp
205       (+) Get core timestamp
206       (+) Get CPU ID
207       (+) Get UID
208       (+) Get CHIPID
209 
210     @endverbatim
211   * @{
212   */
213 
214 /**
215   * @brief  This function invoked by Systick ISR.
216   * @note   This function is declared as __weak to be overwritten in case of
217   *         other implementations in user file.
218   * @retval None
219   */
ald_systick_irq_cbk(void)220 __weak void ald_systick_irq_cbk(void)
221 {
222 	/* do nothing */
223 	return;
224 }
225 
226 /**
227   * @brief  This function is called to increment a global variable "lib_tick"
228   *         used as application time base.
229   * @note   In the default implementation, this variable is incremented each 1ms
230   *         in Systick ISR.
231   * @note   This function is declared as __weak to be overwritten in case of other
232   *         implementations in user file.
233   * @retval None
234   */
ald_inc_tick(void)235 __weak void ald_inc_tick(void)
236 {
237 	++lib_tick;
238 	ald_systick_irq_cbk();
239 }
240 
241 /**
242   * @brief  Provides a tick value in millisecond.
243   * @note   This function is declared as __weak to be overwritten in case of other
244   *         implementations in user file.
245   * @retval tick value
246   */
ald_get_tick(void)247 __weak uint32_t ald_get_tick(void)
248 {
249 	return lib_tick;
250 }
251 
252 /**
253   * @brief  This function provides accurate delay (in microseconds) based
254   *         on variable incremented.
255   * @note   In the default implementation, SysTick timer is the source of time base.
256   *         It is used to generate interrupts at regular time intervals where lib_tick
257   *         is incremented.
258   * @note   This function is declared as __weak to be overwritten in case of other
259   *         implementations in user file.
260   * @param  delay: specifies the delay time length, in microseconds(us).
261   * @retval None
262   */
ald_delay_us(__IO uint32_t delay)263 __weak void ald_delay_us(__IO uint32_t delay)
264 {
265     uint32_t start, now, delta, reload, us_tick;
266     start = SysTick->VAL;
267     reload = SysTick->LOAD;
268     us_tick = ald_cmu_get_sys_clock() / 1000000UL;
269     do
270     {
271         now = SysTick->VAL;
272         delta = (start > now) ? (start - now) : (reload + start - now);
273     }
274     while (delta <  (us_tick * delay));
275 }
276 
277 /**
278   * @brief  This function provides accurate delay (in milliseconds) based
279   *         on variable incremented.
280   * @note   In the default implementation, SysTick timer is the source of time base.
281   *         It is used to generate interrupts at regular time intervals where lib_tick
282   *         is incremented.
283   * @note   This function is declared as __weak to be overwritten in case of other
284   *         implementations in user file.
285   * @param  delay: specifies the delay time length, in milliseconds.
286   * @retval None
287   */
ald_delay_ms(__IO uint32_t delay)288 __weak void ald_delay_ms(__IO uint32_t delay)
289 {
290 	uint32_t tick, __delay;
291 
292 	switch (__systick_interval) {
293 	case SYSTICK_INTERVAL_1MS:
294 		__delay = delay;
295 		break;
296 
297 	case SYSTICK_INTERVAL_10MS:
298 		__delay = delay / 10;
299 		break;
300 
301 	case SYSTICK_INTERVAL_100MS:
302 		__delay = delay / 100;
303 		break;
304 
305 	case SYSTICK_INTERVAL_1000MS:
306 		__delay = delay / 1000;
307 		break;
308 
309 	default:
310 		__delay = delay;
311 		break;
312 	}
313 
314 	tick    = ald_get_tick();
315 	__delay = __delay == 0 ? 1 : __delay;
316 
317 	while ((ald_get_tick() - tick) < __delay)
318 		;
319 }
320 
321 /**
322   * @brief  Suspend Tick increment.
323   * @note   In the default implementation, SysTick timer is the source of time base.
324   *         It is used to generate interrupts at regular time intervals.
325   *         Once ald_suspend_tick() is called, the the SysTick interrupt
326   *         will be disabled and so Tick increment is suspended.
327   * @note   This function is declared as __weak to be overwritten
328   *         in case of other implementations in user file.
329   * @retval None
330   */
ald_suspend_tick(void)331 __weak void ald_suspend_tick(void)
332 {
333 	CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
334 }
335 
336 /**
337   * @brief  Resume Tick increment.
338   * @note   In the default implementation, SysTick timer is the source of
339   *         time base. It is used to generate interrupts at regular time
340   *         intervals. Once ald_resume_tick() is called, the the SysTick
341   *         interrupt will be enabled and so Tick increment is resumed.
342   * @note   This function is declared as __weak to be overwritten
343   *         in case of other implementations in user file.
344   * @retval None
345   */
ald_resume_tick(void)346 __weak void ald_resume_tick(void)
347 {
348 	SET_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
349 }
350 
351 /**
352   * @brief  This method returns the ALD revision
353   * @retval version: 0xXYZR (8bits for each decimal, R for RC)
354   */
ald_get_ald_version(void)355 uint32_t ald_get_ald_version(void)
356 {
357 	return __ALD_VERSION;
358 }
359 
360 /**
361   * @brief  Configure the flash wait period.
362   * @param  cycle: The period.
363   * @retval None
364   */
ald_flash_wait_config(uint8_t cycle)365 void ald_flash_wait_config(uint8_t cycle)
366 {
367 	uint32_t tmp;
368 
369 	tmp = MSC->MEMWAIT;
370 	MODIFY_REG(tmp, MSC_MEMWAIT_FLASH_W_MSK, (0x30U | cycle) << MSC_MEMWAIT_FLASH_W_POSS);
371 	MSC->MEMWAIT = tmp;
372 
373 	return;
374 }
375 
376 /**
377   * @brief  Waiting the specified bit in the register change to SET/RESET.
378   * @param  reg: The register address.
379   * @param  bit: The specified bit.
380   * @param  status: The status for waiting.
381   * @param  timeout: Timeout duration.
382   * @retval Status, see @ref ald_status_t.
383   */
ald_wait_flag(uint32_t * reg,uint32_t bit,flag_status_t status,uint32_t timeout)384 ald_status_t ald_wait_flag(uint32_t *reg, uint32_t bit, flag_status_t status, uint32_t timeout)
385 {
386 	uint32_t tick = ald_get_tick();
387 
388 	assert_param(timeout > 0);
389 
390 	if (status == SET) {
391 		while (!(IS_BIT_SET(*reg, bit))) {
392 			if (((ald_get_tick()) - tick) > timeout)
393 				return TIMEOUT;
394 		}
395 	}
396 	else {
397 		while ((IS_BIT_SET(*reg, bit))) {
398 			if (((ald_get_tick()) - tick) > timeout)
399 				return TIMEOUT;
400 		}
401 	}
402 
403 	return OK;
404 }
405 
406 /**
407   * @brief  Configure interrupt.
408   * @param  irq: Interrunpt type.
409   * @param  preempt_prio: preempt priority(0-3).
410   * @param  sub_prio: sub-priority(0-3).
411   * @param  status: Status.
412   *           @arg ENABLE
413   *           @arg DISABLE
414   * @retval None
415   */
ald_mcu_irq_config(IRQn_Type irq,uint8_t preempt_prio,uint8_t sub_prio,type_func_t status)416 void ald_mcu_irq_config(IRQn_Type irq, uint8_t preempt_prio, uint8_t sub_prio, type_func_t status)
417 {
418 	uint32_t pri;
419 	uint8_t sub_bw, pre_bw;
420 	uint8_t sub_mask = 0xF;
421 
422 	assert_param(IS_FUNC_STATE(status));
423 	assert_param(IS_PREEMPT_PRIO(preempt_prio));
424 	assert_param(IS_SUB_PRIO(sub_prio));
425 
426 	if (status == ENABLE) {
427 		pre_bw     = 7 - (((SCB->AIRCR) >> 8) & 7);
428 		sub_bw     = 4 - pre_bw;
429 		sub_mask >>= pre_bw;
430 
431 		pri  = preempt_prio << sub_bw;
432 		pri |= sub_prio & sub_mask;
433 
434 		NVIC_SetPriority(irq, pri);
435 		NVIC_EnableIRQ(irq);
436 	}
437 	else {
438 		NVIC_DisableIRQ(irq);
439 	}
440 
441 	return;
442 }
443 
444 /**
445   * @brief  Initialize core timestamp.
446   * @retval None
447   */
ald_mcu_timestamp_init(void)448 void ald_mcu_timestamp_init(void)
449 {
450 	DEM_CR    |= (uint32_t)DEM_CR_TRCENA;
451 	DWT_CYCCNT = 0x0;
452 	DWT_CR    |= (uint32_t)DWT_CR_CYCCNTEA;
453 
454 	return;
455 }
456 
457 /**
458   * @brief  Get core timestamp.
459   * @retval None
460   */
ald_mcu_get_timestamp(void)461 uint32_t ald_mcu_get_timestamp(void)
462 {
463 	return (uint32_t)DWT_CYCCNT;
464 }
465 
466 /**
467   * @brief  Get the CPU ID.
468   * @retval CPU ID.
469   */
ald_mcu_get_cpu_id(void)470 uint32_t ald_mcu_get_cpu_id(void)
471 {
472 	return SCB->CPUID;
473 }
474 
475 /**
476   * @brief  Get the UID.
477   * @param  buf: Pointer to UID, len: 12Bytes(96-bits)
478   * @retval None
479   */
ald_mcu_get_uid(uint8_t * buf)480 void ald_mcu_get_uid(uint8_t *buf)
481 {
482 	memcpy(&buf[0], (void *)MCU_UID0_ADDR, 4);
483 	memcpy(&buf[4], (void *)MCU_UID1_ADDR, 4);
484 	memcpy(&buf[8], (void *)MCU_UID2_ADDR, 4);
485 
486 	return;
487 }
488 
489 /**
490   * @brief  Get the CHIPID
491   * @retval CHPID
492   */
ald_mcu_get_chipid(void)493 uint32_t ald_mcu_get_chipid(void)
494 {
495 	return (uint32_t)*(uint32_t *)MCU_CHIPID_ADDR;
496 }
497 
498 /**
499   * @brief  Bypass bootroom and set VR1_Ref 0xA
500   * @retval None
501   */
sys_config(void)502 void sys_config(void)
503 {
504 	uint32_t i = 0, tmp = 0;
505 	uint8_t err = 0, flag = 0;
506 	uint32_t inf014 = 0, inf0154 = 0, inf0244 = 0;
507 	uint8_t cnt = 4;
508 
509 	uint32_t *inf0_addr = (uint32_t *)0x20003C00;
510 	/* read bootroom cfg register */
511 	inf014  = *((uint32_t *)(0x80000 + 56));
512 	/* read VR1_VREF register */
513 	inf0154 = *((uint32_t *)(0x80000 + 616));
514 	/* read Chip_v */
515 	inf0244 = *((uint32_t *)(0x80000 + 0x03D0));
516 
517 	/* if D version ,do nothing */
518 	if (inf0244 == 0xFFFFFF44) return;
519 
520 	if (inf0154 == 0xFFFFFFFF)
521 		while(1);
522 
523 	/* if bypass bootroom */
524 	if ((0xFFFFFFFF != inf014)) {
525 		/* change cfg_boot value = 0xffff */
526 		inf014 = 0xFFFFFFFF;
527 		flag   = 0x1;
528 	}
529 
530 	/* change CFG_VR1_VREF value, FLASH ref 0xA */
531 	tmp = (inf0154 >> 8) & 0xF;
532 	if (0xA != tmp) {
533 		inf0154 &= (uint32_t)~(0xF << 8);
534 		inf0154 |= (0xA << 8);
535 		inf0154 = (inf0154 & (0x0000FFFF)) | ((~(inf0154 & 0xFFFF)) << 16);
536 		flag = 0x1;
537 	}
538 
539 	/* if flag reset, return */
540 	if (0x0 == flag)
541 		return;
542 
543 	/* 0x80000, 256words,INFO0 value */
544 	for (i = 0; i < 256; i++)
545 		inf0_addr[i] = *((uint32_t *)(0x80000 + i * 4));
546 
547 	/* refresh value */
548 	inf0_addr[14]  = inf014;
549 	inf0_addr[154] = inf0154;
550 
551 	while(--cnt) {
552 		err = 0;
553 		/* unlock */
554 		*((volatile uint32_t *)(0x40080000)) = 0x55AA6996;
555 		*((volatile uint32_t *)(0x40080100)) = 0x5A962814;
556 		*((volatile uint32_t *)(0x40080100)) = 0xE7CB69A5;
557 
558 		/* erase */
559 		if (ald_iap_erase_page(0x80000) == OK) {
560 			/* program 256*4bytes, info0 */
561 			if (ald_iap_program_words(0x80000, (uint8_t *)inf0_addr, 1024, 0) == OK) {
562 				/* check */
563 				for (i = 0; i < 256; i++) {
564 					if (inf0_addr[i] != *((uint32_t *)(0x80000 + i * 4))) {
565 						err = 1;
566 						break;;
567 					}
568 				}
569 				if (err == 0) {
570 					/* lock */
571 					*((volatile uint32_t *)(0x40080100)) = 0x123456;
572 					*((volatile uint32_t *)(0x40080100)) = 0x123456;
573 					*((volatile uint32_t *)(0x40080000)) = 0x123456;
574 					return;
575 				}
576 			}
577 			else {
578 				err = 1;
579 			}
580 		}
581 		else {
582 			err = 1;
583 		}
584 	}
585 
586 	if (err) {
587 		ald_iap_erase_page(0x80000);
588 		/* lock */
589 		*((volatile uint32_t *)(0x40080100)) = 0x123456;
590 		*((volatile uint32_t *)(0x40080100)) = 0x123456;
591 		*((volatile uint32_t *)(0x40080000)) = 0x123456;
592 		while(1);
593 	}
594 }
595 
596 /**
597   * @brief  ADC adjust parameter config
598   * @retval None
599   */
adc_config(void)600 void adc_config(void)
601 {
602 	uint32_t inf0176 = 0, inf0178 = 0;
603 	uint32_t inf0250 = 0, inf0251 = 0;
604 	uint32_t inf0242 = 0, i = 0;
605 	uint8_t flag = 0, err = 0;
606 	uint8_t cnt = 4;
607 	/* ram store inf0 1k buffer, 15k ~ 16k */
608 	uint32_t *inf0_addr = (uint32_t *)0x20003C00;
609 
610 	/* Read ADC_GE */
611 	inf0242 = *((uint32_t *)(0x80000 + 968));
612 
613 	if (0xF5230ADC == inf0242)  return;
614 
615 	/* read Lot ID */
616 	inf0250 = *((uint32_t *)(0x80000 + 1000));
617 	inf0251 = *((uint32_t *)(0x80000 + 1004));
618 	inf0251 = (inf0251 & 0xFFFF0000) >> 16;
619 
620 	/* read CFG_ADC0DA/CFG_ADC1DA */
621 	inf0176 = *((uint32_t *)(0x80000 + 704));
622 	inf0178 = *((uint32_t *)(0x80000 + 712));
623 
624 	switch(inf0250) {
625 		case 0x45465537:
626 			if ((inf0251 == 0x3034) || (inf0251 == 0x3035))
627 				flag = 1;
628 			break;
629 		case 0x45503931:
630 			if ((inf0251 == 0x3732) || (inf0251 == 0x3734))
631 				flag = 1;
632 			break;
633 		case 0x45503935:
634 			if ((inf0251 == 0x3837) || (inf0251 == 0x3839))
635 				flag = 1;
636 			break;
637 		default:
638 			break;
639 	}
640 
641 	if (!flag)  return;
642 
643 	inf0176 ^= (0x1 << 15);
644 	inf0176  = (inf0176 & 0x0000FFFF) | ((~(inf0176 & 0xFFFF)) << 16);
645 
646 	inf0178 ^= (0x1 << 15);
647 	inf0178  = (inf0178 & 0x0000FFFF) | ((~(inf0178 & 0xFFFF)) << 16);
648 
649 	/* 0x80000, 256words,INFO0 value */
650 	for (i = 0; i < 256; i++)
651 		inf0_addr[i] = *((uint32_t *)(0x80000 + i * 4));
652 
653 	inf0_addr[176] = inf0176;
654 	inf0_addr[178] = inf0178;
655 	inf0_addr[242] = 0xF5230ADC;
656 
657 	while(--cnt) {
658 		err = 0;
659 		/* unlock */
660 		*((volatile uint32_t *)(0x40080000)) = 0x55AA6996;
661 		*((volatile uint32_t *)(0x40080100)) = 0x5A962814;
662 		*((volatile uint32_t *)(0x40080100)) = 0xE7CB69A5;
663 
664 		/* erase */
665 		if (ald_iap_erase_page(0x80000) == OK) {
666 			/* program 256*4bytes, info0 */
667 			if (ald_iap_program_words(0x80000, (uint8_t *)inf0_addr, 1024, 0) == OK) {
668 				/* check */
669 				for (i = 0; i < 256; i++) {
670 					if (inf0_addr[i] != *((uint32_t *)(0x80000 + i * 4))) {
671 						err = 1;
672 						break;;
673 					}
674 				}
675 				if (err == 0) {
676 					/* lock */
677 					*((volatile uint32_t *)(0x40080100)) = 0x123456;
678 					*((volatile uint32_t *)(0x40080100)) = 0x123456;
679 					*((volatile uint32_t *)(0x40080000)) = 0x123456;
680 					return;
681 				}
682 			}
683 			else {
684 				err = 1;
685 			}
686 		}
687 		else {
688 			err = 1;
689 		}
690 	}
691 
692 	if (err) {
693 		ald_iap_erase_page(0x80000);
694 		/* lock */
695 		*((volatile uint32_t *)(0x40080100)) = 0x123456;
696 		*((volatile uint32_t *)(0x40080100)) = 0x123456;
697 		*((volatile uint32_t *)(0x40080000)) = 0x123456;
698 		while(1);
699 	}
700 }
701 /**
702   * @}
703   */
704 
705 /**
706   * @}
707   */
708 
709 /**
710   * @}
711   */
712 
713 /**
714   * @}
715   */
716