mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-12-16 03:34:24 +08:00
feat[spi]: enable interrupt-safe operations using spinlocks
This commit is contained in:
@@ -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,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user