Help with basics for using two SPI buses on Teensy 3.5

Status
Not open for further replies.

bugeye60

Active member
Hello,

I'm attempting to combine an Adafruit RFM69HCW radio with an Adafruit nRF8001 Bluetooth LE on a Teensy 3.5. The radio is using the first SPI bus (e.g. MOSI0) and the Bluetooth board is using the second SPI bus (e.g. MOSI1). The radio functions fine by itself. The Bluetooth board functions fine with a Teensy 3.2 by itself (using its only SPI bus). I'm unable to get the Bluetooth board working on the Teensy 3.5 and I suspect I'm doing something wrong with the buses. Can someone tell me what I may be doing wrong? Am I being too simplistic in thinking that I can simply define SPI and SPI1 parameters to use both buses?

Thanks!

Code:
#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
#include <RFM69_ATC.h>//get it here: https://www.github.com/lowpowerlab/rfm69
#include <SPI.h>      //comes with Arduino IDE (www.arduino.cc)
.
.
.
//*********************************************************************************************
// for Adafruit RFM69HCW connected to Teensy 3.5 through the first default (0) SPI bus
// The Low Power Labs RFM69.h library does not support multiple buses!
#define RFM69_CS   10
#define LED 13
#define RFM69_RST  33
#define RFM69_IRQ  34
#define RFM69_IRQN 34 // Interrupt number is same as pin number on Teensy
#define RFM69_SCK  14
#define RFM69_MOSI 11
#define RFM69_MISO 12
RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HW, RFM69_IRQN);
//*********************************************************************************************
// for Adafruit nRF8001 Bluetooth Low Energy Breakout connected to Teensy 3.5
#include "Adafruit_BLE_UART.h"
#define BLE_CS  31
#define BLE_RDY 30     // This should be an interrupt pin
#define BLE_RST 29
#define BLE_SCK 32
#define BLE_MOSI 21
#define BLE_MISO  5
Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(BLE_CS, BLE_RDY, BLE_RST);
//*********************************************************************************************
#define SERIAL_BAUD   9600
.
.
.
void setup() {
  Serial.begin(SERIAL_BAUD);
  while(!Serial);  //Teensy 3.2 sketch has this delay.  Don't want it for this node, but debugging now.
  //delay(10);     // commented out while debugging with above line.
  
  // ==================== setup Adafruit RFM69HCW
  SPI.setSCK(RFM69_SCK);
  SPI.setMOSI(RFM69_MOSI);
  SPI.setMISO(RFM69_MISO);
  SPI.setCS(RFM69_CS);
  SPI.begin();

  // Hard reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);
  
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW
  radio.setHighPower(); //only for RFM69HW!
#endif
  // ==================== end of Adafruit RFM69HCW setup 
  
  // ==================== setup Adafruit nRF8001 Bluetooth LE 
  SPI1.setSCK(BLE_SCK);
  SPI1.setMOSI(BLE_MOSI);
  SPI1.setMISO(BLE_MISO);
  SPI1.setCS(BLE_CS);
  SPI1.begin();
  Serial.println(F("Adafruit Bluefruit Low Energy nRF8001 Print echo demo"));
  BTLEserial.setDeviceName("Teensy"); /* 7 characters max! */
  BTLEserial.begin();
  // ==================== end of Adafruit nRF8001 Bluetooth setup 
}

// Bluetooth LE line, constantly checks for new events on the nRF8001
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;

