summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/drivers/include/drivers/dev_spi.h5
-rw-r--r--components/drivers/spi/Kconfig4
-rw-r--r--components/drivers/spi/dev_spi_core.c74
-rw-r--r--components/drivers/spi/dev_spi_flash.h7
-rw-r--r--components/drivers/spi/dev_spi_flash_sfud.c40
5 files changed, 111 insertions, 19 deletions
diff --git a/components/drivers/include/drivers/dev_spi.h b/components/drivers/include/drivers/dev_spi.h
index 195ba4b6ee..4a0ac92c88 100644
--- a/components/drivers/include/drivers/dev_spi.h
+++ b/components/drivers/include/drivers/dev_spi.h
@@ -8,6 +8,7 @@
* 2012-11-23 Bernard Add extern "C"
* 2020-06-13 armink fix the 3 wires issue
* 2022-09-01 liYony fix api rt_spi_sendrecv16 about MSB and LSB bug
+ * 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
*/
#ifndef __DEV_SPI_H__
@@ -181,6 +182,10 @@ struct rt_spi_bus
#endif /* RT_USING_DM */
struct rt_mutex lock;
+#ifdef RT_USING_SPI_ISR
+ rt_base_t _isr_lvl;
+ struct rt_spinlock _spinlock;
+#endif /* RT_USING_SPI_ISR */
struct rt_spi_device *owner;
};
diff --git a/components/drivers/spi/Kconfig b/components/drivers/spi/Kconfig
index 4a61ee8a8f..37a6a9b943 100644
--- a/components/drivers/spi/Kconfig
+++ b/components/drivers/spi/Kconfig
@@ -4,6 +4,10 @@ menuconfig RT_USING_SPI
if RT_USING_SPI
+ menuconfig RT_USING_SPI_ISR
+ bool "Enable interrupt-safe SPI operations (using spinlocks in ISR context)"
+ default y
+
menuconfig RT_USING_SOFT_SPI
bool "Use GPIO to simulate SPI"
default n
diff --git a/components/drivers/spi/dev_spi_core.c b/components/drivers/spi/dev_spi_core.c
index 42f829447a..c9fed8ef8a 100644
--- a/components/drivers/spi/dev_spi_core.c
+++ b/components/drivers/spi/dev_spi_core.c
@@ -11,6 +11,7 @@
* 2012-05-18 bernard Changed SPI message to message list.
* Added take/release SPI device/bus interface.
* 2012-09-28 aozima fixed rt_spi_release_bus assert error.
+ * 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
*/
#include "drivers/dev_spi.h"
@@ -38,6 +39,9 @@ rt_err_t spi_bus_register(struct rt_spi_bus *bus,
/* initialize mutex lock */
rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_PRIO);
+#ifdef RT_USING_SPI_ISR
+ rt_spin_lock_init(&bus->_spinlock);
+#endif /* RT_USING_SPI_ISR */
/* set ops */
bus->ops = ops;
/* initialize owner */
@@ -164,13 +168,53 @@ rt_err_t rt_spi_bus_detach_device(struct rt_spi_device *device)
return rt_spi_bus_detach_device_cspin(device);
}
+static rt_err_t spi_lock(struct rt_spi_bus *bus)
+{
+ RT_ASSERT(bus);
+
+ rt_err_t ret = -RT_ERROR;
+ /* If the scheduler is started and in thread context */
+ if (rt_scheduler_is_available())
+ {
+ ret = rt_mutex_take(&(bus->lock), RT_WAITING_FOREVER);
+ }
+ else
+ {
+#ifdef RT_USING_SPI_ISR
+ bus->_isr_lvl = rt_spin_lock_irqsave(&bus->_spinlock);
+ ret = RT_EOK;
+#endif /* RT_USING_SPI_ISR */
+ }
+ return ret;
+}
+
+static rt_err_t spi_unlock(struct rt_spi_bus *bus)
+{
+ RT_ASSERT(bus);
+
+ rt_err_t ret = -RT_ERROR;
+ /* If the scheduler is started and in thread context */
+ if (rt_scheduler_is_available())
+ {
+ ret = rt_mutex_release(&(bus->lock));
+ }
+ else
+ {
+#ifdef RT_USING_SPI_ISR
+ rt_spin_unlock_irqrestore(&bus->_spinlock, bus->_isr_lvl);
+ ret = RT_EOK;
+#endif /* RT_USING_SPI_ISR */
+ }
+ return ret;
+}
+
rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
{
rt_err_t result = -RT_ERROR;
if (device->bus != RT_NULL)
{
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result == RT_EOK)
{
if (device->bus->owner == device)
@@ -191,7 +235,7 @@ rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
result = -RT_EBUSY;
}
/* release lock */
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
}
}
else
@@ -211,7 +255,7 @@ rt_err_t rt_spi_configure(struct rt_spi_device *device,
/* reset the CS pin */
if (device->cs_pin != PIN_NONE)
{
- rt_err_t result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ rt_err_t result = spi_lock(device->bus);
if (result == RT_EOK)
{
if (cfg->mode & RT_SPI_CS_HIGH)
@@ -222,7 +266,7 @@ rt_err_t rt_spi_configure(struct rt_spi_device *device,
{
rt_pin_write(device->cs_pin, PIN_HIGH);
}
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
}
else
{
@@ -258,7 +302,7 @@ rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result == RT_EOK)
{
if (device->bus->owner != device)
@@ -316,7 +360,7 @@ rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
}
__exit:
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
return result;
}
@@ -333,7 +377,7 @@ rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result == RT_EOK)
{
if (device->bus->owner != device)
@@ -391,7 +435,7 @@ rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
}
__exit:
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
return result;
}
@@ -407,7 +451,7 @@ rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result == RT_EOK)
{
if (device->bus->owner != device)
@@ -449,7 +493,7 @@ rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
}
__exit:
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
return result;
}
@@ -510,7 +554,7 @@ struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
if (index == RT_NULL)
return index;
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result != RT_EOK)
{
return index;
@@ -548,7 +592,7 @@ struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
__exit:
/* release bus lock */
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
return index;
}
@@ -560,7 +604,7 @@ rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
- result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
+ result = spi_lock(device->bus);
if (result != RT_EOK)
{
return -RT_EBUSY;
@@ -579,7 +623,7 @@ rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
else
{
/* configure SPI bus failed */
- rt_mutex_release(&(device->bus->lock));
+ spi_unlock(device->bus);
return result;
}
@@ -595,7 +639,7 @@ rt_err_t rt_spi_release_bus(struct rt_spi_device *device)
RT_ASSERT(device->bus->owner == device);
/* release lock */
- return rt_mutex_release(&(device->bus->lock));
+ return spi_unlock(device->bus);
}
rt_err_t rt_spi_take(struct rt_spi_device *device)
diff --git a/components/drivers/spi/dev_spi_flash.h b/components/drivers/spi/dev_spi_flash.h
index 5ae54c4e2a..b7fd5bf314 100644
--- a/components/drivers/spi/dev_spi_flash.h
+++ b/components/drivers/spi/dev_spi_flash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -7,6 +7,7 @@
* Date Author Notes
* 2016/5/20 bernard the first version
* 2020/1/7 redoc add include
+ * 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
*/
#ifndef __DEV_SPI_FLASH_H__
@@ -20,6 +21,10 @@ struct spi_flash_device
struct rt_device_blk_geometry geometry;
struct rt_spi_device * rt_spi_device;
struct rt_mutex lock;
+#ifdef RT_USING_SPI_ISR
+ rt_base_t _isr_lvl;
+ struct rt_spinlock _spinlock;
+#endif /* RT_USING_SPI_ISR */
void * user_data;
};
diff --git a/components/drivers/spi/dev_spi_flash_sfud.c b/components/drivers/spi/dev_spi_flash_sfud.c
index e24002e639..7efb6e594b 100644
--- a/components/drivers/spi/dev_spi_flash_sfud.c
+++ b/components/drivers/spi/dev_spi_flash_sfud.c
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2016-09-28 armink first version.
+ * 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
*/
#include <stdint.h>
@@ -233,7 +234,17 @@ static void spi_lock(const sfud_spi *spi) {
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
- rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
+ /* If the scheduler is started and in thread context */
+ if (rt_scheduler_is_available())
+ {
+ rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
+ }
+ else
+ {
+#ifdef RT_USING_SPI_ISR
+ rtt_dev->_isr_lvl = rt_spin_lock_irqsave(&rtt_dev->_spinlock);
+#endif /* RT_USING_SPI_ISR */
+ }
}
static void spi_unlock(const sfud_spi *spi) {
@@ -244,12 +255,32 @@ static void spi_unlock(const sfud_spi *spi) {
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
- rt_mutex_release(&(rtt_dev->lock));
+ /* If the scheduler is started and in thread context */
+ if (rt_scheduler_is_available())
+ {
+ rt_mutex_release(&(rtt_dev->lock));
+ }
+ else
+ {
+#ifdef RT_USING_SPI_ISR
+ rt_spin_unlock_irqrestore(&rtt_dev->_spinlock, rtt_dev->_isr_lvl);
+#endif /* RT_USING_SPI_ISR */
+ }
}
static void retry_delay_100us(void) {
/* 100 microsecond delay */
- rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
+ if (rt_scheduler_is_available())
+ {
+ rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
+ }
+ else
+ {
+#ifdef RT_USING_SPI_ISR
+ extern void rt_hw_us_delay(rt_uint32_t us);
+ rt_hw_us_delay(100);
+#endif /* RT_USING_SPI_ISR */
+ }
}
sfud_err sfud_spi_port_init(sfud_flash *flash) {
@@ -320,6 +351,9 @@ rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, con
if (rtt_dev) {
rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
/* initialize lock */
+#ifdef RT_USING_SPI_ISR
+ rt_spin_lock_init(&rtt_dev->_spinlock);
+#endif /* RT_USING_SPI_ISR */
rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
}