1 /*
2 * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-12-30 CDT first version
9 */
10
11 /*
12 * 程序清单:NAND 设备使用例程,例程导出了nand_sample命令到控制终端
13 * 命令调用格式:nand_sample
14 * 程序功能:对整个Nand存储空间进行擦除、写和读操作,比较数据是否一致
15 *
16 * 注意:
17 * F4A0: 修改函数SystemClock_Config,调用函数CLK_SetClockDiv参数,CLK_EXCLK_DIV2改为CLK_EXCLK_DIV4;
18 *
19 * menuconfig:
20 * Hardware Drivers Config ---> Onboard Peripheral Drivers ----> Enable EXMC ----> Using SDRAM or NAND ----> Using NAND
21 */
22
23 #include <stdlib.h>
24 #include <rtthread.h>
25 #include <rtdevice.h>
26 #include <board.h>
27
28 #if defined(BSP_USING_EXMC) && defined(BSP_USING_NAND)
29 #include "nand_port.h"
30
31 #define NAND_DEVICE_NAME "nand"
32
nand_read_id(struct rt_mtd_nand_device * mtd_nand)33 static rt_err_t nand_read_id(struct rt_mtd_nand_device *mtd_nand)
34 {
35 if (mtd_nand == RT_NULL)
36 {
37 rt_kprintf("mtd_nand pointer = NULL!\n");
38 return -RT_ERROR;
39 }
40
41 return rt_mtd_nand_read_id(mtd_nand);
42 }
43
nand_read(struct rt_mtd_nand_device * mtd_nand,int block,rt_off_t page,rt_uint8_t * data)44 static rt_err_t nand_read(struct rt_mtd_nand_device *mtd_nand, int block, rt_off_t page, rt_uint8_t *data)
45 {
46 rt_err_t result;
47
48 if ((mtd_nand == RT_NULL) || (block >= mtd_nand->block_total) || (data == RT_NULL))
49 {
50 rt_kprintf("%s: parameters invallid!\n", __func__);
51 return -RT_ERROR;
52 }
53
54 /* calculate the page number */
55 page = block * mtd_nand->pages_per_block + page;
56 result = rt_mtd_nand_read(mtd_nand, page, data, mtd_nand->page_size, RT_NULL, mtd_nand->oob_size);
57
58 return result;
59 }
60
nand_read_oob_free(struct rt_mtd_nand_device * mtd_nand,int block,rt_off_t page,rt_uint8_t * oob_free_data)61 static rt_err_t nand_read_oob_free(struct rt_mtd_nand_device *mtd_nand, int block, rt_off_t page, rt_uint8_t *oob_free_data)
62 {
63 rt_err_t result;
64
65 if ((mtd_nand == RT_NULL) || (block >= mtd_nand->block_total) || (oob_free_data == RT_NULL))
66 {
67 rt_kprintf("%s: parameters invallid!\n", __func__);
68 return -RT_ERROR;
69 }
70
71 /* calculate the page number */
72 page = block * mtd_nand->pages_per_block + page;
73 result = rt_mtd_nand_read(mtd_nand, page, RT_NULL, 0UL, oob_free_data, mtd_nand->oob_free);
74
75 return result;
76 }
77
nand_write(struct rt_mtd_nand_device * mtd_nand,int block,rt_off_t page,rt_uint8_t * data,rt_uint8_t * oob_free_data)78 static rt_err_t nand_write(struct rt_mtd_nand_device *mtd_nand, int block, rt_off_t page,
79 rt_uint8_t *data, rt_uint8_t *oob_free_data)
80 {
81 rt_err_t result;
82
83 if ((mtd_nand == RT_NULL) || (block >= mtd_nand->block_total) || ((data == RT_NULL) && (oob_free_data == RT_NULL)))
84 {
85 rt_kprintf("%s: parameters invallid!\n", __func__);
86 return -RT_ERROR;
87 }
88
89
90 /* calculate the page number */
91 page = block * mtd_nand->pages_per_block + page;
92 result = rt_mtd_nand_write(mtd_nand, page, data, mtd_nand->page_size, oob_free_data, mtd_nand->oob_free);
93 if (result != RT_MTD_EOK)
94 {
95 rt_kprintf("write page failed!, rc=%d\n", result);
96 }
97
98 return result;
99 }
100
nand_erase(struct rt_mtd_nand_device * mtd_nand,int block)101 static rt_err_t nand_erase(struct rt_mtd_nand_device *mtd_nand, int block)
102 {
103 if ((mtd_nand == RT_NULL) || (block >= mtd_nand->block_total))
104 {
105 rt_kprintf("%s: parameters invallid!\n", __func__);
106 return -RT_ERROR;
107 }
108
109 return rt_mtd_nand_erase_block(mtd_nand, block);
110 }
111
nand_thread_entry(void * parameter)112 static void nand_thread_entry(void *parameter)
113 {
114 rt_err_t result;
115 rt_uint32_t i;
116 rt_uint32_t block = 0UL;
117 rt_uint32_t page = 0UL;
118 rt_uint32_t err_count = 0UL;
119
120 rt_uint8_t *page_rbuf;
121 rt_uint8_t *page_wbuf;
122 rt_uint8_t *page_oob_free_wbuf;
123 rt_uint8_t *page_oob_free_rbuf;
124 struct rt_mtd_nand_device *mtd_nand;
125
126 mtd_nand = RT_MTD_NAND_DEVICE(rt_device_find(NAND_DEVICE_NAME));
127 if (mtd_nand == RT_NULL)
128 {
129 rt_kprintf("no nand device found!\n");
130 return;
131 }
132
133 /* read UID */
134 if (nand_read_id(mtd_nand) != RT_EOK)
135 {
136 rt_kprintf("fail nand_read_id!\n");
137 return;
138 }
139
140 /* memory buffer */
141 page_rbuf = rt_malloc(mtd_nand->page_size);
142 if (page_rbuf == RT_NULL)
143 {
144 rt_kprintf("out of memory!");
145 return;
146 }
147
148 page_wbuf = rt_malloc(mtd_nand->page_size);
149 if (page_wbuf == RT_NULL)
150 {
151 rt_free(page_rbuf);
152 rt_kprintf("out of memory!");
153 return;
154 }
155
156 page_oob_free_rbuf = rt_malloc(mtd_nand->oob_free);
157 if (page_oob_free_rbuf == RT_NULL)
158 {
159 rt_free(page_rbuf);
160 rt_free(page_wbuf);
161 rt_kprintf("out of memory!");
162 return;
163 }
164
165 page_oob_free_wbuf = rt_malloc(mtd_nand->oob_free);
166 if (page_oob_free_wbuf == RT_NULL)
167 {
168 rt_free(page_rbuf);
169 rt_free(page_wbuf);
170 rt_free(page_oob_free_rbuf);
171 rt_kprintf("out of memory!");
172 return;
173 }
174
175 while (1)
176 {
177 for (block = 0UL; block < mtd_nand->block_total; block++)
178 {
179 for (i = 0UL; i < mtd_nand->page_size; i++)
180 {
181 page_rbuf[i] = 0U;
182 page_wbuf[i] = (rt_uint8_t)rand();
183 }
184
185 for (i = 0UL; i < mtd_nand->oob_free; i++)
186 {
187 page_oob_free_rbuf[i] = 0;
188 page_oob_free_wbuf[i] = (rt_uint8_t)rand();
189 }
190
191 result = nand_erase(mtd_nand, block);
192 if (result == RT_EOK)
193 {
194 rt_kprintf("mtd_nand_erase block=0x%08X: ok !\r\n", block);
195 }
196 else
197 {
198 err_count++;
199 rt_kprintf("mtd_nand_erase block=0x%08X: error !\r\n", block);
200 }
201
202 for (page = 0UL; page < mtd_nand->pages_per_block; page++)
203 {
204 rt_thread_mdelay(500);
205
206 result = nand_write(mtd_nand, block, page, page_wbuf, page_oob_free_wbuf);
207 if (result == RT_EOK)
208 {
209 rt_kprintf("nand_write block=0x%08X page=%d(include oob free area): ok !\r\n", block, page);
210 }
211 else
212 {
213 err_count++;
214 rt_kprintf("nand_write block=0x%08X page=%d(include oob free area): error !\r\n", block, page);
215 break;
216 }
217
218 result = nand_read(mtd_nand, block, page, page_rbuf);
219 if (result == RT_EOK)
220 {
221 rt_kprintf("nand_read block=0x%08X page=%d: ok !\r\n", block, page);
222 }
223 else
224 {
225 err_count++;
226 rt_kprintf("nand_read block=0x%08X page=%d: error !\r\n", block, page);
227 break;
228 }
229
230 if (rt_memcmp(page_rbuf, page_wbuf, mtd_nand->page_size) == 0)
231 {
232 rt_kprintf("nand_write and nand_read block=0x%08X page=0x%d data consistency: ok !\r\n", block, page);
233 }
234 else
235 {
236 err_count++;
237 rt_kprintf("nand_write and nand_read block=0x%08X page=0x%d data consistency: error !\r\n", block, page);
238 break;
239 }
240
241 result = nand_read_oob_free(mtd_nand, block, page, page_oob_free_rbuf);
242 if (result == RT_EOK)
243 {
244 rt_kprintf("nand_read_oob_free block=0x%08X page=%d: ok !\r\n", block, page);
245 }
246 else
247 {
248 err_count++;
249 rt_kprintf("nand_read_oob_free block=0x%08X page=%d: error !\r\n", block, page);
250 break;
251 }
252
253 if (rt_memcmp(page_oob_free_rbuf, page_oob_free_wbuf, mtd_nand->oob_free) == 0)
254 {
255 rt_kprintf("nand_write and nand_read_oob_free block=0x%08X page=0x%d data consistency: ok !\r\n", block, page);
256 }
257 else
258 {
259 err_count++;
260 rt_kprintf("nand_write and nand_read_oob_free block=0x%08X page=0x%d data consistency: error !\r\n", block, page);
261 break;
262 }
263
264 rt_kprintf("mtd_nand block=0x%08X, page=%d test result: ok...... !\r\n", block, page);
265 }
266 }
267
268 rt_kprintf("mtd_nand test result: %s !\r\n", err_count ? "err" : "ok");
269 rt_thread_mdelay(500);
270 }
271 }
272
nand_sample(int argc,char * argv[])273 static void nand_sample(int argc, char *argv[])
274 {
275 rt_thread_t thread = rt_thread_create("nand", nand_thread_entry, RT_NULL, 2048, 15, 10);
276 if (thread != RT_NULL)
277 {
278 rt_thread_startup(thread);
279 }
280 }
281 MSH_CMD_EXPORT(nand_sample, nand sample);
282
283 #endif
284