SPI - change SS from pin 10 to pin 3

Hello all,

Long story short, I want to control 2 servos on timer1, which means pins 9 and 10. Therefore, I have to move the SS from pin 10 to pin 3 - reason is because it is the only open pin I have. Im trying to figure out why my main code won't compile. Here is the set up. I have a main .ino file - LIFA_Base_Ethernet - which calls SPI_LIFA.h - SPI with the SS pin changed via #include "SPI_LIFA.h". the main code and SPI_LIFA.cpp/h are in the same folder and they are added to the same Arduino IDE.

Below is the error codes and SPI_LIFA files. The only changes I made were in the .cpp. Instead of having things for to SS, I changed it to 3.

One more thing... I am using an Arduino Ethernet and I'm communicating via Ethernet, would that mean I must also make a custom Ethernet library...? I'm not the best with communication proto calls but I think the ethernet library uses SPI, so that would make sense that I have to.

EDIT:
I know Ethernet uses SPI, just went through the library and the file w5100.h calls the SPI library. Is there a way to single that file out and put it with the rest of my code or will I have to copy over the entire library? I ask because I'm trying to keep all the files associated with LIFA_Base in one folder.

Thanks,
Matt

Errors.

C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:12:17: error: SPI.h: No such file or directory
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:14: error: 'SPIClass' does not name a type
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:16: error: 'SPIClass' has not been declared
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: In function 'void begin()':
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:19: error: 'HIGH' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:19: error: 'digitalWrite' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:24: error: 'OUTPUT' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:24: error: 'pinMode' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: At global scope:
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:43: error: 'SPIClass' has not been declared
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:47: error: 'SPIClass' has not been declared
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: In function 'void setBitOrder(uint8_t)':
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:49: error: 'LSBFIRST' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: At global scope:
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:56: error: 'SPIClass' has not been declared
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: In function 'void setDataMode(uint8_t)':
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:58: error: 'SPI_MODE_MASK' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: At global scope:
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:61: error: 'SPIClass' has not been declared
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp: In function 'void setClockDivider(uint8_t)':
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:63: error: 'SPI_CLOCK_MASK' was not declared in this scope
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:64: error: 'SPI_2XCLOCK_MASK' was not declared in this scope

my code for SPI_LIFA.h is

/*
 * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
 * SPI Master library for arduino.
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#ifndef _SPI_LIFA_H_INCLUDED
#define _SPI_LIFA_H_INCLUDED

#include <stdio.h>
#include <Arduino.h>
#include <avr/pgmspace.h>

#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
//#define SPI_CLOCK_DIV64 0x07

#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define SPI_MODE2 0x08
#define SPI_MODE3 0x0C

#define SPI_MODE_MASK 0x0C  // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03  // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01  // SPI2X = bit 0 on SPSR

class SPIClass {
public:
  inline static byte transfer(byte _data);

  // SPI Configuration methods

  inline static void attachInterrupt();
  inline static void detachInterrupt(); // Default

  static void begin(); // Default
  static void end();

  static void setBitOrder(uint8_t);
  static void setDataMode(uint8_t);
  static void setClockDivider(uint8_t);
};

extern SPIClass SPI;

byte SPIClass::transfer(byte _data) {
  SPDR = _data;
  while (!(SPSR & _BV(SPIF)))
    ;
  return SPDR;
}

void SPIClass::attachInterrupt() {
  SPCR |= _BV(SPIE);
}

void SPIClass::detachInterrupt() {
  SPCR &= ~_BV(SPIE);
}

#endif

my code for SPI_LIFA.cpp is

/*
 * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
 * SPI Master library for arduino.
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */

#include "pins_arduino.h"
#include "SPI_LIFA.h"

SPIClass SPI;

void SPIClass::begin() {

  // Set 3 to high so a connected chip will be "deselected" by default
  digitalWrite(3, HIGH);

  // When the 3 pin is set as OUTPUT, it can be used as
  // a general purpose output port (it doesn't influence
  // SPI operations).
  pinMode(3, OUTPUT);

  // Warning: if the 3 pin ever becomes a LOW INPUT then SPI
  // automatically switches to Slave, so the data direction of
  // the 3 pin MUST be kept as OUTPUT.
  SPCR |= _BV(MSTR);
  SPCR |= _BV(SPE);

  // Set direction register for SCK and MOSI pin.
  // MISO pin automatically overrides to INPUT.
  // By doing this AFTER enabling SPI, we avoid accidentally
  // clocking in a single bit since the lines go directly
  // from "input" to SPI control.  
  // http://code.google.com/p/arduino/issues/detail?id=888
  pinMode(SCK, OUTPUT);
  pinMode(MOSI, OUTPUT);
}


void SPIClass::end() {
  SPCR &= ~_BV(SPE);
}

void SPIClass::setBitOrder(uint8_t bitOrder)
{
  if(bitOrder == LSBFIRST) {
    SPCR |= _BV(DORD);
  } else {
    SPCR &= ~(_BV(DORD));
  }
}

void SPIClass::setDataMode(uint8_t mode)
{
  SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
}

void SPIClass::setClockDivider(uint8_t rate)
{
  SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
  SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
}
C:\Users\Lomanno\Documents\Arduino\libraries\SPI_LIFA\SPI_LIFA.cpp:12:17: error: SPI.h: No such file or directory

This compile run was probably not with the posted code, because there in line 12 SPI_LIFA.h is included and not SPI.h

BTW: you don't have to change the SPI library to use another SS pin (if the Arduino is the SPI master) because you can use any pin for that. Nevertheless pin 10 has to be an output (that's why the begin() method of SPI is configuring it so) because that's how you tell the hardware that it's the bus master and not a slave.
You have to handle the SS pin yourself anyway, the library isn't doing this for you.

That is why I am very confused. I know that in the SPI_LIFA.cpp, I have the #include"SPI_LIFA.h". and that should be the end of it. However, its not working correctly. I tried closing and opening the IDE but that didn't work, still giving me my error.

Again, the Ethernet library has a file - w5100.h - which uses the #include<SPI.h> code. Can this be my problem and can I only change this specific file or will I have to make an entirely custom library?

Matt

What do you want to achieve? Why do you need that library change?

without going too in depth, I want to change the SS pin from 10 to 3. The reason behind that is because I have servos which I wrote code for - low level registry code - and I'd prefer both of them to work on timer1. I only have 1 available pin left and that is pin 3, so that means SS must become pin 3. Timer1 works on pins 9 and 10. I am using ethernet to talk with my Arduino to control said servos and a lens.

Matt

You don't have to repeat what you already wrote. I wanted to know what you want to achieve not how you want to do it.
If you want to communicate with the Ethernet shield using another SS pin than 10, you have to modify the hardware and the Ethernet library, not the SPI library.
But it's still necessary that pin 10 is configured as an output because the hardware depends on it. So don't touch the SPI library, change the Ethernet library if needed.

Here is a post that has my new ethernet library file modifications to change the slave select pin for the w5100.
http://forum.arduino.cc/index.php?topic=217423.msg1601862#msg1601862

No modification is needed to the SPI library. Leave that alone as pylon already stated. If you are using an Uno, you must leave D10 as an output. Changing it to an input will set the SPI bus to slave mode. It must be in master mode to use the devices on the ethernet shield.

edit: Insure you read reply#11. Back up your original ethernet library files before replacing them. If all goes bad, you can replace my files with your originals and you are back in business. Just a good practice.

The function used to change the slave select pin is this:

Ethernet.select(3);

Bend the D10 pin on the ethernet shield so it does not insert into the Arduino, then jumper the D10 pin to D3 on the shield.

@pylon,
Sorry if I came off sounding like a dick, wasn't trying to.

Just wondering, but why would I want to modify the Ethernet library over the SPI library? I'm just curious. I thought that the Ethernet library would call the SPI library which would set the pins correctly.

So if I do successfully change the SS from pin 10 to pin 3, I would need to connect pin 10 to pin 3? I ask because if thats the case, how can I use pin 10 as a PWM signal? The goal of moving the SS was so I could use pin 10 as a PWM control for a servo. If I can't do that then I'll just have to write code to control PWM on pin 3 instead. It won't be the end of the world, I'd just like to my servos work on the same timer - Pin 9 and 10 - not different timers, pin 9 and 3.

Matt

@SurferTim
I replaced the Ethernet.h/cpp and w5100.h/cpp in my ethernet library and I'm still getting these errors.

Ethernet_with_interupt.ino: In function 'void setup()':
Ethernet_with_interupt:61: error: 'class EthernetClass' has no member named 'select'

Any suggestions? Do I need to update the keywords or something in the Ethernet library...?

Attached is my code. It is too long character wise to post here. There are 3 files, a main ino, a header, and the header's ino. A lot of the code has been commented out and can be ignored. It's from previous versions of the code. I've basically just copied the code once I want to add something new to it, so instead of deleting the code, I just comment it out.

Ethernet_with_interupt.7z (2.86 KB)

If you got that error, then you did not replace your files with mine. I downloaded Ethernet.h and Ethernet.cpp from that page, and here it is in Ethernet.h

  void select(uint8_t _ss);

Here it is in Ethernet.cpp

void EthernetClass::select(uint8_t _ss)
{
  W5100.selectSS(_ss);
  slaveSelect = _ss;
}

Ends up I have two versions of the IDE installed... One is in my documents and the other is my program files... I ended up putting the files in the correct Arduino folder and my code builds.

So I'm about 95% sure I've been dumb about this entire thing. I thought that if I changed the SS from 10 to 3, then that would allow me to do what I wanted to on pin 10. I don't think thats the case anymore. I looked at the Atmega168 pinout and I see that pin 10 is stuck to being SS. So even though I can change SS from pin 10 to pin 3, it has no affect on the Arduino whatsoever because pin 10 will always have to have the SS connected to it in some way. Therefore, my idea of having PWM on pin 10 is dead and time to move on, correct?

If thats the case, I have a different question. I was looking at pin 3's PWM which is OCR2B - Timer2 - and I know OCR2A is pin 11. Pin 11 is being used by SPI. Would chaning OCR2A affect? I ask because now I'm thinking of just writing code for Pin 3 instead of Pin 10 and I'd need to change OCR1A to give me the freq I'm looking for with OCR2B.

Matt

So Is this correct? Even if I do change the _SS pin in the code, it still won't matter because the ATMEGA 168 chip states that Pin 10 must be SS. Therefore, I cant do PWM on pin 10 AND use Ethernet communications at the same time.

Link to ATMEGA 168 pin mapping - http://arduino.cc/en/Hacking/PinMapping168#.Uw0RfvldVw4.

Matt

I don't know about that. The specs say that D10 must be an OUTPUT to keep the SPI in master mode. It doesn't say anything about PWM on that pin AFAIK. PWM sets that pin to OUTPUT. You can try it.

edit: I have a Mega, so my default slave select is D53. It isn't PWM capable, but I can change the state from HIGH to LOW and LOW to HIGH each iteration of loop, and it does not affect the SPI bus or my server sketch.

I really don't know why you are changing the slave select on the w5100 though. D3 on the Uno has PWM. Would it not be easier to change the other device (servo?) to D3? Only IDE versions prior to v0016 have a limitation to D9 and D10 for servos. Later IDE versions allow servos on any PWM capable pin.

So Is this correct? Even if I do change the _SS pin in the code, it still won't matter because the ATMEGA 168 chip states that Pin 10 must be SS. Therefore, I cant do PWM on pin 10 AND use Ethernet communications at the same time.

You should be able to use it as a PWM output but you cannot use it as a digital input. It's not used by the hardware if it's configured as an output but that check is done. As a PWM is an output you should be fine (although I did not try it myself yet, the datasheet is telling that).

@SurferTim
The PWM on pin 3 had a low resolution - 8 bit - where pin 10 has a higher resolution - 16 bit - thats what I was interested in it. I ended up searching through a custom servo library - VarServoSpeed - and found out where it sets up the code to use Timer1 as the servo control and I changed it to suit my needs.

@pylon
Thats what my thought was too. I mean, technically, it would be an output as PWM and thats all the SS cares about, right?

So I ended up running the chat server .ino along with my custom servo code. I wired a servo's control signal to pin 10 and then turned everything on. The servo wouldn't go to the commanded location although OCR1B was changing. Also, while OCR1B was changing, I noticed that network communications were down and I'd lose connection.

Anyways, as I just said @SurferTim in this post, I modded a modded servo library to do what I want it to do. They had a prescale constant of 8, I changed it to a 1 and I also changed the refresh rate to 200 Hz instead of 50 Hz (manufacturers said it can handle 250 Hz and the faster the better). So I think I should be good.

If anyone is interested in my VarServoSpeed lib that I modded, ask and I'll zip it and upload. It's currently giving me better resolution - I believe my current resolution is 15 bit resolution for PWM with a prescaler of 1 and 200 Hz.

Thank you pylon and SurferTim for your time!

Matt

Also, while OCR1B was changing, I noticed that network communications were down and I'd lose connection.

That sounds like the modification to the Ethernet library were not active and the library (and the Ethernet shield) are still running on pin 10. Have you checked that separately? I mean did you check the functionality with separate sketches? Running the Ethernet sketch I would check if pin 10 is really no changing during network traffic being sent.

SurferTim stated that I must connect pin 3 to pin 10

Bend the D10 pin on the ethernet shield so it does not insert into the Arduino, then jumper the D10 pin to D3 on the shield.

So my thought is that if I have to connect pin 3 to pin 10, then I can't use pin 10 for anything else. That sounds like it means I'd be using 2 pins for SS - 3 and 10. Changing the SS from pin 10 to pin 3 gives me no Ethernet connection since it wasn't jumpered. If it were jumpered, I would be back to leaving pin 10 as my SS and trying to do PWM over that.

Matt

So my thought is that if I have to connect pin 3 to pin 10, then I can't use pin 10 for anything else. That sounds like it means I'd be using 2 pins for SS - 3 and 10. Changing the SS from pin 10 to pin 3 gives me no Ethernet connection since it wasn't jumpered. If it were jumpered, I would be back to leaving pin 10 as my SS and trying to do PWM over that.

You should bend the pin 10 of the Ethernet shield and connect that pin instead to pin 3 of the Arduino. That means that pin 10 of the Arduino isn't connected to anything at the moment and is free to be used for other stuff. This other stuff is limited to an outgoing signal because pin 10 has to be configured as an output as the hardware is relying on that.
What do you mean by jumpered?

This thread goes into a fair bit of detail about changing SS from the default pin 10 for the ethernet library:

http://forum.arduino.cc/index.php?topic=19770.0

So I forgot to update this until now.

The reason why I was having problems is because I was using an Arduino Ethernet, not an Uno with an Ethernet shield. Therefore, pin 10 is hardwired to the SS on the Wiznet chip, thus forcing me to place a jumper wire from pin 3 (new SS) to pin 10 (Wiznet's SS).

I have since then gotten my hands on an Uno and Enet shield, and like pylon said, just bend the pin 10 the Ethernet shield and put jumper wires from Arduino pin 3 to Enet shield pin 10. I have successfully changed SS from pin 10 to 3 (Thank's to lemming's post) and I can write to ORC1B to do PWM.

Thanks for the help, sorry it took me ~3 months to reply.
Matt