Basic DMA HAL #19
@ -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");
|
||||||
|
@ -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
18
va416xx-hal/CHANGELOG.md
Normal 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
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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::{
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user