Skip to content

Commit cfe15d8

Browse files
committed
feat[spi]: enable interrupt-safe operations using spinlocks
1 parent ba509f9 commit cfe15d8

File tree

5 files changed

+110
-18
lines changed

5 files changed

+110
-18
lines changed

components/drivers/include/drivers/dev_spi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* 2012-11-23 Bernard Add extern "C"
99
* 2020-06-13 armink fix the 3 wires issue
1010
* 2022-09-01 liYony fix api rt_spi_sendrecv16 about MSB and LSB bug
11+
* 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
1112
*/
1213

1314
#ifndef __DEV_SPI_H__
@@ -181,6 +182,10 @@ struct rt_spi_bus
181182
#endif /* RT_USING_DM */
182183

183184
struct rt_mutex lock;
185+
#ifdef RT_USING_SPI_ISR
186+
rt_base_t _isr_lvl;
187+
struct rt_spinlock _spinlock;
188+
#endif /* RT_USING_SPI_ISR */
184189
struct rt_spi_device *owner;
185190
};
186191

components/drivers/spi/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ menuconfig RT_USING_SPI
44

55
if RT_USING_SPI
66

7+
menuconfig RT_USING_SPI_ISR
8+
bool "Enable ISR SPI"
9+
default y
10+
711
menuconfig RT_USING_SOFT_SPI
812
bool "Use GPIO to simulate SPI"
913
default n

components/drivers/spi/dev_spi_core.c

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* 2012-05-18 bernard Changed SPI message to message list.
1212
* Added take/release SPI device/bus interface.
1313
* 2012-09-28 aozima fixed rt_spi_release_bus assert error.
14+
* 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
1415
*/
1516

1617
#include "drivers/dev_spi.h"
@@ -38,6 +39,9 @@ rt_err_t spi_bus_register(struct rt_spi_bus *bus,
3839

3940
/* initialize mutex lock */
4041
rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_PRIO);
42+
#ifdef RT_USING_SPI_ISR
43+
rt_spin_lock_init(&bus->_spinlock);
44+
#endif /* RT_USING_SPI_ISR */
4145
/* set ops */
4246
bus->ops = ops;
4347
/* initialize owner */
@@ -164,13 +168,53 @@ rt_err_t rt_spi_bus_detach_device(struct rt_spi_device *device)
164168
return rt_spi_bus_detach_device_cspin(device);
165169
}
166170

171+
static rt_err_t spi_lock(struct rt_spi_bus *bus)
172+
{
173+
RT_ASSERT(bus);
174+
175+
rt_err_t ret = -RT_ERROR;
176+
/* If the scheduler is started and in thread context */
177+
if (rt_scheduler_is_available())
178+
{
179+
ret = rt_mutex_take(&(bus->lock), RT_WAITING_FOREVER);
180+
}
181+
else
182+
{
183+
#ifdef RT_USING_SPI_ISR
184+
bus->_isr_lvl = rt_spin_lock_irqsave(&bus->_spinlock);
185+
ret = RT_EOK;
186+
#endif /* RT_USING_SPI_ISR */
187+
}
188+
return ret;
189+
}
190+
191+
static rt_err_t spi_unlock(struct rt_spi_bus *bus)
192+
{
193+
RT_ASSERT(bus);
194+
195+
rt_err_t ret = -RT_ERROR;
196+
/* If the scheduler is started and in thread context */
197+
if (rt_scheduler_is_available())
198+
{
199+
ret = rt_mutex_release(&(bus->lock));
200+
}
201+
else
202+
{
203+
#ifdef RT_USING_SPI_ISR
204+
rt_spin_unlock_irqrestore(&bus->_spinlock, bus->_isr_lvl);
205+
ret = RT_EOK;
206+
#endif /* RT_USING_SPI_ISR */
207+
}
208+
return ret;
209+
}
210+
167211
rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
168212
{
169213
rt_err_t result = -RT_ERROR;
170214

171215
if (device->bus != RT_NULL)
172216
{
173-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
217+
result = spi_lock(device->bus);
174218
if (result == RT_EOK)
175219
{
176220
if (device->bus->owner == device)
@@ -191,7 +235,7 @@ rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
191235
result = -RT_EBUSY;
192236
}
193237
/* release lock */
194-
rt_mutex_release(&(device->bus->lock));
238+
spi_unlock(device->bus);
195239
}
196240
}
197241
else
@@ -211,7 +255,7 @@ rt_err_t rt_spi_configure(struct rt_spi_device *device,
211255
/* reset the CS pin */
212256
if (device->cs_pin != PIN_NONE)
213257
{
214-
rt_err_t result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
258+
rt_err_t result = spi_lock(device->bus);
215259
if (result == RT_EOK)
216260
{
217261
if (cfg->mode & RT_SPI_CS_HIGH)
@@ -222,7 +266,7 @@ rt_err_t rt_spi_configure(struct rt_spi_device *device,
222266
{
223267
rt_pin_write(device->cs_pin, PIN_HIGH);
224268
}
225-
rt_mutex_release(&(device->bus->lock));
269+
spi_unlock(device->bus);
226270
}
227271
else
228272
{
@@ -258,7 +302,7 @@ rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
258302
RT_ASSERT(device != RT_NULL);
259303
RT_ASSERT(device->bus != RT_NULL);
260304

261-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
305+
result = spi_lock(device->bus);
262306
if (result == RT_EOK)
263307
{
264308
if (device->bus->owner != device)
@@ -316,7 +360,7 @@ rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
316360
}
317361

318362
__exit:
319-
rt_mutex_release(&(device->bus->lock));
363+
spi_unlock(device->bus);
320364

321365
return result;
322366
}
@@ -333,7 +377,7 @@ rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
333377
RT_ASSERT(device != RT_NULL);
334378
RT_ASSERT(device->bus != RT_NULL);
335379

336-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
380+
result = spi_lock(device->bus);
337381
if (result == RT_EOK)
338382
{
339383
if (device->bus->owner != device)
@@ -391,7 +435,7 @@ rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
391435
}
392436

393437
__exit:
394-
rt_mutex_release(&(device->bus->lock));
438+
spi_unlock(device->bus);
395439

396440
return result;
397441
}
@@ -407,7 +451,7 @@ rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
407451
RT_ASSERT(device != RT_NULL);
408452
RT_ASSERT(device->bus != RT_NULL);
409453

410-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
454+
result = spi_lock(device->bus);
411455
if (result == RT_EOK)
412456
{
413457
if (device->bus->owner != device)
@@ -449,7 +493,7 @@ rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
449493
}
450494

451495
__exit:
452-
rt_mutex_release(&(device->bus->lock));
496+
spi_unlock(device->bus);
453497

454498
return result;
455499
}
@@ -510,7 +554,7 @@ struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
510554
if (index == RT_NULL)
511555
return index;
512556

513-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
557+
result = spi_lock(device->bus);
514558
if (result != RT_EOK)
515559
{
516560
return index;
@@ -548,7 +592,7 @@ struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
548592

549593
__exit:
550594
/* release bus lock */
551-
rt_mutex_release(&(device->bus->lock));
595+
spi_unlock(device->bus);
552596

553597
return index;
554598
}
@@ -560,7 +604,7 @@ rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
560604
RT_ASSERT(device != RT_NULL);
561605
RT_ASSERT(device->bus != RT_NULL);
562606

563-
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
607+
result = spi_lock(device->bus);
564608
if (result != RT_EOK)
565609
{
566610
return -RT_EBUSY;
@@ -579,7 +623,7 @@ rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
579623
else
580624
{
581625
/* configure SPI bus failed */
582-
rt_mutex_release(&(device->bus->lock));
626+
spi_unlock(device->bus);
583627

584628
return result;
585629
}
@@ -595,7 +639,7 @@ rt_err_t rt_spi_release_bus(struct rt_spi_device *device)
595639
RT_ASSERT(device->bus->owner == device);
596640

597641
/* release lock */
598-
return rt_mutex_release(&(device->bus->lock));
642+
return spi_unlock(device->bus);
599643
}
600644

601645
rt_err_t rt_spi_take(struct rt_spi_device *device)

components/drivers/spi/dev_spi_flash.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Date Author Notes
88
* 2016/5/20 bernard the first version
99
* 2020/1/7 redoc add include
10+
* 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
1011
*/
1112

1213
#ifndef __DEV_SPI_FLASH_H__
@@ -20,6 +21,10 @@ struct spi_flash_device
2021
struct rt_device_blk_geometry geometry;
2122
struct rt_spi_device * rt_spi_device;
2223
struct rt_mutex lock;
24+
#ifdef RT_USING_SPI_ISR
25+
rt_base_t _isr_lvl;
26+
struct rt_spinlock _spinlock;
27+
#endif /* RT_USING_SPI_ISR */
2328
void * user_data;
2429
};
2530

