Skip to content
Merged
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
5 changes: 5 additions & 0 deletions components/drivers/include/drivers/dev_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -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;
};

Expand Down
4 changes: 4 additions & 0 deletions components/drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 59 additions & 15 deletions components/drivers/spi/dev_spi_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion components/drivers/spi/dev_spi_flash.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* 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__
Expand All @@ -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;
};

Expand Down
40 changes: 37 additions & 3 deletions components/drivers/spi/dev_spi_flash_sfud.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand Down