diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a5e92e..3a2f982 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic
 
 - `File` now implements the `embedded-io` `Read`, `Write` and `Seek` traits.
 - New `iterate_dir_lfn` method on `VolumeManager` and `Directory` - provides decoded Long File Names as `Option<&str>`
+- Implement `core::error::Error` for all error types (behind crate feature `core-error` as this raises the MSRV to 1.81)
 
 ### Removed
 
diff --git a/Cargo.toml b/Cargo.toml
index 49b1317..74e4e21 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,3 +33,4 @@ sha2 = "0.10"
 default = ["log"]
 defmt-log = ["dep:defmt"]
 log = ["dep:log"]
+core-error = []
diff --git a/src/lib.rs b/src/lib.rs
index c6af4e9..c7e33a2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -68,6 +68,8 @@
 //! * `defmt-log`: By turning off the default features and enabling the
 //!   `defmt-log` feature you can configure this crate to log messages over defmt
 //!   instead.
+//! * `core-error`: Enables implementations of `core::error::Error` for all error
+//!   types. This raises the Minimum Supported Rust Version to 1.81.
 //!
 //! You cannot enable both the `log` feature and the `defmt-log` feature.
 
@@ -272,6 +274,51 @@ where
     }
 }
 
+impl<E> core::fmt::Display for Error<E>
+where
+    E: core::fmt::Debug + core::fmt::Display,
+{
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        match self {
+            Error::DeviceError(e) => write!(f, "error from underlying block device: {e}"),
+            Error::FormatError(s) => write!(f, "filesystem is badly formatted: {s}"),
+            Error::NoSuchVolume => write!(f, "no such volume"),
+            Error::FilenameError(_) => write!(f, "bad filename"),
+            Error::TooManyOpenVolumes => write!(f, "too many open volumes"),
+            Error::TooManyOpenDirs => write!(f, "too many open directories"),
+            Error::TooManyOpenFiles => write!(f, "too many open files"),
+            Error::BadHandle => write!(f, "bad handle"),
+            Error::NotFound => write!(f, "file or directory does not exist"),
+            Error::FileAlreadyOpen => write!(f, "file already open"),
+            Error::DirAlreadyOpen => write!(f, "directory already open"),
+            Error::OpenedDirAsFile => write!(f, "cannot open directory as file"),
+            Error::OpenedFileAsDir => write!(f, "cannot open file as directory"),
+            Error::DeleteDirAsFile => write!(f, "cannot delete directory as file"),
+            Error::VolumeStillInUse => write!(f, "volume is still in use"),
+            Error::VolumeAlreadyOpen => write!(f, "cannot open volume twice"),
+            Error::Unsupported => write!(f, "unsupported operation"),
+            Error::EndOfFile => write!(f, "end of file"),
+            Error::BadCluster => write!(f, "bad cluster"),
+            Error::ConversionError => write!(f, "type conversion failed"),
+            Error::NotEnoughSpace => write!(f, "not enough space on device"),
+            Error::AllocationError => write!(f, "cluster not properly allocated"),
+            Error::UnterminatedFatChain => write!(f, "FAT chain unterminated"),
+            Error::ReadOnly => write!(f, "file is read-only"),
+            Error::FileAlreadyExists => write!(f, "file already exists"),
+            Error::BadBlockSize(size) => {
+                write!(f, "bad block size: {size} (only 512 byte blocks supported)")
+            }
+            Error::InvalidOffset => write!(f, "invalid seek offset"),
+            Error::DiskFull => write!(f, "disk full"),
+            Error::DirAlreadyExists => write!(f, "directory already exists"),
+            Error::LockError => write!(f, "already locked"),
+        }
+    }
+}
+
+#[cfg(feature = "core-error")]
+impl<E> core::error::Error for Error<E> where E: core::fmt::Debug + core::fmt::Display {}
+
 /// A handle to a volume.
 ///
 /// A volume is a partition with a filesystem within it.
diff --git a/src/sdcard/mod.rs b/src/sdcard/mod.rs
index 553791f..c27fa0e 100644
--- a/src/sdcard/mod.rs
+++ b/src/sdcard/mod.rs
@@ -624,6 +624,33 @@ pub enum Error {
     GpioError,
 }
 
+impl core::fmt::Display for Error {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        match self {
+            Error::Transport => write!(f, "error from SPI peripheral"),
+            Error::CantEnableCRC => write!(f, "failed to enable CRC checking"),
+            Error::TimeoutReadBuffer => write!(f, "timeout when reading data"),
+            Error::TimeoutWaitNotBusy => write!(f, "timeout when waiting for card to not be busy"),
+            Error::TimeoutCommand(command) => write!(f, "timeout when executing command {command}"),
+            Error::TimeoutACommand(command) => write!(
+                f,
+                "timeout when executing application-specific command {command}"
+            ),
+            Error::Cmd58Error => write!(f, "bad response from command 58"),
+            Error::RegisterReadError => write!(f, "failed to read Card Specific Data register"),
+            Error::CrcError(_, _) => write!(f, "CRC mismatch"),
+            Error::ReadError => write!(f, "read error"),
+            Error::WriteError => write!(f, "write error"),
+            Error::BadState => write!(f, "cannot perform operation with card in thiis state"),
+            Error::CardNotFound => write!(f, "card not found"),
+            Error::GpioError => write!(f, "cannot set GPIO pin"),
+        }
+    }
+}
+
+#[cfg(feature = "core-error")]
+impl core::error::Error for Error {}
+
 /// The different types of card we support.
 #[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]