Teensie 3.6 SPI communication not getting SCK signal as an output

Status
Not open for further replies.
Hi, I am new to embedded programing recently I bought a Teensie 3.6 board to learn programming for a University project. I was trying to use the SPI library to communicate with an absolute encoder. I have connected MOSI to pin 11, MISO to pin 12 (not needed for the encoder), SCK at pin 13, and CS of the absolute encoder at pin 25. At the same bus I have two other slave device and for this reason I keep pins 10 and 24 high.
I measured with an oscilloscope the output of pin 13 but it seems i am not getting the clock signal as an output. Is there an issue with my code. As a final goal I would like to create a sketch that gives the output data of the abs.encoder in binary form. (Attached is the manual of the encoder not necessary at this point. Between the Teensie board and the abs.encoder i use a differential driver for my clock signal and a differential receiver for the data signals.)

Code:
#include <SPI.h>  // include the SPI library:

const int ssimu = 10;
const int sshand = 24;
const int ssfork = 25;

void setup() {
  // set the slaveSelectPin as an output:
  pinMode (ssimu, OUTPUT);
  pinMode (sshand, OUTPUT);
  pinMode (ssfork, OUTPUT);

  
  // initialize SPI:
 
  SPI.begin(); 
  Serial.begin(9600); 
}

void loop() {
  
// take the SS pin high to de-select the chip:
  digitalWrite(ssimu,HIGH); 
 // take the SS pin high to de-select the chip:
  digitalWrite(sshand,HIGH); 
  // take the SS pin low to select the chip:
  digitalWrite(ssfork,LOW); 
}
 

Attachments

  • Data-sheet-RMB20-magnetic-encoder .pdf
    599.6 KB · Views: 251
  • sn75c1168.pdf
    965.9 KB · Views: 98
Last edited:
I may be missing something, but I don't see anything here that uses SPI, other than the begin, which should change the SPI pins (11, 12, 13) to SPI mode.
But does not cause them to do anything unless you so something like: SPI.transfer...

For example if you wish to read 3 bytes from MISO you might have code in your loop like:
Code:
void loop() {
...
  SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0));  // not sure what speed you want here?
  digitalWrite(ssfork, LOW); 
  uint8_t val1 = SPI.transfer(0);
  uint8_t val2 = SPI.transfer(0);
  uint8_t val3 = SPI.transfer(0);
  digitalWrite(ssfork.HIGH);
  SPI.endTransaction();
The idea is that you call begin transaction to tell the system what format your data is and what speed it should be.
You then need to do transfer calls, which always outputs what you say on MOSI and takes what comes in on MISO and returns it to you as the return value from the transfer
The end transaction is mostly validation code, to say I am done...
 
;) Thank you for your help so far. I would like to also know how I can print the data coming as an output from MISO (pin 12) in the serial port. The encoder than I am using is RMB20SC (13 bit resolution with MSB coming first).
 
Last edited:
Careful. from your pdf datasheets, your devices are 5v. the teensy 3.6 is NOT 5v tolerant, so you will need voltage level shifters to convert between 5v and 3v3. also the RMB20SC appears to be RS422 and not SPI ????
 
I might do something like:

Code:
void loop() {
...
  uint8_t buffer[4];
  SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0));  // not sure what speed you want here?
  digitalWrite(ssfork, LOW);
  // Transfer 4 bytes, we don't care about output value so pass null, and result goes into buffer. 
  SPI.transfer(nullptr, buffer, 4); 
  digitalWrite(ssfork.HIGH);
  SPI.endTransaction();
  uint32_t value = (uint32_t)(buffer[0] << 24) | (uint32_t)(buffer[1] << 16) | (uint32_t)(buffer[2] << 8) | (uint32_t)buffer[3];
  Serial.println(value, DEC);
...
Note: typed in on the fly so could be issues. Also uses newer version of SPI.transfer, so need a reasonably up to date version of Teensyduino...

I have not looked at what device you are using to know things like, how fast you can ask for new values and/or is there an interrupt pin that says I have new value you can configure in or...
 
Good catch Manitou! I'm looking at the datasheet too.

;)The encoder than I am using is RMB20SC (32 bit resolution with MSB coming first).

I'm looking at the info on page 5, but I can't see anywhere that says to expect 32 bits. Did I miss something?

To make this work at all, you're going to need at least a RS422 transmitter from Teensy pin 13 (SCK) to the Clock+ and Clock- pins on the encoder, and a RS422 receiver from the Data+ and Data- pins on the encoder to Teensy pin 12 (MISO). Do you have that circuitry connected? Are you sure it's done properly? There's a lot of opportunity for things to be not connected properly....

