Skip to content
Open
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 ISR SPI"
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English: The configuration option description "Enable ISR SPI" is too brief and unclear. It should clearly explain the feature's purpose and implications. Consider: "Enable interrupt-safe SPI operations (using spinlocks in ISR context)".
中文:配置选项描述 "Enable ISR SPI" 过于简短且不清晰。应明确说明功能目的和影响。建议改为:"Enable interrupt-safe SPI operations (using spinlocks in ISR context)"(启用中断安全的SPI操作,在中断上下文中使用自旋锁)。

Suggested change
bool "Enable ISR SPI"
bool "Enable interrupt-safe SPI operations (using spinlocks in ISR context)"

Copilot uses AI. Check for mistakes.
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;
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English: When RT_USING_SPI_ISR is not defined and the scheduler is unavailable (line 181-187), the function returns -RT_ERROR without taking any lock. This creates an inconsistent lock state and will cause the corresponding spi_unlock() to fail or behave incorrectly. Either return an error to prevent the operation, or implement a fallback locking mechanism.
中文:当 RT_USING_SPI_ISR 未定义且调度器不可用时(181-187行),函数返回 -RT_ERROR 而未获取任何锁。这会导致锁状态不一致,并使对应的 spi_unlock() 失败或行为异常。应返回错误以阻止操作,或实现回退锁机制。

Copilot uses AI. Check for mistakes.
/* 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
5 changes: 5 additions & 0 deletions components/drivers/spi/dev_spi_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
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
Loading