Skip to content

Commit aadcc97

Browse files
danieldegrassedleach02
authored andcommitted
tests: subsys: sd: Add SDMMC subsystem test
Add SDMMC subsystem test, to verify functionality of SDMMC portion of subsystem. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 64c5b93 commit aadcc97

File tree

7 files changed

+326
-0
lines changed

7 files changed

+326
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ scripts/gen_image_info.py @tejlmand
812812
/tests/net/socket/ @rlubos @tbursztyka @pfalcon
813813
/tests/subsys/debug/coredump/ @dcpleung
814814
/tests/subsys/fs/ @nashif @nvlsianpu @de-nordic
815+
/tests/subsys/sd/ @danieldegrasse
815816
/tests/subsys/settings/ @nvlsianpu
816817
/tests/subsys/shell/ @jakub-uC @nordic-krch
817818
# Get all docs reviewed

tests/subsys/sd/sdmmc/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(sdmmc_subsys_test)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
target_sources(app PRIVATE ${app_sources})

tests/subsys/sd/sdmmc/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2022 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
mainmenu "SD Host controller test"
5+
6+
source "Kconfig.zephyr"
7+
8+
config SDHC_LABEL
9+
string "SD host controller label"
10+
default "SDHC_0"
11+
help
12+
Devicetree label for SD host controller. Used to get reference to
13+
device

tests/subsys/sd/sdmmc/README.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
SDMMC Subsystem Test
2+
##################
3+
4+
This test is designed to verify the SD subsystem stack implementation,
5+
and run stress tests to verify large data transfers succeed using the
6+
subsystem. Due to the differences between underlying SD host controller drivers,
7+
this test also serves as a complete test for the SDHC driver implementation in
8+
use. It requires an SD card be connected to the board to pass, and will
9+
perform destructive I/O on the card, wiping any data present. The test has
10+
the following phases:
11+
12+
* Init test: verify the SD host controller can detect card presence, and
13+
test the initialization flow of the SDMMC subsystem to verify that the stack
14+
can correctly initialize an SD card.
15+
16+
* IOCTL test: verify the SD subsystem correctly implements IOCTL calls required
17+
for block devices in Zephyr.
18+
19+
* Read test: verify that single block reads work, followed by multiple
20+
block reads. Ensure the subsystem will reject reads beyond the end of
21+
the card's stated size.
22+
23+
* Write test: verify that single block writes work, followed by multiple
24+
block writes. Ensure the subsystem will reject writes beyond the end of
25+
the card's stated size.
26+
27+
* R/W test: write data to the SD card, and verify that it is able
28+
to be read back without error. Perform this R/W combination at several
29+
sector locations across the SD card.

tests/subsys/sd/sdmmc/prj.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CONFIG_TEST=y
2+
CONFIG_ZTEST=y
3+
CONFIG_SDHC=y
4+
CONFIG_SD_STACK=y
5+
CONFIG_LOG=y

