Forráskód Böngészése

feat[spi]: enable interrupt-safe operations using spinlocks

wdfk-prog 2 hónapja
szülő
commit
ddfe2cd61c

+ 5 - 0
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;
 };
 

+ 4 - 0
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

+ 59 - 15
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)

+ 6 - 1
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;
 };
 

+ 37 - 3
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);
     }