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 * 2025-05-20 Chasel first version
9 *
10 */
11
12 #include <rtconfig.h>
13 #include <rtdef.h>
14
15 #ifdef BSP_USING_ON_CHIP_FLASH
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 #define FLASH_PAGE_SIZE 4096
28
29 /* @note If there is no down-frequency processing, the timeout time needs to be modified */
30 #ifdef ProgramTimeout
31 #undef ProgramTimeout
32 #define ProgramTimeout ((uint32_t)0x00010000)
33 #endif
34
35
36 /**
37 * @brief Gets the page of a given address
38 * @param Addr: Address of the FLASH Memory
39 * @retval The page of a given address
40 */
GetPage(uint32_t addr)41 static uint32_t GetPage(uint32_t addr)
42 {
43 uint32_t page = 0;
44 page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
45 return page;
46 }
47
48 /**
49 * Read data from flash.
50 * @note This operation's units is word.
51 *
52 * @param addr flash address
53 * @param buf buffer to store read data
54 * @param size read bytes size
55 *
56 * @return result
57 */
ch32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)58 int ch32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
59 {
60 size_t i;
61
62 if ((addr + size) > CH32_FLASH_END_ADDRESS)
63 {
64 LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
65 return -RT_EINVAL;
66 }
67
68 for (i = 0; i < size; i++, buf++, addr++)
69 {
70 *buf = *(rt_uint8_t *) addr;
71 }
72
73 return size;
74 }
75
76 /**
77 * Write data to flash.
78 * @note This operation's units is word.
79 * @note This operation must after erase. @see flash_erase.
80 *
81 * @param addr flash address
82 * @param buf the write data buffer
83 * @param size write bytes size
84 *
85 * @return result
86 */
ch32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)87 int ch32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
88 {
89 rt_err_t result = RT_EOK;
90 FLASH_Status status = 0;
91 rt_uint32_t end_addr = addr + size;
92
93 if (addr % 4 != 0)
94 {
95 LOG_E("write addr must be 4-byte alignment");
96 return -RT_EINVAL;
97 }
98
99 if ((end_addr) > CH32_FLASH_END_ADDRESS)
100 {
101 LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
102 return -RT_EINVAL;
103 }
104
105 if (((addr & 0x000000FF) == 0) && (size & 0xFFFFFF00)) {
106 rt_uint32_t fast_size = (size & 0xFFFFFF00);
107
108 status = FLASH_ROM_WRITE(addr, (rt_uint32_t *)buf, fast_size);
109 if (status != FLASH_COMPLETE) {
110 LOG_E("FLASH ROM Write Fail\r\n");
111 return -RT_ERROR;
112 }
113
114 addr += fast_size;
115 buf += fast_size;
116 }
117 if (addr == end_addr) {
118 return size;
119 }
120
121 FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM_HALF);
122 FLASH_Unlock();
123 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
124
125 while (addr < end_addr)
126 {
127 status = FLASH_ProgramWord(addr, *((rt_uint32_t *)buf));
128 if (status == FLASH_COMPLETE)
129 {
130 if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
131 {
132 result = -RT_ERROR;
133 break;
134 }
135 addr += 4;
136 buf += 4;
137 }
138 else
139 {
140 result = -RT_ERROR;
141 break;
142 }
143 }
144
145 FLASH_Lock();
146 FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM);
147
148 if (result != RT_EOK)
149 {
150 return result;
151 }
152
153 return size;
154 }
155
156 /**
157 * Erase data on flash .
158 * @note This operation is irreversible.
159 * @note This operation's units is different which on many chips.
160 *
161 * @param addr flash address
162 * @param size erase bytes size
163 *
164 * @return result
165 */
ch32_flash_erase(rt_uint32_t addr,size_t size)166 int ch32_flash_erase(rt_uint32_t addr, size_t size)
167 {
168 rt_err_t result = RT_EOK;
169 FLASH_Status status = 0;
170 uint32_t num_page = 0;
171 uint32_t i = 0;
172 rt_uint32_t total_size = size;
173
174 if ((addr + size) > CH32_FLASH_END_ADDRESS)
175 {
176 LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
177 return -RT_EINVAL;
178 }
179
180 if (((addr & 0x000000FF) == 0) && (total_size & 0xFFFFFF00)) {
181 rt_uint32_t fast_size = (total_size & 0xFFFFFF00);
182
183 status = FLASH_ROM_ERASE(addr, fast_size);
184 if (status != FLASH_COMPLETE) {
185 LOG_E("FLASH ROM Erase Fail\r\n");
186 return -RT_ERROR;
187 }
188
189 addr += fast_size;
190 total_size -= fast_size;
191 }
192
193 if (0 == total_size) {
194 return size;
195 }
196
197 FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM_HALF);
198 FLASH_Unlock();
199 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
200
201 num_page = (total_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
202
203 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
204
205 for(i = 0; (i < num_page) && (status == FLASH_COMPLETE); i++)
206 {
207 status = FLASH_ErasePage(GetPage(addr + i * FLASH_PAGE_SIZE)); //Erase 4KB
208
209 if(status != FLASH_COMPLETE)
210 {
211 LOG_E("FLASH Erase Fail\r\n");
212 result = -RT_ERROR;
213 goto __exit;
214 }
215 }
216
217 __exit:
218 FLASH_Lock();
219 FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM);
220
221 if (result != RT_EOK)
222 {
223 return -RT_ERROR;
224 }
225
226 return size;
227 }
228
229
230 #if defined(RT_USING_FAL)
231
232 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
233 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
234 static int fal_flash_erase(long offset, size_t size);
235
236 const struct fal_flash_dev ch32_onchip_flash = { "onchip_flash", CH32_FLASH_START_ADRESS, CH32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase}, 8, {} ,};
237
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)238 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
239 {
240 return ch32_flash_read(ch32_onchip_flash.addr + offset, buf, size);
241 }
242
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)243 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
244 {
245 return ch32_flash_write(ch32_onchip_flash.addr + offset, buf, size);
246 }
247
fal_flash_erase(long offset,size_t size)248 static int fal_flash_erase(long offset, size_t size)
249 {
250 return ch32_flash_erase(ch32_onchip_flash.addr + offset, size);
251 }
252
253 #endif
254 #endif /* BSP_USING_ON_CHIP_FLASH */
255