-
Notifications
You must be signed in to change notification settings - Fork 13.3k
libraries: fixed SPI #6423
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
libraries: fixed SPI #6423
Conversation
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.
Thanks, @thangktran. I can't test this, but it seems fine logically.
The problem originated because we had a write16()
call and a transfer16()
call, both of which did the same thing (except for the value return).
I think it makes sense here to remove the write16()
method guts and replace it with a call to (void) transfer16()
(the (void)
to be explicit that we're ignoring the returned value).
This way we only have one version of the actual work code, which seems like good code hygiene. I haven't gone thru the rest, but if there's a writeByte()
and a transferByte()
, the same comment applies...
Thank you for your input @earlephilhower . |
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.
Looks good. We'll do the cleanup (transfer/write de-duplication) in another issue/PR. Thx!
Is this PR ready-to-be-merged? I need it for #6425 |
That's what intended! transfer16() should transfer 16 bits (a word) with bit order for the complete word. If you want to transfer two bytes call transfer() twice in that byte order you want. Without the change you get:
Everything works as expeted. Now let the hardware control the CS signal:
Do you see the difference? The change does not effect old code that does not use the hardware control. Byte order and bit oder isn't changes. The only difference is the behavior of the CS signal. |
e22a97d
to
2b7cacb
Compare
to handle other bit lengths rather than 8. Thanks to @UlliBien for the fix suggestion. Fixes: esp8266#2820
2b7cacb
to
10218d4
Compare
The change affects any app that currently uses transfer16(), and transfer16() has been around for a while. My main concern is that this PR introduces a change in behavior which could affect compatibility. Receiving an arg uint16_t is one thing, and transmitting a 16bit value is something completely unrelated. You can have a transfer16() that receives a uint16_t argument, and transmit it either as 2 individual bytes or as a 16bit value, depending on the setDataBits() setting, or on some member bool in the SPI class. Is the current code illegal SPI? Does it not work? Is there s device with which it does work? You said:
I understand that. But what about the opposite? Do all devices understand 16bit transfers? Is there a device that does not understand 16bit transfers, but to which you would like to send a 16bit value as 2 8bit transfers? To be clear, I'm not saying such a bool should be added and be done with it. I'm saying it is not clear to me that the current code should be dropped in favor of the proposed code, because so far I haven't seen a convincing argument that the current code is invalid. You said:
So then that means that the behavior for hw vs. sw CS is not the same with this change. Enable hw CS, and transfer16 toggles CS between bytes. Does it make sense to have such different behavior? I would think that if I change the CS pin used in my circuit, and switch to sw CS control, the transmission bits within the SPI functions would remain the same! Then again, as I said, I'm not an SPI expert. |
I'm still not convinced that the current code is invalid. However, I also don't want to hold up your SPI work*. *The comments in the discussion that was pointed at are valid. If the hw supports more than one CS, an enhancement proposal would be welcome. Comments in the header would help understand the SPI class methods better and avoid having to look at the cpp. Precalculation. Etc. |
I'm not able to find a "definitive" spec for it, but from what I've seem at TI and uChip, CS is asserted for the length of the transfer for all lengths of comms: CS deassertion looks like it is supposed to reset the slave's state machine, but all I've been able to find are non-definitive verilog (read: some guy on the internet's code) so that's not really canon. |
@devyte just to be clear. So we have |
@thangktran not clear, that is part of my point. What you say is one possibility. transfer(uint8_t arg); //single byte, 8bit mode
transfer(uint16_t arg); //16bits, 8bit mode
transfer16(uint8_t arg); //single byte 16bit mode
transfer16(uint16_t arg); //16bits, 16bit mode |
Yet another possibility is to have a transferWidth flag that defines the number of bits of the transfer mode. It would default to 8bits, but could be set to 16bits for 16bit transfer. |
Would it not make sense that this is a "transaction" setting? So SPISettings should be extended to include |
Looking at the SPISettings class members, a _dataWidth addition looks right at home there. Whatever else, I think that should be done, preferably in its own PR. That still leaves this PR, where the question is which approach to use for write/transfer. I see the following options (please correct me if I'm wrong):
|
Nobody needs such things! The current implementation is far away from the Arduino standards. Don't make it worse. |
I strongly believe that all three options are incorrect. I think this pull is going in the wrong direction to fix the issue. Please correct me if I get this wrong (I may have missed something). The API has two issues that are in conflict. One is that Esp specific issue of the pointer being on 8bit/16bit/32bit boundary. The other a SPI issue of sending "transactions" (SPI specific term here) of different bit width. The SPI API is using SpiSettings is used to configure the "transaction"; and I believe this should be adhered to. There should be no other way to set the bit width of a transaction. This then leaves the Esp specific "16" methods to be left alone to be used to signify the source data size. |
@UlliBien Arduino is not a standard, it's a reference. Please be aware of the difference. @Makuna from looking at the Arduino reference api docs, I see the following:
There is no support for other cases. To me, that looks like an incomplete api. It certainly looks like we already support a broader range of cases. |
That isn't quite right. The discussion is about the argument type passed to the transferXX() functions vs. the XX in tje function name. Currently there is this: transfer(uint8_t arg); //single byte arg, 8bit transfer width
transfer16(uint16_t arg); //16bit arg, 2x 8bit transfer width The Arduino reference for SPI says nothing of 16bit transfer width, only of a 16bit val to send/receive. My overloaded method proposal is this: transfer(uint8_t arg); //single byte arg, 8bit transfer width
transfer(uint16_t arg); //16bit arg, 2x 8bit transfer width
transfer16(uint8_t arg); //single byte arg, 16bit transfer width
transfer16(uint16_t arg); //16bit arg, 16bit transfer width Functionally, this contains our current functionality plus the proposal in this PR, and covers the Arduino reference ambiguity and all, i. e. it's a superset.
As I said, the Arduino reference says nothing about 16bit width for transactions (unless I missed something). Still, I think the suggestion of adding the setting as a member in SPISettings is sound. Again, it would be a superset of the Arduino reference. |
Thank you both for making the issues clear to me. I still feel this is the wrong direction, the nuance of passing a byte versus 16 bit could be too easy to miss the size difference and the nuance of what it means is not obvious when looking at the API. This screams bad API design. This is why I made the suggestion I did. While often we find the Arduino "reference" vague and not well thought out, I feel this would not make it better; or even this API better. It feels like it would be harder to maintain and will require more future work. Let alone more people asking questions on the gitter channel and forums ;-) |
@Makuna I agree with you. |
to handle other bit lengths rather than 8.
Thanks to @UlliBien for the fix suggestion.
Fixes: #2820