Teensy SPI question

Status
Not open for further replies.
kurte i tested your code but it still does not work.
Like Paul mentioned, it is hard to know how to help you without knowing what "it" is or what does not work mean.

If it were me, I would hook up a logic analyzer to see the signals.

Also as I mentioned, I setup that version of the code, so you might try changing the CS_LOW and CS_HIGH to do digitalWrite to some standard IO pin, and then try to setup to use that as CS to help verify that the rest of the code is working.

Also I might experiment. As I asked do you really need to do CS_HIGH followed directly by CS_LOW between I assume these commands?

If so maybe try something like:
CS_HIGH;
delayMicroseconds(100);
CS_LOW;

In all of the appropriate places, example in the code what happens if you change the two macros to something like:
Code:
#define CS_HIGH   {GPIOC_PSOR = (1 << 16); delayMicroseconds(100);}
#define CS_LOW    {GPIOC_PCOR = (1 << 16); delayMicroseconds(100);}
 
yep, i'm betting on CS changes are too fast compared to digitalWrite(), but i think delay sequence should be

Code:
#define CS_HIGH   { delayMicroseconds(100); GPIOC_PSOR = (1 << 16);}
#define CS_LOW    {GPIOC_PCOR = (1 << 16); delayMicroseconds(100);}
 
Signals from logical analyzer

1)
Code:
#include <SPI.h>

#define CS 10

byte lowByte, highByte;
int measurements;
double gyroscope_value_roll, gyroscope_sum_measurements_roll, gyroscope_average_roll;
double gyroscope_value_pitch, gyroscope_sum_measurements_pitch, gyroscope_average_pitch;
double gyroscope_value_yaw, gyroscope_sum_measurements_yaw, gyroscope_average_yaw;

void setup() {

  Serial.begin(9600);
  while(!Serial);

  SPI.begin();
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE3));

  pinMode(CS, OUTPUT);

  digitalWrite(CS, LOW);
  SPI.transfer(0x20 & 0x7F);
  SPI.transfer(0x0F);
  digitalWrite(CS, HIGH);

  digitalWrite(CS, LOW);
  SPI.transfer(0x22 & 0x7F);
  SPI.transfer(0x08);
  digitalWrite(CS, HIGH);

  digitalWrite(CS, LOW);
  SPI.transfer(0x23 & 0x7F);
  SPI.transfer(0x90);
  digitalWrite(CS, HIGH);

  Serial.print("Starting calibration...");
  for (measurements = 0; measurements < 5000; measurements ++) {
    read_gyroscope();
    gyroscope_sum_measurements_roll += gyroscope_value_roll;
    gyroscope_sum_measurements_pitch += gyroscope_value_pitch;
    gyroscope_sum_measurements_yaw += gyroscope_value_yaw;
    if(measurements%100 == 0)Serial.print(".");
    delay(4);
  }

  gyroscope_average_roll = gyroscope_sum_measurements_roll / 5000;
  gyroscope_average_pitch = gyroscope_sum_measurements_pitch / 5000;
  gyroscope_average_yaw = gyroscope_sum_measurements_yaw / 5000;

}

void loop() {

  
  read_gyroscope();
  print_output();
  delay(250);

}

void print_output()
{
  Serial.print("Pitch:");
  if(gyroscope_value_pitch >= 0)Serial.print("+");
  Serial.print(gyroscope_value_pitch/57.14286);               //Convert to degree per second
  if(gyroscope_value_pitch/57.14286 - 2 > 0)Serial.print(" NoU");
  else if(gyroscope_value_pitch/57.14286 + 2 < 0)Serial.print(" NoD");
  else Serial.print(" ---");
  Serial.print("  Roll:");
  if(gyroscope_value_roll >= 0)Serial.print("+");
  Serial.print(gyroscope_value_roll/57.14286);                //Convert to degree per second
  if(gyroscope_value_roll/57.14286 - 2 > 0)Serial.print(" RwD");
  else if(gyroscope_value_roll/57.14286 + 2 < 0)Serial.print(" RwU");
  else Serial.print(" ---");
  Serial.print("  Yaw:");
  if(gyroscope_value_yaw >= 0)Serial.print("+");
  Serial.print(gyroscope_value_yaw/57.14286);                 //Convert to degree per second
  if(gyroscope_value_yaw/57.14286 - 2 > 0)Serial.println(" NoR");
  else if(gyroscope_value_yaw/57.14286 + 2 < 0)Serial.println(" NoL");
  else Serial.println(" ---");

}

