ICSP arduino zero

Hi,

I have a connection over SPI.h on the arduino uno.

Now I want to do it with the zero. How do I adress for example the MISO pin?
At best I would like to define it in the SPI file. Is this possible?

Thanks

SPI.h is not board specific. they are defined in pins_arduino.h in variants

the names are MOSI, MISO, SCK

Hi thanks for the fast and informative answer.

This are all pins_arduino.h files I can find.

./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/robot_control/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/yun/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/leonardo/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/ethernet/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/eightanaloginputs/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/standard/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/mega/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/circuitplay32u4/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/micro/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/gemma/pins_arduino.h
./arduino-1.8.7-linux64/arduino-1.8.7/hardware/arduino/avr/variants/robot_motor/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/arduino_mzero/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkrwan1300/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkrwifi1010/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkrgsm1400/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkr1000/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkrzero/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/mkrfox1200/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/circuitplay/pins_arduino.h
./.arduino15/packages/arduino/hardware/samd/1.6.19/variants/arduino_zero/pins_arduino.h

I my SPI.h file, the there the Arduino.h file is included and in the Arduino.h file the variant.h file is included.
But does the linker take the right one from the folder arduino_zero? The same folder where the pins_arduino.h file is in it?
Since in the Arduino IDE the right board is choosen, it should work, but I don’t think so.

Thanks

yes, it should work. and what doesn't?

there is a catch. SS is defined as dummy, because SAMD as SPI slave is configured differently then on AVR

The problem is if I use a imu, namly the ADIS 16460 the port gets greyed out in the Arduino IDE.

If I use this code line, the IDE doesn't recognize the port anymore.

ADIS16460 imu(10, 2, 9); // Arguments: Chip Select, Data Ready, Reset Pin Assignments.

The problem is probably the arguments: 10,2,9. They work for the Uno, but not now for the zero.
What does this mean "SS is defined as dummy"? And I think I can use the pins <= 10, only 11 (Mosi), 12(Miso), 13 (SCK) I can't use for the zero.

Thanks

gab27:
The problem is if I use a imu, namly the ADIS 16460 the port gets greyed out in the Arduino IDE.

If I use this code line, the IDE doesn't recognize the port anymore.

ADIS16460 imu(10, 2, 9); // Arguments: Chip Select, Data Ready, Reset Pin Assignments.

The problem is probably the arguments: 10,2,9. They work for the Uno, but not now for the zero.
What does this mean "SS is defined as dummy"? And I think I can use the pins <= 10, only 11 (Mosi), 12(Miso), 13 (SCK) I can't use for the zero.

Thanks

so you connected on ICSP header the spi pins, vcc and ground and the CS, data and reset pins to 10, 2, 9. it should work. the port is grayed out because if the sketch hangs the port is not handled. the sketch handles the USB too

what do you mean with "if the sketch hangs the port is not handled." That's really bad? I don't have any connection.

Hi gab27,

On the Arduino Uno the SPI pins (SCK, MISO and MOSI) use digital pins 11, 12 and 13, but also happen to be broken out on the 6 pin (2x3 way) ICSP connector as well.

On the Arduino Zero by contrast, the SPI pins are broken out on the 6 pin ICSP connector like the Uno, but the digital pins 11, 12 and 13 are separate and can be used for other functions. It is however possible to reconfigure one of the Arduino Zero's spare serial communication (SERCOM) modules as a SPI port on digital pins 11, 12 and 13, if that's a requirement.

Adafruit have an excellent tutorial on configuring the SAMD21's SERCOM modules for extra I2C, SPI and Serial ports: Overview | Using ATSAMD21 SERCOM for more SPI, I2C and Serial ports | Adafruit Learning System.

Hi martin

I have gone through this. But I think that is not my problem anymore.

The problem is that the command I have posted before

ADIS16460 imu(10, 2, 9); // Arguments: Chip Select, Data Ready, Reset Pin Assignments.

doesn't work and I don't know why.

Edit: I went through this adafruit tutorial. I think the problem is really this command above, which works for the Uno, but not for the zero.

Thanks

Hi gab27,

Are you using the ICSP connector on the Arduino Zero for the SPI SCK, MISO and MOSI signals, as Juraj suggested?

I had a look at the ADIS16460 library: GitHub - juchong/ADIS16460-Arduino-Teensy: Example C++ library and arduino project for the ADIS16460 and Teensy development platform..

If it works on the Arduino Uno it should also work on the Zero. There doesn't appear to be any processor specific code.

yes and yes

I have to think over it

Which library are you actually using?
It’s quite possible that it doesn’t support both uno and m0....

This ADIS16460 and SPI.h/cpp

