mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
Pico explorer board support
This commit is contained in:
parent
bcfbd72ed1
commit
ae8fe512bd
|
@ -13,7 +13,19 @@ license = "MIT OR Apache-2.0"
|
||||||
cortex-m = "0.7.2"
|
cortex-m = "0.7.2"
|
||||||
rp2040-hal = { path="../../rp2040-hal", version="0.1.0" }
|
rp2040-hal = { path="../../rp2040-hal", version="0.1.0" }
|
||||||
cortex-m-rt = { version="0.6.14", optional=true }
|
cortex-m-rt = { version="0.6.14", optional=true }
|
||||||
|
embedded-hal = { version="0.2.4", features=["unproven"] }
|
||||||
|
st7789 = "0.6.1"
|
||||||
|
display-interface-spi = "0.4.1"
|
||||||
|
embedded-time = "0.12.0"
|
||||||
|
embedded-graphics = "0.7.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
rt = ["cortex-m-rt","rp2040-hal/rt"]
|
rt = ["cortex-m-rt","rp2040-hal/rt"]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
display-interface = "0.4.1"
|
||||||
|
panic-halt = "0.2.0"
|
||||||
|
arrayvec = { version="0.7.1", default-features=false }
|
||||||
|
rp2040-boot2 = { git="https://github.com/rp-rs/rp2040-boot2-rs", branch="main" }
|
||||||
|
nb = "1.0.0"
|
||||||
|
|
111
boards/pico_explorer/examples/pico_explorer_showcase.rs
Normal file
111
boards/pico_explorer/examples/pico_explorer_showcase.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use arrayvec::ArrayString;
|
||||||
|
use core::fmt::Write;
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
use embedded_graphics::{
|
||||||
|
mono_font::{ascii::FONT_10X20, MonoTextStyleBuilder},
|
||||||
|
pixelcolor::Rgb565,
|
||||||
|
prelude::*,
|
||||||
|
text::{Alignment, Text},
|
||||||
|
};
|
||||||
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
|
use embedded_time::rate::*;
|
||||||
|
use hal::{adc::Adc, clocks::*, sio::Sio, watchdog::Watchdog};
|
||||||
|
use panic_halt as _;
|
||||||
|
use pico_explorer::{hal, pac, Button, PicoExplorer, XOSC_CRYSTAL_FREQ};
|
||||||
|
|
||||||
|
#[link_section = ".boot2"]
|
||||||
|
#[used]
|
||||||
|
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
|
||||||
|
|
||||||
|
// See 4.9.5 from RP2040 datasheet
|
||||||
|
fn calc_temp(adc_value: f32, refv: f64) -> f64 {
|
||||||
|
let vbe: f64 = f64::from(adc_value) * refv;
|
||||||
|
27f64 - (vbe - 0.706) / 0.001721
|
||||||
|
}
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut p = pac::Peripherals::take().unwrap();
|
||||||
|
let cp = pac::CorePeripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Enable watchdog and clocks
|
||||||
|
let mut watchdog = Watchdog::new(p.WATCHDOG);
|
||||||
|
let clocks = init_clocks_and_plls(
|
||||||
|
XOSC_CRYSTAL_FREQ,
|
||||||
|
p.XOSC,
|
||||||
|
p.CLOCKS,
|
||||||
|
p.PLL_SYS,
|
||||||
|
p.PLL_USB,
|
||||||
|
&mut p.RESETS,
|
||||||
|
&mut watchdog,
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut delay = cortex_m::delay::Delay::new(cp.SYST, clocks.system_clock.get_freq().integer());
|
||||||
|
|
||||||
|
// Enable adc
|
||||||
|
let mut adc = Adc::new(p.ADC, &mut p.RESETS);
|
||||||
|
let mut temp_sense = adc.enable_temp_sensor();
|
||||||
|
|
||||||
|
let sio = Sio::new(p.SIO);
|
||||||
|
|
||||||
|
let (mut explorer, pins) = PicoExplorer::new(
|
||||||
|
p.IO_BANK0,
|
||||||
|
p.PADS_BANK0,
|
||||||
|
sio.gpio_bank0,
|
||||||
|
p.SPI0,
|
||||||
|
adc,
|
||||||
|
&mut p.RESETS,
|
||||||
|
&mut delay,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut led = pins.led.into_push_pull_output();
|
||||||
|
|
||||||
|
let mut even = true;
|
||||||
|
loop {
|
||||||
|
delay.delay_ms(500);
|
||||||
|
|
||||||
|
// Set GPIO25 to be low
|
||||||
|
led.set_low().unwrap();
|
||||||
|
|
||||||
|
delay.delay_ms(500);
|
||||||
|
|
||||||
|
// Set GPIO25 to be high
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
let adc_value = explorer.get_adc(&mut temp_sense);
|
||||||
|
let temp: f64 = calc_temp(adc_value, 3.3);
|
||||||
|
|
||||||
|
// Create a fixed buffer to store screen contents
|
||||||
|
let mut buf = ArrayString::<100>::new();
|
||||||
|
|
||||||
|
// Write to buffer
|
||||||
|
writeln!(&mut buf, "Hello World {}", if even { '|' } else { '-' }).unwrap();
|
||||||
|
writeln!(&mut buf, "Temp: {:.1}", temp).unwrap();
|
||||||
|
writeln!(
|
||||||
|
&mut buf,
|
||||||
|
"A:{:.1} B:{:.1}\nX:{:.1} Y:{:.1}",
|
||||||
|
explorer.is_pressed(Button::A),
|
||||||
|
explorer.is_pressed(Button::B),
|
||||||
|
explorer.is_pressed(Button::X),
|
||||||
|
explorer.is_pressed(Button::Y)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Draw buffer on screen
|
||||||
|
let style = MonoTextStyleBuilder::new()
|
||||||
|
.font(&FONT_10X20)
|
||||||
|
.text_color(Rgb565::GREEN)
|
||||||
|
.background_color(Rgb565::BLACK)
|
||||||
|
.build();
|
||||||
|
Text::with_alignment(&buf, Point::new(20, 30), style, Alignment::Left)
|
||||||
|
.draw(&mut explorer.screen)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
even = !even;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,62 +1,66 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate rp2040_hal as hal;
|
pub extern crate rp2040_hal as hal;
|
||||||
|
|
||||||
#[cfg(feature = "rt")]
|
#[cfg(feature = "rt")]
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt;
|
||||||
|
|
||||||
#[cfg(feature = "rt")]
|
#[cfg(feature = "rt")]
|
||||||
pub use cortex_m_rt::entry;
|
pub use cortex_m_rt::entry;
|
||||||
|
use display_interface_spi::SPIInterface;
|
||||||
|
use embedded_graphics::{
|
||||||
|
draw_target::DrawTarget,
|
||||||
|
pixelcolor::{Rgb565, RgbColor},
|
||||||
|
};
|
||||||
|
use embedded_hal::{
|
||||||
|
adc::{Channel, OneShot},
|
||||||
|
blocking::delay::DelayUs,
|
||||||
|
digital::v2::{InputPin, OutputPin},
|
||||||
|
spi::MODE_0,
|
||||||
|
};
|
||||||
|
use embedded_time::rate::*;
|
||||||
pub use hal::pac;
|
pub use hal::pac;
|
||||||
|
use hal::{
|
||||||
|
adc::Adc,
|
||||||
|
gpio::{
|
||||||
|
bank0::{
|
||||||
|
Gpio0, Gpio1, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17, Gpio18, Gpio19, Gpio2,
|
||||||
|
Gpio20, Gpio21, Gpio22, Gpio23, Gpio24, Gpio25, Gpio26, Gpio27, Gpio28, Gpio29, Gpio3,
|
||||||
|
Gpio4, Gpio5, Gpio6, Gpio7,
|
||||||
|
},
|
||||||
|
FunctionI2C, FunctionPwm, FunctionSpi, Pin, PinId, PullUpInput, PushPullOutput,
|
||||||
|
},
|
||||||
|
pac::{RESETS, SPI0},
|
||||||
|
sio::SioGpioBank0,
|
||||||
|
spi::{Enabled, Spi},
|
||||||
|
};
|
||||||
|
use st7789::ST7789;
|
||||||
|
|
||||||
|
mod internal_pins {
|
||||||
hal::bsp_pins!(
|
hal::bsp_pins!(
|
||||||
Gpio0 {
|
Gpio0 { name: gpio0 },
|
||||||
name: gpio0,
|
Gpio1 { name: gpio1 },
|
||||||
aliases: { FunctionPwm: Audio0 }
|
Gpio2 { name: gpio2 },
|
||||||
},
|
Gpio3 { name: gpio3 },
|
||||||
Gpio1 {
|
Gpio4 { name: gpio4 },
|
||||||
name: gpio1,
|
Gpio5 { name: gpio5 },
|
||||||
aliases: { FunctionPwm: Audio1 }
|
Gpio6 { name: gpio6 },
|
||||||
},
|
Gpio7 { name: gpio7 },
|
||||||
Gpio2 {
|
|
||||||
name: gpio2,
|
|
||||||
aliases: { FunctionPwm: Audio2 }
|
|
||||||
},
|
|
||||||
Gpio3 {
|
|
||||||
name: gpio3,
|
|
||||||
aliases: { FunctionPwm: Audio3 }
|
|
||||||
},
|
|
||||||
Gpio4 {
|
|
||||||
name: gpio4,
|
|
||||||
aliases: { FunctionPwm: Audio4 }
|
|
||||||
},
|
|
||||||
Gpio5 {
|
|
||||||
name: gpio5,
|
|
||||||
aliases: { FunctionPwm: Audio5 }
|
|
||||||
},
|
|
||||||
Gpio6 {
|
|
||||||
name: gpio6,
|
|
||||||
aliases: { FunctionPwm: Audio6 }
|
|
||||||
},
|
|
||||||
Gpio7 {
|
|
||||||
name: gpio7,
|
|
||||||
aliases: { FunctionPwm: Audio7 }
|
|
||||||
},
|
|
||||||
Gpio8 {
|
Gpio8 {
|
||||||
name: motor1_min,
|
name: motor1_neg,
|
||||||
aliases: { FunctionPwm: Motor1Min }
|
aliases: { FunctionPwm: Motor1Neg }
|
||||||
},
|
},
|
||||||
Gpio9 {
|
Gpio9 {
|
||||||
name: motor1_plus,
|
name: motor1_pos,
|
||||||
aliases: { FunctionPwm: Motor1Plus }
|
aliases: { FunctionPwm: Motor1Pos }
|
||||||
},
|
},
|
||||||
Gpio10 {
|
Gpio10 {
|
||||||
name: motor2_min,
|
name: motor2_neg,
|
||||||
aliases: { FunctionPwm: Motor2Min }
|
aliases: { FunctionPwm: Motor2Neg }
|
||||||
},
|
},
|
||||||
Gpio11 {
|
Gpio11 {
|
||||||
name: motor2_plus,
|
name: motor2_pos,
|
||||||
aliases: { FunctionPwm: Motor2Plus }
|
aliases: { FunctionPwm: Motor2Pos }
|
||||||
},
|
},
|
||||||
Gpio12 { name: switch_a },
|
Gpio12 { name: switch_a },
|
||||||
Gpio13 { name: switch_b },
|
Gpio13 { name: switch_b },
|
||||||
|
@ -87,10 +91,186 @@ hal::bsp_pins!(
|
||||||
aliases: { FunctionI2C: Scl }
|
aliases: { FunctionI2C: Scl }
|
||||||
},
|
},
|
||||||
Gpio22 { name: i2c_int },
|
Gpio22 { name: i2c_int },
|
||||||
|
Gpio23 { name: bootsel },
|
||||||
|
Gpio24 { name: vbus_detect },
|
||||||
Gpio25 { name: led },
|
Gpio25 { name: led },
|
||||||
Gpio26 { name: adc0 },
|
Gpio26 { name: adc0 },
|
||||||
Gpio27 { name: adc1 },
|
Gpio27 { name: adc1 },
|
||||||
Gpio28 { name: adc2 },
|
Gpio28 { name: adc2 },
|
||||||
|
Gpio29 {
|
||||||
|
name: voltage_monitor
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pins {
|
||||||
|
pub gpio0: Pin<Gpio0, <Gpio0 as PinId>::Reset>,
|
||||||
|
pub gpio1: Pin<Gpio1, <Gpio1 as PinId>::Reset>,
|
||||||
|
pub gpio2: Pin<Gpio2, <Gpio2 as PinId>::Reset>,
|
||||||
|
pub gpio3: Pin<Gpio3, <Gpio3 as PinId>::Reset>,
|
||||||
|
pub gpio4: Pin<Gpio4, <Gpio4 as PinId>::Reset>,
|
||||||
|
pub gpio5: Pin<Gpio5, <Gpio5 as PinId>::Reset>,
|
||||||
|
pub gpio6: Pin<Gpio6, <Gpio6 as PinId>::Reset>,
|
||||||
|
pub gpio7: Pin<Gpio7, <Gpio7 as PinId>::Reset>,
|
||||||
|
pub spi_sclk: Pin<Gpio18, FunctionSpi>,
|
||||||
|
pub spi_mosi: Pin<Gpio19, FunctionSpi>,
|
||||||
|
pub i2c_sda: Pin<Gpio20, FunctionI2C>,
|
||||||
|
pub i2c_scl: Pin<Gpio21, FunctionI2C>,
|
||||||
|
pub i2c_int: Pin<Gpio22, FunctionI2C>,
|
||||||
|
pub bootsel: Pin<Gpio23, <Gpio23 as PinId>::Reset>,
|
||||||
|
pub vbus_detect: Pin<Gpio24, <Gpio24 as PinId>::Reset>,
|
||||||
|
pub led: Pin<Gpio25, <Gpio25 as PinId>::Reset>,
|
||||||
|
pub adc0: Pin<Gpio26, <Gpio26 as PinId>::Reset>,
|
||||||
|
pub adc1: Pin<Gpio27, <Gpio27 as PinId>::Reset>,
|
||||||
|
pub adc2: Pin<Gpio28, <Gpio28 as PinId>::Reset>,
|
||||||
|
pub voltage_monitor: Pin<Gpio29, <Gpio29 as PinId>::Reset>,
|
||||||
|
}
|
||||||
|
|
||||||
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
|
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
|
||||||
|
pub enum Button {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Motor {
|
||||||
|
_1,
|
||||||
|
_2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MotorAction {
|
||||||
|
Forward(f32),
|
||||||
|
Reverse(f32),
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Screen = ST7789<
|
||||||
|
SPIInterface<Spi<Enabled, SPI0, 8>, Pin<Gpio16, PushPullOutput>, Pin<Gpio17, PushPullOutput>>,
|
||||||
|
DummyPin,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct PicoExplorer {
|
||||||
|
a: Pin<Gpio12, PullUpInput>,
|
||||||
|
b: Pin<Gpio13, PullUpInput>,
|
||||||
|
x: Pin<Gpio14, PullUpInput>,
|
||||||
|
y: Pin<Gpio15, PullUpInput>,
|
||||||
|
adc: Adc,
|
||||||
|
pub screen: Screen,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DummyPin;
|
||||||
|
|
||||||
|
impl OutputPin for DummyPin {
|
||||||
|
type Error = ();
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PicoExplorer {
|
||||||
|
pub fn new(
|
||||||
|
io: pac::IO_BANK0,
|
||||||
|
pads: pac::PADS_BANK0,
|
||||||
|
sio: SioGpioBank0,
|
||||||
|
spi0: SPI0,
|
||||||
|
adc: Adc,
|
||||||
|
resets: &mut RESETS,
|
||||||
|
delay: &mut impl DelayUs<u32>,
|
||||||
|
) -> (Self, Pins) {
|
||||||
|
let internal_pins = internal_pins::Pins::new(io, pads, sio, resets);
|
||||||
|
|
||||||
|
let a = internal_pins.switch_a.into_pull_up_input();
|
||||||
|
let b = internal_pins.switch_b.into_pull_up_input();
|
||||||
|
let x = internal_pins.switch_x.into_pull_up_input();
|
||||||
|
let y = internal_pins.switch_y.into_pull_up_input();
|
||||||
|
|
||||||
|
internal_pins.motor1_pos.into_mode::<FunctionPwm>();
|
||||||
|
internal_pins.motor1_neg.into_mode::<FunctionPwm>();
|
||||||
|
internal_pins.motor2_pos.into_mode::<FunctionPwm>();
|
||||||
|
internal_pins.motor2_neg.into_mode::<FunctionPwm>();
|
||||||
|
|
||||||
|
let dc = internal_pins.spi_miso.into_push_pull_output();
|
||||||
|
let cs = internal_pins.lcd_cs.into_push_pull_output();
|
||||||
|
let spi_sclk = internal_pins.spi_sclk.into_mode::<FunctionSpi>();
|
||||||
|
let spi_mosi = internal_pins.spi_mosi.into_mode::<FunctionSpi>();
|
||||||
|
|
||||||
|
let spi_screen = Spi::<_, _, 8>::new(spi0).init(
|
||||||
|
resets,
|
||||||
|
125_000_000u32.Hz(),
|
||||||
|
16_000_000u32.Hz(),
|
||||||
|
&MODE_0,
|
||||||
|
);
|
||||||
|
|
||||||
|
let spii_screen = SPIInterface::new(spi_screen, dc, cs);
|
||||||
|
|
||||||
|
let mut screen = ST7789::new(spii_screen, DummyPin, 240, 240);
|
||||||
|
|
||||||
|
screen.init(delay).unwrap();
|
||||||
|
screen
|
||||||
|
.set_orientation(st7789::Orientation::Portrait)
|
||||||
|
.unwrap();
|
||||||
|
screen.clear(Rgb565::BLACK).unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
PicoExplorer {
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
adc,
|
||||||
|
screen,
|
||||||
|
},
|
||||||
|
Pins {
|
||||||
|
gpio0: internal_pins.gpio0,
|
||||||
|
gpio1: internal_pins.gpio1,
|
||||||
|
gpio2: internal_pins.gpio2,
|
||||||
|
gpio3: internal_pins.gpio3,
|
||||||
|
gpio4: internal_pins.gpio4,
|
||||||
|
gpio5: internal_pins.gpio5,
|
||||||
|
gpio6: internal_pins.gpio6,
|
||||||
|
gpio7: internal_pins.gpio7,
|
||||||
|
spi_sclk,
|
||||||
|
spi_mosi,
|
||||||
|
i2c_sda: internal_pins.i2c_sda.into_mode(),
|
||||||
|
i2c_scl: internal_pins.i2c_scl.into_mode(),
|
||||||
|
i2c_int: internal_pins.i2c_int.into_mode(),
|
||||||
|
bootsel: internal_pins.bootsel,
|
||||||
|
vbus_detect: internal_pins.vbus_detect,
|
||||||
|
led: internal_pins.led,
|
||||||
|
adc0: internal_pins.adc0,
|
||||||
|
adc1: internal_pins.adc1,
|
||||||
|
adc2: internal_pins.adc2,
|
||||||
|
voltage_monitor: internal_pins.voltage_monitor,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_pressed(&self, button: Button) -> bool {
|
||||||
|
use Button::*;
|
||||||
|
match button {
|
||||||
|
A => self.a.is_low().unwrap(),
|
||||||
|
B => self.b.is_low().unwrap(),
|
||||||
|
X => self.x.is_low().unwrap(),
|
||||||
|
Y => self.y.is_low().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_adc<Pin: Channel<Adc, ID = u8>>(&mut self, channel: &mut Pin) -> f32 {
|
||||||
|
// scale raw 12-bit adc value to 0 .. 1 float
|
||||||
|
let adc_value: u16 = self.adc.read(channel).unwrap();
|
||||||
|
let mut result: f32 = f32::from(adc_value) / f32::from(1u16 << 12);
|
||||||
|
// clamp result to 0 .. 1
|
||||||
|
if result > 1.0 {
|
||||||
|
result = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if result < 0.0 {
|
||||||
|
result = 0.0
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue