From a2a4b5ff019e561bd2a55d2e8a26ae3ea4a3fad2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 1 Jul 2024 16:02:10 +0200 Subject: [PATCH] small improvements and fixes --- examples/simple/examples/adc.rs | 7 ++-- examples/simple/examples/wdt.rs | 5 ++- va416xx-hal/CHANGELOG.md | 18 ++++++++++ va416xx-hal/src/adc.rs | 64 ++++++++++++++++++++++++--------- va416xx-hal/src/dac.rs | 5 +++ va416xx-hal/src/timer.rs | 7 ++-- va416xx-hal/src/wdt.rs | 9 +++-- 7 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 va416xx-hal/CHANGELOG.md diff --git a/examples/simple/examples/adc.rs b/examples/simple/examples/adc.rs index a8bc5b4..57fb96b 100644 --- a/examples/simple/examples/adc.rs +++ b/examples/simple/examples/adc.rs @@ -36,9 +36,12 @@ fn main() -> ! { let mut read_buf: [ChannelValue; 8] = [ChannelValue::default(); 8]; loop { let single_value = adc - .trigger_and_read_single_channel(va416xx_hal::adc::ChannelSelect::AnIn0) + .trigger_and_read_single_channel(va416xx_hal::adc::ChannelSelect::TempSensor) .expect("reading single channel value failed"); - rprintln!("Read single ADC value on channel 0: {:?}", single_value); + rprintln!( + "Read single ADC value on temperature sensor channel: {:?}", + single_value + ); let read_num = adc .sweep_and_read_range(0, 7, &mut read_buf) .expect("ADC range read failed"); diff --git a/examples/simple/examples/wdt.rs b/examples/simple/examples/wdt.rs index 5e989fc..75c6e43 100644 --- a/examples/simple/examples/wdt.rs +++ b/examples/simple/examples/wdt.rs @@ -10,7 +10,7 @@ use rtt_target::{rprintln, rtt_init_print}; use simple_examples::peb1; use va416xx_hal::pac::{self, interrupt}; use va416xx_hal::prelude::*; -use va416xx_hal::wdt::WdtController; +use va416xx_hal::wdt::Wdt; static WDT_INTRPT_COUNT: Mutex> = Mutex::new(Cell::new(0)); @@ -43,8 +43,7 @@ fn main() -> ! { let mut delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw()); let mut last_interrupt_counter = 0; - let mut wdt_ctrl = - WdtController::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS); + let mut wdt_ctrl = Wdt::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS); wdt_ctrl.enable_reset(); loop { if TEST_MODE != TestMode::AllowReset { diff --git a/va416xx-hal/CHANGELOG.md b/va416xx-hal/CHANGELOG.md new file mode 100644 index 0000000..874c88b --- /dev/null +++ b/va416xx-hal/CHANGELOG.md @@ -0,0 +1,18 @@ +Change Log +======= + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [unreleased] + +## [v0.1.1] 2024-07-01 + +- Documentation improvements +- Small fixes and improvements for ADC drivers + +## [v0.1.0] 2024-07-01 + +- Initial release with basic HAL drivers diff --git a/va416xx-hal/src/adc.rs b/va416xx-hal/src/adc.rs index e7ed722..da2ce49 100644 --- a/va416xx-hal/src/adc.rs +++ b/va416xx-hal/src/adc.rs @@ -1,3 +1,9 @@ +//! Analog to Digital Converter (ADC) driver. +//! +//! ## Examples +//! +//! - [ADC and DAC example](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/dac-adc.rs) +//! - [ADC](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/adc.rs) use core::marker::PhantomData; use crate::clock::Clocks; @@ -46,6 +52,8 @@ pub enum ChannelSelect { } bitflags::bitflags! { + /// This structure is used by the ADC multi-select API to + /// allow selecting multiple channels in a convenient manner. pub struct MultiChannelSelect: u16 { const AnIn0 = 1; const AnIn1 = 1 << 1; @@ -129,6 +137,18 @@ impl ChannelValue { pub enum ChannelTagEnabled {} pub enum ChannelTagDisabled {} +/// ADC driver structure. +/// +/// Currently, this structure supports three primary ways to measure channel value(s): +/// +/// * Trigger and read a single value +/// * Trigger and read a range of ADC values using the sweep functionality +/// * Trigger and read multiple ADC values using the sweep functionality +/// +/// The ADC channel tag feature is enabled or disabled at compile time using the +/// [ChannelTagEnabled] and [ChannelTagDisabled]. The [Adc::new] method returns a driver instance +/// with the channel tag enabled, while the [Adc::new_with_channel_tag] method can be used to +/// return an instance with the channel tag enabled. pub struct Adc { adc: pac::Adc, phantom: PhantomData, @@ -154,34 +174,44 @@ impl Adc { lower_bound_idx: u8, upper_bound_idx: u8, rx_buf: &mut [u16], - ) -> Result<(), AdcRangeReadError> { + ) -> Result { self.generic_prepare_range_sweep_and_wait_until_ready( lower_bound_idx, upper_bound_idx, rx_buf.len(), )?; - for i in 0..self.adc.status().read().fifo_entry_cnt().bits() { + let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits(); + for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) { rx_buf[i as usize] = self.adc.fifo_data().read().bits() as u16 & 0xfff; } - Ok(()) + Ok(fifo_entry_count as usize) } + /// Perform a sweep for selected ADC channels. + /// + /// Returns the number of read values which were written to the passed RX buffer. pub fn sweep_and_read_multiselect( &self, ch_select: MultiChannelSelect, rx_buf: &mut [u16], - ) -> Result<(), BufferTooSmallError> { + ) -> Result { self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?; - for i in 0..self.adc.status().read().fifo_entry_cnt().bits() { + let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits(); + for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) { rx_buf[i as usize] = self.adc.fifo_data().read().bits() as u16 & 0xfff; } - Ok(()) + Ok(fifo_entry_count as usize) } pub fn try_read_single_value(&self) -> nb::Result, ()> { self.generic_try_read_single_value() .map(|v| v.map(|v| v & 0xfff)) } + + #[inline(always)] + pub fn channel_tag_enabled(&self) -> bool { + false + } } impl Adc { @@ -230,17 +260,21 @@ impl Adc { Ok(fifo_entry_count as usize) } + /// Perform a sweep for selected ADC channels. + /// + /// Returns the number of read values which were written to the passed RX buffer. pub fn sweep_and_read_multiselect( &self, ch_select: MultiChannelSelect, rx_buf: &mut [ChannelValue], - ) -> Result<(), BufferTooSmallError> { + ) -> Result { self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?; - for i in 0..self.adc.status().read().fifo_entry_cnt().bits() { + let fifo_entry_count = self.adc.status().read().fifo_entry_cnt().bits(); + for i in 0..core::cmp::min(fifo_entry_count, rx_buf.len() as u8) { rx_buf[i as usize] = self.create_channel_value(self.adc.fifo_data().read().bits() as u16); } - Ok(()) + Ok(fifo_entry_count as usize) } #[inline] @@ -250,6 +284,11 @@ impl Adc { channel: ChannelSelect::try_from(((raw_value >> 12) & 0xf) as u8).unwrap(), } } + + #[inline(always)] + pub fn channel_tag_enabled(&self) -> bool { + true + } } impl Adc { @@ -274,11 +313,6 @@ impl Adc { self.adc.ctrl().modify(|_, w| w.chan_tag_en().clear_bit()); } - #[inline(always)] - pub fn channel_tag_enabled(&self) -> bool { - self.adc.ctrl().read().chan_tag_en().bit_is_set() - } - #[inline(always)] pub fn clear_fifo(&self) { self.adc.fifo_clr().write(|w| unsafe { w.bits(1) }); @@ -326,8 +360,6 @@ impl Adc { ch_select |= 1 << i; } self.generic_trigger_sweep(ch_select); - cortex_m::asm::nop(); - cortex_m::asm::nop(); while self.adc.status().read().adc_busy().bit_is_set() { cortex_m::asm::nop(); } diff --git a/va416xx-hal/src/dac.rs b/va416xx-hal/src/dac.rs index d5aaa9f..a009093 100644 --- a/va416xx-hal/src/dac.rs +++ b/va416xx-hal/src/dac.rs @@ -1,3 +1,8 @@ +//! Digital to Analog Converter (DAC) driver. +//! +//! ## Examples +//! +//! - [ADC and DAC example](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/dac-adc.rs) use core::ops::Deref; use crate::{ diff --git a/va416xx-hal/src/timer.rs b/va416xx-hal/src/timer.rs index 4438e05..68b0084 100644 --- a/va416xx-hal/src/timer.rs +++ b/va416xx-hal/src/timer.rs @@ -2,7 +2,7 @@ //! //! ## Examples //! -//! TODO. +//! - [Timer MS and Second Tick Example](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/timer-ticks.rs) use core::cell::Cell; use cortex_m::interrupt::Mutex; @@ -459,7 +459,10 @@ unsafe impl TimRegInterface for TimDynRegister { // Timers //================================================================================================== -/// Hardware timers +/// Hardware timers. +/// +/// These timers also implement the [embedded_hal::delay::DelayNs] trait and can be used to delay +/// with a higher resolution compared to the Cortex-M systick delays. pub struct CountdownTimer { tim: TimRegister, curr_freq: Hertz, diff --git a/va416xx-hal/src/wdt.rs b/va416xx-hal/src/wdt.rs index 2447954..3875aaa 100644 --- a/va416xx-hal/src/wdt.rs +++ b/va416xx-hal/src/wdt.rs @@ -13,11 +13,16 @@ use crate::{disable_interrupt, enable_interrupt}; pub const WDT_UNLOCK_VALUE: u32 = 0x1ACC_E551; -pub struct WdtController { +/// Watchdog peripheral driver. +pub struct Wdt { clock_freq: Hertz, wdt: pac::WatchDog, } +/// Type alias for backwards compatibility +#[deprecated(since = "0.2.0", note = "Please use `Wdt` instead")] +pub type WdtController = Wdt; + /// Enable the watchdog interrupt /// /// # Safety @@ -33,7 +38,7 @@ pub fn disable_wdt_interrupts() { disable_interrupt(pac::Interrupt::WATCHDOG) } -impl WdtController { +impl Wdt { pub fn new( &self, syscfg: &mut pac::Sysconfig,