use core::cell::RefCell;
use embassy_rp::{
Peripherals,
adc::{Adc, Blocking as AdcBlocking, Channel as AdcChannel, Config as AdcConfig},
gpio::{Input, Level, Output, Pull},
i2c::{Blocking as I2cBlocking, Config as I2cConfig, I2c},
peripherals::I2C1,
pwm::{Config as PwmConfig, Pwm},
};
use embedded_hal::delay::DelayNs;
use embedded_hal_bus::i2c::RefCellDevice as I2cRefCellDevice;
use static_cell::StaticCell;
#[cfg(feature = "async")]
use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice as I2cAsyncDevice;
#[cfg(feature = "async")]
use embassy_rp::{
adc::{self, Async as AdcAsync},
bind_interrupts,
i2c::{self, Async as I2cAsync},
};
#[cfg(feature = "async")]
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex as AsyncMutex};
#[cfg(feature = "power-board")]
use embassy_rp::{
peripherals::SPI0,
spi::{Blocking as SpiBlocking, Config as SpiConfig, Spi},
};
#[cfg(feature = "power-board")]
use embedded_hal_bus::spi::RefCellDevice as SpiRefCellDevice;
#[cfg(feature = "async")]
use crate::Async;
use crate::Uferris;
use crate::components::ldr::OneShot;
#[cfg(feature = "async")]
use crate::components::ldr::OneShotAsync;
#[cfg(feature = "async")]
bind_interrupts!(
struct Irqs {
I2C1_IRQ => i2c::InterruptHandler<I2C1>;
ADC_IRQ_FIFO => adc::InterruptHandler;
}
);
const SYS_CLOCK_HZ: u32 = 125_000_000;
const I2C_FREQ_HZ: u32 = 100_000;
#[cfg(feature = "power-board")]
const SPI_FREQ_HZ: u32 = 400_000;
static I2C_BUS: StaticCell<RefCell<Rp2040I2c>> = StaticCell::new();
#[cfg(feature = "power-board")]
static SPI_BUS: StaticCell<RefCell<Rp2040Spi>> = StaticCell::new();
#[cfg(feature = "async")]
static ASYNC_I2C_BUS: StaticCell<AsyncMutex<NoopRawMutex, Rp2040AsyncI2c>> = StaticCell::new();
type Rp2040I2c = I2c<'static, I2C1, I2cBlocking>;
type SharedI2c = I2cRefCellDevice<'static, Rp2040I2c>;
#[cfg(feature = "async")]
type Rp2040AsyncI2c = I2c<'static, I2C1, I2cAsync>;
#[cfg(feature = "async")]
type SharedAsyncI2c = I2cAsyncDevice<'static, NoopRawMutex, Rp2040AsyncI2c>;
type LedPin = Output<'static>;
type ButtonPin = Input<'static>;
pub struct LdrAdc {
adc: Adc<'static, AdcBlocking>,
channel: AdcChannel<'static>,
}
impl OneShot for LdrAdc {
fn read_raw(&mut self) -> u16 {
self.adc.blocking_read(&mut self.channel).unwrap_or(0)
}
}
#[cfg(feature = "async")]
pub struct LdrAdcAsync {
adc: Adc<'static, AdcAsync>,
channel: AdcChannel<'static>,
}
#[cfg(feature = "async")]
impl OneShotAsync for LdrAdcAsync {
async fn read_raw(&mut self) -> u16 {
self.adc.read(&mut self.channel).await.unwrap_or(0)
}
}
pub type Rp2040BuzzerChannel = Pwm<'static>;
#[cfg(feature = "power-board")]
type Rp2040Spi = Spi<'static, SPI0, SpiBlocking>;
#[cfg(feature = "power-board")]
type SdCsPin = Output<'static>;
#[cfg(feature = "power-board")]
type SdBlockDevice =
embedded_sdmmc::SdCard<SpiRefCellDevice<'static, Rp2040Spi, SdCsPin, CycleDelay>, CycleDelay>;
#[cfg(not(feature = "power-board"))]
pub type UferrisRp2040 = Uferris<
LedPin, ButtonPin, Rp2040BuzzerChannel, SharedI2c, LdrAdc, (),
>;
#[cfg(feature = "power-board")]
pub type UferrisRp2040 = Uferris<
LedPin, ButtonPin, Rp2040BuzzerChannel, SharedI2c, LdrAdc, SdBlockDevice, >;
#[cfg(all(feature = "async", not(feature = "power-board")))]
pub type UferrisRp2040Async = Uferris<
LedPin, ButtonPin, Rp2040BuzzerChannel, SharedAsyncI2c, LdrAdcAsync, (),
Async,
>;
#[cfg(all(feature = "async", feature = "power-board"))]
pub type UferrisRp2040Async = Uferris<
LedPin, ButtonPin, Rp2040BuzzerChannel, SharedAsyncI2c, LdrAdcAsync, SdBlockDevice, Async,
>;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct CycleDelay;
impl DelayNs for CycleDelay {
fn delay_ns(&mut self, ns: u32) {
let cycles = u64::from(ns) * u64::from(SYS_CLOCK_HZ) / 1_000_000_000;
cortex_m::asm::delay(cycles as u32);
}
}
pub const fn delay() -> CycleDelay {
CycleDelay
}
pub fn uferris_init(peripherals: Peripherals) -> UferrisRp2040 {
let adc = Adc::new_blocking(peripherals.ADC, AdcConfig::default());
let ldr_channel = AdcChannel::new_pin(peripherals.PIN_26, Pull::None);
let ldr_driver = LdrAdc {
adc,
channel: ldr_channel,
};
let mut i2c_config = I2cConfig::default();
i2c_config.frequency = I2C_FREQ_HZ;
let i2c = I2c::new_blocking(
peripherals.I2C1,
peripherals.PIN_7,
peripherals.PIN_6,
i2c_config,
);
let i2c_bus_ref = I2C_BUS.init(RefCell::new(i2c));
let expander_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let rtc_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let raw_i2c = I2cRefCellDevice::new(i2c_bus_ref);
#[cfg(feature = "power-board")]
let ina_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let led = Output::new(peripherals.PIN_27, Level::Low);
let button = Input::new(peripherals.PIN_29, Pull::None);
let mut pwm_config = PwmConfig::default();
pwm_config.top = 16384;
pwm_config.divider = pwm_config.divider * 45 / 16;
let buzzer_channel = Pwm::new_output_a(peripherals.PWM_SLICE6, peripherals.PIN_28, pwm_config);
#[cfg(feature = "power-board")]
let vol_mgr = {
let mut spi_config = SpiConfig::default();
spi_config.frequency = SPI_FREQ_HZ;
let spi = Spi::new_blocking(
peripherals.SPI0,
peripherals.PIN_2,
peripherals.PIN_3,
peripherals.PIN_4,
spi_config,
);
let spi_bus_ref = SPI_BUS.init(RefCell::new(spi));
let sd_cs = Output::new(peripherals.PIN_1, Level::High);
let sd_device = SpiRefCellDevice::new(spi_bus_ref, sd_cs, delay()).unwrap();
let sd_card = embedded_sdmmc::SdCard::new(sd_device, delay());
Some(embedded_sdmmc::VolumeManager::new(
sd_card,
crate::DummyTimeSource::default(),
))
};
Uferris::new(
led,
button,
buzzer_channel,
ldr_driver,
expander_i2c,
rtc_i2c,
raw_i2c,
#[cfg(feature = "power-board")]
vol_mgr,
#[cfg(feature = "power-board")]
ina_i2c,
)
.unwrap()
}
#[cfg(feature = "async")]
pub async fn uferris_init_async(peripherals: Peripherals) -> UferrisRp2040Async {
let adc = Adc::new(peripherals.ADC, Irqs, AdcConfig::default());
let ldr_channel = AdcChannel::new_pin(peripherals.PIN_26, Pull::None);
let ldr_driver = LdrAdcAsync {
adc,
channel: ldr_channel,
};
let mut i2c_config = I2cConfig::default();
i2c_config.frequency = I2C_FREQ_HZ;
let i2c = I2c::new_async(
peripherals.I2C1,
peripherals.PIN_7,
peripherals.PIN_6,
Irqs,
i2c_config,
);
let i2c_bus_ref = ASYNC_I2C_BUS.init(AsyncMutex::new(i2c));
let expander_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let rtc_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let raw_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let led = Output::new(peripherals.PIN_27, Level::Low);
let button = Input::new(peripherals.PIN_29, Pull::None);
let mut pwm_config = PwmConfig::default();
pwm_config.top = 16384;
pwm_config.divider = pwm_config.divider * 45 / 16;
let buzzer_channel = Pwm::new_output_a(peripherals.PWM_SLICE6, peripherals.PIN_28, pwm_config);
Uferris::new_async(
led,
button,
buzzer_channel,
ldr_driver,
expander_i2c,
rtc_i2c,
raw_i2c,
)
.await
.unwrap()
}