1//! DSI HOST
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6
7//use crate::gpio::{AnyPin, SealedPin};
8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peripheral};
11
12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18}
19
20/// PacketTypes extracted from CubeMX
21#[repr(u8)]
22#[allow(dead_code)]
23pub enum PacketType {
24 /// DCS short write, no parameters
25 DcsShortPktWriteP0,
26 /// DCS short write, one parameter
27 DcsShortPktWriteP1,
28 /// Generic short write, no parameters
29 GenShortPktWriteP0,
30 /// Generic short write, one parameter
31 GenShortPktWriteP1,
32 /// Generic short write, two parameters
33 GenShortPktWriteP2,
34 /// DCS long write
35 DcsLongPktWrite,
36 /// Generic long write
37 GenLongPktWrite,
38 /// DCS short read
39 DcsShortPktRead(u8),
40 /// Generic short read, no parameters
41 GenShortPktReadP0,
42 /// Generic short read, one parameter
43 GenShortPktReadP1(u8),
44 /// Generic short read, two parameters
45 GenShortPktReadP2(u8, u8),
46 /// Used to set the maximum return packet size for reading data
47 MaxReturnPktSize,
48}
49
50impl From<PacketType> for u8 {
51 fn from(packet_type: PacketType) -> u8 {
52 match packet_type {
53 PacketType::DcsShortPktWriteP0 => 0x05,
54 PacketType::DcsShortPktWriteP1 => 0x15,
55 PacketType::GenShortPktWriteP0 => 0x03,
56 PacketType::GenShortPktWriteP1 => 0x13,
57 PacketType::GenShortPktWriteP2 => 0x23,
58 PacketType::DcsLongPktWrite => 0x39,
59 PacketType::GenLongPktWrite => 0x29,
60 PacketType::DcsShortPktRead(_) => 0x06,
61 PacketType::GenShortPktReadP0 => 0x04,
62 PacketType::GenShortPktReadP1(_) => 0x14,
63 PacketType::GenShortPktReadP2(_, _) => 0x24,
64 PacketType::MaxReturnPktSize => 0x37,
65 }
66 }
67}
68
69/// DSIHOST driver.
70pub struct DsiHost<'d, T: Instance> {
71 _peri: PhantomData<&'d mut T>,
72 _te: PeripheralRef<'d, AnyPin>,
73}
74
75impl<'d, T: Instance> DsiHost<'d, T> {
76 /// Note: Full-Duplex modes are not supported at this time
77 pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self {
78 into_ref!(te);
79
80 rcc::enable_and_reset::<T>();
81
82 // Set Tearing Enable pin according to CubeMx example
83 te.set_as_af(te.af_num(), AfType::output(OutputType::PushPull, Speed::Low));
84 /*
85 T::regs().wcr().modify(|w| {
86 w.set_dsien(true);
87 });
88 */
89 Self {
90 _peri: PhantomData,
91 _te: te.map_into(),
92 }
93 }
94
95 /// Get the DSIHOST hardware version. Found in the reference manual for comparison.
96 pub fn get_version(&self) -> u32 {
97 T::regs().vr().read().version()
98 }
99
100 /// Set the enable bit in the control register and assert that it has been enabled
101 pub fn enable(&mut self) {
102 T::regs().cr().modify(|w| w.set_en(true));
103 assert!(T::regs().cr().read().en())
104 }
105
106 /// Unset the enable bit in the control register and assert that it has been disabled
107 pub fn disable(&mut self) {
108 T::regs().cr().modify(|w| w.set_en(false));
109 assert!(!T::regs().cr().read().en())
110 }
111
112 /// Set the DSI enable bit in the wrapper control register and assert that it has been enabled
113 pub fn enable_wrapper_dsi(&mut self) {
114 T::regs().wcr().modify(|w| w.set_dsien(true));
115 assert!(T::regs().wcr().read().dsien())
116 }
117
118 /// Unset the DSI enable bit in the wrapper control register and assert that it has been disabled
119 pub fn disable_wrapper_dsi(&mut self) {
120 T::regs().wcr().modify(|w| w.set_dsien(false));
121 assert!(!T::regs().wcr().read().dsien())
122 }
123
124 /// DCS or Generic short/long write command
125 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
126 assert!(data.len() > 0);
127
128 if data.len() == 1 {
129 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0])
130 } else {
131 self.long_write(
132 channel_id,
133 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
134 address,
135 data,
136 )
137 }
138 }
139
140 fn short_write(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) -> Result<(), Error> {
141 #[cfg(feature = "defmt")]
142 defmt::debug!("short_write: BEGIN wait for command fifo empty");
143
144 // Wait for Command FIFO empty
145 self.wait_command_fifo_empty()?;
146 #[cfg(feature = "defmt")]
147 defmt::debug!("short_write: END wait for command fifo empty");
148
149 // Configure the packet to send a short DCS command with 0 or 1 parameters
150 // Update the DSI packet header with new information
151 self.config_packet_header(channel_id, packet_type, param1, param2);
152
153 self.wait_command_fifo_empty()?;
154
155 let status = T::regs().isr1().read().0;
156 if status != 0 {
157 error!("ISR1 after short_write(): {:b}", status);
158 }
159 Ok(())
160 }
161
162 fn config_packet_header(&mut self, channel_id: u8, packet_type: PacketType, param1: u8, param2: u8) {
163 T::regs().ghcr().write(|w| {
164 w.set_dt(packet_type.into());
165 w.set_vcid(channel_id);
166 w.set_wclsb(param1);
167 w.set_wcmsb(param2);
168 });
169 }
170
171 /// Write long DCS or long Generic command.
172 ///
173 /// `params` is expected to contain at least 2 elements. Use [`short_write`] for a single element.
174 fn long_write(&mut self, channel_id: u8, packet_type: PacketType, address: u8, data: &[u8]) -> Result<(), Error> {
175 // Must be a long packet if we do the long write, obviously.
176 assert!(matches!(
177 packet_type,
178 PacketType::DcsLongPktWrite | PacketType::GenLongPktWrite
179 ));
180
181 // params needs to have at least 2 elements, otherwise short_write should be used
182 assert!(data.len() >= 2);
183
184 #[cfg(feature = "defmt")]
185 defmt::debug!("long_write: BEGIN wait for command fifo empty");
186
187 self.wait_command_fifo_empty()?;
188
189 #[cfg(feature = "defmt")]
190 defmt::debug!("long_write: DONE wait for command fifo empty");
191
192 // Note: CubeMX example "NbParams" is always one LESS than params.len()
193 // DCS code (last element of params) must be on payload byte 1 and if we have only 2 more params,
194 // then they must go into data2 and data3
195 T::regs().gpdr().write(|w| {
196 // data[2] may or may not exist.
197 if let Some(x) = data.get(2) {
198 w.set_data4(*x);
199 }
200 // data[0] and [1] have to exist if long_write is called.
201 w.set_data3(data[1]);
202 w.set_data2(data[0]);
203
204 // DCS Code
205 w.set_data1(address);
206 });
207
208 self.wait_command_fifo_empty()?;
209
210 // These steps are only necessary if more than 1x 4 bytes need to go into the FIFO
211 if data.len() >= 4 {
212 // Generate an iterator that iterates over chunks of exactly 4 bytes
213 let iter = data[3..data.len()].chunks_exact(4);
214 // Obtain remainder before consuming iter
215 let remainder = iter.remainder();
216
217 // Keep filling the buffer with remaining data
218 for param in iter {
219 self.wait_command_fifo_not_full()?;
220 T::regs().gpdr().write(|w| {
221 w.set_data4(param[3]);
222 w.set_data3(param[2]);
223 w.set_data2(param[1]);
224 w.set_data1(param[0]);
225 });
226
227 self.wait_command_fifo_empty().unwrap();
228 }
229
230 // If the remaining data was not devisible by 4 we get a remainder
231 if remainder.len() >= 1 {
232 self.wait_command_fifo_not_full()?;
233 T::regs().gpdr().write(|w| {
234 if let Some(x) = remainder.get(2) {
235 w.set_data3(*x);
236 }
237 if let Some(x) = remainder.get(1) {
238 w.set_data2(*x);
239 }
240 w.set_data1(remainder[0]);
241 });
242 self.wait_command_fifo_empty().unwrap();
243 }
244 }
245 // Configure the packet to send a long DCS command
246 self.config_packet_header(
247 channel_id,
248 packet_type,
249 ((data.len() + 1) & 0x00FF) as u8, // +1 to account for address byte
250 (((data.len() + 1) & 0xFF00) >> 8) as u8, // +1 to account for address byte
251 );
252
253 self.wait_command_fifo_empty()?;
254
255 let status = T::regs().isr1().read().0;
256 if status != 0 {
257 error!("ISR1 after long_write(): {:b}", status);
258 }
259 Ok(())
260 }
261
262 /// Read DSI Register
263 pub fn read(
264 &mut self,
265 channel_id: u8,
266 packet_type: PacketType,
267 read_size: u16,
268 data: &mut [u8],
269 ) -> Result<(), Error> {
270 if data.len() != read_size as usize {
271 return Err(Error::InvalidReadSize);
272 }
273
274 // Set the maximum return packet size
275 self.short_write(
276 channel_id,
277 PacketType::MaxReturnPktSize,
278 (read_size & 0xFF) as u8,
279 ((read_size & 0xFF00) >> 8) as u8,
280 )?;
281
282 // Set the packet header according to the packet_type
283 use PacketType::*;
284 match packet_type {
285 DcsShortPktRead(cmd) => self.config_packet_header(channel_id, packet_type, cmd, 0),
286 GenShortPktReadP0 => self.config_packet_header(channel_id, packet_type, 0, 0),
287 GenShortPktReadP1(param1) => self.config_packet_header(channel_id, packet_type, param1, 0),
288 GenShortPktReadP2(param1, param2) => self.config_packet_header(channel_id, packet_type, param1, param2),
289 _ => return Err(Error::InvalidPacketType),
290 }
291
292 self.wait_read_not_busy()?;
293
294 // Obtain chunks of 32-bit so the entire FIFO data register can be read
295 for bytes in data.chunks_exact_mut(4) {
296 self.wait_payload_read_fifo_not_empty()?;
297
298 // Only perform a single read on the entire register to avoid unintended side-effects
299 let gpdr = T::regs().gpdr().read();
300 bytes[0] = gpdr.data1();
301 bytes[1] = gpdr.data2();
302 bytes[2] = gpdr.data3();
303 bytes[3] = gpdr.data4();
304 }
305
306 // Collect the remaining chunks and read the corresponding number of bytes from the FIFO
307 let remainder = data.chunks_exact_mut(4).into_remainder();
308 if !remainder.is_empty() {
309 self.wait_payload_read_fifo_not_empty()?;
310 // Only perform a single read on the entire register to avoid unintended side-effects
311 let gpdr = T::regs().gpdr().read();
312 if let Some(x) = remainder.get_mut(0) {
313 *x = gpdr.data1()
314 }
315 if let Some(x) = remainder.get_mut(1) {
316 *x = gpdr.data2()
317 }
318 if let Some(x) = remainder.get_mut(2) {
319 *x = gpdr.data3()
320 }
321 }
322
323 /*
324 // Used this to check whether there are read errors. Does not seem like it.
325 if !self.read_busy() {
326 defmt::debug!("Read not busy!");
327 if self.packet_size_error() {
328 return Err(Error::ReadError);
329 }
330 }
331 */
332 Ok(())
333 }
334
335 fn wait_command_fifo_empty(&self) -> Result<(), Error> {
336 for _ in 1..1000 {
337 // Wait for Command FIFO empty
338 if T::regs().gpsr().read().cmdfe() {
339 return Ok(());
340 }
341 blocking_delay_ms(1);
342 }
343 Err(Error::FifoTimeout)
344 }
345
346 fn wait_command_fifo_not_full(&self) -> Result<(), Error> {
347 for _ in 1..1000 {
348 // Wait for Command FIFO not empty
349 if !T::regs().gpsr().read().cmdff() {
350 return Ok(());
351 }
352 blocking_delay_ms(1);
353 }
354 Err(Error::FifoTimeout)
355 }
356
357 fn wait_read_not_busy(&self) -> Result<(), Error> {
358 for _ in 1..1000 {
359 // Wait for read not busy
360 if !self.read_busy() {
361 return Ok(());
362 }
363 blocking_delay_ms(1);
364 }
365 Err(Error::ReadTimeout)
366 }
367
368 fn wait_payload_read_fifo_not_empty(&self) -> Result<(), Error> {
369 for _ in 1..1000 {
370 // Wait for payload read FIFO not empty
371 if !T::regs().gpsr().read().prdfe() {
372 return Ok(());
373 }
374 blocking_delay_ms(1);
375 }
376 Err(Error::FifoTimeout)
377 }
378
379 fn _packet_size_error(&self) -> bool {
380 T::regs().isr1().read().pse()
381 }
382
383 fn read_busy(&self) -> bool {
384 T::regs().gpsr().read().rcb()
385 }
386}
387
388/// Possible Error Types for DSI HOST
389#[non_exhaustive]
390#[derive(Debug, PartialEq, Eq, Clone, Copy)]
391#[cfg_attr(feature = "defmt", derive(defmt::Format))]
392pub enum Error {
393 /// Waiting for FIFO empty flag timed out
394 FifoTimeout,
395 /// The specified `PacketType` is invalid for the selected operation
396 InvalidPacketType,
397 /// Provided read size does not match the read buffer length
398 InvalidReadSize,
399 /// Error during read
400 ReadError,
401 /// Read operation timed out
402 ReadTimeout,
403}
404
405impl<'d, T: Instance> Drop for DsiHost<'d, T> {
406 fn drop(&mut self) {}
407}
408
409trait SealedInstance: crate::rcc::SealedRccPeripheral {
410 fn regs() -> crate::pac::dsihost::Dsihost;
411}
412
413/// DSI instance trait.
414#[allow(private_bounds)]
415pub trait Instance: SealedInstance + RccPeripheral + 'static {}
416
417pin_trait!(TePin, Instance);
418
419foreach_peripheral!(
420 (dsihost, $inst:ident) => {
421 impl crate::dsihost::SealedInstance for peripherals::$inst {
422 fn regs() -> crate::pac::dsihost::Dsihost {
423 crate::pac::$inst
424 }
425 }
426
427 impl crate::dsihost::Instance for peripherals::$inst {}
428 };
429);
430