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  * 2019-3-2       jinsheng     add Macro judgment
10  * 2020-1-6       duminmin     support single bank mode
11  * 2020-5-17      yufanyufan77 support support H7
12  * 2021-3-3       zhuyf233     fix some bugs
13  */
14 
15 #include <rtconfig.h>
16 #include <rtdef.h>
17 
18 #ifdef BSP_USING_ON_CHIP_FLASH
19 #include "drv_config.h"
20 #include "drv_flash.h"
21 #include <board.h>
22 
23 #if defined(RT_USING_FAL)
24 #include "fal.h"
25 #endif
26 
27 //#define DRV_DEBUG
28 #define LOG_TAG                "drv.flash"
29 #include <drv_log.h>
30 
31 /**
32  * Read data from flash.
33  * @note This operation's units is word.
34  *
35  * @param addr flash address
36  * @param buf buffer to store read data
37  * @param size read bytes size
38  *
39  * @retval The length of bytes that have been read
40  */
stm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)41 int stm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
42 {
43     size_t i;
44 
45     if ((addr + size - 1) > FLASH_END)
46     {
47         LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
48         return -RT_ERROR;
49     }
50 
51     for (i = 0; i < size; i++, buf++, addr++)
52     {
53         *buf = *(rt_uint8_t *) addr;
54     }
55 
56     return size;
57 }
58 
59 /**
60  * Write data to flash.
61  * @note This operation's units is word.
62  * @note This operation must after erase. @see flash_erase.
63  *
64  * @param addr flash address
65  * @param buf the write data buffer
66  * @param size write bytes size
67  *
68  * @return The length of bytes that have been written
69  */
stm32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)70 int stm32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
71 {
72     rt_err_t result      = RT_EOK;
73     rt_uint32_t end_addr = addr + size - 1, write_addr;
74     rt_uint32_t write_granularity = FLASH_NB_32BITWORD_IN_FLASHWORD * 4;
75     rt_uint32_t write_size = write_granularity;
76     rt_uint8_t write_buffer[32] = {0};
77 
78     if ((end_addr) > FLASH_END)
79     {
80         LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
81         return -RT_EINVAL;
82     }
83 
84     if(addr % 32 != 0)
85     {
86         LOG_E("write addr must be 32-byte alignment");
87         return -RT_EINVAL;
88     }
89 
90     if (size < 1)
91     {
92         return -RT_EINVAL;
93     }
94 
95     HAL_FLASH_Unlock();
96     write_addr = (uint32_t)buf;
97     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR);
98     while (addr < end_addr)
99     {
100         if(end_addr - addr + 1 < write_granularity)
101         {
102             write_size = end_addr - addr + 1;
103             for(size_t i = 0; i < write_size; i++)
104             {
105                 write_buffer[i] = *((uint8_t *)(write_addr + i));
106             }
107             write_addr = (uint32_t)((rt_uint32_t *)write_buffer);
108         }
109         if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, addr, write_addr) == HAL_OK)
110         {
111             for(rt_uint8_t i = 0; i < write_size; i++)
112             {
113                 if (*(rt_uint8_t *)(addr + i) != *(rt_uint8_t *)(write_addr + i))
114                 {
115                     result = -RT_ERROR;
116                     goto __exit;
117                 }
118             }
119             addr += write_granularity;
120             write_addr  += write_granularity;
121         }
122         else
123         {
124             result = -RT_ERROR;
125             goto __exit;
126         }
127     }
128 
129 __exit:
130     HAL_FLASH_Lock();
131 
132     if (result != RT_EOK)
133     {
134         return result;
135     }
136 
137     return size;
138 }
139 
140 /**
141  * Erase data on flash.
142  * @note This operation is irreversible.
143  * @note This operation's units is different which on many chips.
144  *
145  * @param addr flash address
146  * @param size erase bytes size
147  *
148  * @return result
149  */
stm32_flash_erase(rt_uint32_t addr,size_t size)150 int stm32_flash_erase(rt_uint32_t addr, size_t size)
151 {
152     rt_err_t result = RT_EOK;
153     rt_uint32_t SECTORError = 0;
154 
155     if ((addr + size - 1) > FLASH_END)
156     {
157         LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
158         return -RT_EINVAL;
159     }
160 
161     rt_uint32_t addr_bank1 = 0;
162     rt_uint32_t size_bank1 = 0;
163 #ifdef FLASH_BANK_2
164     rt_uint32_t addr_bank2 = 0;
165     rt_uint32_t size_bank2 = 0;
166 #endif
167 
168     if((addr + size) < FLASH_BANK2_BASE)
169     {
170         addr_bank1 = addr;
171         size_bank1 = size;
172 #ifdef FLASH_BANK_2
173         size_bank2 = 0;
174 #endif
175     }
176     else if(addr >= FLASH_BANK2_BASE)
177     {
178         size_bank1 = 0;
179 #ifdef FLASH_BANK_2
180         addr_bank2 = addr;
181         size_bank2 = size;
182 #endif
183     }
184     else
185     {
186         addr_bank1 = addr;
187         size_bank1 = FLASH_BANK2_BASE - addr_bank1;
188 #ifdef FLASH_BANK_2
189         addr_bank2 = FLASH_BANK2_BASE;
190         size_bank2 = addr + size - FLASH_BANK2_BASE;
191 #endif
192     }
193 
194     /*Variable used for Erase procedure*/
195     FLASH_EraseInitTypeDef EraseInitStruct;
196     /* Unlock the Flash to enable the flash control register access */
197     HAL_FLASH_Unlock();
198     EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
199     EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
200     SCB_DisableDCache();
201 
202     if(size_bank1)
203     {
204         EraseInitStruct.Sector    = (addr_bank1 - FLASH_BANK1_BASE) / FLASH_SECTOR_SIZE;
205         EraseInitStruct.NbSectors = (addr_bank1 + size_bank1 -1 - FLASH_BANK1_BASE) / FLASH_SECTOR_SIZE - EraseInitStruct.Sector + 1;
206         EraseInitStruct.Banks = FLASH_BANK_1;
207         if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
208         {
209             result = -RT_ERROR;
210             goto __exit;
211         }
212     }
213 
214 #ifdef FLASH_BANK_2
215     if(size_bank2)
216     {
217         EraseInitStruct.Sector    = (addr_bank2 - FLASH_BANK2_BASE) / FLASH_SECTOR_SIZE;
218         EraseInitStruct.NbSectors = (addr_bank2 + size_bank2 -1 - FLASH_BANK2_BASE) / FLASH_SECTOR_SIZE - EraseInitStruct.Sector + 1;
219         EraseInitStruct.Banks = FLASH_BANK_2;
220         if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
221         {
222             result = -RT_ERROR;
223             goto __exit;
224         }
225     }
226 #endif
227 
228 __exit:
229 
230     SCB_EnableDCache();
231     HAL_FLASH_Lock();
232 
233     if (result != RT_EOK)
234     {
235         return result;
236     }
237 
238     LOG_D("erase done: addr (0x%p), size %d", (void *)addr, size);
239     return size;
240 }
241 
242 #if defined(RT_USING_FAL)
243 static int fal_flash_read_128k(long offset, rt_uint8_t *buf, size_t size);
244 static int fal_flash_write_128k(long offset, const rt_uint8_t *buf, size_t size);
245 static int fal_flash_erase_128k(long offset, size_t size);
246 const struct fal_flash_dev stm32_onchip_flash_128k = { "onchip_flash_128k", STM32_FLASH_START_ADRESS, FLASH_SIZE_GRANULARITY_128K, (128 * 1024), {NULL, fal_flash_read_128k, fal_flash_write_128k, fal_flash_erase_128k} };
247 
fal_flash_read_128k(long offset,rt_uint8_t * buf,size_t size)248 static int fal_flash_read_128k(long offset, rt_uint8_t *buf, size_t size)
249 {
250     return stm32_flash_read(stm32_onchip_flash_128k.addr + offset, buf, size);
251 }
fal_flash_write_128k(long offset,const rt_uint8_t * buf,size_t size)252 static int fal_flash_write_128k(long offset, const rt_uint8_t *buf, size_t size)
253 {
254     return stm32_flash_write(stm32_onchip_flash_128k.addr + offset, buf, size);
255 }
256 
fal_flash_erase_128k(long offset,size_t size)257 static int fal_flash_erase_128k(long offset, size_t size)
258 {
259     return stm32_flash_erase(stm32_onchip_flash_128k.addr + offset, size);
260 }
261 
262 #endif
263 #endif /* BSP_USING_ON_CHIP_FLASH */
264