diff --git a/components/drivers/include/drivers/dev_spi.h b/components/drivers/include/drivers/dev_spi.h index 195ba4b6ee5..4a0ac92c88b 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 4a61ee8a8fc..3cbd909ddb6 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 ISR SPI" + 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 42f829447ab..c9fed8ef8ad 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 5ae54c4e2ab..6b51003d580 100644 --- a/components/drivers/spi/dev_spi_flash.h +++ b/components/drivers/spi/dev_spi_flash.h @@ -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 e7198f41a31..85c76eb80d7 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 @@ -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); }