void loop() {
.
.
.
 
i dont see you setting the CS pins high on the bluetooth module, you can drop it low later

what you could also do is when accessing the radio, deassert the bt, when your done, deassert the radio amd assert the bt

this may make it work as i too had issues with 2 open spi transactions being accessed simuletaneously within one function at one time

note: i also have the T3.5,
note2: you could run both off the same spi bus as long as they have their own CS line, and following the deassert/assert method per call
 
Last edited:
The problem may be that the Adafruit Blutooth library is probably not setup to be able to work on SPI1. In order to make it work, you would probably need to edit the library and find all references to SPI. and change them to SPI1.
 
@tonton81:
I'll double check my code again, but except for the pin assignments my bluetooth code should be the same on the Teensy 3.2 and the Teensy 3.5. The bluetooth board works on the 3.2 but not the 3.5. If I resort to using the same SPI bus for both radio and bluetooth with separate CS pins, how do you assert one and de-assert the other?

@KurtE:
I was hoping you'd comment since I've seen lots of info from you regarding SPI. I'll review the Adafruit bluetooth library looking for SPI references to change to SPI2.

Thank you both for the help.
 
Typically most libraries will assert/release their CS line when you do stuff, which is why in many cases you pass that pin number into the constructor and/or logical begin functions...

However there is one issue that the calling code may need to deal with, that is the state of the CS pins before the calls to their begin/setup/init...

That is you first setup the Radio, which will set it's CS pin in the appropriate state, but at that point the CS for the Bluetooth module has not been initialized, so is maybe floating and so it might try to interpret the SPI data begin sent to the radio as many meant for it, which is most likely not correct.

So in case like this you may want to add some code to the start of your setup code like:
Code:
pinMode(RFM69_CS, OUTPUT);
digitalWrite(RFM69_CS, HIGH);  // make sure it is not asserted
pinMode(BLE_CS, OUTPUT);
digitalWrite(BLE_CS, HIGH);

The library you mentioned (version installed by Teensyduino) - has transaction support and the like, all of the SPI reference are in the file:
D:\arduino-1.8.2\hardware\teensy\avr\libraries\Adafruit_nRF8001\utility\hal_aci_tl.cpp
Note: your location will likely be different, I installed Arduino root of my D drive.

Hopefully over time (and assuming we go to the SPIClass as the class for all SPI objects) we can update these libraries to somehow pass in which SPI object to use (either on constructor or an Init function) and then you would not need to edit the library to change from SPI to SPI1 or SPI2...
 
Unfortunately, the bluetooth board is still not advertising a connection. Here's what I did:

Modified file hal_aci_tl.cpp minimally, as follows:
changed SPI.begin(); to SPI1.begin();
changed SPI.usingInterrupt(HAL_IO_RADIO_IRQ); to SPI1.usingInterrupt(HAL_IO_RADIO_IRQ);
changed SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0)); to SPI1.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
changed SPI.endTransaction(); to SPI1.endTransaction();

The board still did not advertise after this change, so per a README file, I changed file ble_system.h from

Code:
/*
#define HAL_IO_RADIO_CSN       SS
#define HAL_IO_RADIO_REQN      SS
#define HAL_IO_RADIO_RDY       [B]3[/B]
#define HAL_IO_RADIO_SCK       SCK
#define HAL_IO_RADIO_MOSI      MOSI
#define HAL_IO_RADIO_MISO      MISO
#define HAL_IO_RADIO_RESET     [B]9[/B]
#define HAL_IO_RADIO_ACTIVE    8

//#define HAL_IO_LED0          2
//#define HAL_IO_LED1          6
*/

To

Code:
/*
#define HAL_IO_RADIO_CSN       SS
#define HAL_IO_RADIO_REQN      SS
#define HAL_IO_RADIO_RDY       [B]30[/B]
#define HAL_IO_RADIO_SCK       SCK
#define HAL_IO_RADIO_MOSI      MOSI
#define HAL_IO_RADIO_MISO      MISO
#define HAL_IO_RADIO_RESET     [B]29[/B]
#define HAL_IO_RADIO_ACTIVE    8

//#define HAL_IO_LED0          2
//#define HAL_IO_LED1          6
*/

I'm wondering if that even mattered because the lines are between comment characters. Anyway, the bluetooth board still did not advertise a connection.

