Skip to content

Fix SPI CS pin trouble #100

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

Merged
merged 3 commits into from Sep 12, 2017
Merged

Fix SPI CS pin trouble #100

merged 3 commits into from Sep 12, 2017

Conversation

ghost
Copy link

@ghost ghost commented Sep 5, 2017

I fixed a bug inside SPI library caused by the use of a CS pin other than Arduino digital pins.
Now, all pins can be used like a CS pin for the SPI.

@fpistm fpistm self-requested a review September 6, 2017 07:07
@@ -133,7 +133,7 @@ enum {

//SPI definitions
//define 16 channels. As many channel as digital IOs
#define SPI_CHANNELS_NUM 16
#define SPI_CHANNELS_NUM PEND
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleaser use NUM_DIGITAL_PINS instead of PEND for all
Amend the commit to avoid twice commit for this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! ;)

@fpistm
Copy link
Member

fpistm commented Sep 6, 2017

Thanks @fprwi6labs
But this will increase memory consumption:

SPISettings spiSettings[SPI_CHANNELS_NUM+1];

I think, we need to study more before merge.

@fpistm fpistm added the bug 🐛 Something isn't working label Sep 6, 2017
@LMESTM
Copy link
Member

LMESTM commented Sep 6, 2017

@fprwi6labs can you please describe the original root cause of the bug and how this is fixed here ?

For now please find my 2 cents as I just discussed it with @fpistm
As I read it, SPI_CHANNELS_NUM[] could be used as a table of CS pins that can be used on the SPI bus. You can have several devices on the same bus, but each of them has its own CS pin. So I would think that there is 1 device per channel and the table is used to store the CS pin.
But you should not need to increase the maximum number of channels higher than 16, you just need to be able to store the pin number in the table, and the pin number needs to be handled as a generic pin (can be D2 or PH3 or PA12 ...)

@ghost
Copy link
Author

ghost commented Sep 6, 2017

@LMESTM

Firstly, the bug is caused by this code:
if(_pin > SPI_CHANNELS_NUM) return;

So when you use a CS pin higher than SPI_CHANNELS_NUM you are out.
The solution was to increase SPI_CHANNELS_NUM to the maximum digital pin number.
And @fpistm points a side effect of my fix.

Secondly, when you look at the avr code, the CS pin is saved only one time when you call the function begin(). So I think it is not to the SPI library to save a list of CS pin but to the user if he has several devices on the same SPI bus.

Finally, spiSettings saved the SPI settings but it is 'idiot' to save multiple settings for the same instance. You should call beginTransaction() to set the SPI before to send data.

I exposed my project to @fpistm to rework the SPI library. I will propose to you soon the code.

@LMESTM
Copy link
Member

LMESTM commented Sep 6, 2017

One more note: I just add a look to SPI.cpp and SPI.h files and the _pin is used as an index to the spiSettings[] table, so the _pin is directly used as an channel index. To be able to use any pin as CS, the table index must be separated from the _pin ... so a deeper change is needed

@LMESTM
Copy link
Member

LMESTM commented Sep 6, 2017

Firstly, the bug is caused by this code:
if(_pin > SPI_CHANNELS_NUM) return;

I found out indeed

The solution was to increase SPI_CHANNELS_NUM to the maximum digital pin number.
And @fpistm points a side effect of my fix.

Yes. I agree this is due to SPI implementation which uses _pin as the index of settings.

Secondly, when you look at the avr code, the CS pin is saved only one time when you call the function begin(). So I think it is not to the SPI library to save a list of CS pin but to the user if he has several devices on the same SPI bus.

I agree the user will store and use the CS pin, which is used as a reference to a device.

Finally, spiSettings saved the SPI settings but it is 'idiot' to save multiple settings for the same instance. You should call beginTransaction() to set the SPI before to send data.

I don't think this is 'idiot'. You can have several devices on the SPI bus, on different CS pins, that have different settings. And you don't want to re-define the settings before each transfer, so the SPI library do the job of applying the right settting. This is efficient: If it's the same device as before, you keep the setting, and only when device changes you re-apply the corresponding setting. I'm not saying that you must store the _pin, but you'd need to find a way to map the table index to a given _pin ...

@ghost
Copy link
Author

ghost commented Sep 6, 2017

I don't think this is 'idiot'. You can have several devices on the SPI bus, on different CS pins, that have different settings. And you don't want to re-define the settings before each transfer, so the SPI library do the job of applying the right settting. This is efficient: If it's the same device as before, you keep the setting, and only when device changes you re-apply the corresponding setting. I'm not saying that you must store the _pin, but you'd need to find a way to map the table index to a given _pin ...

