-
Notifications
You must be signed in to change notification settings - Fork 13.6k
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: support for ISR and work_queue driven transfers #11302
Conversation
Next steps, test this with two IMUs (6500/9250) running on the same SPI bus (SPI1). Schedule one using the new |
Merged into #11261 and tested like so
This appears to be working correctly And I am seeing perf counts for deferred ISR driven transfers @dagar if you want to test it yourself |
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.
@dakejahl I am a tad bit uncomfortable with the removal of result, but I guess it can be added back if we extent the upstream nuttx SPI api.
Please verify the 2 comments raised
I removed result because |
I need to do one more test on this Monday, I had left out applying the bus number to the bitmask when checking if the bus was locked. This shouldn't have had any affect with the way the system runs currently, I just want to sanity check it. |
Okay I think this is done now. I fixed an issue where I wasn't checking the bit position in the This actually isn't relevant though because the default Bench tested on a Teal with 2 IMUs(6500/9250) on SPI1, one running from the new |
src/lib/drivers/device/nuttx/SPI.cpp
Outdated
|
||
void SPI::lock(struct spi_dev_s *dev) | ||
{ | ||
_is_locked |= (1 << _device_id.devid_s.bus); |
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.
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.
FYI once we're sure there's no longer a mix of PX4 SPI drivers running out of HRT and threads we can drop all of this and lean on the underlying nuttx SPI_LOCK (semaphore).
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.
What I meant to emphasize was that this only exists for the case of a potential HRT and thread SPI conflict.
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.
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.
Also this assumes that all SPI instances for a given bus run on the same thread.
Could you explain please? I don't think it does.
The implementation is not correct if this does not hold. This is what can go wrong:
|
…or not the given bus is locked. This is neccessary to defer ISR context SPI transfers that would otherwise stomp on an ongoing SPI transfer
…k -EINVAL. Updated file header.
Co-Authored-By: dakejahl <37091262+dakejahl@users.noreply.github.com>
0abc38c
to
b7dce1c
Compare
@bkueng Thanks for the explanation! I've updated the code. Lock free atomic operations are a new concept to me, please let me know if this doesn't look right. edit: Oh, ignore me. I need to check if the lock bit is already set before setting, otherwise it can potentially be "set" twice. |
@dakejahl @dagar - Is it true that in the end (all done), there is only 1 thread per bus and the possibility of hrt interruption.? If so:There is a 1:1 of bus:semaphore so this reduce to
So the loser is always running in interrupt context. Therefore the test does not need protection as it is non interruptible - no nesting or HI priority IRQ) So Is the problem a shared bus? Barro and Nuttx driver on same bus? |
I believe the only reason that wasn't done is accessing the somewhat hidden spidev semaphore. |
Yeah I wasn't sure how to get at that semaphore. btw thanks everyone for reviewing, lots of little nuances I wasn't aware of with this. |
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 need to check if the lock bit is already set before setting, otherwise it can potentially be "set" twice.
That's fine, if the at-most-one-thread-per-bus assumption holds (same as @davids5's question: 'Is it true that in the end (all done), there is only 1 thread per bus and the possibility of hrt interruption.?').
Given the " at-most-one-thread-per-bus assumption" has a complication we need to resolve to make it so. A spi bus on some platforms can have a device that is accessed from a device driver in nuttx in the foreground. The params module can use a mtd derivative such as at25 eeprom or a ramtron FRAM and should have only non hrt threads running it. This needs to be true because the OS is used for the reader-writer serization (we should check with an test build with PX4_VERIFY_ASSERT(!up_interrupt_context()) in that driver)! FMUv4 has on SPI2 a ms5611 barometer and the FRAM. The barometer data sheet states effectively do not wiggle SPI pins doing conversions. Hece this complication that I am not 100% solves the noise issues. The only way this worked is because A) the ms5611 driver's bus transactions are on a work queue (ISR CAN NOT use OS functions that wait (sem_wait)) and B) it is not on a bus that has hrt threaded devices. We need to catch a potential misuse: PX4_SPI_BUS_BARO == PX4_SPI_BUS_RAMTRON and some hrt device also on bus. Which is the same problem the lock is needed for: The default is
The root problem is 1 can trounce on 3. We should look at moving param module's IO to the SPIx bus thread (and enforce this architecturally) if we do that then everything will be on ONE bus thread and the we can then drop the sem_wait and use only the atomic for isr protection. We should also change the parameter to not be written during flight. That will fully solve the barro noise issue. If we had adequate holdup time and a power fail detection we could commit them with an orderly shutdown as can be done with SW reboot. But that is a whole other issue. |
Co-Authored-By: dakejahl <37091262+dakejahl@users.noreply.github.com>
I think this makes sense architecturally and we should enforce it and document it.
You are referring to
I think the way the ms5611 collects is:
I think we would need to keep the Yeah? |
No param save to the mtd.
I agree but only on HW where it matters and it can be done and that is case by case. |
…hold for the isr lock
Okay, maybe we revisit this once #11261 is merged? I added the comment for the one thread per SPI bus assumption. |
Another option to consider is to simply prevent the SPI transfer from an interrupt. Once #11571 is merged the only concern is 3rd party drivers rebased on newer PX4. I think it would be acceptable to fail at runtime with an error (or even assert) if it points to instructions that show how trivial it is to migrate. |
Added an
_is_locked
variable to theSPI
class which is a simple bit mask where the bit position corresponds to the SPI bus number. When runningSPI::transfer
from an ISR,LockMode
is selected asLOCK_NONE
(because you cannot pend on a sem in interrupt context). I have added a check for the_is_locked
flag for the given bus whenLockMode
is none, thus preventing an ISR drivenSPI::transfer
from clobbering an already active transfer taking place in workqueue/task/etc.