void read_gyroscope() {

  digitalWrite(CS, LOW);
  SPI.transfer(0x28 | 0x80);
  lowByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  digitalWrite(CS, LOW);
  SPI.transfer(0x29 | 0x80);
  highByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  gyroscope_value_roll = (int16_t)((highByte << 8) | lowByte);
  if (measurements == 5000)gyroscope_value_roll -= gyroscope_average_roll;

  digitalWrite(CS, LOW);
  SPI.transfer(0x2A | 0x80);
  lowByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  digitalWrite(CS, LOW);
  SPI.transfer(0x2B | 0x80);
  highByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  gyroscope_value_pitch = (int16_t)((highByte << 8) | lowByte);
  gyroscope_value_pitch *= -1;
  if (measurements == 5000)gyroscope_value_pitch -= gyroscope_average_pitch;

  digitalWrite(CS, LOW);
  SPI.transfer(0x2C | 0x80);
  lowByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  digitalWrite(CS, LOW);
  SPI.transfer(0x2D | 0x80);
  highByte = SPI.transfer(0x00);
  digitalWrite(CS, HIGH); 
  gyroscope_value_yaw = (int16_t)((highByte << 8) | lowByte);
  gyroscope_value_yaw *= -1;
  if (measurements == 5000)gyroscope_value_yaw -= gyroscope_average_yaw;

}

signal port PTC4,i get the measurements correctly from the gyroscope,the code is working properly.

2)
Code:
#include <SPI.h>

byte lowByte, highByte;
int measurements;
double gyroscope_value_roll, gyroscope_sum_measurements_roll, gyroscope_average_roll;
double gyroscope_value_pitch, gyroscope_sum_measurements_pitch, gyroscope_average_pitch;
double gyroscope_value_yaw, gyroscope_sum_measurements_yaw, gyroscope_average_yaw;

void setup() {

  PORTC_PCR16 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
  GPIOC_PDDR |= (1 << 16);
  
  Serial.begin(9600);
  while(!Serial);

  SPI.begin();
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE3));

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x20 & 0x7F);
  SPI.transfer(0x0F);
  GPIOC_PSOR = (1 << 16);

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x22 & 0x7F);
  SPI.transfer(0x08);
  GPIOC_PSOR = (1 << 16);

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x23 & 0x7F);
  SPI.transfer(0x90);
  GPIOC_PSOR = (1 << 16);

  Serial.print("Starting calibration...");
  for (measurements = 0; measurements < 5000; measurements ++) {
    read_gyroscope();
    gyroscope_sum_measurements_roll += gyroscope_value_roll;
    gyroscope_sum_measurements_pitch += gyroscope_value_pitch;
    gyroscope_sum_measurements_yaw += gyroscope_value_yaw;
    if(measurements%100 == 0)Serial.print(".");
    delay(4);
  }

  gyroscope_average_roll = gyroscope_sum_measurements_roll / 5000;
  gyroscope_average_pitch = gyroscope_sum_measurements_pitch / 5000;
  gyroscope_average_yaw = gyroscope_sum_measurements_yaw / 5000;

}

void loop() {

  delay(250);
  read_gyroscope();
  print_output();

}

