Merge 9e5dde9281 into 040c0fd353
This commit is contained in:
commit
92dee4d0cb
@ -55,7 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `adc::{AdcCalSource, Attenuation, Resolution}` now implement `Hash` and `defmt::Format` (#2840)
|
- `adc::{AdcCalSource, Attenuation, Resolution}` now implement `Hash` and `defmt::Format` (#2840)
|
||||||
- `rtc_cntl::{RtcFastClock, RtcSlowClock, RtcCalSel}` now implement `PartialEq`, `Eq`, `Hash` and `defmt::Format` (#2840)
|
- `rtc_cntl::{RtcFastClock, RtcSlowClock, RtcCalSel}` now implement `PartialEq`, `Eq`, `Hash` and `defmt::Format` (#2840)
|
||||||
- Added `tsens::TemperatureSensor` peripheral for ESP32C6 and ESP32C3 (#2875)
|
- Added `tsens::TemperatureSensor` peripheral for ESP32C6 and ESP32C3 (#2875)
|
||||||
- Added `with_rx()` and `with_tx()` methods to Uart, UartRx, and UartTx ()
|
- Added `with_rx()` and `with_tx()` methods to Uart, UartRx, and UartTx (#2904)
|
||||||
|
- SPI: Added support for 3-wire SPI (#2919)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@ -552,8 +552,8 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
this.apply_config(&config)?;
|
this.apply_config(&config)?;
|
||||||
|
|
||||||
let this = this
|
let this = this
|
||||||
.with_mosi(NoPin)
|
.with_sio0(NoPin)
|
||||||
.with_miso(NoPin)
|
.with_sio1(NoPin)
|
||||||
.with_sck(NoPin)
|
.with_sck(NoPin)
|
||||||
.with_cs(NoPin);
|
.with_cs(NoPin);
|
||||||
|
|
||||||
@ -645,9 +645,21 @@ where
|
|||||||
{
|
{
|
||||||
/// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
|
/// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
|
||||||
///
|
///
|
||||||
|
/// Enables output functionality for the pin, and connects it to the MOSI.
|
||||||
|
pub fn with_mosi<MOSI: PeripheralOutput>(self, mosi: impl Peripheral<P = MOSI> + 'd) -> Self {
|
||||||
|
crate::into_mapped_ref!(mosi);
|
||||||
|
mosi.enable_output(false, private::Internal);
|
||||||
|
|
||||||
|
self.driver().info.mosi.connect_to(&mut mosi);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assign the SIO0 pin for the SPI instance.
|
||||||
|
///
|
||||||
/// Enables both input and output functionality for the pin, and connects it
|
/// Enables both input and output functionality for the pin, and connects it
|
||||||
/// to the MOSI signal and SIO0 input signal.
|
/// to the MOSI signal and SIO0 input signal.
|
||||||
pub fn with_mosi<MOSI: PeripheralOutput>(self, mosi: impl Peripheral<P = MOSI> + 'd) -> Self {
|
pub fn with_sio0<MOSI: PeripheralOutput>(self, mosi: impl Peripheral<P = MOSI> + 'd) -> Self {
|
||||||
crate::into_mapped_ref!(mosi);
|
crate::into_mapped_ref!(mosi);
|
||||||
mosi.enable_output(true, private::Internal);
|
mosi.enable_output(true, private::Internal);
|
||||||
mosi.enable_input(true, private::Internal);
|
mosi.enable_input(true, private::Internal);
|
||||||
@ -3123,12 +3135,25 @@ impl Driver {
|
|||||||
no_mosi_miso: bool,
|
no_mosi_miso: bool,
|
||||||
data_mode: DataMode,
|
data_mode: DataMode,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
let three_wire = cmd.mode() == DataMode::SingleThreeWire
|
||||||
|
|| address.mode() == DataMode::SingleThreeWire
|
||||||
|
|| data_mode == DataMode::SingleThreeWire;
|
||||||
|
|
||||||
|
if three_wire
|
||||||
|
&& ((cmd != Command::None && cmd.mode() != DataMode::SingleThreeWire)
|
||||||
|
|| (address != Address::None && address.mode() != DataMode::SingleThreeWire)
|
||||||
|
|| data_mode != DataMode::SingleThreeWire)
|
||||||
|
{
|
||||||
|
return Err(Error::ArgumentsInvalid);
|
||||||
|
}
|
||||||
|
|
||||||
self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
|
self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
|
||||||
|
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
reg_block.user().modify(|_, w| {
|
reg_block.user().modify(|_, w| {
|
||||||
w.usr_miso_highpart().clear_bit();
|
w.usr_miso_highpart().clear_bit();
|
||||||
w.usr_mosi_highpart().clear_bit();
|
w.usr_mosi_highpart().clear_bit();
|
||||||
|
w.sio().bit(three_wire);
|
||||||
w.doutdin().clear_bit();
|
w.doutdin().clear_bit();
|
||||||
w.usr_miso().bit(!is_write && !no_mosi_miso);
|
w.usr_miso().bit(!is_write && !no_mosi_miso);
|
||||||
w.usr_mosi().bit(is_write && !no_mosi_miso);
|
w.usr_mosi().bit(is_write && !no_mosi_miso);
|
||||||
|
|||||||
@ -35,6 +35,8 @@ pub enum Error {
|
|||||||
/// Error indicating that the operation is unsupported by the current
|
/// Error indicating that the operation is unsupported by the current
|
||||||
/// implementation.
|
/// implementation.
|
||||||
Unsupported,
|
Unsupported,
|
||||||
|
/// The given arguments are invalid.
|
||||||
|
ArgumentsInvalid,
|
||||||
/// An unknown error occurred during SPI communication.
|
/// An unknown error occurred during SPI communication.
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
@ -98,14 +100,16 @@ pub enum BitOrder {
|
|||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub enum DataMode {
|
pub enum DataMode {
|
||||||
/// `Single` Data Mode - 1 bit, 2 wires.
|
/// Clock, CS and one data line (SIO0)
|
||||||
|
SingleThreeWire,
|
||||||
|
/// `Single` Data Mode - 1 bit, two data lines. (SIO0, SIO1)
|
||||||
Single,
|
Single,
|
||||||
/// `Dual` Data Mode - 2 bit, 2 wires
|
/// `Dual` Data Mode - 2 bits, two data lines. (SIO0, SIO1)
|
||||||
Dual,
|
Dual,
|
||||||
/// `Quad` Data Mode - 4 bit, 4 wires
|
/// `Quad` Data Mode - 4 bit, 4 data lines. (SIO0 .. SIO3)
|
||||||
Quad,
|
Quad,
|
||||||
#[cfg(spi_octal)]
|
#[cfg(spi_octal)]
|
||||||
/// `Octal` Data Mode - 8 bit, 8 wires
|
/// `Octal` Data Mode - 8 bit, 8 data lines. (SIO0 .. SIO7)
|
||||||
Octal,
|
Octal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -231,7 +231,7 @@ mod tests {
|
|||||||
let [pin, pin_mirror, _] = ctx.gpios;
|
let [pin, pin_mirror, _] = ctx.gpios;
|
||||||
let pin_mirror = Output::new(pin_mirror, Level::High);
|
let pin_mirror = Output::new(pin_mirror, Level::High);
|
||||||
|
|
||||||
let spi = ctx.spi.with_mosi(pin).with_dma(ctx.dma_channel);
|
let spi = ctx.spi.with_sio0(pin).with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
super::execute_read(spi, pin_mirror, 0b0001_0001);
|
super::execute_read(spi, pin_mirror, 0b0001_0001);
|
||||||
}
|
}
|
||||||
@ -241,7 +241,7 @@ mod tests {
|
|||||||
let [pin, pin_mirror, _] = ctx.gpios;
|
let [pin, pin_mirror, _] = ctx.gpios;
|
||||||
let pin_mirror = Output::new(pin_mirror, Level::High);
|
let pin_mirror = Output::new(pin_mirror, Level::High);
|
||||||
|
|
||||||
let spi = ctx.spi.with_miso(pin).with_dma(ctx.dma_channel);
|
let spi = ctx.spi.with_sio1(pin).with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
super::execute_read(spi, pin_mirror, 0b0010_0010);
|
super::execute_read(spi, pin_mirror, 0b0010_0010);
|
||||||
}
|
}
|
||||||
@ -271,7 +271,7 @@ mod tests {
|
|||||||
let [pin, pin_mirror, _] = ctx.gpios;
|
let [pin, pin_mirror, _] = ctx.gpios;
|
||||||
let pin_mirror = Output::new(pin_mirror, Level::High);
|
let pin_mirror = Output::new(pin_mirror, Level::High);
|
||||||
|
|
||||||
let spi = ctx.spi.with_mosi(pin).with_dma(ctx.dma_channel);
|
let spi = ctx.spi.with_sio0(pin).with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
super::execute_write_read(spi, pin_mirror, 0b0001_0001);
|
super::execute_write_read(spi, pin_mirror, 0b0001_0001);
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ mod tests {
|
|||||||
.channel0
|
.channel0
|
||||||
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
||||||
|
|
||||||
let spi = ctx.spi.with_mosi(mosi).with_dma(ctx.dma_channel);
|
let spi = ctx.spi.with_sio0(mosi).with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
super::execute_write(unit0, unit1, spi, 0b0000_0001, false);
|
super::execute_write(unit0, unit1, spi, 0b0000_0001, false);
|
||||||
}
|
}
|
||||||
@ -355,7 +355,7 @@ mod tests {
|
|||||||
|
|
||||||
let spi = ctx
|
let spi = ctx
|
||||||
.spi
|
.spi
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_sio1(gpio)
|
.with_sio1(gpio)
|
||||||
.with_dma(ctx.dma_channel);
|
.with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ mod tests {
|
|||||||
|
|
||||||
let spi = ctx
|
let spi = ctx
|
||||||
.spi
|
.spi
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_sio2(gpio)
|
.with_sio2(gpio)
|
||||||
.with_dma(ctx.dma_channel);
|
.with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
@ -421,7 +421,7 @@ mod tests {
|
|||||||
|
|
||||||
let spi = ctx
|
let spi = ctx
|
||||||
.spi
|
.spi
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_sio3(gpio)
|
.with_sio3(gpio)
|
||||||
.with_dma(ctx.dma_channel);
|
.with_dma(ctx.dma_channel);
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,81 @@ struct Context {
|
|||||||
pcnt_source: InputSignal,
|
pcnt_source: InputSignal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn perform_spi_writes_are_correctly_by_pcnt(ctx: Context, mode: DataMode) {
|
||||||
|
const DMA_BUFFER_SIZE: usize = 4;
|
||||||
|
|
||||||
|
let (_, _, buffer, descriptors) = dma_buffers!(0, DMA_BUFFER_SIZE);
|
||||||
|
let mut dma_tx_buf = DmaTxBuf::new(descriptors, buffer).unwrap();
|
||||||
|
|
||||||
|
let unit = ctx.pcnt_unit;
|
||||||
|
let mut spi = ctx.spi;
|
||||||
|
|
||||||
|
unit.channel0.set_edge_signal(ctx.pcnt_source);
|
||||||
|
unit.channel0
|
||||||
|
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
||||||
|
|
||||||
|
// Fill the buffer where each byte has 3 pos edges.
|
||||||
|
dma_tx_buf.fill(&[0b0110_1010; DMA_BUFFER_SIZE]);
|
||||||
|
|
||||||
|
let transfer = spi
|
||||||
|
.half_duplex_write(
|
||||||
|
mode,
|
||||||
|
Command::None,
|
||||||
|
Address::None,
|
||||||
|
0,
|
||||||
|
dma_tx_buf.len(),
|
||||||
|
dma_tx_buf,
|
||||||
|
)
|
||||||
|
.map_err(|e| e.0)
|
||||||
|
.unwrap();
|
||||||
|
(spi, dma_tx_buf) = transfer.wait();
|
||||||
|
|
||||||
|
assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _);
|
||||||
|
|
||||||
|
let transfer = spi
|
||||||
|
.half_duplex_write(
|
||||||
|
mode,
|
||||||
|
Command::None,
|
||||||
|
Address::None,
|
||||||
|
0,
|
||||||
|
dma_tx_buf.len(),
|
||||||
|
dma_tx_buf,
|
||||||
|
)
|
||||||
|
.map_err(|e| e.0)
|
||||||
|
.unwrap();
|
||||||
|
// dropping SPI would make us see an additional edge - so let's keep SPI alive
|
||||||
|
let (_spi, _) = transfer.wait();
|
||||||
|
|
||||||
|
assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform_spidmabus_writes_are_correctly_by_pcnt(ctx: Context, mode: DataMode) {
|
||||||
|
const DMA_BUFFER_SIZE: usize = 4;
|
||||||
|
|
||||||
|
let (rx, rxd, buffer, descriptors) = dma_buffers!(1, DMA_BUFFER_SIZE);
|
||||||
|
let dma_rx_buf = DmaRxBuf::new(rxd, rx).unwrap();
|
||||||
|
let dma_tx_buf = DmaTxBuf::new(descriptors, buffer).unwrap();
|
||||||
|
|
||||||
|
let unit = ctx.pcnt_unit;
|
||||||
|
let mut spi = ctx.spi.with_buffers(dma_rx_buf, dma_tx_buf);
|
||||||
|
|
||||||
|
unit.channel0.set_edge_signal(ctx.pcnt_source);
|
||||||
|
unit.channel0
|
||||||
|
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
||||||
|
|
||||||
|
let buffer = [0b0110_1010; DMA_BUFFER_SIZE];
|
||||||
|
// Write the buffer where each byte has 3 pos edges.
|
||||||
|
spi.half_duplex_write(mode, Command::None, Address::None, 0, &buffer)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _);
|
||||||
|
|
||||||
|
spi.half_duplex_write(mode, Command::None, Address::None, 0, &buffer)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[embedded_test::tests(default_timeout = 3)]
|
#[embedded_test::tests(default_timeout = 3)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -59,7 +134,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_sck(sclk)
|
.with_sck(sclk)
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_dma(dma_channel);
|
.with_dma(dma_channel);
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
@ -71,78 +146,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_spi_writes_are_correctly_by_pcnt(ctx: Context) {
|
fn test_spi_writes_are_correctly_by_pcnt(ctx: Context) {
|
||||||
const DMA_BUFFER_SIZE: usize = 4;
|
super::perform_spi_writes_are_correctly_by_pcnt(ctx, DataMode::Single);
|
||||||
|
|
||||||
let (_, _, buffer, descriptors) = dma_buffers!(0, DMA_BUFFER_SIZE);
|
|
||||||
let mut dma_tx_buf = DmaTxBuf::new(descriptors, buffer).unwrap();
|
|
||||||
|
|
||||||
let unit = ctx.pcnt_unit;
|
|
||||||
let mut spi = ctx.spi;
|
|
||||||
|
|
||||||
unit.channel0.set_edge_signal(ctx.pcnt_source);
|
|
||||||
unit.channel0
|
|
||||||
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
|
||||||
|
|
||||||
// Fill the buffer where each byte has 3 pos edges.
|
|
||||||
dma_tx_buf.fill(&[0b0110_1010; DMA_BUFFER_SIZE]);
|
|
||||||
|
|
||||||
let transfer = spi
|
|
||||||
.half_duplex_write(
|
|
||||||
DataMode::Single,
|
|
||||||
Command::None,
|
|
||||||
Address::None,
|
|
||||||
0,
|
|
||||||
dma_tx_buf.len(),
|
|
||||||
dma_tx_buf,
|
|
||||||
)
|
|
||||||
.map_err(|e| e.0)
|
|
||||||
.unwrap();
|
|
||||||
(spi, dma_tx_buf) = transfer.wait();
|
|
||||||
|
|
||||||
assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _);
|
|
||||||
|
|
||||||
let transfer = spi
|
|
||||||
.half_duplex_write(
|
|
||||||
DataMode::Single,
|
|
||||||
Command::None,
|
|
||||||
Address::None,
|
|
||||||
0,
|
|
||||||
dma_tx_buf.len(),
|
|
||||||
dma_tx_buf,
|
|
||||||
)
|
|
||||||
.map_err(|e| e.0)
|
|
||||||
.unwrap();
|
|
||||||
// dropping SPI would make us see an additional edge - so let's keep SPI alive
|
|
||||||
let (_spi, _) = transfer.wait();
|
|
||||||
|
|
||||||
assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_spidmabus_writes_are_correctly_by_pcnt(ctx: Context) {
|
fn test_spidmabus_writes_are_correctly_by_pcnt(ctx: Context) {
|
||||||
const DMA_BUFFER_SIZE: usize = 4;
|
super::perform_spidmabus_writes_are_correctly_by_pcnt(ctx, DataMode::Single);
|
||||||
|
}
|
||||||
|
|
||||||
let (rx, rxd, buffer, descriptors) = dma_buffers!(1, DMA_BUFFER_SIZE);
|
#[test]
|
||||||
let dma_rx_buf = DmaRxBuf::new(rxd, rx).unwrap();
|
fn test_spi_writes_are_correctly_by_pcnt_tree_wire(ctx: Context) {
|
||||||
let dma_tx_buf = DmaTxBuf::new(descriptors, buffer).unwrap();
|
super::perform_spi_writes_are_correctly_by_pcnt(ctx, DataMode::SingleThreeWire);
|
||||||
|
}
|
||||||
|
|
||||||
let unit = ctx.pcnt_unit;
|
#[test]
|
||||||
let mut spi = ctx.spi.with_buffers(dma_rx_buf, dma_tx_buf);
|
fn test_spidmabus_writes_are_correctly_by_pcnt_tree_wire(ctx: Context) {
|
||||||
|
super::perform_spidmabus_writes_are_correctly_by_pcnt(ctx, DataMode::SingleThreeWire);
|
||||||
unit.channel0.set_edge_signal(ctx.pcnt_source);
|
|
||||||
unit.channel0
|
|
||||||
.set_input_mode(EdgeMode::Hold, EdgeMode::Increment);
|
|
||||||
|
|
||||||
let buffer = [0b0110_1010; DMA_BUFFER_SIZE];
|
|
||||||
// Write the buffer where each byte has 3 pos edges.
|
|
||||||
spi.half_duplex_write(DataMode::Single, Command::None, Address::None, 0, &buffer)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _);
|
|
||||||
|
|
||||||
spi.half_duplex_write(DataMode::Single, Command::None, Address::None, 0, &buffer)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,7 +71,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_sck(sclk)
|
.with_sck(sclk)
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_dma(dma_channel);
|
.with_dma(dma_channel);
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
|
|||||||
@ -71,8 +71,8 @@ fn main() -> ! {
|
|||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_sck(sclk)
|
.with_sck(sclk)
|
||||||
.with_mosi(mosi)
|
.with_sio0(mosi)
|
||||||
.with_miso(miso)
|
.with_sio1(miso)
|
||||||
.with_sio2(sio2)
|
.with_sio2(sio2)
|
||||||
.with_sio3(sio3)
|
.with_sio3(sio3)
|
||||||
.with_cs(cs);
|
.with_cs(cs);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user