1use core::{future::Future, task::Poll};
2
3use imxrt_ral as ral;
4
5use ral::{flexio, Valid};
6
7use super::{
8 dma::WS2812Dma, flexio_configurator::FlexIOConfigurator,
9 idle_timer_finished_watcher::IdleTimerFinishedWatcher, interleaved_pixels::InterleavedPixels,
10 maybe_own::MaybeOwn, InterruptHandler, InterruptHandlerData, PreprocessedPixels, WS2812Driver,
11 WriteDmaResult,
12};
13use crate::{errors, pixelstream::PixelStreamRef, Pins};
14
15impl<const N: u8, const L: usize, PINS: Pins<N, L>> WS2812Driver<N, L, PINS>
16where
17 flexio::Instance<N>: Valid,
18{
19 pub fn init(
30 flexio: flexio::Instance<N>,
31 mut pins: PINS,
32 ) -> Result<Self, errors::WS2812InitError> {
33 let (version_major, version_minor, available_feature_set) =
35 ral::read_reg!(ral::flexio, flexio, VERID, MAJOR, MINOR, FEATURE);
36 let (available_triggers, available_pins, available_timers, available_shifters) =
37 ral::read_reg!(ral::flexio, flexio, PARAM, TRIGGER, PIN, TIMER, SHIFTER);
38
39 let available_pins = available_pins as u8;
41
42 log::debug!("Initializing FlexIO #{}.", N);
43 log::debug!(" Version: {}.{}", version_major, version_minor);
44 log::debug!(" Feature Set: {}", available_feature_set);
45 log::debug!(" Peripherals:");
46 log::debug!(" {} triggers", available_triggers);
47 log::debug!(" {} pins", available_pins);
48 log::debug!(" {} timers", available_timers);
49 log::debug!(" {} shifters", available_shifters);
50 log::debug!("Output pins: {:?}", PINS::FLEXIO_PIN_OFFSETS);
51
52 if available_shifters < 1 {
53 return Err(errors::WS2812InitError::NotEnoughShifters);
54 }
55
56 if available_timers < 2 + u32::from(PINS::PIN_COUNT) * 2 {
57 return Err(errors::WS2812InitError::NotEnoughTimers);
58 }
59
60 let mut flexio = FlexIOConfigurator::new(flexio);
62
63 let shifter_output_start_pin = {
65 let mut start = 0;
66 let mut found = false;
67 for i in 0..available_pins {
68 if PINS::FLEXIO_PIN_OFFSETS.contains(&i) {
69 start = i + 1;
70 } else if i - start >= 3 {
71 found = true;
73 break;
74 }
75 }
76 if !found {
77 return Err(errors::WS2812InitError::NeedFourConsecutiveInternalPins);
78 }
79 start
80 };
81
82 let shift_timer_output_pin = {
84 let mut found_pin = None;
85
86 for i in 0..available_pins {
87 if !PINS::FLEXIO_PIN_OFFSETS.contains(&i)
88 && !(shifter_output_start_pin..shifter_output_start_pin + 4).contains(&i)
89 {
90 found_pin = Some(i);
91 break;
92 }
93 }
94
95 if let Some(pin) = found_pin {
96 pin
97 } else {
98 return Err(errors::WS2812InitError::NotEnoughPins);
99 }
100 };
101
102 let data_shifter = Self::get_shifter_id();
103 let shifter_timer = Self::get_shifter_timer_id();
104 let idle_timer = Self::get_idle_timer_id();
105
106 flexio.configure_shifter(data_shifter, shifter_timer, shifter_output_start_pin);
107 flexio.configure_shift_timer(shifter_timer, data_shifter, shift_timer_output_pin);
108 flexio.configure_idle_timer(idle_timer, shift_timer_output_pin, None);
109
110 for (pin_pos, pin_id) in PINS::FLEXIO_PIN_OFFSETS.iter().copied().enumerate() {
111 let pin_pos = pin_pos.try_into().unwrap();
112 let low_bit_timer = Self::get_low_bit_timer_id(pin_pos);
113 let high_bit_timer = Self::get_high_bit_timer_id(pin_pos);
114
115 let neopixel_output_pin = pin_id;
116
117 flexio.configure_low_bit_timer(
118 low_bit_timer,
119 shift_timer_output_pin,
120 neopixel_output_pin,
121 );
122 flexio.configure_high_bit_timer(
123 high_bit_timer,
124 shifter_output_start_pin + pin_pos,
125 neopixel_output_pin,
126 );
127 }
128
129 pins.configure();
131
132 let flexio = flexio.finish();
134 let inner = MaybeOwn::new(InterruptHandlerData {
135 finished_watcher: IdleTimerFinishedWatcher::new(flexio, Self::get_idle_timer_id()),
136 });
137
138 Ok(Self { _pins: pins, inner })
139 }
140
141 const fn get_shifter_id() -> u8 {
142 0
143 }
144
145 const fn get_shifter_timer_id() -> u8 {
146 0
147 }
148 const fn get_idle_timer_id() -> u8 {
149 1
150 }
151
152 const fn get_low_bit_timer_id(pin_pos: u8) -> u8 {
153 2 * pin_pos + 2
154 }
155 const fn get_high_bit_timer_id(pin_pos: u8) -> u8 {
156 2 * pin_pos + 3
157 }
158
159 fn flexio(&self) -> &imxrt_ral::flexio::Instance<N> {
160 self.inner.get().finished_watcher.flexio()
161 }
162
163 fn shift_buffer_empty(&self) -> bool {
164 let mask = 1u32 << Self::get_shifter_id();
165 (ral::read_reg!(ral::flexio, self.flexio(), SHIFTSTAT) & mask) != 0
166 }
167
168 fn fill_shift_buffer(&self, data: u32) {
169 let buf_id = usize::from(Self::get_shifter_id());
170 ral::write_reg!(ral::flexio, self.flexio(), SHIFTBUFBIS[buf_id], data);
171 }
172
173 pub fn take_interrupt_handler(
183 &mut self,
184 storage: &'static mut Option<InterruptHandlerData<N>>,
185 ) -> InterruptHandler<N> {
186 let mask = 1u32 << Self::get_idle_timer_id();
187 imxrt_ral::write_reg!(imxrt_ral::flexio, self.flexio(), TIMIEN, mask);
188
189 InterruptHandler {
190 data: self.inner.convert_to_static_ref(storage),
191 }
192 }
193
194 pub fn write(&mut self, data: [&mut dyn PixelStreamRef; L]) {
202 while !self.shift_buffer_empty() {}
204 self.inner.get().finished_watcher.clear();
205
206 for elem in InterleavedPixels::new(data) {
208 self.fill_shift_buffer(elem);
209 while !self.shift_buffer_empty() {}
210 }
211
212 while !self.inner.get().finished_watcher.poll() {}
214 }
215
216 pub async fn write_dma<F, R, const N2: usize, const P: usize>(
237 &mut self,
238 data: &PreprocessedPixels<N2, L, P>,
239 dma: &mut imxrt_dma::channel::Channel,
240 dma_signal_id: u32,
241 concurrent_action: F,
242 ) -> Result<WriteDmaResult<R>, imxrt_dma::Error>
243 where
244 F: Future<Output = R>,
245 {
246 while !self.shift_buffer_empty() {
250 cassette::yield_now().await;
251 }
252 self.inner.get().finished_watcher.clear();
253
254 let result = {
255 let data = data.get_dma_data();
257 let mut destination =
258 WS2812Dma::new(self.flexio(), Self::get_shifter_id(), dma_signal_id);
259 let mut write =
260 core::pin::pin!(imxrt_dma::peripheral::write(dma, data, &mut destination));
261
262 let mut dma_finished = false;
263 if let Poll::Ready(s) = futures::poll!(&mut write) {
264 s?;
265 dma_finished = true;
266 }
267
268 let result = concurrent_action.await;
270
271 if !dma_finished {
273 if let Poll::Ready(s) = futures::poll!(&mut write) {
275 s?;
276 dma_finished = true;
277 } else {
278 write.await?;
279 }
280 }
281
282 WriteDmaResult {
283 result,
284 lagged: dma_finished,
285 }
286 };
287
288 while !self.shift_buffer_empty() {
290 self.inner.get().finished_watcher.finished().await;
291 }
292 self.inner.get().finished_watcher.finished().await;
293
294 Ok(result)
295 }
296
297 pub fn write_dma_blocking<F, R, const N2: usize, const P: usize>(
302 &mut self,
303 data: &PreprocessedPixels<N2, L, P>,
304 dma: &mut imxrt_dma::channel::Channel,
305 dma_signal_id: u32,
306 concurrent_action: F,
307 ) -> Result<WriteDmaResult<R>, imxrt_dma::Error>
308 where
309 F: FnOnce() -> R,
310 {
311 cassette::Cassette::new(core::pin::pin!(self.write_dma(
312 data,
313 dma,
314 dma_signal_id,
315 async { concurrent_action() }
316 )))
317 .block_on()
318 }
319}