-
Notifications
You must be signed in to change notification settings - Fork 3k
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
SPI upgrade - per-peripheral mutex and GPIO-based SSEL #9469
Conversation
First draft - just for discussion and @jarlamsa to try out at the minute, really. |
0fae068
to
ae6feea
Compare
You probably wanted to use the member access through pointer operator with the access to the transaction_buffer. |
drivers/SPI.cpp
Outdated
@@ -167,7 +236,7 @@ void SPI::abort_transfer() | |||
void SPI::clear_transfer_buffer() | |||
{ | |||
#if TRANSACTION_QUEUE_SIZE_SPI | |||
_transaction_buffer.reset(); | |||
_peripheral->transaction_buffer.reset(); |
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.
transaction_buffer->reset
drivers/SPI.cpp
Outdated
@@ -199,12 +268,12 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i | |||
t.callback = callback; | |||
t.width = bit_width; | |||
Transaction<SPI> transaction(this, t); | |||
if (_transaction_buffer.full()) { | |||
if (_peripheral->transaction_buffer.full()) { |
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.
transaction_buffer->full
drivers/SPI.cpp
Outdated
return -1; // the buffer is full | ||
} else { | ||
core_util_critical_section_enter(); | ||
_transaction_buffer.push(transaction); | ||
if (!spi_active(&_spi)) { | ||
_peripheral->transaction_buffer.push(transaction); |
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.
transaction_buffer->push
drivers/SPI.cpp
Outdated
@@ -250,7 +320,7 @@ void SPI::start_transaction(transaction_t *data) | |||
void SPI::dequeue_transaction() | |||
{ | |||
Transaction<SPI> t; | |||
if (_transaction_buffer.pop(t)) { | |||
if (_peripheral->transaction_buffer.pop(t)) { |
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.
transaction_buffer->pop
Otherwise seems to be working without issues on NUCLEO_F429ZI when made changes to stm_spi_api.c and TARGET_STM32F4/TARGET_STM32F429xI/TARGET_NUCLEO_F429ZI/PeripheralNames.h Do we bring the HAL-changes in with this PR or in a separate PR? |
Won't this change collide with the work done on branch feature-hal-spec-spi ? Wouldn't it be better to keep the status quo until the feature gets actually merged into master ? |
Yes, it collides, and the feature branch will need to be rebased and aligned with this :/ The problem is that this feature is required for 5.12, but your feature branch isn't due to land for 5.12. The system-wide mutex is a blocker for @jarlamsa's project - SD card accesses break the radio driver. |
@bulislaw @ARMmbed/mbed-os-maintainers Fyi ^^^ |
Will like to see at least some test code to verify the changes in this PR |
I'm not sure what the current SPI test infrastructure consists of. I see #7976 in progress for specific testing, but that's part of the pending feature branch, and it's testing the HAL, not For the new select/deselect functionality, bringing it into use by SD drivers and 802.15.4 radio drivers would get that exercised by their test suites. (I've asked @jarlamsa to look at that - would simplify their code and offset code size increase here). |
9fd003e
to
c60000f
Compare
@ithinuel - new commit reworks the peripheral blocks to make them allocated on-demand from the heap. This optimises RAM usage for the typical "SPI peripherals in use much fewer than those available in hardware" case. I think that's the least worst option, having considered the "static array of spi peripheral count" and "put 1 peripheral object inside each SPI object" options. The last would have been cunning, and optimal for the typical "1 device per peripheral" case, but I couldn't figure out how to hand over correctly and safely when an SPI object was deleted. Does eliminate the need for |
Requires fix in #9580. |
CI restarted |
Test run: FAILEDSummary: 1 of 9 test jobs failed Failed test jobs:
|
Some targets report |
This commit takes some of the work done on the SPI class from ARMmbed#8445, and refines it, to provide the per-peripheral mutex functionality. This also implements GPIO-based SSEL, which exposes a new select()/deselect() API for users to group transfers, and should work on every platform (unlike the HAL-based SSEL). This requires users to use a new constructor to avoid backwards compatibility issues. To activate the per-peripheral mutex, the HAL must define SPI_COUNT and provide spi_get_peripheral_name(). (In ARMmbed#8445 this is a reworked spi_get_module, but the name is changed here to avoid a collision with existing HALs - this commit is designed to work without wider HAL changes). Fixes: ARMmbed#9149
SPIFBlockDevice was using SingletonPtr without an include, and only getting it via SPI.h. Spotted while changing SPI to not use SingletonPtr - now abandoned, but still this shouldn't have been relying on it.
Avoid collision with some HALs that already define SPI_COUNT.
Some HALs had their own existing Rebased. |
CI restarted |
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.
Aside from the two "style" comment, LGTM
void SPI::select() | ||
{ | ||
lock(); | ||
if (_select_count++ == 0) { |
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.
This is just a matter of coding style, but for clarity, could this increment be done after the if ?
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.
I think I did that quite deliberately because a couple of days before writing it I saw some existing code containing this:
core_util_atomic_incr_u32(foo, 1);
if (foo == 1) {
which is not thread-safe, and needs to be
if (core_util_atomic_incr_u32(foo, 1) == 1) {
I think if people can't get comfortable with the increment/decrement pattern, it just encourages that sort of mistake. (Although breaking it up doesn't hurt in this case, as we are in a lock).
|
||
void SPI::deselect() | ||
{ | ||
if (--_select_count == 0) { |
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.
Like in the previous commend, could this decrement be done before the if to avoid any confusion ?
Test run: FAILEDSummary: 1 of 14 test jobs failed Failed test jobs:
|
@ithinuel Happy with this PR? |
@0xc0170 This broke SPI for Silicon Labs targets, as we currently don't allow instantiating NC pins and the new constructor does exactly that. How was this PR tested? |
Expected behaviour is that targets should permit This isn't explicitly documented, as far as I can see, but is implied by the existence of
The PR would have been tested on whichever devices we have present and operational in CI - but as I believe we don't have any sort of universal SPI test rigs it would have been exercised in devices using 802.15.4 radio modules and the like, and I guess Silicon Labs targets would not have been represented. The Silicon Labs targets should be updated to permit NC GPIO initialisation - I would suggest removing the assert from |
@kjbracey-arm The other issue is targets using asynchronous SPI. the irq_handler is called from IRQ context, and this PR changed the transaction buffer to be a singletonPtr, see https://github.com/ARMmbed/mbed-os/pull/9469/files#diff-ade6379acb4d9069bc0cc21788bb6883R359 Inside the IRQ handler, dequeue_transaction can be called, which in turn tries to dequeue from the transaction buffer. This will cause failure, since the transaction buffer now needs to lock a mutex to get to the singletonPtr. That evidently won't work from IRQ context... |
SingletonPtr's mutex lock only occurs on first use, so AFAICT there would only be an issue if the very first asynchronous transaction was started directly from an interrupt handler. Are you doing that? I guess we could prime the transaction buffer in the constructor to help that case - a call to its |
Priming would be helpful. |
The fact that async calls can be initiated from interrupt does illustrate a (pre-existing) design problem - the mutex locks for the peripheral are being bypassed, which means it won't work correctly in any sort of environment where there are multiple users sharing one SPI peripheral. We do need to pin down exactly what the rules about async use are - I believe the guys working on the SPI HAL upgrade feature branch have been looking at this. Still, for the current environment where asynch is historically lockless, it would make sense to prime it so it continues to work in that scenario. I'll make a patch for that. Will cost a bit of ROM space pulling in the init code for unused asynch, but not a lot. |
Thanks @stevew817 for getting back to us with these issues |
Description
This commit takes some of the work done on the SPI class from #8445, and refines it, to provide the per-peripheral mutex functionality.
This also implements GPIO-based SSEL, which exposes a new
select()/deselect()
API for users to group transfers, and should work on every platform (unlike the HAL-based SSEL). This requires users to use a new constructor to avoid backwards compatibility issues.To activate the per-peripheral mutex, the HAL must define
SPI_COUNT
and providespi_get_peripheral_name()
. (In #8445 this is a reworkedspi_get_module
, but the name is changed here to avoid a collision with existing HALs - this commit is designed to work without wider HAL changes).Fixes: #9149
Pull request type
Reviewers
@jarlamsa, @c1728p9, @ithinuel