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

RFC: Macro for generating all PWM map combinations #120

Closed
wants to merge 2 commits into from
Closed
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
138 changes: 93 additions & 45 deletions src/pwm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
```
*/


use core::marker::PhantomData;
use core::mem;

Expand All @@ -138,8 +139,10 @@ use crate::pac::{TIM2, TIM3, TIM4};

use crate::afio::MAPR;
use crate::bb;
use crate::gpio::gpioa::{PA0, PA1, PA2, PA3, PA6, PA7};
use crate::gpio::gpiob::{PB0, PB1, PB6, PB7, PB8, PB9};
use crate::gpio::gpioa::{PA0, PA1, PA2, PA3, PA6, PA7, PA15};
use crate::gpio::gpiob::{PB0, PB1, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11};
use crate::gpio::gpioc::{PC6, PC7, PC8, PC9};
use crate::gpio::gpiod::{PD12, PD13, PD14, PD15};
use crate::gpio::{Alternate, PushPull};
use crate::time::Hertz;
use crate::timer::Timer;
Expand All @@ -153,54 +156,99 @@ pub trait Pins<TIM> {
type Channels;
}

impl Pins<TIM2>
for (
PA0<Alternate<PushPull>>,
PA1<Alternate<PushPull>>,
PA2<Alternate<PushPull>>,
PA3<Alternate<PushPull>>,
)
{
const REMAP: u8 = 0b00;
const C1: bool = true;
const C2: bool = true;
const C3: bool = true;
const C4: bool = true;
type Channels = (Pwm<TIM2, C1>, Pwm<TIM2, C2>, Pwm<TIM2, C3>, Pwm<TIM2, C4>);
}

impl Pins<TIM3>
for (
PA6<Alternate<PushPull>>,
PA7<Alternate<PushPull>>,
PB0<Alternate<PushPull>>,
PB1<Alternate<PushPull>>,
)
{
const REMAP: u8 = 0b00;
const C1: bool = true;
const C2: bool = true;
const C3: bool = true;
const C4: bool = true;
type Channels = (Pwm<TIM3, C1>, Pwm<TIM3, C2>, Pwm<TIM3, C3>, Pwm<TIM3, C4>);


macro_rules! impl_pins {
// Expands to a struct that implements the Pins trait
// The syntax is a bit strange, but it should be generated by another
// macro anyway, so it's not a huge issue.
//
// 4 channels have to be specified as a comma separated list of $channel(...)
// Each active channel should have $pin, $channel, true; inside the parens
// Each inactive channel should have ;$unused_type, false inside
(
$( $channel:ident{
$($channel_:ty, $pin:ident, $true:expr)?
; $($unused_type:ty, $false:expr)?
}
),*
; for $timX:ident, $remap:expr
) => {
// Expand to a struct containing every active channel
impl Pins<$timX> for ( $( $( $pin<Alternate<PushPull>> )? $( $unused_type )?),* ) {
const REMAP: u8 = $remap;
// Set the channel active booleans to true or false depending on activity
$(
$(const $channel: bool = $true;)?
$(const $channel: bool = $false;)?
)*
// Create the Channels type
type Channels = ( $( $($channel_,)? )* );
}
}
}

impl Pins<TIM4>
for (
PB6<Alternate<PushPull>>,
PB7<Alternate<PushPull>>,
PB8<Alternate<PushPull>>,
PB9<Alternate<PushPull>>,
)
{
const REMAP: u8 = 0b0;
const C1: bool = true;
const C2: bool = true;
const C3: bool = true;
const C4: bool = true;
type Channels = (Pwm<TIM4, C1>, Pwm<TIM4, C2>, Pwm<TIM4, C3>, Pwm<TIM4, C4>);
// Private type representing unused pins to make the following macro more readable
type U = ();
macro_rules! impl_pin_combinations {
($( $channel:ident { $($pin:ident)?; $($unused_type:ident)? } ),* ; $timX:ident, $remap:expr) => {
impl_pins!{
$( $channel {
$($channel, $pin, true)?
; $($unused_type, false)?
}),*
; for $timX, $remap
}
};
// Implement all combinations of unused/used pins apart from all pins being unused
// as that case would lead to multiple definitions defining remaps
($p1:ident, $p2:ident, $p3:ident, $p4:ident; $timX:ident, $remap:expr) => {
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{$p3; }, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{$p3; }, C4{ ;U} ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{ ;U}, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{ ;U}, C4{ ;U} ; $timX, $remap);

impl_pin_combinations!(C1{$p1; }, C2{ ;U}, C3{$p3; }, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{ ;U}, C3{$p3; }, C4{ ;U} ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{ ;U}, C3{ ;U}, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{ ;U}, C3{ ;U}, C4{ ;U} ; $timX, $remap);

impl_pin_combinations!(C1{ ;U}, C2{$p2; }, C3{$p3; }, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{ ;U}, C2{$p2; }, C3{$p3; }, C4{ ;U} ; $timX, $remap);
impl_pin_combinations!(C1{ ;U}, C2{$p2; }, C3{ ;U}, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{ ;U}, C2{$p2; }, C3{ ;U}, C4{ ;U} ; $timX, $remap);

impl_pin_combinations!(C1{ ;U}, C2{ ;U}, C3{$p3; }, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{ ;U}, C2{ ;U}, C3{$p3; }, C4{ ;U} ; $timX, $remap);
impl_pin_combinations!(C1{ ;U}, C2{ ;U}, C3{ ;U}, C4{$p4; } ; $timX, $remap);
}
}
// Since some pins are shared between multiple remaps, the same impl would
// be defined multipel times if the full macro is used. Instead, we define
// another macro that only changes the lower, and upper pins. Again, we shouldn't
// set all varying pins to unused, as that would lead to re-definition of an impl
macro_rules! impl_partial_remap {
($p1:ident, $p2:ident, $p3:ident, $p4:ident; $timX:ident, $remap:expr) => {
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{$p3; }, C4{$p4; } ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{$p3; }, C4{ ;U} ; $timX, $remap);
impl_pin_combinations!(C1{$p1; }, C2{$p2; }, C3{ ;U}, C4{$p4; } ; $timX, $remap);
}
}


impl_pin_combinations!(PA0, PA1, PA2, PA3 ; TIM2, 0b00);
impl_partial_remap! (PA15, PB3, PA2, PA3 ; TIM2, 0b01);
impl_partial_remap! (PA0, PA1, PB10, PB11; TIM2, 0b10);
impl_pin_combinations!(PA15, PB3, PB10, PB11; TIM2, 0b11);

impl_pin_combinations!(PA6, PA7, PB0, PB1 ; TIM3, 0b00);
impl_partial_remap! (PB4, PB5, PB0, PB1 ; TIM3, 0b10);
impl_pin_combinations!(PC6, PC7, PC8, PC9 ; TIM3, 0b11);

impl_pin_combinations!(PB6, PB7, PB8, PB9 ; TIM4, 0b0);
impl_pin_combinations!(PD12, PD13, PD14, PD15 ; TIM4, 0b0);

impl Timer<TIM2> {
pub fn pwm<PINS, T>(
self,
Expand Down