Can't get SPI to work on Teensy 3.2

Status
Not open for further replies.

Mbanzi

Member
Can't get SPI to work on Teensy 3.2 [SOLVED]

I'm unable to get SPI to work reading 4 daisy chained CD4021 shift registers to read 32 switches that are pulled high. I'm an experienced Arduino developer, and the sample code shown below works fine testing on an Arduino Nano. I have tried running the shift registers on 5V, 3.3V & through a Sparkfun bi-directional logic level converter. The result is always the same: all bits are 1 in the 4 bytes I read. I have read somewhere that the CD4021s are troublesome with 3.3V, so I plan to try 74HC165s instead.

NOTE: Solution in post #8


Code:
#include <SPI.h>
 
#define SS 10

byte bank1, bank2, bank3, bank4;
 
void setup() {
  SPI.begin();
  Serial.begin(57600);
  pinMode(SS, OUTPUT);
}
 
void loop() {
    
  digitalWrite(SS, HIGH); // Set latch pin to 1 to collect parallel data
  delayMicroseconds(200);
  digitalWrite(SS, LOW); // Set latch pin to 0 to transmit data serially
  delayMicroseconds(200);
  
  // read CD4021 IC
  bank1 = SPI.transfer(0x00);
  bank2 = SPI.transfer(0x00);
  bank3 = SPI.transfer(0x00);
  bank4 = SPI.transfer(0x00);

  Serial.print("1:");
  Serial.println(bank1, BIN); // Always 1:11111111
  Serial.print("2:");
  Serial.println(bank2, BIN);
  Serial.print("3:");
  Serial.println(bank3, BIN);
  Serial.print("4:");
  Serial.println(bank4, BIN);
  Serial.println("-------------------");

  delay(500); // Slow down serial monitor output
}

Connections:
CD4021 pin 9 (Parallel/Serial Control) [On all chips] -> Teensy pin 10
CD4021 pin 3 (Q8) [On first chips] -> Teensy pin 12
CD4021 pin 10 (Clock) [On all chips] -> Teensy pin 13
First CD4021 pin 11 (Serial In) to next daisy-chained CD4021 pin 3 (Q8)
Last CD4021 pin 11 (Serial In) to GND

As I mentioned, the shift register circuit is in use on several Arduinos, so it works fine.

Interestingly enough if I use:

Code:
shiftIn(DATAPIN, CLOCKPIN);

with the connections unchanged, I can read each one of the 32 switches connected to the shift registers. It appears it's this line that is failing:

Code:
SPI.transfer(0x00);
 
Last edited:
The first thing that strikes my eye is that you don't use SPI transactions. I don't know what SPI settings the CD4021 uses and what settings the SPI is initialized to, but try adding a pair of SPI.beginTransaction(SPISettings(...)) and SPI.endTransaction()
 
The first thing that strikes my eye is that you don't use SPI transactions. I don't know what SPI settings the CD4021 uses and what settings the SPI is initialized to, but try adding a pair of SPI.beginTransaction(SPISettings(...)) and SPI.endTransaction()

the example is so basic that one could do it without begin/end_transaction
Could the teensy SPI be not too fast (exceeding the 6 MHz mentioned in datasheet)?
 
I was wondering about the use of transactions in the samples, but as my old test code worked perfectly on an Arduino, I didn't look into it further. I know the 4021 gets very slow <= 5V, so I'll try something like this to slow it down:

Code:
SPISettings( 3000000, MSBFIRST, SPI_MODE0 )

Any idea if the SPI mode makes a difference?

The first thing that strikes my eye is that you don't use SPI transactions. I don't know what SPI settings the CD4021 uses and what settings the SPI is initialized to, but try adding a pair of SPI.beginTransaction(SPISettings(...)) and SPI.endTransaction()
 
As I mentioned in my previous reply, the 4021 is known to get very slow <= 5V. I'm definitely going to slow down SPI to see if that works. The AtMEGA328 if I recall is limited to 4MHz SPI (fosc (16Mhz) / 4 for slave), so it makes sense that it would work on the Arduino.

the example is so basic that one could do it without begin/end_transaction
Could the teensy SPI be not too fast (exceeding the 6 MHz mentioned in datasheet)?
 
I mentioned SPI transactions just for the point of explicitly setting speed, mode and bit order. By the datasheet I'd start with a 1 MHz clock and mode 1: the 4021 will setup data on the rising clock edge, so sampling can be done on the next falling edge.
 
It works!

Thanks for all the replies - good to know there is such a helpful & knowledgeable community out there for the Teensy!

I got the Teensy reading the daisy-chained shift registers by slowing down SPI as suggested. Interestingly enough the maximum speed I could use with a 5V supply to the CD4021 chips was 4MHz, but changing the supply to 3.3V I had to drop down to 2MHz! The CD4021 is definitely not the ideal shift register for logic level voltages, I'm switching my design to 74HC165 instead.

As I had a hard time finding sample code, here is my final working version for posterity:

Code:
#include <SPI.h>
 
const int slavePin = 10;

void setup() {
  Serial.begin( 57600 );
  pinMode( slavePin, OUTPUT );
  SPI.begin();
}
 
void loop() {
    
  SPI.beginTransaction( SPISettings( 4000000, MSBFIRST, SPI_MODE0 ) );
  
  digitalWrite( slavePin, HIGH ); // Set latch pin to 1 to collect parallel data
  delayMicroseconds( 10 );
  digitalWrite( slavePin, LOW); // Set latch pin to 0 to transmit data serially
  delayMicroseconds( 10 );
  
  // read CD4021 IC
  byte bank1 = SPI.transfer( 0x00 );
  byte bank2 = SPI.transfer( 0x00 );
  byte bank3 = SPI.transfer( 0x00 );
  byte bank4 = SPI.transfer( 0x00 );

  SPI.endTransaction();

  Serial.print("1:");
  Serial.println(bank1, BIN);
  Serial.print("2:");
  Serial.println(bank2, BIN);
  Serial.print("3:");
  Serial.println(bank3, BIN);
  Serial.print("4:");
  Serial.println(bank4, BIN);
  Serial.println("-------------------");

  delay(500); // Slow down serial monitor output
}
 
Status
Not open for further replies.
Back
Top