void print_output()
{
  Serial.print("Pitch:");
  if(gyroscope_value_pitch >= 0)Serial.print("+");
  Serial.print(gyroscope_value_pitch/57.14286);               //Convert to degree per second
  if(gyroscope_value_pitch/57.14286 - 2 > 0)Serial.print(" NoU");
  else if(gyroscope_value_pitch/57.14286 + 2 < 0)Serial.print(" NoD");
  else Serial.print(" ---");
  Serial.print("  Roll:");
  if(gyroscope_value_roll >= 0)Serial.print("+");
  Serial.print(gyroscope_value_roll/57.14286);                //Convert to degree per second
  if(gyroscope_value_roll/57.14286 - 2 > 0)Serial.print(" RwD");
  else if(gyroscope_value_roll/57.14286 + 2 < 0)Serial.print(" RwU");
  else Serial.print(" ---");
  Serial.print("  Yaw:");
  if(gyroscope_value_yaw >= 0)Serial.print("+");
  Serial.print(gyroscope_value_yaw/57.14286);                 //Convert to degree per second
  if(gyroscope_value_yaw/57.14286 - 2 > 0)Serial.println(" NoR");
  else if(gyroscope_value_yaw/57.14286 + 2 < 0)Serial.println(" NoL");
  else Serial.println(" ---");

}

void read_gyroscope() {

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x28 | 0x80);
  lowByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x29 | 0x80);
  highByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  gyroscope_value_roll = (int16_t)((highByte << 8) | lowByte);
  if (measurements == 5000)gyroscope_value_roll -= gyroscope_average_roll;

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x2A | 0x80);
  lowByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x2B | 0x80);
  highByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  gyroscope_value_pitch = (int16_t)((highByte << 8) | lowByte);
  gyroscope_value_pitch *= -1;
  if (measurements == 5000)gyroscope_value_pitch -= gyroscope_average_pitch;

  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x2C | 0x80);
  lowByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  GPIOC_PCOR = (1 << 16);
  SPI.transfer(0x2D | 0x80);
  highByte = SPI.transfer(0x00);
  GPIOC_PSOR = (1 << 16);
  gyroscope_value_yaw = (int16_t)((highByte << 8) | lowByte);
  gyroscope_value_yaw *= -1;
  if (measurements == 5000)gyroscope_value_yaw -= gyroscope_average_yaw;

}

signal port PTC16
 
Last edited:
Again the two traces more or less confirm it, as both I and @manitou mentioned you probably need some delays!

When you have code like this:
Code:
 GPIOC_PSOR = (1 << 16);
  GPIOC_PCOR = (1 << 16);

There is only one instruction between setting the pin High and setting it back to low. The hardware is not picking this up and probably your hardware needs the change in CS, so again try adding some delay between these two lines of code. You may also may run into conditions where you may need other delays as well but maybe not. That is some hardware needs a delay between the time the CS is asserted (goes low) and the time that SPI IO lines. If you still have problems after you add a delay between these two lines. And again like pairs of statements...

If this does not get it working, you may want to also plot the other SPIO pins
 
You're configuring the pin for slew rate control, by using PORT_PCR_SRE.

Code:
  PORTC_PCR16 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);

Slew rate limiting is an awesome feature which greatly reduces noise and high-speed effects by limiting how fast the pin's voltage can change. While it does limit the speed somewhat, the reduction in high frequency noise and ringing are pretty incredible.

Teensy 3.5 is changing the pin much too fast for this mode.

Code:
  GPIOC_PSOR = (1 << 16);

  GPIOC_PCOR = (1 << 16);

This code can "change" the port output register faster than the pin's voltage can actually change with the slew rate limit effect.
 
And does it work? Note: When I put in 100 microsecond delay that was probably totally overkill. you might try something like 5 or 10...

And again it is hard to know with your tracing on how the CS pin signals relate to your other SPI signals (clk, mosi, miso). So again suggest you hook those up as well and then look at your trace. If it is still not working, you then may want to look at the traces again for both a CS pin that works and then your pin.
 
