Skip to content

Commit acf81f4

Browse files
Add PIO-based SoftwareSPI enabling SPI on any pins (earlephilhower#2778)
* Add PIO-based SoftwareSPI enabling SPI on any pins The Raspberry Pi team has a working PIO-based SPI interface. Wrap it to work like a hardware SPI interface, allowing SPI on any pin combination. Tested reading and writing an SD card using unmodified SD library. * Add W5500 example Good for testing, shows non-contiguous pin outs.
1 parent a426fbf commit acf81f4

File tree

11 files changed

+1110
-2
lines changed

11 files changed

+1110
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ The RP2040 PIO state machines (SMs) are used to generate jitter-free:
148148
* I2S Input
149149
* I2S Output
150150
* Software UARTs (Serial ports)
151-
151+
* Software SPIs
152152

153153
# Installing via Arduino Boards Manager
154154
## Windows-specific Notes

docs/spi.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ pin itself, as is the standard way in Arduino.
2828

2929
* The interrupt calls (``attachInterrupt``, and ``detachInterrpt``) are not implemented.
3030

31+
Software SPI (Master Only)
32+
==========================
33+
34+
Similar to ``SoftwareSerial``, ``SoftwareSPI`` creates a PIO based SPI interface that
35+
can be used in the same manner as the hardware SPI devices. The constructor takes the
36+
pins desired, which can be any GPIO pins with the rule that if hardware CS is used then
37+
it must be on pin ``SCK + 1``. Construct a ``SoftwareSPI`` object in your code as
38+
follows and use it as needed (i.e. pass it into ``SD.begin(_CS, softwareSPI);``
39+
40+
.. code:: cpp
41+
42+
#include <SoftwareSPI.h>
43+
SoftwareSPI softSPI(_sck, _miso, _mosi); // no HW CS support, any selection of pins can be used
3144
3245
SPI Slave (SPISlave)
3346
====================
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
SD card basic file example with Software SPI
3+
4+
This example shows how to create and destroy an SD card file
5+
The circuit:
6+
SD card attached to Pico as follows:
7+
** SCK - GPIO0
8+
** CS - GPIO1
9+
** MISO (AKA RX) - GPIO2
10+
** MOSI (AKA TX) - GPIO3
11+
12+
created Nov 2010
13+
by David A. Mellis
14+
modified 9 Apr 2012
15+
by Tom Igoe
16+
17+
This example code is in the public domain.
18+
*/
19+
20+
#include <SoftwareSPI.h>
21+
22+
const int _SCK = 0;
23+
const int _CS = 1; // Must be SCK+1 for HW CS support
24+
const int _MISO = 2;
25+
const int _MOSI = 3;
26+
SoftwareSPI softSPI(_SCK, _MISO, _MOSI, _CS);
27+
28+
#include <SD.h>
29+
30+
File myFile;
31+
32+
void setup() {
33+
// Open serial communications and wait for port to open:
34+
Serial.begin(115200);
35+
36+
do {
37+
delay(100); // wait for serial port to connect. Needed for native USB port only
38+
} while (!Serial);
39+
40+
Serial.print("Initializing SD card...");
41+
42+
bool sdInitialized = false;
43+
sdInitialized = SD.begin(_CS, softSPI);
44+
if (!sdInitialized) {
45+
Serial.println("initialization failed!");
46+
return;
47+
}
48+
Serial.println("initialization done.");
49+
50+
if (SD.exists("example.txt")) {
51+
Serial.println("example.txt exists.");
52+
} else {
53+
Serial.println("example.txt doesn't exist.");
54+
}
55+
56+
// open a new file and immediately close it:
57+
Serial.println("Creating example.txt...");
58+
myFile = SD.open("example.txt", FILE_WRITE);
59+
myFile.close();
60+
61+
// Check to see if the file exists:
62+
if (SD.exists("example.txt")) {
63+
Serial.println("example.txt exists.");
64+
} else {
65+
Serial.println("example.txt doesn't exist.");
66+
}
67+
68+
// delete the file:
69+
Serial.println("Removing example.txt...");
70+
SD.remove("example.txt");
71+
72+
if (SD.exists("example.txt")) {
73+
Serial.println("example.txt exists.");
74+
} else {
75+
Serial.println("example.txt doesn't exist.");
76+
}
77+
}
78+
79+
void loop() {
80+
// nothing happens after setup finishes.
81+
}
82+
83+
84+
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
This sketch establishes a TCP connection to a "quote of the day" service.
3+
It sends a "hello" message, and then prints received data.
4+
*/
5+
6+
#include <W5500lwIP.h>
7+
8+
const char* host = "djxmmx.net";
9+
const uint16_t port = 17;
10+
11+
#include <SoftwareSPI.h>
12+
const int _SCK = 0; // Any pin allowed
13+
const int _CS = 1; // Must be SCK+1 for HW CS support
14+
const int _MISO = 28; // Note that MOSI and MISO don't need to be contiguous. Any pins allowed
15+
const int _MOSI = 3; // Any pin not used elsewhere
16+
const int _INT = 4; // W5500 IRQ line
17+
18+
SoftwareSPI softSPI(_SCK, _MISO, _MOSI, _CS);
19+
20+
Wiznet5500lwIP eth(_CS, softSPI, _INT);
21+
22+
void setup() {
23+
Serial.begin(115200);
24+
delay(5000);
25+
Serial.println();
26+
Serial.println();
27+
Serial.println("Starting Ethernet port");
28+
29+
// Start the Ethernet port
30+
if (!eth.begin()) {
31+
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
32+
while (1) {
33+
delay(1000);
34+
}
35+
}
36+
37+
while (!eth.connected()) {
38+
Serial.print(".");
39+
delay(500);
40+
}
41+
42+
Serial.println("");
43+
Serial.println("Ethernet connected");
44+
Serial.println("IP address: ");
45+
Serial.println(eth.localIP());
46+
}
47+
48+
void loop() {
49+
static bool wait = false;
50+
51+
Serial.print("connecting to ");
52+
Serial.print(host);
53+
Serial.print(':');
54+
Serial.println(port);
55+
56+
// Use WiFiClient class to create TCP connections
57+
WiFiClient client;
58+
if (!client.connect(host, port)) {
59+
Serial.println("connection failed");
60+
delay(5000);
61+
return;
62+
}
63+
64+
// This will send a string to the server
65+
Serial.println("sending data to server");
66+
if (client.connected()) {
67+
client.println("hello from RP2040");
68+
}
69+
70+
// wait for data to be available
71+
unsigned long timeout = millis();
72+
while (client.available() == 0) {
73+
if (millis() - timeout > 5000) {
74+
Serial.println(">>> Client Timeout !");
75+
client.stop();
76+
delay(60000);
77+
return;
78+
}
79+
}
80+
81+
// Read all the lines of the reply from server and print them to Serial
82+
Serial.println("receiving from remote server");
83+
// not testing 'client.connected()' since we do not need to send data here
84+
while (client.available()) {
85+
char ch = static_cast<char>(client.read());
86+
Serial.print(ch);
87+
}
88+
89+
// Close the connection
90+
Serial.println();
91+
Serial.println("closing connection");
92+
client.stop();
93+
94+
if (wait) {
95+
delay(300000); // execute once every 5 minutes, don't flood remote service
96+
}
97+
wait = true;
98+
}

libraries/SoftwareSPI/keywords.txt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#######################################
2+
# Syntax Coloring Map SPI
3+
#######################################
4+
5+
#######################################
6+
# Instances (KEYWORD2)
7+
#######################################
8+
9+
SoftwareSPI KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
beginTransaction KEYWORD2
17+
endTransaction KEYWORD2
18+
SPISettings KEYWORD2
19+
transfer KEYWORD2
20+
transfer16 KEYWORD2
21+
setBitOrder KEYWORD2
22+
setDataMode KEYWORD2
23+
setClockDivider KEYWORD2
24+
setSCK KEYWORD2
25+
setMOSI KEYWORD2
26+
setMISO KEYWORD2
27+
setCS KEYWORD2
28+
29+
#######################################
30+
# Constants (LITERAL1)
31+
#######################################
32+
SPI_CLOCK_DIV4 LITERAL1
33+
SPI_CLOCK_DIV16 LITERAL1
34+
SPI_CLOCK_DIV64 LITERAL1
35+
SPI_CLOCK_DIV128 LITERAL1
36+
SPI_CLOCK_DIV2 LITERAL1
37+
SPI_CLOCK_DIV8 LITERAL1
38+
SPI_CLOCK_DIV32 LITERAL1
39+
SPI_CLOCK_DIV64 LITERAL1
40+
SPI_MODE0 LITERAL1
41+
SPI_MODE1 LITERAL1
42+
SPI_MODE2 LITERAL1
43+
SPI_MODE3 LITERAL1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name=SoftwareSPI
2+
version=1.0
3+
author=Earle F. Philhower, III <[email protected]>
4+
maintainer=Earle F. Philhower, III <[email protected]>
5+
sentence=Uses the PIO to provide an SPI interface on any pin.
6+
paragraph=
7+
category=Signal Input/Output
8+
url=http://arduino.cc/en/Reference/SPI
9+
architectures=rp2040
10+
dot_a_linkage=true

0 commit comments

Comments
 (0)