SPI Chapter updated

This commit is contained in:
ImplFerris 2025-07-20 00:09:40 +05:30
parent e37e52cbb4
commit 9064b784c8
9 changed files with 468 additions and 558 deletions

View File

@ -101,6 +101,8 @@
- [Code](./thermistor/oled/code.md)
# TODO: Temperature on WebServer
- [SPI](spi/index.md)
- [SPI in Rust Ecosystem](./spi/spi-and-rust.md)
- [ESP32 SPI](./spi/esp32-spi.md)
- [SD Card (MMC/SDC)](./sdcard/index.md)
- [Circuit](./sdcard/circuit.md)
- [Read From SD Card](./sdcard/read-sdcard.md)

56
src/spi/esp32-spi.md Normal file
View File

@ -0,0 +1,56 @@
# ESP32 SPI Peripherals
The ESP32 includes four SPI controllers, but only two of them: SPI2 and SPI3 are available for general use. These are commonly known as HSPI and VSPI. The other two SPI controllers, SPI0 and SPI1, are reserved for internal usage.
The ESP32 offers flexible GPIO matrix, which allows SPI signals to be mapped to almost any GPIO pin. However, most ESP32 development boards use fixed default pins for convenience.
<img style="display: block; margin: auto;" alt="SPI Multiple Bus Multiple SPI Device" src="./images/spi-multiple-spi-bus-multiple-spi-device.svg"/>
Here are the default SPI pin assignments for the ESP32 Devkit:
| SPI Channel | MOSI (SDI) | MISO (SDO) | SCLK | CS |
| ----------- | ---------- | ---------- | ------- | ------- |
| VSPI | GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 |
| HSPI | GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
## Using SPI in esp-hal
To use SPI in the esp-hal crate, we create and configure the SPI interface with the pins we want. Here is an example that uses the SPI2 bus.
```rust
use esp_hal::spi::master::Config as SpiConfig;
use esp_hal::spi::master::Spi;
use esp_hal::spi::Mode as SpiMode;
// Initialize SPI
let spi_bus = Spi::new(
peripherals.SPI2,
SpiConfig::default()
.with_frequency(Rate::from_mhz(60))
.with_mode(SpiMode::_0),
)
.unwrap()
//CLK
.with_sck(peripherals.GPIO18)
//DIN
.with_mosi(peripherals.GPIO23);
let cs = Output::new(peripherals.GPIO15, Level::Low, OutputConfig::default());
```
## Example Driver Usage
Now that we have the SPI interface set up, let's use it to talk to an SD card using the embedded_sdmmc crate. We will use ExclusiveDevice from the embedded-hal-bus crate.
```rust
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::SdCard;
use esp_hal::delay::Delay;
// Gets exclusive access to the SPI bus (not shared).
let spi_dev = ExclusiveDevice::new(spi_bus, cs, Delay).unwrap();
// Initialize the SD Card driver with SPI Device
let sdcard = SdCard::new(spi_dev, Delay);
```

View File

