small improvements and fixes #18

Merged
muellerr merged 1 commits from smaller-improvements-and-fixes into main 2024-07-03 22:48:09 +02:00
7 changed files with 90 additions and 25 deletions

View File

@ -36,9 +36,12 @@ fn main() -> ! {
let mut read_buf: [ChannelValue; 8] = [ChannelValue::default(); 8]; let mut read_buf: [ChannelValue; 8] = [ChannelValue::default(); 8];
loop { loop {
let single_value = adc 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"); .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 let read_num = adc
.sweep_and_read_range(0, 7, &mut read_buf) .sweep_and_read_range(0, 7, &mut read_buf)
.expect("ADC range read failed"); .expect("ADC range read failed");

View File

@ -10,7 +10,7 @@ use rtt_target::{rprintln, rtt_init_print};
use simple_examples::peb1; use simple_examples::peb1;
use va416xx_hal::pac::{self, interrupt}; use va416xx_hal::pac::{self, interrupt};
use va416xx_hal::prelude::*; use va416xx_hal::prelude::*;
use va416xx_hal::wdt::WdtController; use va416xx_hal::wdt::Wdt;
static WDT_INTRPT_COUNT: Mutex<Cell<u32>> = Mutex::new(Cell::new(0)); static WDT_INTRPT_COUNT: Mutex<Cell<u32>> = 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 delay_sysclk = cortex_m::delay::Delay::new(cp.SYST, clocks.apb0().raw());
let mut last_interrupt_counter = 0; let mut last_interrupt_counter = 0;
let mut wdt_ctrl = let mut wdt_ctrl = Wdt::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS);
WdtController::start(&mut dp.sysconfig, dp.watch_dog, &clocks, WDT_ROLLOVER_MS);
wdt_ctrl.enable_reset(); wdt_ctrl.enable_reset();
loop { loop {
if TEST_MODE != TestMode::AllowReset { if TEST_MODE != TestMode::AllowReset {

18
va416xx-hal/CHANGELOG.md Normal file
View File

@ -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

View File

@ -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 core::marker::PhantomData;
use crate::clock::Clocks; use crate::clock::Clocks;
@ -46,6 +52,8 @@ pub enum ChannelSelect {
} }
bitflags::bitflags! { 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 { pub struct MultiChannelSelect: u16 {
const AnIn0 = 1; const AnIn0 = 1;
const AnIn1 = 1 << 1; const AnIn1 = 1 << 1;
@ -129,6 +137,18 @@ impl ChannelValue {
pub enum ChannelTagEnabled {} pub enum ChannelTagEnabled {}
pub enum ChannelTagDisabled {} 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<TagEnabled = ChannelTagDisabled> { pub struct Adc<TagEnabled = ChannelTagDisabled> {
adc: pac::Adc, adc: pac::Adc,
phantom: PhantomData<TagEnabled>, phantom: PhantomData<TagEnabled>,
@ -154,34 +174,44 @@ impl Adc<ChannelTagDisabled> {
lower_bound_idx: u8, lower_bound_idx: u8,
upper_bound_idx: u8, upper_bound_idx: u8,
rx_buf: &mut [u16], rx_buf: &mut [u16],
) -> Result<(), AdcRangeReadError> { ) -> Result<usize, AdcRangeReadError> {
self.generic_prepare_range_sweep_and_wait_until_ready( self.generic_prepare_range_sweep_and_wait_until_ready(
lower_bound_idx, lower_bound_idx,
upper_bound_idx, upper_bound_idx,
rx_buf.len(), 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; 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( pub fn sweep_and_read_multiselect(
&self, &self,
ch_select: MultiChannelSelect, ch_select: MultiChannelSelect,
rx_buf: &mut [u16], rx_buf: &mut [u16],
) -> Result<(), BufferTooSmallError> { ) -> Result<usize, BufferTooSmallError> {
self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?; 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; 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<Option<u16>, ()> { pub fn try_read_single_value(&self) -> nb::Result<Option<u16>, ()> {
self.generic_try_read_single_value() self.generic_try_read_single_value()
.map(|v| v.map(|v| v & 0xfff)) .map(|v| v.map(|v| v & 0xfff))
} }
#[inline(always)]
pub fn channel_tag_enabled(&self) -> bool {
false
}
} }
impl Adc<ChannelTagEnabled> { impl Adc<ChannelTagEnabled> {
@ -230,17 +260,21 @@ impl Adc<ChannelTagEnabled> {
Ok(fifo_entry_count as usize) 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( pub fn sweep_and_read_multiselect(
&self, &self,
ch_select: MultiChannelSelect, ch_select: MultiChannelSelect,
rx_buf: &mut [ChannelValue], rx_buf: &mut [ChannelValue],
) -> Result<(), BufferTooSmallError> { ) -> Result<usize, BufferTooSmallError> {
self.generic_prepare_multiselect_sweep_and_wait_until_ready(ch_select, rx_buf.len())?; 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] = rx_buf[i as usize] =
self.create_channel_value(self.adc.fifo_data().read().bits() as u16); self.create_channel_value(self.adc.fifo_data().read().bits() as u16);
} }
Ok(()) Ok(fifo_entry_count as usize)
} }
#[inline] #[inline]
@ -250,6 +284,11 @@ impl Adc<ChannelTagEnabled> {
channel: ChannelSelect::try_from(((raw_value >> 12) & 0xf) as u8).unwrap(), channel: ChannelSelect::try_from(((raw_value >> 12) & 0xf) as u8).unwrap(),
} }
} }
#[inline(always)]
pub fn channel_tag_enabled(&self) -> bool {
true
}
} }
impl<TagEnabled> Adc<TagEnabled> { impl<TagEnabled> Adc<TagEnabled> {
@ -274,11 +313,6 @@ impl<TagEnabled> Adc<TagEnabled> {
self.adc.ctrl().modify(|_, w| w.chan_tag_en().clear_bit()); 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)] #[inline(always)]
pub fn clear_fifo(&self) { pub fn clear_fifo(&self) {
self.adc.fifo_clr().write(|w| unsafe { w.bits(1) }); self.adc.fifo_clr().write(|w| unsafe { w.bits(1) });
@ -326,8 +360,6 @@ impl<TagEnabled> Adc<TagEnabled> {
ch_select |= 1 << i; ch_select |= 1 << i;
} }
self.generic_trigger_sweep(ch_select); self.generic_trigger_sweep(ch_select);
cortex_m::asm::nop();
cortex_m::asm::nop();
while self.adc.status().read().adc_busy().bit_is_set() { while self.adc.status().read().adc_busy().bit_is_set() {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }

View File

@ -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 core::ops::Deref;
use crate::{ use crate::{

View File

@ -2,7 +2,7 @@
//! //!
//! ## Examples //! ## 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 core::cell::Cell;
use cortex_m::interrupt::Mutex; use cortex_m::interrupt::Mutex;
@ -459,7 +459,10 @@ unsafe impl TimRegInterface for TimDynRegister {
// Timers // 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: ValidTim> { pub struct CountdownTimer<TIM: ValidTim> {
tim: TimRegister<TIM>, tim: TimRegister<TIM>,
curr_freq: Hertz, curr_freq: Hertz,

View File

@ -13,11 +13,16 @@ use crate::{disable_interrupt, enable_interrupt};
pub const WDT_UNLOCK_VALUE: u32 = 0x1ACC_E551; pub const WDT_UNLOCK_VALUE: u32 = 0x1ACC_E551;
pub struct WdtController { /// Watchdog peripheral driver.
pub struct Wdt {
clock_freq: Hertz, clock_freq: Hertz,
wdt: pac::WatchDog, 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 /// Enable the watchdog interrupt
/// ///
/// # Safety /// # Safety
@ -33,7 +38,7 @@ pub fn disable_wdt_interrupts() {
disable_interrupt(pac::Interrupt::WATCHDOG) disable_interrupt(pac::Interrupt::WATCHDOG)
} }
impl WdtController { impl Wdt {
pub fn new( pub fn new(
&self, &self,
syscfg: &mut pac::Sysconfig, syscfg: &mut pac::Sysconfig,