Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configuration options to QEI interface #178

Merged
merged 3 commits into from
Jan 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions examples/qei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,8 @@ use panic_semihosting as _;

use cortex_m_semihosting::hprintln;

use stm32f1xx_hal::{
prelude::*,
pac,
delay::Delay,
timer::Timer,
};
use cortex_m_rt::entry;
use stm32f1xx_hal::{delay::Delay, pac, prelude::*, qei::QeiOptions, timer::Timer};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the expanded version that was removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was rustfmt. Should I change it or leave it as is?


#[entry]
fn main() -> ! {
Expand Down Expand Up @@ -43,8 +38,11 @@ fn main() -> ! {
let c1 = gpiob.pb6;
let c2 = gpiob.pb7;

let qei = Timer::tim4(dp.TIM4, &clocks, &mut rcc.apb1)
.qei((c1, c2), &mut afio.mapr);
let qei = Timer::tim4(dp.TIM4, &clocks, &mut rcc.apb1).qei(
(c1, c2),
&mut afio.mapr,
QeiOptions::default(),
);
let mut delay = Delay::new(cp.SYST, clocks);

loop {
Expand Down
110 changes: 81 additions & 29 deletions src/qei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,96 +4,152 @@
NOTE: In some cases you need to specify remap you need, especially for TIM2
(see [Alternate function remapping](super::timer)):
*/

use core::u16;

use core::marker::PhantomData;

use crate::hal::{self, Direction};
#[cfg(any(
feature = "stm32f100",
feature = "stm32f103",
feature = "stm32f105",
))]
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "stm32f105",))]
use crate::pac::TIM1;
use crate::pac::{TIM2, TIM3};
#[cfg(feature = "medium")]
use crate::pac::TIM4;
use crate::pac::{TIM2, TIM3};

use crate::afio::MAPR;

use crate::timer::{Timer, sealed::Remap};
use crate::pwm_input::Pins;
use crate::timer::{sealed::Remap, Timer};

/// SMS (Slave Mode Selection) register
#[derive(Copy, Clone, Debug)]
pub enum SlaveMode {
/// Counter counts up/down on TI2FP1 edge depending on TI1FP2 level.
EncoderMode1 = 0b001,
/// Encoder mode 2 - Counter counts up/down on TI1FP2 edge depending on TI2FP1 level.
EncoderMode2 = 0b010,
/// Encoder mode 3 - Counter counts up/down on both TI1FP1 and TI2FP2 edges depending on the
/// level of the other input.
EncoderMode3 = 0b011,
/// Reset Mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter and
/// generates an update of the registers.
ResetMode = 0b100,
/// Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
/// reset). Only the start of the counter is controlled.
TriggerMode = 0b110,
/// External Clock Mode 1 - Rising edges of the selected trigger (TRGI) clock the counter.
ExternalClockMode1 = 0b111,
}

/// Quadrature Encoder Interface (QEI) options
///
/// The `Default` implementation provides a configuration for a 4-count pulse which counts from
/// 0-65535. The counter wraps back to 0 on overflow.
#[derive(Copy, Clone, Debug)]
pub struct QeiOptions {
/// Encoder slave mode
pub slave_mode: SlaveMode,

/// Autoreload value
///
/// This value allows the maximum count to be configured, up to 65535. Setting a lower value
/// will overflow the counter to 0 sooner.
pub auto_reload_value: u16,
}

impl Default for QeiOptions {
fn default() -> Self {
Self {
slave_mode: SlaveMode::EncoderMode3,
auto_reload_value: u16::MAX,
}
}
}

pub struct Qei<TIM, REMAP, PINS> {
tim: TIM,
pins: PINS,
_remap: PhantomData<REMAP>,
}

