1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
//! Interfaces for SPI master and slave communication. use core::option::Option; use returncode::ReturnCode; /// Values for the ordering of bits #[derive(Copy, Clone, Debug)] pub enum DataOrder { MSBFirst, LSBFirst, } /// Values for the clock polarity (idle state or CPOL) #[derive(Copy, Clone, Debug, PartialEq)] pub enum ClockPolarity { IdleLow, IdleHigh, } /// Which clock edge values are sampled on #[derive(Copy, Clone, Debug, PartialEq)] pub enum ClockPhase { SampleLeading, SampleTrailing, } pub trait SpiMasterClient { /// Called when a read/write operation finishes fn read_write_done( &self, write_buffer: &'static mut [u8], read_buffer: Option<&'static mut [u8]>, len: usize, ); } /// The `SpiMaster` trait for interacting with SPI slave /// devices at a byte or buffer level. /// /// Using SpiMaster normally involves three steps: /// /// 1. Configure the SPI bus for a peripheral /// 1a. Call set_chip_select to select which peripheral and /// turn on SPI /// 1b. Call set operations as needed to configure bus /// NOTE: You MUST select the chip select BEFORE configuring /// SPI settings. /// 2. Invoke read, write, read_write on SpiMaster /// 3a. Call clear_chip_select to turn off bus, or /// 3b. Call set_chip_select to choose another peripheral, /// go to step 1b or 2. /// /// This interface assumes that the SPI configuration for /// a particular peripheral persists across chip select. For /// example, with this set of calls: /// /// specify_chip_select(1); /// set_phase(SampleLeading); /// specify_chip_select(2); /// set_phase(SampleTrailing); /// specify_chip_select(1); /// write_byte(0); // Uses SampleLeading /// /// If additional chip selects are needed, they can be performed /// with GPIO and manual re-initialization of settings. /// /// specify_chip_select(0); /// set_phase(SampleLeading); /// pin_a.set(); /// write_byte(0xaa); // Uses SampleLeading /// pin_a.clear(); /// set_phase(SampleTrailing); /// pin_b.set(); /// write_byte(0xaa); // Uses SampleTrailing /// pub trait SpiMaster { type ChipSelect: Copy; fn set_client(&self, client: &'static SpiMasterClient); fn init(&self); fn is_busy(&self) -> bool; /// Perform an asynchronous read/write operation, whose /// completion is signaled by invoking SpiMasterClient on /// the initialized client. write_buffer must be Some, /// read_buffer may be None. If read_buffer is Some, the /// length of the operation is the minimum of the size of /// the two buffers. fn read_write_bytes( &self, write_buffer: &'static mut [u8], read_buffer: Option<&'static mut [u8]>, len: usize, ) -> ReturnCode; fn write_byte(&self, val: u8); fn read_byte(&self) -> u8; fn read_write_byte(&self, val: u8) -> u8; /// Tell the SPI peripheral what to use as a chip select pin. /// The type of the argument is based on what makes sense for the /// peripheral when this trait is implemented. fn specify_chip_select(&self, cs: Self::ChipSelect); /// Returns the actual rate set fn set_rate(&self, rate: u32) -> u32; fn get_rate(&self) -> u32; fn set_clock(&self, polarity: ClockPolarity); fn get_clock(&self) -> ClockPolarity; fn set_phase(&self, phase: ClockPhase); fn get_phase(&self) -> ClockPhase; // These two functions determine what happens to the chip // select line between transfers. If hold_low() is called, // then the chip select line is held low after transfers // complete. If release_low() is called, then the chip select // line is brought high after a transfer completes. A "transfer" // is any of the read/read_write calls. These functions // allow an application to manually control when the // CS line is high or low, such that it can issue multi-byte // requests with single byte operations. fn hold_low(&self); fn release_low(&self); } /// SPIMasterDevice provides a chip-specific interface to the SPI Master /// hardware. The interface wraps the chip select line so that chip drivers /// cannot communicate with different SPI devices. pub trait SpiMasterDevice { /// Setup the SPI settings and speed of the bus. fn configure(&self, cpol: ClockPolarity, cpal: ClockPhase, rate: u32); /// Perform an asynchronous read/write operation, whose /// completion is signaled by invoking SpiMasterClient.read_write_done on /// the provided client. write_buffer must be Some, /// read_buffer may be None. If read_buffer is Some, the /// length of the operation is the minimum of the size of /// the two buffers. fn read_write_bytes( &self, write_buffer: &'static mut [u8], read_buffer: Option<&'static mut [u8]>, len: usize, ) -> ReturnCode; fn set_polarity(&self, cpol: ClockPolarity); fn set_phase(&self, cpal: ClockPhase); fn set_rate(&self, rate: u32); fn get_polarity(&self) -> ClockPolarity; fn get_phase(&self) -> ClockPhase; fn get_rate(&self) -> u32; } pub trait SpiSlaveClient { /// This is called whenever the slave is selected by the master fn chip_selected(&self); /// This is called as a DMA interrupt when a transfer has completed fn read_write_done( &self, write_buffer: Option<&'static mut [u8]>, read_buffer: Option<&'static mut [u8]>, len: usize, ); } pub trait SpiSlave { fn init(&self); /// Returns true if there is a client. fn has_client(&self) -> bool; fn set_client(&self, client: Option<&'static SpiSlaveClient>); fn set_write_byte(&self, write_byte: u8); fn read_write_bytes( &self, write_buffer: Option<&'static mut [u8]>, read_buffer: Option<&'static mut [u8]>, len: usize, ) -> ReturnCode; fn set_clock(&self, polarity: ClockPolarity); fn get_clock(&self) -> ClockPolarity; fn set_phase(&self, phase: ClockPhase); fn get_phase(&self) -> ClockPhase; } /// SPISlaveDevice provides a chip-specific interface to the SPI Slave /// hardware. The interface wraps the chip select line so that chip drivers /// cannot communicate with different SPI devices. pub trait SpiSlaveDevice { /// Setup the SPI settings and speed of the bus. fn configure(&self, cpol: ClockPolarity, cpal: ClockPhase); /// Perform an asynchronous read/write operation, whose /// completion is signaled by invoking SpiSlaveClient.read_write_done on /// the provided client. Either write_buffer or read_buffer may be /// None. If read_buffer is Some, the length of the operation is the /// minimum of the size of the two buffers. fn read_write_bytes( &self, write_buffer: Option<&'static mut [u8]>, read_buffer: Option<&'static mut [u8]>, len: usize, ) -> ReturnCode; fn set_polarity(&self, cpol: ClockPolarity); fn get_polarity(&self) -> ClockPolarity; fn set_phase(&self, cpal: ClockPhase); fn get_phase(&self) -> ClockPhase; }