Skip to content

Commit 05e9308

Browse files
committed
PWM example
1 parent 236a82f commit 05e9308

File tree

5 files changed

+238
-92
lines changed

5 files changed

+238
-92
lines changed

e310x-hal/src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use embedded_hal::{
1414
delay::DelayNs,
1515
digital::{InputPin, OutputPin, StatefulOutputPin},
1616
i2c::I2c,
17+
pwm::SetDutyCycle,
1718
spi::{SpiBus, SpiDevice},
1819
};
1920

e310x-hal/src/pwm.rs

Lines changed: 116 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
//! You can use the `PWM` with these [Pwm] instances
44
//!
55
//! # PWM0 - 8 bit period and duty
6-
//! - Channel 1: Pin 9 IOF1
7-
//! - Channel 2: Pin 10 IOF1
8-
//! - Channel 3: Pin 11 IOF1
6+
//! - Channel 1: Pin 1 IOF1
7+
//! - Channel 2: Pin 2 IOF1
8+
//! - Channel 3: Pin 3 IOF1
99
//!
1010
//! # PWM1 - 16 bit period and duty
11-
//! - Channel 1: Pin 3 IOF1
12-
//! - Channel 2: Pin 5 IOF1
13-
//! - Channel 3: Pin 6 IOF1
11+
//! - Channel 1: Pin 19 IOF1
12+
//! - Channel 2: Pin 21 IOF1
13+
//! - Channel 3: Pin 22 IOF1
1414
//!
1515
//! # PWM2 - 16 bit period and duty
16-
//! - Channel 1: Pin 17 IOF1
17-
//! - Channel 2: Pin 18 IOF1
18-
//! - Channel 3: Pin 19 IOF1
19-
20-
use core::{marker::PhantomData, ops::Deref};
16+
//! - Channel 1: Pin 11 IOF1
17+
//! - Channel 2: Pin 12 IOF1
18+
//! - Channel 3: Pin 13 IOF1
2119
20+
use core::ops::Deref;
2221
use e310x::{pwm0, Pwm0, Pwm1, Pwm2};
22+
use embedded_hal::pwm::{ErrorKind, ErrorType, SetDutyCycle};
2323

2424
/// PWM comparator index
2525
#[derive(Copy, Clone)]
@@ -33,71 +33,53 @@ pub enum CmpIndex {
3333
}
3434

3535
/// PWM pin
36-
pub trait Pin<PWM>: private::Sealed {
36+
pub trait Pin<PWM: PwmX>: private::Sealed {
3737
/// Channel index associated with the pin
3838
const CMP_INDEX: CmpIndex;
3939
}
4040

4141
mod pwm_impl {
4242
use super::{CmpIndex, Pin, Pwm0, Pwm1, Pwm2};
43-
use crate::gpio::{gpio0, NoInvert, IOF1};
43+
use crate::gpio::{gpio0, Invert, IOF1};
4444

4545
// PWM0
46-
impl Pin<Pwm0> for gpio0::Pin1<IOF1<NoInvert>> {
46+
impl Pin<Pwm0> for gpio0::Pin1<IOF1<Invert>> {
4747
const CMP_INDEX: CmpIndex = CmpIndex::Cmp1;
4848
}
49-
impl Pin<Pwm0> for gpio0::Pin2<IOF1<NoInvert>> {
49+
impl Pin<Pwm0> for gpio0::Pin2<IOF1<Invert>> {
5050
const CMP_INDEX: CmpIndex = CmpIndex::Cmp2;
5151
}
52-
impl Pin<Pwm0> for gpio0::Pin3<IOF1<NoInvert>> {
52+
impl Pin<Pwm0> for gpio0::Pin3<IOF1<Invert>> {
5353
const CMP_INDEX: CmpIndex = CmpIndex::Cmp3;
5454
}
5555

5656
// PWM1
57-
impl Pin<Pwm1> for gpio0::Pin19<IOF1<NoInvert>> {
57+
impl Pin<Pwm1> for gpio0::Pin19<IOF1<Invert>> {
5858
const CMP_INDEX: CmpIndex = CmpIndex::Cmp1;
5959
}
60-
impl Pin<Pwm1> for gpio0::Pin21<IOF1<NoInvert>> {
60+
impl Pin<Pwm1> for gpio0::Pin21<IOF1<Invert>> {
6161
const CMP_INDEX: CmpIndex = CmpIndex::Cmp2;
6262
}
63-
impl Pin<Pwm1> for gpio0::Pin22<IOF1<NoInvert>> {
63+
impl Pin<Pwm1> for gpio0::Pin22<IOF1<Invert>> {
6464
const CMP_INDEX: CmpIndex = CmpIndex::Cmp3;
6565
}
6666

6767
// PWM2
68-
impl Pin<Pwm2> for gpio0::Pin11<IOF1<NoInvert>> {
68+
impl Pin<Pwm2> for gpio0::Pin11<IOF1<Invert>> {
6969
const CMP_INDEX: CmpIndex = CmpIndex::Cmp1;
7070
}
71-
impl Pin<Pwm2> for gpio0::Pin12<IOF1<NoInvert>> {
71+
impl Pin<Pwm2> for gpio0::Pin12<IOF1<Invert>> {
7272
const CMP_INDEX: CmpIndex = CmpIndex::Cmp2;
7373
}
74-
impl Pin<Pwm2> for gpio0::Pin13<IOF1<NoInvert>> {
74+
impl Pin<Pwm2> for gpio0::Pin13<IOF1<Invert>> {
7575
const CMP_INDEX: CmpIndex = CmpIndex::Cmp3;
7676
}
7777
}
7878

79-
/// PWM channel
80-
#[derive(Copy, Clone)]
81-
pub struct Channel<PWM> {
82-
_pwm: PhantomData<PWM>,
83-
cmp_index: CmpIndex,
84-
}
85-
86-
impl<PWM> Channel<PWM> {
87-
/// Constructs a PWM channel from a PWM pin for use with [Pwm]
88-
pub fn from<PIN: Pin<PWM>>(_: PIN) -> Channel<PWM> {
89-
Channel {
90-
_pwm: PhantomData,
91-
cmp_index: PIN::CMP_INDEX,
92-
}
93-
}
94-
}
95-
9679
/// PwmX trait extends the PWM peripherals
9780
#[doc(hidden)]
9881
pub trait PwmX: Deref<Target = pwm0::RegisterBlock> + private::Sealed {
9982
type CmpWidth: Ord;
100-
fn peripheral() -> Self;
10183
fn bits_from_cmp_width(other: Self::CmpWidth) -> u32;
10284
fn bits_into_cmp_width(other: u32) -> Self::CmpWidth;
10385
}
@@ -106,9 +88,6 @@ macro_rules! pwmx_impl {
10688
($PWM:ident,$CMP_WIDTH:ident) => {
10789
impl PwmX for $PWM {
10890
type CmpWidth = $CMP_WIDTH;
109-
fn peripheral() -> Self {
110-
unsafe { Self::steal() }
111-
}
11291
fn bits_from_cmp_width(other: Self::CmpWidth) -> u32 {
11392
other as u32
11493
}
@@ -152,103 +131,148 @@ impl<PWM: PwmX> Pwm<PWM> {
152131
Self { pwm }
153132
}
154133

134+
/// Frees the PWM device
135+
pub fn free(self) -> PWM {
136+
self.pwm
137+
}
138+
139+
/// Returns the period of the PWM
140+
pub fn get_period(&self) -> PWM::CmpWidth {
141+
PWM::bits_into_cmp_width(self.pwm.cmp0().read().bits())
142+
}
143+
144+
/// Sets the period of the PWM
145+
pub fn set_period(&mut self, period: PWM::CmpWidth) {
146+
let period = PWM::bits_from_cmp_width(period);
147+
self.pwm.count().reset();
148+
self.pwm.cmp0().write(|w| unsafe { w.bits(period) });
149+
}
150+
151+
/// Returns the duty cycle of the PWM
152+
fn get_duty(&self, cmp_index: CmpIndex) -> PWM::CmpWidth {
153+
let duty = match cmp_index {
154+
CmpIndex::Cmp1 => self.pwm.cmp1().read().bits(),
155+
CmpIndex::Cmp2 => self.pwm.cmp2().read().bits(),
156+
CmpIndex::Cmp3 => self.pwm.cmp3().read().bits(),
157+
};
158+
PWM::bits_into_cmp_width(duty)
159+
}
160+
161+
/// Sets the duty cycle of the PWM
162+
fn set_duty(&self, cmp_index: CmpIndex, duty: PWM::CmpWidth) {
163+
let duty = PWM::bits_from_cmp_width(duty.min(self.get_period()));
164+
match cmp_index {
165+
CmpIndex::Cmp1 => self.pwm.cmp1().write(|w| unsafe { w.bits(duty) }),
166+
CmpIndex::Cmp2 => self.pwm.cmp2().write(|w| unsafe { w.bits(duty) }),
167+
CmpIndex::Cmp3 => self.pwm.cmp3().write(|w| unsafe { w.bits(duty) }),
168+
}
169+
}
170+
155171
/// Enables the PWM channel
156-
pub fn enable(&mut self, channel: &Channel<PWM>) {
157-
match channel.cmp_index {
172+
fn enable(&self, cmp_index: CmpIndex) {
173+
match cmp_index {
158174
CmpIndex::Cmp1 => self.pwm.cmp1().write(|w| unsafe { w.bits(u32::MAX) }),
159175
CmpIndex::Cmp2 => self.pwm.cmp2().write(|w| unsafe { w.bits(u32::MAX) }),
160176
CmpIndex::Cmp3 => self.pwm.cmp3().write(|w| unsafe { w.bits(u32::MAX) }),
161177
}
162178
}
163179

164180
/// Disables the PWM channel
165-
pub fn disable(&mut self, channel: &Channel<PWM>) {
166-
match channel.cmp_index {
181+
fn disable(&self, cmp_index: CmpIndex) {
182+
match cmp_index {
167183
CmpIndex::Cmp1 => self.pwm.cmp1().reset(),
168184
CmpIndex::Cmp2 => self.pwm.cmp2().reset(),
169185
CmpIndex::Cmp3 => self.pwm.cmp3().reset(),
170186
}
171187
}
172188

189+
/// Returns the PWM channel associated with the given index
190+
pub fn channel<PIN: Pin<PWM>>(&self, pin: PIN) -> Channel<'_, PWM, PIN> {
191+
Channel { pwm: self, pin }
192+
}
193+
}
194+
195+
/// PWM channel
196+
pub struct Channel<'a, PWM, PIN> {
197+
pwm: &'a Pwm<PWM>,
198+
pin: PIN,
199+
}
200+
201+
impl<'a, PWM, PIN> Channel<'a, PWM, PIN> {
202+
/// Frees the PWM channel
203+
pub fn free(self) -> PIN {
204+
self.pin
205+
}
206+
}
207+
208+
impl<'a, PWM: PwmX, PIN: Pin<PWM>> Channel<'a, PWM, PIN> {
173209
/// Returns the period of the PWM
174210
pub fn get_period(&self) -> PWM::CmpWidth {
175-
PWM::bits_into_cmp_width(self.pwm.cmp0().read().bits())
211+
self.pwm.get_period()
212+
}
213+
214+
/// Returns the maximum duty cycle of the PWM (equal to the period)
215+
pub fn max_duty(&self) -> PWM::CmpWidth {
216+
self.pwm.get_period()
176217
}
177218

178219
/// Returns the duty cycle of the PWM
179-
pub fn get_duty(&self, channel: &Channel<PWM>) -> PWM::CmpWidth {
180-
let duty = match channel.cmp_index {
181-
CmpIndex::Cmp1 => self.pwm.cmp1().read().bits(),
182-
CmpIndex::Cmp2 => self.pwm.cmp2().read().bits(),
183-
CmpIndex::Cmp3 => self.pwm.cmp3().read().bits(),
184-
};
185-
PWM::bits_into_cmp_width(duty)
220+
pub fn get_duty(&self) -> PWM::CmpWidth {
221+
self.pwm.get_duty(PIN::CMP_INDEX)
186222
}
187223

188-
/// Returns the maximum duty cycle of the PWM (equal to the period)
189-
pub fn get_max_duty(&self) -> PWM::CmpWidth {
190-
self.get_period()
224+
/// Sets the duty cycle to 100%
225+
pub fn enable(&mut self) {
226+
self.pwm.enable(PIN::CMP_INDEX);
191227
}
192228

193-
/// Sets the duty cycle of the PWM
194-
pub fn set_duty(&mut self, channel: &Channel<PWM>, duty: PWM::CmpWidth) {
195-
let duty = PWM::bits_from_cmp_width(duty.min(self.get_max_duty()));
196-
match channel.cmp_index {
197-
CmpIndex::Cmp1 => self.pwm.cmp1().write(|w| unsafe { w.bits(duty) }),
198-
CmpIndex::Cmp2 => self.pwm.cmp2().write(|w| unsafe { w.bits(duty) }),
199-
CmpIndex::Cmp3 => self.pwm.cmp3().write(|w| unsafe { w.bits(duty) }),
200-
}
229+
/// Sets the duty cycle to 0%
230+
pub fn disable(&mut self) {
231+
self.pwm.disable(PIN::CMP_INDEX);
201232
}
202233

203-
/// Sets the period of the PWM
204-
pub fn set_period(&mut self, period: PWM::CmpWidth) {
205-
let period = PWM::bits_from_cmp_width(period);
206-
self.pwm.count().reset();
207-
self.pwm.cmp0().write(|w| unsafe { w.bits(period) });
234+
/// Sets the duty cycle of the PWM
235+
pub fn set_duty(&mut self, duty: PWM::CmpWidth) {
236+
self.pwm.set_duty(PIN::CMP_INDEX, duty);
208237
}
209238
}
210239

211-
impl<PWM: PwmX> embedded_hal::pwm::ErrorType for Channel<PWM> {
212-
type Error = embedded_hal::pwm::ErrorKind;
240+
impl<'a, PWM: PwmX, PIN: Pin<PWM>> ErrorType for Channel<'a, PWM, PIN> {
241+
type Error = ErrorKind;
213242
}
214243

215-
impl<PWM: PwmX> embedded_hal::pwm::SetDutyCycle for Channel<PWM> {
244+
impl<'a, PWM: PwmX, PIN: Pin<PWM>> SetDutyCycle for Channel<'a, PWM, PIN> {
216245
fn max_duty_cycle(&self) -> u16 {
217-
let pwm: Pwm<PWM> = Pwm {
218-
pwm: PWM::peripheral(),
219-
};
220-
PWM::bits_from_cmp_width(pwm.get_max_duty()) as _
246+
PWM::bits_from_cmp_width(self.max_duty()) as _
221247
}
222248

223249
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
224-
let mut pwm: Pwm<PWM> = Pwm {
225-
pwm: PWM::peripheral(),
226-
};
227-
pwm.set_duty(self, PWM::bits_into_cmp_width(duty as _));
250+
self.pwm
251+
.set_duty(PIN::CMP_INDEX, PWM::bits_into_cmp_width(duty as _));
228252
Ok(())
229253
}
230254
}
231255

232256
mod private {
233257
use super::{Pwm0, Pwm1, Pwm2};
234-
use crate::gpio::{gpio0, NoInvert, IOF1};
258+
use crate::gpio::{gpio0, Invert, IOF1};
235259
pub trait Sealed {}
236260

237261
// PWM0
238262
impl Sealed for Pwm0 {}
239-
impl Sealed for gpio0::Pin1<IOF1<NoInvert>> {}
240-
impl Sealed for gpio0::Pin2<IOF1<NoInvert>> {}
241-
impl Sealed for gpio0::Pin3<IOF1<NoInvert>> {}
263+
impl Sealed for gpio0::Pin1<IOF1<Invert>> {}
264+
impl Sealed for gpio0::Pin2<IOF1<Invert>> {}
265+
impl Sealed for gpio0::Pin3<IOF1<Invert>> {}
242266

243267
// PWM1
244268
impl Sealed for Pwm1 {}
245-
impl Sealed for gpio0::Pin19<IOF1<NoInvert>> {}
246-
impl Sealed for gpio0::Pin21<IOF1<NoInvert>> {}
247-
impl Sealed for gpio0::Pin22<IOF1<NoInvert>> {}
269+
impl Sealed for gpio0::Pin19<IOF1<Invert>> {}
270+
impl Sealed for gpio0::Pin21<IOF1<Invert>> {}
271+
impl Sealed for gpio0::Pin22<IOF1<Invert>> {}
248272

249273
// PWM2
250274
impl Sealed for Pwm2 {}
251-
impl Sealed for gpio0::Pin11<IOF1<NoInvert>> {}
252-
impl Sealed for gpio0::Pin12<IOF1<NoInvert>> {}
253-
impl Sealed for gpio0::Pin13<IOF1<NoInvert>> {}
275+
impl Sealed for gpio0::Pin11<IOF1<Invert>> {}
276+
impl Sealed for gpio0::Pin12<IOF1<Invert>> {}
277+
impl Sealed for gpio0::Pin13<IOF1<Invert>> {}
254278
}

hifive1-examples/examples/button_poll.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
//! Example of polling a button and turning on a LED when the button is pressed.
2+
//!
3+
//! # Hardware
4+
//!
5+
//! - HiFive1 or RED-V board
6+
//! - A button connected to pin 9
27
38
#![no_std]
49
#![no_main]

0 commit comments

Comments
 (0)