Skip to content

Commit 1050ce5

Browse files
authored
Make sure FD SPI works after HD SPI (#3176)
* Make sure FD SPI works after HD SPI * CHANGELOG * Rename * Fmt
1 parent 49788f4 commit 1050ce5

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

esp-hal/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16+
- Full-duplex SPI works when mixed with half-duplex SPI (#3176)
17+
1618
### Removed
1719

1820
## v1.0.0-beta.0

esp-hal/src/spi/master.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ where
675675
/// Write bytes to SPI. After writing, flush is called to ensure all data
676676
/// has been transmitted.
677677
pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
678+
self.driver().setup_full_duplex()?;
678679
self.driver().write(words)?;
679680
self.driver().flush()?;
680681

@@ -684,11 +685,13 @@ where
684685
/// Read bytes from SPI. The provided slice is filled with data received
685686
/// from the slave.
686687
pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
688+
self.driver().setup_full_duplex()?;
687689
self.driver().read(words)
688690
}
689691

690692
/// Sends `words` to the slave. Returns the `words` received from the slave.
691693
pub fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Error> {
694+
self.driver().setup_full_duplex()?;
692695
self.driver().transfer(words)
693696
}
694697
}
@@ -880,6 +883,7 @@ impl<'d> Spi<'d, Async> {
880883
// We need to flush because the blocking transfer functions may return while a
881884
// transfer is still in progress.
882885
self.flush_async().await?;
886+
self.driver().setup_full_duplex()?;
883887
self.driver().transfer_in_place_async(words).await
884888
}
885889
}
@@ -1747,7 +1751,9 @@ mod dma {
17471751
mut buffer: TX,
17481752
) -> Result<SpiDmaTransfer<'d, Dm, TX>, (Error, Self, TX)> {
17491753
self.wait_for_idle();
1750-
1754+
if let Err(e) = self.driver().setup_full_duplex() {
1755+
return Err((e, self, buffer));
1756+
};
17511757
match unsafe { self.start_dma_write(bytes_to_write, &mut buffer) } {
17521758
Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
17531759
Err(e) => Err((e, self, buffer)),
@@ -1781,6 +1787,9 @@ mod dma {
17811787
mut buffer: RX,
17821788
) -> Result<SpiDmaTransfer<'d, Dm, RX>, (Error, Self, RX)> {
17831789
self.wait_for_idle();
1790+
if let Err(e) = self.driver().setup_full_duplex() {
1791+
return Err((e, self, buffer));
1792+
};
17841793
match unsafe { self.start_dma_read(bytes_to_read, &mut buffer) } {
17851794
Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
17861795
Err(e) => Err((e, self, buffer)),
@@ -1818,6 +1827,9 @@ mod dma {
18181827
mut tx_buffer: TX,
18191828
) -> Result<SpiDmaTransfer<'d, Dm, (RX, TX)>, (Error, Self, RX, TX)> {
18201829
self.wait_for_idle();
1830+
if let Err(e) = self.driver().setup_full_duplex() {
1831+
return Err((e, self, rx_buffer, tx_buffer));
1832+
};
18211833
match unsafe {
18221834
self.start_dma_transfer(
18231835
bytes_to_read,
@@ -2081,6 +2093,7 @@ mod dma {
20812093
#[instability::unstable]
20822094
pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
20832095
self.wait_for_idle();
2096+
self.spi_dma.driver().setup_full_duplex()?;
20842097
for chunk in words.chunks_mut(self.rx_buf.capacity()) {
20852098
self.rx_buf.set_length(chunk.len());
20862099

@@ -2106,6 +2119,7 @@ mod dma {
21062119
#[instability::unstable]
21072120
pub fn write(&mut self, words: &[u8]) -> Result<(), Error> {
21082121
self.wait_for_idle();
2122+
self.spi_dma.driver().setup_full_duplex()?;
21092123
for chunk in words.chunks(self.tx_buf.capacity()) {
21102124
self.tx_buf.fill(chunk);
21112125

@@ -2128,6 +2142,7 @@ mod dma {
21282142
#[instability::unstable]
21292143
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
21302144
self.wait_for_idle();
2145+
self.spi_dma.driver().setup_full_duplex()?;
21312146
let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
21322147

21332148
let common_length = min(read.len(), write.len());
@@ -2168,6 +2183,7 @@ mod dma {
21682183
#[instability::unstable]
21692184
pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
21702185
self.wait_for_idle();
2186+
self.spi_dma.driver().setup_full_duplex()?;
21712187
let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
21722188

21732189
for chunk in words.chunks_mut(chunk_size) {
@@ -2325,6 +2341,7 @@ mod dma {
23252341
#[instability::unstable]
23262342
pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
23272343
self.spi_dma.wait_for_idle_async().await;
2344+
self.spi_dma.driver().setup_full_duplex()?;
23282345
let chunk_size = self.rx_buf.capacity();
23292346

23302347
for chunk in words.chunks_mut(chunk_size) {
@@ -2351,6 +2368,7 @@ mod dma {
23512368
#[instability::unstable]
23522369
pub async fn write_async(&mut self, words: &[u8]) -> Result<(), Error> {
23532370
self.spi_dma.wait_for_idle_async().await;
2371+
self.spi_dma.driver().setup_full_duplex()?;
23542372

23552373
let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
23562374
let chunk_size = self.tx_buf.capacity();
@@ -2378,6 +2396,7 @@ mod dma {
23782396
write: &[u8],
23792397
) -> Result<(), Error> {
23802398
self.spi_dma.wait_for_idle_async().await;
2399+
self.spi_dma.driver().setup_full_duplex()?;
23812400

23822401
let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
23832402
let chunk_size = min(self.tx_buf.capacity(), self.rx_buf.capacity());
@@ -2423,6 +2442,7 @@ mod dma {
24232442
#[instability::unstable]
24242443
pub async fn transfer_in_place_async(&mut self, words: &mut [u8]) -> Result<(), Error> {
24252444
self.spi_dma.wait_for_idle_async().await;
2445+
self.spi_dma.driver().setup_full_duplex()?;
24262446

24272447
let mut spi = DropGuard::new(&mut self.spi_dma, |spi| spi.cancel_transfer());
24282448
for chunk in words.chunks_mut(self.tx_buf.capacity()) {
@@ -2603,13 +2623,15 @@ mod ehal1 {
26032623
// We need to flush because the blocking transfer functions may return while a
26042624
// transfer is still in progress.
26052625
self.flush_async().await?;
2626+
self.driver().setup_full_duplex()?;
26062627
self.driver().read_async(words).await
26072628
}
26082629

26092630
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
26102631
// We need to flush because the blocking transfer functions may return while a
26112632
// transfer is still in progress.
26122633
self.flush_async().await?;
2634+
self.driver().setup_full_duplex()?;
26132635
self.driver().write_async(words).await
26142636
}
26152637

@@ -3379,6 +3401,23 @@ impl Driver {
33793401
future.await;
33803402
}
33813403

3404+
fn setup_full_duplex(&self) -> Result<(), Error> {
3405+
self.regs().user().modify(|_, w| {
3406+
w.usr_miso().set_bit();
3407+
w.usr_mosi().set_bit();
3408+
w.doutdin().set_bit();
3409+
w.usr_dummy().clear_bit();
3410+
w.sio().clear_bit()
3411+
});
3412+
3413+
self.init_spi_data_mode(
3414+
DataMode::SingleTwoDataLines,
3415+
DataMode::SingleTwoDataLines,
3416+
DataMode::SingleTwoDataLines,
3417+
)?;
3418+
Ok(())
3419+
}
3420+
33823421
#[allow(clippy::too_many_arguments)]
33833422
fn setup_half_duplex(
33843423
&self,

hil-test/tests/spi_full_duplex.rs

+55
Original file line numberDiff line numberDiff line change
@@ -785,4 +785,59 @@ mod tests {
785785
transfer.cancel();
786786
_ = transfer.wait();
787787
}
788+
789+
#[test]
790+
#[cfg(feature = "unstable")]
791+
fn transfer_works_after_half_duplex_operation(ctx: Context) {
792+
let mut spi = ctx.spi;
793+
794+
let mut buffer = [0u8; 4];
795+
spi.half_duplex_read(
796+
esp_hal::spi::DataMode::Dual,
797+
esp_hal::spi::master::Command::_8Bit(0x92, esp_hal::spi::DataMode::SingleTwoDataLines),
798+
esp_hal::spi::master::Address::_32Bit(0x000000_00, esp_hal::spi::DataMode::Dual),
799+
0,
800+
&mut buffer,
801+
)
802+
.unwrap();
803+
804+
const DATA: &[u8] = &[0xde, 0xad, 0xbe, 0xef];
805+
let mut buffer: [u8; 4] = [0x00u8; 4];
806+
buffer.copy_from_slice(DATA);
807+
808+
spi.transfer(&mut buffer)
809+
.expect("Symmetric transfer failed");
810+
assert_eq!(buffer, DATA);
811+
}
812+
813+
#[test]
814+
#[cfg(feature = "unstable")]
815+
fn dma_transfer_works_after_half_duplex_operation(ctx: Context) {
816+
let mut spi = ctx.spi;
817+
818+
let mut buffer = [0u8; 4];
819+
spi.half_duplex_read(
820+
esp_hal::spi::DataMode::Dual,
821+
esp_hal::spi::master::Command::_8Bit(0x92, esp_hal::spi::DataMode::SingleTwoDataLines),
822+
esp_hal::spi::master::Address::_32Bit(0x000000_00, esp_hal::spi::DataMode::Dual),
823+
0,
824+
&mut buffer,
825+
)
826+
.unwrap();
827+
828+
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(4);
829+
let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
830+
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
831+
832+
let mut spi = spi
833+
.with_dma(ctx.dma_channel)
834+
.with_buffers(dma_rx_buf, dma_tx_buf);
835+
836+
let tx_buf = [0xde, 0xad, 0xbe, 0xef];
837+
let mut rx_buf = [0; 4];
838+
839+
spi.transfer(&mut rx_buf, &tx_buf).unwrap();
840+
841+
assert_eq!(tx_buf, rx_buf);
842+
}
788843
}

0 commit comments

Comments
 (0)