|
| 1 | +//! (TODO) Serial Peripheral Interface (SPI) |
| 2 | +
|
| 3 | +use crate::pac::SPI0; |
| 4 | +use crate::clock::Clocks; |
| 5 | +use crate::sysctl::{self, APB0}; |
| 6 | +pub use embedded_hal::spi::{Mode, Polarity, Phase}; |
| 7 | +use core::convert::Infallible; |
| 8 | + |
| 9 | +/// |
| 10 | +pub struct Spi<SPI> { |
| 11 | + spi: SPI |
| 12 | +} |
| 13 | + |
| 14 | +impl Spi<SPI0> { |
| 15 | + pub fn spi0( |
| 16 | + spi: SPI0, |
| 17 | + mode: Mode, |
| 18 | + frame_format: FrameFormat, |
| 19 | + endian: Endian, |
| 20 | + clock: &Clocks, |
| 21 | + apb0: &mut APB0 |
| 22 | + ) -> Self { |
| 23 | + let work_mode = hal_mode_to_pac(mode); |
| 24 | + let frame_format = frame_format_to_pac(frame_format); |
| 25 | + let tmod = crate::pac::spi0::ctrlr0::TMOD_A::TRANS_RECV; // todo other modes |
| 26 | + let endian = endian as u32; |
| 27 | + let data_bit_length = 8; // todo more length |
| 28 | + let _ = clock; // todo |
| 29 | + unsafe { |
| 30 | + // no interrupts for now |
| 31 | + spi.imr.write(|w| w.bits(0x00)); |
| 32 | + // no dma for now |
| 33 | + spi.dmacr.write(|w| w.bits(0x00)); |
| 34 | + spi.dmatdlr.write(|w| w.bits(0x10)); |
| 35 | + spi.dmardlr.write(|w| w.bits(0x00)); |
| 36 | + // no slave access for now |
| 37 | + spi.ser.write(|w| w.bits(0x00)); |
| 38 | + spi.ssienr.write(|w| w.bits(0x00)); |
| 39 | + // set control registers |
| 40 | + spi.ctrlr0.write(|w| { |
| 41 | + w.work_mode() |
| 42 | + .variant(work_mode) |
| 43 | + .tmod() |
| 44 | + .variant(tmod) |
| 45 | + .frame_format() |
| 46 | + .variant(frame_format) |
| 47 | + .data_length() |
| 48 | + .bits(data_bit_length - 1) |
| 49 | + }); |
| 50 | + spi.spi_ctrlr0.reset(); // standard |
| 51 | + spi.endian.write(|w| w.bits(endian)); |
| 52 | + } |
| 53 | + // enable APB0 bus |
| 54 | + apb0.enable(); |
| 55 | + // enable peripheral via sysctl |
| 56 | + sysctl::clk_en_peri().modify(|_r, w| |
| 57 | + w.spi0_clk_en().set_bit()); |
| 58 | + Spi { spi } |
| 59 | + } |
| 60 | + |
| 61 | + pub fn release(self) -> SPI0 { |
| 62 | + // power off |
| 63 | + sysctl::clk_en_peri().modify(|_r, w| |
| 64 | + w.spi0_clk_en().clear_bit()); |
| 65 | + self.spi |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +impl embedded_hal::spi::FullDuplex<u8> for Spi<SPI0> { |
| 70 | + /// An enumeration of SPI errors |
| 71 | + type Error = Infallible; |
| 72 | + |
| 73 | + /// Reads the word stored in the shift register |
| 74 | + /// |
| 75 | + /// **NOTE** A word must be sent to the slave before attempting to call this |
| 76 | + /// method. |
| 77 | + fn try_read(&mut self) -> nb::Result<u8, Self::Error> { |
| 78 | + todo!() |
| 79 | + } |
| 80 | + |
| 81 | + /// Sends a word to the slave |
| 82 | + fn try_send(&mut self, word: u8) -> nb::Result<(), Self::Error> { |
| 83 | + todo!("{}", word) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +#[derive(Clone, Copy, PartialEq, Eq)] |
| 88 | +pub enum FrameFormat { |
| 89 | + Standard, |
| 90 | + Dual, |
| 91 | + Quad, |
| 92 | + Octal, |
| 93 | +} |
| 94 | +#[derive(Clone, Copy, PartialEq, Eq)] |
| 95 | +#[repr(u32)] |
| 96 | +pub enum Endian { |
| 97 | + Little = 0, |
| 98 | + Big = 1, |
| 99 | +} |
| 100 | + |
| 101 | +#[inline] |
| 102 | +fn hal_mode_to_pac(mode: Mode) -> crate::pac::spi0::ctrlr0::WORK_MODE_A { |
| 103 | + use crate::pac::spi0::ctrlr0::WORK_MODE_A; |
| 104 | + use {Polarity::*, Phase::*}; |
| 105 | + match (mode.polarity, mode.phase) { |
| 106 | + (IdleLow, CaptureOnFirstTransition) => WORK_MODE_A::MODE0, |
| 107 | + (IdleLow, CaptureOnSecondTransition) => WORK_MODE_A::MODE1, |
| 108 | + (IdleHigh, CaptureOnFirstTransition) => WORK_MODE_A::MODE2, |
| 109 | + (IdleHigh, CaptureOnSecondTransition) => WORK_MODE_A::MODE3, |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +#[inline] |
| 114 | +fn frame_format_to_pac(frame_format: FrameFormat) -> crate::pac::spi0::ctrlr0::FRAME_FORMAT_A { |
| 115 | + use crate::pac::spi0::ctrlr0::FRAME_FORMAT_A; |
| 116 | + match frame_format { |
| 117 | + FrameFormat::Standard => FRAME_FORMAT_A::STANDARD, |
| 118 | + FrameFormat::Dual => FRAME_FORMAT_A::DUAL, |
| 119 | + FrameFormat::Quad => FRAME_FORMAT_A::QUAD, |
| 120 | + FrameFormat::Octal => FRAME_FORMAT_A::OCTAL, |
| 121 | + } |
| 122 | +} |
0 commit comments