Obviously there is no chip select signal on this encoder. You can perhaps make one with the driver and receiver enable signals on that RS422 chip. But you're going to need to use 2 pins on Teensy, or add an inverter, since the driver enable is active high and the receiver enable is active low. To "select" this encoder, you're going to need to drive DE high AND drive RE low. To deselect it, so you can talk to other SPI chips on SCK & MISO, you'll need to driver DE low B]AND[/B] drive RE high. You might also need to add resistors to the Clock+ and Clock- lines, so the encoder still sees the proper idle state when the driver is turned off.

Perhaps for testing you should just connect RE low and DE high, so they're always enabled. This project has a lot of circuitry that needs to all be connected properly before you can even have any hope of getting the software side working. Simplifying things as much as possible would be a good idea. If you have any way to watch with a scope or logic analyzer, you really should check that the clock signal is reaching both Clock+ and Clock-, and both Data+ and Data- are responding with *something*, which really is reaching Teensy pin 12 (MISO).

Kurt's code looks correct, except this part appears to have a 4 MHz maximum clock. For testing, I'd recommend using much slower, like 250 kHz or less. Some RS422/485 chips are limited in speed. Save yourself a lot of headaches by testing at low speed, and then try faster after you know everything else is working.

To specifically answer your question:

I would like to also know how I can print the data coming as an output from MISO

The function SPI.transfer(b) causes SCK to pulse 8 times, and the data you give it (b) to be output on MISO, and whatever voltage was present on MISO gets returned.

So the code looks like this:

Code:
  uint8_t mybyte;
  mybyte = SPI.transfer(0);
  Serial.println(mybyte);

SPI.transfer() does everything. Then you use Serial.println() to send the data to the Arduino Serial Monitor.

If you're new to all this, I'd highly recommend just putting some Serial.println() functions into your program with fixed data and make sure you can open the Arduino Serial Monitor and see the known data. That's how pretty much everything works with electronics... take small steps and check everything at every step to know it works. Then as you try more and something doesn't work, at least you know for sure the pieces you've already tested worked.
 
That is correct I am just using SPI Library to initiate the clock signal also for my RS422 devices. I am using lever shifters to protect my board and also differential drivers and receiver where needed. I was only asking how this could be implemented software wise. The only problem that I am facing right now is that my absolute encoder is 13bit and I am only reading 8 bits with this command uint8_t mybyte; and I need to read 13 bits=8192 (not 32 as previously mentioned in my post). Since now the data I receive are not correct but of course change with the rotation of the actuation magnet of my encoder. I checked step by step everything with an oscilloscope and a signal generator device. So I guess i need to find a way to read 13 bits. Thank you so far for your help any tips are more than welcome.
 
Last edited:
I checked step by step everything with an oscilloscope and a signal generator device.

Maybe you could share a little more about this testing?

I know you're probably only focused on getting the answer you seek, but long-term this thread will likely be found by searching. Maybe this info could help others who later find this conversation?

Also, showing that things really are working hardware-wise, actually seeing the real effort you've already done, is inspiring to all of us who spend our limited time into trying to answer your questions....

So I guess i need to find a way to read 13 bits. Thank you so far for your help any tips are more than welcome.

The SPI library only supports 8 and 16 bits. But the hardware does have more flexibility. To access it, you'll need to directly use the SPI registers. The CTAR register configures the number of bits and other parameters of the data format. Maybe you could just make a copy of the SPI lib and edit the settings used by SPI.transfer16() to do only 13 bits.

When/if you get this working, I really hope you'll consider sharing the result? Remember, long-term people will find this thread by searching.
 
PaulStoffregen I will share the hardware and software as soon as I finish. I will try to change the settings of SPI.transfer16() to do only 13 bits tommorow. I was also thinking somehow reading the 16 bits and then getting rid off the 3 MSB but I am not sure if this is the best approach?
 
Last edited:
Connection between RMB20SC and teensie 3.6

As promised attached is the schematic showing the connection between the RMB20SC encoder and the components needed to interface it with teensie 3.6. PA5 is the sck connected to (pin13 of the teensie board) PA4 and PA5 are the ss for my two encoders (pin 24,25 of the teensie board) and PA6 is the MISO (pin 13 of teensie). The encoders and components U7 and U8 are power by an external 5V supply. Clock signals of enc1 are connected at pins 14,11 of U7 receiver and for my second encoder at pins 10 and 13 of U7. Data signals are connected at pins 2 and 1 and pins 6 and 7 of U7 driver. Below is the sketch that I am using to generate the clock signal. To check MISO independent i just input a 3.3 V at MISO (pin 13) if I have uint8_t mybyte; I receive 255 as an output of my serial port, however when I change uint16_t mybyte; I still receive 255 shouldn't I receive 65535 is something wrong with the library or do I miss something code wise. I am trying to check that everything is working properly before I try to change the CTAR register of the SPI library to make it possible to read 13 bits. Thank you so far for the effort.


