Skip to content

Commit 0054738

Browse files
authoredSep 5, 2023
[skip-changelog] Porting legacy tests to new integration-test infra (part 2...) (#2295)
* Ported legacy TestIncludesToIncludeFolders test * Ported legacy TestIncludesToIncludeFoldersANewLibrary test * Ported legacy TestIncludesToIncludeFoldersDuplicateLibs* test Also improved build options in test
1 parent 8ba101c commit 0054738

File tree

20 files changed

+2022
-161
lines changed

20 files changed

+2022
-161
lines changed
 

‎internal/integrationtest/compile_4/compile_test.go

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ func TestCompileOfProblematicSketches(t *testing.T) {
6363
_, _, err = cli.Run("lib", "install", "CapacitiveSensor@0.5")
6464
require.NoError(t, err)
6565

66+
// Install custom hardware required for tests
67+
customHwDir, err := paths.New("testdata", "user_hardware").Abs()
68+
require.NoError(t, err)
69+
require.NoError(t, customHwDir.CopyDirTo(cli.SketchbookDir().Join("hardware")))
70+
6671
integrationtest.CLISubtests{
6772
{"SketchWithInlineFunction", testBuilderSketchWithInlineFunction},
6873
{"SketchWithConst", testBuilderSketchWithConst},
@@ -97,6 +102,8 @@ func TestCompileOfProblematicSketches(t *testing.T) {
97102
{"SketchWithFunctionPointer", tryBuildAvrLeonardo},
98103
{"USBHostExample", testBuilderUSBHostExample},
99104
{"SketchWithConflictingLibraries", testBuilderSketchWithConflictingLibraries},
105+
{"SketchLibraryProvidesAllIncludes", testBuilderSketchLibraryProvidesAllIncludes},
106+
{"UserHardware", testBuilderWithUserHardware},
100107
}.Run(t, env, cli)
101108
}
102109

@@ -322,8 +329,12 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
322329
require.True(t, buildPath.Join("BridgeExample.ino.hex").Exist())
323330
require.True(t, buildPath.Join("libraries", "Bridge", "Mailbox.cpp.o").Exist())
324331

332+
libs := out.BuilderResult.UsedLibraries
333+
require.Len(t, libs, 1)
334+
require.Equal(t, "Bridge", libs[0].Name)
335+
325336
// Build again...
326-
out2, err2 := tryBuild(t, env, cli, "arduino:avr:leonardo", "no-clean")
337+
out2, err2 := tryBuild(t, env, cli, "arduino:avr:leonardo", &buildOptions{NoClean: true})
327338
require.NoError(t, err2)
328339
buildPath2 := out2.BuilderResult.BuildPath
329340
require.True(t, buildPath2.Join("core", "HardwareSerial.cpp.o").Exist())
@@ -335,7 +346,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
335346

336347
t.Run("BuildForSAM", func(t *testing.T) {
337348
// Build again for SAM...
338-
out, err := tryBuild(t, env, cli, "arduino:sam:arduino_due_x_dbg", "all-warnings")
349+
out, err := tryBuild(t, env, cli, "arduino:sam:arduino_due_x_dbg", &buildOptions{AllWarnings: true})
339350
require.NoError(t, err)
340351

341352
buildPath := out.BuilderResult.BuildPath
@@ -358,7 +369,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
358369

359370
t.Run("BuildForRedBearAVR", func(t *testing.T) {
360371
// Build again for RedBearLab...
361-
out, err := tryBuild(t, env, cli, "RedBear:avr:blend", "verbose")
372+
out, err := tryBuild(t, env, cli, "RedBear:avr:blend", &buildOptions{Verbose: true})
362373
require.NoError(t, err)
363374
buildPath := out.BuilderResult.BuildPath
364375
require.True(t, buildPath.Join("core", "HardwareSerial.cpp.o").Exist())
@@ -377,7 +388,7 @@ func testBuilderBridgeExample(t *testing.T, env *integrationtest.Environment, cl
377388
require.NoError(t, buildPath.Join("libraries", "SPI").MkdirAll())
378389

379390
// Build again...
380-
_, err = tryBuild(t, env, cli, "arduino:avr:leonardo", "no-clean")
391+
_, err = tryBuild(t, env, cli, "arduino:avr:leonardo", &buildOptions{NoClean: true})
381392
require.NoError(t, err)
382393

383394
require.False(t, buildPath.Join("libraries", "SPI").Exist())
@@ -548,6 +559,52 @@ func testBuilderSketchWithConflictingLibraries(t *testing.T, env *integrationtes
548559
})
549560
}
550561

562+
func testBuilderSketchLibraryProvidesAllIncludes(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
563+
t.Run("Build", func(t *testing.T) {
564+
// Build
565+
out, err := tryBuild(t, env, cli, "arduino:avr:leonardo")
566+
require.NoError(t, err)
567+
libs := out.BuilderResult.UsedLibraries
568+
slices.SortFunc(libs, func(x, y *builderLibrary) bool { return x.Name < y.Name })
569+
require.Len(t, libs, 2)
570+
require.Equal(t, "ANewLibrary-master", libs[0].Name)
571+
require.Equal(t, "IRremote", libs[1].Name)
572+
})
573+
}
574+
575+
func testBuilderWithUserHardware(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
576+
coreSPILib, err := cli.SketchbookDir().Join("hardware", "my_avr_platform", "avr", "libraries", "SPI").Abs()
577+
require.NoError(t, err)
578+
sketchPath := coreSPILib.Join("examples", "BarometricPressureSensor", "BarometricPressureSensor.ino")
579+
580+
t.Run("TestIncludesToIncludeFoldersDuplicateLibs", func(t *testing.T) {
581+
out, err := tryBuild(t, env, cli, "my_avr_platform:avr:custom_yun", &buildOptions{
582+
Sketch: sketchPath,
583+
NoTestLibraries: true,
584+
})
585+
require.NoError(t, err)
586+
587+
importedLibraries := out.BuilderResult.UsedLibraries
588+
require.Equal(t, 1, len(importedLibraries))
589+
require.Equal(t, "SPI", importedLibraries[0].Name)
590+
require.True(t, importedLibraries[0].SourceDir.EquivalentTo(coreSPILib))
591+
})
592+
593+
t.Run("TestIncludesToIncludeFoldersDuplicateLibsWithConflictingLibsOutsideOfPlatform", func(t *testing.T) {
594+
SPILib, err := paths.New("testdata", "libraries", "SPI").Abs()
595+
require.NoError(t, err)
596+
out, err := tryBuild(t, env, cli, "my_avr_platform:avr:custom_yun", &buildOptions{
597+
Sketch: sketchPath,
598+
})
599+
require.NoError(t, err)
600+
601+
importedLibraries := out.BuilderResult.UsedLibraries
602+
require.Equal(t, 1, len(importedLibraries))
603+
require.Equal(t, "SPI", importedLibraries[0].Name)
604+
require.True(t, importedLibraries[0].SourceDir.EquivalentTo(SPILib))
605+
})
606+
}
607+
551608
func tryBuildAvrLeonardo(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI) {
552609
_, err := tryBuild(t, env, cli, "arduino:avr:leonardo")
553610
require.NoError(t, err)
@@ -568,25 +625,49 @@ type builderLibrary struct {
568625
SourceDir *paths.Path `json:"source_dir"`
569626
}
570627

571-
func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, options ...string) (*builderOutput, error) {
572-
subTestName := strings.Split(t.Name(), "/")[1]
573-
sketchPath, err := paths.New("testdata", subTestName).Abs()
574-
require.NoError(t, err)
575-
libsPath, err := paths.New("testdata", "libraries").Abs()
576-
require.NoError(t, err)
628+
type buildOptions struct {
629+
Sketch *paths.Path
630+
NoTestLibraries bool
631+
CustomLibPath *paths.Path
632+
NoClean bool
633+
AllWarnings bool
634+
Verbose bool
635+
}
636+
637+
func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, optionsArg ...*buildOptions) (*builderOutput, error) {
638+
var options *buildOptions
639+
if len(optionsArg) == 0 {
640+
options = &buildOptions{}
641+
} else {
642+
require.Len(t, optionsArg, 1)
643+
options = optionsArg[0]
644+
}
645+
if options.Sketch == nil {
646+
subTestName := strings.Split(t.Name(), "/")[1]
647+
sketchPath, err := paths.New("testdata", subTestName).Abs()
648+
require.NoError(t, err)
649+
options.Sketch = sketchPath
650+
}
577651
args := []string{
578652
"compile",
579653
"-b", fqbn,
580-
"--libraries", libsPath.String(),
581654
"--format", "json",
582-
sketchPath.String()}
583-
if !slices.Contains(options, "no-clean") {
655+
options.Sketch.String()}
656+
if !options.NoTestLibraries {
657+
libsPath, err := paths.New("testdata", "libraries").Abs()
658+
require.NoError(t, err)
659+
args = append(args, "--libraries", libsPath.String())
660+
}
661+
if options.CustomLibPath != nil {
662+
args = append(args, "--library", options.CustomLibPath.String())
663+
}
664+
if !options.NoClean {
584665
args = append(args, "--clean")
585666
}
586-
if slices.Contains(options, "all-warnings") {
667+
if options.AllWarnings {
587668
args = append(args, "--warnings", "all")
588669
}
589-
if slices.Contains(options, "verbose") {
670+
if options.Verbose {
590671
args = append(args, "-v")
591672
}
592673
jsonOut, _, err := cli.Run(args...)
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <anewlibrary.h>
2-
#include <IRremoteInt.h>
2+
#include <IRremote.h>
33

44
void setup() {}
55
void loop() {}

‎internal/integrationtest/compile_4/testdata/libraries/ANewLibrary-master/anewlibrary.h

Whitespace-only changes.
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
3+
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
4+
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
5+
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
6+
* SPI Master library for arduino.
7+
*
8+
* This file is free software; you can redistribute it and/or modify
9+
* it under the terms of either the GNU General Public License version 2
10+
* or the GNU Lesser General Public License version 2.1, both as
11+
* published by the Free Software Foundation.
12+
*/
13+
14+
#include "SPI.h"
15+
16+
SPIClass SPI;
17+
18+
uint8_t SPIClass::initialized = 0;
19+
uint8_t SPIClass::interruptMode = 0;
20+
uint8_t SPIClass::interruptMask = 0;
21+
uint8_t SPIClass::interruptSave = 0;
22+
#ifdef SPI_TRANSACTION_MISMATCH_LED
23+
uint8_t SPIClass::inTransactionFlag = 0;
24+
#endif
25+
26+
void SPIClass::begin()
27+
{
28+
uint8_t sreg = SREG;
29+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
30+
if (!initialized) {
31+
// Set SS to high so a connected chip will be "deselected" by default
32+
uint8_t port = digitalPinToPort(SS);
33+
uint8_t bit = digitalPinToBitMask(SS);
34+
volatile uint8_t *reg = portModeRegister(port);
35+
36+
// if the SS pin is not already configured as an output
37+
// then set it high (to enable the internal pull-up resistor)
38+
if(!(*reg & bit)){
39+
digitalWrite(SS, HIGH);
40+
}
41+
42+
// When the SS pin is set as OUTPUT, it can be used as
43+
// a general purpose output port (it doesn't influence
44+
// SPI operations).
45+
pinMode(SS, OUTPUT);
46+
47+
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
48+
// automatically switches to Slave, so the data direction of
49+
// the SS pin MUST be kept as OUTPUT.
50+
SPCR |= _BV(MSTR);
51+
SPCR |= _BV(SPE);
52+
53+
// Set direction register for SCK and MOSI pin.
54+
// MISO pin automatically overrides to INPUT.
55+
// By doing this AFTER enabling SPI, we avoid accidentally
56+
// clocking in a single bit since the lines go directly
57+
// from "input" to SPI control.
58+
// http://code.google.com/p/arduino/issues/detail?id=888
59+
pinMode(SCK, OUTPUT);
60+
pinMode(MOSI, OUTPUT);
61+
}
62+
initialized++; // reference count
63+
SREG = sreg;
64+
}
65+
66+
void SPIClass::end() {
67+
uint8_t sreg = SREG;
68+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
69+
// Decrease the reference counter
70+
if (initialized)
71+
initialized--;
72+
// If there are no more references disable SPI
73+
if (!initialized) {
74+
SPCR &= ~_BV(SPE);
75+
interruptMode = 0;
76+
#ifdef SPI_TRANSACTION_MISMATCH_LED
77+
inTransactionFlag = 0;
78+
#endif
79+
}
80+
SREG = sreg;
81+
}
82+
83+
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
84+
#if defined(__AVR_ATmega32U4__)
85+
#define SPI_INT0_MASK (1<<INT0)
86+
#define SPI_INT1_MASK (1<<INT1)
87+
#define SPI_INT2_MASK (1<<INT2)
88+
#define SPI_INT3_MASK (1<<INT3)
89+
#define SPI_INT4_MASK (1<<INT6)
90+
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
91+
#define SPI_INT0_MASK (1<<INT0)
92+
#define SPI_INT1_MASK (1<<INT1)
93+
#define SPI_INT2_MASK (1<<INT2)
94+
#define SPI_INT3_MASK (1<<INT3)
95+
#define SPI_INT4_MASK (1<<INT4)
96+
#define SPI_INT5_MASK (1<<INT5)
97+
#define SPI_INT6_MASK (1<<INT6)
98+
#define SPI_INT7_MASK (1<<INT7)
99+
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
100+
#define SPI_INT0_MASK (1<<INT4)
101+
#define SPI_INT1_MASK (1<<INT5)
102+
#define SPI_INT2_MASK (1<<INT0)
103+
#define SPI_INT3_MASK (1<<INT1)
104+
#define SPI_INT4_MASK (1<<INT2)
105+
#define SPI_INT5_MASK (1<<INT3)
106+
#define SPI_INT6_MASK (1<<INT6)
107+
#define SPI_INT7_MASK (1<<INT7)
108+
#else
109+
#ifdef INT0
110+
#define SPI_INT0_MASK (1<<INT0)
111+
#endif
112+
#ifdef INT1
113+
#define SPI_INT1_MASK (1<<INT1)
114+
#endif
115+
#ifdef INT2
116+
#define SPI_INT2_MASK (1<<INT2)
117+
#endif
118+
#endif
119+
120+
void SPIClass::usingInterrupt(uint8_t interruptNumber)
121+
{
122+
uint8_t mask = 0;
123+
uint8_t sreg = SREG;
124+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
125+
switch (interruptNumber) {
126+
#ifdef SPI_INT0_MASK
127+
case 0: mask = SPI_INT0_MASK; break;
128+
#endif
129+
#ifdef SPI_INT1_MASK
130+
case 1: mask = SPI_INT1_MASK; break;
131+
#endif
132+
#ifdef SPI_INT2_MASK
133+
case 2: mask = SPI_INT2_MASK; break;
134+
#endif
135+
#ifdef SPI_INT3_MASK
136+
case 3: mask = SPI_INT3_MASK; break;
137+
#endif
138+
#ifdef SPI_INT4_MASK
139+
case 4: mask = SPI_INT4_MASK; break;
140+
#endif
141+
#ifdef SPI_INT5_MASK
142+
case 5: mask = SPI_INT5_MASK; break;
143+
#endif
144+
#ifdef SPI_INT6_MASK
145+
case 6: mask = SPI_INT6_MASK; break;
146+
#endif
147+
#ifdef SPI_INT7_MASK
148+
case 7: mask = SPI_INT7_MASK; break;
149+
#endif
150+
default:
151+
interruptMode = 2;
152+
break;
153+
}
154+
interruptMask |= mask;
155+
if (!interruptMode)
156+
interruptMode = 1;
157+
SREG = sreg;
158+
}
159+
160+
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
161+
{
162+
// Once in mode 2 we can't go back to 0 without a proper reference count
163+
if (interruptMode == 2)
164+
return;
165+
uint8_t mask = 0;
166+
uint8_t sreg = SREG;
167+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
168+
switch (interruptNumber) {
169+
#ifdef SPI_INT0_MASK
170+
case 0: mask = SPI_INT0_MASK; break;
171+
#endif
172+
#ifdef SPI_INT1_MASK
173+
case 1: mask = SPI_INT1_MASK; break;
174+
#endif
175+
#ifdef SPI_INT2_MASK
176+
case 2: mask = SPI_INT2_MASK; break;
177+
#endif
178+
#ifdef SPI_INT3_MASK
179+
case 3: mask = SPI_INT3_MASK; break;
180+
#endif
181+
#ifdef SPI_INT4_MASK
182+
case 4: mask = SPI_INT4_MASK; break;
183+
#endif
184+
#ifdef SPI_INT5_MASK
185+
case 5: mask = SPI_INT5_MASK; break;
186+
#endif
187+
#ifdef SPI_INT6_MASK
188+
case 6: mask = SPI_INT6_MASK; break;
189+
#endif
190+
#ifdef SPI_INT7_MASK
191+
case 7: mask = SPI_INT7_MASK; break;
192+
#endif
193+
default:
194+
break;
195+
// this case can't be reached
196+
}
197+
interruptMask &= ~mask;
198+
if (!interruptMask)
199+
interruptMode = 0;
200+
SREG = sreg;
201+
}
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
3+
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
4+
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
5+
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
6+
* SPI Master library for arduino.
7+
*
8+
* This file is free software; you can redistribute it and/or modify
9+
* it under the terms of either the GNU General Public License version 2
10+
* or the GNU Lesser General Public License version 2.1, both as
11+
* published by the Free Software Foundation.
12+
*/
13+
14+
#ifndef _SPI_H_INCLUDED
15+
#define _SPI_H_INCLUDED
16+
17+
#include <Arduino.h>
18+
19+
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
20+
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
21+
#define SPI_HAS_TRANSACTION 1
22+
23+
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
24+
#define SPI_HAS_NOTUSINGINTERRUPT 1
25+
26+
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
27+
// This way when there is a bug fix you can check this define to alert users
28+
// of your code if it uses better version of this library.
29+
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
30+
// available too.
31+
#define SPI_ATOMIC_VERSION 1
32+
33+
// Uncomment this line to add detection of mismatched begin/end transactions.
34+
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
35+
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
36+
// on if any mismatch is ever detected.
37+
//#define SPI_TRANSACTION_MISMATCH_LED 5
38+
39+
#ifndef LSBFIRST
40+
#define LSBFIRST 0
41+
#endif
42+
#ifndef MSBFIRST
43+
#define MSBFIRST 1
44+
#endif
45+
46+
#define SPI_CLOCK_DIV4 0x00
47+
#define SPI_CLOCK_DIV16 0x01
48+
#define SPI_CLOCK_DIV64 0x02
49+
#define SPI_CLOCK_DIV128 0x03
50+
#define SPI_CLOCK_DIV2 0x04
51+
#define SPI_CLOCK_DIV8 0x05
52+
#define SPI_CLOCK_DIV32 0x06
53+
54+
#define SPI_MODE0 0x00
55+
#define SPI_MODE1 0x04
56+
#define SPI_MODE2 0x08
57+
#define SPI_MODE3 0x0C
58+
59+
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
60+
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
61+
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
62+
63+
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
64+
#if defined(EIMSK)
65+
#define SPI_AVR_EIMSK EIMSK
66+
#elif defined(GICR)
67+
#define SPI_AVR_EIMSK GICR
68+
#elif defined(GIMSK)
69+
#define SPI_AVR_EIMSK GIMSK
70+
#endif
71+
72+
class SPISettings {
73+
public:
74+
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
75+
if (__builtin_constant_p(clock)) {
76+
init_AlwaysInline(clock, bitOrder, dataMode);
77+
} else {
78+
init_MightInline(clock, bitOrder, dataMode);
79+
}
80+
}
81+
SPISettings() {
82+
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
83+
}
84+
private:
85+
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
86+
init_AlwaysInline(clock, bitOrder, dataMode);
87+
}
88+
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
89+
__attribute__((__always_inline__)) {
90+
// Clock settings are defined as follows. Note that this shows SPI2X
91+
// inverted, so the bits form increasing numbers. Also note that
92+
// fosc/64 appears twice
93+
// SPR1 SPR0 ~SPI2X Freq
94+
// 0 0 0 fosc/2
95+
// 0 0 1 fosc/4
96+
// 0 1 0 fosc/8
97+
// 0 1 1 fosc/16
98+
// 1 0 0 fosc/32
99+
// 1 0 1 fosc/64
100+
// 1 1 0 fosc/64
101+
// 1 1 1 fosc/128
102+
103+
// We find the fastest clock that is less than or equal to the
104+
// given clock rate. The clock divider that results in clock_setting
105+
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
106+
// slowest (128 == 2 ^^ 7, so clock_div = 6).
107+
uint8_t clockDiv;
108+
109+
// When the clock is known at compiletime, use this if-then-else
110+
// cascade, which the compiler knows how to completely optimize
111+
// away. When clock is not known, use a loop instead, which generates
112+
// shorter code.
113+
if (__builtin_constant_p(clock)) {
114+
if (clock >= F_CPU / 2) {
115+
clockDiv = 0;
116+
} else if (clock >= F_CPU / 4) {
117+
clockDiv = 1;
118+
} else if (clock >= F_CPU / 8) {
119+
clockDiv = 2;
120+
} else if (clock >= F_CPU / 16) {
121+
clockDiv = 3;
122+
} else if (clock >= F_CPU / 32) {
123+
clockDiv = 4;
124+
} else if (clock >= F_CPU / 64) {
125+
clockDiv = 5;
126+
} else {
127+
clockDiv = 6;
128+
}
129+
} else {
130+
uint32_t clockSetting = F_CPU / 2;
131+
clockDiv = 0;
132+
while (clockDiv < 6 && clock < clockSetting) {
133+
clockSetting /= 2;
134+
clockDiv++;
135+
}
136+
}
137+
138+
// Compensate for the duplicate fosc/64
139+
if (clockDiv == 6)
140+
clockDiv = 7;
141+
142+
// Invert the SPI2X bit
143+
clockDiv ^= 0x1;
144+
145+
// Pack into the SPISettings class
146+
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
147+
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
148+
spsr = clockDiv & SPI_2XCLOCK_MASK;
149+
}
150+
uint8_t spcr;
151+
uint8_t spsr;
152+
friend class SPIClass;
153+
};
154+
155+
156+
class SPIClass {
157+
public:
158+
// Initialize the SPI library
159+
static void begin();
160+
161+
// If SPI is used from within an interrupt, this function registers
162+
// that interrupt with the SPI library, so beginTransaction() can
163+
// prevent conflicts. The input interruptNumber is the number used
164+
// with attachInterrupt. If SPI is used from a different interrupt
165+
// (eg, a timer), interruptNumber should be 255.
166+
static void usingInterrupt(uint8_t interruptNumber);
167+
// And this does the opposite.
168+
static void notUsingInterrupt(uint8_t interruptNumber);
169+
// Note: the usingInterrupt and notUsingInterrupt functions should
170+
// not to be called from ISR context or inside a transaction.
171+
// For details see:
172+
// https://github.com/arduino/Arduino/pull/2381
173+
// https://github.com/arduino/Arduino/pull/2449
174+
175+
// Before using SPI.transfer() or asserting chip select pins,
176+
// this function is used to gain exclusive access to the SPI bus
177+
// and configure the correct settings.
178+
inline static void beginTransaction(SPISettings settings) {
179+
if (interruptMode > 0) {
180+
uint8_t sreg = SREG;
181+
noInterrupts();
182+
183+
#ifdef SPI_AVR_EIMSK
184+
if (interruptMode == 1) {
185+
interruptSave = SPI_AVR_EIMSK;
186+
SPI_AVR_EIMSK &= ~interruptMask;
187+
SREG = sreg;
188+
} else
189+
#endif
190+
{
191+
interruptSave = sreg;
192+
}
193+
}
194+
195+
#ifdef SPI_TRANSACTION_MISMATCH_LED
196+
if (inTransactionFlag) {
197+
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
198+
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
199+
}
200+
inTransactionFlag = 1;
201+
#endif
202+
203+
SPCR = settings.spcr;
204+
SPSR = settings.spsr;
205+
}
206+
207+
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
208+
inline static uint8_t transfer(uint8_t data) {
209+
SPDR = data;
210+
/*
211+
* The following NOP introduces a small delay that can prevent the wait
212+
* loop form iterating when running at the maximum speed. This gives
213+
* about 10% more speed, even if it seems counter-intuitive. At lower
214+
* speeds it is unnoticed.
215+
*/
216+
asm volatile("nop");
217+
while (!(SPSR & _BV(SPIF))) ; // wait
218+
return SPDR;
219+
}
220+
inline static uint16_t transfer16(uint16_t data) {
221+
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
222+
in.val = data;
223+
if (!(SPCR & _BV(DORD))) {
224+
SPDR = in.msb;
225+
asm volatile("nop"); // See transfer(uint8_t) function
226+
while (!(SPSR & _BV(SPIF))) ;
227+
out.msb = SPDR;
228+
SPDR = in.lsb;
229+
asm volatile("nop");
230+
while (!(SPSR & _BV(SPIF))) ;
231+
out.lsb = SPDR;
232+
} else {
233+
SPDR = in.lsb;
234+
asm volatile("nop");
235+
while (!(SPSR & _BV(SPIF))) ;
236+
out.lsb = SPDR;
237+
SPDR = in.msb;
238+
asm volatile("nop");
239+
while (!(SPSR & _BV(SPIF))) ;
240+
out.msb = SPDR;
241+
}
242+
return out.val;
243+
}
244+
inline static void transfer(void *buf, size_t count) {
245+
if (count == 0) return;
246+
uint8_t *p = (uint8_t *)buf;
247+
SPDR = *p;
248+
while (--count > 0) {
249+
uint8_t out = *(p + 1);
250+
while (!(SPSR & _BV(SPIF))) ;
251+
uint8_t in = SPDR;
252+
SPDR = out;
253+
*p++ = in;
254+
}
255+
while (!(SPSR & _BV(SPIF))) ;
256+
*p = SPDR;
257+
}
258+
// After performing a group of transfers and releasing the chip select
259+
// signal, this function allows others to access the SPI bus
260+
inline static void endTransaction(void) {
261+
#ifdef SPI_TRANSACTION_MISMATCH_LED
262+
if (!inTransactionFlag) {
263+
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
264+
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
265+
}
266+
inTransactionFlag = 0;
267+
#endif
268+
269+
if (interruptMode > 0) {
270+
#ifdef SPI_AVR_EIMSK
271+
uint8_t sreg = SREG;
272+
#endif
273+
noInterrupts();
274+
#ifdef SPI_AVR_EIMSK
275+
if (interruptMode == 1) {
276+
SPI_AVR_EIMSK = interruptSave;
277+
SREG = sreg;
278+
} else
279+
#endif
280+
{
281+
SREG = interruptSave;
282+
}
283+
}
284+
}
285+
286+
// Disable the SPI bus
287+
static void end();
288+
289+
// This function is deprecated. New applications should use
290+
// beginTransaction() to configure SPI settings.
291+
inline static void setBitOrder(uint8_t bitOrder) {
292+
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
293+
else SPCR &= ~(_BV(DORD));
294+
}
295+
// This function is deprecated. New applications should use
296+
// beginTransaction() to configure SPI settings.
297+
inline static void setDataMode(uint8_t dataMode) {
298+
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
299+
}
300+
// This function is deprecated. New applications should use
301+
// beginTransaction() to configure SPI settings.
302+
inline static void setClockDivider(uint8_t clockDiv) {
303+
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
304+
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
305+
}
306+
// These undocumented functions should not be used. SPI.transfer()
307+
// polls the hardware flag which is automatically cleared as the
308+
// AVR responds to SPI's interrupt
309+
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
310+
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
311+
312+
private:
313+
static uint8_t initialized;
314+
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
315+
static uint8_t interruptMask; // which interrupts to mask
316+
static uint8_t interruptSave; // temp storage, to restore state
317+
#ifdef SPI_TRANSACTION_MISMATCH_LED
318+
static uint8_t inTransactionFlag;
319+
#endif
320+
};
321+
322+
extern SPIClass SPI;
323+
324+
#endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#######################################
2+
# Syntax Coloring Map SPI
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
SPI KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
transfer KEYWORD2
17+
setBitOrder KEYWORD2
18+
setDataMode KEYWORD2
19+
setClockDivider KEYWORD2
20+
21+
22+
#######################################
23+
# Constants (LITERAL1)
24+
#######################################
25+
SPI_CLOCK_DIV4 LITERAL1
26+
SPI_CLOCK_DIV16 LITERAL1
27+
SPI_CLOCK_DIV64 LITERAL1
28+
SPI_CLOCK_DIV128 LITERAL1
29+
SPI_CLOCK_DIV2 LITERAL1
30+
SPI_CLOCK_DIV8 LITERAL1
31+
SPI_CLOCK_DIV32 LITERAL1
32+
SPI_CLOCK_DIV64 LITERAL1
33+
SPI_MODE0 LITERAL1
34+
SPI_MODE1 LITERAL1
35+
SPI_MODE2 LITERAL1
36+
SPI_MODE3 LITERAL1
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=SPI
2+
version=1.0
3+
author=Arduino
4+
maintainer=Arduino <info@arduino.cc>
5+
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE.
6+
paragraph=
7+
url=http://arduino.cc/en/Reference/SPI
8+
architectures=avr
9+
types=Arduino
10+
category=Other
11+

‎internal/integrationtest/compile_4/testdata/user_hardware/arduino/avr/.gitkeep

Whitespace-only changes.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
menu.cpu=Processor
2+
3+
custom_yun.name=Arduino Yún
4+
custom_yun.upload.via_ssh=true
5+
6+
custom_yun.build.core=arduino:arduino
7+
custom_yun.bootloader.tool=arduino:avrdude
8+
custom_yun.upload.tool=arduino:avrdude
9+
10+
custom_yun.vid.0=0x2341
11+
custom_yun.pid.0=0x0041
12+
custom_yun.vid.1=0x2341
13+
custom_yun.pid.1=0x8041
14+
custom_yun.upload.protocol=avr109
15+
custom_yun.upload.maximum_size=28672
16+
custom_yun.upload.maximum_data_size=2560
17+
custom_yun.upload.speed=57600
18+
custom_yun.upload.disable_flushing=true
19+
custom_yun.upload.use_1200bps_touch=true
20+
custom_yun.upload.wait_for_upload_port=true
21+
22+
custom_yun.bootloader.low_fuses=0xff
23+
custom_yun.bootloader.high_fuses=0xd8
24+
custom_yun.bootloader.extended_fuses=0xfb
25+
custom_yun.bootloader.file=caterina/Caterina-custom_yun.hex
26+
custom_yun.bootloader.unlock_bits=0x3F
27+
custom_yun.bootloader.lock_bits=0x2F
28+
29+
custom_yun.build.mcu=atmega32u4
30+
custom_yun.build.f_cpu=16000000L
31+
custom_yun.build.vid=0x2341
32+
custom_yun.build.pid=0x8041
33+
custom_yun.build.usb_product="Arduino My"
34+
custom_yun.build.board=AVR_YUN
35+
custom_yun.build.variant=arduino:yun
36+
custom_yun.build.extra_flags={build.usb_flags}
37+
38+
mymega.name=Arduino Mega or Mega 2560
39+
40+
mymega.vid.0=0x2341
41+
mymega.pid.0=0x0010
42+
mymega.vid.1=0x2341
43+
mymega.pid.1=0x0042
44+
mymega.vid.2=0x2A03
45+
mymega.pid.2=0x0010
46+
mymega.vid.3=0x2A03
47+
mymega.pid.3=0x0042
48+
49+
mymega.upload.tool=avrdude
50+
mymega.upload.maximum_data_size=8192
51+
52+
mymega.bootloader.tool=avrdude
53+
mymega.bootloader.low_fuses=0xFF
54+
mymega.bootloader.unlock_bits=0x3F
55+
mymega.bootloader.lock_bits=0x0F
56+
57+
mymega.build.f_cpu=16000000L
58+
mymega.build.core=arduino
59+
mymega.build.variant=mega
60+
61+
mymega.menu.cpu.atmega2560=ATmega2560 (Mega 2560)
62+
63+
mymega.menu.cpu.atmega2560.upload.protocol=wiring
64+
mymega.menu.cpu.atmega2560.upload.maximum_size=253952
65+
mymega.menu.cpu.atmega2560.upload.speed=115200
66+
67+
mymega.menu.cpu.atmega2560.bootloader._folder=stk500v2
68+
mymega.menu.cpu.atmega2560.bootloader.high_fuses=0xD8
69+
mymega.menu.cpu.atmega2560.bootloader.extended_fuses=0xFD
70+
mymega.menu.cpu.atmega2560.bootloader.file={bootloader._folder}/stk500boot_v2_mega2560.hex
71+
72+
mymega.menu.cpu.atmega2560.build.mcu=atmega2560
73+
# Do not define build.board to test autogeneration
74+
#mymega.menu.cpu.atmega2560.build.board=AVR_MYMEGA2560
75+
76+
mymega.menu.cpu.atmega1280=ATmega1280
77+
78+
mymega.menu.cpu.atmega1280.upload.protocol=arduino
79+
mymega.menu.cpu.atmega1280.upload.maximum_size=126976
80+
mymega.menu.cpu.atmega1280.upload.speed=57600
81+
82+
mymega.menu.cpu.atmega1280.bootloader._folder=atmega
83+
mymega.menu.cpu.atmega1280.bootloader.high_fuses=0xDA
84+
mymega.menu.cpu.atmega1280.bootloader.extended_fuses=0xF5
85+
mymega.menu.cpu.atmega1280.bootloader.file={bootloader._folder}/ATmegaBOOT_168_atmega1280.hex
86+
87+
mymega.menu.cpu.atmega1280.build.mcu=atmega1280
88+
# define custom build.board for testing
89+
mymega.menu.cpu.atmega1280.build.board=MYMEGA1280

‎internal/integrationtest/compile_4/testdata/user_hardware/my_avr_platform/avr/bootloaders/stk500v2/stk500boot_v2_mega2560.hex

Lines changed: 469 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
3+
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
4+
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
5+
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
6+
* SPI Master library for arduino.
7+
*
8+
* This file is free software; you can redistribute it and/or modify
9+
* it under the terms of either the GNU General Public License version 2
10+
* or the GNU Lesser General Public License version 2.1, both as
11+
* published by the Free Software Foundation.
12+
*/
13+
14+
#include "SPI.h"
15+
16+
SPIClass SPI;
17+
18+
uint8_t SPIClass::initialized = 0;
19+
uint8_t SPIClass::interruptMode = 0;
20+
uint8_t SPIClass::interruptMask = 0;
21+
uint8_t SPIClass::interruptSave = 0;
22+
#ifdef SPI_TRANSACTION_MISMATCH_LED
23+
uint8_t SPIClass::inTransactionFlag = 0;
24+
#endif
25+
26+
void SPIClass::begin()
27+
{
28+
uint8_t sreg = SREG;
29+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
30+
if (!initialized) {
31+
// Set SS to high so a connected chip will be "deselected" by default
32+
uint8_t port = digitalPinToPort(SS);
33+
uint8_t bit = digitalPinToBitMask(SS);
34+
volatile uint8_t *reg = portModeRegister(port);
35+
36+
// if the SS pin is not already configured as an output
37+
// then set it high (to enable the internal pull-up resistor)
38+
if(!(*reg & bit)){
39+
digitalWrite(SS, HIGH);
40+
}
41+
42+
// When the SS pin is set as OUTPUT, it can be used as
43+
// a general purpose output port (it doesn't influence
44+
// SPI operations).
45+
pinMode(SS, OUTPUT);
46+
47+
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
48+
// automatically switches to Slave, so the data direction of
49+
// the SS pin MUST be kept as OUTPUT.
50+
SPCR |= _BV(MSTR);
51+
SPCR |= _BV(SPE);
52+
53+
// Set direction register for SCK and MOSI pin.
54+
// MISO pin automatically overrides to INPUT.
55+
// By doing this AFTER enabling SPI, we avoid accidentally
56+
// clocking in a single bit since the lines go directly
57+
// from "input" to SPI control.
58+
// http://code.google.com/p/arduino/issues/detail?id=888
59+
pinMode(SCK, OUTPUT);
60+
pinMode(MOSI, OUTPUT);
61+
}
62+
initialized++; // reference count
63+
SREG = sreg;
64+
}
65+
66+
void SPIClass::end() {
67+
uint8_t sreg = SREG;
68+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
69+
// Decrease the reference counter
70+
if (initialized)
71+
initialized--;
72+
// If there are no more references disable SPI
73+
if (!initialized) {
74+
SPCR &= ~_BV(SPE);
75+
interruptMode = 0;
76+
#ifdef SPI_TRANSACTION_MISMATCH_LED
77+
inTransactionFlag = 0;
78+
#endif
79+
}
80+
SREG = sreg;
81+
}
82+
83+
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
84+
#if defined(__AVR_ATmega32U4__)
85+
#define SPI_INT0_MASK (1<<INT0)
86+
#define SPI_INT1_MASK (1<<INT1)
87+
#define SPI_INT2_MASK (1<<INT2)
88+
#define SPI_INT3_MASK (1<<INT3)
89+
#define SPI_INT4_MASK (1<<INT6)
90+
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
91+
#define SPI_INT0_MASK (1<<INT0)
92+
#define SPI_INT1_MASK (1<<INT1)
93+
#define SPI_INT2_MASK (1<<INT2)
94+
#define SPI_INT3_MASK (1<<INT3)
95+
#define SPI_INT4_MASK (1<<INT4)
96+
#define SPI_INT5_MASK (1<<INT5)
97+
#define SPI_INT6_MASK (1<<INT6)
98+
#define SPI_INT7_MASK (1<<INT7)
99+
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
100+
#define SPI_INT0_MASK (1<<INT4)
101+
#define SPI_INT1_MASK (1<<INT5)
102+
#define SPI_INT2_MASK (1<<INT0)
103+
#define SPI_INT3_MASK (1<<INT1)
104+
#define SPI_INT4_MASK (1<<INT2)
105+
#define SPI_INT5_MASK (1<<INT3)
106+
#define SPI_INT6_MASK (1<<INT6)
107+
#define SPI_INT7_MASK (1<<INT7)
108+
#else
109+
#ifdef INT0
110+
#define SPI_INT0_MASK (1<<INT0)
111+
#endif
112+
#ifdef INT1
113+
#define SPI_INT1_MASK (1<<INT1)
114+
#endif
115+
#ifdef INT2
116+
#define SPI_INT2_MASK (1<<INT2)
117+
#endif
118+
#endif
119+
120+
void SPIClass::usingInterrupt(uint8_t interruptNumber)
121+
{
122+
uint8_t mask = 0;
123+
uint8_t sreg = SREG;
124+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
125+
switch (interruptNumber) {
126+
#ifdef SPI_INT0_MASK
127+
case 0: mask = SPI_INT0_MASK; break;
128+
#endif
129+
#ifdef SPI_INT1_MASK
130+
case 1: mask = SPI_INT1_MASK; break;
131+
#endif
132+
#ifdef SPI_INT2_MASK
133+
case 2: mask = SPI_INT2_MASK; break;
134+
#endif
135+
#ifdef SPI_INT3_MASK
136+
case 3: mask = SPI_INT3_MASK; break;
137+
#endif
138+
#ifdef SPI_INT4_MASK
139+
case 4: mask = SPI_INT4_MASK; break;
140+
#endif
141+
#ifdef SPI_INT5_MASK
142+
case 5: mask = SPI_INT5_MASK; break;
143+
#endif
144+
#ifdef SPI_INT6_MASK
145+
case 6: mask = SPI_INT6_MASK; break;
146+
#endif
147+
#ifdef SPI_INT7_MASK
148+
case 7: mask = SPI_INT7_MASK; break;
149+
#endif
150+
default:
151+
interruptMode = 2;
152+
break;
153+
}
154+
interruptMask |= mask;
155+
if (!interruptMode)
156+
interruptMode = 1;
157+
SREG = sreg;
158+
}
159+
160+
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
161+
{
162+
// Once in mode 2 we can't go back to 0 without a proper reference count
163+
if (interruptMode == 2)
164+
return;
165+
uint8_t mask = 0;
166+
uint8_t sreg = SREG;
167+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
168+
switch (interruptNumber) {
169+
#ifdef SPI_INT0_MASK
170+
case 0: mask = SPI_INT0_MASK; break;
171+
#endif
172+
#ifdef SPI_INT1_MASK
173+
case 1: mask = SPI_INT1_MASK; break;
174+
#endif
175+
#ifdef SPI_INT2_MASK
176+
case 2: mask = SPI_INT2_MASK; break;
177+
#endif
178+
#ifdef SPI_INT3_MASK
179+
case 3: mask = SPI_INT3_MASK; break;
180+
#endif
181+
#ifdef SPI_INT4_MASK
182+
case 4: mask = SPI_INT4_MASK; break;
183+
#endif
184+
#ifdef SPI_INT5_MASK
185+
case 5: mask = SPI_INT5_MASK; break;
186+
#endif
187+
#ifdef SPI_INT6_MASK
188+
case 6: mask = SPI_INT6_MASK; break;
189+
#endif
190+
#ifdef SPI_INT7_MASK
191+
case 7: mask = SPI_INT7_MASK; break;
192+
#endif
193+
default:
194+
break;
195+
// this case can't be reached
196+
}
197+
interruptMask &= ~mask;
198+
if (!interruptMask)
199+
interruptMode = 0;
200+
SREG = sreg;
201+
}
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
3+
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
4+
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
5+
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
6+
* SPI Master library for arduino.
7+
*
8+
* This file is free software; you can redistribute it and/or modify
9+
* it under the terms of either the GNU General Public License version 2
10+
* or the GNU Lesser General Public License version 2.1, both as
11+
* published by the Free Software Foundation.
12+
*/
13+
14+
#ifndef _SPI_H_INCLUDED
15+
#define _SPI_H_INCLUDED
16+
17+
#include <Arduino.h>
18+
19+
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
20+
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
21+
#define SPI_HAS_TRANSACTION 1
22+
23+
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
24+
#define SPI_HAS_NOTUSINGINTERRUPT 1
25+
26+
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
27+
// This way when there is a bug fix you can check this define to alert users
28+
// of your code if it uses better version of this library.
29+
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
30+
// available too.
31+
#define SPI_ATOMIC_VERSION 1
32+
33+
// Uncomment this line to add detection of mismatched begin/end transactions.
34+
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
35+
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
36+
// on if any mismatch is ever detected.
37+
//#define SPI_TRANSACTION_MISMATCH_LED 5
38+
39+
#ifndef LSBFIRST
40+
#define LSBFIRST 0
41+
#endif
42+
#ifndef MSBFIRST
43+
#define MSBFIRST 1
44+
#endif
45+
46+
#define SPI_CLOCK_DIV4 0x00
47+
#define SPI_CLOCK_DIV16 0x01
48+
#define SPI_CLOCK_DIV64 0x02
49+
#define SPI_CLOCK_DIV128 0x03
50+
#define SPI_CLOCK_DIV2 0x04
51+
#define SPI_CLOCK_DIV8 0x05
52+
#define SPI_CLOCK_DIV32 0x06
53+
54+
#define SPI_MODE0 0x00
55+
#define SPI_MODE1 0x04
56+
#define SPI_MODE2 0x08
57+
#define SPI_MODE3 0x0C
58+
59+
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
60+
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
61+
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
62+
63+
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
64+
#if defined(EIMSK)
65+
#define SPI_AVR_EIMSK EIMSK
66+
#elif defined(GICR)
67+
#define SPI_AVR_EIMSK GICR
68+
#elif defined(GIMSK)
69+
#define SPI_AVR_EIMSK GIMSK
70+
#endif
71+
72+
class SPISettings {
73+
public:
74+
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
75+
if (__builtin_constant_p(clock)) {
76+
init_AlwaysInline(clock, bitOrder, dataMode);
77+
} else {
78+
init_MightInline(clock, bitOrder, dataMode);
79+
}
80+
}
81+
SPISettings() {
82+
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
83+
}
84+
private:
85+
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
86+
init_AlwaysInline(clock, bitOrder, dataMode);
87+
}
88+
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
89+
__attribute__((__always_inline__)) {
90+
// Clock settings are defined as follows. Note that this shows SPI2X
91+
// inverted, so the bits form increasing numbers. Also note that
92+
// fosc/64 appears twice
93+
// SPR1 SPR0 ~SPI2X Freq
94+
// 0 0 0 fosc/2
95+
// 0 0 1 fosc/4
96+
// 0 1 0 fosc/8
97+
// 0 1 1 fosc/16
98+
// 1 0 0 fosc/32
99+
// 1 0 1 fosc/64
100+
// 1 1 0 fosc/64
101+
// 1 1 1 fosc/128
102+
103+
// We find the fastest clock that is less than or equal to the
104+
// given clock rate. The clock divider that results in clock_setting
105+
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
106+
// slowest (128 == 2 ^^ 7, so clock_div = 6).
107+
uint8_t clockDiv;
108+
109+
// When the clock is known at compiletime, use this if-then-else
110+
// cascade, which the compiler knows how to completely optimize
111+
// away. When clock is not known, use a loop instead, which generates
112+
// shorter code.
113+
if (__builtin_constant_p(clock)) {
114+
if (clock >= F_CPU / 2) {
115+
clockDiv = 0;
116+
} else if (clock >= F_CPU / 4) {
117+
clockDiv = 1;
118+
} else if (clock >= F_CPU / 8) {
119+
clockDiv = 2;
120+
} else if (clock >= F_CPU / 16) {
121+
clockDiv = 3;
122+
} else if (clock >= F_CPU / 32) {
123+
clockDiv = 4;
124+
} else if (clock >= F_CPU / 64) {
125+
clockDiv = 5;
126+
} else {
127+
clockDiv = 6;
128+
}
129+
} else {
130+
uint32_t clockSetting = F_CPU / 2;
131+
clockDiv = 0;
132+
while (clockDiv < 6 && clock < clockSetting) {
133+
clockSetting /= 2;
134+
clockDiv++;
135+
}
136+
}
137+
138+
// Compensate for the duplicate fosc/64
139+
if (clockDiv == 6)
140+
clockDiv = 7;
141+
142+
// Invert the SPI2X bit
143+
clockDiv ^= 0x1;
144+
145+
// Pack into the SPISettings class
146+
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
147+
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
148+
spsr = clockDiv & SPI_2XCLOCK_MASK;
149+
}
150+
uint8_t spcr;
151+
uint8_t spsr;
152+
friend class SPIClass;
153+
};
154+
155+
156+
class SPIClass {
157+
public:
158+
// Initialize the SPI library
159+
static void begin();
160+
161+
// If SPI is used from within an interrupt, this function registers
162+
// that interrupt with the SPI library, so beginTransaction() can
163+
// prevent conflicts. The input interruptNumber is the number used
164+
// with attachInterrupt. If SPI is used from a different interrupt
165+
// (eg, a timer), interruptNumber should be 255.
166+
static void usingInterrupt(uint8_t interruptNumber);
167+
// And this does the opposite.
168+
static void notUsingInterrupt(uint8_t interruptNumber);
169+
// Note: the usingInterrupt and notUsingInterrupt functions should
170+
// not to be called from ISR context or inside a transaction.
171+
// For details see:
172+
// https://github.com/arduino/Arduino/pull/2381
173+
// https://github.com/arduino/Arduino/pull/2449
174+
175+
// Before using SPI.transfer() or asserting chip select pins,
176+
// this function is used to gain exclusive access to the SPI bus
177+
// and configure the correct settings.
178+
inline static void beginTransaction(SPISettings settings) {
179+
if (interruptMode > 0) {
180+
uint8_t sreg = SREG;
181+
noInterrupts();
182+
183+
#ifdef SPI_AVR_EIMSK
184+
if (interruptMode == 1) {
185+
interruptSave = SPI_AVR_EIMSK;
186+
SPI_AVR_EIMSK &= ~interruptMask;
187+
SREG = sreg;
188+
} else
189+
#endif
190+
{
191+
interruptSave = sreg;
192+
}
193+
}
194+
195+
#ifdef SPI_TRANSACTION_MISMATCH_LED
196+
if (inTransactionFlag) {
197+
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
198+
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
199+
}
200+
inTransactionFlag = 1;
201+
#endif
202+
203+
SPCR = settings.spcr;
204+
SPSR = settings.spsr;
205+
}
206+
207+
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
208+
inline static uint8_t transfer(uint8_t data) {
209+
SPDR = data;
210+
/*
211+
* The following NOP introduces a small delay that can prevent the wait
212+
* loop form iterating when running at the maximum speed. This gives
213+
* about 10% more speed, even if it seems counter-intuitive. At lower
214+
* speeds it is unnoticed.
215+
*/
216+
asm volatile("nop");
217+
while (!(SPSR & _BV(SPIF))) ; // wait
218+
return SPDR;
219+
}
220+
inline static uint16_t transfer16(uint16_t data) {
221+
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
222+
in.val = data;
223+
if (!(SPCR & _BV(DORD))) {
224+
SPDR = in.msb;
225+
asm volatile("nop"); // See transfer(uint8_t) function
226+
while (!(SPSR & _BV(SPIF))) ;
227+
out.msb = SPDR;
228+
SPDR = in.lsb;
229+
asm volatile("nop");
230+
while (!(SPSR & _BV(SPIF))) ;
231+
out.lsb = SPDR;
232+
} else {
233+
SPDR = in.lsb;
234+
asm volatile("nop");
235+
while (!(SPSR & _BV(SPIF))) ;
236+
out.lsb = SPDR;
237+
SPDR = in.msb;
238+
asm volatile("nop");
239+
while (!(SPSR & _BV(SPIF))) ;
240+
out.msb = SPDR;
241+
}
242+
return out.val;
243+
}
244+
inline static void transfer(void *buf, size_t count) {
245+
if (count == 0) return;
246+
uint8_t *p = (uint8_t *)buf;
247+
SPDR = *p;
248+
while (--count > 0) {
249+
uint8_t out = *(p + 1);
250+
while (!(SPSR & _BV(SPIF))) ;
251+
uint8_t in = SPDR;
252+
SPDR = out;
253+
*p++ = in;
254+
}
255+
while (!(SPSR & _BV(SPIF))) ;
256+
*p = SPDR;
257+
}
258+
// After performing a group of transfers and releasing the chip select
259+
// signal, this function allows others to access the SPI bus
260+
inline static void endTransaction(void) {
261+
#ifdef SPI_TRANSACTION_MISMATCH_LED
262+
if (!inTransactionFlag) {
263+
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
264+
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
265+
}
266+
inTransactionFlag = 0;
267+
#endif
268+
269+
if (interruptMode > 0) {
270+
#ifdef SPI_AVR_EIMSK
271+
uint8_t sreg = SREG;
272+
#endif
273+
noInterrupts();
274+
#ifdef SPI_AVR_EIMSK
275+
if (interruptMode == 1) {
276+
SPI_AVR_EIMSK = interruptSave;
277+
SREG = sreg;
278+
} else
279+
#endif
280+
{
281+
SREG = interruptSave;
282+
}
283+
}
284+
}
285+
286+
// Disable the SPI bus
287+
static void end();
288+
289+
// This function is deprecated. New applications should use
290+
// beginTransaction() to configure SPI settings.
291+
inline static void setBitOrder(uint8_t bitOrder) {
292+
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
293+
else SPCR &= ~(_BV(DORD));
294+
}
295+
// This function is deprecated. New applications should use
296+
// beginTransaction() to configure SPI settings.
297+
inline static void setDataMode(uint8_t dataMode) {
298+
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
299+
}
300+
// This function is deprecated. New applications should use
301+
// beginTransaction() to configure SPI settings.
302+
inline static void setClockDivider(uint8_t clockDiv) {
303+
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
304+
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
305+
}
306+
// These undocumented functions should not be used. SPI.transfer()
307+
// polls the hardware flag which is automatically cleared as the
308+
// AVR responds to SPI's interrupt
309+
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
310+
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
311+
312+
private:
313+
static uint8_t initialized;
314+
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
315+
static uint8_t interruptMask; // which interrupts to mask
316+
static uint8_t interruptSave; // temp storage, to restore state
317+
#ifdef SPI_TRANSACTION_MISMATCH_LED
318+
static uint8_t inTransactionFlag;
319+
#endif
320+
};
321+
322+
extern SPIClass SPI;
323+
324+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
SCP1000 Barometric Pressure Sensor Display
3+
4+
Shows the output of a Barometric Pressure Sensor on a
5+
Uses the SPI library. For details on the sensor, see:
6+
http://www.sparkfun.com/commerce/product_info.php?products_id=8161
7+
http://www.vti.fi/en/support/obsolete_products/pressure_sensors/
8+
9+
This sketch adapted from Nathan Seidle's SCP1000 example for PIC:
10+
http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip
11+
12+
Circuit:
13+
SCP1000 sensor attached to pins 6, 7, 10 - 13:
14+
DRDY: pin 6
15+
CSB: pin 7
16+
MOSI: pin 11
17+
MISO: pin 12
18+
SCK: pin 13
19+
20+
created 31 July 2010
21+
modified 14 August 2010
22+
by Tom Igoe
23+
*/
24+
25+
// the sensor communicates using SPI, so include the library:
26+
#include <SPI.h>
27+
28+
//Sensor's memory register addresses:
29+
const int PRESSURE = 0x1F; //3 most significant bits of pressure
30+
const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure
31+
const int TEMPERATURE = 0x21; //16 bit temperature reading
32+
const byte READ = 0b11111100; // SCP1000's read command
33+
const byte WRITE = 0b00000010; // SCP1000's write command
34+
35+
// pins used for the connection with the sensor
36+
// the other you need are controlled by the SPI library):
37+
const int dataReadyPin = 6;
38+
const int chipSelectPin = 7;
39+
40+
void setup() {
41+
Serial.begin(9600);
42+
43+
// start the SPI library:
44+
SPI.begin();
45+
46+
// initalize the data ready and chip select pins:
47+
pinMode(dataReadyPin, INPUT);
48+
pinMode(chipSelectPin, OUTPUT);
49+
50+
//Configure SCP1000 for low noise configuration:
51+
writeRegister(0x02, 0x2D);
52+
writeRegister(0x01, 0x03);
53+
writeRegister(0x03, 0x02);
54+
// give the sensor time to set up:
55+
delay(100);
56+
}
57+
58+
void loop() {
59+
//Select High Resolution Mode
60+
writeRegister(0x03, 0x0A);
61+
62+
// don't do anything until the data ready pin is high:
63+
if (digitalRead(dataReadyPin) == HIGH) {
64+
//Read the temperature data
65+
int tempData = readRegister(0x21, 2);
66+
67+
// convert the temperature to celsius and display it:
68+
float realTemp = (float)tempData / 20.0;
69+
Serial.print("Temp[C]=");
70+
Serial.print(realTemp);
71+
72+
73+
//Read the pressure data highest 3 bits:
74+
byte pressure_data_high = readRegister(0x1F, 1);
75+
pressure_data_high &= 0b00000111; //you only needs bits 2 to 0
76+
77+
//Read the pressure data lower 16 bits:
78+
unsigned int pressure_data_low = readRegister(0x20, 2);
79+
//combine the two parts into one 19-bit number:
80+
long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;
81+
82+
// display the temperature:
83+
Serial.println("\tPressure [Pa]=" + String(pressure));
84+
}
85+
}
86+
87+
//Read from or write to register from the SCP1000:
88+
unsigned int readRegister(byte thisRegister, int bytesToRead ) {
89+
byte inByte = 0; // incoming byte from the SPI
90+
unsigned int result = 0; // result to return
91+
Serial.print(thisRegister, BIN);
92+
Serial.print("\t");
93+
// SCP1000 expects the register name in the upper 6 bits
94+
// of the byte. So shift the bits left by two bits:
95+
thisRegister = thisRegister << 2;
96+
// now combine the address and the command into one byte
97+
byte dataToSend = thisRegister & READ;
98+
Serial.println(thisRegister, BIN);
99+
// take the chip select low to select the device:
100+
digitalWrite(chipSelectPin, LOW);
101+
// send the device the register you want to read:
102+
SPI.transfer(dataToSend);
103+
// send a value of 0 to read the first byte returned:
104+
result = SPI.transfer(0x00);
105+
// decrement the number of bytes left to read:
106+
bytesToRead--;
107+
// if you still have another byte to read:
108+
if (bytesToRead > 0) {
109+
// shift the first byte left, then get the second byte:
110+
result = result << 8;
111+
inByte = SPI.transfer(0x00);
112+
// combine the byte you just got with the previous one:
113+
result = result | inByte;
114+
// decrement the number of bytes left to read:
115+
bytesToRead--;
116+
}
117+
// take the chip select high to de-select:
118+
digitalWrite(chipSelectPin, HIGH);
119+
// return the result:
120+
return(result);
121+
}
122+
123+
124+
//Sends a write command to SCP1000
125+
126+
void writeRegister(byte thisRegister, byte thisValue) {
127+
128+
// SCP1000 expects the register address in the upper 6 bits
129+
// of the byte. So shift the bits left by two bits:
130+
thisRegister = thisRegister << 2;
131+
// now combine the register address and the command into one byte:
132+
byte dataToSend = thisRegister | WRITE;
133+
134+
// take the chip select low to select the device:
135+
digitalWrite(chipSelectPin, LOW);
136+
137+
SPI.transfer(dataToSend); //Send register location
138+
SPI.transfer(thisValue); //Send value to record into register
139+
140+
// take the chip select high to de-select:
141+
digitalWrite(chipSelectPin, HIGH);
142+
}
143+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
Digital Pot Control
3+
4+
This example controls an Analog Devices AD5206 digital potentiometer.
5+
The AD5206 has 6 potentiometer channels. Each channel's pins are labeled
6+
A - connect this to voltage
7+
W - this is the pot's wiper, which changes when you set it
8+
B - connect this to ground.
9+
10+
The AD5206 is SPI-compatible,and to command it, you send two bytes,
11+
one with the channel number (0 - 5) and one with the resistance value for the
12+
channel (0 - 255).
13+
14+
The circuit:
15+
* All A pins of AD5206 connected to +5V
16+
* All B pins of AD5206 connected to ground
17+
* An LED and a 220-ohm resisor in series connected from each W pin to ground
18+
* CS - to digital pin 10 (SS pin)
19+
* SDI - to digital pin 11 (MOSI pin)
20+
* CLK - to digital pin 13 (SCK pin)
21+
22+
created 10 Aug 2010
23+
by Tom Igoe
24+
25+
Thanks to Heather Dewey-Hagborg for the original tutorial, 2005
26+
27+
*/
28+
29+
30+
// inslude the SPI library:
31+
#include <SPI.h>
32+
33+
34+
// set pin 10 as the slave select for the digital pot:
35+
const int slaveSelectPin = 10;
36+
37+
void setup() {
38+
// set the slaveSelectPin as an output:
39+
pinMode (slaveSelectPin, OUTPUT);
40+
// initialize SPI:
41+
SPI.begin();
42+
}
43+
44+
void loop() {
45+
// go through the six channels of the digital pot:
46+
for (int channel = 0; channel < 6; channel++) {
47+
// change the resistance on this channel from min to max:
48+
for (int level = 0; level < 255; level++) {
49+
digitalPotWrite(channel, level);
50+
delay(10);
51+
}
52+
// wait a second at the top:
53+
delay(100);
54+
// change the resistance on this channel from max to min:
55+
for (int level = 0; level < 255; level++) {
56+
digitalPotWrite(channel, 255 - level);
57+
delay(10);
58+
}
59+
}
60+
61+
}
62+
63+
void digitalPotWrite(int address, int value) {
64+
// take the SS pin low to select the chip:
65+
digitalWrite(slaveSelectPin, LOW);
66+
// send in the address and value via SPI:
67+
SPI.transfer(address);
68+
SPI.transfer(value);
69+
// take the SS pin high to de-select the chip:
70+
digitalWrite(slaveSelectPin, HIGH);
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#######################################
2+
# Syntax Coloring Map SPI
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
SPI KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
transfer KEYWORD2
17+
setBitOrder KEYWORD2
18+
setDataMode KEYWORD2
19+
setClockDivider KEYWORD2
20+
21+
22+
#######################################
23+
# Constants (LITERAL1)
24+
#######################################
25+
SPI_CLOCK_DIV4 LITERAL1
26+
SPI_CLOCK_DIV16 LITERAL1
27+
SPI_CLOCK_DIV64 LITERAL1
28+
SPI_CLOCK_DIV128 LITERAL1
29+
SPI_CLOCK_DIV2 LITERAL1
30+
SPI_CLOCK_DIV8 LITERAL1
31+
SPI_CLOCK_DIV32 LITERAL1
32+
SPI_CLOCK_DIV64 LITERAL1
33+
SPI_MODE0 LITERAL1
34+
SPI_MODE1 LITERAL1
35+
SPI_MODE2 LITERAL1
36+
SPI_MODE3 LITERAL1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name=SPI
2+
version=1.0
3+
author=Arduino
4+
maintainer=Arduino <info@arduino.cc>
5+
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE.
6+
paragraph=
7+
url=http://arduino.cc/en/Reference/SPI
8+
architectures=avr
9+
types=Arduino
10+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
# Arduino AVR Core and platform.
3+
# ------------------------------
4+
5+
# For more info:
6+
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
7+
8+
name=My AVR Boards
9+
version=9.9.9
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
my_avr_platform

‎legacy/builder/test/includes_to_include_folders_test.go

Lines changed: 0 additions & 141 deletions
This file was deleted.

‎legacy/builder/test/try_build_of_problematic_sketch_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ import (
3131
// tryBuild(t, paths.New("sketch_that_checks_if_SPI_has_transactions_and_includes_missing_Ethernet", "sketch.ino"))
3232
//}
3333

34-
func TestTryBuild032(t *testing.T) {
35-
tryBuild(t, paths.New("sketch10", "sketch10.ino"))
36-
}
37-
3834
func TestTryBuild033(t *testing.T) {
3935
tryBuild(t, paths.New("sketch_that_includes_arduino_h", "sketch_that_includes_arduino_h.ino"))
4036
}

0 commit comments

Comments
 (0)
Please sign in to comment.