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