Skip to content

Commit d45f565

Browse files
authored
Merge pull request #14 from Jim-Hodapp-Coaching/initial_interface
Initial interface
2 parents 54cc3bc + 5878807 commit d45f565

File tree

13 files changed

+940
-7
lines changed

13 files changed

+940
-7
lines changed

.cargo/config

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2+
runner = "probe-run --chip RP2040"
3+
4+
rustflags = [
5+
"-C", "linker=flip-link",
6+
"-C", "link-arg=--nmagic",
7+
"-C", "link-arg=-Tlink.x",
8+
"-C", "link-arg=-Tdefmt.x",
9+
10+
# Code-size optimizations.
11+
# trap unreachable can save a lot of space, but requires nightly compiler.
12+
# uncomment the next line if you wish to enable it
13+
# "-Z", "trap-unreachable=no",
14+
"-C", "inline-threshold=5",
15+
"-C", "no-vectorize-loops",
16+
]
17+
18+
[build]
19+
target = "thumbv6m-none-eabi"
20+
21+
[env]
22+
# Set the level of debug output to display from the target application
23+
DEFMT_LOG = "debug"

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"rust.target": "thumbv6m-none-eabi",
3+
"rust.all_targets": true
4+
}

Cargo.toml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,25 @@ readme = "README.md"
99
name = "esp32-wroom-rp"
1010
version = "0.1.0"
1111
resolver = "2"
12-
description = "Rust-based Espressif ESP32-WROOM WiFi hardware abstraction layer for RP2040 series microcontroller."
12+
description = "Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards."
13+
14+
[lib]
15+
name = "esp32_wroom_rp"
1316

1417
[dependencies]
18+
cortex-m = "0.7"
19+
cortex-m-rt = "0.7"
20+
embedded-hal = { version = "=1.0.0-alpha.7" }
21+
eh-02 = { version = "0.2", package="embedded-hal" }
22+
embedded-time = "0.12"
23+
24+
defmt = "0.3"
25+
defmt-rtt = "0.3"
26+
panic-probe = { version = "0.3", features = ["print-rtt"] }
27+
28+
rp2040-hal = { version = "0.5", features=["rt", "eh1_0_alpha"] }
29+
rp2040-boot2 = { version = "0.2" }
30+
cortex-m-semihosting = "0.5"
1531