tests/subsys/sd/sdmmc/src/main.c

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* Copyright 2022 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/zephyr.h>
8+
#include <zephyr/sd/sdmmc.h>
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/disk.h>
11+
#include <ztest.h>
12+
13+
14+
#define SECTOR_COUNT 32
15+
#define SECTOR_SIZE 512 /* subsystem should set all cards to 512 byte blocks */
16+
#define BUF_SIZE SECTOR_SIZE * SECTOR_COUNT
17+
const struct device *sdhc_dev;
18+
static struct sd_card card;
19+
static uint8_t buf[BUF_SIZE] __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT);
20+
static uint8_t check_buf[BUF_SIZE] __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT);
21+
static uint32_t sector_size;
22+
static uint32_t sector_count;
23+
24+
#define SDMMC_UNALIGN_OFFSET 1
25+
26+
27+
/* Verify that SD stack can initialize an SD card */
28+
static void test_init(void)
29+
{
30+
int ret;
31+
32+
sdhc_dev = device_get_binding(CONFIG_SDHC_LABEL);
33+
zassert_not_null(sdhc_dev, "Could not get SD host controller dev");
34+
35+
ret = sd_is_card_present(sdhc_dev);
36+
zassert_equal(ret, 1, "SD card not present in slot");
37+
38+
ret = sd_init(sdhc_dev, &card);
39+
zassert_equal(ret, 0, "Card initialization failed");
40+
}
41+
42+
/* Verify that SD stack returns valid IOCTL values */
43+
static void test_ioctl(void)
44+
{
45+
int ret;
46+
47+
ret = sdmmc_ioctl(&card, DISK_IOCTL_GET_SECTOR_COUNT, &sector_count);
48+
zassert_equal(ret, 0, "IOCTL sector count read failed");
49+
TC_PRINT("SD card reports sector count of %d\n", sector_count);
50+
51+
ret = sdmmc_ioctl(&card, DISK_IOCTL_GET_SECTOR_SIZE, &sector_size);
52+
zassert_equal(ret, 0, "IOCTL sector size read failed");
53+
TC_PRINT("SD card reports sector size of %d\n", sector_size);
54+
}
55+
56+
57+
/* Verify that SD stack can read from an SD card */
58+
static void test_read(void)
59+
{
60+
int ret;
61+
int block_addr = 0;
62+
63+
/* Try simple reads from start of SD card */
64+
65+
ret = sdmmc_read_blocks(&card, buf, block_addr, 1);
66+
zassert_equal(ret, 0, "Single block card read failed");
67+
68+
ret = sdmmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
69+
zassert_equal(ret, 0, "Multiple block card read failed");
70+
71+
/* Try a series of reads from the same block */
72+
block_addr = sector_count / 2;
73+
for (int i = 0; i < 10; i++) {
74+
ret = sdmmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT);
75+
zassert_equal(ret, 0, "Multiple reads from same addr failed");
76+
}
77+
/* Verify that out of bounds read fails */
78+
block_addr = sector_count;
79+
ret = sdmmc_read_blocks(&card, buf, block_addr, 1);
80+
zassert_not_equal(ret, 0, "Out of bounds read should fail");
81+
82+
block_addr = sector_count - 2;
83+
ret = sdmmc_read_blocks(&card, buf, block_addr, 2);
84+
zassert_equal(ret, 0, "Read from end of card failed");
85+
86+
/* Verify that unaligned reads work */
87+
block_addr = 3;
88+
ret = sdmmc_read_blocks(&card, buf + SDMMC_UNALIGN_OFFSET,
89+
block_addr, SECTOR_COUNT - 1);
90+
zassert_equal(ret, 0, "Unaligned read failed");
91+
}
92+
93+
/* Verify that SD stack can write to an SD card */
94+
static void test_write(void)
95+
{
96+
int ret;
97+
int block_addr = 0;
98+
99+
/* Try simple writes from start of SD card */
100+
101+
ret = sdmmc_write_blocks(&card, buf, block_addr, 1);
102+
zassert_equal(ret, 0, "Single block card write failed");
103+
104+
ret = sdmmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
105+
zassert_equal(ret, 0, "Multiple block card write failed");
106+
107+
/* Try a series of reads from the same block */
108+
block_addr = sector_count / 2;
109+
for (int i = 0; i < 10; i++) {
110+
ret = sdmmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT);
111+
zassert_equal(ret, 0, "Multiple writes to same addr failed");
112+
}
113+
/* Verify that out of bounds write fails */
114+
block_addr = sector_count;
115+
ret = sdmmc_write_blocks(&card, buf, block_addr, 1);
116+
zassert_not_equal(ret, 0, "Out of bounds write should fail");
117+
118+
block_addr = sector_count - 2;
119+
ret = sdmmc_write_blocks(&card, buf, block_addr, 2);
120+
zassert_equal(ret, 0, "Write to end of card failed");
121+
122+
/* Verify that unaligned writes work */
123+
block_addr = 3;
124+
ret = sdmmc_write_blocks(&card, buf + SDMMC_UNALIGN_OFFSET,
125+
block_addr, SECTOR_COUNT - 1);
126+
zassert_equal(ret, 0, "Unaligned write failed");
127+
}
128+
129+
/* Test reads and writes interleaved, to verify data is making it on disk */
130+
static void test_rw(void)
131+
{
132+
int ret;
133+
int block_addr = 0;
134+
135+
/* Zero the write buffer */
136+
memset(buf, 0, BUF_SIZE);
137+
memset(check_buf, 0, BUF_SIZE);
138+
ret = sdmmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
139+
zassert_equal(ret, 0, "Write to card failed");
140+
/* Verify that a read from this area is empty */
141+
ret = sdmmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
142+
zassert_equal(ret, 0, "Read from card failed");
143+
zassert_mem_equal(buf, check_buf, BUF_SIZE,
144+
"Read of erased area was not zero");
145+
146+
/* Now write nonzero data block */
147+
for (int i = 0; i < sizeof(buf); i++) {
148+
check_buf[i] = buf[i] = (uint8_t)i;
149+
}
150+
151+
ret = sdmmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT);
152+
zassert_equal(ret, 0, "Write to card failed");
153+
/* Clear the read buffer, then write to it again */
154+
memset(buf, 0, BUF_SIZE);
155+
ret = sdmmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT);
156+
zassert_equal(ret, 0, "Read from card failed");
157+
zassert_mem_equal(buf, check_buf, BUF_SIZE,
158+
"Read of written area was not correct");
159+
160+
block_addr = (sector_count / 3);
161+
for (int i = 0; i < 10; i++) {
162+
/* Verify that unaligned writes work */
163+
ret = sdmmc_write_blocks(&card, buf + SDMMC_UNALIGN_OFFSET,
164+
block_addr, SECTOR_COUNT - 1);
165+
zassert_equal(ret, 0, "Write to card failed");
166+
/* Zero check buffer and read into it */
167+
memset(check_buf + SDMMC_UNALIGN_OFFSET, 0,
168+
(SECTOR_COUNT - 1) * sector_size);
169+
ret = sdmmc_read_blocks(&card, check_buf + SDMMC_UNALIGN_OFFSET,
170+
block_addr, (SECTOR_COUNT - 1));
171+
zassert_equal(ret, 0, "Read from card failed");
172+
zassert_mem_equal(buf + SDMMC_UNALIGN_OFFSET,
173+
check_buf + SDMMC_UNALIGN_OFFSET,
174+
(SECTOR_COUNT - 1) * sector_size,
175+
"Unaligned read of written area was not correct");
176+
}
177+
}
178+
179+
/* Simply dump the card configuration. */
180+
void test_card_config(void)
181+
{
182+
switch (card.card_voltage) {
183+
case SD_VOL_1_2_V:
184+
TC_PRINT("Card voltage: 1.2V\n");
185+
break;
186+
case SD_VOL_1_8_V:
187+
TC_PRINT("Card voltage: 1.8V\n");
188+
break;
189+
case SD_VOL_3_0_V:
190+
TC_PRINT("Card voltage: 3.0V\n");
191+
break;
192+
case SD_VOL_3_3_V:
193+
TC_PRINT("Card voltage: 3.3V\n");
194+
break;
195+
default:
196+
zassert_unreachable("Card voltage is not known value");
197+
}
198+
zassert_equal(card.status, CARD_INITIALIZED, "Card status is not OK");
199+
switch (card.card_speed) {
200+
case SD_TIMING_SDR12:
201+
TC_PRINT("Card timing: SDR12\n");
202+
break;
203+
case SD_TIMING_SDR25:
204+
TC_PRINT("Card timing: SDR25\n");
205+
break;
206+
case SD_TIMING_SDR50:
207+
TC_PRINT("Card timing: SDR50\n");
208+
break;
209+
case SD_TIMING_SDR104:
210+
TC_PRINT("Card timing: SDR104\n");
211+
break;
212+
case SD_TIMING_DDR50:
213+
TC_PRINT("Card timing: DDR50\n");
214+
break;
215+
default:
216+
zassert_unreachable("Card timing is not known value");
217+
}
218+
switch (card.type) {
219+
case CARD_SDIO:
220+
TC_PRINT("Card type: SDIO\n");
221+
break;
222+
case CARD_SDMMC:
223+
TC_PRINT("Card type: SDMMC\n");
224+
break;
225+
case CARD_COMBO:
226+
TC_PRINT("Card type: combo card\n");
227+
break;
228+
default:
229+
zassert_unreachable("Card type is not known value");
230+
}
231+
if (card.sd_version >= SD_SPEC_VER3_0) {
232+
TC_PRINT("Card spec: 3.0\n");
233+
} else if (card.sd_version >= SD_SPEC_VER2_0) {
234+
TC_PRINT("Card spec: 2.0\n");
235+
} else if (card.sd_version >= SD_SPEC_VER1_1) {
236+
TC_PRINT("Card spec: 1.1\n");
237+
} else if (card.sd_version >= SD_SPEC_VER1_0) {
238+
TC_PRINT("Card spec: 1.0\n");
239+
} else {
240+
zassert_unreachable("Card spec is unknown value");
241+
}
242+
}
243+
244+
245+
void test_main(void)
246+
{
247+
ztest_test_suite(sd_stack_test,
248+
ztest_unit_test(test_init),
249+
ztest_unit_test(test_ioctl),
250+
ztest_unit_test(test_read),
251+
ztest_unit_test(test_write),
252+
ztest_unit_test(test_rw),
253+
ztest_unit_test(test_card_config)
254+
);
255+
256+
ztest_run_test_suite(sd_stack_test);
257+
}

tests/subsys/sd/sdmmc/testcase.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
common:
2+
depends_on: sdhc
3+
tags: drivers sdhc
4+
tests:
5+
subsys.sd.sdmmc:
6+
harness: ztest
7+
harness_config:
8+
fixture: fixture_sdhc
9+
filter: CONFIG_SD_STACK
10+
tags: sdhc
11+
min_ram: 32
12+
integration_platforms:
13+
- mimxrt1064_evk

0 commit comments

Comments
 (0)