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