Skip to content

Commit 4fd3ae6

Browse files
authored
Merge pull request #34 from IamfromSpace/pwm-channels
Pwm channels
2 parents 3e47e9b + 022eec8 commit 4fd3ae6

File tree

5 files changed

+1850
-2
lines changed

5 files changed

+1850
-2
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ debug = true
7575
lto = true
7676
opt-level = "s"
7777

78+
[[example]]
79+
name = "pwm"
80+
required-features = ["stm32f303xc"]
81+
7882
[[example]]
7983
name = "toggle"
8084
required-features = ["rt", "stm32f303xc"]

examples/pwm.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//! Example of using a number of timer channels in PWM mode.
2+
//! Target board: STM32F3DISCOVERY
3+
#![no_std]
4+
#![no_main]
5+
6+
extern crate panic_semihosting;
7+
8+
use cortex_m_rt::entry;
9+
//use cortex_m_semihosting::hprintln;
10+
use embedded_hal::PwmPin;
11+
use stm32f3::stm32f303;
12+
use stm32f3xx_hal::flash::FlashExt;
13+
use stm32f3xx_hal::gpio::GpioExt;
14+
use stm32f3xx_hal::pwm::{tim16, tim2, tim3, tim8};
15+
use stm32f3xx_hal::rcc::RccExt;
16+
use stm32f3xx_hal::time::U32Ext;
17+
18+
#[entry]
19+
fn main() -> ! {
20+
// Get our peripherals
21+
let dp = stm32f303::Peripherals::take().unwrap();
22+
23+
// Configure our clocks
24+
let mut flash = dp.FLASH.constrain();
25+
let mut rcc = dp.RCC.constrain();
26+
let clocks = rcc.cfgr.freeze(&mut flash.acr);
27+
28+
// Prep the pins we need in their correct alternate function
29+
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
30+
let pa4 = gpioa.pa4.into_af2(&mut gpioa.moder, &mut gpioa.afrl);
31+
let pa6 = gpioa.pa6.into_af2(&mut gpioa.moder, &mut gpioa.afrl);
32+
let pa7 = gpioa.pa7.into_af2(&mut gpioa.moder, &mut gpioa.afrl);
33+
34+
let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
35+
let pb0 = gpiob.pb0.into_af2(&mut gpiob.moder, &mut gpiob.afrl);
36+
let pb1 = gpiob.pb1.into_af2(&mut gpiob.moder, &mut gpiob.afrl);
37+
let pb3 = gpiob.pb3.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
38+
let pb4 = gpiob.pb4.into_af2(&mut gpiob.moder, &mut gpiob.afrl);
39+
let pb5 = gpiob.pb5.into_af2(&mut gpiob.moder, &mut gpiob.afrl);
40+
let pb7 = gpiob.pb7.into_af10(&mut gpiob.moder, &mut gpiob.afrl);
41+
let pb8 = gpiob.pb8.into_af1(&mut gpiob.moder, &mut gpiob.afrh);
42+
let pb10 = gpiob.pb10.into_af1(&mut gpiob.moder, &mut gpiob.afrh);
43+
44+
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb);
45+
let pc10 = gpioc.pc10.into_af4(&mut gpioc.moder, &mut gpioc.afrh);
46+
47+
// TIM3
48+
//
49+
// A four channel general purpose timer that's broadly available
50+
let tim3_channels = tim3(
51+
dp.TIM3,
52+
1280, // resolution of duty cycle
53+
50.hz(), // frequency of period
54+
&clocks, // To get the timer's clock speed
55+
);
56+
57+
// Channels without pins cannot be enabled, so we can't forget to
58+
// connect a pin.
59+
//
60+
// DOES NOT COMPILE
61+
// tim3_channels.0.enable();
62+
63+
// Each channel can be used with a different duty cycle and have many pins
64+
let mut tim3_ch1 = tim3_channels.0.output_to_pa6(pa6).output_to_pb4(pb4);
65+
tim3_ch1.set_duty(tim3_ch1.get_max_duty() / 20); // 5% duty cyle
66+
tim3_ch1.enable();
67+
68+
let mut tim3_ch2 = tim3_channels
69+
.1
70+
.output_to_pa4(pa4)
71+
.output_to_pa7(pa7)
72+
.output_to_pb5(pb5);
73+
tim3_ch2.set_duty(tim3_ch2.get_max_duty() / 40 * 3); // 7.5% duty cyle
74+
tim3_ch2.enable();
75+
76+
let mut tim3_ch3 = tim3_channels.2.output_to_pb0(pb0);
77+
tim3_ch3.set_duty(tim3_ch3.get_max_duty() / 50 * 3); // 6% duty cyle
78+
tim3_ch3.enable();
79+
80+
let mut tim3_ch4 = tim3_channels.3.output_to_pb1(pb1).output_to_pb7(pb7);
81+
tim3_ch4.set_duty(tim3_ch4.get_max_duty() / 10); // 10% duty cyle
82+
tim3_ch4.enable();
83+
84+
// We can only add valid pins, so we can't do this:
85+
//
86+
// DOES NOT COMPILE
87+
// tim3_ch1.output_to_pb8(pb8);
88+
89+
// The pins that we've used are given away so they can't be
90+
// accidentaly modified. This line would "disconnect" our pin
91+
// from the channel.
92+
//
93+
// DOES NOT COMPILE
94+
// pb0.into_af15(&mut gpiob.moder, &mut gpiob.afrl);
95+
96+
// TIM2
97+
//
98+
// A 32-bit timer, so we can set a larger resolution
99+
let tim2_channels = tim2(
100+
dp.TIM2,
101+
160000, // resolution of duty cycle
102+
50.hz(), // frequency of period
103+
&clocks, // To get the timer's clock speed
104+
);
105+
106+
let mut tim2_ch3 = tim2_channels.2.output_to_pb10(pb10);
107+
tim2_ch3.set_duty(tim2_ch3.get_max_duty() / 20); // 5% duty cyle
108+
tim2_ch3.enable();
109+
110+
// TIM16
111+
//
112+
// A single channel timer, so it doesn't return a tuple. We can
113+
// just use it directly
114+
let mut tim16_ch1 = tim16(
115+
dp.TIM16,
116+
1280, // resolution of duty cycle
117+
50.hz(), // frequency of period
118+
&clocks, // To get the timer's clock speed
119+
)
120+
.output_to_pb8(pb8);
121+
tim16_ch1.set_duty(tim16_ch1.get_max_duty() / 20); // 5% duty cyle
122+
tim16_ch1.enable();
123+
124+
// TIM8
125+
//
126+
// An advanced timer with complementary outputs, so we can output
127+
// to complementary pins (works just like standard pins)
128+
let tim8_channels = tim8(
129+
dp.TIM8,
130+
1280, // resolution of duty cycle
131+
50.hz(), // frequency of period
132+
&clocks, // To get the timer's clock speed
133+
);
134+
135+
let mut tim8_ch1 = tim8_channels.0.output_to_pb3(pb3).output_to_pc10(pc10);
136+
tim8_ch1.set_duty(tim8_ch1.get_max_duty() / 10); // 10% duty cyle
137+
tim8_ch1.enable();
138+
139+
// Once we select PB3, we can only use complementary pins (such as
140+
// PC10). These are pins with alternate functions with an 'N' at
141+
// the end of the channel (such as TIM8_CH1N) in the reference
142+
// manual. If we had selected a non-complementary pin first, we
143+
// would not be able to use PB3 or PC10 (or PA7 which is aready in
144+
// use).
145+
//
146+
// DOES NOT COMPILE
147+
// tim8_ch1.output_to_pc6(gpioc.pc6.into_af4(&mut gpioc.moder, &mut gpioc.afrl));
148+
149+
loop {}
150+
}

