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-16 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(APM32F030x6) || defined(APM32F030x8) || defined(APM32F051))
26 #define FLASH_PAGE_SIZE 0x400U
27 #elif (defined(APM32F030xC) || defined(APM32F070xB) || defined(APM32F071) || defined(APM32F072) || defined(APM32F091))
28 #define FLASH_PAGE_SIZE 0x800U
29 #endif
30
31 /**
32 * @brief Gets the page of a given address
33 * @param Addr: Address of the FLASH Memory
34 * @retval The page of a given address
35 */
GetPage(uint32_t addr)36 static uint32_t GetPage(uint32_t addr)
37 {
38 uint32_t page = 0;
39 page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
40 return page;
41 }
42
43 /**
44 * Read data from flash.
45 * @note This operation's units is word.
46 *
47 * @param addr flash address
48 * @param buf buffer to store read data
49 * @param size read bytes size
50 *
51 * @return result
52 */
apm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)53 int apm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
54 {
55 size_t i;
56
57 if ((addr + size) > APM32_FLASH_END_ADDRESS)
58 {
59 LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
60 return -RT_EINVAL;
61 }
62
63 for (i = 0; i < size; i++, buf++, addr++)
64 {
65 *buf = *(rt_uint8_t *) addr;
66 }
67
68 return size;
69 }
70
71 /**
72 * Write data to flash.
73 * @note This operation's units is word.
74 * @note This operation must after erase. @see flash_erase.
75 *
76 * @param addr flash address
77 * @param buf the write data buffer
78 * @param size write bytes size
79 *
80 * @return result
81 */
apm32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)82 int apm32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
83 {
84 rt_err_t result = RT_EOK;
85 rt_uint32_t end_addr = addr + size;
86
87 if (addr % 4 != 0)
88 {
89 LOG_E("write addr must be 4-byte alignment");
90 return -RT_EINVAL;
91 }
92
93 if ((end_addr) > APM32_FLASH_END_ADDRESS)
94 {
95 LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
96 return -RT_EINVAL;
97 }
98
99 FMC_Unlock();
100
101 while (addr < end_addr)
102 {
103 if (FMC_ProgramWord(addr, *((rt_uint32_t *)buf)) == FMC_STATE_COMPLETE)
104 {
105 if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
106 {
107 result = -RT_ERROR;
108 break;
109 }
110 addr += 4;
111 buf += 4;
112 }
113 else
114 {
115 result = -RT_ERROR;
116 break;
117 }
118 }
119
120 FMC_Lock();
121
122 if (result != RT_EOK)
123 {
124 return result;
125 }
126
127 return size;
128 }
129
130 /**
131 * @brief erase data on flash .
132 * @note this operation is irreversible.
133 * @note this operation's units is different which on many chips.
134 *
135 * @param addr flash address
136 * @param size erase bytes size
137 *
138 * @return result
139 */
apm32_flash_erase(rt_uint32_t addr,size_t size)140 int apm32_flash_erase(rt_uint32_t addr, size_t size)
141 {
142 rt_err_t result = RT_EOK;
143 rt_uint32_t start_addr = addr;
144 rt_uint32_t end_addr = addr + size;
145 rt_uint32_t page_addr = 0;
146
147 FMC_Unlock();
148
149 if ((end_addr) > APM32_FLASH_END_ADDRESS)
150 {
151 LOG_E("erase outrange flash size! addr is (0x%p)", (void *)(addr + size));
152 return -RT_EINVAL;
153 }
154
155 /* clear program error flag */
156 if (FMC_ReadStatusFlag(FMC_FLAG_PE) == SET)
157 {
158 FMC_ClearStatusFlag(FMC_FLAG_PE);
159 }
160
161 while(addr < end_addr)
162 {
163 page_addr = GetPage(addr);
164
165 if(FMC_ErasePage(page_addr) != FMC_STATE_COMPLETE)
166 {
167 result = -RT_ERROR;
168 goto __exit;
169 }
170
171 addr += FLASH_PAGE_SIZE;
172 }
173
174 __exit:
175 FMC_Lock();
176
177 if(result != RT_EOK)
178 {
179 return result;
180 }
181
182 LOG_D("erase done: addr (0x%p), size %d", (void *)start_addr, size);
183
184 return size;
185 }
186
187
188 #if defined(RT_USING_FAL)
189
190 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
191 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
192 static int fal_flash_erase(long offset, size_t size);
193
194 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} };
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 apm32_flash_read(apm32_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 apm32_flash_write(apm32_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 apm32_flash_erase(apm32_onchip_flash.addr + offset, size);
209 }
210
211 #endif
212 #endif /* BSP_USING_ON_CHIP_FLASH */
213