#[cfg(any(
feature = "stm32f100",
feature = "stm32f103",
feature = "stm32f105",
))]
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "stm32f105",))]
impl Timer<TIM1> {
pub fn qei<REMAP, PINS>(self, pins: PINS, mapr: &mut MAPR) -> Qei<TIM1, REMAP, PINS>
pub fn qei<REMAP, PINS>(
self,
pins: PINS,
mapr: &mut MAPR,
options: QeiOptions,
) -> Qei<TIM1, REMAP, PINS>
where
REMAP: Remap<Periph = TIM1>,
PINS: Pins<REMAP>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim1_remap().bits(REMAP::REMAP) });

let Self { tim, clk: _ } = self;
Qei::_tim1(tim, pins)
Qei::_tim1(tim, pins, options)
}
}

impl Timer<TIM2> {
pub fn qei<REMAP, PINS>(self, pins: PINS, mapr: &mut MAPR) -> Qei<TIM2, REMAP, PINS>
pub fn qei<REMAP, PINS>(
self,
pins: PINS,
mapr: &mut MAPR,
options: QeiOptions,
) -> Qei<TIM2, REMAP, PINS>
where
REMAP: Remap<Periph = TIM2>,
PINS: Pins<REMAP>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim2_remap().bits(REMAP::REMAP) });

let Self { tim, clk: _ } = self;
Qei::_tim2(tim, pins)
Qei::_tim2(tim, pins, options)
}
}

impl Timer<TIM3> {
pub fn qei<REMAP, PINS>(self, pins: PINS, mapr: &mut MAPR) -> Qei<TIM3, REMAP, PINS>
pub fn qei<REMAP, PINS>(
self,
pins: PINS,
mapr: &mut MAPR,
options: QeiOptions,
) -> Qei<TIM3, REMAP, PINS>
where
REMAP: Remap<Periph = TIM3>,
PINS: Pins<REMAP>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim3_remap().bits(REMAP::REMAP) });

let Self { tim, clk: _ } = self;
Qei::_tim3(tim, pins)
Qei::_tim3(tim, pins, options)
}
}

#[cfg(feature = "medium")]
impl Timer<TIM4> {
pub fn qei<REMAP, PINS>(self, pins: PINS, mapr: &mut MAPR) -> Qei<TIM4, REMAP, PINS>
pub fn qei<REMAP, PINS>(
self,
pins: PINS,
mapr: &mut MAPR,
options: QeiOptions,
) -> Qei<TIM4, REMAP, PINS>
where
REMAP: Remap<Periph = TIM4>,
PINS: Pins<REMAP>,
{
mapr.modify_mapr(|_, w| w.tim4_remap().bit(REMAP::REMAP == 1));

let Self { tim, clk: _ } = self;
Qei::_tim4(tim, pins)
Qei::_tim4(tim, pins, options)
}
}

macro_rules! hal {
($($TIMX:ident: ($timX:ident, $timXen:ident, $timXrst:ident),)+) => {
$(
impl<REMAP, PINS> Qei<$TIMX, REMAP, PINS> {
fn $timX(tim: $TIMX, pins: PINS) -> Self {
fn $timX(tim: $TIMX, pins: PINS, options: QeiOptions) -> Self {
// Configure TxC1 and TxC2 as captures
tim.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2());

Expand All @@ -110,9 +166,9 @@ macro_rules! hal {
});

// configure as quadrature encoder
tim.smcr.write(|w| w.sms().bits(3));
tim.smcr.write(|w| w.sms().bits(options.slave_mode as u8));

tim.arr.write(|w| w.arr().bits(u16::MAX));
tim.arr.write(|w| w.arr().bits(options.auto_reload_value));
tim.cr1.write(|w| w.cen().set_bit());

Qei { tim, pins, _remap: PhantomData }
Expand Down Expand Up @@ -143,11 +199,7 @@ macro_rules! hal {
}
}

#[cfg(any(
feature = "stm32f100",
feature = "stm32f103",
feature = "stm32f105",
))]
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "stm32f105",))]
hal! {
TIM1: (_tim1, tim1en, tim1rst),
}
Expand Down