Skip to content

Commit

Permalink
Merge pull request #14 from Jim-Hodapp-Coaching/initial_interface
Browse files Browse the repository at this point in the history
Initial interface
  • Loading branch information
calebbourg authored Aug 19, 2022
2 parents 54cc3bc + 5878807 commit d45f565
Show file tree
Hide file tree
Showing 13 changed files with 940 additions and 7 deletions.
23 changes: 23 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-run --chip RP2040"

rustflags = [
"-C", "linker=flip-link",
"-C", "link-arg=--nmagic",
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",

# Code-size optimizations.
# trap unreachable can save a lot of space, but requires nightly compiler.
# uncomment the next line if you wish to enable it
# "-Z", "trap-unreachable=no",
"-C", "inline-threshold=5",
"-C", "no-vectorize-loops",
]

[build]
target = "thumbv6m-none-eabi"

[env]
# Set the level of debug output to display from the target application
DEFMT_LOG = "debug"
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"rust.target": "thumbv6m-none-eabi",
"rust.all_targets": true
}
21 changes: 20 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,25 @@ readme = "README.md"
name = "esp32-wroom-rp"
version = "0.1.0"
resolver = "2"
description = "Rust-based Espressif ESP32-WROOM WiFi hardware abstraction layer for RP2040 series microcontroller."
description = "Rust-based Espressif ESP32-WROOM WiFi driver crate for RP2040 series microcontroller boards."

[lib]
name = "esp32_wroom_rp"

[dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = { version = "=1.0.0-alpha.7" }
eh-02 = { version = "0.2", package="embedded-hal" }
embedded-time = "0.12"

defmt = "0.3"
defmt-rtt = "0.3"
panic-probe = { version = "0.3", features = ["print-rtt"] }

rp2040-hal = { version = "0.5", features=["rt", "eh1_0_alpha"] }
rp2040-boot2 = { version = "0.2" }
cortex-m-semihosting = "0.5"

[features]
default = [
Expand Down Expand Up @@ -75,3 +91,6 @@ debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 3

[[example]]
name = "get_fw_version"
125 changes: 124 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,130 @@ Supports the [ESP32-WROOM-32E](https://www.espressif.com/sites/default/files/doc

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

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.
## Usage

```
use esp32_wroom_rp::wifi;
let spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
let spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
let spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();
let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);
Exchange the uninitialized SPI driver for an initialized one
let spi = spi.init(
&mut pac.RESETS,
clocks.peripheral_clock.freq(),
8_000_000u32.Hz(),
&MODE_0,
);
let esp_pins = esp32_wroom_rp::gpio::EspControlPins {
// CS on pin x (GPIO7)
cs: pins.gpio7.into_mode::<hal::gpio::PushPullOutput>(),
// GPIO0 on pin x (GPIO2)
gpio0: pins.gpio2.into_mode::<hal::gpio::PushPullOutput>(),
// RESETn on pin x (GPIO11)
resetn: pins.gpio11.into_mode::<hal::gpio::PushPullOutput>(),
// ACK on pin x (GPIO10)
ack: pins.gpio10.into_mode::<hal::gpio::FloatingInput>(),
};
let mut wifi = esp32_wroom_rp::spi::Wifi::init(spi, esp_pins, &mut delay).unwrap();
let version = wifi.firmware_version();
```

## Hardware

In order to run this code you need to purchase some hardware. This section provides a list of required hardware
needed at minimum, and some suggested items to make your life even easier.

### Required Hardware

1. [Raspberry Pi Pico with pre-soldered headers](https://www.elektor.com/raspberry-pi-pico-rp2040-with-pre-soldered-headers) (2x)
* [Alternate distributors](https://www.raspberrypi.com/products/raspberry-pi-pico/)

2. Pimoroni Pico Wireless Pack (1x)
* [US distributor](https://www.digikey.com/en/products/detail/pimoroni-ltd/PIM548/15851367)
* [UK distributor](https://shop.pimoroni.com/products/pico-wireless-pack?variant=32369508581459)
* [EU distributor](https://www.elektor.com/pimoroni-raspberry-pi-pico-wireless-pack)

3. [Breadboard](https://www.sparkfun.com/products/12614) (1x)
* __Note__: If you already have a medium/large breadboard, then don't worry about purchasing this specific one


### Optional but Helpful Hardware

1. [Break Away Headers](https://www.sparkfun.com/products/116) (1x)
* If you want to solder headers to the non-pre-soldered BME280 sensor board from #2 above

2. [Multi-length Jumper Wire Kit 140pcs](https://www.sparkfun.com/products/124) (1x)

3. [Straight 7" Jumper Wires M/M](https://www.sparkfun.com/products/11026) (1x)
* Helpful to have some of these on hand

4. [Straight 6" Jumper Wires M/F](https://www.sparkfun.com/products/12794) (1x)
* Helpful to have some of these on hand

5. [Saleae Logic 8](https://www.saleae.com/) (1x)
* __Note__: Only needed if you'd like to participate in developing/debugging parts of this project that communicate
on the SPI/I2C buses

### Wiring Details

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.

Once properly wired, it should look similar to the following:

![IMG_3747](https://user-images.githubusercontent.com/3219120/159986814-37c99e4f-97cb-43c8-aa2f-1b325a1eb670.jpg)

![IMG_3746](https://user-images.githubusercontent.com/3219120/159986853-d1f84e01-1caa-4f0f-bc84-53ef79fa25b1.jpg)

__Pico to ESP32 WiFi__

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.

| Pico | ESP32 WiFi | Adafuit Airlift | Breadboard |
| ----------------- | ---------------- | ----------------| ---------- |
| | GND (Pin 3) | GND (Pin 3) | V- rail |
| GP2 (Pin 4) | GPIO0 (Pin 4) | GP0 (Pin 10) | |
| GP7 (Pin 10) | ESP_CSn (Pin 10) | CS (Pin 7) | |
| GP8 (Pin 11) | | | |
| GP9 (Pin 12) | | | |
| GP10 (Pin 14) | ACK (Pin 14) | Busy (Pin 8) | |
| GP11 (Pin 15) | RESETn (Pin 15) | RSTn (Pin 9) | |
| GP12 (Pin 16) | SW_A (Pin 16) | N/A | |
| | GND (Pin 18) | | V- rail |
| VBUS (Pin 40) | VBUS (Pin 40) | | |
| VSYS (Pin 39) | VSYS (Pin 39) | VIN (Pin 1) | V+ rail |
| GND (Pin 38) | GND (Pin 38) | | V- rail |
| 3V3(OUT) (Pin 36) | 3V3 (Pin 36) | 3Vo (Pin 2) | |
| GP19 (Pin 25) | MOSI (Pin 25) | MOSI (Pin 5) | |
| GP18 (Pin 24) | SCLK (Pin 24) | SCK (Pin 4) | |
| | GND (Pin 23) | | V- rail |
| GP16 (Pin 21) | MISO (Pin 21) | MISO (Pin 5) | |


***

## Software Requirements
- The standard Rust tooling (cargo, rustup) which you can install from https://rustup.rs/

- Toolchain support for the cortex-m0+ processors in the rp2040 (thumbv6m-none-eabi)

- flip-link - this allows you to detect stack-overflows on the first core, which is the only supported target for now.

## Installation of development dependencies
```
rustup target install thumbv6m-none-eabi
cargo install flip-link
cargo install probe-run
```

## Getting Involved

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.

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.

Expand Down
32 changes: 31 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
fn main() {}
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}
133 changes: 133 additions & 0 deletions examples/get_fw_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//! # ESP32-WROOM-RP Pico Wireless Example
//!
//! This application demonstrates how to use the ESP32-WROOM-RP crate to communicate
//! with a remote ESP32 wifi and retrieve its firmware version.
//!
//! See the `Cargo.toml` file for Copyright and license details.
#![no_std]
#![no_main]

extern crate esp32_wroom_rp;

// The macro for our start-up function
use cortex_m_rt::entry;

// Needed for debug output symbols to be linked in binary image
use defmt_rtt as _;

use panic_probe as _;

// Alias for our HAL crate
use rp2040_hal as hal;

use eh_02::spi::MODE_0;
use embedded_time::fixed_point::FixedPoint;
use embedded_time::rate::Extensions;
use hal::clocks::Clock;
use hal::pac;

/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;

/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
/// if your board has a different frequency
const XTAL_FREQ_HZ: u32 = 12_000_000u32;

// Until cortex_m implements the DelayUs trait needed for embedded-hal-1.0.0,
// provide a wrapper around it
pub struct DelayWrap(cortex_m::delay::Delay);

impl embedded_hal::delay::blocking::DelayUs for DelayWrap {
type Error = core::convert::Infallible;

fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
self.0.delay_us(us);
Ok(())
}

fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
self.0.delay_ms(ms);
Ok(())
}
}

/// Entry point to our bare-metal application.
///
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables are initialized.
#[entry]
fn main() -> ! {
// Grab our singleton objects
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();

// Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

// Configure the clocks
let clocks = hal::clocks::init_clocks_and_plls(
XTAL_FREQ_HZ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();

let mut delay = DelayWrap(cortex_m::delay::Delay::new(
core.SYST,
clocks.system_clock.freq().integer(),
));

// The single-cycle I/O block controls our GPIO pins
let sio = hal::Sio::new(pac.SIO);

// Set the pins to their default state
let pins = hal::gpio::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);

defmt::info!("ESP32-WROOM-RP get NINA firmware version example");

// These are implicitly used by the spi driver if they are in the correct mode
let spi_miso = pins.gpio16.into_mode::<hal::gpio::FunctionSpi>();
let spi_sclk = pins.gpio18.into_mode::<hal::gpio::FunctionSpi>();
let spi_mosi = pins.gpio19.into_mode::<hal::gpio::FunctionSpi>();

let spi = hal::Spi::<_, _, 8>::new(pac.SPI0);

// Exchange the uninitialized SPI driver for an initialized one
let spi = spi.init(
&mut pac.RESETS,
clocks.peripheral_clock.freq(),
8_000_000u32.Hz(),
&MODE_0,
);

let esp_pins = esp32_wroom_rp::gpio::EspControlPins {
// CS on pin x (GPIO7)
cs: pins.gpio7.into_mode::<hal::gpio::PushPullOutput>(),
// GPIO0 on pin x (GPIO2)
gpio0: pins.gpio2.into_mode::<hal::gpio::PushPullOutput>(),
// RESETn on pin x (GPIO11)
resetn: pins.gpio11.into_mode::<hal::gpio::PushPullOutput>(),
// ACK on pin x (GPIO10)
ack: pins.gpio10.into_mode::<hal::gpio::FloatingInput>(),
};
let mut wifi = esp32_wroom_rp::wifi::Wifi::init(spi, esp_pins, &mut delay).unwrap();
let firmware_version = wifi.firmware_version();
defmt::info!("NINA firmware version: {:?}", firmware_version);

defmt::info!("Entering main loop");
loop {}
}
13 changes: 13 additions & 0 deletions memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;
Loading

0 comments on commit d45f565

Please sign in to comment.