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