0

SPI on the Trinket M0
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

SPI on the Trinket M0

by maxthomas on Tue Jul 02, 2019 12:29 pm

Hi, I'm trying to use a Trinket M0 to communicate with a Trinamic stepper motor driver board through SPI and have not been able to get the SPI interface to work.

I have a test sketch that sets some config registers and then polls the driver for speed and status. The sketch compiles and runs fine, but every bit I receive back from the driver is a 0.

I initially wrote this using the built-in SPI class, and then tried defining my own SPI SERCOM using the instructions here, with the same results. I have Arduino SAMD Boards v1.8.2 and Adafruit SAMD Boards v1.5.1 installed.

If I take this exact sketch (with the standard SPI class) and run it on an old Arduino UNO I have here, it works perfectly and communicates with the motor driver fine. The motor driver is 3.3 & 5V compatible so I don't think the voltage difference between these two boards is the issue.

Is there anything else I need to do to get SPI running on a Trinket M0?

SKETCH:
Code: Select all | TOGGLE FULL SIZE
#include <SPI.h>
#include "wiring_private.h" // pinPeripheral() function

// pin defs
const int PIN_CS = 0;
const int PIN_ENABLE = 1;

// SPI config
SPIClass tmcSPI (&sercom0, 2, 3, 4, SPI_PAD_2_SCK_3, SERCOM_RX_PAD_1);

uint8_t status_response = 0;
uint32_t response = 0;

void setup() {
  pinMode(PIN_CS, OUTPUT);
  pinMode(PIN_ENABLE, OUTPUT);

  digitalWrite(PIN_CS, HIGH); // SPI CS off
  digitalWrite(PIN_ENABLE, HIGH); // driver disable

  Serial.begin(9600);
  delay(2000); // not getting serial text in the console without this delay
  Serial.println("TMC5160 SPI");

  tmcSPI.begin();

  pinPeripheral(2, PIO_SERCOM_ALT);
  pinPeripheral(3, PIO_SERCOM_ALT);
  pinPeripheral(4, PIO_SERCOM);

  // TRINAMIC CONFIG
  writeReg(0x0B,0x00000080); // GLOBAL SCALER: 128
  writeReg(0x10,0x000C1F1F); // IHOLD_IRUN: IHOLD=31, IRUN=31 (max. current), IHOLDDELAY=6
  writeReg(0x11,0x0000000A); // TPOWERDOWN=10: Delay before power down in stand still
  writeReg(0x00,0x00000004); // GCONF: EN_PWM_MODE=1 enables StealthChop
  writeReg(0x80,0xC40C001E); // PWMCONF:  1100 0100 00 00 1 1 00 00000000 00011110
  writeReg(0x6C,0x128105C8); // CHOPCONF: 0 0 0 1 0010 1000 0 0 0 10 0 0 0 0 1011 100 0011
  writeReg(0x13,0x000000FF); // TPWM_THRS=512
  writeReg(0x15,0x00000080); // THIGH = 128
 
  digitalWrite(PIN_ENABLE, LOW); // driver enable

  // wait a beat for stealthChop autoconfigure and then set final current levels
  delay(250);
  writeReg(0x10,0x000C1F0A); // IHOLD_IRUN: IHOLD=10, IRUN=31 (max. current), IHOLDDELAY=6
  delay(250);
}

void loop() {
  response = readReg(0x12); // motor speed in clock cycles/step
  Serial.print("TSTEP: ");
  Serial.println(response);

  response = readReg(0x72); // stealthChop auto config value
  Serial.print("StealthChop: ");
  Serial.println(response, BIN);

  delay(1000);
}

uint32_t readReg(uint8_t address) {
  uint32_t tmc_response = 0;

  beginTMC();
  tmcSPI.transfer(address);
  tmcSPI.transfer(0x00);
  tmcSPI.transfer(0x00);
  tmcSPI.transfer(0x00);
  tmcSPI.transfer(0x00);
  endTMC();

  delayMicroseconds(1);

  beginTMC();
  tmcSPI.transfer(address);
  tmc_response |= tmcSPI.transfer(0x00) << 24;
  tmc_response |= tmcSPI.transfer(0x00) << 16;
  tmc_response |= tmcSPI.transfer(0x00) << 8;
  tmc_response |= tmcSPI.transfer(0x00);
  endTMC();

  return tmc_response;
}