I added the pin PTC16 in the archives "core_pins.h" and "pins_tensy.c".

1) core_pins.h
Code:
i changed

#define CORE_NUM_TOTAL_PINS     64 --->65

#define CORE_NUM_DIGITAL           64 --->65

#define CORE_NUM_INTERRUPT       64 --->65

#define CORE_MAX_PIN_PORTC       11 ---> 12

i added

#define CORE_PIN64_BIT		16

#define CORE_PIN64_BITMASK	(1<<(CORE_PIN64_BIT))

#define CORE_PIN64_PORTREG	GPIOC_PDOR

#define CORE_PIN64_PORTSET	GPIOC_PSOR

#define CORE_PIN64_PORTCLEAR	GPIOC_PCOR

#define CORE_PIN64_DDRREG	GPIOC_PDDR

#define CORE_PIN64_PINREG	GPIOC_PDIR

#define CORE_PIN64_CONFIG	PORTC_PCR16

#define CORE_INT64_PIN		64

for digitalWrite routine

else if (pin == 64) {
CORE_PIN64_PORTSET = CORE_PIN64_BITMASK; 
}

for digitalRead routine

else if (pin == 64) {
return (CORE_PIN64_PINREG & CORE_PIN64_BITMASK) ? 1 : 0;
}

2) pins_tensy.c
Code:
i added

{GPIO_BITBAND_PTR(CORE_PIN64_PORTREG, CORE_PIN64_BIT),
&CORE_PIN64_CONFIG},

I run the code with the digitalWrite and i get right measurements from the gyroscope.
I need to add something else in these or some other files?
 
Last edited:
I added the pin PTC16 in the archives "core_pins.h" and "pins_tensy.c".

I run the code with the digitalWrite and i get right measurements from the gyroscope.
I need to add something else in these or some other files?

Ahhh, that's probably the best solution. :D
 
And does it work? Note: When I put in 100 microsecond delay that was probably totally overkill. you might try something like 5 or 10...

Νo i can't read the gyroscope.I changed the delay time many times without effect.
 
Again if still experimenting, again look at differences in timings using digitalWrite and manipulating the pins directly. Again in relationship to the other signals. Like when you assert CS how much time is there before the clk signal changes... Likewise at the end, after the last clock, how long until the CS is unasserted....

But again I prefer the solution you did to add it as a real pin...

As to wanting/needing to do anything else with it. It depends on what your plans are and how thorough you wish to be. Example:

I believe that C16 has some alternative functionality: PTC16 DISABLED PTC16 CAN1_RX UART3_RX ENET0_1588_TMR0 ...
So for example you could update the Serial code to allow Serial4 to use this as an alternate pin for RX, probably likewise for CAN1_RX... Although I have not played with CAN stuff so not sure what that takes.
 
Again if still experimenting, again look at differences in timings using digitalWrite and manipulating the pins directly. Again in relationship to the other signals. Like when you assert CS how much time is there before the clk signal changes... Likewise at the end, after the last clock, how long until the CS is unasserted....

I just wanted to know why it does not work,we ended up having to do with the time lags,i will experiment and tell you the results.:D
About the pin PTC16 i need to add something else in these files(post35)?
Do they need other changes to other files?
 
Last edited:
Hello again,
I added additionally the pins PTA24, PTA25, PTA27 and PTC16 in the archives "core_pins.h" and "pins_tensy.c".

1) core_pins.h
Code:
[B]i changed[/B]

#define CORE_NUM_TOTAL_PINS     64 ---> 68

#define CORE_NUM_DIGITAL           64 ---> 68
 
#define CORE_NUM_INTERRUPT       64 ---> 68

#define CORE_MAX_PIN_PORTC       11 ---> 12

#define CORE_MAX_PIN_PORTA       29 ---> 32

[B]i added[/B]

