initial commit
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
|
||||
use ufmt::{uDisplay, uWrite, uwrite, Formatter};
|
||||
|
||||
pub struct DumbError(String);
|
||||
|
||||
impl<T: ToString + 'static> From<T> for DumbError {
|
||||
fn from(error: T) -> Self {
|
||||
Self(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl uDisplay for DumbError {
|
||||
fn fmt<W>(&self, fmt: &mut Formatter<'_, W>) -> core::result::Result<(), W::Error>
|
||||
where
|
||||
W: uWrite + ?Sized,
|
||||
{
|
||||
uwrite!(fmt, "{}", self.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = core::result::Result<T, DumbError>;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(_: core::alloc::Layout) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use super::pac;
|
||||
pub use super::pac::CLKGEN;
|
||||
use super::time::Hertz;
|
||||
|
||||
pub const CLKGEN_FREQ_MAX_HZ: Hertz = Hertz(48_000_000);
|
||||
pub const CLKGEN_CLKKEY: u32 = 71;
|
||||
|
||||
#[allow(unused)]
|
||||
fn clk_cfg<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
cortex_m::interrupt::free(|_| {
|
||||
unsafe {
|
||||
(*pac::CLKGEN::ptr())
|
||||
.clkkey
|
||||
.write(|w| w.bits(CLKGEN_CLKKEY));
|
||||
}
|
||||
let r = f();
|
||||
unsafe {
|
||||
(*pac::CLKGEN::ptr()).clkkey.write(|w| w.bits(0x00));
|
||||
}
|
||||
r
|
||||
})
|
||||
}
|
||||
|
||||
pub struct ClockCtrl<'a> {
|
||||
clkgen: &'a mut CLKGEN,
|
||||
}
|
||||
|
||||
impl<'a> ClockCtrl<'a> {
|
||||
pub fn new(clkgen: &'a mut CLKGEN) -> ClockCtrl {
|
||||
ClockCtrl { clkgen }
|
||||
}
|
||||
pub fn enable_xt(&mut self) {
|
||||
self.clkgen.octrl.modify(|_, w| w.stopxt().en());
|
||||
}
|
||||
pub fn disable_xt(&mut self) {
|
||||
self.clkgen.octrl.modify(|_, w| w.stopxt().stop());
|
||||
}
|
||||
pub fn rtc_use_xt(&mut self) {
|
||||
self.clkgen.octrl.write(|w| w.stopxt().en().osel().rtc_xt());
|
||||
}
|
||||
pub fn rtc_use_lfrc(&mut self) {
|
||||
self.clkgen.octrl.modify(|_, w| w.osel().rtc_lfrc());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
use cortex_m::peripheral::syst::SystClkSource;
|
||||
use cortex_m::peripheral::SYST;
|
||||
|
||||
pub use flash::FlashDelay;
|
||||
|
||||
use super::clock;
|
||||
use super::ehal::blocking::delay::{DelayMs, DelayUs};
|
||||
use super::halc;
|
||||
use super::pac;
|
||||
use super::pac::CLKGEN;
|
||||
use super::time::Hertz;
|
||||
|
||||
pub struct Delay {
|
||||
sysclock: Hertz,
|
||||
syst: SYST,
|
||||
}
|
||||
|
||||
pub fn sysclock(clkgen: &pac::clkgen::RegisterBlock) -> Hertz {
|
||||
match clkgen.cctrl.read().coresel().variant() {
|
||||
pac::clkgen::cctrl::CORESEL_A::HFRC => clock::CLKGEN_FREQ_MAX_HZ,
|
||||
pac::clkgen::cctrl::CORESEL_A::HFRC_DIV2 => Hertz(clock::CLKGEN_FREQ_MAX_HZ.0 / 2),
|
||||
}
|
||||
}
|
||||
|
||||
impl Delay {
|
||||
pub fn new(mut syst: SYST, clkgen: &mut CLKGEN) -> Self {
|
||||
syst.set_clock_source(SystClkSource::Core);
|
||||
let sysclock = sysclock(clkgen);
|
||||
Delay { syst, sysclock }
|
||||
}
|
||||
|
||||
pub fn free(self) -> SYST {
|
||||
self.syst
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u32> for Delay {
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
self.delay_us(ms * 1_000);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u16> for Delay {
|
||||
fn delay_ms(&mut self, ms: u16) {
|
||||
self.delay_ms(ms as u32);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u8> for Delay {
|
||||
fn delay_ms(&mut self, ms: u8) {
|
||||
self.delay_ms(ms as u32);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u32> for Delay {
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
const MAX_RVR: u32 = 0x00FF_FFFF;
|
||||
let mut total_rvr = us * (self.sysclock.0 / 1_000_000);
|
||||
while total_rvr != 0 {
|
||||
let current_rvr = if total_rvr <= MAX_RVR {
|
||||
total_rvr
|
||||
} else {
|
||||
MAX_RVR
|
||||
};
|
||||
self.syst.set_reload(current_rvr);
|
||||
self.syst.clear_current();
|
||||
self.syst.enable_counter();
|
||||
total_rvr -= current_rvr;
|
||||
while !self.syst.has_wrapped() {}
|
||||
self.syst.disable_counter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u16> for Delay {
|
||||
fn delay_us(&mut self, us: u16) {
|
||||
self.delay_us(us as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u8> for Delay {
|
||||
fn delay_us(&mut self, us: u8) {
|
||||
self.delay_us(us as u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod flash {
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FlashDelay;
|
||||
|
||||
impl FlashDelay {
|
||||
pub fn new() -> FlashDelay {
|
||||
FlashDelay
|
||||
}
|
||||
|
||||
pub fn delay_us(us: u32) {
|
||||
let clkgen = unsafe { &*CLKGEN::ptr() };
|
||||
let sysclock = sysclock(clkgen);
|
||||
let cycles = us * (sysclock.0 / 3_000_000);
|
||||
unsafe {
|
||||
halc::am_hal_flash_delay(cycles);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delay_cycles(cycles: u32) {
|
||||
unsafe {
|
||||
halc::am_hal_flash_delay(cycles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u32> for FlashDelay {
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
let clkgen = unsafe { &*CLKGEN::ptr() };
|
||||
let sysclock = sysclock(clkgen);
|
||||
let cycles = us * (sysclock.0 / 3_000_000);
|
||||
unsafe {
|
||||
halc::am_hal_flash_delay(cycles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u16> for FlashDelay {
|
||||
fn delay_us(&mut self, us: u16) {
|
||||
self.delay_us(us as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u8> for FlashDelay {
|
||||
fn delay_us(&mut self, us: u8) {
|
||||
self.delay_us(us as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DelayMs<T> for FlashDelay
|
||||
where
|
||||
T: Into<u32>,
|
||||
{
|
||||
fn delay_ms(&mut self, us: T) {
|
||||
let us = us.into();
|
||||
DelayUs::<u32>::delay_us(self, us * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use super::pac::GPIO;
|
||||
pub use super::pin::*;
|
||||
|
||||
pub struct Pins {
|
||||
_gpio: GPIO,
|
||||
pub d10: P14<{ Mode::Floating }>,
|
||||
pub tx0: P48<{ Mode::Floating }>,
|
||||
pub rx0: P49<{ Mode::Floating }>,
|
||||
pub d18: P26<{ Mode::Floating }>,
|
||||
}
|
||||
|
||||
impl Pins {
|
||||
pub fn new(gpio: GPIO) -> Pins {
|
||||
Pins {
|
||||
_gpio: gpio,
|
||||
d10: Pin::new(),
|
||||
d18: Pin::new(),
|
||||
tx0: Pin::new(),
|
||||
rx0: Pin::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
pub use artemis_thing_plus::Pins;
|
||||
|
||||
use super::ehal;
|
||||
use super::pac;
|
||||
|
||||
const PAD_KEY: u32 = 0x73;
|
||||
|
||||
pub fn gpio_cfg<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
cortex_m::interrupt::free(|_| {
|
||||
unsafe {
|
||||
(*pac::GPIO::ptr()).padkey.write(|w| w.bits(PAD_KEY));
|
||||
}
|
||||
let r = f();
|
||||
unsafe {
|
||||
(*pac::GPIO::ptr()).padkey.write(|w| w.bits(0x00));
|
||||
}
|
||||
r
|
||||
})
|
||||
}
|
||||
|
||||
mod artemis_thing_plus;
|
||||
pub mod pin;
|
||||
@@ -0,0 +1,204 @@
|
||||
use paste::paste;
|
||||
|
||||
use super::ehal::digital::v2::{OutputPin, ToggleableOutputPin};
|
||||
use super::gpio_cfg;
|
||||
use super::pac;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum DriveStrength {
|
||||
D2mA,
|
||||
D4mA,
|
||||
D8mA,
|
||||
D12mA,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum OutputMode {
|
||||
Disable = 0,
|
||||
PushPull,
|
||||
OpenDrain,
|
||||
TriState,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum InputMode {
|
||||
NoneOrAuto = 0,
|
||||
Enable = 1,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum Mode {
|
||||
Floating,
|
||||
Input,
|
||||
Output,
|
||||
AF0,
|
||||
}
|
||||
|
||||
pub struct Pin<const PINNUM: usize, const MODE: Mode> {}
|
||||
|
||||
pub trait PinCfg {
|
||||
unsafe fn padfncsel(&mut self, f: u8);
|
||||
unsafe fn padinpen(&mut self, on: bool);
|
||||
unsafe fn padpull(&mut self, on: bool);
|
||||
unsafe fn padstrng(&mut self, high: bool);
|
||||
|
||||
unsafe fn outcfg(&mut self, c: u8);
|
||||
}
|
||||
|
||||
macro_rules! pin {
|
||||
($id:literal, $padreg:ident, $cfgreg: ident) => {
|
||||
paste! {
|
||||
pub type [<P $id>]<const MODE: Mode> = Pin<$id, MODE>;
|
||||
|
||||
impl<const MODE: Mode>PinCfg for Pin<$id, MODE> {
|
||||
unsafe fn padpull(&mut self, on: bool) {
|
||||
// XXX: Pad 20 differs in behavior to the rest of the pads, see p. 420.
|
||||
|
||||
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
|
||||
.write(|p| p.[< pad $id pull >]().bit(on))
|
||||
}
|
||||
|
||||
unsafe fn padinpen(&mut self, on: bool) {
|
||||
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
|
||||
.write(|p| p.[< pad $id inpen >]().bit(on))
|
||||
}
|
||||
|
||||
unsafe fn padstrng(&mut self, high: bool) {
|
||||
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
|
||||
.write(|p| p.[< pad $id strng >]().bit(high))
|
||||
}
|
||||
|
||||
unsafe fn padfncsel(&mut self, f: u8) {
|
||||
(*pac::GPIO::ptr()).[<padreg $padreg:lower>]
|
||||
.write(|p| p.[< pad $id fncsel >]().bits(f))
|
||||
}
|
||||
|
||||
unsafe fn outcfg(&mut self, f: u8) {
|
||||
(*pac::GPIO::ptr()).[<cfg $cfgreg:lower>]
|
||||
.write(|p| p.[< gpio $id outcfg >]().bits(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<const P: usize> Pin<P, { Mode::Floating }> {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const P: usize, const M: Mode> Pin<P, M>
|
||||
where
|
||||
Pin<P, M>: PinCfg,
|
||||
{
|
||||
pub fn with_mode() -> Self {
|
||||
Self {}.into_mode::<M>()
|
||||
}
|
||||
|
||||
pub fn into_mode<const NEWM: Mode>(mut self) -> Pin<P, NEWM> {
|
||||
gpio_cfg(|| unsafe {
|
||||
self.padfncsel(3);
|
||||
match NEWM {
|
||||
Mode::Floating | Mode::Input => self.padinpen(true),
|
||||
Mode::Output => {
|
||||
self.padinpen(false);
|
||||
self.outcfg(1); // push-pull
|
||||
}
|
||||
Mode::AF0 => {
|
||||
self.padfncsel(0);
|
||||
self.padinpen(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Pin {}
|
||||
}
|
||||
pub fn pin_num(&self) -> usize {
|
||||
P
|
||||
}
|
||||
pub fn into_push_pull_output(self) -> Pin<P, { Mode::Output }> {
|
||||
self.into_mode()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const P: usize> Pin<P, { Mode::Output }>
|
||||
where
|
||||
Pin<P, { Mode::Output }>: PinCfg,
|
||||
{
|
||||
pub fn internal_pull_up(&mut self, on: bool) {
|
||||
gpio_cfg(|| unsafe { self.padpull(on) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<const P: usize> Pin<P, { Mode::AF0 }>
|
||||
where
|
||||
Pin<P, { Mode::AF0 }>: PinCfg,
|
||||
{
|
||||
pub fn set_drive_strength(&mut self, d: DriveStrength) {
|
||||
gpio_cfg(|| unsafe {
|
||||
match d {
|
||||
DriveStrength::D2mA => self.padstrng(false),
|
||||
DriveStrength::D4mA => self.padstrng(true),
|
||||
_ => (), // XXX: is configured in altpadcfg
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<const P: usize> OutputPin for Pin<P, { Mode::Output }>
|
||||
where
|
||||
Pin<P, { Mode::Output }>: PinCfg,
|
||||
{
|
||||
type Error = !;
|
||||
|
||||
fn set_low(&mut self) -> Result<(), !> {
|
||||
let mask: u32 = 0b1u32 << (P % 32);
|
||||
let reg = unsafe {
|
||||
match P {
|
||||
0..=31 => (*pac::GPIO::ptr()).wtca.as_ptr(),
|
||||
_ => (*pac::GPIO::ptr()).wtcb.as_ptr(),
|
||||
}
|
||||
};
|
||||
gpio_cfg(|| unsafe { reg.write(mask) });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), !> {
|
||||
let mask: u32 = 0b1u32 << (P % 32);
|
||||
let reg = unsafe {
|
||||
match P {
|
||||
0..=31 => (*pac::GPIO::ptr()).wtsa.as_ptr(),
|
||||
_ => (*pac::GPIO::ptr()).wtsb.as_ptr(),
|
||||
}
|
||||
};
|
||||
gpio_cfg(|| unsafe { reg.write(mask) });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const P: usize> ToggleableOutputPin for Pin<P, { Mode::Output }>
|
||||
where
|
||||
Pin<P, { Mode::Output }>: PinCfg,
|
||||
{
|
||||
type Error = !;
|
||||
|
||||
fn toggle(&mut self) -> Result<(), !> {
|
||||
let mask: u32 = 0b1u32 << (P % 32);
|
||||
let reg = unsafe {
|
||||
match P {
|
||||
0..=31 => (*pac::GPIO::ptr()).wta.as_ptr(),
|
||||
_ => (*pac::GPIO::ptr()).wtb.as_ptr(),
|
||||
}
|
||||
};
|
||||
gpio_cfg(|| unsafe {
|
||||
*reg ^= mask;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pin!(14, D, B);
|
||||
pin!(26, G, D);
|
||||
pin!(48, M, G);
|
||||
pin!(49, M, G);
|
||||
@@ -0,0 +1,18 @@
|
||||
pub extern crate ambiq_apollo3_pac2 as pac;
|
||||
pub extern crate ambiq_hal_sys as halc;
|
||||
pub extern crate embedded_hal as ehal;
|
||||
|
||||
pub mod clock;
|
||||
pub mod delay;
|
||||
pub mod gpio;
|
||||
pub mod rtc;
|
||||
pub mod time;
|
||||
pub mod uart;
|
||||
pub mod watchdog;
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::ehal::digital::v2::{InputPin, OutputPin, ToggleableOutputPin};
|
||||
pub use super::ehal::prelude::*;
|
||||
pub use super::halc;
|
||||
pub use super::halc::c_types::*;
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
use chrono::{Datelike, Timelike};
|
||||
use rtcc::DateTimeAccess;
|
||||
|
||||
use super::clock::ClockCtrl;
|
||||
use super::pac;
|
||||
use super::pac::rtc::rtcctl::RPT_A;
|
||||
use super::pac::{CLKGEN, RTC};
|
||||
|
||||
pub struct Rtc {
|
||||
rtc: RTC,
|
||||
}
|
||||
|
||||
fn bcd_to_dec(bcd: u8) -> u8 {
|
||||
(((bcd & 0xf0) >> 4) * 10) + (bcd & 0x0f)
|
||||
}
|
||||
|
||||
fn dec_to_bcd(dec: u8) -> u8 {
|
||||
((dec / 10) << 4) | (dec % 10)
|
||||
}
|
||||
|
||||
impl Rtc {
|
||||
pub fn new(rtc: RTC, clkgen: &mut CLKGEN) -> Rtc {
|
||||
let mut clk = ClockCtrl::new(clkgen);
|
||||
rtc.rtcctl.reset();
|
||||
rtc.almup.reset();
|
||||
rtc.almlow.reset();
|
||||
rtc.inten.write(|w| w.alm().clear_bit());
|
||||
rtc.intclr.write(|w| w.alm().set_bit());
|
||||
|
||||
clk.rtc_use_xt();
|
||||
|
||||
rtc.rtcctl.modify(|_, w| w.hr1224()._24hr());
|
||||
|
||||
Rtc { rtc }
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
self.rtc.rtcctl.modify(|_, w| w.rstop().run());
|
||||
}
|
||||
|
||||
pub fn disable(&mut self) {
|
||||
self.rtc.rtcctl.modify(|_, w| w.rstop().stop());
|
||||
}
|
||||
|
||||
pub fn set(&self, dt: &chrono::NaiveDateTime) {
|
||||
let date = dt.date();
|
||||
let time = dt.time();
|
||||
|
||||
let year = date.year();
|
||||
let yr = year % 100;
|
||||
|
||||
self.rtc.rtcctl.modify(|_, w| w.wrtc().en());
|
||||
|
||||
self.rtc.ctrlow.write(|w| unsafe {
|
||||
w.ctrhr()
|
||||
.bits(dec_to_bcd(time.hour() as u8))
|
||||
.ctrmin()
|
||||
.bits(dec_to_bcd(time.minute() as u8))
|
||||
.ctrsec()
|
||||
.bits(dec_to_bcd(time.second() as u8))
|
||||
.ctr100()
|
||||
.bits(dec_to_bcd((time.nanosecond() / 1_000_000 * 100) as u8))
|
||||
});
|
||||
|
||||
self.rtc.ctrup.write(|w| unsafe {
|
||||
w.ceb()
|
||||
.dis() // TODO: support other centuries
|
||||
.ctryr()
|
||||
.bits(dec_to_bcd(yr as u8))
|
||||
.ctrmo()
|
||||
.bits(dec_to_bcd(date.month() as u8))
|
||||
.ctrdate()
|
||||
.bits(dec_to_bcd(date.day() as u8))
|
||||
.ctrwkdy()
|
||||
.bits(date.weekday() as u8)
|
||||
});
|
||||
|
||||
self.rtc.rtcctl.modify(|_, w| w.wrtc().dis());
|
||||
}
|
||||
|
||||
pub fn now(&self) -> chrono::NaiveDateTime {
|
||||
let (upper, lower) = loop {
|
||||
let lower = self.rtc.ctrlow.read();
|
||||
let no_err = self.rtc.ctrup.read().cterr().is_noerr();
|
||||
let upper = self.rtc.ctrup.read();
|
||||
if no_err {
|
||||
break (upper, lower);
|
||||
}
|
||||
};
|
||||
|
||||
let yr = bcd_to_dec(upper.ctryr().bits()) as i32;
|
||||
const CE: i32 = 20;
|
||||
|
||||
chrono::NaiveDate::from_ymd(
|
||||
CE * 100 + yr,
|
||||
bcd_to_dec(upper.ctrmo().bits()).into(),
|
||||
bcd_to_dec(upper.ctrdate().bits()).into(),
|
||||
)
|
||||
.and_hms_milli(
|
||||
bcd_to_dec(lower.ctrhr().bits()).into(),
|
||||
bcd_to_dec(lower.ctrmin().bits()).into(),
|
||||
bcd_to_dec(lower.ctrsec().bits()).into(),
|
||||
u32::from(bcd_to_dec(lower.ctr100().bits())) * 10u32,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_alarm_repeat(&mut self, interval: AlarmRepeat) {
|
||||
self.rtc.almup.reset();
|
||||
self.rtc.almlow.reset();
|
||||
|
||||
self.rtc
|
||||
.rtcctl
|
||||
.modify(|_, w| w.rpt().variant(interval.into()));
|
||||
|
||||
match interval {
|
||||
AlarmRepeat::DeciSecond => {
|
||||
self.rtc.almlow.write(|w| unsafe { w.alm100().bits(0xf0) });
|
||||
}
|
||||
AlarmRepeat::CentiSecond => {
|
||||
self.rtc.almlow.write(|w| unsafe { w.alm100().bits(0xff) });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_interrupts(&mut self) {
|
||||
self.rtc.intclr.write(|w| w.alm().set_bit());
|
||||
}
|
||||
|
||||
pub fn disable_alarm_repeat(&mut self) {
|
||||
self.rtc.rtcctl.modify(|_, w| w.rpt().dis());
|
||||
}
|
||||
|
||||
pub fn enable_alarm(&mut self) {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
self.clear_interrupts();
|
||||
self.rtc.inten.write(|w| w.alm().set_bit());
|
||||
unsafe {
|
||||
pac::NVIC::unmask(pac::Interrupt::RTC);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn disable_alarm(&mut self) {
|
||||
pac::NVIC::mask(pac::Interrupt::RTC);
|
||||
self.rtc.inten.write(|w| w.alm().clear_bit());
|
||||
self.clear_interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
impl DateTimeAccess for Rtc {
|
||||
type Error = !;
|
||||
|
||||
fn datetime(&mut self) -> Result<chrono::NaiveDateTime, !> {
|
||||
Ok(self.now())
|
||||
}
|
||||
|
||||
fn set_datetime(&mut self, datetime: &chrono::NaiveDateTime) -> Result<(), !> {
|
||||
self.set(datetime);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum AlarmRepeat {
|
||||
Disabled,
|
||||
Year,
|
||||
Month,
|
||||
Week,
|
||||
Day,
|
||||
Hour,
|
||||
Minute,
|
||||
Second,
|
||||
DeciSecond,
|
||||
CentiSecond,
|
||||
}
|
||||
|
||||
impl Into<RPT_A> for AlarmRepeat {
|
||||
fn into(self) -> RPT_A {
|
||||
use AlarmRepeat::*;
|
||||
use RPT_A::*;
|
||||
|
||||
match self {
|
||||
Disabled => DIS,
|
||||
Year => YEAR,
|
||||
Month => MONTH,
|
||||
Week => WEEK,
|
||||
Day => DAY,
|
||||
Hour => HR,
|
||||
Minute => MIN,
|
||||
Second => SEC,
|
||||
DeciSecond => SEC,
|
||||
CentiSecond => SEC,
|
||||
}
|
||||
}
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Bps(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Hertz(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct KiloHertz(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct MegaHertz(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Seconds(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Milliseconds(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Microseconds(pub u32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Nanoseconds(pub u32);
|
||||
|
||||
pub trait U32Ext {
|
||||
fn bps(self) -> Bps;
|
||||
fn hz(self) -> Hertz;
|
||||
fn khz(self) -> KiloHertz;
|
||||
fn mhz(self) -> MegaHertz;
|
||||
fn s(self) -> Seconds;
|
||||
fn ms(self) -> Milliseconds;
|
||||
fn us(self) -> Microseconds;
|
||||
fn ns(self) -> Nanoseconds;
|
||||
}
|
||||
|
||||
impl U32Ext for u32 {
|
||||
fn bps(self) -> Bps {
|
||||
Bps(self)
|
||||
}
|
||||
fn hz(self) -> Hertz {
|
||||
Hertz(self)
|
||||
}
|
||||
fn khz(self) -> KiloHertz {
|
||||
KiloHertz(self)
|
||||
}
|
||||
fn mhz(self) -> MegaHertz {
|
||||
MegaHertz(self)
|
||||
}
|
||||
fn s(self) -> Seconds {
|
||||
Seconds(self)
|
||||
}
|
||||
fn ms(self) -> Milliseconds {
|
||||
Milliseconds(self)
|
||||
}
|
||||
fn us(self) -> Microseconds {
|
||||
Microseconds(self)
|
||||
}
|
||||
fn ns(self) -> Nanoseconds {
|
||||
Nanoseconds(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KiloHertz> for Hertz {
|
||||
fn from(item: KiloHertz) -> Self {
|
||||
Hertz(item.0 * 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MegaHertz> for Hertz {
|
||||
fn from(item: MegaHertz) -> Self {
|
||||
Hertz(item.0 * 1_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MegaHertz> for KiloHertz {
|
||||
fn from(item: MegaHertz) -> Self {
|
||||
KiloHertz(item.0 * 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Hertz> for KiloHertz {
|
||||
fn from(item: Hertz) -> Self {
|
||||
KiloHertz(item.0 / 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Hertz> for MegaHertz {
|
||||
fn from(item: Hertz) -> Self {
|
||||
MegaHertz(item.0 / 1_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KiloHertz> for MegaHertz {
|
||||
fn from(item: KiloHertz) -> Self {
|
||||
MegaHertz(item.0 / 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for Milliseconds {
|
||||
fn from(item: Seconds) -> Self {
|
||||
Milliseconds(item.0 * 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for Microseconds {
|
||||
fn from(item: Seconds) -> Self {
|
||||
Microseconds(item.0 * 1_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for Nanoseconds {
|
||||
fn from(item: Seconds) -> Self {
|
||||
Nanoseconds(item.0 * 1_000_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Milliseconds> for Microseconds {
|
||||
fn from(item: Milliseconds) -> Self {
|
||||
Microseconds(item.0 * 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Microseconds> for Nanoseconds {
|
||||
fn from(item: Microseconds) -> Self {
|
||||
Nanoseconds(item.0 * 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Milliseconds> for Seconds {
|
||||
fn from(item: Milliseconds) -> Self {
|
||||
Seconds(item.0 / 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Microseconds> for Seconds {
|
||||
fn from(item: Microseconds) -> Self {
|
||||
Seconds(item.0 / 1_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Microseconds> for Milliseconds {
|
||||
fn from(item: Microseconds) -> Self {
|
||||
Milliseconds(item.0 / 1_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Milliseconds> for Nanoseconds {
|
||||
fn from(item: Milliseconds) -> Self {
|
||||
Nanoseconds(item.0 * 1_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Nanoseconds> for Hertz {
|
||||
fn from(item: Nanoseconds) -> Self {
|
||||
Hertz(1_000_000_000_u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Microseconds> for Hertz {
|
||||
fn from(item: Microseconds) -> Self {
|
||||
Hertz(1_000_000_u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Nanoseconds> for KiloHertz {
|
||||
fn from(item: Nanoseconds) -> Self {
|
||||
KiloHertz(1_000_000_u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Nanoseconds> for MegaHertz {
|
||||
fn from(item: Nanoseconds) -> Self {
|
||||
MegaHertz(1_000_u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Hertz> for Microseconds {
|
||||
fn from(item: Hertz) -> Self {
|
||||
Microseconds(1_000_000_u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Hertz> for Nanoseconds {
|
||||
fn from(item: Hertz) -> Self {
|
||||
Nanoseconds(1_000_000_000u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KiloHertz> for Nanoseconds {
|
||||
fn from(item: KiloHertz) -> Self {
|
||||
Nanoseconds(1_000_000u32 / item.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MegaHertz> for Nanoseconds {
|
||||
fn from(item: MegaHertz) -> Self {
|
||||
Nanoseconds(1_000u32 / item.0)
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
use core::ptr;
|
||||
|
||||
use super::ehal::serial::{Read, Write};
|
||||
use super::halc;
|
||||
use super::halc::c_types::*;
|
||||
use super::pac;
|
||||
use super::{gpio, gpio::pin::Mode};
|
||||
|
||||
pub struct Uart0 {
|
||||
ph_uart: *mut c_void,
|
||||
uart: pac::UART0,
|
||||
|
||||
tx: gpio::pin::P48<{ Mode::Floating }>,
|
||||
rx: gpio::pin::P49<{ Mode::Floating }>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for Uart0 {}
|
||||
|
||||
unsafe impl Send for Uart0 {}
|
||||
|
||||
impl Uart0 {
|
||||
pub fn new(
|
||||
uart: pac::UART0,
|
||||
tx: gpio::pin::P48<{ Mode::Floating }>,
|
||||
rx: gpio::pin::P49<{ Mode::Floating }>,
|
||||
) -> Uart0 {
|
||||
let mut ph_uart = ptr::null_mut();
|
||||
|
||||
let uart_config = halc::am_hal_uart_config_t {
|
||||
ui32BaudRate: 115200,
|
||||
ui32DataBits: halc::cAM_HAL_UART_DATA_BITS_8,
|
||||
ui32Parity: halc::cAM_HAL_UART_PARITY_NONE,
|
||||
ui32StopBits: halc::cAM_HAL_UART_ONE_STOP_BIT,
|
||||
ui32FlowControl: halc::cAM_HAL_UART_FLOW_CTRL_NONE,
|
||||
ui32FifoLevels: (halc::cAM_HAL_UART_TX_FIFO_1_2 | halc::cAM_HAL_UART_RX_FIFO_1_2),
|
||||
pui8TxBuffer: ptr::null_mut(),
|
||||
ui32TxBufferSize: 0,
|
||||
pui8RxBuffer: ptr::null_mut(),
|
||||
ui32RxBufferSize: 0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
halc::am_hal_uart_initialize(0, &mut ph_uart);
|
||||
halc::am_hal_uart_power_control(ph_uart, 0, false);
|
||||
halc::am_hal_uart_configure(ph_uart, &uart_config);
|
||||
halc::am_hal_gpio_pinconfig(tx.pin_num() as u32, halc::g_AM_BSP_GPIO_COM_UART_TX);
|
||||
halc::am_hal_gpio_pinconfig(rx.pin_num() as u32, halc::g_AM_BSP_GPIO_COM_UART_RX);
|
||||
}
|
||||
|
||||
Uart0 {
|
||||
ph_uart,
|
||||
uart,
|
||||
tx,
|
||||
rx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Uart0 {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
halc::am_hal_uart_power_control(self.ph_uart, 2, false);
|
||||
halc::am_hal_uart_deinitialize(self.ph_uart);
|
||||
halc::am_hal_gpio_pinconfig(self.tx.pin_num() as u32, halc::g_AM_HAL_GPIO_DISABLE);
|
||||
halc::am_hal_gpio_pinconfig(self.rx.pin_num() as u32, halc::g_AM_HAL_GPIO_DISABLE);
|
||||
self.ph_uart = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read<u8> for Uart0 {
|
||||
type Error = ();
|
||||
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
if self.uart.fr.read().rxfe().bit_is_set() {
|
||||
Err(nb::Error::WouldBlock)
|
||||
} else {
|
||||
let dr = self.uart.dr.read();
|
||||
if dr.oedata().is_err()
|
||||
|| dr.bedata().is_err()
|
||||
|| dr.pedata().is_err()
|
||||
|| dr.fedata().is_err()
|
||||
{
|
||||
Err(nb::Error::Other(()))
|
||||
} else {
|
||||
Ok(dr.data().bits())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write<u8> for Uart0 {
|
||||
type Error = !;
|
||||
|
||||
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
|
||||
if self.uart.fr.read().txff().bit_is_set() {
|
||||
Err(nb::Error::WouldBlock)
|
||||
} else {
|
||||
unsafe {
|
||||
self.uart.dr.write(|dr| dr.data().bits(byte));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||
if self.uart.fr.read().txbusy().bit_is_set() {
|
||||
Err(nb::Error::WouldBlock)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ufmt::uWrite for Uart0 {
|
||||
type Error = !;
|
||||
|
||||
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||
for b in s.as_bytes().iter() {
|
||||
nb::block!(self.write(*b))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
use super::ehal::watchdog;
|
||||
use super::pac::{wdt, WDT};
|
||||
|
||||
pub struct Watchdog {
|
||||
wdt: WDT,
|
||||
}
|
||||
|
||||
pub type Frequency = wdt::cfg::CLKSEL_A;
|
||||
|
||||
impl Watchdog {
|
||||
pub fn from(wdt: WDT, reset: bool, reset_count: u8, freq: Frequency) -> Watchdog {
|
||||
wdt.cfg.write(|w| unsafe {
|
||||
w.resen()
|
||||
.bit(reset)
|
||||
.resval()
|
||||
.bits(reset_count)
|
||||
.clksel()
|
||||
.variant(freq)
|
||||
});
|
||||
Watchdog { wdt }
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.wdt.cfg.modify(|_, w| w.wdten().set_bit());
|
||||
watchdog::Watchdog::feed(self);
|
||||
self.wdt.rstrt.read().bits();
|
||||
}
|
||||
|
||||
pub fn lock_and_start(&mut self) {
|
||||
self.wdt
|
||||
.lock
|
||||
.write(|w| w.lock().variant(wdt::lock::LOCK_A::KEYVALUE));
|
||||
}
|
||||
|
||||
pub fn halt(&mut self) {
|
||||
self.wdt.cfg.modify(|_, w| w.wdten().clear_bit());
|
||||
}
|
||||
}
|
||||
|
||||
impl watchdog::Watchdog for Watchdog {
|
||||
fn feed(&mut self) {
|
||||
self.wdt
|
||||
.rstrt
|
||||
.write(|w| w.rstrt().variant(wdt::rstrt::RSTRT_A::KEYVALUE));
|
||||
}
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(never_type)]
|
||||
#![feature(alloc_error_handler)]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use ufmt::{uwrite, uwriteln};
|
||||
|
||||
use error::Result;
|
||||
use hal::prelude::*;
|
||||
|
||||
mod error;
|
||||
mod hal;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: alloc_cortex_m::CortexMHeap = alloc_cortex_m::CortexMHeap::empty();
|
||||
|
||||
#[cortex_m_rt::pre_init]
|
||||
unsafe fn pre_init() {
|
||||
(*cortex_m::peripheral::SCB::PTR).vtor.write(0x10000);
|
||||
}
|
||||
|
||||
struct App<'a> {
|
||||
command: &'a str,
|
||||
func: fn(&mut State, &str) -> Result<()>,
|
||||
description: &'a str,
|
||||
}
|
||||
|
||||
static APPS: [App; 5] = [
|
||||
App {
|
||||
command: "help",
|
||||
func: help,
|
||||
description: "Help command",
|
||||
},
|
||||
App {
|
||||
command: "free",
|
||||
func: free,
|
||||
description: "Show memory allocation",
|
||||
},
|
||||
App {
|
||||
command: "reset",
|
||||
func: reset,
|
||||
description: "Soft reboot the device",
|
||||
},
|
||||
App {
|
||||
command: "time",
|
||||
func: time,
|
||||
description: "Perform clock operations, set accepts %d/%m/%Y %H:%M:%S",
|
||||
},
|
||||
App {
|
||||
command: "mandelbrot",
|
||||
func: mandelbrot,
|
||||
description: "Display a mandelbrot set",
|
||||
},
|
||||
];
|
||||
|
||||
fn help(state: &mut State, _args: &str) -> Result<()> {
|
||||
for app in &APPS {
|
||||
uwriteln!(state.serial, "{}: {}\r", app.command, app.description)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn free(state: &mut State, _args: &str) -> Result<()> {
|
||||
uwriteln!(
|
||||
state.serial,
|
||||
"memory> used: {}, free: {}\r",
|
||||
ALLOCATOR.used(),
|
||||
ALLOCATOR.free()
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset(_state: &mut State, _args: &str) -> Result<()> {
|
||||
unsafe {
|
||||
halc::am_hal_reset_control(
|
||||
halc::am_hal_reset_control_e_AM_HAL_RESET_CONTROL_SWPOI,
|
||||
core::ptr::null_mut::<c_void>(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn time(state: &mut State, args: &str) -> Result<()> {
|
||||
match args.split_once(' ').unwrap_or((&args, "")) {
|
||||
("set", time) => {
|
||||
let dt = NaiveDateTime::parse_from_str(time, "%d/%m/%Y %H:%M:%S")?;
|
||||
state.rtc.set(&dt);
|
||||
}
|
||||
_ => return Err("Command not recognized".into()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mandelbrot(state: &mut State, args: &str) -> Result<()> {
|
||||
use num_complex::Complex;
|
||||
|
||||
struct Ifs {
|
||||
max_iter: u64,
|
||||
}
|
||||
|
||||
trait Dds<State> {
|
||||
fn cont(&self, z: State) -> bool;
|
||||
fn next(&self, z: State, c: State) -> State;
|
||||
}
|
||||
|
||||
impl Dds<Complex<f64>> for Ifs {
|
||||
fn cont(&self, z: Complex<f64>) -> bool {
|
||||
z.norm_sqr() <= 4.0
|
||||
}
|
||||
|
||||
fn next(&self, z: Complex<f64>, c: Complex<f64>) -> Complex<f64> {
|
||||
z * z + c
|
||||
}
|
||||
}
|
||||
|
||||
impl Ifs {
|
||||
pub fn new(max_iter: u64) -> Self {
|
||||
Self { max_iter }
|
||||
}
|
||||
|
||||
pub fn iter(&self, c: Complex<f64>) -> u64 {
|
||||
let mut i: u64 = 0;
|
||||
let mut z = c;
|
||||
while i < self.max_iter && self.cont(z) {
|
||||
z = self.next(z, c);
|
||||
i += 1;
|
||||
}
|
||||
if i < self.max_iter {
|
||||
return self.max_iter - i;
|
||||
}
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_args(args: &str) -> Result<(f64, f64, i32, i32)> {
|
||||
let mut args = args.split(' ');
|
||||
let min = args
|
||||
.next()
|
||||
.ok_or("expected min")?
|
||||
.parse::<f64>()
|
||||
.map_err(|_| "min: expected float")?;
|
||||
let max = args
|
||||
.next()
|
||||
.ok_or("expected max")?
|
||||
.parse::<f64>()
|
||||
.map_err(|_| "min: expected float")?;
|
||||
let d_x = args
|
||||
.next()
|
||||
.ok_or("expected d_x")?
|
||||
.parse::<i32>()
|
||||
.map_err(|_| "d_x: expected int")?;
|
||||
let d_y = args
|
||||
.next()
|
||||
.ok_or("expected d_y")?
|
||||
.parse::<i32>()
|
||||
.map_err(|_| "d_y: expected int")?;
|
||||
Ok((min, max, d_x, d_y))
|
||||
}
|
||||
|
||||
let (min, max, d_x, d_y) = parse_args(args)?;
|
||||
let min = Complex::new(min, min);
|
||||
let max = Complex::new(max, max);
|
||||
|
||||
let mandel = Ifs::new(256);
|
||||
for j in 0..d_y - 1 {
|
||||
for i in 0..d_x - 1 {
|
||||
let x = min.re + (max.re - min.re) * (i as f64) / (d_x as f64);
|
||||
let y = min.im + (max.im - min.im) * (j as f64) / (d_y as f64);
|
||||
let c = Complex::new(x, y);
|
||||
let m = mandel.iter(c);
|
||||
let mut ch = ' ';
|
||||
if (1..63).contains(&m) {
|
||||
ch = '.';
|
||||
}
|
||||
if (64..128).contains(&m) {
|
||||
ch = 'o';
|
||||
}
|
||||
if (128..192).contains(&m) {
|
||||
ch = '*';
|
||||
}
|
||||
if (192..256).contains(&m) {
|
||||
ch = '0';
|
||||
}
|
||||
uwrite!(state.serial, "{}", ch)?;
|
||||
}
|
||||
uwriteln!(state.serial, "\r")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct State {
|
||||
serial: hal::uart::Uart0,
|
||||
rtc: hal::rtc::Rtc,
|
||||
delay: hal::delay::Delay,
|
||||
}
|
||||
|
||||
#[cortex_m_rt::entry]
|
||||
fn main() -> ! {
|
||||
unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, (1024 * 384) - 0x100) }
|
||||
|
||||
let mut dp = hal::pac::Peripherals::take().unwrap();
|
||||
let core = hal::pac::CorePeripherals::take().unwrap();
|
||||
let pins = hal::gpio::Pins::new(dp.GPIO);
|
||||
let serial = hal::uart::Uart0::new(dp.UART0, pins.tx0, pins.rx0);
|
||||
let mut rtc = hal::rtc::Rtc::new(dp.RTC, &mut dp.CLKGEN);
|
||||
let delay = hal::delay::Delay::new(core.SYST, &mut dp.CLKGEN);
|
||||
rtc.enable();
|
||||
|
||||
let mut state = State { serial, rtc, delay };
|
||||
|
||||
let mut led = pins.d18.into_push_pull_output();
|
||||
loop {
|
||||
led.toggle().unwrap();
|
||||
|
||||
let timestamp = state.rtc.now().to_string();
|
||||
uwrite!(state.serial, "{}:artemis> ", timestamp.as_str()).unwrap();
|
||||
|
||||
let mut line = String::new();
|
||||
loop {
|
||||
let char = match state.serial.read() {
|
||||
Ok(word) => {
|
||||
state.serial.write(word).unwrap();
|
||||
char::from(word)
|
||||
}
|
||||
Err(_) => continue,
|
||||
};
|
||||
match char {
|
||||
'\r' => {
|
||||
uwrite!(state.serial, "\r\n").unwrap();
|
||||
break;
|
||||
}
|
||||
'\x08' => {
|
||||
line.pop();
|
||||
uwrite!(state.serial, "\x20\x08").unwrap();
|
||||
}
|
||||
_ => line.push(char),
|
||||
}
|
||||
}
|
||||
let (command, args) = line.split_once(' ').unwrap_or((&line, ""));
|
||||
for app in &APPS {
|
||||
if command == app.command {
|
||||
match (app.func)(&mut state, args.trim()) {
|
||||
Ok(_) => continue,
|
||||
Err(e) => uwriteln!(state.serial, "{}\r", e).unwrap(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user