Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion embassy-stm32/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- feat: Configurable gpio speed for QSPI
- feat: derive Clone, Copy and defmt::Format for all *SPI-related configs
- fix: handle address and data-length errors in OSPI
- feat: Allow OSPI DMA writes larger than 64kB using chunking
- feat: Allow OSPI/HSPI/XSPI DMA writes larger than 64kB using chunking
- feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times
- feat: Add USB CRS sync support for STM32C071
- fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map.
Expand All @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668))
- feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options
- change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer
- fix: Properly set the transfer size for OSPI/HSPI/XSPI transfers with word sizes other than 8 bits.

## 0.4.0 - 2025-08-26

Expand Down
93 changes: 54 additions & 39 deletions embassy-stm32/src/hspi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
while T::REGS.sr().read().busy() {}

T::REGS.cr().modify(|w| {
w.set_fmode(0.into());
w.set_fmode(FunctionalMode::IndirectWrite.into());
});

// Configure alternate bytes
Expand Down Expand Up @@ -498,7 +498,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
w.set_dmaen(false);
});

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand Down Expand Up @@ -537,7 +538,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
w.set_dmaen(false);
});

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

T::REGS
.cr()
Expand Down Expand Up @@ -767,7 +769,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand All @@ -782,16 +785,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
T::REGS.ar().write(|v| v.set_address(current_address));
}

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
};
for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.blocking_wait();
transfer.blocking_wait();
}

finish_dma(T::REGS);

Expand All @@ -807,21 +812,24 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;
T::REGS
.cr()
.modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
};
for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.blocking_wait();
transfer.blocking_wait();
}

finish_dma(T::REGS);

Expand All @@ -837,7 +845,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand All @@ -852,16 +861,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
T::REGS.ar().write(|v| v.set_address(current_address));
}

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
};
for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.await;
transfer.await;
}

finish_dma(T::REGS);

Expand All @@ -877,21 +888,25 @@ impl<'d, T: Instance> Hspi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;
T::REGS
.cr()
.modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into()));

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default())
};
// TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.await;
transfer.await;
}

finish_dma(T::REGS);

Expand Down
60 changes: 35 additions & 25 deletions embassy-stm32/src/ospi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
}

T::REGS.cr().modify(|w| {
w.set_fmode(0.into());
w.set_fmode(vals::FunctionalMode::INDIRECT_WRITE);
});

// Configure alternate bytes
Expand Down Expand Up @@ -577,7 +577,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
w.set_dmaen(false);
});

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand Down Expand Up @@ -616,7 +617,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
w.set_dmaen(false);
});

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

T::REGS
.cr()
Expand Down Expand Up @@ -1153,7 +1155,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand All @@ -1168,16 +1171,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
T::REGS.ar().write(|v| v.set_address(current_address));
}

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
};
for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.blocking_wait();
transfer.blocking_wait();
}

finish_dma(T::REGS);

Expand All @@ -1193,13 +1198,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;
T::REGS
.cr()
.modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));

// TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
for chunk in buf.chunks(0xFFFF) {
for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
Expand All @@ -1226,7 +1232,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;

let current_address = T::REGS.ar().read().address();
let current_instruction = T::REGS.ir().read().instruction();
Expand All @@ -1241,16 +1248,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
T::REGS.ar().write(|v| v.set_address(current_address));
}

let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default())
};
for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
.unwrap()
.read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default())
};

T::REGS.cr().modify(|w| w.set_dmaen(true));
T::REGS.cr().modify(|w| w.set_dmaen(true));

transfer.await;
transfer.await;
}

finish_dma(T::REGS);

Expand All @@ -1266,13 +1275,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
// Wait for peripheral to be free
while T::REGS.sr().read().busy() {}

self.configure_command(&transaction, Some(buf.len()))?;
let transfer_size_bytes = buf.len() * W::size().bytes();
self.configure_command(&transaction, Some(transfer_size_bytes))?;
T::REGS
.cr()
.modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));

// TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
for chunk in buf.chunks(0xFFFF) {
for chunk in buf.chunks(0xFFFF / W::size().bytes()) {
let transfer = unsafe {
self.dma
.as_mut()
Expand Down
Loading