Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions bsp/qemu-vexpress-a9/.config
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE=y
#
# CONFIG_RT_USING_RYM is not set
# CONFIG_RT_USING_ULOG is not set
# CONFIG_RT_USING_UTEST is not set
CONFIG_RT_USING_UTEST=y
# CONFIG_RT_USING_VAR_EXPORT is not set
CONFIG_RT_USING_RESOURCE_ID=y
CONFIG_RT_USING_ADT=y
Expand Down Expand Up @@ -478,7 +478,15 @@ CONFIG_RT_PAGE_MAX_ORDER=11
#
# RT-Thread Utestcases
#
# CONFIG_RT_USING_UTESTCASES is not set
CONFIG_RT_USING_UTESTCASES=y
CONFIG_RT_UTEST_SPI_LOOPBACK=y
CONFIG_RT_UTEST_SPI_LOOPBACK_BUS_NAME="spi2"
CONFIG_RT_UTEST_SPI_LOOPBACK_DEV_NAME="spi_loop"
CONFIG_RT_UTEST_SPI_LOOPBACK_DATA_SIZE=512
CONFIG_RT_UTEST_SPI_LOOPBACK_MAX_HZ=10000000
# CONFIG_RT_UTEST_SPI_LOOPBACK_API_SMOKE is not set
CONFIG_RT_UTEST_SPI_LOOPBACK_TIMEOUT=60
# CONFIG_RT_UTEST_SPI_FLASH is not set
# end of RT-Thread Utestcases

#
Expand Down
15 changes: 15 additions & 0 deletions bsp/qemu-vexpress-a9/rtconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,21 @@
#define RT_USING_PIN
/* end of Device Drivers */

/* Utilities */

#define RT_USING_UTESTCASES
#define RT_USING_UTEST
#define UTEST_THR_STACK_SIZE 8192
#define UTEST_THR_PRIORITY 20
#define RT_UTEST_MAX_OPTIONS 64
#define RT_UTEST_SPI_LOOPBACK
#define RT_UTEST_SPI_LOOPBACK_BUS_NAME "spi2"
#define RT_UTEST_SPI_LOOPBACK_DEV_NAME "spi_loop"
#define RT_UTEST_SPI_LOOPBACK_DATA_SIZE 512
#define RT_UTEST_SPI_LOOPBACK_MAX_HZ 10000000
#define RT_UTEST_SPI_LOOPBACK_TIMEOUT 60
/* end of Utilities */

/* C/C++ and POSIX layer */

/* ISO-ANSI C layer */
Expand Down
3 changes: 3 additions & 0 deletions components/drivers/spi/utest/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ if RT_UTEST_SPI_LOOPBACK
config RT_UTEST_SPI_LOOPBACK_BUS_NAME
string "SPI bus name for loopback test"
default "spi2"
help
On BSPs without a real SPI controller (e.g. qemu-vexpress-a9) the
virtual loopback bus "spi2" is registered by spi_virt_bus.c.

config RT_UTEST_SPI_LOOPBACK_DEV_NAME
string "Temporary SPI device name for loopback test"
Expand Down
5 changes: 3 additions & 2 deletions components/drivers/spi/utest/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ from building import *

cwd = GetCurrentDir()
src = []
CPPPATH = [cwd, cwd + '/..', cwd + '/../sfud/inc']
CPPPATH = [cwd, cwd + '/..', cwd + '/../../include', cwd + '/../sfud/inc',
cwd + '/../../../utilities/utest']

if GetDepend(['RT_UTEST_SPI_LOOPBACK']):
src += ['spi_loopback_tc.c']
src += ['spi_loopback_tc.c', 'spi_virt_bus.c']

if GetDepend(['RT_UTEST_SPI_FLASH']):
src += ['spi_flash_tc.c']
Expand Down
92 changes: 92 additions & 0 deletions components/drivers/spi/utest/spi_virt_bus.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2006-2026, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2026-11-02 add SPI virtual loopback bus for utest
*
* A pure-software SPI bus that feeds MOSI data back to MISO. It lets the
* SPI loopback utest run on BSPs (such as qemu-vexpress-a9) which have no
* real SPI controller wired to external pins.
*/

#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <drivers/dev_spi.h>

#ifdef RT_UTEST_SPI_LOOPBACK

#ifndef RT_UTEST_SPI_LOOPBACK_BUS_NAME
#define RT_UTEST_SPI_LOOPBACK_BUS_NAME "spi2"
#endif

#define SPI_VIRT_BUS_NAME RT_UTEST_SPI_LOOPBACK_BUS_NAME
#define SPI_VIRT_BUS_MAX_HZ 10000000
#define SPI_VIRT_BUS_DEFAULT_HZ 1000000

static struct rt_spi_bus spi_virt_bus;

static rt_err_t spi_virt_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
{
if (configuration->max_hz == 0)
{
configuration->max_hz = SPI_VIRT_BUS_DEFAULT_HZ;
}

if (configuration->max_hz > SPI_VIRT_BUS_MAX_HZ)
{
configuration->max_hz = SPI_VIRT_BUS_MAX_HZ;
}

device->config = *configuration;
device->config.usage_freq = configuration->max_hz;

return RT_EOK;
}

static rt_ssize_t spi_virt_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
rt_size_t i;

if (message == RT_NULL)
{
return 0;
}

if (message->send_buf != RT_NULL && message->recv_buf != RT_NULL)
{
rt_memcpy(message->recv_buf, message->send_buf, message->length);
}
else if (message->send_buf != RT_NULL)
{
/* TX-only: drop the data, nothing to verify. */
}
else if (message->recv_buf != RT_NULL)
{
/* RX-only: fill with a deterministic pattern. */
rt_uint8_t *rx = (rt_uint8_t *)message->recv_buf;

for (i = 0; i < message->length; i++)
{
rx[i] = (rt_uint8_t)(0xA5 + i);
}
}

return (rt_ssize_t)message->length;
}

static const struct rt_spi_ops spi_virt_ops = {
.configure = spi_virt_configure,
.xfer = spi_virt_xfer,
};

static int spi_virt_bus_init(void)
{
return rt_spi_bus_register(&spi_virt_bus, SPI_VIRT_BUS_NAME, &spi_virt_ops);
}
INIT_BOARD_EXPORT(spi_virt_bus_init);

#endif /* RT_UTEST_SPI_LOOPBACK */
Loading