aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgoodhoko <[email protected]>2025-09-15 15:34:07 +0200
committergoodhoko <[email protected]>2025-09-16 09:47:23 +0200
commit8ed1e796bad7b3dbf6e78ea5e5d89b7257571d06 (patch)
treeec600c8b8fb91cbd5979ac13832851890c21dca7
parentfe95e338617d28116e38af6b8c5a5be37c6c24a0 (diff)
Handle OSPI address errors
We were using OSPI in indirect mode via DMA and noticed that the transfer future would never resolve. It was forever busy-looping in `finish_dma()` on the `while !regs.sr().read().tcf() {}` line. After some debugging we noticed that the the `TEF` flag is set. The data sheet says the following about this flag: > The following errors set the TEF flag in OCTOSPI_SR and generates an interrupt if enabled (TEIE = 1 in OCTOSPI_CR): > - in indirect or automatic status-polling mode, when a wrong address has been programmed in OCTOSPI_AR (according to the device size defined by DEVSIZE[4:0]). > - in indirect mode, if the address plus the data length exceed the device size: TEF is set as soon as the access is triggered. Indeed we were configuring our device size to 0 while specifying a non-zero address. Detect this condition and return an error early - as soon as we configure the registers (which, according to the data sheet, should be enough to raise the flag) Also document this behavior on the respective TransferConfig and Config fields. Testing ------- See https://github.com/goodhoko/spi-error-test/blob/main/src/main.rs
-rw-r--r--embassy-stm32/src/ospi/mod.rs21
1 files changed, 18 insertions, 3 deletions
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index eebaf5573..c291a311d 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -31,7 +31,9 @@ pub struct Config {
31 /// Indicates the type of external device connected 31 /// Indicates the type of external device connected
32 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface 32 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
33 /// Defines the size of the external device connected to the OSPI corresponding 33 /// Defines the size of the external device connected to the OSPI corresponding
34 /// to the number of address bits required to access the device 34 /// to the number of address bits required to access the device.
35 /// When using indirect mode, [`TransferConfig::address`] + the length of the data being read
36 /// or written must fit within the configured `device_size`, otherwise an error is returned.
35 pub device_size: MemorySize, 37 pub device_size: MemorySize,
36 /// Sets the minimum number of clock cycles that the chip select signal must be held high 38 /// Sets the minimum number of clock cycles that the chip select signal must be held high
37 /// between commands 39 /// between commands
@@ -95,10 +97,11 @@ pub struct TransferConfig {
95 pub isize: AddressSize, 97 pub isize: AddressSize,
96 /// Instruction Double Transfer rate enable 98 /// Instruction Double Transfer rate enable
97 pub idtr: bool, 99 pub idtr: bool,
98
99 /// Address width (ADMODE) 100 /// Address width (ADMODE)
100 pub adwidth: OspiWidth, 101 pub adwidth: OspiWidth,
101 /// Device memory address 102 /// Device memory address.
103 /// In indirect mode, this value + the length of the data being read or written must be within
104 /// configured [`Config::device_size`], otherwise the transfer returns an error.
102 pub address: Option<u32>, 105 pub address: Option<u32>,
103 /// Number of Address Bytes 106 /// Number of Address Bytes
104 pub adsize: AddressSize, 107 pub adsize: AddressSize,
@@ -528,6 +531,18 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
528 } 531 }
529 } 532 }
530 533
534 // The following errors set the TEF flag in OCTOSPI_SR register:
535 // - in indirect or automatic status-polling mode, when a wrong address has been programmed
536 // in OCTOSPI_AR (according to the device size defined by DEVSIZE[4:0])
537 // - in indirect mode, if the address plus the data length exceed the device size: TEF is
538 // set as soon as the access is triggered.
539 if T::REGS.sr().read().tef() {
540 // Clear the TEF register to make it ready for the next transfer.
541 T::REGS.fcr().write(|w| w.set_ctef(true));
542
543 return Err(OspiError::InvalidCommand);
544 }
545
531 Ok(()) 546 Ok(())
532 } 547 }
533 548