Noisy, unintelligible SPI signals using T3SPI

Status
Not open for further replies.

trent

Member
I'm trying to use Teensy 3.0's both as a master and a slave in an SPI setup. However, trying to use the example sketches provided with the library, I haven't been successful at getting the Teensy to send out any signal recognizable by SPI. After fixing a small compile-time error in the example (changing CTAR0 to CTAR_0 in two places), the signals look like this:

t3spi.jpg

(Pictured above is a single transmission. This happens every 2 seconds--as instructed by the example code--before all pins go HIGH or LOW for the remainder of the 2 seconds.)

As you can see, none of the pins do what they are supposed to: clock is not periodic, ENABLE doesn't go low. This is not a problem with the Teensy, because I have run Nick Gammon's SPI example master code and seen this (on the same Teensy):

Gammon_master_example success.jpg

I started with Arduino 1.6.5 and Teensyduino 1.24, but suspected that my software version might be the problem. Now I'm running Arduino 1.0.6 and Teensyduino 1.20. I am using a Teensy 3.0 (black) and the default output pins.

Does anyone have experience in t3spi that could help me with this?
 
I'm trying to use Teensy 3.0's both as a master and a slave in an SPI setup. However, trying to use the example sketches provided with the library, I haven't been successful at getting the Teensy to send out any signal recognizable by SPI. After fixing a small compile-time error in the example (changing CTAR0 to CTAR_0 in two places), the signals look like this:

View attachment 4737

(Pictured above is a single transmission. This happens every 2 seconds--as instructed by the example code--before all pins go HIGH or LOW for the remainder of the 2 seconds.)

As you can see, none of the pins do what they are supposed to: clock is not periodic, ENABLE doesn't go low. This is not a problem with the Teensy, because I have run Nick Gammon's SPI example master code and seen this (on the same Teensy):

View attachment 4738

I started with Arduino 1.6.5 and Teensyduino 1.24, but suspected that my software version might be the problem. Now I'm running Arduino 1.0.6 and Teensyduino 1.20. I am using a Teensy 3.0 (black) and the default output pins.

Does anyone have experience in t3spi that could help me with this?

What speed are you using ?
How long is the connection ?
 
Rookie mistake in not checking my speed. It was at 24 MHz.

Now I've got it set to SPI_CLOCK_DIV8, and I can read it on my network analyzer. However, my CS0 pin (which I assume is pin 10) is not going low when the transmission starts. Thoughts?

enable not enabling.jpg

Appended note: I can make sense of the noise now.

And here's my code (the bold represents the changes I made to the code):


#include <t3spi.h>

//Initialize T3SPI class as SPI_MASTER
T3SPI SPI_MASTER;

//The number of integers per data packet
#define dataLength 256

//Initialize the arrays for outgoing data
//volatile uint8_t data[dataLength] = {};
volatile uint16_t data[dataLength] = {};


void setup(){

pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(CS0, OUTPUT);

Serial.begin(115200);

//Begin SPI in MASTER (SCK pin, MOSI pin, MISO pin, CS pin, Active State)
SPI_MASTER.begin_MASTER(SCK, MOSI, MISO, CS0, CS_ActiveLOW);

//Set the CTAR (CTARn, Frame Size, SPI Mode, Shift Mode, Clock Divider)
//SPI_MASTER.setCTAR(CTAR1,8,SPI_MODE0,LSB_FIRST,SPI_CLOCK_DIV4);
SPI_MASTER.setCTAR(CTAR_0,16,SPI_MODE0,LSB_FIRST,SPI_CLOCK_DIV32);

//Populate data array
for (int i=0; i<dataLength; i++){
data=i;}

//Wait for Slave
delay(5000);
}
 
Last edited:
However, my CS0 pin (which I assume is pin 10) is not going low when the transmission starts. Thoughts?

Presumably you want the SPI port to control pin 10?

Each pin has a mux. By default, the pins are configured on mux channel zero, which causes the pin to be disabled. If you want the pin to be controlled by GPIO, its mux needs to be configured for channel 1. The pinMode() function does that for you.

If you want the pin to be controlled by SPI, its mux needs to be configured for channel 2. The mux settings for all pins are documented in a big table in chapter 10 of the reference manual, on page 209.

The header file core_pins.h defines convenient names for each mux config register. For pin 10, use CORE_PIN10_CONFIG.

