aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrafael <[email protected]>2024-10-20 23:28:47 +0200
committerrafael <[email protected]>2024-10-20 23:28:47 +0200
commit7fc09f89e8e4b611a868bc986104762b1c5ba81a (patch)
tree727067bbaced3aa804eb9145dd21717e37bd95aa
parentc9358e1f1e5d88aa0ad998c44eb2da6be73cf477 (diff)
embassy_rp: implement pwm traits from embedded_hal
• Update crate versions • Implement embedded-hal PWM traits • Add TB6612FNG motor driver example
-rw-r--r--embassy-rp/Cargo.toml8
-rw-r--r--embassy-rp/src/pwm.rs42
-rw-r--r--examples/rp23/Cargo.toml3
-rw-r--r--examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs114
4 files changed, 163 insertions, 4 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 54de238b3..baa92398b 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -118,18 +118,18 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
118atomic-polyfill = "1.0.1" 118atomic-polyfill = "1.0.1"
119defmt = { version = "0.3", optional = true } 119defmt = { version = "0.3", optional = true }
120log = { version = "0.4.14", optional = true } 120log = { version = "0.4.14", optional = true }
121nb = "1.0.0" 121nb = "1.1.0"
122cfg-if = "1.0.0" 122cfg-if = "1.0.0"
123cortex-m-rt = ">=0.6.15,<0.8" 123cortex-m-rt = ">=0.6.15,<0.8"
124cortex-m = "0.7.6" 124cortex-m = "0.7.6"
125critical-section = "1.1" 125critical-section = "1.2.0"
126chrono = { version = "0.4", default-features = false, optional = true } 126chrono = { version = "0.4", default-features = false, optional = true }
127embedded-io = { version = "0.6.1" } 127embedded-io = { version = "0.6.1" }
128embedded-io-async = { version = "0.6.1" } 128embedded-io-async = { version = "0.6.1" }
129embedded-storage = { version = "0.3" } 129embedded-storage = { version = "0.3" }
130embedded-storage-async = { version = "0.4.1" } 130embedded-storage-async = { version = "0.4.1" }
131rand_core = "0.6.4" 131rand_core = "0.6.4"
132fixed = "1.23.1" 132fixed = "1.28.0"
133 133
134rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] } 134rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] }
135 135
@@ -141,7 +141,7 @@ embedded-hal-nb = { version = "1.0" }
141pio-proc = {version= "0.2" } 141pio-proc = {version= "0.2" }
142pio = {version= "0.2.1" } 142pio = {version= "0.2.1" }
143rp2040-boot2 = "0.3" 143rp2040-boot2 = "0.3"
144document-features = "0.2.7" 144document-features = "0.2.10"
145sha2-const-stable = "0.1" 145sha2-const-stable = "0.1"
146rp-binary-info = { version = "0.1.0", optional = true } 146rp-binary-info = { version = "0.1.0", optional = true }
147smart-leds = "0.4.0" 147smart-leds = "0.4.0"
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 027f5504e..79e626802 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -1,6 +1,7 @@
1//! Pulse Width Modulation (PWM) 1//! Pulse Width Modulation (PWM)
2 2
3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
4use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType, SetDutyCycle};
4use fixed::traits::ToFixed; 5use fixed::traits::ToFixed;
5use fixed::FixedU16; 6use fixed::FixedU16;
6use pac::pwm::regs::{ChDiv, Intr}; 7use pac::pwm::regs::{ChDiv, Intr};
@@ -80,6 +81,21 @@ impl From<InputMode> for Divmode {
80 } 81 }
81} 82}
82 83
84/// PWM error.
85#[derive(Debug)]
86pub enum PwmError {
87 /// Invalid Duty Cycle.
88 InvalidDutyCycle,
89}
90
91impl Error for PwmError {
92 fn kind(&self) -> ErrorKind {
93 match self {
94 PwmError::InvalidDutyCycle => ErrorKind::Other,
95 }
96 }
97}
98
83/// PWM driver. 99/// PWM driver.
84pub struct Pwm<'d> { 100pub struct Pwm<'d> {
85 pin_a: Option<PeripheralRef<'d, AnyPin>>, 101 pin_a: Option<PeripheralRef<'d, AnyPin>>,
@@ -87,6 +103,32 @@ pub struct Pwm<'d> {
87 slice: usize, 103 slice: usize,
88} 104}
89 105
106impl<'d> ErrorType for Pwm<'d> {
107 type Error = PwmError;
108}
109
110impl<'d> SetDutyCycle for Pwm<'d> {
111 fn max_duty_cycle(&self) -> u16 {
112 pac::PWM.ch(self.slice).top().read().top()
113 }
114
115 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
116 info!("duty {}",&duty);
117 let max_duty = self.max_duty_cycle();
118 info!("max duty {}", &max_duty);
119 if duty > max_duty {
120 return Err(PwmError::InvalidDutyCycle);
121 }
122
123 let p = pac::PWM.ch(self.slice);
124 p.cc().modify(|w| {
125 w.set_a(duty);
126 w.set_b(duty);
127 });
128 Ok(())
129 }
130}
131
90impl<'d> Pwm<'d> { 132impl<'d> Pwm<'d> {
91 fn new_inner( 133 fn new_inner(
92 slice: usize, 134 slice: usize,
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
index 08646463c..f35e3a11d 100644
--- a/examples/rp23/Cargo.toml
+++ b/examples/rp23/Cargo.toml
@@ -30,6 +30,9 @@ serde-json-core = "0.5.1"
30# for assign resources example 30# for assign resources example
31assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } 31assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
32 32
33# for TB6612FNG example
34tb6612fng = "1.0.0"
35
33#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 36#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
34cortex-m = { version = "0.7.6", features = ["inline-asm"] } 37cortex-m = { version = "0.7.6", features = ["inline-asm"] }
35cortex-m-rt = "0.7.0" 38cortex-m-rt = "0.7.0"
diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs
new file mode 100644
index 000000000..92c1ff6ba
--- /dev/null
+++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs
@@ -0,0 +1,114 @@
1//! # PWM TB6612FNG motor driver
2//!
3//! This example shows the use of a TB6612FNG motor driver. The driver is built on top of embedded_hal and the example demonstrates how embassy_rp can be used to interact with ist.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::config::Config;
12use embassy_rp::gpio::Output;
13use embassy_rp::peripherals;
14use embassy_rp::gpio;
15use embassy_rp::pwm;
16use embassy_time::Duration;
17use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _};
19use tb6612fng::{DriveCommand, Motor, Tb6612fng};
20use assign_resources::assign_resources;
21
22/// Maximum PWM value (fully on)
23const PWM_MAX: u16 = 50000;
24
25/// Minimum PWM value (fully off)
26const PWM_MIN: u16 = 0;
27
28#[link_section = ".start_block"]
29#[used]
30pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
31
32assign_resources! {
33 motor: MotorResources {
34 standby_pin: PIN_22,
35 left_slice: PWM_SLICE6,
36 left_pwm_pin: PIN_28,
37 left_forward_pin: PIN_21,
38 left_backward_pin: PIN_20,
39 right_slice: PWM_SLICE5,
40 right_pwm_pin: PIN_27,
41 right_forward_pin: PIN_19,
42 right_backward_pin: PIN_18,
43 },
44}
45
46#[embassy_executor::main]
47async fn main(_spawner: Spawner) {
48 let p = embassy_rp::init(Config::default());
49 let s = split_resources!(p);
50 let r = s.motor;
51
52 // we need a standby output and two motors to construct a full TB6612FNG
53
54 // standby pin
55 let stby = Output::new(r.standby_pin, gpio::Level::Low);
56
57 // motor A, here defined to be the left motor
58 let left_fwd = gpio::Output::new(r.left_forward_pin, gpio::Level::Low);
59 let left_bckw = gpio::Output::new(r.left_backward_pin, gpio::Level::Low);
60 let mut left_speed = pwm::Config::default();
61 left_speed.top = PWM_MAX;
62 left_speed.compare_a = PWM_MIN;
63 let left_pwm = pwm::Pwm::new_output_a(r.left_slice, r.left_pwm_pin, left_speed);
64 let left_motor = Motor::new(left_fwd, left_bckw, left_pwm).unwrap();
65
66 // motor B, here defined to be the right motor
67 let right_fwd = gpio::Output::new(r.right_forward_pin, gpio::Level::Low);
68 let right_bckw = gpio::Output::new(r.right_backward_pin, gpio::Level::Low);
69 let mut right_speed = pwm::Config::default();
70 right_speed.top = PWM_MAX;
71 right_speed.compare_b = PWM_MIN;
72 let right_pwm = pwm::Pwm::new_output_b(r.right_slice, r.right_pwm_pin, right_speed);
73 let right_motor = Motor::new(right_fwd, right_bckw, right_pwm).unwrap();
74
75 // construct the motor driver
76 let mut control = Tb6612fng::new(left_motor, right_motor, stby).unwrap();
77
78 loop {
79 // wake up the motor driver
80 info!("end standby");
81 control.disable_standby().unwrap();
82 Timer::after(Duration::from_millis(100)).await;
83
84 // drive a straight line forward at 20% speed for 5s
85 info!("drive straight");
86 control.motor_a.drive(DriveCommand::Forward(20)).unwrap();
87 control.motor_b.drive(DriveCommand::Forward(20)).unwrap();
88 Timer::after(Duration::from_secs(5)).await;
89
90 // coast for 2s
91 info!("coast");
92 control.motor_a.drive(DriveCommand::Stop).unwrap();
93 control.motor_b.drive(DriveCommand::Stop).unwrap();
94 Timer::after(Duration::from_secs(2)).await;
95
96 // actively brake
97 info!("brake");
98 control.motor_a.drive(DriveCommand::Brake).unwrap();
99 control.motor_b.drive(DriveCommand::Brake).unwrap();
100 Timer::after(Duration::from_secs(1)).await;
101
102 // slowly turn for 3s
103 info!( "turn");
104 control.motor_a.drive(DriveCommand::Backward(10)).unwrap();
105 control.motor_b.drive(DriveCommand::Forward(10)).unwrap();
106 Timer::after(Duration::from_secs(3)).await;
107
108 // and put the driver in standby mode and wait for 5s
109 info!( "standby");
110 control.enable_standby().unwrap();
111 Timer::after(Duration::from_secs(5)).await;
112 }
113}
114