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 * 2022-01-21 charlown the first version
9 */
10
11 #include <rtthread.h>
12 #include <board.h>
13
14 #ifdef BSP_USING_ON_CHIP_FLASH
15
16 #include "drv_flash.h"
17
18 #if defined(RT_USING_FAL)
19 #include "fal.h"
20 #endif
21
22
23 #define LOG_TAG "drv.flash"
24 #include <drv_log.h>
25
26 /**
27 * @brief Gets the page of a given address
28 * @param addr: address of the flash memory
29 * @retval The page of a given address
30 */
get_page(uint32_t addr)31 static rt_uint32_t get_page(uint32_t addr)
32 {
33 rt_uint32_t page = 0;
34
35 page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
36
37 return page;
38 }
39
40 /**
41 * Read data from flash.
42 * @note This operation's units is word.
43 *
44 * @param addr flash address
45 * @param buf buffer to store read data
46 * @param size read bytes size
47 *
48 * @return result
49 */
ch32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,rt_size_t size)50 int ch32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, rt_size_t size)
51 {
52 rt_size_t i;
53
54 if ((addr + size) > CH32_FLASH_END_ADDRESS)
55 {
56 LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
57 return -RT_EINVAL;
58 }
59
60 for (i = 0; i < size; i++, buf++, addr++)
61 {
62 *buf = *(rt_uint8_t *) addr;
63 }
64
65 return size;
66 }
67
68 /**
69 * Write data to flash.
70 * @note This operation's units is word.
71 * @note This operation must after erase. @see flash_erase.
72 *
73 * @param addr flash address
74 * @param buf the write data buffer
75 * @param size write bytes size
76 *
77 * @return result
78 */
ch32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,rt_size_t size)79 int ch32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, rt_size_t size)
80 {
81 rt_err_t result = RT_EOK;
82 rt_uint32_t end_addr = addr + size;
83
84 if (addr % 4 != 0)
85 {
86 LOG_E("write addr must be 4-byte alignment");
87 return -RT_EINVAL;
88 }
89
90 if ((end_addr) > CH32_FLASH_END_ADDRESS)
91 {
92 LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
93 return -RT_EINVAL;
94 }
95
96 FLASH_Unlock();
97
98 while (addr < end_addr)
99 {
100 if (FLASH_ProgramWord(addr, *((rt_uint32_t *)buf)) == FLASH_COMPLETE)
101 {
102 if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
103 {
104 result = -RT_ERROR;
105 break;
106 }
107 addr += 4;
108 buf += 4;
109 }
110 else
111 {
112 result = -RT_ERROR;
113 break;
114 }
115 }
116
117 FLASH_Lock();
118
119 if (result != RT_EOK)
120 {
121 return result;
122 }
123
124 return size;
125 }
126
127 /**
128 * Erase data on flash .
129 * @note This operation is irreversible.
130 * @note This operation's units is different which on many chips.
131 *
132 * @param addr flash address
133 * @param size erase bytes size
134 *
135 * @return result
136 */
ch32_flash_erase(rt_uint32_t addr,rt_size_t size)137 int ch32_flash_erase(rt_uint32_t addr, rt_size_t size)
138 {
139 rt_err_t result = RT_EOK;
140 rt_uint32_t end_addr = addr + size;
141 rt_uint32_t page_addr = 0;
142
143 FLASH_Unlock();
144
145 if ((end_addr) > CH32_FLASH_END_ADDRESS)
146 {
147 LOG_E("erase outrange flash size! addr is (0x%p)", (void *)(addr + size));
148 return -RT_EINVAL;
149 }
150
151 while(addr < end_addr)
152 {
153 page_addr = get_page(addr);
154
155 if(FLASH_ErasePage(page_addr) != FLASH_COMPLETE)
156 {
157 result = -RT_ERROR;
158 goto __exit;
159 }
160
161 addr += FLASH_PAGE_SIZE;
162 }
163
164 FLASH_Lock();
165
166 __exit:
167 if(result != RT_EOK)
168 {
169 return result;
170 }
171
172 return size;
173 }
174
175 #if defined(RT_USING_FAL)
176
177 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
178 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
179 static int fal_flash_erase(long offset, size_t size);
180
181 /*fal_cfg.h use it*/
182 const struct fal_flash_dev ch32_onchip_flash =
183 {
184 "onchip_flash",
185 CH32_FLASH_START_ADRESS,
186 CH32_FLASH_SIZE,
187 FLASH_PAGE_SIZE,
188 {
189 NULL,
190 fal_flash_read,
191 fal_flash_write,
192 fal_flash_erase
193 }
194 };
195
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)196 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
197 {
198 return ch32_flash_read(ch32_onchip_flash.addr + offset, buf, size);
199 }
200
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)201 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
202 {
203 return ch32_flash_write(ch32_onchip_flash.addr + offset, buf, size);
204 }
205
fal_flash_erase(long offset,size_t size)206 static int fal_flash_erase(long offset, size_t size)
207 {
208 return ch32_flash_erase(ch32_onchip_flash.addr + offset, size);
209 }
210
211 #endif /* RT_USING_FAL */
212
213 #endif /* BSP_USING_ON_CHIP_FLASH */
214