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