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 * 2023-03-28 luobeihai first version
9 *
10 */
11
12 #include "board.h"
13
14 #ifdef BSP_USING_ON_CHIP_FLASH
15 #include "drv_flash.h"
16
17 #if defined(RT_USING_FAL)
18 #include "fal.h"
19 #endif
20
21 #define DRV_DEBUG
22 #define LOG_TAG "drv.flash"
23 #include <drv_log.h>
24
25 #if defined(APM32E10X_HD)
26 #define FLASH_PAGE_SIZE 0x800U
27 #endif
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 */
apm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)51 int apm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
52 {
53 size_t i;
54
55 if ((addr + size) > APM32_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 */
apm32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)80 int apm32_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) > APM32_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 FMC_Unlock();
98
99 while (addr < end_addr)
100 {
101 if (FMC_ProgramWord(addr, *((rt_uint32_t *)buf)) == FMC_STATUS_COMPLETE)
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 FMC_Lock();
119
120 if (result != RT_EOK)
121 {
122 return result;
123 }
124
125 return size;
126 }
127
128 /**
129 * @brief erase data on flash .
130 * @note this operation is irreversible.
131 * @note this operation's units is different which on many chips.
132 *
133 * @param addr flash address
134 * @param size erase bytes size
135 *
136 * @return result
137 */
apm32_flash_erase(rt_uint32_t addr,size_t size)138 int apm32_flash_erase(rt_uint32_t addr, size_t size)
139 {
140 rt_err_t result = RT_EOK;
141 rt_uint32_t start_addr = addr;
142 rt_uint32_t end_addr = addr + size;
143 rt_uint32_t page_addr = 0;
144
145 FMC_Unlock();
146
147 if ((end_addr) > APM32_FLASH_END_ADDRESS)
148 {
149 LOG_E("erase outrange flash size! addr is (0x%p)", (void *)(addr + size));
150 return -RT_EINVAL;
151 }
152
153 /* clear program error flag */
154 if (FMC_ReadStatus() == FMC_STATUS_ERROR_PG)
155 {
156 FMC_ClearStatusFlag(FMC_FLAG_PE);
157 }
158
159 while(addr < end_addr)
160 {
161 page_addr = GetPage(addr);
162
163 if(FMC_ErasePage(page_addr) != FMC_STATUS_COMPLETE)
164 {
165 result = -RT_ERROR;
166 goto __exit;
167 }
168
169 addr += FLASH_PAGE_SIZE;
170 }
171
172 __exit:
173 FMC_Lock();
174
175 if(result != RT_EOK)
176 {
177 return result;
178 }
179
180 LOG_D("erase done: addr (0x%p), size %d", (void *)start_addr, size);
181
182 return size;
183 }
184
185
186 #if defined(RT_USING_FAL)
187
188 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
189 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
190 static int fal_flash_erase(long offset, size_t size);
191
192 const struct fal_flash_dev apm32_onchip_flash = { "onchip_flash", APM32_FLASH_START_ADRESS, APM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} };
193
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)194 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
195 {
196 return apm32_flash_read(apm32_onchip_flash.addr + offset, buf, size);
197 }
198
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)199 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
200 {
201 return apm32_flash_write(apm32_onchip_flash.addr + offset, buf, size);
202 }
203
fal_flash_erase(long offset,size_t size)204 static int fal_flash_erase(long offset, size_t size)
205 {
206 return apm32_flash_erase(apm32_onchip_flash.addr + offset, size);
207 }
208
209 #endif
210 #endif /* BSP_USING_ON_CHIP_FLASH */
211