#define CORE_PIN64_BIT		16

#define CORE_PIN65_BIT		24

#define CORE_PIN66_BIT		25

#define CORE_PIN67_BIT		27


#define CORE_PIN64_BITMASK	(1<<(CORE_PIN64_BIT))

#define CORE_PIN65_BITMASK	(1<<(CORE_PIN65_BIT))

#define CORE_PIN66_BITMASK	(1<<(CORE_PIN66_BIT))

#define CORE_PIN67_BITMASK	(1<<(CORE_PIN67_BIT))


#define CORE_PIN64_PORTREG	GPIOC_PDOR

#define CORE_PIN65_PORTREG	GPIOA_PDOR

#define CORE_PIN66_PORTREG	GPIOA_PDOR

#define CORE_PIN67_PORTREG	GPIOA_PDOR


#define CORE_PIN64_PORTSET	GPIOC_PSOR

#define CORE_PIN65_PORTSET	GPIOA_PSOR

#define CORE_PIN66_PORTSET	GPIOA_PSOR

#define CORE_PIN67_PORTSET	GPIOA_PSOR


#define CORE_PIN64_PORTCLEAR	GPIOC_PCOR

#define CORE_PIN65_PORTCLEAR	GPIOA_PCOR

#define CORE_PIN66_PORTCLEAR	GPIOA_PCOR

#define CORE_PIN67_PORTCLEAR	GPIOA_PCOR


#define CORE_PIN64_DDRREG	GPIOC_PDDR

#define CORE_PIN65_DDRREG	GPIOA_PDDR

#define CORE_PIN66_DDRREG	GPIOA_PDDR

#define CORE_PIN67_DDRREG	GPIOA_PDDR


#define CORE_PIN64_PINREG	GPIOC_PDIR

#define CORE_PIN65_PINREG	GPIOA_PDIR

#define CORE_PIN66_PINREG	GPIOA_PDIR

#define CORE_PIN67_PINREG	GPIOA_PDIR


#define CORE_PIN64_CONFIG	PORTC_PCR16

#define CORE_PIN65_CONFIG	PORTA_PCR24

#define CORE_PIN66_CONFIG	PORTA_PCR25

#define CORE_PIN67_CONFIG	PORTA_PCR27


#define CORE_INT64_PIN		64

#define CORE_INT65_PIN		65

#define CORE_INT66_PIN		66

#define CORE_INT67_PIN		67


[B]for digitalWrite routine[/B]

else if (pin == 64) {
   CORE_PIN64_PORTSET = CORE_PIN64_BITMASK; 
}

else if (pin == 65) {
   CORE_PIN65_PORTSET = CORE_PIN65_BITMASK; 
}

else if (pin == 66) {
   CORE_PIN66_PORTSET = CORE_PIN66_BITMASK; 
}

else if (pin == 67) {
   CORE_PIN67_PORTSET = CORE_PIN67_BITMASK; 
}


[B]for digitalRead routine[/B]

else if (pin == 64) {
return (CORE_PIN64_PINREG & CORE_PIN64_BITMASK) ? 1 : 0;
}

else if (pin == 65) {
   return (CORE_PIN65_PINREG & CORE_PIN65_BITMASK) ? 1 : 0;
}

else if (pin == 66) {
   return (CORE_PIN66_PINREG & CORE_PIN66_BITMASK) ? 1 : 0;
}

else if (pin == 67) {
   return (CORE_PIN67_PINREG & CORE_PIN67_BITMASK) ? 1 : 0;
}

2) pins_tensy.c
Code:
[B]i added[/B]

{GPIO_BITBAND_PTR(CORE_PIN64_PORTREG, CORE_PIN64_BIT),&CORE_PIN64_CONFIG},

{GPIO_BITBAND_PTR(CORE_PIN65_PORTREG, CORE_PIN65_BIT), &CORE_PIN65_CONFIG},

