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 */
10
11 #include <rtconfig.h>
12 #include <rtdef.h>
13
14 #ifdef BSP_USING_ON_CHIP_FLASH
15 #include "drv_config.h"
16 #include "drv_flash.h"
17 #include <board.h>
18
19 #if defined(RT_USING_FAL)
20 #include "fal.h"
21 #endif
22
23 //#define DRV_DEBUG
24 #define LOG_TAG "drv.flash"
25 #include <drv_log.h>
26
27 /**
28 * @brief Gets the page of a given address
29 * @param Addr: Address of the FLASH Memory
30 * @retval The page of a given address
31 */
GetPage(uint32_t Addr)32 static uint32_t GetPage(uint32_t Addr)
33 {
34 uint32_t page = 0;
35
36 if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
37 {
38 /* Bank 1 */
39 page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
40 }
41 else
42 {
43 /* Bank 2 */
44 page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
45 }
46
47 return page;
48 }
49
50 /**
51 * @brief Gets the bank of a given address
52 * @param Addr: Address of the FLASH Memory
53 * @retval The bank of a given address
54 */
GetBank(uint32_t Addr)55 static uint32_t GetBank(uint32_t Addr)
56 {
57 uint32_t bank = 0;
58 #ifndef FLASH_BANK_2
59 bank = FLASH_BANK_1;
60 #else
61 if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0)
62 {
63 /* No Bank swap */
64 if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
65 {
66 bank = FLASH_BANK_1;
67 }
68 else
69 {
70 bank = FLASH_BANK_2;
71 }
72 }
73 else
74 {
75 /* Bank swap */
76 if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
77 {
78 bank = FLASH_BANK_2;
79 }
80 else
81 {
82 bank = FLASH_BANK_1;
83 }
84 }
85 #endif
86 return bank;
87 }
88
89 /**
90 * Read data from flash.
91 * @note This operation's units is word.
92 *
93 * @param addr flash address
94 * @param buf buffer to store read data
95 * @param size read bytes size
96 *
97 * @return result
98 */
stm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)99 int stm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
100 {
101 size_t i;
102
103 if ((addr + size) > STM32_FLASH_END_ADDRESS)
104 {
105 LOG_E("read outrange flash size! addr is (0x%p)", (void*)(addr + size));
106 return -RT_EINVAL;
107 }
108
109 for (i = 0; i < size; i++, buf++, addr++)
110 {
111 *buf = *(rt_uint8_t *) addr;
112 }
113
114 return size;
115 }
116
117 /**
118 * Write data to flash.
119 * @note This operation's units is word.
120 * @note This operation must after erase. @see flash_erase.
121 *
122 * @param addr flash address
123 * @param buf the write data buffer
124 * @param size write bytes size
125 *
126 * @return result
127 */
128
stm32_flash_write(rt_uint32_t addr,const uint8_t * buf,size_t size)129 int stm32_flash_write(rt_uint32_t addr, const uint8_t *buf, size_t size)
130 {
131 size_t i, j;
132 rt_err_t result = 0;
133 rt_uint64_t write_data = 0, temp_data = 0;
134
135 if ((addr + size) > STM32_FLASH_END_ADDRESS)
136 {
137 LOG_E("ERROR: write outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
138 return -RT_EINVAL;
139 }
140
141 if(addr % 8 != 0)
142 {
143 LOG_E("write addr must be 8-byte alignment");
144 return -RT_EINVAL;
145 }
146
147 HAL_FLASH_Unlock();
148
149 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR);
150
151 if (size < 1)
152 {
153 return -RT_ERROR;
154 }
155
156 for (i = 0; i < size;)
157 {
158 if ((size - i) < 8)
159 {
160 for (j = 0; (size - i) > 0; i++, j++)
161 {
162 temp_data = *buf;
163 write_data = (write_data) | (temp_data << 8 * j);
164 buf ++;
165 }
166 }
167 else
168 {
169 for (j = 0; j < 8; j++, i++)
170 {
171 temp_data = *buf;
172 write_data = (write_data) | (temp_data << 8 * j);
173 buf ++;
174 }
175 }
176
177 /* write data */
178 if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, write_data) == HAL_OK)
179 {
180 /* Check the written value */
181 if (*(uint64_t*)addr != write_data)
182 {
183 LOG_E("ERROR: write data != read data\n");
184 result = -RT_ERROR;
185 goto __exit;
186 }
187 }
188 else
189 {
190 result = -RT_ERROR;
191 goto __exit;
192 }
193
194 temp_data = 0;
195 write_data = 0;
196
197 addr += 8;
198 }
199
200 __exit:
201 HAL_FLASH_Lock();
202 if (result != 0)
203 {
204 return result;
205 }
206
207 return size;
208 }
209
210 /**
211 * Erase data on flash.
212 * @note This operation is irreversible.
213 * @note This operation's units is different which on many chips.
214 *
215 * @param addr flash address
216 * @param size erase bytes size
217 *
218 * @return result
219 */
stm32_flash_erase(rt_uint32_t addr,size_t size)220 int stm32_flash_erase(rt_uint32_t addr, size_t size)
221 {
222 rt_err_t result = RT_EOK;
223 uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0;
224 uint32_t PAGEError = 0;
225
226 if ((addr + size) > STM32_FLASH_END_ADDRESS)
227 {
228 LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
229 return -RT_EINVAL;
230 }
231
232 /*Variable used for Erase procedure*/
233 FLASH_EraseInitTypeDef EraseInitStruct;
234 /* Unlock the Flash to enable the flash control register access *************/
235 HAL_FLASH_Unlock();
236
237 /* Clear OPTVERR bit set on virgin samples */
238 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_PGSERR);
239 /* Get the 1st page to erase */
240 FirstPage = GetPage(addr);
241 /* Get the number of pages to erase from 1st page */
242 NbOfPages = GetPage(addr + size - 1) - FirstPage + 1;
243 /* Get the bank */
244 BankNumber = GetBank(addr);
245 /* Fill EraseInit structure*/
246 EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
247 EraseInitStruct.Banks = BankNumber;
248 EraseInitStruct.Page = FirstPage;
249 EraseInitStruct.NbPages = NbOfPages;
250
251 if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
252 {
253 result = -RT_ERROR;
254 goto __exit;
255 }
256
257 __exit:
258 HAL_FLASH_Lock();
259
260 if (result != RT_EOK)
261 {
262 return result;
263 }
264
265 LOG_D("erase done: addr (0x%p), size %d", (void*)addr, size);
266 return size;
267 }
268
269 #if defined(RT_USING_FAL)
270
271 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
272 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
273 static int fal_flash_erase(long offset, size_t size);
274
275 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} };
276
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)277 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
278 {
279 return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size);
280 }
281
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)282 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
283 {
284 return stm32_flash_write(stm32_onchip_flash.addr + offset, buf, size);
285 }
286
fal_flash_erase(long offset,size_t size)287 static int fal_flash_erase(long offset, size_t size)
288 {
289 return stm32_flash_erase(stm32_onchip_flash.addr + offset, size);
290 }
291
292 #endif
293 #endif /* BSP_USING_ON_CHIP_FLASH */
294