-
Notifications
You must be signed in to change notification settings - Fork 5.3k
feat[spi]: enable interrupt-safe operations using spinlocks #10873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 */ | ||
wdfk-prog marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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; | ||
wdfk-prog marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /* 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) | ||
|
|
||
There was a problem hiding this comment.
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操作,在中断上下文中使用自旋锁)。