nrf: sequencepwm add events
This commit is contained in:
		
							parent
							
								
									0f322c1d4e
								
							
						
					
					
						commit
						2bcacd4f16
					
				| @ -9,6 +9,7 @@ use crate::gpio::sealed::Pin as _; | |||||||
| use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin}; | use crate::gpio::{AnyPin, OptionalPin as GpioOptionalPin}; | ||||||
| use crate::interrupt::Interrupt; | use crate::interrupt::Interrupt; | ||||||
| use crate::pac; | use crate::pac; | ||||||
|  | use crate::ppi::{Event, Task}; | ||||||
| use crate::util::slice_in_ram_or; | use crate::util::slice_in_ram_or; | ||||||
| 
 | 
 | ||||||
| /// SimplePwm is the traditional pwm interface you're probably used to, allowing
 | /// SimplePwm is the traditional pwm interface you're probably used to, allowing
 | ||||||
| @ -101,6 +102,13 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||||||
|         // Disable all interrupts
 |         // Disable all interrupts
 | ||||||
|         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |         r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||||||
|         r.shorts.reset(); |         r.shorts.reset(); | ||||||
|  |         r.events_stopped.reset(); | ||||||
|  |         r.events_loopsdone.reset(); | ||||||
|  |         r.events_seqend[0].reset(); | ||||||
|  |         r.events_seqend[1].reset(); | ||||||
|  |         r.events_pwmperiodend.reset(); | ||||||
|  |         r.events_seqstarted[0].reset(); | ||||||
|  |         r.events_seqstarted[1].reset(); | ||||||
| 
 | 
 | ||||||
|         r.seq0 |         r.seq0 | ||||||
|             .ptr |             .ptr | ||||||
| @ -200,6 +208,106 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Returns reference to `Stopped` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_stopped(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_stopped) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `LoopsDone` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_loops_done(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_loopsdone) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_pwm_period_end(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_pwmperiodend) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq0 End` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_seq_end(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_seqend[0]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq1 End` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_seq1_end(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_seqend[1]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq0 Started` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_seq0_started(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_seqstarted[0]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq1 Started` event endpoint for PPI.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub fn event_seq1_started(&self) -> Event { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Event::from_reg(&r.events_seqstarted[1]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq0 Start` task endpoint for PPI.
 | ||||||
|  |     /// # Safety
 | ||||||
|  |     ///
 | ||||||
|  |     /// Interacting with the sequence while it runs puts it in an unknown state
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn task_start_seq0(&self) -> Task { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Task::from_reg(&r.tasks_seqstart[0]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Seq1 Started` task endpoint for PPI.
 | ||||||
|  |     /// # Safety
 | ||||||
|  |     ///
 | ||||||
|  |     /// Interacting with the sequence while it runs puts it in an unknown state
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn task_start_seq1(&self) -> Task { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Task::from_reg(&r.tasks_seqstart[1]) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `NextStep` task endpoint for PPI.
 | ||||||
|  |     /// # Safety
 | ||||||
|  |     ///
 | ||||||
|  |     /// Interacting with the sequence while it runs puts it in an unknown state
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn task_next_step(&self) -> Task { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Task::from_reg(&r.tasks_nextstep) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns reference to `Stop` task endpoint for PPI.
 | ||||||
|  |     /// # Safety
 | ||||||
|  |     ///
 | ||||||
|  |     /// Interacting with the sequence while it runs puts it in an unknown state
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub unsafe fn task_stop(&self) -> Task { | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         Task::from_reg(&r.tasks_stop) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Stop playback.
 |     /// Stop playback.
 | ||||||
|     #[inline(always)] |     #[inline(always)] | ||||||
|     pub fn stop(&self) { |     pub fn stop(&self) { | ||||||
|  | |||||||
							
								
								
									
										73
									
								
								examples/nrf/src/bin/pwm_sequence_ppi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								examples/nrf/src/bin/pwm_sequence_ppi.rs
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user