1#![no_std]
2
3pub extern crate rp2040_hal as hal;
4
5#[cfg(feature = "rt")]
6extern crate cortex_m_rt;
7
8#[cfg(feature = "rt")]
9pub use hal::entry;
10
11#[cfg(feature = "boot2")]
17#[link_section = ".boot2"]
18#[no_mangle]
19#[used]
20pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
21
22use display_interface_spi::SPIInterface;
23use embedded_graphics::{
24 draw_target::DrawTarget,
25 pixelcolor::{Rgb565, RgbColor},
26};
27use embedded_hal_0_2::{
28 adc::{Channel, OneShot},
29 blocking::delay::DelayUs,
30 digital::v2::{InputPin, OutputPin},
31 spi::MODE_0,
32};
33use fugit::RateExtU32;
34pub use hal::pac;
35use hal::{
36 adc::Adc,
37 gpio::{
38 bank0::{
39 Gpio0, Gpio1, Gpio12, Gpio13, Gpio14, Gpio15, Gpio16, Gpio17, Gpio2, Gpio22, Gpio23,
40 Gpio24, Gpio25, Gpio26, Gpio27, Gpio28, Gpio29, Gpio3, Gpio4, Gpio5, Gpio6, Gpio7,
41 },
42 FunctionNull, FunctionPwm, FunctionSioInput, FunctionSioOutput, Pin, PullNone, PullUp,
43 },
44 pac::{RESETS, SPI0},
45 sio::SioGpioBank0,
46 spi::{Enabled, Spi},
47};
48use st7789::ST7789;
49
50pub mod all_pins {
51 hal::bsp_pins!(
52 Gpio0 { name: gpio0 },
53 Gpio1 { name: gpio1 },
54 Gpio2 { name: gpio2 },
55 Gpio3 { name: gpio3 },
56 Gpio4 { name: gpio4 },
57 Gpio5 { name: gpio5 },
58 Gpio6 { name: gpio6 },
59 Gpio7 { name: gpio7 },
60 Gpio8 {
61 name: motor1_neg,
62 aliases: { FunctionPwm, PullNone: Motor1Neg }
63 },
64 Gpio9 {
65 name: motor1_pos,
66 aliases: { FunctionPwm, PullNone: Motor1Pos }
67 },
68 Gpio10 {
69 name: motor2_neg,
70 aliases: { FunctionPwm, PullNone: Motor2Neg }
71 },
72 Gpio11 {
73 name: motor2_pos,
74 aliases: { FunctionPwm, PullNone: Motor2Pos }
75 },
76 Gpio12 { name: switch_a },
77 Gpio13 { name: switch_b },
78 Gpio14 { name: switch_x },
79 Gpio15 { name: switch_y },
80 Gpio16 {
81 name: spi_miso,
82 aliases: { FunctionSpi, PullNone: Miso }
83 },
84 Gpio17 {
85 name: lcd_cs,
86 aliases: { FunctionSpi, PullNone: LcdCs }
87 },
88 Gpio18 {
89 name: spi_sclk,
90 aliases: { FunctionSpi, PullNone: Sclk }
91 },
92 Gpio19 {
93 name: spi_mosi,
94 aliases: { FunctionSpi, PullNone: Mosi }
95 },
96 Gpio20 {
97 name: i2c_sda,
98 aliases: { FunctionI2C, PullUp: Sda }
99 },
100 Gpio21 {
101 name: i2c_scl,
102 aliases: { FunctionI2C, PullUp: Scl }
103 },
104 Gpio22 { name: i2c_int },
105 Gpio23 { name: b_power_save },
106 Gpio24 { name: vbus_detect },
107 Gpio25 { name: led },
108 Gpio26 { name: adc0 },
109 Gpio27 { name: adc1 },
110 Gpio28 { name: adc2 },
111 Gpio29 {
112 name: voltage_monitor
113 },
114 );
115}
116
117pub struct Pins {
119 pub gpio0: Pin<Gpio0, FunctionNull, PullNone>,
120 pub gpio1: Pin<Gpio1, FunctionNull, PullNone>,
121 pub gpio2: Pin<Gpio2, FunctionNull, PullNone>,
122 pub gpio3: Pin<Gpio3, FunctionNull, PullNone>,
123 pub gpio4: Pin<Gpio4, FunctionNull, PullNone>,
124 pub gpio5: Pin<Gpio5, FunctionNull, PullNone>,
125 pub gpio6: Pin<Gpio6, FunctionNull, PullNone>,
126 pub gpio7: Pin<Gpio7, FunctionNull, PullNone>,
127 pub i2c_sda: all_pins::Sda,
128 pub i2c_scl: all_pins::Scl,
129 pub i2c_int: Pin<Gpio22, FunctionSioInput, PullUp>,
130 pub b_power_save: Pin<Gpio23, FunctionNull, PullNone>,
131 pub vbus_detect: Pin<Gpio24, FunctionNull, PullNone>,
132 pub led: Pin<Gpio25, FunctionNull, PullNone>,
133 pub adc0: Pin<Gpio26, FunctionNull, PullNone>,
134 pub adc1: Pin<Gpio27, FunctionNull, PullNone>,
135 pub adc2: Pin<Gpio28, FunctionNull, PullNone>,
136 pub voltage_monitor: Pin<Gpio29, FunctionNull, PullNone>,
137}
138
139pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
140pub enum Button {
141 A,
142 B,
143 X,
144 Y,
145}
146
147pub enum Motor {
148 _1,
149 _2,
150}
151
152pub enum MotorAction {
153 Forward(f32),
154 Reverse(f32),
155 Stop,
156}
157
158pub type Screen = ST7789<
159 SPIInterface<
160 Spi<Enabled, SPI0, (all_pins::Mosi, all_pins::Sclk), 8>,
161 Pin<Gpio16, FunctionSioOutput, PullNone>,
162 Pin<Gpio17, FunctionSioOutput, PullNone>,
163 >,
164 DummyPin,
165>;
166
167pub struct PicoExplorer {
168 pub a: Pin<Gpio12, FunctionSioInput, PullUp>,
169 pub b: Pin<Gpio13, FunctionSioInput, PullUp>,
170 pub x: Pin<Gpio14, FunctionSioInput, PullUp>,
171 pub y: Pin<Gpio15, FunctionSioInput, PullUp>,
172 adc: Adc,
173 pub screen: Screen,
174}
175
176pub struct DummyPin;
177
178impl OutputPin for DummyPin {
179 type Error = ();
180 fn set_high(&mut self) -> Result<(), Self::Error> {
181 Ok(())
182 }
183 fn set_low(&mut self) -> Result<(), Self::Error> {
184 Ok(())
185 }
186}
187
188impl PicoExplorer {
189 pub fn new(
190 io: pac::IO_BANK0,
191 pads: pac::PADS_BANK0,
192 sio: SioGpioBank0,
193 spi0: SPI0,
194 adc: Adc,
195 resets: &mut RESETS,
196 delay: &mut impl DelayUs<u32>,
197 ) -> (Self, Pins) {
198 let internal_pins = all_pins::Pins::new(io, pads, sio, resets);
199
200 let a = internal_pins.switch_a.into_pull_up_input();
201 let b = internal_pins.switch_b.into_pull_up_input();
202 let x = internal_pins.switch_x.into_pull_up_input();
203 let y = internal_pins.switch_y.into_pull_up_input();
204
205 internal_pins.motor1_pos.into_function::<FunctionPwm>();
206 internal_pins.motor1_neg.into_function::<FunctionPwm>();
207 internal_pins.motor2_pos.into_function::<FunctionPwm>();
208 internal_pins.motor2_neg.into_function::<FunctionPwm>();
209
210 let dc = internal_pins.spi_miso.reconfigure();
211 let cs = internal_pins.lcd_cs.reconfigure();
212 let spi_sclk = internal_pins.spi_sclk.reconfigure();
213 let spi_mosi = internal_pins.spi_mosi.reconfigure();
214
215 let spi_screen =
216 Spi::new(spi0, (spi_mosi, spi_sclk)).init(resets, 125u32.MHz(), 16u32.MHz(), MODE_0);
217
218 let spii_screen = SPIInterface::new(spi_screen, dc, cs);
219
220 let mut screen = ST7789::new(spii_screen, DummyPin, 240, 240);
221
222 screen.init(delay).unwrap();
223 screen
224 .set_orientation(st7789::Orientation::Portrait)
225 .unwrap();
226 screen.clear(Rgb565::BLACK).unwrap();
227
228 (
229 PicoExplorer {
230 a,
231 b,
232 x,
233 y,
234 adc,
235 screen,
236 },
237 Pins {
238 gpio0: internal_pins.gpio0.reconfigure(),
239 gpio1: internal_pins.gpio1.reconfigure(),
240 gpio2: internal_pins.gpio2.reconfigure(),
241 gpio3: internal_pins.gpio3.reconfigure(),
242 gpio4: internal_pins.gpio4.reconfigure(),
243 gpio5: internal_pins.gpio5.reconfigure(),
244 gpio6: internal_pins.gpio6.reconfigure(),
245 gpio7: internal_pins.gpio7.reconfigure(),
246 i2c_sda: internal_pins.i2c_sda.reconfigure(),
247 i2c_scl: internal_pins.i2c_scl.reconfigure(),
248 i2c_int: internal_pins.i2c_int.reconfigure(),
249 b_power_save: internal_pins.b_power_save.reconfigure(),
250 vbus_detect: internal_pins.vbus_detect.reconfigure(),
251 led: internal_pins.led.reconfigure(),
252 adc0: internal_pins.adc0.reconfigure(),
253 adc1: internal_pins.adc1.reconfigure(),
254 adc2: internal_pins.adc2.reconfigure(),
255 voltage_monitor: internal_pins.voltage_monitor.reconfigure(),
256 },
257 )
258 }
259
260 pub fn is_pressed(&self, button: Button) -> bool {
261 use Button::*;
262 match button {
263 A => self.a.is_low().unwrap(),
264 B => self.b.is_low().unwrap(),
265 X => self.x.is_low().unwrap(),
266 Y => self.y.is_low().unwrap(),
267 }
268 }
269
270 pub fn get_adc<Pin: Channel<Adc, ID = u8>>(&mut self, channel: &mut Pin) -> f32 {
271 let adc_value: u16 = self.adc.read(channel).unwrap();
273 let result: f32 = f32::from(adc_value) / f32::from(1u16 << 12);
274 result.clamp(0.0, 1.0)
275 }
276}