@ -1,546 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="290pt"
height="230pt"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.45"
sodipodi:docbase="/home/cburnett/wikipedia/images/electronics"
sodipodi:docname="SPI three slaves.svg"
version="1.0"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:modified="true">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible">
<path
id="path2570"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(0.6,0,0,0.6,-3,0)" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible">
<path
id="path2502"
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z "
style="fill-rule:evenodd;stroke:red;stroke-width:1pt;marker-start:none"
transform="scale(-0.8,-0.8)" />
</marker>
<marker
inkscape:stockid="TriangleOutL"
orient="auto"
refY="0"
refX="0"
id="TriangleOutL"
style="overflow:visible">
<path
id="path2493"
d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z "
style="fill-rule:evenodd;stroke:red;stroke-width:1pt;marker-start:none"
transform="scale(0.8,0.8)" />
</marker>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible">
<path
id="path2576"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(1.1,0,0,1.1,-5.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible">
<path
id="path3298"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="matrix(-1.1,0,0,-1.1,5.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible">
<path
id="path3316"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:red;stroke-width:1pt;marker-start:none"
transform="scale(-0.8,-0.8)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path3319"
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
style="fill-rule:evenodd;stroke:red;stroke-width:1pt;marker-start:none"
transform="scale(0.8,0.8)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="210.40651"
inkscape:cy="140.60009"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="976"
inkscape:window-height="962"
inkscape:window-x="0"
inkscape:window-y="31" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g2202">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96824229px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 131.25,25 L 131.25,25.96875 C 176.07915,25.96875 198.51146,25.96875 209.71875,25.96875 C 215.32239,25.96875 218.13034,25.96875 219.53125,25.96875 C 220.23171,25.96875 220.57489,25.96875 220.75,25.96875 C 220.83756,25.96875 220.88436,25.96875 220.90625,25.96875 L 220.90625,25.5 L 220.90625,25 C 220.90625,25 220.90829,25 131.25,25 z "
id="path3144" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.77459383pt;marker-start:none"
d="M 225.38904,25.497581 L 218.6888,29.37055 L 218.6888,21.624612 L 225.38904,25.497581 z "
id="path2208" />
</g>
<g
id="g2210">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96824229px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 131.25,40.625 L 131.25,41.59375 C 176.07915,41.593749 198.51146,41.59375 209.71875,41.59375 C 215.32239,41.59375 218.13034,41.59375 219.53125,41.59375 C 220.23171,41.59375 220.57489,41.59375 220.75,41.59375 C 220.83756,41.59375 220.88436,41.59375 220.90625,41.59375 L 220.90625,41.09375 L 220.90625,40.625 C 220.90625,40.625 220.90829,40.624998 131.25,40.625 z "
id="path3330" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.77459383pt;marker-start:none"
d="M 225.38904,41.101164 L 218.6888,44.974133 L 218.6888,37.228195 L 225.38904,41.101164 z "
id="path2216" />
</g>
<g
id="g2226">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96824229px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 131.25,71.8125 L 131.25,72.78125 C 176.07915,72.78125 198.51146,72.78125 209.71875,72.78125 C 215.32239,72.78125 218.13034,72.78125 219.53125,72.78125 C 220.23171,72.78125 220.57489,72.78125 220.75,72.78125 C 220.83756,72.78125 220.88436,72.78125 220.90625,72.78125 L 220.90625,72.3125 L 220.90625,71.8125 C 220.90625,71.8125 220.90829,71.8125 131.25,71.8125 z "
id="path3334" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.77459383pt;marker-start:none"
d="M 225.38904,72.308296 L 218.6888,76.181265 L 218.6888,68.435327 L 225.38904,72.308296 z "
id="path2232" />
</g>
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2607"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-12.09375,-18)" />
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2609"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-23.59098,-2.4645)" />
<g
id="g2254">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.02442479px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 131.03125,85.34375 L 131.03125,86.375 L 162.53125,86.375 L 162.53125,162.375 L 162.53125,162.875 L 163.03125,162.875 L 220.5,162.875 L 220.5,161.84375 L 163.53125,161.84375 L 163.53125,85.875 L 163.53125,85.34375 L 163.03125,85.34375 L 131.03125,85.34375 z "
id="path2677" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.81953983pt;marker-start:none"
d="M 225.21856,162.36218 L 218.12955,166.45988 L 218.12955,158.26448 L 225.21856,162.36218 z "
id="path2260" />
</g>
<g
id="g2262">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.0245285px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 131.03125,100.46875 L 131.03125,101.5 L 145.9375,101.5 L 145.9375,252.46875 L 145.9375,253 L 146.4375,253 L 220.65625,253 L 220.65625,251.96875 L 146.9375,251.96875 L 146.9375,100.96875 L 146.9375,100.46875 L 146.4375,100.46875 L 131.03125,100.46875 z "
id="path2679" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.8196228pt;marker-start:none"
d="M 225.38937,252.47886 L 218.29964,256.57697 L 218.29964,248.38075 L 225.38937,252.47886 z "
id="path2268" />
</g>
<g
id="g2242">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.0321871px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 185.625,41.0625 L 185.625,132.4375 L 185.625,132.96875 L 186.15625,132.96875 L 220.78125,132.96875 L 220.78125,131.9375 L 186.65625,131.9375 L 186.65625,41.0625 L 185.625,41.0625 z "
id="path2687" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.82574968pt;marker-start:none"
d="M 225.55987,132.44748 L 218.41713,136.57623 L 218.41713,128.31873 L 225.55987,132.44748 z "
id="path2248" />
</g>
<g
id="g2234">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.04614723px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 197.09375,25.5 L 197.09375,117.40625 L 197.09375,117.9375 L 197.625,117.9375 L 220.65625,117.9375 L 220.65625,116.90625 L 198.15625,116.90625 L 198.15625,25.5 L 197.09375,25.5 z "
id="path2689" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.83691778pt;marker-start:none"
d="M 225.48174,117.42146 L 218.2424,121.60605 L 218.2424,113.23687 L 225.48174,117.42146 z "
id="path2240" />
</g>
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 174.25,56.375 L 174.25,147.875 L 174.25,148.375 L 174.75,148.375 L 226.5,148.375 L 226.5,147.375 L 175.25,147.375 L 175.25,56.375 L 174.25,56.375 z "
id="path2691" />
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99764985px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 174.25,148.375 L 174.25,239.125 L 174.25,239.625 L 174.75,239.625 L 226.75,239.625 L 226.75,238.625 L 175.25,238.625 L 175.25,148.375 L 174.25,148.375 z "
id="path2693" />
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2695"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-34.89167,13.09186)" />
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2697"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-34.78125,104.5938)" />
<g
id="g2274">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.02505863px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 185.6875,132.28125 L 185.6875,223.5 L 185.6875,224 L 186.1875,224 L 220.5625,224 L 220.5625,222.96875 L 186.71875,222.96875 L 186.71875,132.28125 L 185.6875,132.28125 z "
id="path2699" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.8200469pt;marker-start:none"
d="M 225.28696,223.48748 L 218.19355,227.58771 L 218.19355,219.38725 L 225.28696,223.48748 z "
id="path2280" />
</g>
<g
id="g2282">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.03560543px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 197.1875,117.25 L 197.1875,208.09375 L 197.1875,208.625 L 197.6875,208.625 L 220.4375,208.625 L 220.4375,207.59375 L 198.21875,207.59375 L 198.21875,117.25 L 197.1875,117.25 z "
id="path2701" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.82848434pt;marker-start:none"
d="M 225.22445,208.10791 L 218.05807,212.25033 L 218.05807,203.96549 L 225.22445,208.10791 z "
id="path2288" />
</g>
<g
id="g2218">
<path
style="fill:red;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.98819256px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 136.71875,56.375 L 136.71875,57.375 C 181.77434,57.375 204.2986,57.375 215.5625,57.375 C 221.19445,57.375 223.99826,57.375 225.40625,57.375 C 226.11024,57.375 226.449,57.375 226.625,57.375 C 226.713,57.375 226.75925,57.375 226.78125,57.375 C 226.79225,57.375 226.80975,57.375 226.8125,57.375 L 226.8125,56.875 L 226.8125,56.375 C 226.8125,56.375 226.82993,56.375 136.71875,56.375 z "
id="path2789" />
<path
style="fill-rule:evenodd;stroke:red;stroke-width:0.79055405pt;marker-start:none"
d="M 132.14357,56.869228 L 138.98187,52.916458 L 138.98187,60.821998 L 132.14357,56.869228 z "
id="path2224" />
</g>
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2567"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-23.48829,88.96704)" />
<path
sodipodi:type="arc"
style="fill:red;fill-opacity:1"
id="path2569"
sodipodi:cx="209.65625"
sodipodi:cy="43.518429"
sodipodi:rx="1.9375"
sodipodi:ry="1.9375"
d="M 211.59375 43.518429 A 1.9375 1.9375 0 1 1 207.71875,43.518429 A 1.9375 1.9375 0 1 1 211.59375 43.518429 z"
transform="translate(-12.01454,73.9631)" />
<g
id="g2794">
<rect
y="12.917446"
x="12.858437"
height="100.88948"
width="118.28313"
id="rect1307"
style="fill:#ffc2a1;fill-opacity:1;fill-rule:evenodd;stroke:red;stroke-width:0.88664234px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text2182"
y="60.212772"
x="38"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="60.212772"
x="38"
id="tspan2184"
sodipodi:role="line">SPI</tspan><tspan
id="tspan2186"
y="75.212772"
x="38"
sodipodi:role="line">Master</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3061"
y="30.724487"
x="120"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="30.724487"
x="120"
id="tspan3063"
sodipodi:role="line">SCLK</tspan><tspan
id="tspan3065"
y="45.724487"
x="120"
sodipodi:role="line">MOSI</tspan><tspan
id="tspan3067"
y="60.724487"
x="120"
sodipodi:role="line">MISO</tspan><tspan
id="tspan3069"
y="75.724487"
x="120"
sodipodi:role="line">SS1</tspan><tspan
id="tspan2673"
y="90.724487"
x="120"
sodipodi:role="line">SS2</tspan><tspan
id="tspan2675"
y="105.72449"
x="120"
sodipodi:role="line">SS3</tspan></text>
<path
id="path2341"
d="M 97.886043,64.584585 L 118.40024,64.584585"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path2624"
d="M 97.886044,79.919953 L 118.40024,79.919953"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path2626"
d="M 97.886043,95.255342 L 118.40024,95.255342"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g2771">
<rect
y="12.768347"
x="226.85843"
height="72.187675"
width="118.28313"
id="rect3084"
style="fill:#b9e179;fill-opacity:1;fill-rule:evenodd;stroke:red;stroke-width:0.74999273px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text3086"
y="45.712769"
x="320"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="45.712769"
x="320"
id="tspan3088"
sodipodi:role="line">SPI</tspan><tspan
id="tspan3090"
y="60.712769"
x="320"
sodipodi:role="line">Slave</tspan></text>
<text
id="text3092"
y="30.724487"
x="236"
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="30.724487"
x="236"
id="tspan3094"
sodipodi:role="line">SCLK</tspan><tspan
id="tspan3096"
y="45.724487"
x="236"
sodipodi:role="line">MOSI</tspan><tspan
id="tspan3098"
y="60.724487"
x="236"
sodipodi:role="line">MISO</tspan><tspan
id="tspan3100"
y="75.724487"
x="236"
sodipodi:role="line">SS</tspan></text>
<path
id="path2694"
d="M 236.92188,65.124998 L 250.14063,65.124998"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g2750">
<rect
y="103.46392"
x="226.87628"
height="72.187675"
width="118.28313"
id="rect1462"
style="fill:#8fbbdf;fill-opacity:1;fill-rule:evenodd;stroke:red;stroke-width:0.74999273px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text1464"
y="136.40834"
x="320.01785"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="136.40834"
x="320.01785"
id="tspan1466"
sodipodi:role="line">SPI</tspan><tspan
id="tspan1468"
y="151.40834"
x="320.01785"
sodipodi:role="line">Slave</tspan></text>
<text
id="text1470"
y="121.42006"
x="236.01785"
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="121.42006"
x="236.01785"
id="tspan1472"
sodipodi:role="line">SCLK</tspan><tspan
id="tspan1474"
y="136.42006"
x="236.01785"
sodipodi:role="line">MOSI</tspan><tspan
id="tspan1476"
y="151.42006"
x="236.01785"
sodipodi:role="line">MISO</tspan><tspan
id="tspan1478"
y="166.42006"
x="236.01785"
sodipodi:role="line">SS</tspan></text>
<path
id="path2696"
d="M 236.95313,155.4375 L 250.17188,155.4375"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g2729">
<rect
y="194.15945"
x="226.87628"
height="72.187675"
width="118.28313"
id="rect1482"
style="fill:#bfa1d1;fill-opacity:1;fill-rule:evenodd;stroke:red;stroke-width:0.74999273px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text1484"
y="227.10387"
x="320.01785"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="227.10387"
x="320.01785"
id="tspan1486"
sodipodi:role="line">SPI</tspan><tspan
id="tspan1488"
y="242.10387"
x="320.01785"
sodipodi:role="line">Slave</tspan></text>
<text
id="text1490"
y="212.11559"
x="236.01785"
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="212.11559"
x="236.01785"
id="tspan1492"
sodipodi:role="line">SCLK</tspan><tspan
id="tspan1494"
y="227.11559"
x="236.01785"
sodipodi:role="line">MOSI</tspan><tspan
id="tspan1496"
y="242.11559"
x="236.01785"
sodipodi:role="line">MISO</tspan><tspan
id="tspan1498"
y="257.11559"
x="236.01785"
sodipodi:role="line">SS</tspan></text>
<path
id="path2698"
d="M 236.57813,246 L 249.79688,246"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:red;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,89 @@
<svg width="880" height="360" xmlns="http://www.w3.org/2000/svg">
<!--
Source: https://github.com/ImplFerris/ImplFerris
Copyright (c) 2025 implrust.com
Licensed under CC BY-SA 4.0
-->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#009688" />
</marker>
<marker id="arrowhead-reverse" markerWidth="10" markerHeight="7"
refX="1" refY="3.5" orient="auto">
<polygon points="10 0, 0 3.5, 10 7" fill="#009688" />
</marker>
<marker id="arrowhead-cs" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#FF7043" />
</marker>
</defs>
<style>
.label { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel { font: italic 14px sans-serif; fill: #000; text-anchor: middle; }
.label-slave { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel-slave { font: italic 14px sans-serif; fill: #333; text-anchor: middle; }
.pin { font: 14px sans-serif; fill: #000; dominant-baseline: middle; }
.pin-master { fill: #000; text-anchor: end; }
.line { stroke: #009688; stroke-width: 2; fill: none; }
.line-out { marker-end: url(#arrowhead); }
.line-in { marker-start: url(#arrowhead-reverse); }
.line-cs { stroke: #FF7043; stroke-width: 2; fill: none; marker-end: url(#arrowhead-cs); }
</style>
<!-- ESP32 SPI Controller -->
<rect x="40" y="30" width="240" height="200" rx="10" ry="10" fill="#7ade82" />
<text x="150" y="120" class="label">Controller</text>
<text x="150" y="160" class="sublabel">(master)</text>
<!-- SPI Peripheral 1 -->
<rect x="540" y="30" width="280" height="140" rx="10" ry="10" fill="#CFD8DC" />
<text x="730" y="70" class="label-slave">1</text>
<text x="730" y="95" class="label-slave">Peripheral</text>
<text x="730" y="120" class="sublabel-slave">(slave)</text>
<!-- SPI Peripheral 2 -->
<rect x="540" y="190" width="280" height="140" rx="10" ry="10" fill="#81D4FA" />
<text x="730" y="230" class="label-slave">2</text>
<text x="730" y="255" class="label-slave">Peripheral</text>
<text x="730" y="280" class="sublabel-slave">(slave)</text>
<!-- Master Pin Labels -->
<text x="260" y="60" class="pin pin-master">SCLK</text>
<text x="260" y="90" class="pin pin-master">MOSI</text>
<text x="260" y="120" class="pin pin-master">MISO</text>
<text x="260" y="170" class="pin pin-master">CS1</text>
<text x="260" y="205" class="pin pin-master">CS2</text>
<!-- Connection lines -->
<!-- SCLK -->
<path class="line line-out" d="M280 60 H540" />
<path class="line line-out" d="M280 60 H460 V220 H540" />
<!-- MOSI -->
<path class="line line-out" d="M280 90 H540" />
<path class="line line-out" d="M280 90 H430 V250 H540" />
<!-- MISO (reverse arrows) -->
<path class="line line-in" d="M280 120 H540" />
<path class="line line-in" d="M280 120 H400 V275 H540" />
<!-- CS1 -->
<path class="line-cs" d="M280 170 H320 V145 H540" />
<!-- CS2 -->
<path class="line-cs" d="M280 205 H320 V300 H540" />
<!-- Slave Pin Labels 1 -->
<text x="560" y="60" class="pin">SCLK</text>
<text x="560" y="90" class="pin">MOSI/SDI</text>
<text x="560" y="120" class="pin">MISO/SDO</text>
<text x="560" y="145" class="pin">CS/SS</text>
<!-- Slave Pin Labels 2 -->
<text x="560" y="220" class="pin">SCLK</text>
<text x="560" y="250" class="pin">MOSI/SDI</text>
<text x="560" y="275" class="pin">MISO/SDO</text>
<text x="560" y="300" class="pin">CS/SS</text>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,90 @@
<svg width="880" height="360" xmlns="http://www.w3.org/2000/svg">
<!--
Source: https://github.com/ImplFerris/ImplFerris
Copyright (c) 2025 implrust.com
Licensed under CC BY-SA 4.0
-->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#009688" />
</marker>
<marker id="arrowhead-reverse" markerWidth="10" markerHeight="7"
refX="1" refY="3.5" orient="auto">
<polygon points="10 0, 0 3.5, 10 7" fill="#009688" />
</marker>
<marker id="arrowhead-cs" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#FF7043" />
</marker>
</defs>
<style>
.label { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel { font: italic 14px sans-serif; fill: #000; text-anchor: middle; }
.label-slave { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel-slave { font: italic 14px sans-serif; fill: #333; text-anchor: middle; }
.pin { font: 14px sans-serif; fill: #000; dominant-baseline: middle; }
.pin-master { fill: #000; text-anchor: end; }
.line { stroke: #009688; stroke-width: 2; fill: none; }
.line-out { marker-end: url(#arrowhead); }
.line-in { marker-start: url(#arrowhead-reverse); }
.line-cs { stroke: #FF7043; stroke-width: 2; fill: none; marker-end: url(#arrowhead-cs); }
</style>
<!-- ESP32 SPI Controller -->
<rect x="40" y="30" width="240" height="200" rx="10" ry="10" fill="#7ade82" />
<text x="150" y="120" class="label">MCU</text>
<text x="150" y="140" class="sublabel">SPI Controller</text>
<text x="150" y="160" class="sublabel">(master)</text>
<!-- SPI Peripheral 1 -->
<rect x="540" y="30" width="280" height="140" rx="10" ry="10" fill="#CFD8DC" />
<text x="730" y="70" class="label-slave">1</text>
<text x="730" y="95" class="label-slave">SPI Device</text>
<text x="730" y="120" class="sublabel-slave">(slave)</text>
<!-- SPI Peripheral 2 -->
<rect x="540" y="190" width="280" height="140" rx="10" ry="10" fill="#81D4FA" />
<text x="730" y="230" class="label-slave">2</text>
<text x="730" y="255" class="label-slave">SPI Device</text>
<text x="730" y="280" class="sublabel-slave">(slave)</text>
<!-- Master Pin Labels -->
<text x="260" y="60" class="pin pin-master">SCLK</text>
<text x="260" y="90" class="pin pin-master">MOSI</text>
<text x="260" y="120" class="pin pin-master">MISO</text>
<text x="260" y="170" class="pin pin-master">CS1</text>
<text x="260" y="205" class="pin pin-master">CS2</text>
<!-- Connection lines -->
<!-- SCLK -->
<path class="line line-out" d="M280 60 H540" />
<path class="line line-out" d="M280 60 H460 V220 H540" />
<!-- MOSI -->
<path class="line line-out" d="M280 90 H540" />
<path class="line line-out" d="M280 90 H430 V250 H540" />
<!-- MISO (reverse arrows) -->
<path class="line line-in" d="M280 120 H540" />
<path class="line line-in" d="M280 120 H400 V275 H540" />
<!-- CS1 -->
<path class="line-cs" d="M280 170 H320 V145 H540" />
<!-- CS2 -->
<path class="line-cs" d="M280 205 H320 V300 H540" />
<!-- Slave Pin Labels 1 -->
<text x="560" y="60" class="pin">SCLK</text>
<text x="560" y="90" class="pin">MOSI/SDI</text>
<text x="560" y="120" class="pin">MISO/SDO</text>
<text x="560" y="145" class="pin">CS/SS</text>
<!-- Slave Pin Labels 2 -->
<text x="560" y="220" class="pin">SCLK</text>
<text x="560" y="250" class="pin">MOSI/SDI</text>
<text x="560" y="275" class="pin">MISO/SDO</text>
<text x="560" y="300" class="pin">CS/SS</text>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,49 @@
<svg width="860" height="220" xmlns="http://www.w3.org/2000/svg">
<!--
Source: https://github.com/ImplFerris/ImplFerris
Copyright (c) 2025 implrust.com
Licensed under CC BY-SA 4.0
-->
<style>
.label { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel { font: italic 14px sans-serif; fill: #333; text-anchor: middle; }
.label-slave { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel-slave { font: italic 14px sans-serif; fill: #000; text-anchor: middle; }
.pin { font: 14px sans-serif; fill: #000; dominant-baseline: middle; }
.pin-master { text-anchor: end; }
.arrow { stroke: #26A69A; marker-end: url(#arrowhead); }
</style>
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#26A69A" />
</marker>
</defs>
<!-- SPI Controller (master) -->
<rect x="40" y="30" width="280" height="160" rx="10" ry="10" fill="#7ade82"/>
<text x="180" y="100" class="label">Controller</text>
<text x="180" y="120" class="sublabel">(master)</text>
<!-- SPI Peripheral (slave) -->
<rect x="500" y="30" width="280" height="160" rx="10" ry="10" fill="#81D4FA"/>
<text x="650" y="100" class="label-slave">Peripheral</text>
<text x="650" y="120" class="sublabel-slave">(slave)</text>
<!-- Signal Lines -->
<line x1="320" y1="66" x2="500" y2="66" stroke-width="2" class="arrow"/>
<text x="310" y="66" class="pin pin-master">SCLK</text>
<text x="510" y="66" class="pin">SCLK</text>
<line x1="320" y1="98" x2="500" y2="98" stroke-width="2" class="arrow"/>
<text x="310" y="98" class="pin pin-master">MOSI</text>
<text x="510" y="98" class="pin">MOSI/SDI</text>
<line x1="500" y1="130" x2="320" y2="130" stroke-width="2" class="arrow"/>
<text x="310" y="130" class="pin pin-master">MISO</text>
<text x="510" y="130" class="pin">MISO/SDO</text>
<line x1="320" y1="160" x2="500" y2="160" stroke-width="2" class="arrow"/>
<text x="310" y="160" class="pin pin-master">CS/SS</text>
<text x="510" y="160" class="pin">CS/SS</text>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,95 @@
<svg width="880" height="460" xmlns="http://www.w3.org/2000/svg">
<!--
Source: https://github.com/ImplFerris/ImplFerris
Copyright (c) 2025 implrust.com
Licensed under CC BY-SA 4.0
-->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#009688" />
</marker>
<marker id="arrowhead-reverse" markerWidth="10" markerHeight="7"
refX="1" refY="3.5" orient="auto">
<polygon points="10 0, 0 3.5, 10 7" fill="#009688" />
</marker>
<marker id="arrowhead-cs" markerWidth="10" markerHeight="7"
refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#FF7043" />
</marker>
</defs>
<style>
.label { font: bold 16px sans-serif; fill: #fff; text-anchor: middle; }
.label-master{ font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel { font: italic 14px sans-serif; fill: #000; text-anchor: middle; }
.label-slave { font: bold 16px sans-serif; fill: #000; text-anchor: middle; }
.sublabel-slave { font: italic 14px sans-serif; fill: #333; text-anchor: middle; }
.pin { font: 14px sans-serif; fill: #000; dominant-baseline: middle; }
.pin-master { fill: #fff; text-anchor: end; }
.line { stroke: #009688; stroke-width: 2; fill: none; }
.line-out { marker-end: url(#arrowhead); }
.line-in { marker-start: url(#arrowhead-reverse); }
.line-cs { stroke: #FF7043; stroke-width: 2; fill: none; marker-end: url(#arrowhead-cs); }
</style>
<!-- ESP32 SPI Controller -->
<rect x="40" y="50" width="240" height="380" rx="10" ry="10" fill="#7ade82" />
<text x="150" y="220" class="label-master">MCU</text>
<text x="150" y="245" class="sublabel">SPI Controller</text>
<text x="150" y="265" class="sublabel">(master)</text>
<!-- HSPI Sub-Block -->
<rect x="150" y="70" width="110" height="110" rx="5" ry="5" fill="#00796B" />
<text x="180" y="130" class="label">HSPI</text>
<text x="245" y="100" class="pin pin-master">SCLK</text>
<text x="245" y="120" class="pin pin-master">MOSI</text>
<text x="245" y="140" class="pin pin-master">MISO</text>
<text x="245" y="160" class="pin pin-master">CS</text>
<!-- VSPI Sub-Block -->
<rect x="150" y="305" width="110" height="110" rx="5" ry="5" fill="#00796B" />
<text x="180" y="365" class="label">VSPI</text>
<text x="245" y="330" class="pin pin-master">SCLK</text>
<text x="245" y="350" class="pin pin-master">MOSI</text>
<text x="245" y="370" class="pin pin-master">MISO</text>
<text x="245" y="390" class="pin pin-master">CS</text>
<!-- SPI Peripheral 1 -->
<rect x="540" y="60" width="280" height="140" rx="10" ry="10" fill="#CFD8DC" />
<text x="730" y="100" class="label-slave">1</text>
<text x="730" y="125" class="label-slave">SPI Device</text>
<text x="730" y="150" class="sublabel-slave">(slave)</text>
<!-- SPI Peripheral 2 -->
<rect x="540" y="280" width="280" height="140" rx="10" ry="10" fill="#81D4FA" />
<text x="730" y="320" class="label-slave">2</text>
<text x="730" y="345" class="label-slave">SPI Device</text>
<text x="730" y="370" class="sublabel-slave">(slave)</text>
<!-- Connection lines HSPI -->
<path class="line line-out" d="M260 100 H540" />
<path class="line line-out" d="M260 120 H540" />
<path class="line line-in" d="M260 140 H540" />
<path class="line-cs" d="M260 160 H540" />
<!-- Connection lines VSPI -->
<path class="line line-out" d="M260 330 H540" />
<path class="line line-out" d="M260 350 H540" />
<path class="line line-in" d="M260 370 H540" />
<path class="line-cs" d="M260 390 H540" />
<!-- Slave Pin Labels 1 -->
<text x="560" y="100" class="pin">SCLK</text>
<text x="560" y="120" class="pin">MOSI/SDI</text>
<text x="560" y="140" class="pin">MISO/SDO</text>
<text x="560" y="160" class="pin">CS/SS</text>
<!-- Slave Pin Labels 2 -->
<text x="560" y="330" class="pin">SCLK</text>
<text x="560" y="350" class="pin">MOSI/SDI</text>
<text x="560" y="370" class="pin">MISO/SDO</text>
<text x="560" y="390" class="pin">CS/SS</text>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,26 +1,39 @@
# Serial Peripheral Interface (SPI)
SPI stands for Serial Peripheral Interface. It's one of the most common ways for microcontrollers to talk to other devices like displays, sensors, and memory chips.
In this section, we will learn what SPI is and how to use the SPI communication buses of the ESP32.
## Why SPI?
## What is SPI?
SPI is a great choice when you want fast and reliable communication between your microcontroller and a peripheral. It's much faster than I²C or UART, simple to use, and allows data to be sent and received at the same time (full-duplex). This makes it ideal for high-speed devices like displays or SD cards. As long as you have enough GPIO pins and don't need to connect a large number of devices, SPI is usually the best tool for the job.
SPI stands for Serial Peripheral Interface. It is one of the most common ways for microcontrollers to communicate with devices like displays, sensors, and SD Cards. Technically, it is called as a serial, full duplex, and synchronous interface. But what do those terms mean?
## How SPI Works
- Serial means data is sent one bit at a time. Imagine a single-lane bridge where only one car can pass at a time. Each bit of data is like a car crossing the bridge one after another in a line. This is different from a multi-lane highway (parallel communication) where many cars can go side by side all at once.
SPI communication involves a single master device (usually the microcontroller) and one or more slave devices (e.g., a sensor or display). The master initiates and controls all communication. The connection typically uses four lines:
- Full duplex means two devices can talk to each other at the same time. Imagine two people having a phone call. They can both speak and listen at the same time. That's full duplex. In contrast, half duplex would be like using a walkie talkie - only one person can talk at a time while the other listens, and then they switch.
- **SCK** (Serial Clock): Clock signal generated by the master to synchronize data.
- **MOSI** (Master Out Slave In): Data sent from the master to the slave.
- **MISO** (Master In Slave Out): Data sent from the slave to the master.
- **CS** (Chip Select): Used by the master to choose which device to talk to.
- Synchronous means both devices use the same clock to stay in sync. Think of two people playing catch, but they throw and catch only when a whistle blows. The whistle acts like a clock signal, making sure both sides know exactly when to send and receive data.
<img style="display: block; margin: auto;width:60vh;" alt="SPI" src="./images/SPI_three_slaves.svg"/>
<p>Image Credit: <a href="https://commons.wikimedia.org/wiki/File:SPI_three_slaves.svg">Wikimedia</a></p>
## Controller and Peripheral
SPI uses a controller-peripheral model (previously called master-slave). The controller is the device that starts the communication and provides the clock signal. The peripheral is the device that responds to the controller.
In most embedded projects, the ESP32 acts as the controller, and devices like displays, sensors, or SD Cards are peripherals.
Only one slave is active at a time. The master pulls the corresponding CS line low to begin communication, sends data over MOSI, and receives data over MISO. When done, it pulls CS back high to end the communication.
<img style="display: block; margin: auto;" alt="SPI Single Bus Multiple SPI Device" src="./images/spi-bus.svg"/>
<p align="center"><em>Figure: Single SPI bus with a controller and a single peripheral</em></p>
The connection typically uses four lines:
- The SCK (Serial Clock) line carries the clock signal generated by the controller. This signal keeps both the controller and the device in sync during data transfer.
- The MOSI (Master Out, Slave In) line is used to send data from the controller to the device. In some datasheets, this line may be labeled as SDO (Serial Data Out).
- The MISO (Master In, Slave Out) line carries data from the device to the controller. It may also be referred to as SDI (Serial Data In) depending on the device.
- Finally, the CS (Chip Select) line is used by the controller to choose which device it wants to communicate with. Each connected device usually has its own dedicated CS line. When the controller pulls a device's CS line low(active), that device becomes active and ready to communicate. In some older documentation, this line may be referred to as SS (Slave Select).
<img style="display: block; margin: auto;" alt="SPI Single Bus Multiple SPI Device" src="./images/generic-spi-single-bus-multiple-spi-device.svg"/>
<p align="center"><em>Figure: Single SPI bus with a controller and multiple peripherals</em></p>
### SPI Modes
@ -28,6 +41,14 @@ SPI supports four modes, numbered from 0 to 3. These decide when data is read an
Don't worry too much about the details right now. Mode 0 is the most common and works with most devices.
## Why SPI?
SPI is a great choice when you want fast and reliable communication between your microcontroller and a peripheral. It's much faster than I²C or UART, simple to use, and allows data to be sent and received at the same time (full-duplex). This makes it ideal for high-speed devices like displays or SD cards.
As long as you have enough GPIO pins and don't need to connect a large number of devices, SPI is usually the best tool for the job.
## Resources
For more in-depth technical details, refer these
- [Serial Peripheral Interface (SPI) by Sparkfun](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all)

54
src/spi/spi-and-rust.md Normal file
View File

@ -0,0 +1,54 @@
# Using SPI with Embedded Rust Ecosystem
In the previous section, we learned what SPI is and how the controller-peripheral model works. Now, let's see how these concepts apply within the Embedded Rust ecosystem.
Rust's embedded ecosystem is designed to be modular and reusable. This means you can write code for one microcontroller and reuse it on another with minimal changes. One key to this flexibility is the use of traits defined by the embedded-hal crate.
## SPI in embedded-hal
The embedded-hal crate defines standard traits for working with SPI, so that drivers and libraries can be written generically. Two important traits for SPI are:
- SpiBus: Represents full control over the SPI bus, including the SCK, MOSI, and MISO lines. This must be implemented by the microcontroller's HAL crate. For example, the esp-hal crate implements SpiBus. If you are curious, you can look at the implementation [here](https://github.com/esp-rs/esp-hal/blob/de67c3101346cdbe030ffa1bb95b13943ee8d790/esp-hal/src/spi/master.rs#L2703).
- SpiDevice: Represents access to a single SPI device that may share the bus with others. It takes control of the chip select (CS) pin and ensures the device is properly selected before communication and released afterward.
## Platform-Independent Drivers
Imagine you are writing a driver for a sensor or a display that communicates over SPI. You don't want to tie your code to a specific microcontroller like the Raspberry Pi Pico or ESP32. Instead, you can write the driver in a generic way using the embedded-hal traits.
As long as your driver only depends on the SpiDevice or SpiBus traits, it can run on any platform that provides an implementation of these traits-such as STM32, nRF, or ESP32.
## Sharing the SPI Bus
In many projects, multiple SPI devices share the same SPI bus. For example, you might have a display, an SD card, and a temperature sensor all connected to the same MOSI, MISO, and SCK lines. The only thing that separates them is their chip select (CS) pin.
<img style="display: block; margin: auto;" alt="SPI Single Bus Multiple SPI Device" src="./images/mcu-spi-single-bus-multiple-spi-device.svg"/>
<p align="center"><em>Figure: Single SPI bus with a controller and multiple peripherals</em></p>
If you give full control of the SPI bus to just one driver (using SpiBus), the others can't use it. Instead, we need a way to share the SPI bus safely across multiple devices.
That's where SpiDevice comes in - it allows each driver to use only its own CS pin, while still sharing the underlying bus.
In practice, this means we need to pass a struct that implements SpiDevice to each driver, rather than giving them the full bus.
## How do we get a SpiDevice?
We said that each driver should be given a SpiDevice implementation instead of the full SpiBus. But are we supposed to write this SpiDevice struct ourselves?
Not really. While it's possible to write your own implementation, it's usually unnecessary-and can be tricky to get right, especially when multiple devices need to coordinate bus access.
That's where the embedded-hal-bus crate comes in. It provides ready-to-use wrappers that implement the SpiDevice trait for you. These wrappers handle bus access, chip select control, and optional synchronization between devices.
- If your project only uses one SPI device and doesn't need sharing, you can use the `ExclusiveDevice` struct - it gives exclusive access to the bus for one device.
- But if your project has multiple SPI devices sharing the same bus, you can choose one of the shared access implementations such as `AtomicDevice` or `CriticalSectionDevice`. These manage access to the bus so that each device gets a turn without interfering with the others.
These structs allow you to focus on using or building drivers without worrying about low-level coordination or writing boilerplate code.
## Resources
- [embedded-hal docs on SPI](https://docs.rs/embedded-hal/latest/embedded_hal/spi/index.html): This documentation provides in-depth details on how SPI traits are structured and how they are intended to be used across different platforms.