1632
[features]
1733
default = [
@@ -75,3 +91,6 @@ debug-assertions = false
7591
incremental = false
7692
lto = 'fat'
7793
opt-level = 3
94+
95+
[[example]]
96+
name = "get_fw_version"

README.md

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,130 @@ Supports the [ESP32-WROOM-32E](https://www.espressif.com/sites/default/files/doc
55

66
Future implementations will support the [ESP32-WROOM-DA](https://www.espressif.com/sites/default/files/documentation/esp32-wroom-da_datasheet_en.pdf) module.
77

8-
This is a new project that has recently launched (end of April, 2022). See the main page section [Getting Involved](https://github.com/Jim-Hodapp-Coaching#getting-involved) for more info on how to contribute to this project and the Rust Never Sleeps community.
8+
## Usage
9+
10+
```
11+
use esp32_wroom_rp::wifi;
12+
13+
let spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
14+
let spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
15+
let spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();
16+
17+
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
18+
19+
Exchange the uninitialized SPI driver for an initialized one
20+
let spi = spi.init(
21+
&mut pac.RESETS,
22+
clocks.peripheral_clock.freq(),
23+
8_000_000u32.Hz(),
24+
&MODE_0,
25+
);
26+
27+
let esp_pins = esp32_wroom_rp::gpio::EspControlPins {
28+
// CS on pin x (GPIO7)
29+
cs: pins.gpio7.into_mode::<hal::gpio::PushPullOutput>(),
30+
// GPIO0 on pin x (GPIO2)
31+
gpio0: pins.gpio2.into_mode::<hal::gpio::PushPullOutput>(),
32+
// RESETn on pin x (GPIO11)
33+
resetn: pins.gpio11.into_mode::<hal::gpio::PushPullOutput>(),
34+
// ACK on pin x (GPIO10)
35+
ack: pins.gpio10.into_mode::<hal::gpio::FloatingInput>(),
36+
};
37+
38+
let mut wifi = esp32_wroom_rp::spi::Wifi::init(spi, esp_pins, &mut delay).unwrap();
39+
let version = wifi.firmware_version();
40+
```
41+
42+
## Hardware
43+
44+
In order to run this code you need to purchase some hardware. This section provides a list of required hardware
45+
needed at minimum, and some suggested items to make your life even easier.
46+
47+
### Required Hardware
48+
49+
1. [Raspberry Pi Pico with pre-soldered headers](https://www.elektor.com/raspberry-pi-pico-rp2040-with-pre-soldered-headers) (2x)
50+
* [Alternate distributors](https://www.raspberrypi.com/products/raspberry-pi-pico/)
51+
52+
2. Pimoroni Pico Wireless Pack (1x)
53+
* [US distributor](https://www.digikey.com/en/products/detail/pimoroni-ltd/PIM548/15851367)
54+
* [UK distributor](https://shop.pimoroni.com/products/pico-wireless-pack?variant=32369508581459)
55+
* [EU distributor](https://www.elektor.com/pimoroni-raspberry-pi-pico-wireless-pack)
56+
57+
3. [Breadboard](https://www.sparkfun.com/products/12614) (1x)
58+
* __Note__: If you already have a medium/large breadboard, then don't worry about purchasing this specific one
59+
60+
61+
### Optional but Helpful Hardware
62+
63+
1. [Break Away Headers](https://www.sparkfun.com/products/116) (1x)
64+
* If you want to solder headers to the non-pre-soldered BME280 sensor board from #2 above
65+
66+
2. [Multi-length Jumper Wire Kit 140pcs](https://www.sparkfun.com/products/124) (1x)
67+
68+
3. [Straight 7" Jumper Wires M/M](https://www.sparkfun.com/products/11026) (1x)
69+
* Helpful to have some of these on hand
70+
71+
4. [Straight 6" Jumper Wires M/F](https://www.sparkfun.com/products/12794) (1x)
72+
* Helpful to have some of these on hand
73+
74+
5. [Saleae Logic 8](https://www.saleae.com/) (1x)
75+
* __Note__: Only needed if you'd like to participate in developing/debugging parts of this project that communicate
76+
on the SPI/I2C buses
77+
78+
### Wiring Details
79+
80+
Start with the section [Pico to Pico Wiring in this article](https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry?s=w) to set up using two Picos together, one as a Picoprobe (flash/debug) and the other as your embedded target.
81+
82+
Once properly wired, it should look similar to the following:
83+
84+
![IMG_3747](https://user-images.githubusercontent.com/3219120/159986814-37c99e4f-97cb-43c8-aa2f-1b325a1eb670.jpg)
85+
86+
![IMG_3746](https://user-images.githubusercontent.com/3219120/159986853-d1f84e01-1caa-4f0f-bc84-53ef79fa25b1.jpg)
87+
88+
__Pico to ESP32 WiFi__
89+
90+
The following table lists the pin name and pin number to properly wire between a Pico board and an ESP32 WiFi. This can be done on a breadboard such as the one listed above. Note that V+/- rail means the +/- columns on the breadboard for use as +5 VDC and GND respectively.
91+
92+
| Pico | ESP32 WiFi | Adafuit Airlift | Breadboard |
93+
| ----------------- | ---------------- | ----------------| ---------- |
94+
| | GND (Pin 3) | GND (Pin 3) | V- rail |
95+
| GP2 (Pin 4) | GPIO0 (Pin 4) | GP0 (Pin 10) | |
96+
| GP7 (Pin 10) | ESP_CSn (Pin 10) | CS (Pin 7) | |
97+
| GP8 (Pin 11) | | | |
98+
| GP9 (Pin 12) | | | |
99+
| GP10 (Pin 14) | ACK (Pin 14) | Busy (Pin 8) | |
100+
| GP11 (Pin 15) | RESETn (Pin 15) | RSTn (Pin 9) | |
101+
| GP12 (Pin 16) | SW_A (Pin 16) | N/A | |
102+
| | GND (Pin 18) | | V- rail |
103+
| VBUS (Pin 40) | VBUS (Pin 40) | | |
104+
| VSYS (Pin 39) | VSYS (Pin 39) | VIN (Pin 1) | V+ rail |
105+
| GND (Pin 38) | GND (Pin 38) | | V- rail |
106+
| 3V3(OUT) (Pin 36) | 3V3 (Pin 36) | 3Vo (Pin 2) | |
107+
| GP19 (Pin 25) | MOSI (Pin 25) | MOSI (Pin 5) | |
108+
| GP18 (Pin 24) | SCLK (Pin 24) | SCK (Pin 4) | |
109+
| | GND (Pin 23) | | V- rail |
110+
| GP16 (Pin 21) | MISO (Pin 21) | MISO (Pin 5) | |
111+
112+
113+
***
114+
115+
## Software Requirements
116+
- The standard Rust tooling (cargo, rustup) which you can install from https://rustup.rs/
117+
118+
- Toolchain support for the cortex-m0+ processors in the rp2040 (thumbv6m-none-eabi)
119+
120+
- flip-link - this allows you to detect stack-overflows on the first core, which is the only supported target for now.
121+
122+
## Installation of development dependencies
123+
```
124+
rustup target install thumbv6m-none-eabi
125+
cargo install flip-link
126+
cargo install probe-run
127+
```
128+
129+
## Getting Involved
130+
131+
This project launched in April, 2022). See the main page section [Getting Involved](https://github.com/Jim-Hodapp-Coaching#getting-involved) for more info on how to contribute to this project and the Rust Never Sleeps community.
9132

10133
To get involved, please [request to join the community here on GitHub](https://rustneversleeps.wufoo.com/forms/z1x3dy1j0ycafxq/) and then start contributing to the [research and design discussions](https://github.com/Jim-Hodapp-Coaching/esp32-wroom-rp/discussions) currently underway.
11134

build.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1-
fn main() {}
1+
//! This build script copies the `memory.x` file from the crate root into
2+
//! a directory where the linker can always find it at build time.
3+
//! For many projects this is optional, as the linker always searches the
4+
//! project root directory -- wherever `Cargo.toml` is. However, if you
5+
//! are using a workspace or have a more complicated build setup, this
6+
//! build script becomes required. Additionally, by requesting that
7+
//! Cargo re-run the build script whenever `memory.x` is changed,
8+
//! updating `memory.x` ensures a rebuild of the application with the
9+
//! new memory settings.
10+
11+
use std::env;
12+
use std::fs::File;
13+
use std::io::Write;
14+
use std::path::PathBuf;
15+
16+
fn main() {
17+
// Put `memory.x` in our output directory and ensure it's
18+
// on the linker search path.
19+
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20+
File::create(out.join("memory.x"))
21+
.unwrap()
22+
.write_all(include_bytes!("memory.x"))
23+
.unwrap();
24+
println!("cargo:rustc-link-search={}", out.display());
25+
26+
// By default, Cargo will re-run a build script whenever
27+
// any file in the project changes. By specifying `memory.x`
28+
// here, we ensure the build script is only re-run when
29+
// `memory.x` is changed.
30+
println!("cargo:rerun-if-changed=memory.x");
31+
}

examples/get_fw_version.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//! # ESP32-WROOM-RP Pico Wireless Example
2+
//!
3+
//! This application demonstrates how to use the ESP32-WROOM-RP crate to communicate
4+
//! with a remote ESP32 wifi and retrieve its firmware version.
5+
//!
6+
//! See the `Cargo.toml` file for Copyright and license details.
7+
8+
#![no_std]
9+
#![no_main]
10+
11+
extern crate esp32_wroom_rp;
12+
13+
// The macro for our start-up function
14+
use cortex_m_rt::entry;
15+
16+
// Needed for debug output symbols to be linked in binary image
17+
use defmt_rtt as _;
18+
19+
use panic_probe as _;
20+
21+
// Alias for our HAL crate
22+
use rp2040_hal as hal;
23+
24+
use eh_02::spi::MODE_0;
25+
use embedded_time::fixed_point::FixedPoint;
26+
use embedded_time::rate::Extensions;
27+
use hal::clocks::Clock;
28+
use hal::pac;
29+
30+
/// The linker will place this boot block at the start of our program image. We
31+
/// need this to help the ROM bootloader get our code up and running.
32+
#[link_section = ".boot2"]
33+
#[used]
34+
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
35+
36+
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
37+
/// if your board has a different frequency
38+
const XTAL_FREQ_HZ: u32 = 12_000_000u32;
39+
40+
// Until cortex_m implements the DelayUs trait needed for embedded-hal-1.0.0,
41+
// provide a wrapper around it
42+
pub struct DelayWrap(cortex_m::delay::Delay);
43+
44+
impl embedded_hal::delay::blocking::DelayUs for DelayWrap {
45+
type Error = core::convert::Infallible;
46+
47+
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
48+
self.0.delay_us(us);
49+
Ok(())
50+
}
51+
52+
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
53+
self.0.delay_ms(ms);
54+
Ok(())
55+
}
56+
}
57+
58+
/// Entry point to our bare-metal application.
59+
///
60+
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
61+
/// as soon as all global variables are initialized.
62+
#[entry]
63+
fn main() -> ! {
64+
// Grab our singleton objects
65+
let mut pac = pac::Peripherals::take().unwrap();
66+
let core = pac::CorePeripherals::take().unwrap();
67+
68+
// Set up the watchdog driver - needed by the clock setup code
69+
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
70+
71+
// Configure the clocks
72+
let clocks = hal::clocks::init_clocks_and_plls(
73+
XTAL_FREQ_HZ,
74+
pac.XOSC,
75+
pac.CLOCKS,
76+
pac.PLL_SYS,
77+
pac.PLL_USB,
78+
&mut pac.RESETS,
79+
&mut watchdog,
80+
)
81+
.ok()
82+
.unwrap();
83+
84+
let mut delay = DelayWrap(cortex_m::delay::Delay::new(
85+
core.SYST,
86+
clocks.system_clock.freq().integer(),
87+
));
88+
89+
// The single-cycle I/O block controls our GPIO pins
90+
let sio = hal::Sio::new(pac.SIO);
91+
92+
// Set the pins to their default state
93+
let pins = hal::gpio::Pins::new(
94+
pac.IO_BANK0,
95+
pac.PADS_BANK0,
96+
sio.gpio_bank0,
97+
&mut pac.RESETS,
98+
);
99+
100+
defmt::info!("ESP32-WROOM-RP get NINA firmware version example");
101+
102+
// These are implicitly used by the spi driver if they are in the correct mode
103+
let spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
104+
let spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
105+
let spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();
106+
107+
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
108+
109+
// Exchange the uninitialized SPI driver for an initialized one
110+
let spi = spi.init(
111+
&mut pac.RESETS,
112+
clocks.peripheral_clock.freq(),
113+
8_000_000u32.Hz(),
114+
&MODE_0,
115+
);
116+
117+
let esp_pins = esp32_wroom_rp::gpio::EspControlPins {
118+
// CS on pin x (GPIO7)
119+
cs: pins.gpio7.into_mode::<hal::gpio::PushPullOutput>(),
120+
// GPIO0 on pin x (GPIO2)
121+
gpio0: pins.gpio2.into_mode::<hal::gpio::PushPullOutput>(),
122+
// RESETn on pin x (GPIO11)
123+
resetn: pins.gpio11.into_mode::<hal::gpio::PushPullOutput>(),
124+
// ACK on pin x (GPIO10)
125+
ack: pins.gpio10.into_mode::<hal::gpio::FloatingInput>(),
126+
};
127+
let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap();
128+
let firmware_version = wifi.firmware_version();
129+
defmt::info!("NINA firmware version: {:?}", firmware_version);
130+
131+
defmt::info!("Entering main loop");
132+
loop {}
133+
}

memory.x

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
MEMORY {
2+
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3+
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
4+
RAM : ORIGIN = 0x20000000, LENGTH = 256K
5+
}
6+
7+
SECTIONS {
8+
/* ### Boot loader */
9+
.boot2 ORIGIN(BOOT2) :
10+
{
11+
KEEP(*(.boot2));
12+
} > BOOT2
13+
} INSERT BEFORE .text;

0 commit comments

Comments
 (0)