1 /*
2 * Copyright (c) 2016 Linaro Limited
3 * 2016 Intel Corporation.
4 * Copyright (c) 2024 Nordic Semiconductor ASA
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/flash.h>
11 #include <zephyr/storage/flash_map.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <stdio.h>
15
16
17 #define TEST_PARTITION storage_partition
18
19 #define TEST_PARTITION_OFFSET FIXED_PARTITION_OFFSET(TEST_PARTITION)
20 #define TEST_PARTITION_DEVICE FIXED_PARTITION_DEVICE(TEST_PARTITION)
21
22 #define FLASH_PAGE_SIZE 4096
23 #define TEST_DATA_WORD_0 0x1122
24 #define TEST_DATA_WORD_1 0xaabb
25 #define TEST_DATA_WORD_2 0xabcd
26 #define TEST_DATA_WORD_3 0x1234
27
28 #define FLASH_TEST_OFFSET2 0x41234
29 #define FLASH_TEST_PAGE_IDX 37
30
31 #if defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && \
32 defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE)
33 #define FLASH_PE_RUNTIME_CHECK(cond) (cond)
34 #elif defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE)
35 #define FLASH_PE_RUNTIME_CHECK(cond) (true)
36 #else
37 /* Assumed IS_ENABLED(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE) */
38 #define FLASH_PE_RUNTIME_CHECK(cond) (false)
39 #endif
40
41 /**
42 * Depending on value of condition erase a device or not. The condition
43 * is supposed to be value of erase_requirement picked up from
44 * flash_parameters.flags for device.
45 */
erase_when_needed(const struct device * dev,bool condition,uint32_t off,uint32_t size)46 static void erase_when_needed(const struct device *dev, bool condition,
47 uint32_t off, uint32_t size)
48 {
49 /*
50 * Alwayes invoke erase when there are only erase requiring devices,
51 * never invoke erase when there are no devices requiring erase,
52 * always check condition if there are both kind of devices.
53 */
54 if (FLASH_PE_RUNTIME_CHECK(condition)) {
55 if (flash_erase(dev, off, size) != 0) {
56 printf(" Erase failed!\n");
57 } else {
58 printf(" Erase succeeded!\n");
59 }
60 } else {
61 (void)condition;
62 printf(" Erase not required by device\n");
63 }
64 }
65
main(void)66 int main(void)
67 {
68 const struct device *flash_dev = TEST_PARTITION_DEVICE;
69 struct flash_parameters flash_params;
70 uint32_t buf_array_1[4] = { TEST_DATA_WORD_0, TEST_DATA_WORD_1,
71 TEST_DATA_WORD_2, TEST_DATA_WORD_3 };
72 uint32_t buf_array_2[4] = { TEST_DATA_WORD_3, TEST_DATA_WORD_1,
73 TEST_DATA_WORD_2, TEST_DATA_WORD_0 };
74 uint32_t buf_array_3[8] = { TEST_DATA_WORD_0, TEST_DATA_WORD_1,
75 TEST_DATA_WORD_2, TEST_DATA_WORD_3,
76 TEST_DATA_WORD_0, TEST_DATA_WORD_1,
77 TEST_DATA_WORD_2, TEST_DATA_WORD_3 };
78 uint32_t buf_word = 0U;
79 uint32_t i, offset;
80
81 memcpy(&flash_params, flash_get_parameters(flash_dev), sizeof(flash_params));
82
83 printf("\nNordic nRF5 Internal Storage Sample\n");
84 printf("=====================================\n");
85
86 if (!device_is_ready(flash_dev)) {
87 printf("Internal storage device not ready\n");
88 return 0;
89 }
90
91 printf("\nTest 1: Internal storage erase page at 0x%x\n", TEST_PARTITION_OFFSET);
92 erase_when_needed(flash_dev,
93 flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
94 TEST_PARTITION_OFFSET, FLASH_PAGE_SIZE);
95
96 printf("\nTest 2: Internal storage write (word array 1)\n");
97 for (i = 0U; i < ARRAY_SIZE(buf_array_1); i++) {
98 offset = TEST_PARTITION_OFFSET + (i << 2);
99 printf(" Attempted to write %x at 0x%x\n", buf_array_1[i],
100 offset);
101 if (flash_write(flash_dev, offset, &buf_array_1[i],
102 sizeof(uint32_t)) != 0) {
103 printf(" Write failed!\n");
104 return 0;
105 }
106 printf(" Attempted to read 0x%x\n", offset);
107 if (flash_read(flash_dev, offset, &buf_word,
108 sizeof(uint32_t)) != 0) {
109 printf(" Read failed!\n");
110 return 0;
111 }
112 printf(" Data read: %x\n", buf_word);
113 if (buf_array_1[i] == buf_word) {
114 printf(" Data read matches data written. Good!\n");
115 } else {
116 printf(" Data read does not match data written!\n");
117 }
118 }
119
120 offset = TEST_PARTITION_OFFSET;
121 printf("\nTest 3: Internal storage erase (2 pages at 0x%x)\n", offset);
122 erase_when_needed(flash_dev,
123 flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
124 offset, FLASH_PAGE_SIZE * 2);
125 printf("\nTest 4: Internal storage write (word array 2)\n");
126 for (i = 0U; i < ARRAY_SIZE(buf_array_2); i++) {
127 offset = TEST_PARTITION_OFFSET + (i << 2);
128 printf(" Attempted to write %x at 0x%x\n", buf_array_2[i],
129 offset);
130 if (flash_write(flash_dev, offset, &buf_array_2[i],
131 sizeof(uint32_t)) != 0) {
132 printf(" Write failed!\n");
133 return 0;
134 }
135 printf(" Attempted to read 0x%x\n", offset);
136 if (flash_read(flash_dev, offset, &buf_word,
137 sizeof(uint32_t)) != 0) {
138 printf(" Read failed!\n");
139 return 0;
140 }
141 printf(" Data read: %x\n", buf_word);
142 if (buf_array_2[i] == buf_word) {
143 printf(" Data read matches data written. Good!\n");
144 } else {
145 printf(" Data read does not match data written!\n");
146 }
147 }
148
149 printf("\nTest 5: Internal storage erase page at 0x%x\n", TEST_PARTITION_OFFSET);
150 erase_when_needed(flash_dev,
151 flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
152 TEST_PARTITION_OFFSET, FLASH_PAGE_SIZE);
153
154 printf("\nTest 6: Non-word aligned write (word array 3)\n");
155 for (i = 0U; i < ARRAY_SIZE(buf_array_3); i++) {
156 offset = TEST_PARTITION_OFFSET + (i << 2) + 1;
157 printf(" Attempted to write %x at 0x%x\n", buf_array_3[i],
158 offset);
159 if (flash_write(flash_dev, offset, &buf_array_3[i],
160 sizeof(uint32_t)) != 0) {
161 printf(" Write failed!\n");
162 return 0;
163 }
164 printf(" Attempted to read 0x%x\n", offset);
165 if (flash_read(flash_dev, offset, &buf_word,
166 sizeof(uint32_t)) != 0) {
167 printf(" Read failed!\n");
168 return 0;
169 }
170 printf(" Data read: %x\n", buf_word);
171 if (buf_array_3[i] == buf_word) {
172 printf(" Data read matches data written. Good!\n");
173 } else {
174 printf(" Data read does not match data written!\n");
175 }
176 }
177
178 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
179 struct flash_pages_info info;
180 int rc;
181
182 rc = flash_get_page_info_by_offs(flash_dev, FLASH_TEST_OFFSET2, &info);
183
184 printf("\nTest 7: Page layout API\n");
185
186 if (!rc) {
187 printf(" Offset 0x%08x:\n", FLASH_TEST_OFFSET2);
188 printf(" belongs to the page %u of start offset 0x%08lx\n",
189 info.index, (unsigned long) info.start_offset);
190 printf(" and the size of 0x%08x B.\n", info.size);
191 } else {
192 printf(" Error: flash_get_page_info_by_offs returns %d\n",
193 rc);
194 }
195
196 rc = flash_get_page_info_by_idx(flash_dev, FLASH_TEST_PAGE_IDX, &info);
197
198 if (!rc) {
199 printf(" Page of number %u has start offset 0x%08lx\n",
200 FLASH_TEST_PAGE_IDX,
201 (unsigned long) info.start_offset);
202 printf(" and size of 0x%08x B.\n", info.size);
203 if (info.index == FLASH_TEST_PAGE_IDX) {
204 printf(" Page index resolved properly\n");
205 } else {
206 printf(" ERROR: Page index resolved to %u\n",
207 info.index);
208 }
209
210 } else {
211 printf(" Error: flash_get_page_info_by_idx returns %d\n", rc);
212 }
213
214 printf(" SoC flash consists of %u pages.\n",
215 flash_get_page_count(flash_dev));
216
217 #endif
218
219 printf("\nTest 8: Write block size API\n");
220 printf(" write-block-size = %u\n", flash_params.write_block_size);
221
222 printf("\nFinished!\n");
223 return 0;
224 }
225