1 /**
2   *********************************************************************************
3   *
4   * @file    ald_flash_ext.c
5   * @brief   FLASH module driver.
6   *
7   * @version V1.0
8   * @date    15 May 2019
9   * @author  AE Team
10   * @note
11   *
12   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
13   *
14   * SPDX-License-Identifier: Apache-2.0
15   *
16   * Licensed under the Apache License, Version 2.0 (the License); you may
17   * not use this file except in compliance with the License.
18   * You may obtain a copy of the License at
19   *
20   * www.apache.org/licenses/LICENSE-2.0
21   *
22   * Unless required by applicable law or agreed to in writing, software
23   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25   * See the License for the specific language governing permissions and
26   * limitations under the License.
27   *
28   *********************************************************************************
29   *
30   *********************************************************************************
31   * @verbatim
32   ==============================================================================
33                     ##### FLASH Peripheral features #####
34   ==============================================================================
35   [..]
36   Base address is 0x00000000
37 
38   [..]
39   FLASH have just one programme mode , word programme.
40   word programme can programme 8 bytes once ;
41 
42   ==============================================================================
43                         ##### How to use this driver #####
44   ==============================================================================
45   [..]
46    (#) programme flash using ald_flash_write(uint32_t addr, uint8_t *buf, uint16_t len)
47        (++) call the function and supply all the three paraments is needs, addr means
48             the first address to write in this operation, buf is a pointer to the data which
49 	    need writing to flash.
50 
51    (#) erase flash using ald_flash_erase(uint32_t addr, uint16_t len)
52        (++) call the function and supply two paraments, addr is the first address to erase,
53             len is the length to erase
54 
55    (#) read flash using ald_flash_read(uint32_t *ram_addr, uint32_t addr, uint16_t len)
56        (++) read the flash and save to a buffer, ram_addr is the buffer's first address,
57             addr is the start reading address in flash, len is the length need read
58 
59     @endverbatim
60   */
61 
62 
63 #include "ald_flash.h"
64 
65 
66 /** @addtogroup ES32FXXX_ALD
67   * @{
68   */
69 
70 /** @addtogroup FLASH
71   * @{
72   */
73 
74 #ifdef ALD_FLASH
75 
76 /** @addtogroup Flash_Private_Variables
77   * @{
78   */
79 /* opration buffer*/
80 static uint8_t write_buf[FLASH_PAGE_SIZE];
81 /**
82   * @}
83   */
84 
85 /** @addtogroup Flash_Private_Functions
86   * @{
87   */
88 
89 /**
90   * @brief  Check whether the flash between the given address section
91   *         have been writen, if it have been writen, return TRUE, else
92   *         return FALSE.
93   * @param  begin_addr: The begin address.
94   * @param  end_addr: The end address.
95   * @retval The check result
96   *         - TRUE
97   *         - FALSE
98   */
page_have_writen(uint32_t begin_addr,uint32_t end_addr)99 static type_bool_t page_have_writen(uint32_t begin_addr, uint32_t end_addr)
100 {
101 	uint8_t* addr_to_read;
102 	uint8_t value;
103 	uint32_t index;
104 
105 	/* Check the parameters */
106 	assert_param(IS_FLASH_ADDRESS(begin_addr));
107 	assert_param(IS_FLASH_ADDRESS(end_addr));
108 
109 	addr_to_read = (uint8_t *)begin_addr;
110 	index        = begin_addr;
111 	value        = 0xFF;
112 
113 	if (begin_addr > end_addr)
114 		return FALSE;
115 
116 	while (index++ <= end_addr) {
117 		value = *addr_to_read++;
118 
119 		if (value != 0xFF)
120 			break;
121 	}
122 
123 	return value == 0xFF ? FALSE : TRUE;
124 }
125 /**
126   * @}
127   */
128 
129 /** @defgroup Flash_Public_Functions Flash Public Functions
130   * @verbatim
131  ===============================================================================
132               ##### Flash operation functions #####
133  ===============================================================================
134   [..]
135     This section provides functions allowing to operate flash, such as read and write.
136 
137     @endverbatim
138   * @{
139   */
140 
141 /**
142   * @brief  read the specified length bytes from flash, and store to the specified area.
143   * @param  ram_addr: the specified area to store the reading bytes.
144   * @param  addr: the start address.
145   * @param  len: the length to read.
146   * @retval Status, see @ref ald_status_t.
147   */
ald_flash_read(uint32_t * ram_addr,uint32_t addr,uint16_t len)148 ald_status_t ald_flash_read(uint32_t *ram_addr, uint32_t addr, uint16_t len)
149 {
150 	uint32_t i;
151 	uint32_t temp;
152 
153 	assert_param(IS_4BYTES_ALIGN(ram_addr));
154 	assert_param(IS_FLASH_ADDRESS(addr));
155 	assert_param(IS_FLASH_ADDRESS(addr + len - 1));
156 
157 	temp = (uint32_t)ram_addr;
158 
159 	if (((temp & 0x3) != 0) || (((addr) & 0x3) != 0))
160 		return ERROR;
161 
162 	for (i = 0; i < len; i++) {
163 		ram_addr[i] = ((uint32_t *)addr)[i];
164 	}
165 
166 	return OK;
167 }
168 
169 /**
170   * @brief  Write the give bytes to the given address section.
171   * @param  addr: The start address to write.
172   * @param  buf: The bytes' address.
173   * @param  len: The length to write,and multiple of 2.
174   * @retval Status, see @ref ald_status_t.
175   */
176 
ald_flash_write(uint32_t addr,uint8_t * buf,uint16_t len)177 ald_status_t ald_flash_write(uint32_t addr, uint8_t *buf, uint16_t len)
178 {
179 	uint32_t index = 0;
180 	uint32_t para = 0;
181 	uint32_t index2 = 0;
182 	uint32_t start_write_addr;
183 	uint32_t end_write_addr;
184 	uint32_t start_word_addr;
185 	uint32_t end_word_addr;
186 	uint16_t len_to_write;
187 	uint32_t len_index;
188 	type_bool_t need_erase_page;
189 
190 	assert_param(IS_FLASH_ADDRESS(addr));
191 	assert_param(IS_FLASH_ADDRESS(addr + len - 1));
192 
193 	len_to_write = len;
194 
195 	__disable_irq();
196 	while (len_to_write > 0) {
197 		need_erase_page = FALSE;
198 
199 		for (index = 0; index < FLASH_PAGE_SIZE; index++)
200 			write_buf[index] = 0xFF;
201 
202 		start_write_addr = addr + (len - len_to_write);
203 		end_write_addr   = addr + len - 1;
204 		end_write_addr   = FLASH_PAGE_ADDR(start_write_addr) == FLASH_PAGE_ADDR(end_write_addr)
205 		                   ? end_write_addr : FLASH_PAGEEND_ADDR(start_write_addr);
206 		need_erase_page  = page_have_writen(FLASH_WORD_ADDR(start_write_addr),
207 		                                    FLASH_WORDEND_ADDR(end_write_addr));
208 
209 		if (need_erase_page) {
210 			if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_write_addr),
211                                  		  FLASH_PAGE_SIZE >> 2)) {
212 				__enable_irq();
213 				return ERROR;
214 			}
215 
216 			if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_write_addr))) {
217 				__enable_irq();
218 				return ERROR;
219 			}
220 
221 			para   = end_write_addr & (FLASH_PAGE_SIZE - 1);
222 			index  = start_write_addr & (FLASH_PAGE_SIZE - 1);
223 			index2 = len - len_to_write;
224 
225 			while (index <= para)
226 				write_buf[index++] = buf[index2++];
227 
228 			index2     = 0;
229 			index      = FLASH_PAGE_ADDR(start_write_addr);
230 			len_index  = FLASH_PAGE_SIZE;
231 		}
232 		else {
233 			para   = end_write_addr & (FLASH_PAGE_SIZE - 1);
234 			index  = start_write_addr & (FLASH_PAGE_SIZE - 1);
235 			index2 = len - len_to_write;
236 
237 			while (index <= para)
238 				write_buf[index++] = buf[index2++];
239 
240 			start_word_addr = FLASH_WORD_ADDR(start_write_addr);
241 			end_word_addr   = FLASH_WORDEND_ADDR(end_write_addr);
242 			index2          = (FLASH_WORD_ADDR(start_word_addr) - FLASH_PAGE_ADDR(start_word_addr));
243 			index           = start_word_addr;
244 			len_index       = end_word_addr - start_word_addr + 1;
245 		}
246 
247 		if (ERROR == flash_word_program(index, (uint32_t *)(write_buf + index2), (len_index >> 3), FLASH_FIFO)) {
248 			__enable_irq();
249 			return ERROR;
250 		}
251 
252 		len_to_write = len_to_write - (end_write_addr - start_write_addr + 1);
253 	}
254 
255 	__enable_irq();
256 	return OK;
257 }
258 
259 /**
260   * @brief  erase The flash between the given address section.
261   * @param  addr: The start address to erase.
262   * @param  len: The length to erase.
263   * @retval Status, see @ref ald_status_t.
264   */
ald_flash_erase(uint32_t addr,uint16_t len)265 ald_status_t ald_flash_erase(uint32_t addr, uint16_t len)
266 {
267 	uint32_t index;
268 	int32_t para;
269 	int32_t start_erase_addr;
270 	int32_t end_erase_addr;
271 	uint16_t len_not_erase;
272 	uint32_t len_index;
273 	type_bool_t page_need_save;
274 
275 	assert_param(IS_FLASH_ADDRESS(addr));
276 	assert_param(IS_FLASH_ADDRESS(addr + len - 1));
277 
278 	len_not_erase = len;
279 
280 	__disable_irq();
281 	while (len_not_erase > 0) {
282 		page_need_save = FALSE;
283 
284 		start_erase_addr = addr + len - len_not_erase;
285 		end_erase_addr   = addr + len - 1;
286 		end_erase_addr   = (FLASH_PAGE_ADDR(start_erase_addr) == FLASH_PAGE_ADDR(end_erase_addr))
287 		                    ? end_erase_addr : FLASH_PAGEEND_ADDR(start_erase_addr);
288 
289 		if (start_erase_addr != FLASH_PAGE_ADDR(start_erase_addr)) {
290 			if (page_have_writen(FLASH_PAGE_ADDR(start_erase_addr), (start_erase_addr - 1)))
291 				page_need_save = TRUE;
292 		}
293 		if (end_erase_addr != FLASH_PAGEEND_ADDR(end_erase_addr)) {
294 			if (page_have_writen((end_erase_addr + 1), FLASH_PAGEEND_ADDR(end_erase_addr)))
295 				page_need_save = TRUE;
296 		}
297 
298 		if (page_need_save) {
299 			if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_erase_addr),
300 			                                                     FLASH_PAGE_SIZE >> 2)) {
301 				__enable_irq();
302 				return ERROR;
303 			}
304 		}
305 
306 		if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_erase_addr))) {
307 			__enable_irq();
308 			return ERROR;
309 		}
310 
311 		if (page_need_save) {
312 			para  = end_erase_addr & (FLASH_PAGE_SIZE - 1);
313 			index = start_erase_addr & (FLASH_PAGE_SIZE - 1);
314 
315 			while (index <= para)
316 				write_buf[index++] = 0xFF;
317 
318 			index     = FLASH_PAGE_ADDR(start_erase_addr);
319 			len_index = FLASH_PAGE_SIZE;
320 			if (ERROR == flash_word_program(index, (uint32_t *)write_buf, (len_index >> 3), FLASH_FIFO)) {
321 				__enable_irq();
322 				return ERROR;
323 			}
324 		}
325 		len_not_erase = len_not_erase - (end_erase_addr - start_erase_addr + 1);
326 	}
327 
328 	__enable_irq();
329 	return OK;
330 }
331 /**
332   * @}
333   */
334 
335 
336 #endif
337 
338 /**
339   * @}
340   */
341 
342 /**
343   * @}
344   */
345