1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-12-5 SummerGift first version
9 * 2020-03-05 redoc support stm32f103vg
10 *
11 */
12
13 #include <rtconfig.h>
14 #include <rtdef.h>
15
16 #ifdef BSP_USING_ON_CHIP_FLASH
17 #include "drv_config.h"
18 #include "drv_flash.h"
19 #include <board.h>
20
21 #if defined(RT_USING_FAL)
22 #include "fal.h"
23 #endif
24
25 //#define DRV_DEBUG
26 #define LOG_TAG "drv.flash"
27 #include <drv_log.h>
28
29 /**
30 * @brief Gets the page of a given address
31 * @param Addr: Address of the FLASH Memory
32 * @retval The page of a given address
33 */
GetPage(uint32_t addr)34 static uint32_t GetPage(uint32_t addr)
35 {
36 uint32_t page = 0;
37 page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
38 return page;
39 }
40
41 /**
42 * Read data from flash.
43 * @note This operation's units is word.
44 *
45 * @param addr flash address
46 * @param buf buffer to store read data
47 * @param size read bytes size
48 *
49 * @return result
50 */
stm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)51 int stm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
52 {
53 size_t i;
54
55 if ((addr + size) > STM32_FLASH_END_ADDRESS)
56 {
57 LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
58 return -RT_EINVAL;
59 }
60
61 for (i = 0; i < size; i++, buf++, addr++)
62 {
63 *buf = *(rt_uint8_t *) addr;
64 }
65
66 return size;
67 }
68
69 /**
70 * Write data to flash.
71 * @note This operation's units is word.
72 * @note This operation must after erase. @see flash_erase.
73 *
74 * @param addr flash address
75 * @param buf the write data buffer
76 * @param size write bytes size
77 *
78 * @return result
79 */
stm32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)80 int stm32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
81 {
82 rt_err_t result = RT_EOK;
83 rt_uint32_t end_addr = addr + size;
84
85 if (addr % 4 != 0)
86 {
87 LOG_E("write addr must be 4-byte alignment");
88 return -RT_EINVAL;
89 }
90
91 if ((end_addr) > STM32_FLASH_END_ADDRESS)
92 {
93 LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
94 return -RT_EINVAL;
95 }
96
97 HAL_FLASH_Unlock();
98
99 while (addr < end_addr)
100 {
101 if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, *((rt_uint32_t *)buf)) == HAL_OK)
102 {
103 if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
104 {
105 result = -RT_ERROR;
106 break;
107 }
108 addr += 4;
109 buf += 4;
110 }
111 else
112 {
113 result = -RT_ERROR;
114 break;
115 }
116 }
117
118 HAL_FLASH_Lock();
119
120 if (result != RT_EOK)
121 {
122 return result;
123 }
124
125 return size;
126 }
127
128 /**
129 * Erase data on flash with bank.
130 * @note This operation is irreversible.
131 * @note This operation's units is different which on many chips.
132 *
133 * @param bank flash bank
134 * @param addr flash address
135 * @param size erase bytes size
136 *
137 * @return result
138 */
stm32_flash_erase_bank(uint32_t bank,rt_uint32_t addr,size_t size)139 int stm32_flash_erase_bank(uint32_t bank, rt_uint32_t addr, size_t size)
140 {
141 rt_err_t result = RT_EOK;
142 uint32_t PAGEError = 0;
143
144 /*Variable used for Erase procedure*/
145 FLASH_EraseInitTypeDef EraseInitStruct;
146
147 if ((addr + size) > STM32_FLASH_END_ADDRESS)
148 {
149 LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
150 return -RT_EINVAL;
151 }
152
153 HAL_FLASH_Unlock();
154
155 /* Fill EraseInit structure*/
156 EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
157 EraseInitStruct.PageAddress = GetPage(addr);
158 EraseInitStruct.NbPages = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
159 EraseInitStruct.Banks = bank;
160
161 if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
162 {
163 result = -RT_ERROR;
164 goto __exit;
165 }
166
167 __exit:
168 HAL_FLASH_Lock();
169
170 if (result != RT_EOK)
171 {
172 return result;
173 }
174
175 LOG_D("erase done: addr (0x%p), size %d", (void *)addr, size);
176 return size;
177 }
178
179 /**
180 * Erase data on flash .
181 * @note This operation is irreversible.
182 * @note This operation's units is different which on many chips.
183 *
184 * @param addr flash address
185 * @param size erase bytes size
186 *
187 * @return result
188 */
stm32_flash_erase(rt_uint32_t addr,size_t size)189 int stm32_flash_erase(rt_uint32_t addr, size_t size)
190 {
191 #if defined(FLASH_BANK2_END)
192 rt_err_t result = RT_EOK;
193 rt_uint32_t addr_bank1 = 0;
194 rt_uint32_t size_bank1 = 0;
195 rt_uint32_t addr_bank2 = 0;
196 rt_uint32_t size_bank2 = 0;
197
198 if((addr + size) <= FLASH_BANK1_END)
199 {
200 addr_bank1 = addr;
201 size_bank1 = size;
202 size_bank2 = 0;
203 }
204 else if(addr > FLASH_BANK1_END)
205 {
206 size_bank1 = 0;
207 addr_bank2 = addr;
208 size_bank2 = size;
209 }
210 else
211 {
212 addr_bank1 = addr;
213 size_bank1 = FLASH_BANK1_END + 1 - addr_bank1;
214 addr_bank2 = FLASH_BANK1_END + 1;
215 size_bank2 = addr + size - (FLASH_BANK1_END + 1);
216 }
217
218 if(size_bank1)
219 {
220 LOG_D("bank1: addr (0x%p), size %d", (void *)addr_bank1, size_bank1);
221 if(size_bank1 != stm32_flash_erase_bank(FLASH_BANK_1, addr_bank1, size_bank1))
222 {
223 result = -RT_ERROR;
224 goto __exit;
225 }
226 }
227
228 if(size_bank2)
229 {
230 LOG_D("bank2: addr (0x%p), size %d", (void *)addr_bank2, size_bank2);
231 if(size_bank2 != stm32_flash_erase_bank(FLASH_BANK_2, addr_bank2, size_bank2))
232 {
233 result = -RT_ERROR;
234 goto __exit;
235 }
236 }
237
238 __exit:
239 if(result != RT_EOK)
240 {
241 return result;
242 }
243
244 return size_bank1 + size_bank2;
245 #else
246 return stm32_flash_erase_bank(FLASH_BANK_1, addr, size);
247 #endif
248 }
249
250
251 #if defined(RT_USING_FAL)
252
253 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
254 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
255 static int fal_flash_erase(long offset, size_t size);
256
257 const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} };
258
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)259 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
260 {
261 return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size);
262 }
263
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)264 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
265 {
266 return stm32_flash_write(stm32_onchip_flash.addr + offset, buf, size);
267 }
268
fal_flash_erase(long offset,size_t size)269 static int fal_flash_erase(long offset, size_t size)
270 {
271 return stm32_flash_erase(stm32_onchip_flash.addr + offset, size);
272 }
273
274 #endif
275 #endif /* BSP_USING_ON_CHIP_FLASH */
276