Code:
#include <SPI.h>  // include the SPI library:

const int ssimu = 10;
const int sshand = 24;
const int ssfork = 25;
const int pwrencoders = 26;


void setup() {
  // set the slaveSelectPin as an output:
  
  pinMode (ssimu, OUTPUT);
  pinMode (sshand, OUTPUT);
  pinMode (ssfork, OUTPUT);
  pinMode (pwrencoders, OUTPUT);
  // initialize SPI:
 
  SPI.begin(); 
   Serial.begin(500000);
}


void loop() {
  digitalWrite(ssimu,HIGH); 
  digitalWrite(sshand,HIGH); 
  digitalWrite(pwrencoders,LOW); 
  digitalWrite(ssfork,LOW); 
  
  SPI.beginTransaction(SPISettings(125000, MSBFIRST, SPI_MODE0));  
  
uint8_t mybyte; 
 
  mybyte = SPI.transfer(0);
 

   Serial.print("Fork(deg)");
  Serial.println(mybyte); 
 
}
 

Attachments

  • Connection.jpg
    Connection.jpg
    43.3 KB · Views: 142
  • sn74aup2g32.pdf
    1,011.2 KB · Views: 86
  • sn74lvc2g125-q1.pdf
    780.3 KB · Views: 100
  • sn75c1168.pdf
    965.9 KB · Views: 98
Last edited:
I was also thinking somehow reading the 16 bits and then getting rid off the 3 MSB but I am not sure if this is the best approach?
I was wondering what your RS422 device would do if you clock 16 bits when it's expecting only 13. if you just get 3 garbage bits and everything stays in synch for the next request, then you should wouldn't need to modify the SPI lib. just do 16-bit transfers and mask/shift off the garbage bits.

for SPI testing, you can just jumper MISO to MOSI, and see if you get back what you send out. Do have a scope or logic analyzer to watch the bits fly?

if MISO is unconnected, you should get back 0's from SPI.transfer(), and if you have 3v3 on MISO, you should get back 255 for 8-bit transfer and 65535 for SPI.transfer16()

Here is analyzer snapshot of 4 8-bit transfers and 1 16-bit transfer with MISO jumpered to MOSI
Code:
  v=SPI.transfer(255);
  v=SPI.transfer(255);
  v=SPI.transfer(0);
  v=SPI.transfer(255);
  v=SPI.transfer16(1234);

spitmp.png
 
Last edited:
Thank you manitou. I tried it out the SPI library works fine. I am trying to mask off the last 3 garbage bits to get the DAC number coming as an output of my encoder but since I am a newbie I am struggling doing that. I guess I have to read more. Thank you for the feedback so far.
 
to get rid of low-order 3 bits of uint16_t x, x = x>>3;

to mask off high-order 3 bits, x = x & 0x1fff;
 
Thank you manitou. Below is my code. it is working and I am able to get the counts as an output of the encoder. After checking the manual again I realized that I need to mask out the first MSB bit and also the two LSB. I manage to get rid off the two LSB and now I am trying to get rid of the MSB. Do you maybe know how I can do that? otherwise i will keep on reading.......

Code:
#include <SPI.h>  // include the SPI library:

const int ssimu = 10;
const int sshand = 24;
const int ssfork = 25;
const int pwrencoders = 26;


void setup() {
  // set the slaveSelectPin as an output:
  
  pinMode (ssimu, OUTPUT);
  pinMode (sshand, OUTPUT);
  pinMode (ssfork, OUTPUT);
  pinMode (pwrencoders, OUTPUT);
  // initialize SPI:
 
  SPI.begin(); 
   Serial.begin(500000);
}


void loop() {
  digitalWrite(ssimu,HIGH); 
  digitalWrite(sshand,LOW); 
  digitalWrite(pwrencoders,HIGH); 
  digitalWrite(ssfork,HIGH); 
  
  SPI.beginTransaction(SPISettings(125000, MSBFIRST, SPI_MODE3));  
  
uint16_t mybyte;
mybyte= SPI.transfer16(0);
  uint16_t mybyte1;
 
 
 mybyte1 = mybyte>>2;

 
 SPI.endTransaction();
 delayMicroseconds(20);
   Serial.print("Fork(deg)");
   Serial.println(mybyte1); 
 
}
 
Last edited by a moderator:
to get rid off the two LSB and now I am trying to get rid of the MSB

Code:
[B]mybyte1 = (mybyte & 0x7fff)>>2;[/B]

To retain indentation in your posts you should use CODE tags (# button) when including code.

good job.
 
Last edited:
Status
Not open for further replies.
Back
Top