From 88290ac3e51e7ea2c832ae82a882c0f17d334398 Mon Sep 17 00:00:00 2001 From: Jianhua Liu Date: Tue, 12 May 2026 17:32:52 +0800 Subject: [PATCH] [drv][ns800]: add SPI driver support for NS800RT7P65X Add SPI bus driver for NS800 series BSP based on RT-Thread SPI framework. This driver supports SPI1~SPI4 peripherals with polled transfer mode. Features: - GPIO initialization for SCK/MOSI/MISO pins - SPI mode 0~3 configuration (CPOL/CPHA) - 8-bit and 16-bit data width support - Master mode full-duplex communication - Internal loopback test support Co-Authored-By: liujianghua --- .../libraries/HAL_Drivers/drivers/SConscript | 3 + .../libraries/HAL_Drivers/drivers/drv_spi.c | 327 ++++++++++++++++++ .../libraries/HAL_Drivers/drivers/drv_spi.h | 49 +++ .../ns800rt7p65-nssinepad/applications/main.c | 72 ++++ .../ns800/ns800rt7p65-nssinepad/board/Kconfig | 22 ++ .../ns800/ns800rt7p65-nssinepad/rtconfig.h | 12 +- 6 files changed, 481 insertions(+), 4 deletions(-) create mode 100644 bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.c create mode 100644 bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.h diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript index 6f2f6c5427..65981919ee 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript @@ -19,6 +19,9 @@ if GetDepend('BSP_USING_CAN'): if GetDepend('BSP_USING_ECAP'): src += ['drv_ecap.c'] +if GetDepend('BSP_USING_SPI'): + src += ['drv_spi.c'] + group = DefineGroup('HAL_Drivers', src, depend = [''], CPPPATH = path) Return('group') diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.c b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.c new file mode 100644 index 0000000000..6aec6e3488 --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-05-12 Codex first version + */ + +#include "board.h" +#include "drv_spi.h" +#include "drv_config.h" + +#ifdef RT_USING_SPI + +#define DRV_DEBUG +#define LOG_TAG "drv.spi" +#include + +#if !defined(BSP_USING_SPI1) && !defined(BSP_USING_SPI2) && !defined(BSP_USING_SPI3) && \ + !defined(BSP_USING_SPI4) +#error "Please define at least one BSP_USING_SPIx" +#endif + +enum +{ +#ifdef BSP_USING_SPI1 + SPI1_INDEX, +#endif +#ifdef BSP_USING_SPI2 + SPI2_INDEX, +#endif +#ifdef BSP_USING_SPI3 + SPI3_INDEX, +#endif +#ifdef BSP_USING_SPI4 + SPI4_INDEX, +#endif +}; + +static struct ns800_spi_config spi_config[] = +{ +#ifdef BSP_USING_SPI1 + { + .name = "spi1", + .Instance = SPI1, + .rx_irq_type = SPI1_RX_IRQn, + .tx_irq_type = SPI1_TX_IRQn, + .sck_port = GPIOA, + .sck_pin = GPIO_PIN_18, + .sck_mux = ALT1_FUNCTION, + .mosi_port = GPIOA, + .mosi_pin = GPIO_PIN_16, + .mosi_mux = ALT1_FUNCTION, + .miso_port = GPIOA, + .miso_pin = GPIO_PIN_17, + .miso_mux = ALT1_FUNCTION, + }, +#endif +#ifdef BSP_USING_SPI2 + { + .name = "spi2", + .Instance = SPI2, + .rx_irq_type = SPI2_RX_IRQn, + .tx_irq_type = SPI2_TX_IRQn, + .sck_port = GPIOB, + .sck_pin = GPIO_PIN_0, + .sck_mux = ALT9_FUNCTION, + .mosi_port = GPIOB, + .mosi_pin = GPIO_PIN_1, + .mosi_mux = ALT9_FUNCTION, + .miso_port = GPIOB, + .miso_pin = GPIO_PIN_2, + .miso_mux = ALT9_FUNCTION, + }, +#endif +#ifdef BSP_USING_SPI3 + { + .name = "spi3", + .Instance = SPI3, + .rx_irq_type = SPI3_RX_IRQn, + .tx_irq_type = SPI3_TX_IRQn, + .sck_port = GPIOC, + .sck_pin = GPIO_PIN_0, + .sck_mux = ALT7_FUNCTION, + .mosi_port = GPIOC, + .mosi_pin = GPIO_PIN_1, + .mosi_mux = ALT7_FUNCTION, + .miso_port = GPIOC, + .miso_pin = GPIO_PIN_2, + .miso_mux = ALT7_FUNCTION, + }, +#endif +#ifdef BSP_USING_SPI4 + { + .name = "spi4", + .Instance = SPI4, + .rx_irq_type = SPI4_RX_IRQn, + .tx_irq_type = SPI4_TX_IRQn, + .sck_port = GPIOC, + .sck_pin = GPIO_PIN_4, + .sck_mux = ALT7_FUNCTION, + .mosi_port = GPIOC, + .mosi_pin = GPIO_PIN_5, + .mosi_mux = ALT7_FUNCTION, + .miso_port = GPIOC, + .miso_pin = GPIO_PIN_6, + .miso_mux = ALT7_FUNCTION, + }, +#endif +}; + +static struct ns800_spi spi_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0}; + +static void ns800_spi_gpio_init(const struct ns800_spi_config *config) +{ + RT_ASSERT(config != RT_NULL); + + GPIO_setPinConfig(config->sck_port, config->sck_pin, config->sck_mux); + GPIO_setAnalogMode(config->sck_port, config->sck_pin, GPIO_ANALOG_DISABLED); + GPIO_setPadConfig(config->sck_port, config->sck_pin, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(config->sck_port, config->sck_pin, GPIO_QUAL_SYNC); + GPIO_setDirectionMode(config->sck_port, config->sck_pin, GPIO_DIR_MODE_OUT); + + GPIO_setPinConfig(config->mosi_port, config->mosi_pin, config->mosi_mux); + GPIO_setAnalogMode(config->mosi_port, config->mosi_pin, GPIO_ANALOG_DISABLED); + GPIO_setPadConfig(config->mosi_port, config->mosi_pin, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(config->mosi_port, config->mosi_pin, GPIO_QUAL_SYNC); + GPIO_setDirectionMode(config->mosi_port, config->mosi_pin, GPIO_DIR_MODE_OUT); + + GPIO_setPinConfig(config->miso_port, config->miso_pin, config->miso_mux); + GPIO_setAnalogMode(config->miso_port, config->miso_pin, GPIO_ANALOG_DISABLED); + GPIO_setPadConfig(config->miso_port, config->miso_pin, GPIO_PIN_TYPE_PULLUP); + GPIO_setQualificationMode(config->miso_port, config->miso_pin, GPIO_QUAL_SYNC); + GPIO_setDirectionMode(config->miso_port, config->miso_pin, GPIO_DIR_MODE_IN); +} + +static rt_err_t ns800_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration) +{ + struct ns800_spi *spi; + SPI_TransferProtocol protocol; + SPI_BitWidth data_width; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(configuration != RT_NULL); + + spi = rt_container_of(device->bus, struct ns800_spi, spi_bus); + + ns800_spi_gpio_init(spi->config); + + switch (configuration->mode & RT_SPI_MODE_3) + { + case RT_SPI_MODE_0: + protocol = SPI_PROT_POL0PHA0; + break; + case RT_SPI_MODE_1: + protocol = SPI_PROT_POL0PHA1; + break; + case RT_SPI_MODE_2: + protocol = SPI_PROT_POL1PHA0; + break; + case RT_SPI_MODE_3: + protocol = SPI_PROT_POL1PHA1; + break; + default: + protocol = SPI_PROT_POL0PHA0; + break; + } + + switch (configuration->data_width) + { + case 8: + data_width = SPI_BIT_WIDTH_8_BITS; + break; + case 16: + data_width = SPI_BIT_WIDTH_16_BITS; + break; + default: + data_width = SPI_BIT_WIDTH_8_BITS; + break; + } + + SPI_disableModule(spi->config->Instance); + + SPI_setConfig(spi->config->Instance, + protocol, + SPI_MASTER_MODE, + SPI_FULL_DUPLEX_COMM_MODE, + configuration->max_hz, + data_width); + + SPI_resetFifo(spi->config->Instance); + SPI_enableModule(spi->config->Instance); + + return RT_EOK; +} + +static rt_ssize_t ns800_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message) +{ + struct ns800_spi *spi; + SPI_TypeDef *instance; + const rt_uint8_t *send_buf; + rt_uint8_t *recv_buf; + rt_size_t length; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->bus != RT_NULL); + + spi = rt_container_of(device->bus, struct ns800_spi, spi_bus); + instance = spi->config->Instance; + length = message->length; + send_buf = message->send_buf; + recv_buf = message->recv_buf; + + if (message->cs_take) + { + rt_pin_write(device->cs_pin, PIN_LOW); + } + + while (length) + { + if (send_buf) + { + if (recv_buf) + { + recv_buf[0] = SPI_transmitReceive(instance, send_buf[0]); + recv_buf++; + } + else + { + SPI_transmitReceive(instance, send_buf[0]); + } + send_buf++; + } + else + { + if (recv_buf) + { + recv_buf[0] = SPI_transmitReceive(instance, 0xFF); + recv_buf++; + } + else + { + SPI_transmitReceive(instance, 0xFF); + } + } + length--; + } + + if (message->cs_release) + { + rt_pin_write(device->cs_pin, PIN_HIGH); + } + + return message->length; +} + +static const struct rt_spi_ops ns800_spi_ops = +{ + .configure = ns800_spi_configure, + .xfer = ns800_spi_xfer, +}; + +static void ns800_spi_clock_init(SPI_TypeDef *Instance) +{ +#ifdef BSP_USING_SPI1 + if (Instance == SPI1) + { + RCC_enableSpi1Clock(); + RCC_resetSpi1Module(); + RCC_releaseSpi1Module(); + } +#endif +#ifdef BSP_USING_SPI2 + if (Instance == SPI2) + { + RCC_enableSpi2Clock(); + RCC_resetSpi2Module(); + RCC_releaseSpi2Module(); + } +#endif +#ifdef BSP_USING_SPI3 + if (Instance == SPI3) + { + RCC_enableSpi3Clock(); + RCC_resetSpi3Module(); + RCC_releaseSpi3Module(); + } +#endif +#ifdef BSP_USING_SPI4 + if (Instance == SPI4) + { + RCC_enableSpi4Clock(); + RCC_resetSpi4Module(); + RCC_releaseSpi4Module(); + } +#endif +} + +int rt_hw_spi_init(void) +{ + rt_size_t i; + rt_err_t result; + + for (i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++) + { + ns800_spi_clock_init(spi_config[i].Instance); + + spi_obj[i].config = &spi_config[i]; + spi_obj[i].spi_bus.parent.user_data = &spi_config[i]; + + result = rt_spi_bus_register(&spi_obj[i].spi_bus, + spi_config[i].name, + &ns800_spi_ops); + if (result != RT_EOK) + { + LOG_E("rt_spi_bus_register(%s) failed: %d", spi_config[i].name, result); + } + } + + return RT_EOK; +} + +INIT_BOARD_EXPORT(rt_hw_spi_init); + +#endif diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.h b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.h new file mode 100644 index 0000000000..3d3badd64d --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_spi.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-05-12 Codex first version + */ + +#ifndef __DRV_SPI_H__ +#define __DRV_SPI_H__ + +#include +#include "rtdevice.h" +#include +#include + +#ifdef RT_USING_SPI + +struct ns800_spi_config +{ + const char *name; + SPI_TypeDef *Instance; + IRQn_Type rx_irq_type; + IRQn_Type tx_irq_type; + GPIO_TypeDef *sck_port; + GPIO_PinNum sck_pin; + GPIO_AltFunc sck_mux; + GPIO_TypeDef *mosi_port; + GPIO_PinNum mosi_pin; + GPIO_AltFunc mosi_mux; + GPIO_TypeDef *miso_port; + GPIO_PinNum miso_pin; + GPIO_AltFunc miso_mux; +}; + +struct ns800_spi +{ + SPI_TypeDef *Instance; + struct rt_spi_bus spi_bus; + struct ns800_spi_config *config; +}; + +int rt_hw_spi_init(void); + +#endif + +#endif /* __DRV_SPI_H__ */ diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/applications/main.c b/bsp/novosns/ns800/ns800rt7p65-nssinepad/applications/main.c index 62ab0863ff..534e1e34d0 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/applications/main.c +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/applications/main.c @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2026-05-06 Jiawei.Deng first version + * 2026-05-12 Codex add SPI loopback test */ #include @@ -15,10 +16,81 @@ /* defined the LED1 pin: GPIO_68 = PC4 */ #define LED1_PIN PIN_NUM(GPIO_68) +#ifdef BSP_USING_SPI1 +#include "spi.h" + +static struct rt_spi_device spi_dev; +static struct rt_spi_configuration cfg; + +static void spi_loopback_test(void) +{ + rt_err_t result; + rt_uint8_t send_data[4] = {0x55, 0xAA, 0x5A, 0xA5}; + rt_uint8_t recv_data[4] = {0}; + + /* Attach a SPI device to the spi1 bus */ + result = rt_spi_bus_attach_device(&spi_dev, "spi10", "spi1", RT_NULL); + if (result != RT_EOK) + { + rt_kprintf("spi loopback test: bus attach failed: %d\n", result); + return; + } + + /* Configure SPI: MODE_0, 8-bit, 1MHz */ + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; + cfg.max_hz = 1000000; + result = rt_spi_configure(&spi_dev, &cfg); + if (result != RT_EOK) + { + rt_kprintf("spi loopback test: configure failed: %d\n", result); + return; + } + + /* Enable loopback2 mode for internal loopback test */ + SPI_enableLoopback2(SPI1); + + rt_kprintf("spi loopback test: sending 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + send_data[0], send_data[1], send_data[2], send_data[3]); + + /* Perform SPI transfer in loopback mode */ + result = rt_spi_transfer(&spi_dev, send_data, recv_data, 4); + + if (result == 4) + { + rt_kprintf("spi loopback test: received 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + recv_data[0], recv_data[1], recv_data[2], recv_data[3]); + + /* Verify data matches */ + if (rt_memcmp(send_data, recv_data, 4) == 0) + { + rt_kprintf("spi loopback test: PASSED!\n"); + } + else + { + rt_kprintf("spi loopback test: FAILED - data mismatch!\n"); + } + } + else + { + rt_kprintf("spi loopback test: transfer failed: %d\n", result); + } + + /* Disable loopback mode */ + SPI_disableLoopback2(SPI1); +} +#endif + int main(void) { rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT); +#ifdef BSP_USING_SPI1 + /* Run SPI loopback test after short delay */ + rt_thread_mdelay(500); + spi_loopback_test(); +#endif + while (1) { /* rt_kprintf("\r\n led1_thread_entry running! \r\n"); */ diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig index c4bbdf3080..db71438c7f 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig @@ -105,4 +105,26 @@ menu "On-chip Peripheral Drivers" endif + menuconfig BSP_USING_SPI + bool "Enable SPI" + select RT_USING_SPI + default n + if BSP_USING_SPI + menuconfig BSP_USING_SPI1 + bool "Enable SPI1" + default n + + menuconfig BSP_USING_SPI2 + bool "Enable SPI2" + default n + + menuconfig BSP_USING_SPI3 + bool "Enable SPI3" + default n + + menuconfig BSP_USING_SPI4 + bool "Enable SPI4" + default n + endif + endmenu diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h b/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h index 380f2986c7..acbbcc9576 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/rtconfig.h @@ -149,6 +149,8 @@ #define RT_CANSND_BOX_NUM 1 #define RT_CANSND_MSG_TIMEOUT 100 #define RT_CAN_NB_TX_FIFO_SIZE 256 +#define RT_USING_SPI +#define RT_USING_SPI_ISR #define RT_USING_PIN /* end of Device Drivers */ @@ -310,14 +312,14 @@ /* end of HC32 DDL Drivers */ -/* NXP HAL & SDK Drivers */ - -/* end of NXP HAL & SDK Drivers */ - /* NUVOTON Drivers */ /* end of NUVOTON Drivers */ +/* NXP HAL & SDK Drivers */ + +/* end of NXP HAL & SDK Drivers */ + /* GD32 Drivers */ /* end of GD32 Drivers */ @@ -424,6 +426,8 @@ #define BSP_USING_ECAP #define BSP_USING_CAN #define BSP_USING_CANFD1 +#define BSP_USING_SPI +#define BSP_USING_SPI1 /* end of On-chip Peripheral Drivers */ #endif -- Gitee