Merge pull request #5 from embassy-rs/main
Merge latest including SAI driver
This commit is contained in:
commit
fa8d5da4a5
@ -463,6 +463,15 @@ fn main() {
|
||||
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
|
||||
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
|
||||
(("lpuart", "DE"), quote!(crate::usart::DePin)),
|
||||
(("sai", "SCK_A"), quote!(crate::sai::SckAPin)),
|
||||
(("sai", "SCK_B"), quote!(crate::sai::SckBPin)),
|
||||
(("sai", "FS_A"), quote!(crate::sai::FsAPin)),
|
||||
(("sai", "FS_B"), quote!(crate::sai::FsBPin)),
|
||||
(("sai", "SD_A"), quote!(crate::sai::SdAPin)),
|
||||
(("sai", "SD_B"), quote!(crate::sai::SdBPin)),
|
||||
(("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)),
|
||||
(("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)),
|
||||
(("sai", "WS"), quote!(crate::sai::WsPin)),
|
||||
(("spi", "SCK"), quote!(crate::spi::SckPin)),
|
||||
(("spi", "MOSI"), quote!(crate::spi::MosiPin)),
|
||||
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
|
||||
@ -750,6 +759,8 @@ fn main() {
|
||||
(("usart", "TX"), quote!(crate::usart::TxDma)),
|
||||
(("lpuart", "RX"), quote!(crate::usart::RxDma)),
|
||||
(("lpuart", "TX"), quote!(crate::usart::TxDma)),
|
||||
(("sai", "A"), quote!(crate::sai::DmaA)),
|
||||
(("sai", "B"), quote!(crate::sai::DmaB)),
|
||||
(("spi", "RX"), quote!(crate::spi::RxDma)),
|
||||
(("spi", "TX"), quote!(crate::spi::TxDma)),
|
||||
(("i2c", "RX"), quote!(crate::i2c::RxDma)),
|
||||
|
@ -55,6 +55,8 @@ pub mod qspi;
|
||||
pub mod rng;
|
||||
#[cfg(all(rtc, not(rtc_v1)))]
|
||||
pub mod rtc;
|
||||
#[cfg(sai)]
|
||||
pub mod sai;
|
||||
#[cfg(sdmmc)]
|
||||
pub mod sdmmc;
|
||||
#[cfg(spi)]
|
||||
|
@ -32,6 +32,9 @@ pub struct Config {
|
||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||
pub plli2s: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pub pllsai: Option<Hertz>,
|
||||
|
||||
pub pll48: bool,
|
||||
pub rtc: Option<RtcClockSource>,
|
||||
pub lsi: bool,
|
||||
@ -50,10 +53,9 @@ fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
||||
}
|
||||
|
||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
||||
fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> {
|
||||
let min_div = 2;
|
||||
let max_div = 7;
|
||||
let target = match plli2s {
|
||||
let target = match target {
|
||||
Some(target) => target,
|
||||
None => return None,
|
||||
};
|
||||
@ -77,15 +79,48 @@ fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
||||
})
|
||||
.min_by_key(|(_, _, _, error)| *error)?;
|
||||
|
||||
Some((n, outdiv, output))
|
||||
}
|
||||
|
||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
||||
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 7, plli2s)?;
|
||||
|
||||
RCC.plli2scfgr().modify(|w| {
|
||||
w.set_plli2sn(n as u16);
|
||||
w.set_plli2sr(outdiv as u8);
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
w.set_plli2sq(outdiv as u8); //set sai divider same as i2s
|
||||
});
|
||||
|
||||
Some(output)
|
||||
}
|
||||
|
||||
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
|
||||
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
|
||||
fn setup_sai_pll(_vco_in: u32, _pllsai: Option<u32>) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
fn setup_sai_pll(vco_in: u32, pllsai: Option<u32>) -> Option<u32> {
|
||||
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 15, pllsai)?;
|
||||
|
||||
RCC.pllsaicfgr().modify(|w| {
|
||||
w.set_pllsain(n as u16);
|
||||
w.set_pllsaiq(outdiv as u8);
|
||||
});
|
||||
|
||||
Some(output)
|
||||
}
|
||||
|
||||
fn setup_pll(
|
||||
pllsrcclk: u32,
|
||||
use_hse: bool,
|
||||
pllsysclk: Option<u32>,
|
||||
plli2s: Option<u32>,
|
||||
pllsai: Option<u32>,
|
||||
pll48clk: bool,
|
||||
) -> PllResults {
|
||||
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
||||
|
||||
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
||||
@ -97,6 +132,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
||||
pllsysclk: None,
|
||||
pll48clk: None,
|
||||
plli2sclk: None,
|
||||
pllsaiclk: None,
|
||||
};
|
||||
}
|
||||
// Input divisor from PLL source clock, must result to frequency in
|
||||
@ -147,6 +183,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
||||
w.set_pllp(Pllp::from_bits(pllp as u8));
|
||||
w.set_pllq(pllq as u8);
|
||||
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
|
||||
w.set_pllr(0);
|
||||
});
|
||||
|
||||
let real_pllsysclk = vco_in * plln / sysclk_div;
|
||||
@ -156,6 +193,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
||||
pllsysclk: Some(real_pllsysclk),
|
||||
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
|
||||
plli2sclk: setup_i2s_pll(vco_in, plli2s),
|
||||
pllsaiclk: setup_sai_pll(vco_in, pllsai),
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,6 +381,10 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
config.plli2s.map(|i2s| i2s.0),
|
||||
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
|
||||
None,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
config.pllsai.map(|sai| sai.0),
|
||||
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
|
||||
None,
|
||||
config.pll48,
|
||||
);
|
||||
|
||||
@ -440,6 +482,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
while !RCC.cr().read().plli2srdy() {}
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
if plls.pllsaiclk.is_some() {
|
||||
RCC.cr().modify(|w| w.set_pllsaion(true));
|
||||
while !RCC.cr().read().pllsairdy() {}
|
||||
}
|
||||
|
||||
RCC.cfgr().modify(|w| {
|
||||
w.set_ppre2(Ppre::from_bits(ppre2_bits));
|
||||
w.set_ppre1(Ppre::from_bits(ppre1_bits));
|
||||
@ -490,7 +538,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
plli2s: plls.plli2sclk.map(Hertz),
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai: None,
|
||||
pllsai: plls.pllsaiclk.map(Hertz),
|
||||
|
||||
rtc: rtc,
|
||||
rtc_hse: None,
|
||||
@ -503,6 +551,8 @@ struct PllResults {
|
||||
pll48clk: Option<u32>,
|
||||
#[allow(dead_code)]
|
||||
plli2sclk: Option<u32>,
|
||||
#[allow(dead_code)]
|
||||
pllsaiclk: Option<u32>,
|
||||
}
|
||||
|
||||
mod max {
|
||||
|
894
embassy-stm32/src/sai/mod.rs
Normal file
894
embassy-stm32/src/sai/mod.rs
Normal file
@ -0,0 +1,894 @@
|
||||
#![macro_use]
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
pub use crate::dma::word;
|
||||
use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, TransferOptions, WritableRingBuffer};
|
||||
use crate::gpio::sealed::{AFType, Pin as _};
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::pac::sai::{vals, Sai as Regs};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
NotATransmitter,
|
||||
NotAReceiver,
|
||||
OverrunError,
|
||||
}
|
||||
|
||||
impl From<ringbuffer::OverrunError> for Error {
|
||||
fn from(_: ringbuffer::OverrunError) -> Self {
|
||||
Self::OverrunError
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SyncBlock {
|
||||
None,
|
||||
Sai1BlockA,
|
||||
Sai1BlockB,
|
||||
Sai2BlockA,
|
||||
Sai2BlockB,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SyncIn {
|
||||
None,
|
||||
ChannelZero,
|
||||
ChannelOne,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Mode {
|
||||
Master,
|
||||
Slave,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum TxRx {
|
||||
Transmiter,
|
||||
Receiver,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
|
||||
match tx_rx {
|
||||
TxRx::Transmiter => match self {
|
||||
Mode::Master => vals::Mode::MASTERTX,
|
||||
Mode::Slave => vals::Mode::SLAVETX,
|
||||
},
|
||||
TxRx::Receiver => match self {
|
||||
Mode::Master => vals::Mode::MASTERRX,
|
||||
Mode::Slave => vals::Mode::SLAVERX,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SlotSize {
|
||||
DataSize,
|
||||
/// 16 bit data length on 16 bit wide channel
|
||||
Channel16,
|
||||
/// 16 bit data length on 32 bit wide channel
|
||||
Channel32,
|
||||
}
|
||||
|
||||
impl SlotSize {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn slotsz(&self) -> vals::Slotsz {
|
||||
match self {
|
||||
SlotSize::DataSize => vals::Slotsz::DATASIZE,
|
||||
SlotSize::Channel16 => vals::Slotsz::BIT16,
|
||||
SlotSize::Channel32 => vals::Slotsz::BIT32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum DataSize {
|
||||
Data8,
|
||||
Data10,
|
||||
Data16,
|
||||
Data20,
|
||||
Data24,
|
||||
Data32,
|
||||
}
|
||||
|
||||
impl DataSize {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn ds(&self) -> vals::Ds {
|
||||
match self {
|
||||
DataSize::Data8 => vals::Ds::BIT8,
|
||||
DataSize::Data10 => vals::Ds::BIT10,
|
||||
DataSize::Data16 => vals::Ds::BIT16,
|
||||
DataSize::Data20 => vals::Ds::BIT20,
|
||||
DataSize::Data24 => vals::Ds::BIT24,
|
||||
DataSize::Data32 => vals::Ds::BIT32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FifoThreshold {
|
||||
Empty,
|
||||
Quarter,
|
||||
Half,
|
||||
ThreeQuarters,
|
||||
Full,
|
||||
}
|
||||
|
||||
impl FifoThreshold {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn fth(&self) -> vals::Fth {
|
||||
match self {
|
||||
FifoThreshold::Empty => vals::Fth::EMPTY,
|
||||
FifoThreshold::Quarter => vals::Fth::QUARTER1,
|
||||
FifoThreshold::Half => vals::Fth::QUARTER2,
|
||||
FifoThreshold::ThreeQuarters => vals::Fth::QUARTER3,
|
||||
FifoThreshold::Full => vals::Fth::FULL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FifoLevel {
|
||||
Empty,
|
||||
FirstQuarter,
|
||||
SecondQuarter,
|
||||
ThirdQuarter,
|
||||
FourthQuarter,
|
||||
Full,
|
||||
}
|
||||
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
impl From<vals::Flvl> for FifoLevel {
|
||||
fn from(flvl: vals::Flvl) -> Self {
|
||||
match flvl {
|
||||
vals::Flvl::EMPTY => FifoLevel::Empty,
|
||||
vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter,
|
||||
vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter,
|
||||
vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter,
|
||||
vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter,
|
||||
vals::Flvl::FULL => FifoLevel::Full,
|
||||
_ => FifoLevel::Empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum MuteDetection {
|
||||
NoMute,
|
||||
Mute,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum MuteValue {
|
||||
Zero,
|
||||
LastValue,
|
||||
}
|
||||
|
||||
impl MuteValue {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn muteval(&self) -> vals::Muteval {
|
||||
match self {
|
||||
MuteValue::Zero => vals::Muteval::SENDZERO,
|
||||
MuteValue::LastValue => vals::Muteval::SENDLAST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum OverUnderStatus {
|
||||
NoError,
|
||||
OverUnderRunDetected,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Protocol {
|
||||
Free,
|
||||
Spdif,
|
||||
Ac97,
|
||||
}
|
||||
|
||||
impl Protocol {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn prtcfg(&self) -> vals::Prtcfg {
|
||||
match self {
|
||||
Protocol::Free => vals::Prtcfg::FREE,
|
||||
Protocol::Spdif => vals::Prtcfg::SPDIF,
|
||||
Protocol::Ac97 => vals::Prtcfg::AC97,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SyncEnable {
|
||||
Asynchronous,
|
||||
/// Syncs with the other A/B sub-block within the SAI unit
|
||||
Internal,
|
||||
/// Syncs with a sub-block in the other SAI unit - use set_sync_output() and set_sync_input()
|
||||
External,
|
||||
}
|
||||
|
||||
impl SyncEnable {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn syncen(&self) -> vals::Syncen {
|
||||
match self {
|
||||
SyncEnable::Asynchronous => vals::Syncen::ASYNCHRONOUS,
|
||||
SyncEnable::Internal => vals::Syncen::INTERNAL,
|
||||
SyncEnable::External => vals::Syncen::EXTERNAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum StereoMono {
|
||||
Stereo,
|
||||
Mono,
|
||||
}
|
||||
|
||||
impl StereoMono {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn mono(&self) -> vals::Mono {
|
||||
match self {
|
||||
StereoMono::Stereo => vals::Mono::STEREO,
|
||||
StereoMono::Mono => vals::Mono::MONO,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum BitOrder {
|
||||
LsbFirst,
|
||||
MsbFirst,
|
||||
}
|
||||
|
||||
impl BitOrder {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn lsbfirst(&self) -> vals::Lsbfirst {
|
||||
match self {
|
||||
BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
|
||||
BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FrameSyncOffset {
|
||||
/// This is used in modes other than standard I2S phillips mode
|
||||
OnFirstBit,
|
||||
/// This is used in standard I2S phillips mode
|
||||
BeforeFirstBit,
|
||||
}
|
||||
|
||||
impl FrameSyncOffset {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn fsoff(&self) -> vals::Fsoff {
|
||||
match self {
|
||||
FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
|
||||
FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FrameSyncPolarity {
|
||||
ActiveLow,
|
||||
ActiveHigh,
|
||||
}
|
||||
|
||||
impl FrameSyncPolarity {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn fspol(&self) -> vals::Fspol {
|
||||
match self {
|
||||
FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
|
||||
FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum FrameSyncDefinition {
|
||||
StartOfFrame,
|
||||
ChannelIdentification,
|
||||
}
|
||||
|
||||
impl FrameSyncDefinition {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn fsdef(&self) -> bool {
|
||||
match self {
|
||||
FrameSyncDefinition::StartOfFrame => false,
|
||||
FrameSyncDefinition::ChannelIdentification => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ClockStrobe {
|
||||
Falling,
|
||||
Rising,
|
||||
}
|
||||
|
||||
impl ClockStrobe {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn ckstr(&self) -> vals::Ckstr {
|
||||
match self {
|
||||
ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
|
||||
ClockStrobe::Rising => vals::Ckstr::RISINGEDGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ComplementFormat {
|
||||
OnesComplement,
|
||||
TwosComplement,
|
||||
}
|
||||
|
||||
impl ComplementFormat {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn cpl(&self) -> vals::Cpl {
|
||||
match self {
|
||||
ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
|
||||
ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Companding {
|
||||
None,
|
||||
MuLaw,
|
||||
ALaw,
|
||||
}
|
||||
|
||||
impl Companding {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn comp(&self) -> vals::Comp {
|
||||
match self {
|
||||
Companding::None => vals::Comp::NOCOMPANDING,
|
||||
Companding::MuLaw => vals::Comp::MULAW,
|
||||
Companding::ALaw => vals::Comp::ALAW,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum OutputDrive {
|
||||
OnStart,
|
||||
Immediately,
|
||||
}
|
||||
|
||||
impl OutputDrive {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn outdriv(&self) -> vals::Outdriv {
|
||||
match self {
|
||||
OutputDrive::OnStart => vals::Outdriv::ONSTART,
|
||||
OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum MasterClockDivider {
|
||||
MasterClockDisabled,
|
||||
Div1,
|
||||
Div2,
|
||||
Div4,
|
||||
Div6,
|
||||
Div8,
|
||||
Div10,
|
||||
Div12,
|
||||
Div14,
|
||||
Div16,
|
||||
Div18,
|
||||
Div20,
|
||||
Div22,
|
||||
Div24,
|
||||
Div26,
|
||||
Div28,
|
||||
Div30,
|
||||
}
|
||||
|
||||
impl MasterClockDivider {
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
pub const fn mckdiv(&self) -> u8 {
|
||||
match self {
|
||||
MasterClockDivider::MasterClockDisabled => 0,
|
||||
MasterClockDivider::Div1 => 0,
|
||||
MasterClockDivider::Div2 => 1,
|
||||
MasterClockDivider::Div4 => 2,
|
||||
MasterClockDivider::Div6 => 3,
|
||||
MasterClockDivider::Div8 => 4,
|
||||
MasterClockDivider::Div10 => 5,
|
||||
MasterClockDivider::Div12 => 6,
|
||||
MasterClockDivider::Div14 => 7,
|
||||
MasterClockDivider::Div16 => 8,
|
||||
MasterClockDivider::Div18 => 9,
|
||||
MasterClockDivider::Div20 => 10,
|
||||
MasterClockDivider::Div22 => 11,
|
||||
MasterClockDivider::Div24 => 12,
|
||||
MasterClockDivider::Div26 => 13,
|
||||
MasterClockDivider::Div28 => 14,
|
||||
MasterClockDivider::Div30 => 15,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// [`SAI`] configuration.
|
||||
#[non_exhaustive]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Config {
|
||||
pub mode: Mode,
|
||||
pub sync_enable: SyncEnable,
|
||||
pub is_sync_output: bool,
|
||||
pub protocol: Protocol,
|
||||
pub slot_size: SlotSize,
|
||||
pub slot_count: word::U4,
|
||||
pub slot_enable: u16,
|
||||
pub first_bit_offset: word::U5,
|
||||
pub data_size: DataSize,
|
||||
pub stereo_mono: StereoMono,
|
||||
pub bit_order: BitOrder,
|
||||
pub frame_sync_offset: FrameSyncOffset,
|
||||
pub frame_sync_polarity: FrameSyncPolarity,
|
||||
pub frame_sync_active_level_length: word::U7,
|
||||
pub frame_sync_definition: FrameSyncDefinition,
|
||||
pub frame_length: u8,
|
||||
pub clock_strobe: ClockStrobe,
|
||||
pub output_drive: OutputDrive,
|
||||
pub master_clock_divider: MasterClockDivider,
|
||||
pub is_high_impedenane_on_inactive_slot: bool,
|
||||
pub fifo_threshold: FifoThreshold,
|
||||
pub companding: Companding,
|
||||
pub complement_format: ComplementFormat,
|
||||
pub mute_value: MuteValue,
|
||||
pub mute_detection_counter: word::U5,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: Mode::Master,
|
||||
is_sync_output: false,
|
||||
sync_enable: SyncEnable::Asynchronous,
|
||||
protocol: Protocol::Free,
|
||||
slot_size: SlotSize::DataSize,
|
||||
slot_count: word::U4(2),
|
||||
first_bit_offset: word::U5(0),
|
||||
slot_enable: 0b11,
|
||||
data_size: DataSize::Data16,
|
||||
stereo_mono: StereoMono::Stereo,
|
||||
bit_order: BitOrder::LsbFirst,
|
||||
frame_sync_offset: FrameSyncOffset::BeforeFirstBit,
|
||||
frame_sync_polarity: FrameSyncPolarity::ActiveLow,
|
||||
frame_sync_active_level_length: word::U7(16),
|
||||
frame_sync_definition: FrameSyncDefinition::ChannelIdentification,
|
||||
frame_length: 32,
|
||||
master_clock_divider: MasterClockDivider::MasterClockDisabled,
|
||||
clock_strobe: ClockStrobe::Rising,
|
||||
output_drive: OutputDrive::Immediately,
|
||||
is_high_impedenane_on_inactive_slot: false,
|
||||
fifo_threshold: FifoThreshold::ThreeQuarters,
|
||||
companding: Companding::None,
|
||||
complement_format: ComplementFormat::TwosComplement,
|
||||
mute_value: MuteValue::Zero,
|
||||
mute_detection_counter: word::U5(4),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new_i2s() -> Self {
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
pub fn new_msb_first() -> Self {
|
||||
Self {
|
||||
bit_order: BitOrder::MsbFirst,
|
||||
frame_sync_offset: FrameSyncOffset::OnFirstBit,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SubBlock {
|
||||
A = 0,
|
||||
B = 1,
|
||||
}
|
||||
|
||||
enum RingBuffer<'d, C: Channel, W: word::Word> {
|
||||
Writable(WritableRingBuffer<'d, C, W>),
|
||||
#[allow(dead_code)] // remove this after implementing new_* functions for receiver
|
||||
Readable(ReadableRingBuffer<'d, C, W>),
|
||||
}
|
||||
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
fn wdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W {
|
||||
let ch = w.ch(sub_block as usize);
|
||||
ch.dr().as_ptr() as _
|
||||
}
|
||||
|
||||
pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
sd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
fs: Option<PeripheralRef<'d, AnyPin>>,
|
||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mclk: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ring_buffer: RingBuffer<'d, C, W>,
|
||||
sub_block: SubBlock,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
|
||||
fn get_transmitter_af_types(mode: Mode) -> (AFType, AFType) {
|
||||
match mode {
|
||||
Mode::Master => (AFType::OutputPushPull, AFType::OutputPushPull),
|
||||
Mode::Slave => (AFType::OutputPushPull, AFType::Input),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_asynchronous_transmitter_with_mclk_a(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
|
||||
sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
|
||||
fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
|
||||
mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
|
||||
dma: impl Peripheral<P = C> + 'd,
|
||||
dma_buf: &'d mut [W],
|
||||
mut config: Config,
|
||||
) -> Self
|
||||
where
|
||||
C: Channel + DmaA<T>,
|
||||
{
|
||||
into_ref!(mclk);
|
||||
|
||||
mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull);
|
||||
mclk.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
|
||||
config.master_clock_divider = MasterClockDivider::Div1;
|
||||
}
|
||||
|
||||
Self::new_asynchronous_transmitter_a(peri, sck, sd, fs, dma, dma_buf, config)
|
||||
}
|
||||
|
||||
pub fn new_asynchronous_transmitter_a(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
|
||||
sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
|
||||
fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
|
||||
dma: impl Peripheral<P = C> + 'd,
|
||||
dma_buf: &'d mut [W],
|
||||
config: Config,
|
||||
) -> Self
|
||||
where
|
||||
C: Channel + DmaA<T>,
|
||||
{
|
||||
into_ref!(peri, dma, sck, sd, fs);
|
||||
|
||||
let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode);
|
||||
sd.set_as_af(sd.af_num(), sd_af_type);
|
||||
sd.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
sck.set_as_af(sck.af_num(), ck_af_type);
|
||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
fs.set_as_af(fs.af_num(), ck_af_type);
|
||||
fs.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
let request = dma.request();
|
||||
let opts = TransferOptions {
|
||||
half_transfer_ir: true,
|
||||
circular: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sub_block = SubBlock::A;
|
||||
|
||||
Self::new_inner(
|
||||
peri,
|
||||
sub_block,
|
||||
Some(sck.map_into()),
|
||||
None,
|
||||
Some(sd.map_into()),
|
||||
Some(fs.map_into()),
|
||||
RingBuffer::Writable(unsafe {
|
||||
WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
|
||||
}),
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_asynchronous_transmitter_with_mclk_b(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
|
||||
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
|
||||
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
|
||||
mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd,
|
||||
dma: impl Peripheral<P = C> + 'd,
|
||||
dma_buf: &'d mut [W],
|
||||
mut config: Config,
|
||||
) -> Self
|
||||
where
|
||||
C: Channel + DmaB<T>,
|
||||
{
|
||||
into_ref!(mclk);
|
||||
|
||||
mclk.set_as_af(mclk.af_num(), AFType::OutputPushPull);
|
||||
mclk.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
|
||||
config.master_clock_divider = MasterClockDivider::Div1;
|
||||
}
|
||||
|
||||
Self::new_asynchronous_transmitter_b(peri, sck, sd, fs, dma, dma_buf, config)
|
||||
}
|
||||
|
||||
pub fn new_asynchronous_transmitter_b(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
|
||||
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
|
||||
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
|
||||
dma: impl Peripheral<P = C> + 'd,
|
||||
dma_buf: &'d mut [W],
|
||||
config: Config,
|
||||
) -> Self
|
||||
where
|
||||
C: Channel + DmaB<T>,
|
||||
{
|
||||
into_ref!(dma, peri, sck, sd, fs);
|
||||
|
||||
let (sd_af_type, ck_af_type) = Self::get_transmitter_af_types(config.mode);
|
||||
|
||||
sd.set_as_af(sd.af_num(), sd_af_type);
|
||||
sd.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
sck.set_as_af(sck.af_num(), ck_af_type);
|
||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
fs.set_as_af(fs.af_num(), ck_af_type);
|
||||
fs.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
let request = dma.request();
|
||||
let opts = TransferOptions {
|
||||
half_transfer_ir: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let sub_block = SubBlock::B;
|
||||
|
||||
Self::new_inner(
|
||||
peri,
|
||||
sub_block,
|
||||
Some(sck.map_into()),
|
||||
None,
|
||||
Some(sd.map_into()),
|
||||
Some(fs.map_into()),
|
||||
RingBuffer::Writable(unsafe {
|
||||
WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts)
|
||||
}),
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn start(self: &mut Self) {
|
||||
match self.ring_buffer {
|
||||
RingBuffer::Writable(ref mut rb) => {
|
||||
rb.start();
|
||||
}
|
||||
RingBuffer::Readable(ref mut rb) => {
|
||||
rb.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
|
||||
match ring_buffer {
|
||||
RingBuffer::Writable(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sub_block: SubBlock,
|
||||
sck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mclk: Option<PeripheralRef<'d, AnyPin>>,
|
||||
sd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
fs: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ring_buffer: RingBuffer<'d, C, W>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
#[cfg(any(sai_v4))]
|
||||
{
|
||||
// Not totally clear from the datasheet if this is right
|
||||
// This is only used if using SyncEnable::External
|
||||
let value: u8 = if T::REGS.as_ptr() == stm32_metapac::SAI1.as_ptr() {
|
||||
1 //this is SAI1, so sync with SAI2
|
||||
} else {
|
||||
0 //this is SAI2, so sync with SAI1
|
||||
};
|
||||
T::REGS.gcr().modify(|w| {
|
||||
w.set_syncin(value);
|
||||
});
|
||||
|
||||
if config.is_sync_output {
|
||||
let syncout: u8 = match sub_block {
|
||||
SubBlock::A => 0b01,
|
||||
SubBlock::B => 0b10,
|
||||
};
|
||||
T::REGS.gcr().modify(|w| {
|
||||
w.set_syncout(syncout);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
|
||||
{
|
||||
let ch = T::REGS.ch(sub_block as usize);
|
||||
ch.cr1().modify(|w| {
|
||||
w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) {
|
||||
TxRx::Transmiter
|
||||
} else {
|
||||
TxRx::Receiver
|
||||
}));
|
||||
w.set_prtcfg(config.protocol.prtcfg());
|
||||
w.set_ds(config.data_size.ds());
|
||||
w.set_lsbfirst(config.bit_order.lsbfirst());
|
||||
w.set_ckstr(config.clock_strobe.ckstr());
|
||||
w.set_syncen(config.sync_enable.syncen());
|
||||
w.set_mono(config.stereo_mono.mono());
|
||||
w.set_outdriv(config.output_drive.outdriv());
|
||||
w.set_mckdiv(config.master_clock_divider.mckdiv());
|
||||
w.set_nodiv(
|
||||
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
|
||||
vals::Nodiv::NODIV
|
||||
} else {
|
||||
vals::Nodiv::MASTERCLOCK
|
||||
},
|
||||
);
|
||||
w.set_dmaen(true);
|
||||
});
|
||||
|
||||
ch.cr2().modify(|w| {
|
||||
w.set_fth(config.fifo_threshold.fth());
|
||||
w.set_comp(config.companding.comp());
|
||||
w.set_cpl(config.complement_format.cpl());
|
||||
w.set_muteval(config.mute_value.muteval());
|
||||
w.set_mutecnt(config.mute_detection_counter.0 as u8);
|
||||
w.set_tris(config.is_high_impedenane_on_inactive_slot);
|
||||
});
|
||||
|
||||
ch.frcr().modify(|w| {
|
||||
w.set_fsoff(config.frame_sync_offset.fsoff());
|
||||
w.set_fspol(config.frame_sync_polarity.fspol());
|
||||
w.set_fsdef(config.frame_sync_definition.fsdef());
|
||||
w.set_fsall(config.frame_sync_active_level_length.0 as u8);
|
||||
w.set_frl(config.frame_length - 1);
|
||||
});
|
||||
|
||||
ch.slotr().modify(|w| {
|
||||
w.set_nbslot(config.slot_count.0 as u8 - 1);
|
||||
w.set_slotsz(config.slot_size.slotsz());
|
||||
w.set_fboff(config.first_bit_offset.0 as u8);
|
||||
w.set_sloten(vals::Sloten(config.slot_enable as u16));
|
||||
});
|
||||
|
||||
ch.cr1().modify(|w| w.set_saien(true));
|
||||
}
|
||||
|
||||
Self {
|
||||
_peri: peri.into_ref(),
|
||||
sub_block,
|
||||
sck,
|
||||
mclk,
|
||||
sd,
|
||||
fs,
|
||||
ring_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {
|
||||
let ch = T::REGS.ch(self.sub_block as usize);
|
||||
ch.cr1().modify(|w| w.set_saien(false));
|
||||
#[cfg(any(sai_v1, sai_v2))]
|
||||
{
|
||||
ch.cr2().modify(|w| w.set_fflush(vals::Fflush::FLUSH));
|
||||
}
|
||||
#[cfg(any(sai_v3, sai_v4))]
|
||||
{
|
||||
ch.cr2().modify(|w| w.set_fflush(true));
|
||||
}
|
||||
ch.cr1().modify(|w| w.set_saien(true));
|
||||
}
|
||||
|
||||
pub fn set_mute(&mut self, value: bool) {
|
||||
let ch = T::REGS.ch(self.sub_block as usize);
|
||||
ch.cr2().modify(|w| w.set_mute(value));
|
||||
}
|
||||
|
||||
/// Reconfigures it with the supplied config.
|
||||
pub fn reconfigure(&mut self, _config: Config) {}
|
||||
|
||||
pub fn get_current_config(&self) -> Config {
|
||||
Config::default()
|
||||
}
|
||||
|
||||
pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
|
||||
match &mut self.ring_buffer {
|
||||
RingBuffer::Writable(buffer) => {
|
||||
buffer.write_exact(data).await?;
|
||||
Ok(())
|
||||
}
|
||||
_ => return Err(Error::NotATransmitter),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
match &mut self.ring_buffer {
|
||||
RingBuffer::Readable(buffer) => {
|
||||
buffer.read_exact(data).await?;
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::NotAReceiver),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> {
|
||||
fn drop(&mut self) {
|
||||
let ch = T::REGS.ch(self.sub_block as usize);
|
||||
ch.cr1().modify(|w| w.set_saien(false));
|
||||
self.fs.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.sck.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.mclk.as_ref().map(|x| x.set_as_disconnected());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub trait Instance {
|
||||
const REGS: Regs;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Word: word::Word {}
|
||||
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
|
||||
pin_trait!(SckAPin, Instance);
|
||||
pin_trait!(SckBPin, Instance);
|
||||
pin_trait!(FsAPin, Instance);
|
||||
pin_trait!(FsBPin, Instance);
|
||||
pin_trait!(SdAPin, Instance);
|
||||
pin_trait!(SdBPin, Instance);
|
||||
pin_trait!(MclkAPin, Instance);
|
||||
pin_trait!(MclkBPin, Instance);
|
||||
|
||||
dma_trait!(DmaA, Instance);
|
||||
dma_trait!(DmaB, Instance);
|
||||
|
||||
foreach_peripheral!(
|
||||
(sai, $inst:ident) => {
|
||||
impl sealed::Instance for peripherals::$inst {
|
||||
const REGS: Regs = crate::pac::$inst;
|
||||
}
|
||||
|
||||
impl Instance for peripherals::$inst {}
|
||||
};
|
||||
);
|
||||
|
||||
impl<'d, T: Instance, C: Channel, W: word::Word> SetConfig for Sai<'d, T, C, W> {
|
||||
type Config = Config;
|
||||
fn set_config(&mut self, config: &Self::Config) {
|
||||
self.reconfigure(*config);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ pub mod simple_pwm;
|
||||
use stm32_metapac::timer::vals;
|
||||
|
||||
use crate::interrupt;
|
||||
use crate::rcc::sealed::RccPeripheral as __RccPeri;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::time::Hertz;
|
||||
|
||||
@ -22,33 +21,88 @@ pub(crate) mod sealed {
|
||||
|
||||
fn regs() -> crate::pac::timer::TimBasic;
|
||||
|
||||
fn start(&mut self);
|
||||
fn start(&mut self) {
|
||||
Self::regs().cr1().modify(|r| r.set_cen(true));
|
||||
}
|
||||
|
||||
fn stop(&mut self);
|
||||
fn stop(&mut self) {
|
||||
Self::regs().cr1().modify(|r| r.set_cen(false));
|
||||
}
|
||||
|
||||
fn reset(&mut self);
|
||||
fn reset(&mut self) {
|
||||
Self::regs().cnt().write(|r| r.set_cnt(0));
|
||||
}
|
||||
|
||||
fn set_frequency(&mut self, frequency: Hertz);
|
||||
fn set_frequency(&mut self, frequency: Hertz) {
|
||||
let f = frequency.0;
|
||||
let timer_f = Self::frequency().0;
|
||||
assert!(f > 0);
|
||||
let pclk_ticks_per_timer_period = timer_f / f;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
|
||||
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
|
||||
|
||||
fn clear_update_interrupt(&mut self) -> bool;
|
||||
let regs = Self::regs();
|
||||
regs.psc().write(|r| r.set_psc(psc));
|
||||
regs.arr().write(|r| r.set_arr(arr));
|
||||
|
||||
fn enable_update_interrupt(&mut self, enable: bool);
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||
}
|
||||
|
||||
fn set_autoreload_preload(&mut self, enable: vals::Arpe);
|
||||
fn clear_update_interrupt(&mut self) -> bool {
|
||||
let regs = Self::regs();
|
||||
let sr = regs.sr().read();
|
||||
if sr.uif() {
|
||||
regs.sr().modify(|r| {
|
||||
r.set_uif(false);
|
||||
});
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_update_interrupt(&mut self, enable: bool) {
|
||||
Self::regs().dier().write(|r| r.set_uie(enable));
|
||||
}
|
||||
|
||||
fn set_autoreload_preload(&mut self, enable: vals::Arpe) {
|
||||
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16;
|
||||
|
||||
fn set_count_direction(&mut self, direction: vals::Dir);
|
||||
fn set_count_direction(&mut self, direction: vals::Dir) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
|
||||
}
|
||||
|
||||
fn set_clock_division(&mut self, ckd: vals::Ckd);
|
||||
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
|
||||
fn regs_gp32() -> crate::pac::timer::TimGp32;
|
||||
|
||||
fn set_frequency(&mut self, frequency: Hertz);
|
||||
fn set_frequency(&mut self, frequency: Hertz) {
|
||||
let f = frequency.0;
|
||||
assert!(f > 0);
|
||||
let timer_f = Self::frequency().0;
|
||||
let pclk_ticks_per_timer_period = (timer_f / f) as u64;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
|
||||
let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
|
||||
|
||||
let regs = Self::regs_gp32();
|
||||
regs.psc().write(|r| r.set_psc(psc));
|
||||
regs.arr().write(|r| r.set_arr(arr));
|
||||
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
|
||||
@ -56,68 +110,115 @@ pub(crate) mod sealed {
|
||||
}
|
||||
|
||||
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
||||
}
|
||||
|
||||
fn clear_input_interrupt(&mut self, channel: Channel);
|
||||
fn clear_input_interrupt(&mut self, channel: Channel) {
|
||||
Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false));
|
||||
}
|
||||
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
||||
Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable));
|
||||
}
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
||||
}
|
||||
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
||||
}
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||
Self::regs_gp16().ccer().modify(|r| match mode {
|
||||
InputCaptureMode::Rising => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), false);
|
||||
}
|
||||
InputCaptureMode::Falling => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
InputCaptureMode::BothEdges => {
|
||||
r.set_ccnp(channel.raw(), true);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
fn enable_outputs(&mut self, _enable: bool) {}
|
||||
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
||||
let r = Self::regs_gp16();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
Self::regs_gp16()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
/// Global output enable. Does not do anything on non-advanced timers.
|
||||
fn enable_outputs(&mut self, enable: bool);
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u16 {
|
||||
Self::regs_gp16().ccr(channel.raw()).read().ccr()
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16);
|
||||
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u16;
|
||||
|
||||
fn get_max_compare_value(&self) -> u16;
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
Self::regs_gp16().arr().read().arr()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
|
||||
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
|
||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
|
||||
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccnp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd);
|
||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
|
||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||
}
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8);
|
||||
fn set_dead_time_value(&mut self, value: u8) {
|
||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||
}
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccne(channel.raw(), enable));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf);
|
||||
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn clear_input_interrupt(&mut self, channel: Channel);
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u32 {
|
||||
Self::regs_gp32().ccr(channel.raw()).read().ccr()
|
||||
}
|
||||
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8);
|
||||
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection);
|
||||
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode);
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32);
|
||||
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u32;
|
||||
|
||||
fn get_max_compare_value(&self) -> u32;
|
||||
fn get_max_compare_value(&self) -> u32 {
|
||||
Self::regs_gp32().arr().read().arr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,57 +355,6 @@ macro_rules! impl_basic_16bit_timer {
|
||||
fn regs() -> crate::pac::timer::TimBasic {
|
||||
unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
Self::regs().cr1().modify(|r| r.set_cen(true));
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
Self::regs().cr1().modify(|r| r.set_cen(false));
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
Self::regs().cnt().write(|r| r.set_cnt(0));
|
||||
}
|
||||
|
||||
fn set_frequency(&mut self, frequency: Hertz) {
|
||||
use core::convert::TryInto;
|
||||
let f = frequency.0;
|
||||
let timer_f = Self::frequency().0;
|
||||
assert!(f > 0);
|
||||
let pclk_ticks_per_timer_period = timer_f / f;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
|
||||
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
|
||||
|
||||
let regs = Self::regs();
|
||||
regs.psc().write(|r| r.set_psc(psc));
|
||||
regs.arr().write(|r| r.set_arr(arr));
|
||||
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||
}
|
||||
|
||||
fn clear_update_interrupt(&mut self) -> bool {
|
||||
let regs = Self::regs();
|
||||
let sr = regs.sr().read();
|
||||
if sr.uif() {
|
||||
regs.sr().modify(|r| {
|
||||
r.set_uif(false);
|
||||
});
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_update_interrupt(&mut self, enable: bool) {
|
||||
Self::regs().dier().write(|r| r.set_uie(enable));
|
||||
}
|
||||
|
||||
fn set_autoreload_preload(&mut self, enable: vals::Arpe) {
|
||||
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -316,24 +366,6 @@ macro_rules! impl_32bit_timer {
|
||||
fn regs_gp32() -> crate::pac::timer::TimGp32 {
|
||||
crate::pac::$inst
|
||||
}
|
||||
|
||||
fn set_frequency(&mut self, frequency: Hertz) {
|
||||
use core::convert::TryInto;
|
||||
let f = frequency.0;
|
||||
assert!(f > 0);
|
||||
let timer_f = Self::frequency().0;
|
||||
let pclk_ticks_per_timer_period = (timer_f / f) as u64;
|
||||
let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
|
||||
let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
|
||||
|
||||
let regs = Self::regs_gp32();
|
||||
regs.psc().write(|r| r.set_psc(psc));
|
||||
regs.arr().write(|r| r.set_arr(arr));
|
||||
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -341,99 +373,7 @@ macro_rules! impl_32bit_timer {
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_compare_capable_16bit {
|
||||
($inst:ident) => {
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
||||
}
|
||||
|
||||
fn clear_input_interrupt(&mut self, channel: Channel) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.sr()
|
||||
.modify(|r| r.set_ccif(channel.raw(), false));
|
||||
}
|
||||
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.dier()
|
||||
.modify(|r| r.set_ccie(channel.raw(), enable));
|
||||
}
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
||||
}
|
||||
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp16()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
||||
}
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().ccer().modify(|r| match mode {
|
||||
InputCaptureMode::Rising => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), false);
|
||||
}
|
||||
InputCaptureMode::Falling => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
InputCaptureMode::BothEdges => {
|
||||
r.set_ccnp(channel.raw(), true);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
fn enable_outputs(&mut self, _enable: bool) {}
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
let r = Self::regs_gp16();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u16 {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().ccr(channel.raw()).read().ccr()
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().arr().read().arr()
|
||||
}
|
||||
}
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
};
|
||||
}
|
||||
|
||||
@ -453,14 +393,6 @@ foreach_interrupt! {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
crate::pac::$inst
|
||||
}
|
||||
|
||||
fn set_count_direction(&mut self, direction: vals::Dir) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
|
||||
}
|
||||
|
||||
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -473,111 +405,12 @@ foreach_interrupt! {
|
||||
impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
||||
use sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
||||
}
|
||||
|
||||
fn clear_input_interrupt(&mut self, channel: Channel) {
|
||||
use sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32()
|
||||
.sr()
|
||||
.modify(|r| r.set_ccif(channel.raw(), false));
|
||||
}
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
||||
use sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32()
|
||||
.dier()
|
||||
.modify(|r| r.set_ccie(channel.raw(), enable));
|
||||
}
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
||||
}
|
||||
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
||||
}
|
||||
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccer().modify(|r| match mode {
|
||||
InputCaptureMode::Rising => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), false);
|
||||
}
|
||||
InputCaptureMode::Falling => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
InputCaptureMode::BothEdges => {
|
||||
r.set_ccnp(channel.raw(), true);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u32 {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccr(channel.raw()).read().ccr()
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u32 {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().arr().read().arr() as u32
|
||||
}
|
||||
}
|
||||
impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||
}
|
||||
|
||||
fn set_count_direction(&mut self, direction: vals::Dir) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
|
||||
}
|
||||
|
||||
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -589,19 +422,12 @@ foreach_interrupt! {
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl AdvancedControlInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||
}
|
||||
|
||||
fn set_count_direction(&mut self, direction: vals::Dir) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_dir(direction));
|
||||
}
|
||||
|
||||
fn set_clock_division(&mut self, ckd: vals::Ckd) {
|
||||
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
|
||||
@ -610,133 +436,7 @@ foreach_interrupt! {
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_advanced()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icf(raw_channel % 2, icf));
|
||||
}
|
||||
|
||||
fn clear_input_interrupt(&mut self, channel: Channel) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.sr()
|
||||
.modify(|r| r.set_ccif(channel.raw(), false));
|
||||
}
|
||||
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.dier()
|
||||
.modify(|r| r.set_ccie(channel.raw(), enable));
|
||||
}
|
||||
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_advanced()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
|
||||
}
|
||||
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_advanced()
|
||||
.ccmr_input(raw_channel / 2)
|
||||
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
|
||||
}
|
||||
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().ccer().modify(|r| match mode {
|
||||
InputCaptureMode::Rising => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), false);
|
||||
}
|
||||
InputCaptureMode::Falling => {
|
||||
r.set_ccnp(channel.raw(), false);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
InputCaptureMode::BothEdges => {
|
||||
r.set_ccnp(channel.raw(), true);
|
||||
r.set_ccp(channel.raw(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
fn enable_outputs(&mut self, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
r.bdtr().modify(|w| w.set_moe(enable));
|
||||
}
|
||||
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn get_capture_value(&mut self, channel: Channel) -> u16 {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().ccr(channel.raw()).read().ccr()
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccr(channel.raw())
|
||||
.modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().arr().read().arr()
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccnp(channel.raw(), polarity.into()));
|
||||
}
|
||||
|
||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||
}
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||
}
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccne(channel.raw(), enable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
Examples use a CLI tool named `wasm-pack` to build this example:
|
||||
|
||||
```
|
||||
cargo install wasm-pack --version 0.9.1
|
||||
cargo install wasm-pack --version 0.12.1
|
||||
```
|
||||
|
||||
## Building
|
||||
@ -23,4 +23,4 @@ To run the example, start a webserver server the local folder:
|
||||
python -m http.server
|
||||
```
|
||||
|
||||
Then, open a browser at https://127.0.0.1:8000 and watch the ticker print entries to the window.
|
||||
Then, open a browser at http://127.0.0.1:8000 and watch the ticker print entries to the window.
|
||||
|
Loading…
Reference in New Issue
Block a user