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

This commit is contained in:
wdfk-prog
2025-11-13 11:21:49 +08:00
committed by R b b666
parent ec27e09df8
commit ddfe2cd61c
5 changed files with 111 additions and 19 deletions

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
};

View File

@@ -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);
}