aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2020-09-29 19:18:52 +0200
committerDario Nieuwenhuis <[email protected]>2020-09-29 19:18:52 +0200
commit33dce24e8a87070417c0905f6639e9952f26c602 (patch)
tree6319e7cf4e62b85225e62bed1efe80ac60261050
parentc81d626254d4c27e7412d192eb1cb6b6bea2648a (diff)
Add gpiote output channel.
-rw-r--r--embassy-nrf/src/gpiote.rs160
1 files changed, 128 insertions, 32 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index b9a1f6132..5195f926a 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -1,13 +1,17 @@
1use core::cell::Cell; 1use core::cell::Cell;
2use core::pin::Pin;
3use core::ptr; 2use core::ptr;
4use defmt::trace; 3use defmt::trace;
5use embassy::util::Signal; 4use embassy::util::Signal;
6use nrf52840_hal::gpio::{Floating, Input, Pin as GpioPin, Port}; 5use nrf52840_hal::gpio::{Input, Level, Output, Pin, Port};
7 6
8use crate::interrupt; 7use crate::interrupt;
8use crate::pac::generic::Reg;
9use crate::pac::gpiote::_TASKS_OUT;
9use crate::pac::GPIOTE; 10use crate::pac::GPIOTE;
10 11
12#[cfg(not(feature = "51"))]
13use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET};
14
11pub struct Gpiote { 15pub struct Gpiote {
12 inner: GPIOTE, 16 inner: GPIOTE,
13 free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself. 17 free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself.
@@ -23,6 +27,13 @@ pub enum EventPolarity {
23 Toggle, 27 Toggle,
24} 28}
25 29
30/// Polarity of the `task out` operation.
31pub enum TaskOutPolarity {
32 Set,
33 Clear,
34 Toggle,
35}
36
26#[derive(defmt::Format)] 37#[derive(defmt::Format)]
27pub enum NewChannelError { 38pub enum NewChannelError {
28 NoFreeChannels, 39 NoFreeChannels,
@@ -30,8 +41,6 @@ pub enum NewChannelError {
30 41
31impl Gpiote { 42impl Gpiote {
32 pub fn new(gpiote: GPIOTE) -> Self { 43 pub fn new(gpiote: GPIOTE) -> Self {
33 let signal: Signal<()> = Signal::new();
34
35 interrupt::unpend(interrupt::GPIOTE); 44 interrupt::unpend(interrupt::GPIOTE);
36 interrupt::enable(interrupt::GPIOTE); 45 interrupt::enable(interrupt::GPIOTE);
37 46
@@ -51,24 +60,40 @@ impl Gpiote {
51 } 60 }
52 } 61 }
53 62
54 pub fn new_input_channel<'a, T>( 63 fn allocate_channel(&self) -> Result<u8, NewChannelError> {
55 &'a self,
56 pin: &'a GpioPin<Input<T>>,
57 trigger_mode: EventPolarity,
58 ) -> Result<Channel<'a>, NewChannelError> {
59 interrupt::free(|_| { 64 interrupt::free(|_| {
60 unsafe { INSTANCE = self };
61
62 let chs = self.free_channels.get(); 65 let chs = self.free_channels.get();
63 let index = chs.trailing_zeros() as usize; 66 let index = chs.trailing_zeros() as usize;
64 if index == 8 { 67 if index == 8 {
65 return Err(NewChannelError::NoFreeChannels); 68 return Err(NewChannelError::NoFreeChannels);
66 } 69 }
67 self.free_channels.set(chs & !(1 << index)); 70 self.free_channels.set(chs & !(1 << index));
71 Ok(index as u8)
72 })
73 }
74
75 fn free_channel(&self, index: u8) {
76 interrupt::free(|_| {
77 self.inner.config[index as usize].write(|w| w.mode().disabled());
78 self.inner.intenclr.write(|w| unsafe { w.bits(1 << index) });
79
80 self.free_channels
81 .set(self.free_channels.get() | 1 << index);
82 trace!("freed ch {:u8}", index);
83 })
84 }
68 85
69 trace!("allocated ch {:u8}", index as u8); 86 pub fn new_input_channel<'a, T>(
87 &'a self,
88 pin: &'a Pin<Input<T>>,
89 trigger_mode: EventPolarity,
90 ) -> Result<InputChannel<'a>, NewChannelError> {
91 interrupt::free(|_| {
92 unsafe { INSTANCE = self };
93 let index = self.allocate_channel()?;
94 trace!("allocated in ch {:u8}", index as u8);
70 95
71 self.inner.config[index].write(|w| { 96 self.inner.config[index as usize].write(|w| {
72 match trigger_mode { 97 match trigger_mode {
73 EventPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), 98 EventPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
74 EventPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), 99 EventPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
@@ -85,44 +110,115 @@ impl Gpiote {
85 // Enable interrupt 110 // Enable interrupt
86 self.inner.intenset.write(|w| unsafe { w.bits(1 << index) }); 111 self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
87 112
88 Ok(Channel { 113 Ok(InputChannel {
114 gpiote: self,
115 index,
116 })
117 })
118 }
119
120 pub fn new_output_channel<'a, T>(
121 &'a self,
122 pin: Pin<Output<T>>,
123 level: Level,
124 task_out_polarity: TaskOutPolarity,
125 ) -> Result<OutputChannel<'a>, NewChannelError> {
126 interrupt::free(|_| {
127 unsafe { INSTANCE = self };
128 let index = self.allocate_channel()?;
129 trace!("allocated out ch {:u8}", index);
130
131 self.inner.config[index as usize].write(|w| {
132 w.mode().task();
133 match level {
134 Level::High => w.outinit().high(),
135 Level::Low => w.outinit().low(),
136 };
137 match task_out_polarity {
138 TaskOutPolarity::Set => w.polarity().lo_to_hi(),
139 TaskOutPolarity::Clear => w.polarity().hi_to_lo(),
140 TaskOutPolarity::Toggle => w.polarity().toggle(),
141 };
142 w.port().bit(match pin.port() {
143 Port::Port0 => false,
144 Port::Port1 => true,
145 });
146 unsafe { w.psel().bits(pin.pin()) }
147 });
148
149 // Enable interrupt
150 self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
151
152 Ok(OutputChannel {
89 gpiote: self, 153 gpiote: self,
90 index: index as u8, 154 index,
91 }) 155 })
92 }) 156 })
93 } 157 }
94} 158}
95 159
96pub struct Channel<'a> { 160pub struct InputChannel<'a> {
97 gpiote: &'a Gpiote, 161 gpiote: &'a Gpiote,
98 index: u8, 162 index: u8,
99} 163}
100 164
101impl<'a> Drop for Channel<'a> { 165impl<'a> Drop for InputChannel<'a> {
102 fn drop(&mut self) { 166 fn drop(&mut self) {
103 let g = unsafe { Pin::new_unchecked(self.gpiote) }; 167 self.gpiote.free_channel(self.index);
104
105 interrupt::free(|_| {
106 self.gpiote.inner.config[self.index as usize].write(|w| w.mode().disabled());
107 self.gpiote
108 .inner
109 .intenclr
110 .write(|w| unsafe { w.bits(1 << self.index) });
111
112 self.gpiote
113 .free_channels
114 .set(self.gpiote.free_channels.get() | 1 << self.index);
115 trace!("freed ch {:u8}", self.index);
116 })
117 } 168 }
118} 169}
119 170
120impl<'a> Channel<'a> { 171impl<'a> InputChannel<'a> {
121 pub async fn wait(&self) -> () { 172 pub async fn wait(&self) -> () {
122 self.gpiote.signals[self.index as usize].wait().await; 173 self.gpiote.signals[self.index as usize].wait().await;
123 } 174 }
124} 175}
125 176
177pub struct OutputChannel<'a> {
178 gpiote: &'a Gpiote,
179 index: u8,
180}
181
182impl<'a> Drop for OutputChannel<'a> {
183 fn drop(&mut self) {
184 self.gpiote.free_channel(self.index);
185 }
186}
187
188impl<'a> OutputChannel<'a> {
189 /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle).
190 pub fn out(&self) {
191 self.gpiote.inner.tasks_out[self.index as usize].write(|w| unsafe { w.bits(1) });
192 }
193 /// Triggers `task set` (set associated pin high).
194 #[cfg(not(feature = "51"))]
195 pub fn set(&self) {
196 self.gpiote.inner.tasks_set[self.index as usize].write(|w| unsafe { w.bits(1) });
197 }
198 /// Triggers `task clear` (set associated pin low).
199 #[cfg(not(feature = "51"))]
200 pub fn clear(&self) {
201 self.gpiote.inner.tasks_clr[self.index as usize].write(|w| unsafe { w.bits(1) });
202 }
203
204 /// Returns reference to task_out endpoint for PPI.
205 pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> {
206 &self.gpiote.inner.tasks_out[self.index as usize]
207 }
208
209 /// Returns reference to task_clr endpoint for PPI.
210 #[cfg(not(feature = "51"))]
211 pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> {
212 &self.gpiote.inner.tasks_clr[self.index as usize]
213 }
214
215 /// Returns reference to task_set endpoint for PPI.
216 #[cfg(not(feature = "51"))]
217 pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> {
218 &self.gpiote.inner.tasks_set[self.index as usize]
219 }
220}
221
126#[interrupt] 222#[interrupt]
127unsafe fn GPIOTE() { 223unsafe fn GPIOTE() {
128 let s = &(*INSTANCE); 224 let s = &(*INSTANCE);