486: Pwm ppi events r=Dirbaio a=jacobrosenthal

More PWM yak shaving. I was going to do some safe pwm ppi events stuff but I just dont think it fits this api design.. ppi is just very low level, im not sure how safe it will be in general

* first we should probably have borrows of handlers for ppi with lifetime of the peripheral?  hal does eb4ba6ae42/nrf-hal-common/src/pwm.rs (L714-L716)
* in general having access to tasks can put the state in some configuration the api doesnt understand anymore. for `SequencePwm` ideally id hand you back either only seq_start0 or seq_start1 because youd only use one based on if your `Times` is even or odd.. but again we only know that with this api AFTER start has been called. I dont think were ready for typestates

SO I figured why not add the pwm ppi events but make them unsafe and commit this example since I started it.

Somewhat related drop IS removing the last duty cycle from the pin correctly, but stop DOES NOT..the only thing that sets the pin back is pin.conf() as far as I can tell, so I tried to document that better and got rid of stop for the `SimplePwm` again since that doesnt need it then. However its ackward we dont have a way to unset the pwm without setting a new sequence of 0s, or dropping the peripheral


Co-authored-by: Jacob Rosenthal <jacobrosenthal@gmail.com>
This commit is contained in:
bors[bot]
2021-11-26 23:08:24 +00:00
committed by GitHub
2 changed files with 206 additions and 37 deletions

View File

@ -0,0 +1,73 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![feature(array_from_fn)]
#[path = "../example_common.rs"]
mod example_common;
use core::future::pending;
use defmt::*;
use embassy::executor::Spawner;
use embassy_nrf::gpio::{Input, NoPin, Pull};
use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
use embassy_nrf::ppi::Ppi;
use embassy_nrf::pwm::{Prescaler, SequenceConfig, SequenceMode, SequencePwm};
use embassy_nrf::Peripherals;
#[embassy::main]
async fn main(_spawner: Spawner, p: Peripherals) {
let seq_values: [u16; 5] = [1000, 250, 100, 50, 0];
let mut config = SequenceConfig::default();
config.prescaler = Prescaler::Div128;
// 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8ms
// but say we want to hold the value for 250ms 250ms/8 = 31.25 periods
// so round to 31 - 1 (we get the one period for free remember)
// thus our sequence takes 5 * 250ms or 1.25 seconds
config.refresh = 30;
let pwm = unwrap!(SequencePwm::new(
p.PWM0,
p.P0_13,
NoPin,
NoPin,
NoPin,
config,
&seq_values
));
let _ = pwm.start(SequenceMode::Times(1));
// pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
// so its going to have to start running in order load the configuration
let button1 = InputChannel::new(
p.GPIOTE_CH0,
Input::new(p.P0_11, Pull::Up),
InputChannelPolarity::HiToLo,
);
let button2 = InputChannel::new(
p.GPIOTE_CH1,
Input::new(p.P0_12, Pull::Up),
InputChannelPolarity::HiToLo,
);
// messing with the pwm tasks is ill advised
// Times::Ininite and Times even are seq0, Times odd is seq1
let start = unsafe { pwm.task_start_seq0() };
let stop = unsafe { pwm.task_stop() };
let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button1.event_in(), start);
ppi.enable();
let mut ppi2 = Ppi::new_one_to_one(p.PPI_CH0, button2.event_in(), stop);
ppi2.enable();
info!("PPI setup!");
info!("Press button 1 to start LED 1");
info!("Press button 2 to stop LED 1");
info!("Note! task_stop stops the sequence, but not the pin output");
// Block forever so the above drivers don't get dropped
pending::<()>().await;
}