src/gpio.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,14 @@ gpio!([
12621262
AF7: (into_af7, 7,),
12631263
AF15: (into_af15, 15,),
12641264
], []),
1265+
PB11: (pb11, 11, Input<Floating>, AFRH, [
1266+
AF1: (into_af1, 1,),
1267+
AF3: (into_af3, 3,),
1268+
AF5: (into_af5, 5,),
1269+
AF6: (into_af6, 6,),
1270+
AF7: (into_af7, 7,),
1271+
AF15: (into_af15, 15,),
1272+
], []),
12651273
PB14: (pb14, 14, Input<Floating>, AFRH, [
12661274
AF1: (into_af1, 1,),
12671275
AF3: (into_af3, 3,),
@@ -1306,7 +1314,7 @@ gpio!([
13061314
]),
13071315
PC1: (pc1, 1, Input<Floating>, AFRL, [], [
13081316
AF1: (into_af1, 1, ["stm32f301", "stm32f373", "stm32f378", "stm32f358", "stm32f398",],),
1309-
AF2: (into_af2, 2, ["stm32f301", "stm32f373", "stm32f378", "stm32f398",],),
1317+
AF2: (into_af2, 2, ["stm32f301", "stm32f373", "stm32f378", "stm32f334", "stm32f398",],),
13101318
]),
13111319
PC2: (pc2, 2, Input<Floating>, AFRL, [], [
13121320
AF1: (into_af1, 1, ["stm32f301", "stm32f373", "stm32f378", "stm32f334", "stm32f358", "stm32f398",],),
@@ -1394,7 +1402,7 @@ gpio!([
13941402
]),
13951403
PC13: (pc13, 13, Input<Floating>, AFRH, [], [
13961404
AF1: (into_af1, 1, ["stm32f378", "stm32f398",],),
1397-
AF4: (into_af4, 4, ["stm32f301", "stm32f334", "stm32f328", "stm32f358", "stm32f398",],),
1405+
AF4: (into_af4, 4, ["stm32f301", "stm32f318", "stm32f334", "stm32f328", "stm32f358", "stm32f398",],),
13981406
]),
13991407
PC14: (pc14, 14, Input<Floating>, AFRH, [], [
14001408
AF1: (into_af1, 1, ["stm32f378", "stm32f398",],),

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub mod i2c;
6060
#[cfg(feature = "device-selected")]
6161
pub mod prelude;
6262
#[cfg(feature = "device-selected")]
63+
pub mod pwm;
64+
#[cfg(feature = "device-selected")]
6365
pub mod rcc;
6466
#[cfg(feature = "device-selected")]
6567
pub mod serial;

0 commit comments

Comments
 (0)