https://github.com/PaulStoffregen/cores/blob/master/teensy3/core_pins.h#L373
 
Presumably you want the SPI port to control pin 10?
If you want the pin to be controlled by SPI, its mux needs to be configured for channel 2. The mux settings for all pins are documented in a big table in chapter 10 of the reference manual, on page 209.

The header file core_pins.h defines convenient names for each mux config register. For pin 10, use CORE_PIN10_CONFIG.

https://github.com/PaulStoffregen/cores/blob/master/teensy3/core_pins.h#L373

So if I want pin 10 to be controlled by SPI, I do something like

CORE_PIN10_CONFIG = 3;

in setup?
 
You may want to take a look at SPFIFO.h: https://github.com/PaulStoffregen/cores/blob/master/teensy3/SPIFIFO.h

Code:
[COLOR=#333333][FONT=Consolas]CORE_PIN10_CONFIG = [/FONT][/COLOR][COLOR=#0086B3][FONT=Consolas]PORT_PCR_MUX[/FONT][/COLOR][COLOR=#333333][FONT=Consolas]([/FONT][/COLOR][COLOR=#0086B3][FONT=Consolas]2[/FONT][/COLOR][COLOR=#333333][FONT=Consolas]);
[/FONT][/COLOR]

Or even t3spi's enablePins method:
Code:
void T3SPI::enablePins(uint8_t sck, uint8_t mosi, uint8_t miso, uint8_t cs, bool activeState){
	if (sck == 0x0D){
		CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);}	//Set Pin13 Output & SCK
	if (sck == 0x0E){
		CORE_PIN13_CONFIG = PORT_PCR_MUX(1);
		CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);}	//Set Pin14 Output & SCK
	if (mosi == 0x0B){
		CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);}	//Set Pin11 Output & MOSI
	if (mosi ==  0x07){
		CORE_PIN7_CONFIG  = PORT_PCR_DSE | PORT_PCR_MUX(2);}	//Set Pin7  Output & MOSI
	if (miso == 0x0C){
		CORE_PIN12_CONFIG = PORT_PCR_MUX(2);}					//Set Pin12 Input & MISO
	if (miso ==  0x08){
		CORE_PIN8_CONFIG  = PORT_PCR_MUX(2);}					//Set Pin8  Input & MISO
	enableCS(cs, activeState);
}
 
Last edited:
Got it working. Btmcmahan's T3SPI example worked well without having to designate these pin modes. Turns out the problems were more down-to-earth (literally): grounding issues with my network analyzer and needing the master to run MISO to MOSI and MOSI to MISO. Thanks for all the help!
 
Glad to hear it. But I know there are some problems with the Master/Slave lib, specifically the ctar0 (ctar_0) issue. But also, I've experience issues with the data on the slave end not matching up with the master.

For example:
The master sends out 1, 2, 3, 4 in 4 separate SPI transactions.
The slave reads 0, 1, 2, 3.

For some reason, and I can't figure out why, the slave seems to boot with a value already inside the spi register. I can't seem to prevent this, but I have been able to do a Syncing process to get the data aligned.
 
I've been working on SPI slave stuff using btmcmahan's library and as far as I can tell the only way that it's possible to get the slave FIFO in sync with the external master is if you actually toggle the _SS pin. I had it pulled low since it's the only thing on my bus but I've been unable to find any combination of register manipulation that will clear out whatever leftover junk you happen to have in there before valid frames started.
 
That's interesting. When are you toggling the SS pin? Just once during the setup () to clear the junk? Or do you have to toggle it with every transfer?
 
I actually have what's basically an end of frame signal, so I'm just using that for _SS right now but when I get the chance I'll try controlling it from another pin on the slave device and just doing it once at the initial sync (I only figured out this was an issue last night). Even if that appears to fix it I'd be very tempted to do it every transfer as it appears to empty the shift register and there's no easy way to tell if anything has gone wrong with your frames unless you control the protocol and can do some sort of CRC.
 
Well it definitely sounds promising. Let us know what you find out, this issue has been plaguing me for months.
 
If I manually hold _SS high until SPI is started up I seem to get clean frames until I deliberately mess with the signal to throw it off, however I wouldn't want to count on that in cases where a valid _SS is easy. Keep in mind also that I'm not doing any transfers back to the Master, I'm strictly reading in the data, so having _SS working might not fix the transmit side.

Here's the current version of my hybrid code (embedded in a little project specific junk), but it's pretty similar to the slave portions of your library.