I agree but when I read the documentation of the Arduino SPI I understand that the user should follow the following sequence:

  • call beginTransaction() to set the bus
  • call transfer() to send data
  • call endTransaction() to release the bus

The native Arduino SPI library is simpler than our. But I can try to save several settings.

int16_t _CSpin;
spi_t _spi;

uint8_t getIdx(uint8_t _pin)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge getIdx and addIdx and use a second arg to define if a new idx could be added with a default value (no add by default)
This will avoid to loop twice if there is no idx for pin then call addIdx.

spiSettings[_pin].bOrder = settings.bOrder;
if(spiSettings[_pin].bOrder == MSBFIRST) {
spiSettings[_pin].msb = MSBFIRST;
idx = getIdx(_pin);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in SPI.h for getIdx and AddIdx to avoid loop twice

@@ -97,45 +97,59 @@ class SPISettings {
friend class SPIClass;
};


typedef struct {
int16_t pinCS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not add the pinCS in the SPISettings class?

@fpistm fpistm requested review from cparata and LMESTM September 12, 2017 08:40
#define SPI_TRANSFER_TIMEOUT 5000

// Defines the number of settings saved per SPI instance. Must be < 254.
#ifndef NB_SPI_SETTINGS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in the comment, it could be redefined in the variant.h

@ghost ghost requested a review from fpistm September 12, 2017 09:34
Copy link
Member

@LMESTM LMESTM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this new solution - this looks good. I added a few comments or questions but I'm happy with the change overall that keeps the "dynamic" settings management

if(idx == NB_SPI_SETTINGS) {
idx = addPin(_pin);
if(idx == NB_SPI_SETTINGS)
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this case here is not clear - is this an error ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is an error because there is no more place available for a new CS pin.

UNUSED(_pin);
end();
if(_pin > NUM_DIGITAL_PINS)
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also an error because _pin must be a defined pin (presents in digitalPin[]).

* The transfer function can reconfigure the SPI instance if the CS pin is
* different from the previous one.
* If the _mode is set to SPI_CONTINUE, keep the spi instance alive. That means
* the CS pin is not reset. Becareful in case you use several CS pin.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good comment thx. 1 typo: Becareful => Be careful


// Defines a default timeout delay in seconds for the SPI transfer
#define SPI_TRANSFER_TIMEOUT 5000

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems not related to CS related change and should be in a different commit.
The timeout was hardcoded to 10000 before and now is defined as 5000.
Is it really 5000 seconds ?? Do we consider that timeout can be fixed, whatever the number of bytes and frequency ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not 5000 seconds but 5000 milliseconds. I took advantage of the fix to standardize the timeout value.
This timeout doesn't change whatever the number of bytes or frequency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above the definition is
// Defines a default timeout delay in seconds for the SPI transfer
so you need to change that ...
How many bytes does it allow to send @ slowest supported frequency ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I am mistaken, we can send 78kbytes at slowest frequency = 125000.

Copy link
Member

@LMESTM LMESTM Sep 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok that sounds like a reasonable number. Even 1 sec might be enough then (~15kBytes) ... as I don't know the max supported length ...

#define BOARD_SPI_OWN_SS SPI_CHANNELS_NUM

#define SS BOARD_SPI_DEFAULT_SS
#define SS 43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this commit, but was is 43 ? can't we use a pin name like e.g. D10 or PB13 ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

43 == D43

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See PR #83 for more information.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that D43 is same as 43 and same as PX_y ...but D43 or 43 cannot be read anywhere on my board schematics or on the board itself, so I would prefer to use a commonly used names (either D0/D16 A0/A5 or PX_y ....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that on VLdisco there is no Arduino connector and so using Dx is not well appropriate while all PXn names are on the board silkscreen print. But it's not the subject of this PR. Currently, variant.h using the same naming (Dx). Probably a new PR could be done to update all variants which do not have Arduino connector or those one using a pin number > 15.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, that's why I started my comment with "Not related to this commit" ;-)

Copy link
Member

@fpistm fpistm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR ok. Waiting comment correction raised by @LMESTM before merge.

@ghost ghost requested a review from fpistm September 12, 2017 12:43
@fpistm fpistm merged commit f1b576d into stm32duino:master Sep 12, 2017
@ghost ghost deleted the remove_spics_limitation branch September 19, 2017 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants