Why does SPI.h have to be included?

Why does SPI.h have to be included in a sketch that doesn't explicitly use SPI?

Does a library the sketch uses talk over SPI?

acboother: Why does SPI.h have to be included in a sketch that doesn't explicitly use SPI?

It would help considerably if you posted an example.....

acboother: Why does SPI.h have to be included in a sketch that doesn't explicitly use SPI?

Because you used a library that used SPI.

Here is a test sketch and my compiler output

#include <_esm.h>

void setup() {
  // put your setup code here, to run once:
  

}

void loop() {
  // put your main code here, to run repeatedly:

}

Arduino: 1.6.4 (Windows 8.1), Board: “Arduino Nano, ATmega328”
Using library _ESM in folder: D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM (legacy)
D:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\tools\avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -ID:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\cores\arduino -ID:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\variants\eightanaloginputs -ID:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM C:\Users\Alan\AppData\Local\Temp\build954570892796097350.tmp\sketch_sep06a.cpp -o C:\Users\Alan\AppData\Local\Temp\build954570892796097350.tmp\sketch_sep06a.cpp.o
D:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\tools\avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10604 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -ID:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\cores\arduino -ID:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\variants\eightanaloginputs -ID:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM -ID:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM\utility D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp -o C:\Users\Alan\AppData\Local\Temp\build954570892796097350.tmp_ESM_esm.cpp.o
D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘void ESMprint(const char*, …)’:
D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:30:33: error: ‘memset’ was not declared in this scope

  • memset(acTmp, 0, sizeof(acTmp));*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:37:40: error: ‘strlen’ was not declared in this scope
  • printf("%s$%d\n", acTmp, strlen(acTmp));*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘int _putc(char, __file*)’:
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:44:3: error: ‘Serial’ was not declared in this scope
  • Serial.write(c);*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘void ESMbegin(long int)’:
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:50:3: error: ‘Serial’ was not declared in this scope
  • Serial.begin(lBaudRate);*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘int ESMread(char*, int)’:
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:57:7: error: ‘Serial’ was not declared in this scope
  • if (Serial.available()) {*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:59:15: error: ‘delay’ was not declared in this scope
  • delay(10);*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:62:30: error: ‘memset’ was not declared in this scope
  • memset(acDest, 0 , iLen);*
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘char* ESMupper(char*)’:
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:102:30: error: ‘toupper’ was not declared in this scope
    _ *pStr = toupper(*pStr);_
  • ^*
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp: In function ‘void ESMtrace(int, long int, char*)’:
    D:\Arduino_Tools\Arduino\arduino-1.6.4\libraries_ESM_esm.cpp:112:32: error: ‘millis’ was not declared in this scope
  • static long lMillis = millis();*
  • ^*
    Error compiling.

And here is the library header

/*
#define SYSTEM "_esm.h 06/09/2015 12:57"
*/

#ifndef _esm_h
#define _esm_h


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

// have to do this...
#include <D:\Arduino\_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\libraries\SPI\SPI.h>

// wold like to do this!
//#include <SPI.h>

char * ESMf2s(float fValue, int iPrecision);
void ESMprint(const char *sFmt, ...);
void ESMbegin(long lBaudRate);
int ESMread(char acDest[], int iLen);
char * ESMparam(char *pBuff, int iParam);
char * ESMupper(char *pStr);
void ESMtrace(int iRestart, long lLINE, char * sFILE);

#define elif else if
#define ESM ESMprint
#define ESMs ESMf2s
#define ESM0(x) ESMs(x, 0)
#define ESM1(x) ESMs(x, 1)
#define ESM2(x) ESMs(x, 2)
#define ESM3(x) ESMs(x, 3)

#define TRACE(b) ESMtrace(b, __LINE__, __FILE__)
#define T ESMtrace(true, __LINE__, __FILE__)

#define PSTRING(buff, str) const char buff[] PROGMEM = str

#endif // _esm_h

and source

/*
#define SYSTEM "_esm.cpp 02/09/2015 18:57"
Support library for Enhanced Serial Monitor
*/

#include <stdlib.h>
#include <stdio.h>

#include "_esm.h"
//--------------------------------------------------------------------------------------
char * ESMf2s(float f, int p) {
  char * pBuff;                         // use to remember which part of the buffer to use for dtostrf
  const int iSize = 10;                 // number of bufffers, one for each float before wrapping around
  static char sBuff[iSize][20];         // space for 20 characters including NULL terminator for each float
  static int iCount = 0;                // keep a tab of next place in sBuff to use
  pBuff = sBuff[iCount];                // use this buffer
  if (iCount >= iSize - 1) {            // check for wrap
    iCount = 0;                         // if wrapping start again and reset
  }
  else {
    iCount++;                           // advance the counter
  }
  return dtostrf(f, 0, p, pBuff);       // call the library function
}
//--------------------------------------------------------------------------------------
void ESMprint(const char *sFmt, ...)
{
  char acTmp[128];

  memset(acTmp, 0, sizeof(acTmp));

  va_list args;
  va_start(args, sFmt);
  vsprintf(acTmp, sFmt, args);
  va_end(args);

  printf("%s$%d\n", acTmp, strlen(acTmp));

  return;
}
//--------------------------------------------------------------------------------------
int _putc(char c, FILE *)
{
  Serial.write(c);
  return c;
}
//-------------------------------------------------------------------------------------------
void ESMbegin(long lBaudRate)
{
  Serial.begin(lBaudRate);
  fdevopen(&_putc, 0);
}
//--------------------------------------------------------------------------------------
int ESMread(char acDest[], int iLen)
{
  acDest[0] = 0;
  if (Serial.available()) {
    if (Serial.peek() == '#') { // # character starts ESM message
      delay(10);
      Serial.read();
      int n = 1;
      memset(acDest, 0 , iLen);
      acDest[0] = 1;
      while (n < iLen -1) {
        delay(1);  // ! seems to make reading more reliable !
        if (Serial.available()) {
          char c = Serial.read();
          if (c == '~') {
            c = 0;
            acDest[0] = acDest[0] + 1;
          }
          acDest[n++] = c;
        }
        else {
          acDest[n] = 0;
          return acDest[0];
        }
      }
    }
    else
      Serial.read();
  }
  return acDest[0];
}
//--------------------------------------------------------------------------------------
char * ESMparam(char *pBuff, int iParam)
{
  if (iParam > *pBuff) return NULL;
  pBuff++;
  while (iParam-- > 0) {
    while (*pBuff++ != 0);
  }
  return pBuff;
}
//--------------------------------------------------------------------------------------
char * ESMupper(char *pStr)
{
    char *pStart = pStr;

    while(*pStr)
    {
        *pStr = toupper(*pStr);
        *pStr++;
    }

    return pStart;
}
//------------------------------------------------------------------------------------
void ESMtrace(int iRestart, long lLINE, char * sFILE)
{

  static long lMillis = millis();
  long lMillisNow = millis();

  if(iRestart) lMillis = lMillisNow;
  ESM("#log~%s~%s~%s~%s", ESM0(lMillisNow), ESM0(lMillisNow - lMillis), ESM0(lLINE), sFILE);
  lMillis = lMillisNow;

}
//------------------------------------------------------------------------------------

Another odd thing that I used to notice is that when I first opened a sketch I had to include SPI.h and/or Wire.h for it to compile the first time. Afterwards I could comment them out and everyhting was fine until I closed the IDE down when I would have to go through the routine again upon opening… not sure wwhich version that seemed to stop happening on.

Comment out the #include ... SPI.h in the aabove header file to generate the error messages

Riva: Does a library the sketch uses talk over SPI?

No

UKHeliBob: It would help considerably if you posted an example.....

Does that help?

Riva: Does a library the sketch uses talk over SPI?

No[quote author=Nick Gammon link=msg=2385730 date=1441537265] Because you used a library that used SPI. [/quote]

I can't identify one

acboother:
I can’t identify one

It’s right here in the header you posted:

// have to do this...
#include <D:\Arduino\_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\libraries\SPI\SPI.h>

// wold like to do this!
//#include <SPI.h>

Delta_G:
It’s right here in the header you posted:

// have to do this...

#include <D:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\libraries\SPI\SPI.h>

// wold like to do this!
//#include <SPI.h>

Due to the way the IDE assembles the files, if it is included in a header then it must also be included by the sketch or the header won’t be able to find it.

Delta_G:
It’s right here in the header you posted:

// have to do this...

#include <D:\Arduino_Tools\Arduino\arduino-1.6.4\hardware\arduino\avr\libraries\SPI\SPI.h>

// wold like to do this!
//#include <SPI.h>




I included it to make it compile! And that's my point...

Delta_G: Due to the way the IDE assembles the files, if it is included in a header then it must also be included by the sketch or the header won't be able to find it.

It compiles when in the header and not in the sketch.

Take it out of the header and it fails to compile

acboother:
No

It might not talk over SPI but it’s using a function (memset) from the SPI library.

memset(acTmp, 0, sizeof(acTmp));

EDIT: memset is not in SPI library but is in Arduino.h that SPI library includes.
Remove reference to SPI and include

#include <Arduino.h>

and it will compile (it does on mine)

Riva:
It might not talk over SPI but it’s using a function (memset) from the SPI library.

memset(acTmp, 0, sizeof(acTmp));

EDIT: memset is not in SPI library but is in Arduino.h that SPI library includes.
Remove reference to SPI and include

#include <Arduino.h>

and it will compile (it does on mine)

Eek! Never expected memset to be in SPI.!!! How weird {update} that’s not what you said - I realise now what is happening {/update}

Thanks for that. I’ll try it when I get back to the 'puter

If that one line makes a difference, then you don'y have that library installed in the correct location. And if one of those #includes HAS to be there for the sketch to compile, then one of the include files in the project IS using SPI.

Regards, Ray L.

Riva:
It might not talk over SPI but it’s using a function (memset) from the SPI library.

memset(acTmp, 0, sizeof(acTmp));

EDIT: memset is not in SPI library but is in Arduino.h that SPI library includes.
Remove reference to SPI and include

#include <Arduino.h>

and it will compile (it does on mine)

Oh, that’s sneaky. So it’s not SPI.h that it needs at all. Any other library that includes Arduino.h would have behaved similarly.

What’s with the leading underscores in file names?

To summarize, for anyone else following this thread:

  1. Including SPI.h is not necessary at all in this case, as it isn’t used. If it was used (in the library) the include should also be in the main .ino file, to tell the compiler to copy it into the temporary compilation directory.

  2. These lines can be omitted:

#include <stdlib.h>
#include <stdio.h>
  1. The library (which is compiled as a separate file) needs to have this at the start of the .cpp file:
#include <Arduino.h>

Such a strange workflow the arduino compiler process must go through...

... there is the issue of tricking the preprocessor to do its job properly as I was shown last week here on the forum.

I spent years with C and use the leading underscore as part of my personal variation of Hungarian notation

Hungarian notation for files? Next you'll be using a leading dot and wonder why they disappear. :P