/*
 * SPI Master library for Arduino Zero.
 * Copyright (c) 2015 Arduino LLC
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "SPI.h"
#include <Arduino.h>
#include <wiring_private.h>
#include <assert.h>

#define SPI_IMODE_NONE   0
#define SPI_IMODE_EXTINT 1
#define SPI_IMODE_GLOBAL 2

const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();

SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad PadTx, SercomRXPad PadRx)
{
  initialized = false;
  assert(p_sercom != NULL);
  _p_sercom = p_sercom;

  // pins
  _uc_pinMiso = uc_pinMISO;
  _uc_pinSCK = uc_pinSCK;
  _uc_pinMosi = uc_pinMOSI;

  // SERCOM pads
  _padTx=PadTx;
  _padRx=PadRx;
}

void SPIClass::begin()
{
  init();

  // PIO init
  pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
  pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
  pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);

  config(DEFAULT_SPI_SETTINGS);
}

void SPIClass::init()
{
  if (initialized)
    return;
  interruptMode = SPI_IMODE_NONE;
  interruptSave = 0;
  interruptMask = 0;
  initialized = true;
}

void SPIClass::config(SPISettings settings)
{
  _p_sercom->disableSPI();

  _p_sercom->initSPI(_padTx, _padRx, SPI_CHAR_SIZE_8_BITS, settings.bitOrder);
  _p_sercom->initSPIClock(settings.dataMode, settings.clockFreq);

  _p_sercom->enableSPI();

}

void SPIClass::end()
{
  _p_sercom->resetSPI();
  initialized = false;
}

#ifndef interruptsStatus
#define interruptsStatus() __interruptsStatus()
static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused));
static inline unsigned char __interruptsStatus(void)
{
  // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIBGJ.html
  return (__get_PRIMASK() ? 0 : 1);
}
#endif

void SPIClass::usingInterrupt(int interruptNumber)
{
  if ((interruptNumber == NOT_AN_INTERRUPT) || (interruptNumber == EXTERNAL_INT_NMI))
    return;

  uint8_t irestore = interruptsStatus();
  noInterrupts();

  if (interruptNumber >= EXTERNAL_NUM_INTERRUPTS)
    interruptMode = SPI_IMODE_GLOBAL;
  else
  {
    interruptMode |= SPI_IMODE_EXTINT;
    interruptMask |= (1 << g_APinDescription[interruptNumber].ulExtInt);
  }

  if (irestore)
    interrupts();
}

void SPIClass::notUsingInterrupt(int interruptNumber)
{
  if ((interruptNumber == NOT_AN_INTERRUPT) || (interruptNumber == EXTERNAL_INT_NMI))
    return;

  if (interruptMode & SPI_IMODE_GLOBAL)
    return; // can't go back, as there is no reference count

  uint8_t irestore = interruptsStatus();
  noInterrupts();

  interruptMask &= ~(1 << g_APinDescription[interruptNumber].ulExtInt);

  if (interruptMask == 0)
    interruptMode = SPI_IMODE_NONE;

  if (irestore)
    interrupts();
}

void SPIClass::beginTransaction(SPISettings settings)
{
  if (interruptMode != SPI_IMODE_NONE)
  {
    if (interruptMode & SPI_IMODE_GLOBAL)
    {
      interruptSave = interruptsStatus();
      noInterrupts();
    }
    else if (interruptMode & SPI_IMODE_EXTINT)
      EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(interruptMask);
  }

  config(settings);
}

void SPIClass::endTransaction(void)
{
  if (interruptMode != SPI_IMODE_NONE)
  {
    if (interruptMode & SPI_IMODE_GLOBAL)
    {
      if (interruptSave)
        interrupts();
    }
    else if (interruptMode & SPI_IMODE_EXTINT)
      EIC->INTENSET.reg = EIC_INTENSET_EXTINT(interruptMask);
  }
}

void SPIClass::setBitOrder(BitOrder order)
{
  if (order == LSBFIRST) {
    _p_sercom->setDataOrderSPI(LSB_FIRST);
  } else {
    _p_sercom->setDataOrderSPI(MSB_FIRST);
  }
}

void SPIClass::setDataMode(uint8_t mode)
{
  switch (mode)
  {
    case SPI_MODE0:
      _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_0);
      break;

    case SPI_MODE1:
      _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_1);
      break;

    case SPI_MODE2:
      _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_2);
      break;

    case SPI_MODE3:
      _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_3);
      break;

    default:
      break;
  }
}

void SPIClass::setClockDivider(uint8_t div)
{
  if (div < SPI_MIN_CLOCK_DIVIDER) {
    _p_sercom->setBaudrateSPI(SPI_MIN_CLOCK_DIVIDER);
  } else {
    _p_sercom->setBaudrateSPI(div);
  }
}

byte SPIClass::transfer(uint8_t data)
{
  return _p_sercom->transferDataSPI(data);
}

uint16_t SPIClass::transfer16(uint16_t data) {
  union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } t;

  t.val = data;

  if (_p_sercom->getDataOrderSPI() == LSB_FIRST) {
    t.lsb = transfer(t.lsb);
    t.msb = transfer(t.msb);
  } else {
    t.msb = transfer(t.msb);
    t.lsb = transfer(t.lsb);
  }

  return t.val;
}

void SPIClass::transfer(void *buf, size_t count)
{
  uint8_t *buffer = reinterpret_cast<uint8_t *>(buf);
  for (size_t i=0; i<count; i++) {
    *buffer = transfer(*buffer);
    buffer++;
  }
}

void SPIClass::attachInterrupt() {
  // Should be enableInterrupt()
}

void SPIClass::detachInterrupt() {
  // Should be disableInterrupt()
}

#if SPI_INTERFACES_COUNT > 0
  /* In case new variant doesn't define these macros,
   * we put here the ones for Arduino Zero.
   *
   * These values should be different on some variants!
   *
   * The SPI PAD values can be found in cores/arduino/SERCOM.h:
   *   - SercomSpiTXPad
   *   - SercomRXPad
   */
  #ifndef PERIPH_SPI
    #define PERIPH_SPI           sercom4
    #define PAD_SPI_TX           SPI_PAD_2_SCK_3
    #define PAD_SPI_RX           SERCOM_RX_PAD_0
  #endif // PERIPH_SPI

