From 83849063c01e64a6b53316b8f97c77ff774f49b3 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sat, 30 Mar 2024 12:03:50 +0000 Subject: [PATCH] sdspi: SpiBus -> SpiDevice (#26) * SpiBus -> SpiDevice add rp2040 example fixes up some deps that have moved around for the examples updated to the unified esp-hal * Switch to embassy rev * Dep, import cleanup * Update all references to aligned to v0.4.2 --- Cargo.toml | 5 +- block-device-adapters/Cargo.toml | 4 +- block-device-driver/Cargo.toml | 2 +- examples/esp32c6/Cargo.toml | 11 +- examples/esp32c6/src/main.rs | 12 +- examples/rp2040/.cargo/config.toml | 11 ++ examples/rp2040/Cargo.toml | 41 ++++++ examples/rp2040/LICENSE-APACHE | 201 ++++++++++++++++++++++++++++ examples/rp2040/LICENSE-MIT | 25 ++++ examples/rp2040/build.rs | 36 +++++ examples/rp2040/memory.x | 17 +++ examples/rp2040/rust-toolchain.toml | 5 + examples/rp2040/src/main.rs | 95 +++++++++++++ sdspi/Cargo.toml | 4 +- sdspi/src/lib.rs | 29 ++-- 15 files changed, 456 insertions(+), 42 deletions(-) create mode 100644 examples/rp2040/.cargo/config.toml create mode 100644 examples/rp2040/Cargo.toml create mode 100644 examples/rp2040/LICENSE-APACHE create mode 100644 examples/rp2040/LICENSE-MIT create mode 100644 examples/rp2040/build.rs create mode 100644 examples/rp2040/memory.x create mode 100644 examples/rp2040/rust-toolchain.toml create mode 100644 examples/rp2040/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 035b4f2..94a19cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,4 @@ resolver = "2" members = ["embedded-fatfs", "block-device-driver", "block-device-adapters", "sdspi"] # exclude embedded examples because cargo doesn't do well with multi-arch workspaces -exclude = ["examples/esp32c6"] - -[patch.crates-io] -aligned = { git = "https://github.com/MabezDev/aligned", branch = "a1" } \ No newline at end of file +exclude = ["examples/esp32c6", "examples/rp2040"] diff --git a/block-device-adapters/Cargo.toml b/block-device-adapters/Cargo.toml index d550743..783377b 100644 --- a/block-device-adapters/Cargo.toml +++ b/block-device-adapters/Cargo.toml @@ -12,7 +12,7 @@ Block device adapters for managing byte level access and partitions """ [dependencies] -aligned = "0.4.1" +aligned = "0.4.2" embedded-io-async = "0.6.1" block-device-driver = { version = "0.1", path = "../block-device-driver" } @@ -27,4 +27,4 @@ embedded-io-adapters = { version = "0.6", package = "embedded-io-adapters", feat [features] log = ["dep:log"] -defmt = ["dep:defmt"] \ No newline at end of file +defmt = ["dep:defmt"] diff --git a/block-device-driver/Cargo.toml b/block-device-driver/Cargo.toml index c66f82f..19c1bc1 100644 --- a/block-device-driver/Cargo.toml +++ b/block-device-driver/Cargo.toml @@ -12,4 +12,4 @@ Block device trait """ [dependencies] -aligned = "0.4.1" \ No newline at end of file +aligned = "0.4.2" diff --git a/examples/esp32c6/Cargo.toml b/examples/esp32c6/Cargo.toml index 102c9b7..bd12679 100644 --- a/examples/esp32c6/Cargo.toml +++ b/examples/esp32c6/Cargo.toml @@ -6,28 +6,25 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -esp32c6-hal = { version = "0.8.0", features = ["eh1", "async", "embassy", "embassy-time-systick", "embassy-executor-thread"] } +esp-hal = { version = "0.16.1", features = ["esp32c6", "eh1", "async", "embassy", "embassy-time-systick-16mhz", "embassy-executor-thread", "embassy-integrated-timers"] } esp-backtrace = { version = "0.11.0", features = ["esp32c6", "panic-handler", "exception-handler", "println"] } esp-println = { version = "0.9.0", features = ["esp32c6", "log"] } log = { version = "0.4.20" } embassy-time = "0.3" embassy-executor = { version = "0.5.0", features = ["task-arena-size-8192"] } embedded-hal-async = "1" +embedded-hal-bus = { version = "0.1.0", features = ["async", "defmt-03"] } static_cell = { version = "1", features = ["nightly"] } embedded-io-async = "0.6" sdspi = { version = "0.1.0", path = "../../sdspi", features = ["log"] } -aligned = "0.4.1" +aligned = "0.4.2" block-device-adapters = { version = "0.1.0", path = "../../block-device-adapters" } embedded-fatfs = { version = "0.1.0", path = "../../embedded-fatfs", default-features = false, features = ["log"] } [patch.crates-io] -# we can remove this once esp-hal is unified: https://github.com/esp-rs/esp-hal/pull/1196 -esp32c6-hal = { git = "https://github.com/MabezDev/esp-hal/", rev = "9a95c0aa880af7271f059797339bf890d2d59c64" } -esp-hal = { git = "https://github.com/MabezDev/esp-hal/", rev = "9a95c0aa880af7271f059797339bf890d2d59c64" } -aligned = { git = "https://github.com/MabezDev/aligned", branch = "a1" } # We can remove this once https://github.com/embassy-rs/embassy/pull/2593 is released embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "4657c105473122017a2df0fec6449ffb401927f4" } embassy-time-driver = { git = "https://github.com/embassy-rs/embassy", rev = "4657c105473122017a2df0fec6449ffb401927f4" } -embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "4657c105473122017a2df0fec6449ffb401927f4" } \ No newline at end of file +embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "4657c105473122017a2df0fec6449ffb401927f4" } diff --git a/examples/esp32c6/src/main.rs b/examples/esp32c6/src/main.rs index 32463a5..8e00115 100644 --- a/examples/esp32c6/src/main.rs +++ b/examples/esp32c6/src/main.rs @@ -6,8 +6,10 @@ use block_device_adapters::BufStreamError; use embassy_executor::Spawner; use embedded_fatfs::FsOptions; use embedded_hal_async::delay::DelayNs; +use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::{Read, Seek, Write}; -use esp32c6_hal::{ +use esp_backtrace as _; +use esp_hal::{ clock::ClockControl, dma::Dma, dma::DmaPriority, @@ -20,7 +22,6 @@ use esp32c6_hal::{ }, FlashSafeDma, IO, }; -use esp_backtrace as _; use sdspi::SdSpi; #[main] @@ -31,7 +32,7 @@ async fn main(_spawner: Spawner) { embassy::init( &clocks, - esp32c6_hal::systimer::SystemTimer::new(peripherals.SYSTIMER), + esp_hal::systimer::SystemTimer::new(peripherals.SYSTIMER), ); esp_println::logger::init_logger_from_env(); @@ -62,14 +63,15 @@ async fn main(_spawner: Spawner) { let spi = FlashSafeDma::<_, 512>::new(spi); - let mut sd = - SdSpi::<_, _, _, aligned::A1>::new(spi, cs.into_push_pull_output(), embassy_time::Delay); + let spid = ExclusiveDevice::new(spi, cs.into_push_pull_output(), embassy_time::Delay); + let mut sd = SdSpi::<_, _, aligned::A1>::new(spid, embassy_time::Delay); loop { // Initialize the card if let Ok(_) = sd.init().await { // Increase the speed up to the SD max of 25mhz sd.spi() + .bus_mut() .inner_mut() .change_bus_frequency(25u32.MHz(), &clocks); log::info!("Initialization complete!"); diff --git a/examples/rp2040/.cargo/config.toml b/examples/rp2040/.cargo/config.toml new file mode 100644 index 0000000..afb8f4e --- /dev/null +++ b/examples/rp2040/.cargo/config.toml @@ -0,0 +1,11 @@ +#[unstable] +#build-std = ["core"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-rs run --chip RP2040" + +[build] +target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ + +[env] +DEFMT_LOG = "debug" diff --git a/examples/rp2040/Cargo.toml b/examples/rp2040/Cargo.toml new file mode 100644 index 0000000..303b4ad --- /dev/null +++ b/examples/rp2040/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "embedded-fatfs-example" +version = "0.1.0" +authors = ["Scott Mabin ", "Caleb Jamison "] +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-embedded-hal = { version = "0.1.0", features = ["defmt"] } +embassy-sync = { version = "0.5.0", features = ["defmt"] } +embassy-executor = { version = "0.5.0", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } +embassy-usb = { version = "0.1.0", features = ["defmt"] } +embassy-net = { version = "0.4.0", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-futures = { version = "0.1.0" } + +cortex-m = { version = "0.7.6", features = ["inline-asm"] } +cortex-m-rt = "0.7.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } +defmt = "0.3" +defmt-rtt = "0.4" +static_cell = { version = "1", features = ["nightly"] } +embedded-hal-async = "1" +embedded-io-async = "0.6" +heapless = {version = "0.8", features = ["defmt-03"]} + +sdspi = { version = "0.1.0", path = "../../sdspi", features = ["defmt"] } +aligned = "0.4.2" +block-device-adapters = { version = "0.1.0", path = "../../block-device-adapters" } +embedded-fatfs = { version = "0.1.0", path = "../../embedded-fatfs", default-features = false, features = ["defmt", "lfn"] } + + +[patch.crates-io] +# we can remove this once embassy #2732 is released: https://github.com/embassy-rs/embassy/pull/2732 +embassy-sync = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } +embassy-executor = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } +embassy-time = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } +embassy-rp = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } +embassy-futures = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } +embassy-embedded-hal = {git = "https://github.com/embassy-rs/embassy", rev = "a009275875228a3f9c59dcad114ef378b3f6f2ea" } diff --git a/examples/rp2040/LICENSE-APACHE b/examples/rp2040/LICENSE-APACHE new file mode 100644 index 0000000..d2c040e --- /dev/null +++ b/examples/rp2040/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/examples/rp2040/LICENSE-MIT b/examples/rp2040/LICENSE-MIT new file mode 100644 index 0000000..05c9efc --- /dev/null +++ b/examples/rp2040/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright 2024 Scott Mabin + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/examples/rp2040/build.rs b/examples/rp2040/build.rs new file mode 100644 index 0000000..3f915f9 --- /dev/null +++ b/examples/rp2040/build.rs @@ -0,0 +1,36 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/rp2040/memory.x b/examples/rp2040/memory.x new file mode 100644 index 0000000..ef19dff --- /dev/null +++ b/examples/rp2040/memory.x @@ -0,0 +1,17 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + + /* Pick one of the two options for RAM layout */ + + /* OPTION A: Use all RAM banks as one big block */ + /* Reasonable, unless you are doing something */ + /* really particular with DMA or other concurrent */ + /* access that would benefit from striping */ + RAM : ORIGIN = 0x20000000, LENGTH = 264K + + /* OPTION B: Keep the unstriped sections separate */ + /* RAM: ORIGIN = 0x20000000, LENGTH = 256K */ + /* SCRATCH_A: ORIGIN = 0x20040000, LENGTH = 4K */ + /* SCRATCH_B: ORIGIN = 0x20041000, LENGTH = 4K */ +} diff --git a/examples/rp2040/rust-toolchain.toml b/examples/rp2040/rust-toolchain.toml new file mode 100644 index 0000000..a0f0e47 --- /dev/null +++ b/examples/rp2040/rust-toolchain.toml @@ -0,0 +1,5 @@ +[toolchain] +channel = "stable" +components = ["rust-src", "rustfmt"] +targets = ["thumbv6m-none-eabi"] + diff --git a/examples/rp2040/src/main.rs b/examples/rp2040/src/main.rs new file mode 100644 index 0000000..7c4ba7a --- /dev/null +++ b/examples/rp2040/src/main.rs @@ -0,0 +1,95 @@ +#![no_std] +#![no_main] + +use block_device_adapters::BufStream; +use block_device_adapters::BufStreamError; +use embassy_embedded_hal::shared_bus::asynch::spi::SpiDeviceWithConfig; +use embassy_executor::Spawner; +use embassy_rp::{ + gpio::{Level, Output}, + peripherals::*, + spi::{Async, Config, Spi}, +}; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex}; +use embedded_fatfs::FsOptions; +use embedded_hal_async::delay::DelayNs; +use heapless::{String, Vec}; +use sdspi::SdSpi; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +static SPI_BUS: StaticCell>> = + StaticCell::new(); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + defmt::info!("Hello World!"); + + let miso = p.PIN_16; + let mosi = p.PIN_7; + let clk = p.PIN_6; + let cs = Output::new(p.PIN_5, Level::High); + + let mut config = Config::default(); + config.frequency = 400_000; + + let spi = Spi::new( + p.SPI0, + clk, + mosi, + miso, + p.DMA_CH0, + p.DMA_CH1, + config.clone(), + ); + let spi_bus = SPI_BUS.init(Mutex::new(spi)); + + let spid = SpiDeviceWithConfig::new(spi_bus, cs, config); + let mut sd = SdSpi::<_, _, aligned::A1>::new(spid, embassy_time::Delay); + + loop { + // Initialize the card + if let Ok(_) = sd.init().await { + // Increase the speed up to the SD max of 25mhz + + let mut config = Config::default(); + config.frequency = 25_000_000; + sd.spi().set_config(config); + defmt::info!("Initialization complete!"); + + break; + } + defmt::info!("Failed to init card, retrying..."); + embassy_time::Delay.delay_ns(5000u32).await; + } + + let inner = BufStream::<_, 512>::new(sd); + + async { + let fs = embedded_fatfs::FileSystem::new(inner, FsOptions::new()).await?; + { + let root = fs.root_dir(); + let mut iter = root.iter(); + loop { + if let Some(Ok(entry)) = iter.next().await { + let name: String<256> = String::from_utf8( + Vec::from_slice(entry.short_file_name_as_bytes()).unwrap(), + ) + .unwrap(); + defmt::info!("Name:{} Length:{}", &name, entry.len()); + } else { + defmt::info!("end"); + break; + } + } + } + fs.unmount().await?; + + Ok::<(), embedded_fatfs::Error>>(()) + } + .await + .expect("Filesystem tests failed!"); + + loop {} +} diff --git a/sdspi/Cargo.toml b/sdspi/Cargo.toml index aa274cb..28209f9 100644 --- a/sdspi/Cargo.toml +++ b/sdspi/Cargo.toml @@ -9,7 +9,7 @@ embedded-hal = "1" sdio-host = "0.9.0" block-device-driver = { version = "0.1.0", path = "../block-device-driver" } embassy-futures = "0.1.1" -aligned = "0.4.1" +aligned = "0.4.2" log = { version = "0.4", optional = true } defmt = { version = "0.3", optional = true } @@ -18,4 +18,4 @@ defmt = { version = "0.3", optional = true } # enable log support log = ["dep:log"] # enable defmt support -defmt = ["dep:defmt"] \ No newline at end of file +defmt = ["dep:defmt"] diff --git a/sdspi/src/lib.rs b/sdspi/src/lib.rs index 2d180e2..50fb95d 100644 --- a/sdspi/src/lib.rs +++ b/sdspi/src/lib.rs @@ -69,31 +69,27 @@ pub enum Error { WriteError, } -pub struct SdSpi +pub struct SdSpi where - SPI: embedded_hal_async::spi::SpiBus, - CS: embedded_hal::digital::OutputPin, + SPI: embedded_hal_async::spi::SpiDevice, D: embedded_hal_async::delay::DelayNs, ALIGN: aligned::Alignment, { spi: SPI, - cs: CS, delay: D, card: Option, _align: PhantomData, } -impl SdSpi +impl SdSpi where - SPI: embedded_hal_async::spi::SpiBus, - CS: embedded_hal::digital::OutputPin, + SPI: embedded_hal_async::spi::SpiDevice, D: embedded_hal_async::delay::DelayNs + Clone, ALIGN: aligned::Alignment, { - pub fn new(spi: SPI, cs: CS, delay: D) -> Self { + pub fn new(spi: SPI, delay: D) -> Self { Self { spi, - cs, delay, card: None, _align: PhantomData, @@ -101,14 +97,12 @@ where } pub async fn init(&mut self) -> Result<(), Error> { - self.cs.set_high().map_err(|_| Error::ChipSelect)?; let r = async { // Supply minimum of 74 clock cycles without CS asserted. self.spi .write(&[0xFF; 10]) .await .map_err(|_| Error::SpiError)?; - self.cs.set_low().map_err(|_| Error::ChipSelect)?; with_timeout(self.delay.clone(), 1000, async { loop { @@ -207,8 +201,6 @@ where } .await; - self.cs.set_high().map_err(|_| Error::ChipSelect)?; - r } @@ -217,7 +209,6 @@ where block_address: u32, data: &mut [Aligned], ) -> Result<(), Error> { - self.cs.set_low().map_err(|_| Error::ChipSelect)?; let r = async { if data.len() == 1 { self.cmd(read_single_block(block_address)).await?; @@ -232,7 +223,6 @@ where Ok(()) } .await; - self.cs.set_high().map_err(|_| Error::ChipSelect)?; r?; @@ -244,7 +234,6 @@ where block_address: u32, data: &[Aligned], ) -> Result<(), Error> { - self.cs.set_low().map_err(|_| Error::ChipSelect)?; let r = async { if data.len() == 1 { self.cmd(write_single_block(block_address)).await?; @@ -280,7 +269,6 @@ where Ok(()) } .await; - self.cs.set_high().map_err(|_| Error::ChipSelect)?; r?; @@ -412,11 +400,10 @@ where } } -impl block_device_driver::BlockDevice - for SdSpi +impl block_device_driver::BlockDevice + for SdSpi where - SPI: embedded_hal_async::spi::SpiBus, - CS: embedded_hal::digital::OutputPin, + SPI: embedded_hal_async::spi::SpiDevice, D: embedded_hal_async::delay::DelayNs + Clone, ALIGN: aligned::Alignment, {