{GPIO_BITBAND_PTR(CORE_PIN66_PORTREG, CORE_PIN66_BIT), &CORE_PIN66_CONFIG}, 

{GPIO_BITBAND_PTR(CORE_PIN67_PORTREG, CORE_PIN67_BIT), &CORE_PIN67_CONFIG},

I tried the new pins with the program below but only pin 64(PTC16) blinks the led.
Why is this happening?

Code:
int led1 = 64;
int led2 = 65;
int led3 = 66;
int led4 = 67;

void setup() {                
 
  pinMode(led1, OUTPUT);  
  pinMode(led2, OUTPUT); 
  pinMode(led3, OUTPUT); 
  pinMode(led4, OUTPUT);    
}

void loop() {
  digitalWrite(led1, HIGH);digitalWrite(led2, HIGH); digitalWrite(led3, HIGH);digitalWrite(led4, HIGH);
  delay(2000);               
  digitalWrite(led1, LOW);digitalWrite(led2, LOW);digitalWrite(led3, LOW);digitalWrite(led4, LOW);       
  delay(2000);               
}
 
Last edited:
In my project i want to use two spi channels, SPI1 and SP2 at 10Mhz.
They can work at the same time or i'll have to stop each channel sequentially??
 
Hi Thanos,

Are you asking if you can use both at the same time? The answer is yes, but...

The but is if you do something like:
Code:
    SPI1.transfer(buffer1, sizeof(buffer1));
    SPI2.transfer(buffer2, sizeof(buffer2));
Or other similar variants, the library code will wait until SPI1 finishes it's transfer before it returns to start SPI2's transfer, which it will wait for...

But we did add an non-blocking version of the transfer call using the event responder. There was a discussion recently about this in the thread: https://forum.pjrc.com/threads/5379...nsfer-function?p=187663&viewfull=1#post187663

In there I had an example program, that used SPI and SPI1, which just as easily work for SPI1 and SPI2...
Here is a copy of that program... (I did not edit for SPI1 and 2...)
Code:
#include <SPI.h>

EventResponder event;
EventResponder event1;

uint8_t buffer0[100];
uint8_t buffer1[100];
volatile bool spi_active = false;
volatile bool spi1_active = false;

void Event_SPI0_Responder(EventResponderRef event_responder) {
  digitalWriteFast(2, HIGH);
  SPI.endTransaction();
  Serial.println("SPI0 ended");
  spi_active = false;
}
void Event_SPI1_Responder(EventResponderRef event_responder) {
  digitalWriteFast(3, HIGH);
  SPI1.endTransaction();
  Serial.println("SPI1 ended");
  spi1_active = false;
}

void setup() {
  while (!Serial && (millis() < 2000)) ;
  Serial.println("Test SPI DMA on SPI and SPI1");

  pinMode(2, OUTPUT);
  digitalWriteFast(2, HIGH);
  SPI.begin();
  event.attachImmediate(&Event_SPI0_Responder);
  for (int i = 0; i < sizeof(buffer0); i++) buffer0[i] = i;

  pinMode(3, OUTPUT);
  digitalWriteFast(3, HIGH);
  SPI1.begin();
  event1.attachImmediate(&Event_SPI1_Responder);
  for (int i = 0; i < sizeof(buffer1); i++) buffer1[i] = sizeof(buffer1) - i;
}

void loop() {
  Serial.println("Start Two SPI transfers");
  spi_active = true;
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  digitalWriteFast(2, LOW);
  SPI.transfer(buffer0, nullptr, sizeof(buffer0), event);

  spi1_active = true;
  SPI1.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  digitalWriteFast(3, LOW);
  SPI1.transfer(buffer1, nullptr, sizeof(buffer1), event1);

  while (spi_active || spi1_active) ; // wait until both are done
  Serial.println("Both done");
  delay(1000);  // wait a second

}
 
Status
Not open for further replies.
Back
Top