SPIClass SPI (&PERIPH_SPI,  PIN_SPI_MISO,  PIN_SPI_SCK,  PIN_SPI_MOSI,  PAD_SPI_TX,  PAD_SPI_RX);
#endif
#if SPI_INTERFACES_COUNT > 1
  SPIClass SPI1(&PERIPH_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI, PAD_SPI1_TX, PAD_SPI1_RX);
#endif
#if SPI_INTERFACES_COUNT > 2
  SPIClass SPI2(&PERIPH_SPI2, PIN_SPI2_MISO, PIN_SPI2_SCK, PIN_SPI2_MOSI, PAD_SPI2_TX, PAD_SPI2_RX);
#endif
#if SPI_INTERFACES_COUNT > 3
  SPIClass SPI3(&PERIPH_SPI3, PIN_SPI3_MISO, PIN_SPI3_SCK, PIN_SPI3_MOSI, PAD_SPI3_TX, PAD_SPI3_RX);
#endif
#if SPI_INTERFACES_COUNT > 4
  SPIClass SPI4(&PERIPH_SPI4, PIN_SPI4_MISO, PIN_SPI4_SCK, PIN_SPI4_MOSI, PAD_SPI4_TX, PAD_SPI4_RX);
#endif
#if SPI_INTERFACES_COUNT > 5
  SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
#endif
ADIS16460 imu(10, 2, 9); // Arguments: Chip Select, Data Ready, Reset Pin Assignments.

Do you have ALL the needed pins connected? Are you using a particular shield?
You need the SPI pins (MISO, MOSI, SCK) connected via the ICSP connector on the Zero, PLUS pins 10 (SS), 2, and 9. 2 and 9 are additional signals outside of the normal SPI spec.
The web page talks about connecting to a Teensy, and shows a teensy adapter motherboard and weird cable...

yes I'm using a shield, which a collegue has made and which works for the uno.

Since the pins MOSI, MISK and SCK should the only ones which get changed, it should work.

I know that the webpage talks about Teensy, but the same works for the UNO and should also work for the Zero with a different SPI.h

gab27:
yes I'm using a shield, which a collegue has made and which works for the uno.

Since the pins MOSI, MISK and SCK should the only ones which get changed, it should work.

I know that the webpage talks about Teensy, but the same works for the UNO and should also work for the Zero with a different SPI.h

does the shield connect SPI on the ICSP header or on pins 11,12,13?

yes of course

My SPI.h has a include Arduino.h, and this file has a variant.h

In the variant.h there are these lines of code:

/*
 * SPI Interfaces
 */
#define SPI_INTERFACES_COUNT 1

#define PIN_SPI_MISO         (22u)
#define PIN_SPI_MOSI         (23u)
#define PIN_SPI_SCK          (24u)
#define PERIPH_SPI           sercom4
#define PAD_SPI_TX           SPI_PAD_2_SCK_3
#define PAD_SPI_RX           SERCOM_RX_PAD_0

static const uint8_t SS	  = PIN_A2 ;	// SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference.
static const uint8_t MOSI = PIN_SPI_MOSI ;
static const uint8_t MISO = PIN_SPI_MISO ;
static const uint8_t SCK  = PIN_SPI_SCK ;

and in the variant.cpp these:

// 22..24 - SPI pins (ICSP:MISO,SCK,MOSI)
  // ----------------------
  // pins should be the same as in variant.h
  { PORTA, 12, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 }, // MISO: SERCOM4/PAD[0]
  { PORTB, 10, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 }, // MOSI: SERCOM4/PAD[2]
  { PORTB, 11, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 }, // SCK: SERCOM4/PAD[3]

There I have also tried it 22,23,24 than 12,10,11.

22, 23, 24 are pin numbers for the pins on the ISCP headers. the 12, 10, 11 are bit positions in PORT registers

yes