Best practices for adjusting libraries for non-default SPI channels

Status
Not open for further replies.

kdharbert

Well-known member
I need to adjust a set of libraries that use default SPI such that I can specify SPI1 or SPI2. I've seen a thread relating to best practices for this doing this but I can't find it now. Is there a good guide out there?
Specifically, I need to use an RF24 library on SPI1 and SPI2. The targets are: 1) an easy interposer that will let a Teensy 4.1 host multiple NRF24L01 units on SPI1 and 2) an NRF24L01 unit mounted to an interposer with a microSD form factor that can be inserted into the Teensy's SD port used on SPI2.
 
I am not sure about "Best" practice, but...

Again that library looks like you can hard code it to any specific SPI port, (by changing the code)...
On my install the file is: C:\Users\kurte\Documents\Arduino\libraries\RF24\utility\Teensy\RF24_arch_config.h
Which has a line in it:
Code:
#define _SPI SPI
Which you can change to SPI1 or SPI2... But than it is hard coded to that one... Which is probably not what you want:

Then it looks like this library is hard coded to use _SPI, like:
Code:
    _SPI.beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0));

If it were my library, I would probably do something like:

Probably add a member variable in the RF24 class like:
Code:
    SPIClass *_pspi;
And change everywhere in the code that uses the _SPI. to _pspi->
Like:
Code:
    _pspi->beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0));

I would then need to decide when to set the _pspi variable, there could be a few different ways like:
a) Constructor assign it to default or as initial value when defined:
In constructor: _pspi = &_SPI;
or
Code:
/****************************************************************************/

RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed)
        :ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(true), addr_width(5), _is_p_variant(false),
         csDelay(5),_pspi(&SPI)
{
    pipe0_reading_address[0] = 0;
    if(spi_speed <= 35000){ //Handle old BCM2835 speed constants, default to RF24_SPI_SPEED
      spi_speed = RF24_SPI_SPEED;
    }
}
In definition: SPIClass *_pspi = &SPI;

b) could do the assignment probably in the begin method.


But now how to get the specific SPI port set, again a few options...
Add it to the constructor, like:
By reference:
Code:
    RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spispeed = RF24_SPI_SPEED, SPIClass &spi=SPI);

By Pointer
Code:
    RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spispeed = RF24_SPI_SPEED, SPIClass *pspi=&SPI);

Note: You may want second version of constructor as to make it such that library still works with bitbang version (SOFTWARE SPI)

In both of these cases change constructor implementation to use this than the hard coded one... Like:

Code:
/****************************************************************************/

RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed, SPIClass spi)
        :ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(true), addr_width(5), _is_p_variant(false),
         csDelay(5),_pspi(&spi)
{
    pipe0_reading_address[0] = 0;
    if(spi_speed <= 35000){ //Handle old BCM2835 speed constants, default to RF24_SPI_SPEED
      spi_speed = RF24_SPI_SPEED;
    }
}

And/or you could add it as an option parameter to the begin method: where maybe you have option like: radio.begin(SPI1)   or radio.begin(&SPI1) 
depending on if you want to pass by reference or pointer.


And/Or you could add new method like setSPI which again could be either pass by reference or by pointer:  radio.setSPI(SPI1); 
Which would need to be called before the begin is called.

-----------

In many cases like this if you can get something working great.  Better yet if you can then get the library owner to take the changes in with a Pull Request even better!

Hope that helps
 
No luck so far. Here are my steps:
1. Added this line to RF24.h:
SPIClass *_pspi= &SPI;

2. Global replace in RF24.cpp:
_SPI. to _pspi->

3. Changed constructor in RF24.cpp:
RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed,SPIClass spi)
:ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(false), addr_width(5),
csDelay(5),_pspi(&spi)

4. Changed Teensy code to use the new constructor format:
RF24 dongle_RF(9, 10,RF24_SPI_SPEED,SPI);

The Teensy code hangs. It is working with SPI0 when the unmodified library is used. Did I miss or botch any of the changes?
 
Hard to say without looking through all of the changes.

And checking any other places that do something funky...

You might try embedding a copy of your current library changes. Could zip them up and add the zip file... And then will try to take a look.
 
I took a look and there were a few things I changed and it now does not crash :D

In the file RF24.h
The SPIClass object I don't initialize in header as you are doing it in constructor:

Code:
	SPIClass *_pspi; //pointer to spi hardware object
The Constructor:
Code:
   RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spispeed = RF24_SPI_SPEED, SPIClass [COLOR="#FF0000"]&spiN[/COLOR]=SPI);
I changed the parameter name as first thing as I saw the usage of spi other places in code, probably not needed to change:
But the & is important as it says you are passing a REFERENCE and not a copy of the SPI object, which would be on stack and when we take the address of it it is later garbage...

In the C++ file I changed the constructor to match

Code:
RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed,[COLOR="#FF0000"]SPIClass &spiN[/COLOR])
        :ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(false), addr_width(5),
         _pspi(&spiN), csDelay(5)//,pipe0_reading_address(0)
{
    pipe0_reading_address[0] = 0;
    if(spi_speed <= 35000){ //Handle old BCM2835 speed constants, default to RF24_SPI_SPEED
      spi_speed = RF24_SPI_SPEED;
    }
}
But also changed where the _pspi(...) was set as you get compiler warnings if these inits are not in the same order as the defines in the header file.

Good luck
 
Status
Not open for further replies.
Back
Top