Pico explorer board support

This commit is contained in:
Hmvp 2021-07-07 12:45:09 +02:00 committed by 9names
parent bcfbd72ed1
commit ae8fe512bd
3 changed files with 391 additions and 88 deletions

View file

@ -11,9 +11,21 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
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"

View 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;
}
}

View file

@ -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;
hal::bsp_pins!( mod internal_pins {
Gpio0 { hal::bsp_pins!(
name: gpio0, Gpio0 { name: gpio0 },
aliases: { FunctionPwm: Audio0 } Gpio1 { name: gpio1 },
}, Gpio2 { name: gpio2 },
Gpio1 { Gpio3 { name: gpio3 },
name: gpio1, Gpio4 { name: gpio4 },
aliases: { FunctionPwm: Audio1 } Gpio5 { name: gpio5 },
}, Gpio6 { name: gpio6 },
Gpio2 { Gpio7 { name: gpio7 },
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
}
}