-
Notifications
You must be signed in to change notification settings - Fork 62
Description
Hi,
I'm trying to change the frequency of a PWM pin dynamically. This is impossible with the currant API because the method to change the frequency is on the timer, but the timer contains all the pwm channels and when you 'associate' a pwm channel to a pin it is moved out of the timer struct. When you then try to configure the pwm frequency you get a 'borrow of partially moved value' error.
Example:
let mut pwm_timer = Timer::new(peripherals.TIM2, 100.hz(), &mut rcc);
let front_led_pwm_pin = pwm_timer.channel1.assign(gpioa.pa0);
// Some code
pwm_timer.set_frequency(10.hz(), &rcc);
Resulting in the following error:
error[E0382]: borrow of partially moved value: `pwm_timer`
--> src/main.rs:104:5
|
102 | let front_led_pwm_pin = pwm_timer.channel1.assign(gpioa.pa0);
| ----------------- `pwm_timer.channel1` partially moved due to this method call
103 |
104 | pwm_timer.set_frequency(10.hz(), &rcc);
| ^^^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `pwm_timer.channel1`
Workaround
I discussed this on the matrix channel a bit and I currently have two workarounds requiring unsafe:
-
Change the registers directly
unsafe { (*pac::TIM2::ptr()).psc.write(|w| w.bits(psc_val)); (*pac::TIM2::ptr()).arr.write(|w| w.bits(arr_val)); }
This works but you loose the niceties provided by the
set_frequency
function (e.g. provide a frequency in Hz). -
Make a raw pointer to the timer object to bypass Rust's ownership
let pwm_timer_ptr: *mut Timer<TIM2> = &mut pwm_timer; // Some code unsafe { (*pwm_timer_ptr).set_frequency(frequency.hz(), &context.rcc); }
This also compiles, however I'm not sure what the implications are. Is this "safe"? I guess it is as long as I don't try to associate the channel with another pin?
HAL crate
Would it be possible to support this use case in the HAL library to avoid the need to use unsafe
?
- Maybe this could be achieved by supporting changing the frequency from a
Pwm
instance? Although it would probably be very strange to have one Pwm instance change the frequency for all the other channels remotely. 🤔 - The other solution would involve some major changes because it would require the timer not to own the channels. I'm not sure what that involves.
What are your thoughts about this?