uint8_t writeReg(uint8_t address, uint32_t data) {
  beginTMC();

  // send address
  status_response = tmcSPI.transfer(address | 0x80);

  // send new value
  tmcSPI.transfer((data & 0xFF000000) >> 24);
  tmcSPI.transfer((data & 0xFF0000) >> 16);
  tmcSPI.transfer((data & 0xFF00) >> 8);
  tmcSPI.transfer(data & 0xFF);
  endTMC();

  Serial.print("Wrote to reg: ");
  Serial.print(address, HEX);
  Serial.print(" status received: ");
  Serial.println(status_response, BIN);

  return status_response;
}

void beginTMC() {
  tmcSPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE3));
  chipSelect(true);
}

void endTMC() {
  chipSelect(false);
  tmcSPI.endTransaction();
}

void chipSelect(bool select) {
  digitalWrite(PIN_CS, select?LOW:HIGH);
  if (select)
    delayMicroseconds(100);
}


SAMPLE RESPONSE FROM DRIVER:
Code: Select all | TOGGLE FULL SIZE
TMC5160 SPI
Wrote to reg: B status received: 0
Wrote to reg: 10 status received: 0
Wrote to reg: 11 status received: 0
Wrote to reg: 0 status received: 0
Wrote to reg: 80 status received: 0
Wrote to reg: 6C status received: 0
Wrote to reg: 13 status received: 0
Wrote to reg: 15 status received: 0
Wrote to reg: 10 status received: 0
TSTEP: 0
StealthChop: 0
TSTEP: 0
StealthChop: 0
TSTEP: 0
StealthChop: 0
TSTEP: 0


WIRING:
(see attached photo)
Code: Select all | TOGGLE FULL SIZE
TRINKET   -->   TRINAMIC
GND             GND
3V              VCC_IO
D0              CSN
D1              DRV_ENN
D2              SDO
D3              SCK
D4              SDI


If needed, the datasheets for the Trinamic board & IC are here, however I believe the communication code is good since it runs fine on the UNO.
Board
IC


Any advice is appreciated, thanks!
Attachments
IMG_1609.jpg
IMG_1609.jpg (258.06 KiB) Viewed 143 times

maxthomas
 
Posts: 2
Joined: Tue Jan 18, 2011 5:32 pm

Re: SPI on the Trinket M0

by XRAD on Tue Jul 02, 2019 8:00 pm

If it works fine on UNO, then sounds like something is muxed up a bit on your M0 SPI pin defines....

XRAD
 
Posts: 501
Joined: Sat Nov 19, 2016 3:28 pm

Re: SPI on the Trinket M0

by maxthomas on Wed Jul 03, 2019 1:08 pm

Is there any reference on what those pin defines should be for the Trinket? I tried both the SPI class (no custom pin definition) and defining my own using the mux chart here.

Assuming I'm reading that right, these are the only pin options for the Trinket:

Code: Select all | TOGGLE FULL SIZE
MISO    D2 or D0
SCK     D3 only
MOSI    D4 only


I did realize I had the pinPeripheral assignments incorrect above, it should be set like this:

Code: Select all | TOGGLE FULL SIZE
  pinPeripheral(2, PIO_SERCOM);
  pinPeripheral(3, PIO_SERCOM_ALT);
  pinPeripheral(4, PIO_SERCOM_ALT);


This doesn't fix the issue, but it does cause me to receive every bit as a 1 instead of a 0...

Switching MISO to D0, I do get a different result– I get B1001/decimal 9 back for every command:

Code: Select all | TOGGLE FULL SIZE
** Serial console with MISO on D0 **
TSTEP: 9
StealthChop: 1001
TSTEP: 9
StealthChop: 1001
TSTEP: 9
StealthChop: 1001


Cutting power to the motor driver makes this revert back to all 1s, so there does seem to be some signal being received. Still, I don't receive any actual data, and the motor driver doesn't enable meaning it's not receiving/understanding the commands from the Trinket either.

maxthomas
 
Posts: 2
Joined: Tue Jan 18, 2011 5:32 pm

Re: SPI on the Trinket M0

by XRAD on Thu Jul 04, 2019 12:11 pm

probably need to read through the the ATSAM21D data sheets (will describe what each pin is capable of: https://cdn.sparkfun.com/datasheets/Dev ... asheet.pdf )

and :
https://learn.adafruit.com/adafruit-tri ... no/pinouts

Correlate this with the actual board connections, if you have not done this already....

XRAD
 
Posts: 501
Joined: Sat Nov 19, 2016 3:28 pm

Please be positive and constructive with your questions and comments.