1 /**
2   *********************************************************************************
3   *
4   * @file    ald_flash_ext.c
5   * @brief   FLASH extra module driver.
6   *
7   * @version V1.0
8   * @date    17 Jun 2019
9   * @author  AE Team
10   * @note
11   *          Change Logs:
12   *          Date            Author          Notes
13   *          17 Jun 2019     AE Team         The first version
14   *
15   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
16   *
17   * SPDX-License-Identifier: Apache-2.0
18   *
19   * Licensed under the Apache License, Version 2.0 (the License); you may
20   * not use this file except in compliance with the License.
21   * You may obtain a copy of the License at
22   *
23   * www.apache.org/licenses/LICENSE-2.0
24   *
25   * Unless required by applicable law or agreed to in writing, software
26   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
27   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28   * See the License for the specific language governing permissions and
29   * limitations under the License.
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_conf.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 	return OK;
166 }
167 
168 /**
169   * @brief  Write the give bytes to the given address section.
170   * @param  addr: The start address to write.
171   * @param  buf: The bytes' address.
172   * @param  len: The length to write,and multiple of 2.
173   * @retval Status, see @ref ald_status_t.
174   */
175 
ald_flash_write(uint32_t addr,uint8_t * buf,uint16_t len)176 ald_status_t ald_flash_write(uint32_t addr, uint8_t *buf, uint16_t len)
177 {
178 	uint32_t index = 0;
179 	uint32_t para = 0;
180 	uint32_t index2 = 0;
181 	uint32_t start_write_addr;
182 	uint32_t end_write_addr;
183 	uint32_t start_word_addr;
184 	uint32_t end_word_addr;
185 	uint16_t len_to_write;
186 	uint32_t len_index;
187 	type_bool_t need_erase_page;
188 
189 	assert_param(IS_FLASH_ADDRESS(addr));
190 	assert_param(IS_FLASH_ADDRESS(addr + len - 1));
191 
192 	len_to_write = len;
193 
194 	__disable_irq();
195 	while (len_to_write > 0) {
196 		need_erase_page = FALSE;
197 
198 		for (index = 0; index < FLASH_PAGE_SIZE; index++)
199 			write_buf[index] = 0xFF;
200 
201 		start_write_addr = addr + (len - len_to_write);
202 		end_write_addr   = addr + len - 1;
203 		end_write_addr   = FLASH_PAGE_ADDR(start_write_addr) == FLASH_PAGE_ADDR(end_write_addr)
204 		                   ? end_write_addr : FLASH_PAGEEND_ADDR(start_write_addr);
205 		need_erase_page  = page_have_writen(FLASH_WORD_ADDR(start_write_addr),
206 		                                    FLASH_WORDEND_ADDR(end_write_addr));
207 
208 		if (need_erase_page) {
209 			if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_write_addr),
210                                  		  FLASH_PAGE_SIZE >> 2)) {
211 				__enable_irq();
212 				return ERROR;
213 			}
214 
215 			if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_write_addr))) {
216 				__enable_irq();
217 				return ERROR;
218 			}
219 
220 			para   = end_write_addr & (FLASH_PAGE_SIZE - 1);
221 			index  = start_write_addr & (FLASH_PAGE_SIZE - 1);
222 			index2 = len - len_to_write;
223 
224 			while (index <= para)
225 				write_buf[index++] = buf[index2++];
226 
227 			index2     = 0;
228 			index      = FLASH_PAGE_ADDR(start_write_addr);
229 			len_index  = FLASH_PAGE_SIZE;
230 		}
231 		else {
232 			para   = end_write_addr & (FLASH_PAGE_SIZE - 1);
233 			index  = start_write_addr & (FLASH_PAGE_SIZE - 1);
234 			index2 = len - len_to_write;
235 
236 			while (index <= para)
237 				write_buf[index++] = buf[index2++];
238 
239 			start_word_addr = FLASH_WORD_ADDR(start_write_addr);
240 			end_word_addr   = FLASH_WORDEND_ADDR(end_write_addr);
241 			index2          = (FLASH_WORD_ADDR(start_word_addr) - FLASH_PAGE_ADDR(start_word_addr));
242 			index           = start_word_addr;
243 			len_index       = end_word_addr - start_word_addr + 1;
244 		}
245 
246 		if (ERROR == flash_word_program(index, (uint32_t *)(write_buf + index2), (len_index >> 3), FLASH_FIFO)) {
247 			__enable_irq();
248 			return ERROR;
249 		}
250 
251 		len_to_write = len_to_write - (end_write_addr - start_write_addr + 1);
252 	}
253 
254 	__enable_irq();
255 	return OK;
256 }
257 
258 /**
259   * @brief  erase The flash between the given address section.
260   * @param  addr: The start address to erase.
261   * @param  len: The length to erase.
262   * @retval Status, see @ref ald_status_t.
263   */
ald_flash_erase(uint32_t addr,uint16_t len)264 ald_status_t ald_flash_erase(uint32_t addr, uint16_t len)
265 {
266 	uint32_t index;
267 	int32_t para;
268 	int32_t start_erase_addr;
269 	int32_t end_erase_addr;
270 	uint16_t len_not_erase;
271 	uint32_t len_index;
272 	type_bool_t page_need_save;
273 
274 	assert_param(IS_FLASH_ADDRESS(addr));
275 	assert_param(IS_FLASH_ADDRESS(addr + len - 1));
276 
277 	len_not_erase = len;
278 
279 	__disable_irq();
280 	while (len_not_erase > 0) {
281 		page_need_save = FALSE;
282 
283 		start_erase_addr = addr + len - len_not_erase;
284 		end_erase_addr   = addr + len - 1;
285 		end_erase_addr   = (FLASH_PAGE_ADDR(start_erase_addr) == FLASH_PAGE_ADDR(end_erase_addr))
286 		                    ? end_erase_addr : FLASH_PAGEEND_ADDR(start_erase_addr);
287 
288 		if (start_erase_addr != FLASH_PAGE_ADDR(start_erase_addr)) {
289 			if (page_have_writen(FLASH_PAGE_ADDR(start_erase_addr), (start_erase_addr - 1)))
290 				page_need_save = TRUE;
291 		}
292 		if (end_erase_addr != FLASH_PAGEEND_ADDR(end_erase_addr)) {
293 			if (page_have_writen((end_erase_addr + 1), FLASH_PAGEEND_ADDR(end_erase_addr)))
294 				page_need_save = TRUE;
295 		}
296 
297 		if (page_need_save) {
298 			if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_erase_addr),
299 			                                                     FLASH_PAGE_SIZE >> 2)) {
300 				__enable_irq();
301 				return ERROR;
302 			}
303 		}
304 
305 		if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_erase_addr))) {
306 			__enable_irq();
307 			return ERROR;
308 		}
309 
310 		if (page_need_save) {
311 			para  = end_erase_addr & (FLASH_PAGE_SIZE - 1);
312 			index = start_erase_addr & (FLASH_PAGE_SIZE - 1);
313 
314 			while (index <= para)
315 				write_buf[index++] = 0xFF;
316 
317 			index     = FLASH_PAGE_ADDR(start_erase_addr);
318 			len_index = FLASH_PAGE_SIZE;
319 			if (ERROR == flash_word_program(index, (uint32_t *)write_buf, (len_index >> 3), FLASH_FIFO)) {
320 				__enable_irq();
321 				return ERROR;
322 			}
323 		}
324 		len_not_erase = len_not_erase - (end_erase_addr - start_erase_addr + 1);
325 	}
326 
327 	__enable_irq();
328 	return OK;
329 }
330 /**
331   * @}
332   */
333 
334 
335 #endif
336 
337 /**
338   * @}
339   */
340 
341 /**
342   * @}
343   */
344