Finally, I added KurtE's suggested lines to the original setup as follows:
Code:
void setup() {
  Serial.begin(SERIAL_BAUD);
  while(!Serial);  //Teensy 3.2 sketch has this delay.  Don't want it for a this node, but debugging now.
  //delay(10);     // commented out while debugging with above line.

  [B]// Recommended by KurtE of Teensy forum on 05/23/2017:
  pinMode(RFM69_CS, OUTPUT);
  digitalWrite(RFM69_CS, HIGH);  // make sure it is not asserted
  pinMode(BLE_CS, OUTPUT);
  digitalWrite(BLE_CS, HIGH);
  // End of KurtE's recommendation[/B]
  
  // ==================== setup Adafruit RFM69HCW
  SPI.setSCK(RFM69_SCK);
  SPI.setMOSI(RFM69_MOSI);
  SPI.setMISO(RFM69_MISO);
  SPI.setCS(RFM69_CS);
  SPI.begin();

  // Hard reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);
  
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW
  radio.setHighPower(); //only for RFM69HW!
#endif
  // ==================== end of Adafruit RFM69HCW setup
  
  // ==================== setup Adafruit nRF8001 Bluetooth LE
  SPI1.setSCK(BLE_SCK);
  SPI1.setMOSI(BLE_MOSI);
  SPI1.setMISO(BLE_MISO);
  SPI1.setCS(BLE_CS);
  SPI1.begin();
  Serial.println(F("Adafruit Bluefruit Low Energy nRF8001 Print echo demo"));
  BTLEserial.setDeviceName("Teensy"); /* 7 characters max! */
  BTLEserial.begin();
  // ==================== end of Adafruit nRF8001 Bluetooth setup

}

// Bluetooth LE line, constantly checks for new events on the nRF8001
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;

void loop() {

Were there more SPI references in file hal_aci_tl.cpp that I should have changed, such as SPI_MODE0?

The README.md file I referenced above states the following:
# Adafruit_nRF8001 #

Driver and example code for Adafruit's nRF8001 Bluetooth Low Energy Breakout.

## PINOUT ##

The pin locations are defined in **ble_system.h**, the supported systems are defined in **hal_aci_tl.cpp**. The following pinout is used by default for the Arduino Uno:

* SCK -> Pin 13
* MISO -> Pin 12
* MOSI -> Pin 11
* REQ -> Pin 10
* RDY -> Pin 2 (HW interrupt)
* ACT -> Not connected
* RST -> Pin 9
* 3V0 - > Not connected
* GND -> GND
* VIN -> 5V

RDY must be on pin 2 since this pin requires a HW interrupt.

Do you think I really need to define RDY on pin 2, or would that only be for the Arduino Uno example??

Any other help and thoughts are appreciated.
 
Last edited:
I finally had time to work on this again and now have it working as intended.

I abandoned trying to use SPI1 pins on Teensy 3.5 and went back to using the SPI pins for both the RFM69HCW and the Bluetooth boards. In other words, I used SCK0, MISO0, and MOSI0 pins instead of using SCK1, MISO1, and MOSI1 pins. I used different Chip Select pins, as suggested by tonton81.

Current definition is now:

Code:
//*********************************************************************************************
// for Adafruit RFM69HCW connected to Teensy 3.5 through the first default (0) SPI bus
// The Low Power Labs RFM69.h library does not support multiple buses!
#define RFM69_CS   10
#define LED 13
#define RFM69_RST  33
#define RFM69_IRQ  34
#define RFM69_IRQN 34 // Interrupt number is same as pin number on Teensy
#define RFM69_SCK  14
#define RFM69_MOSI 11
#define RFM69_MISO 12
RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HW, RFM69_IRQN);
//*********************************************************************************************
// for Adafruit nRF8001 Bluetooth Low Energy Breakout connected to Teensy 3.5
#include "Adafruit_BLE_UART.h"
#define BLE_CS  31
#define BLE_RDY 30     // This should be an interrupt pin
#define BLE_RST 29
#define BLE_SCK 14     // was 32
#define BLE_MOSI 11    // was 21
#define BLE_MISO 12    // was 5
Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(BLE_CS, BLE_RDY, BLE_RST);
//*********************************************************************************************

I reverted back to the original hal_aci_tl.cpp file (SPI references instead of SPI1 references) but kept the modified ble_system.h file since I had to modify the default data-ready pin (RDY) and reset pin (RST) in it for the bluetooth board.

Both the RFM69HCW and Bluetooth boards are now working!
 
Status
Not open for further replies.
Back
Top