Code:
#include "DMAChannel.h"

// Display size
#define FRAME_COUNT 4
#define ROW_COUNT 32
#define COL_COUNT 128
#define dataLength  COL_COUNT / 16

// Dot data
uint16_t data[dataLength];
volatile uint8_t dataPointer;
uint16_t frames[FRAME_COUNT][ROW_COUNT][dataLength];
volatile uint8_t frame = 0;
volatile uint8_t row = 0;
volatile bool gotFrame = false;

// Input pins
const int COL_LATCH = 3;
const int ROW_DATA = 2;
const int ROW_CLK = 4;

// Output pins
const int SS_TEST = 1;

// DMA channel
DMAChannel* spi0RxDMA;

void setup() {
  pinMode(ROW_DATA, INPUT_PULLUP);
  pinMode(ROW_CLK, INPUT);
  pinMode(COL_LATCH, INPUT_PULLUP);
  pinMode(SS_TEST, OUTPUT);
  
  Serial.begin(115200);

  // Configure pins for use by SPI0
  CORE_PIN10_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_PE | PORT_PCR_PS;
  CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
  CORE_PIN12_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_PE;
  CORE_PIN13_CONFIG = PORT_PCR_MUX(2);
  
  // Enable clock to SPI0
  SIM_SCGC6 |= SIM_SCGC6_SPI0;
  SPI0_MCR = SPI_MCR_HALT | SPI_MCR_MDIS | SPI_MCR_PCSIS(1<<0);
  
  SPI0_CTAR0_SLAVE = SPI_CTAR_FMSZ(15); // 16 bit frames, on rising edge
  
  // Enable FIFO Drain Request Interrupt
  /*
  SPI0_RSER = SPI_RSER_RFDF_RE;
  NVIC_ENABLE_IRQ(IRQ_SPI0);
  */
  
  // Enable FIFO Drain Request DMA
  SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS;
  spi0RxDMA = new DMAChannel();
  spi0RxDMA->source((volatile uint16_t&) SPI0_POPR);
  spi0RxDMA->destinationBuffer(data, dataLength * sizeof(uint16_t));
  spi0RxDMA->disableOnCompletion(); 
  spi0RxDMA->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX);
 
  //Enable Row Data Interrupt
  attachInterrupt(digitalPinToInterrupt(ROW_CLK), row_clk_isr, FALLING);
  
  //Enable Dot Latch Interrupt
  attachInterrupt(digitalPinToInterrupt(COL_LATCH), col_latch_isr, RISING);

  // Wait for frame alignment
  do {
   SPI0_MCR |= SPI_MCR_CLR_RXF;
   digitalWriteFast(SS_TEST, HIGH);
  } while (digitalReadFast(ROW_CLK) || !digitalReadFast(COL_LATCH));
  digitalWriteFast(SS_TEST, LOW);

  // Turn on the SPI
  SPI0_MCR &= ~SPI_MCR_HALT & ~SPI_MCR_MDIS;
}

int counter = 0;

void loop() {

 if (gotFrame) {
  uint8_t currentFrame = frame;
  uint8_t currentRow = row;
  
  gotFrame = false;
  
  memcpy(frames[currentFrame][currentRow], data, sizeof(data));
    
  // REMOVED DEBUG CODE DUMPING FRAME TO USB
  }

}


//Interrupt Service Routine to handle incoming data
/*
void spi0_isr(void) {
  while (SPI0_SR & 0xF0) {
    data[dataPointer++] = SPI0_POPR;
  }
  
  SPI0_SR |= SPI_SR_RFDF;
}

void col_latch_isr(void) {
  if (dataPointer < 8) {
    while (SPI0_SR & 0xF0) {
      data[dataPointer++] = SPI0_POPR;
    }
    SPI0_SR |= SPI_SR_RFDF;
  }
  
  dataPointer = 0;
  
  frame++;
  gotFrame = true;
}
*/

// DMA to handle incoming data
void col_latch_isr(void) {
 spi0RxDMA->disable();
 spi0RxDMA->clearComplete();
 spi0RxDMA->enable();
  
  frame++;
  gotFrame = true;
}

void row_clk_isr(void) {
  if (digitalReadFast(ROW_DATA) == HIGH) {
    row = 0;
  }
  else {
    row++;
  }

  frame = 0;
}
 
Status
Not open for further replies.
Back
Top