components/drivers/spi/dev_spi_flash_sfud.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Change Logs:
77
* Date Author Notes
88
* 2016-09-28 armink first version.
9+
* 2025-10-30 wdfk-prog enable interrupt-safe operations using spinlocks
910
*/
1011

1112
#include <stdint.h>
@@ -233,7 +234,17 @@ static void spi_lock(const sfud_spi *spi) {
233234
RT_ASSERT(sfud_dev);
234235
RT_ASSERT(rtt_dev);
235236

236-
rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
237+
/* If the scheduler is started and in thread context */
238+
if (rt_scheduler_is_available())
239+
{
240+
rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
241+
}
242+
else
243+
{
244+
#ifdef RT_USING_SPI_ISR
245+
rtt_dev->_isr_lvl = rt_spin_lock_irqsave(&rtt_dev->_spinlock);
246+
#endif /* RT_USING_SPI_ISR */
247+
}
237248
}
238249

239250
static void spi_unlock(const sfud_spi *spi) {
@@ -244,12 +255,32 @@ static void spi_unlock(const sfud_spi *spi) {
244255
RT_ASSERT(sfud_dev);
245256
RT_ASSERT(rtt_dev);
246257

247-
rt_mutex_release(&(rtt_dev->lock));
258+
/* If the scheduler is started and in thread context */
259+
if (rt_scheduler_is_available())
260+
{
261+
rt_mutex_release(&(rtt_dev->lock));
262+
}
263+
else
264+
{
265+
#ifdef RT_USING_SPI_ISR
266+
rt_spin_unlock_irqrestore(&rtt_dev->_spinlock, rtt_dev->_isr_lvl);
267+
#endif /* RT_USING_SPI_ISR */
268+
}
248269
}
249270

250271
static void retry_delay_100us(void) {
251272
/* 100 microsecond delay */
252-
rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
273+
if (rt_scheduler_is_available())
274+
{
275+
rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
276+
}
277+
else
278+
{
279+
#ifdef RT_USING_SPI_ISR
280+
extern void rt_hw_us_delay(rt_uint32_t us);
281+
rt_hw_us_delay(100);
282+
#endif /* RT_USING_SPI_ISR */
283+
}
253284
}
254285

255286
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
320351
if (rtt_dev) {
321352
rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
322353
/* initialize lock */
354+
#ifdef RT_USING_SPI_ISR
355+
rt_spin_lock_init(&rtt_dev->_spinlock);
356+
#endif /* RT_USING_SPI_ISR */
323357
rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
324358
}
325359

0 commit comments

Comments
 (0)