1 | use core::cmp; |
2 | use core::future::poll_fn; |
3 | use core::task::Poll; |
4 | |
5 | use embassy_embedded_hal::SetConfig; |
6 | use embassy_hal_internal::drop::OnDrop; |
7 | use embedded_hal_1::i2c::Operation; |
8 | |
9 | use super::*; |
10 | use crate::pac::i2c; |
11 | |
12 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
13 | let regs: I2c = T::info().regs; |
14 | let isr: Isr = regs.isr().read(); |
15 | |
16 | if isr.tcr() || isr.tc() { |
17 | T::state().waker.wake(); |
18 | } |
19 | // The flag can only be cleared by writting to nbytes, we won't do that here, so disable |
20 | // the interrupt |
21 | critical_section::with(|_| { |
22 | regs.cr1().modify(|w: &mut Cr1| w.set_tcie(val:false)); |
23 | }); |
24 | } |
25 | |
26 | impl<'d, M: Mode> I2c<'d, M> { |
27 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
28 | self.info.regs.cr1().modify(|reg| { |
29 | reg.set_pe(false); |
30 | reg.set_anfoff(false); |
31 | }); |
32 | |
33 | let timings = Timings::new(self.kernel_clock, freq.into()); |
34 | |
35 | self.info.regs.timingr().write(|reg| { |
36 | reg.set_presc(timings.prescale); |
37 | reg.set_scll(timings.scll); |
38 | reg.set_sclh(timings.sclh); |
39 | reg.set_sdadel(timings.sdadel); |
40 | reg.set_scldel(timings.scldel); |
41 | }); |
42 | |
43 | self.info.regs.cr1().modify(|reg| { |
44 | reg.set_pe(true); |
45 | }); |
46 | } |
47 | |
48 | fn master_stop(&mut self) { |
49 | self.info.regs.cr2().write(|w| w.set_stop(true)); |
50 | } |
51 | |
52 | fn master_read( |
53 | info: &'static Info, |
54 | address: u8, |
55 | length: usize, |
56 | stop: Stop, |
57 | reload: bool, |
58 | restart: bool, |
59 | timeout: Timeout, |
60 | ) -> Result<(), Error> { |
61 | assert!(length < 256); |
62 | |
63 | if !restart { |
64 | // Wait for any previous address sequence to end |
65 | // automatically. This could be up to 50% of a bus |
66 | // cycle (ie. up to 0.5/freq) |
67 | while info.regs.cr2().read().start() { |
68 | timeout.check()?; |
69 | } |
70 | } |
71 | |
72 | // Set START and prepare to receive bytes into |
73 | // `buffer`. The START bit can be set even if the bus |
74 | // is BUSY or I2C is in slave mode. |
75 | |
76 | let reload = if reload { |
77 | i2c::vals::Reload::NOT_COMPLETED |
78 | } else { |
79 | i2c::vals::Reload::COMPLETED |
80 | }; |
81 | |
82 | info.regs.cr2().modify(|w| { |
83 | w.set_sadd((address << 1 | 0) as u16); |
84 | w.set_add10(i2c::vals::Addmode::BIT7); |
85 | w.set_dir(i2c::vals::Dir::READ); |
86 | w.set_nbytes(length as u8); |
87 | w.set_start(true); |
88 | w.set_autoend(stop.autoend()); |
89 | w.set_reload(reload); |
90 | }); |
91 | |
92 | Ok(()) |
93 | } |
94 | |
95 | fn master_write( |
96 | info: &'static Info, |
97 | address: u8, |
98 | length: usize, |
99 | stop: Stop, |
100 | reload: bool, |
101 | timeout: Timeout, |
102 | ) -> Result<(), Error> { |
103 | assert!(length < 256); |
104 | |
105 | // Wait for any previous address sequence to end |
106 | // automatically. This could be up to 50% of a bus |
107 | // cycle (ie. up to 0.5/freq) |
108 | while info.regs.cr2().read().start() { |
109 | timeout.check()?; |
110 | } |
111 | |
112 | // Wait for the bus to be free |
113 | while info.regs.isr().read().busy() { |
114 | timeout.check()?; |
115 | } |
116 | |
117 | let reload = if reload { |
118 | i2c::vals::Reload::NOT_COMPLETED |
119 | } else { |
120 | i2c::vals::Reload::COMPLETED |
121 | }; |
122 | |
123 | // Set START and prepare to send `bytes`. The |
124 | // START bit can be set even if the bus is BUSY or |
125 | // I2C is in slave mode. |
126 | info.regs.cr2().modify(|w| { |
127 | w.set_sadd((address << 1 | 0) as u16); |
128 | w.set_add10(i2c::vals::Addmode::BIT7); |
129 | w.set_dir(i2c::vals::Dir::WRITE); |
130 | w.set_nbytes(length as u8); |
131 | w.set_start(true); |
132 | w.set_autoend(stop.autoend()); |
133 | w.set_reload(reload); |
134 | }); |
135 | |
136 | Ok(()) |
137 | } |
138 | |
139 | fn master_continue(info: &'static Info, length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { |
140 | assert!(length < 256 && length > 0); |
141 | |
142 | while !info.regs.isr().read().tcr() { |
143 | timeout.check()?; |
144 | } |
145 | |
146 | let reload = if reload { |
147 | i2c::vals::Reload::NOT_COMPLETED |
148 | } else { |
149 | i2c::vals::Reload::COMPLETED |
150 | }; |
151 | |
152 | info.regs.cr2().modify(|w| { |
153 | w.set_nbytes(length as u8); |
154 | w.set_reload(reload); |
155 | }); |
156 | |
157 | Ok(()) |
158 | } |
159 | |
160 | fn flush_txdr(&self) { |
161 | if self.info.regs.isr().read().txis() { |
162 | self.info.regs.txdr().write(|w| w.set_txdata(0)); |
163 | } |
164 | if !self.info.regs.isr().read().txe() { |
165 | self.info.regs.isr().modify(|w| w.set_txe(true)) |
166 | } |
167 | } |
168 | |
169 | fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { |
170 | loop { |
171 | let isr = self.info.regs.isr().read(); |
172 | if isr.txe() { |
173 | return Ok(()); |
174 | } else if isr.berr() { |
175 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); |
176 | return Err(Error::Bus); |
177 | } else if isr.arlo() { |
178 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); |
179 | return Err(Error::Arbitration); |
180 | } else if isr.nackf() { |
181 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); |
182 | self.flush_txdr(); |
183 | return Err(Error::Nack); |
184 | } |
185 | |
186 | timeout.check()?; |
187 | } |
188 | } |
189 | |
190 | fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { |
191 | loop { |
192 | let isr = self.info.regs.isr().read(); |
193 | if isr.rxne() { |
194 | return Ok(()); |
195 | } else if isr.berr() { |
196 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); |
197 | return Err(Error::Bus); |
198 | } else if isr.arlo() { |
199 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); |
200 | return Err(Error::Arbitration); |
201 | } else if isr.nackf() { |
202 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); |
203 | self.flush_txdr(); |
204 | return Err(Error::Nack); |
205 | } |
206 | |
207 | timeout.check()?; |
208 | } |
209 | } |
210 | |
211 | fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { |
212 | loop { |
213 | let isr = self.info.regs.isr().read(); |
214 | if isr.tc() { |
215 | return Ok(()); |
216 | } else if isr.berr() { |
217 | self.info.regs.icr().write(|reg| reg.set_berrcf(true)); |
218 | return Err(Error::Bus); |
219 | } else if isr.arlo() { |
220 | self.info.regs.icr().write(|reg| reg.set_arlocf(true)); |
221 | return Err(Error::Arbitration); |
222 | } else if isr.nackf() { |
223 | self.info.regs.icr().write(|reg| reg.set_nackcf(true)); |
224 | self.flush_txdr(); |
225 | return Err(Error::Nack); |
226 | } |
227 | |
228 | timeout.check()?; |
229 | } |
230 | } |
231 | |
232 | fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { |
233 | let completed_chunks = read.len() / 255; |
234 | let total_chunks = if completed_chunks * 255 == read.len() { |
235 | completed_chunks |
236 | } else { |
237 | completed_chunks + 1 |
238 | }; |
239 | let last_chunk_idx = total_chunks.saturating_sub(1); |
240 | |
241 | Self::master_read( |
242 | self.info, |
243 | address, |
244 | read.len().min(255), |
245 | Stop::Automatic, |
246 | last_chunk_idx != 0, |
247 | restart, |
248 | timeout, |
249 | )?; |
250 | |
251 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
252 | if number != 0 { |
253 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
254 | } |
255 | |
256 | for byte in chunk { |
257 | // Wait until we have received something |
258 | self.wait_rxne(timeout)?; |
259 | |
260 | *byte = self.info.regs.rxdr().read().rxdata(); |
261 | } |
262 | } |
263 | Ok(()) |
264 | } |
265 | |
266 | fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { |
267 | let completed_chunks = write.len() / 255; |
268 | let total_chunks = if completed_chunks * 255 == write.len() { |
269 | completed_chunks |
270 | } else { |
271 | completed_chunks + 1 |
272 | }; |
273 | let last_chunk_idx = total_chunks.saturating_sub(1); |
274 | |
275 | // I2C start |
276 | // |
277 | // ST SAD+W |
278 | if let Err(err) = Self::master_write( |
279 | self.info, |
280 | address, |
281 | write.len().min(255), |
282 | Stop::Software, |
283 | last_chunk_idx != 0, |
284 | timeout, |
285 | ) { |
286 | if send_stop { |
287 | self.master_stop(); |
288 | } |
289 | return Err(err); |
290 | } |
291 | |
292 | for (number, chunk) in write.chunks(255).enumerate() { |
293 | if number != 0 { |
294 | Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; |
295 | } |
296 | |
297 | for byte in chunk { |
298 | // Wait until we are allowed to send data |
299 | // (START has been ACKed or last byte when |
300 | // through) |
301 | if let Err(err) = self.wait_txe(timeout) { |
302 | if send_stop { |
303 | self.master_stop(); |
304 | } |
305 | return Err(err); |
306 | } |
307 | |
308 | self.info.regs.txdr().write(|w| w.set_txdata(*byte)); |
309 | } |
310 | } |
311 | // Wait until the write finishes |
312 | let result = self.wait_tc(timeout); |
313 | if send_stop { |
314 | self.master_stop(); |
315 | } |
316 | result |
317 | } |
318 | |
319 | // ========================= |
320 | // Blocking public API |
321 | |
322 | /// Blocking read. |
323 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { |
324 | self.read_internal(address, read, false, self.timeout()) |
325 | // Automatic Stop |
326 | } |
327 | |
328 | /// Blocking write. |
329 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
330 | self.write_internal(address, write, true, self.timeout()) |
331 | } |
332 | |
333 | /// Blocking write, restart, read. |
334 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
335 | let timeout = self.timeout(); |
336 | self.write_internal(address, write, false, timeout)?; |
337 | self.read_internal(address, read, true, timeout) |
338 | // Automatic Stop |
339 | } |
340 | |
341 | /// Blocking transaction with operations. |
342 | /// |
343 | /// Consecutive operations of same type are merged. See [transaction contract] for details. |
344 | /// |
345 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
346 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
347 | let _ = addr; |
348 | let _ = operations; |
349 | todo!() |
350 | } |
351 | |
352 | /// Blocking write multiple buffers. |
353 | /// |
354 | /// The buffers are concatenated in a single write transaction. |
355 | pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { |
356 | if write.is_empty() { |
357 | return Err(Error::ZeroLengthTransfer); |
358 | } |
359 | |
360 | let timeout = self.timeout(); |
361 | |
362 | let first_length = write[0].len(); |
363 | let last_slice_index = write.len() - 1; |
364 | |
365 | if let Err(err) = Self::master_write( |
366 | self.info, |
367 | address, |
368 | first_length.min(255), |
369 | Stop::Software, |
370 | (first_length > 255) || (last_slice_index != 0), |
371 | timeout, |
372 | ) { |
373 | self.master_stop(); |
374 | return Err(err); |
375 | } |
376 | |
377 | for (idx, slice) in write.iter().enumerate() { |
378 | let slice_len = slice.len(); |
379 | let completed_chunks = slice_len / 255; |
380 | let total_chunks = if completed_chunks * 255 == slice_len { |
381 | completed_chunks |
382 | } else { |
383 | completed_chunks + 1 |
384 | }; |
385 | let last_chunk_idx = total_chunks.saturating_sub(1); |
386 | |
387 | if idx != 0 { |
388 | if let Err(err) = Self::master_continue( |
389 | self.info, |
390 | slice_len.min(255), |
391 | (idx != last_slice_index) || (slice_len > 255), |
392 | timeout, |
393 | ) { |
394 | self.master_stop(); |
395 | return Err(err); |
396 | } |
397 | } |
398 | |
399 | for (number, chunk) in slice.chunks(255).enumerate() { |
400 | if number != 0 { |
401 | if let Err(err) = Self::master_continue( |
402 | self.info, |
403 | chunk.len(), |
404 | (number != last_chunk_idx) || (idx != last_slice_index), |
405 | timeout, |
406 | ) { |
407 | self.master_stop(); |
408 | return Err(err); |
409 | } |
410 | } |
411 | |
412 | for byte in chunk { |
413 | // Wait until we are allowed to send data |
414 | // (START has been ACKed or last byte when |
415 | // through) |
416 | if let Err(err) = self.wait_txe(timeout) { |
417 | self.master_stop(); |
418 | return Err(err); |
419 | } |
420 | |
421 | // Put byte on the wire |
422 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); |
423 | self.info.regs.txdr().write(|w| w.set_txdata(*byte)); |
424 | } |
425 | } |
426 | } |
427 | // Wait until the write finishes |
428 | let result = self.wait_tc(timeout); |
429 | self.master_stop(); |
430 | result |
431 | } |
432 | } |
433 | |
434 | impl<'d> I2c<'d, Async> { |
435 | async fn write_dma_internal( |
436 | &mut self, |
437 | address: u8, |
438 | write: &[u8], |
439 | first_slice: bool, |
440 | last_slice: bool, |
441 | timeout: Timeout, |
442 | ) -> Result<(), Error> { |
443 | let total_len = write.len(); |
444 | |
445 | let dma_transfer = unsafe { |
446 | let regs = self.info.regs; |
447 | regs.cr1().modify(|w| { |
448 | w.set_txdmaen(true); |
449 | if first_slice { |
450 | w.set_tcie(true); |
451 | } |
452 | }); |
453 | let dst = regs.txdr().as_ptr() as *mut u8; |
454 | |
455 | self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) |
456 | }; |
457 | |
458 | let mut remaining_len = total_len; |
459 | |
460 | let on_drop = OnDrop::new(|| { |
461 | let regs = self.info.regs; |
462 | regs.cr1().modify(|w| { |
463 | if last_slice { |
464 | w.set_txdmaen(false); |
465 | } |
466 | w.set_tcie(false); |
467 | }) |
468 | }); |
469 | |
470 | poll_fn(|cx| { |
471 | self.state.waker.register(cx.waker()); |
472 | |
473 | let isr = self.info.regs.isr().read(); |
474 | if remaining_len == total_len { |
475 | if first_slice { |
476 | Self::master_write( |
477 | self.info, |
478 | address, |
479 | total_len.min(255), |
480 | Stop::Software, |
481 | (total_len > 255) || !last_slice, |
482 | timeout, |
483 | )?; |
484 | } else { |
485 | Self::master_continue(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; |
486 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
487 | } |
488 | } else if !(isr.tcr() || isr.tc()) { |
489 | // poll_fn was woken without an interrupt present |
490 | return Poll::Pending; |
491 | } else if remaining_len == 0 { |
492 | return Poll::Ready(Ok(())); |
493 | } else { |
494 | let last_piece = (remaining_len <= 255) && last_slice; |
495 | |
496 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { |
497 | return Poll::Ready(Err(e)); |
498 | } |
499 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
500 | } |
501 | |
502 | remaining_len = remaining_len.saturating_sub(255); |
503 | Poll::Pending |
504 | }) |
505 | .await?; |
506 | |
507 | dma_transfer.await; |
508 | |
509 | if last_slice { |
510 | // This should be done already |
511 | self.wait_tc(timeout)?; |
512 | self.master_stop(); |
513 | } |
514 | |
515 | drop(on_drop); |
516 | |
517 | Ok(()) |
518 | } |
519 | |
520 | async fn read_dma_internal( |
521 | &mut self, |
522 | address: u8, |
523 | buffer: &mut [u8], |
524 | restart: bool, |
525 | timeout: Timeout, |
526 | ) -> Result<(), Error> { |
527 | let total_len = buffer.len(); |
528 | |
529 | let dma_transfer = unsafe { |
530 | let regs = self.info.regs; |
531 | regs.cr1().modify(|w| { |
532 | w.set_rxdmaen(true); |
533 | w.set_tcie(true); |
534 | }); |
535 | let src = regs.rxdr().as_ptr() as *mut u8; |
536 | |
537 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) |
538 | }; |
539 | |
540 | let mut remaining_len = total_len; |
541 | |
542 | let on_drop = OnDrop::new(|| { |
543 | let regs = self.info.regs; |
544 | regs.cr1().modify(|w| { |
545 | w.set_rxdmaen(false); |
546 | w.set_tcie(false); |
547 | }) |
548 | }); |
549 | |
550 | poll_fn(|cx| { |
551 | self.state.waker.register(cx.waker()); |
552 | |
553 | let isr = self.info.regs.isr().read(); |
554 | if remaining_len == total_len { |
555 | Self::master_read( |
556 | self.info, |
557 | address, |
558 | total_len.min(255), |
559 | Stop::Software, |
560 | total_len > 255, |
561 | restart, |
562 | timeout, |
563 | )?; |
564 | } else if !(isr.tcr() || isr.tc()) { |
565 | // poll_fn was woken without an interrupt present |
566 | return Poll::Pending; |
567 | } else if remaining_len == 0 { |
568 | return Poll::Ready(Ok(())); |
569 | } else { |
570 | let last_piece = remaining_len <= 255; |
571 | |
572 | if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { |
573 | return Poll::Ready(Err(e)); |
574 | } |
575 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
576 | } |
577 | |
578 | remaining_len = remaining_len.saturating_sub(255); |
579 | Poll::Pending |
580 | }) |
581 | .await?; |
582 | |
583 | dma_transfer.await; |
584 | |
585 | // This should be done already |
586 | self.wait_tc(timeout)?; |
587 | self.master_stop(); |
588 | |
589 | drop(on_drop); |
590 | |
591 | Ok(()) |
592 | } |
593 | |
594 | // ========================= |
595 | // Async public API |
596 | |
597 | /// Write. |
598 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
599 | let timeout = self.timeout(); |
600 | if write.is_empty() { |
601 | self.write_internal(address, write, true, timeout) |
602 | } else { |
603 | timeout |
604 | .with(self.write_dma_internal(address, write, true, true, timeout)) |
605 | .await |
606 | } |
607 | } |
608 | |
609 | /// Write multiple buffers. |
610 | /// |
611 | /// The buffers are concatenated in a single write transaction. |
612 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { |
613 | let timeout = self.timeout(); |
614 | |
615 | if write.is_empty() { |
616 | return Err(Error::ZeroLengthTransfer); |
617 | } |
618 | let mut iter = write.iter(); |
619 | |
620 | let mut first = true; |
621 | let mut current = iter.next(); |
622 | while let Some(c) = current { |
623 | let next = iter.next(); |
624 | let is_last = next.is_none(); |
625 | |
626 | let fut = self.write_dma_internal(address, c, first, is_last, timeout); |
627 | timeout.with(fut).await?; |
628 | first = false; |
629 | current = next; |
630 | } |
631 | Ok(()) |
632 | } |
633 | |
634 | /// Read. |
635 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
636 | let timeout = self.timeout(); |
637 | |
638 | if buffer.is_empty() { |
639 | self.read_internal(address, buffer, false, timeout) |
640 | } else { |
641 | let fut = self.read_dma_internal(address, buffer, false, timeout); |
642 | timeout.with(fut).await |
643 | } |
644 | } |
645 | |
646 | /// Write, restart, read. |
647 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
648 | let timeout = self.timeout(); |
649 | |
650 | if write.is_empty() { |
651 | self.write_internal(address, write, false, timeout)?; |
652 | } else { |
653 | let fut = self.write_dma_internal(address, write, true, true, timeout); |
654 | timeout.with(fut).await?; |
655 | } |
656 | |
657 | if read.is_empty() { |
658 | self.read_internal(address, read, true, timeout)?; |
659 | } else { |
660 | let fut = self.read_dma_internal(address, read, true, timeout); |
661 | timeout.with(fut).await?; |
662 | } |
663 | |
664 | Ok(()) |
665 | } |
666 | |
667 | /// Transaction with operations. |
668 | /// |
669 | /// Consecutive operations of same type are merged. See [transaction contract] for details. |
670 | /// |
671 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
672 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
673 | let _ = addr; |
674 | let _ = operations; |
675 | todo!() |
676 | } |
677 | } |
678 | |
679 | /// I2C Stop Configuration |
680 | /// |
681 | /// Peripheral options for generating the STOP condition |
682 | #[derive (Copy, Clone, PartialEq)] |
683 | enum Stop { |
684 | /// Software end mode: Must write register to generate STOP condition |
685 | Software, |
686 | /// Automatic end mode: A STOP condition is automatically generated once the |
687 | /// configured number of bytes have been transferred |
688 | Automatic, |
689 | } |
690 | |
691 | impl Stop { |
692 | fn autoend(&self) -> i2c::vals::Autoend { |
693 | match self { |
694 | Stop::Software => i2c::vals::Autoend::SOFTWARE, |
695 | Stop::Automatic => i2c::vals::Autoend::AUTOMATIC, |
696 | } |
697 | } |
698 | } |
699 | |
700 | struct Timings { |
701 | prescale: u8, |
702 | scll: u8, |
703 | sclh: u8, |
704 | sdadel: u8, |
705 | scldel: u8, |
706 | } |
707 | |
708 | impl Timings { |
709 | fn new(i2cclk: Hertz, freq: Hertz) -> Self { |
710 | let i2cclk = i2cclk.0; |
711 | let freq = freq.0; |
712 | // Refer to RM0433 Rev 7 Figure 539 for setup and hold timing: |
713 | // |
714 | // t_I2CCLK = 1 / PCLK1 |
715 | // t_PRESC = (PRESC + 1) * t_I2CCLK |
716 | // t_SCLL = (SCLL + 1) * t_PRESC |
717 | // t_SCLH = (SCLH + 1) * t_PRESC |
718 | // |
719 | // t_SYNC1 + t_SYNC2 > 4 * t_I2CCLK |
720 | // t_SCL ~= t_SYNC1 + t_SYNC2 + t_SCLL + t_SCLH |
721 | let ratio = i2cclk / freq; |
722 | |
723 | // For the standard-mode configuration method, we must have a ratio of 4 |
724 | // or higher |
725 | assert!(ratio >= 4, "The I2C PCLK must be at least 4 times the bus frequency!" ); |
726 | |
727 | let (presc_reg, scll, sclh, sdadel, scldel) = if freq > 100_000 { |
728 | // Fast-mode (Fm) or Fast-mode Plus (Fm+) |
729 | // here we pick SCLL + 1 = 2 * (SCLH + 1) |
730 | |
731 | // Prescaler, 384 ticks for sclh/scll. Round up then subtract 1 |
732 | let presc_reg = ((ratio - 1) / 384) as u8; |
733 | // ratio < 1200 by pclk 120MHz max., therefore presc < 16 |
734 | |
735 | // Actual precale value selected |
736 | let presc = (presc_reg + 1) as u32; |
737 | |
738 | let sclh = ((ratio / presc) - 3) / 3; |
739 | let scll = (2 * (sclh + 1)) - 1; |
740 | |
741 | let (sdadel, scldel) = if freq > 400_000 { |
742 | // Fast-mode Plus (Fm+) |
743 | assert!(i2cclk >= 17_000_000); // See table in datsheet |
744 | |
745 | let sdadel = i2cclk / 8_000_000 / presc; |
746 | let scldel = i2cclk / 4_000_000 / presc - 1; |
747 | |
748 | (sdadel, scldel) |
749 | } else { |
750 | // Fast-mode (Fm) |
751 | assert!(i2cclk >= 8_000_000); // See table in datsheet |
752 | |
753 | let sdadel = i2cclk / 4_000_000 / presc; |
754 | let scldel = i2cclk / 2_000_000 / presc - 1; |
755 | |
756 | (sdadel, scldel) |
757 | }; |
758 | |
759 | (presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8) |
760 | } else { |
761 | // Standard-mode (Sm) |
762 | // here we pick SCLL = SCLH |
763 | assert!(i2cclk >= 2_000_000); // See table in datsheet |
764 | |
765 | // Prescaler, 512 ticks for sclh/scll. Round up then |
766 | // subtract 1 |
767 | let presc = (ratio - 1) / 512; |
768 | let presc_reg = cmp::min(presc, 15) as u8; |
769 | |
770 | // Actual prescale value selected |
771 | let presc = (presc_reg + 1) as u32; |
772 | |
773 | let sclh = ((ratio / presc) - 2) / 2; |
774 | let scll = sclh; |
775 | |
776 | // Speed check |
777 | assert!(sclh < 256, "The I2C PCLK is too fast for this bus frequency!" ); |
778 | |
779 | let sdadel = i2cclk / 2_000_000 / presc; |
780 | let scldel = i2cclk / 500_000 / presc - 1; |
781 | |
782 | (presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8) |
783 | }; |
784 | |
785 | // Sanity check |
786 | assert!(presc_reg < 16); |
787 | |
788 | // Keep values within reasonable limits for fast per_ck |
789 | let sdadel = cmp::max(sdadel, 2); |
790 | let scldel = cmp::max(scldel, 4); |
791 | |
792 | //(presc_reg, scll, sclh, sdadel, scldel) |
793 | Self { |
794 | prescale: presc_reg, |
795 | scll, |
796 | sclh, |
797 | sdadel, |
798 | scldel, |
799 | } |
800 | } |
801 | } |
802 | |
803 | impl<'d, M: Mode> SetConfig for I2c<'d, M> { |
804 | type Config = Hertz; |
805 | type ConfigError = (); |
806 | fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { |
807 | let timings: Timings = Timings::new(self.kernel_clock, *config); |
808 | self.info.regs.timingr().write(|reg: &mut Timingr| { |
809 | reg.set_presc(val:timings.prescale); |
810 | reg.set_scll(val:timings.scll); |
811 | reg.set_sclh(val:timings.sclh); |
812 | reg.set_sdadel(val:timings.sdadel); |
813 | reg.set_scldel(val:timings.scldel); |
814 | }); |
815 | |
816 | Ok(()) |
817 | } |
818 | } |
819 | |