From 802d726c3bc82a4fef2f0be49ed743c6d0c2c7bc Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Mon, 10 Jan 2022 20:52:11 +0100 Subject: [PATCH] Added rtic example with modified ws2812-pio --- README.md | 2 + rtic_ws2812_pio/.cargo/config | 19 +++ rtic_ws2812_pio/.gitignore | 16 +++ rtic_ws2812_pio/Cargo.toml | 94 ++++++++++++++ rtic_ws2812_pio/build.rs | 31 +++++ rtic_ws2812_pio/memory.x | 13 ++ rtic_ws2812_pio/src/main.rs | 281 ++++++++++++++++++++++++++++++++++++++++++ sd_card_spi/Cargo.toml | 2 +- sd_card_spi/src/main.rs | 37 +++--- 9 files changed, 474 insertions(+), 21 deletions(-) create mode 100644 rtic_ws2812_pio/.cargo/config create mode 100644 rtic_ws2812_pio/.gitignore create mode 100644 rtic_ws2812_pio/Cargo.toml create mode 100644 rtic_ws2812_pio/build.rs create mode 100644 rtic_ws2812_pio/memory.x create mode 100644 rtic_ws2812_pio/src/main.rs diff --git a/README.md b/README.md index 5bac1d3..b13df61 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,5 @@ An overview of this repository: - [8-Bit PWM DAC with an RC filter synthesizing sine and saw waveforms](pwm_dac_saw_sampling) - [WS2812 on the Raspberry Pi Pico with Rust](ws2812_led_cube) - [SD/MMC Card with FAT32 filesystem via SPI on Raspberry Pi Pico](sd_card_spi) + If you search for a nicer documented example also have a look at my PR + for `rp-hal`: https://github.com/WeirdConstructor/rp-hal/blob/pico_sd_card_example/boards/rp-pico/examples/pico_spi_sd_card.rs diff --git a/rtic_ws2812_pio/.cargo/config b/rtic_ws2812_pio/.cargo/config new file mode 100644 index 0000000..99730af --- /dev/null +++ b/rtic_ws2812_pio/.cargo/config @@ -0,0 +1,19 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-run-rp --chip RP2040" + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + + # Code-size optimizations. + # trap unreachable can save a lot of space, but requires nightly compiler. + # uncomment the next line if you wish to enable it + # "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] + +[build] +target = "thumbv6m-none-eabi" diff --git a/rtic_ws2812_pio/.gitignore b/rtic_ws2812_pio/.gitignore new file mode 100644 index 0000000..8511af2 --- /dev/null +++ b/rtic_ws2812_pio/.gitignore @@ -0,0 +1,16 @@ +**/*.rs.bk +.#* +.gdb_history +Cargo.lock +target/ + +# editor files +.vscode/* +!.vscode/*.md +!.vscode/*.svd +!.vscode/launch.json +!.vscode/tasks.json +!.vscode/extensions.json +!.vscode/settings.json + +*.history diff --git a/rtic_ws2812_pio/Cargo.toml b/rtic_ws2812_pio/Cargo.toml new file mode 100644 index 0000000..9c3036c --- /dev/null +++ b/rtic_ws2812_pio/Cargo.toml @@ -0,0 +1,94 @@ +[package] +authors = ["Weird Constructor"] +edition = "2018" +readme = "README.md" +name = "rp2040-rtic-ws2812-led" +version = "0.1.0" +resolver = "2" + +[dependencies] +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +embedded-hal = { version = "0.2.5", features=["unproven"] } +embedded-time = "0.12.0" +cortex-m-rtic = "0.6.0-rc.4" + +defmt = "0.2.0" +defmt-rtt = "0.2.0" +panic-probe = { version = "0.2.0", features = ["print-defmt"] } + +#rp2040-hal = { git = "https://github.com/rp-rs/rp-hal", branch="main", features=["rt"] } +rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } +pico = { git = "https://github.com/rp-rs/rp-hal.git", branch="main" } + +smart-leds = "0.3.0" +ws2812-pio = { path = "../../ws2812-pio-rs/" } + +nb = "1.0" + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 3 +overflow-checks = true + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 3 +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 3 +overflow-checks = true + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 3 + +[dependencies.num-traits] +version = "0.2.14" +default-features = false diff --git a/rtic_ws2812_pio/build.rs b/rtic_ws2812_pio/build.rs new file mode 100644 index 0000000..d534cc3 --- /dev/null +++ b/rtic_ws2812_pio/build.rs @@ -0,0 +1,31 @@ +//! 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"); +} diff --git a/rtic_ws2812_pio/memory.x b/rtic_ws2812_pio/memory.x new file mode 100644 index 0000000..0596611 --- /dev/null +++ b/rtic_ws2812_pio/memory.x @@ -0,0 +1,13 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +SECTIONS { + /* ### Boot loader */ + .boot2 ORIGIN(BOOT2) : + { + KEEP(*(.boot2)); + } > BOOT2 +} INSERT BEFORE .text; \ No newline at end of file diff --git a/rtic_ws2812_pio/src/main.rs b/rtic_ws2812_pio/src/main.rs new file mode 100644 index 0000000..b36b7fe --- /dev/null +++ b/rtic_ws2812_pio/src/main.rs @@ -0,0 +1,281 @@ +#![no_std] +#![no_main] + +//use cortex_m_rt::entry; +//use embedded_time::duration::*; +//use embedded_hal::timer::CountDown; +use panic_probe as _; +// +//use embedded_hal::adc::OneShot; +//use pico::hal::{ +// pac, +// clocks::{Clock, init_clocks_and_plls}, +// sio::Sio, +// adc::Adc, +// watchdog::Watchdog, +// timer::Timer, +//}; +// +//use pico::hal::pio::PIOExt; +////use rp2040_hal::pio::PIOExt; +//use smart_leds::{brightness, SmartLedsWrite, RGB8}; +//use ws2812_pio::Ws2812; +// +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; + +const LEN : usize = 302; + +pub fn hsv2rgb(hue: f32, sat: f32, val: f32) -> (f32, f32, f32) { + let c = val * sat; + let v = (hue / 60.0) % 2.0 - 1.0; + let v = if v < 0.0 { -v } else { v }; + let x = c * (1.0 - v); + let m = val - c; + let (r, g, b) = if hue < 60.0 { + (c, x, 0.0) + } else if hue < 120.0 { + (x, c, 0.0) + } else if hue < 180.0 { + (0.0, c, x) + } else if hue < 240.0 { + (0.0, x, c) + } else if hue < 300.0 { + (x, 0.0, c) + } else { + (c, 0.0, x) + }; + (r + m, g + m, b + m) +} + +pub fn hsv2rgb_u8(h: f32, s: f32, v: f32) -> (u8, u8, u8) { + let r = hsv2rgb(h, s, v); + ( + (r.0 * 255.0) as u8, + (r.1 * 255.0) as u8, + (r.2 * 255.0) as u8 + ) +} + +//#[entry] +//fn main() -> ! { +// info!("Program start"); +// let mut pac = pac::Peripherals::take().unwrap(); +// let _core = pac::CorePeripherals::take().unwrap(); +// let mut watchdog = Watchdog::new(pac.WATCHDOG); +// let sio = Sio::new(pac.SIO); +// +// // External high-speed crystal on the pico board is 12Mhz +// let external_xtal_freq_hz = 12_000_000u32; +// let clocks = +// init_clocks_and_plls( +// external_xtal_freq_hz, +// pac.XOSC, +// pac.CLOCKS, +// pac.PLL_SYS, +// pac.PLL_USB, +// &mut pac.RESETS, +// &mut watchdog) +// .ok() +// .unwrap(); +// +// let pins = pico::Pins::new( +// pac.IO_BANK0, +// pac.PADS_BANK0, +// sio.gpio_bank0, +// &mut pac.RESETS, +// ); +// +// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); +// let mut delay = timer.count_down(); +// +// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +// let mut ws = Ws2812::new( +// pins.gpio16.into_mode(), +// &mut pio, +// sm0, +// clocks.peripheral_clock.freq(), +// timer.count_down(), +// ); +// +// let mut adc = Adc::new(pac.ADC, &mut pac.RESETS); +// let mut adc_pin_0 = pins.gpio26.into_floating_input(); +// +// +// let mut n: u8 = 0; +// let mut leds_off : [RGB8; LEN] = [(0,0,0).into(); LEN]; +// let mut leds : [RGB8; LEN] = [(0,0,0).into(); LEN]; +// +// for i in 0..LEN { +// leds[i] = (255, 128, 64).into(); +// } +//// leds[149] = (255, 255, 255).into(); +//// leds[70] = (255, 0, 255).into(); +//// leds[100] = (255, 0, 0).into(); +// +// let colors : [RGB8; 3] = [ +// hsv2rgb_u8(0.0, 1.0, 1.0).into(), +// (0, 255, 0).into(), +// (0, 0, 255).into(), +// ]; +// +// let amperes = 8.0; +// let all_on_amp = (LEN as f32 * 3.0 * 60.0) / 1000.0; +// +// let vbrightness = ((amperes / all_on_amp) * 255.0) as u8; +// info!("brightness={} / 255", vbrightness); +// ws.write(brightness(leds_off.iter().copied(), vbrightness)).unwrap(); +// +//// for i in 0..LEN { +//// leds[i] = colors[1]; +//// } +//// info!("LEDS={}", leds.len()); +// +// let mut cnt = 0; +// +// let mut j = 0; +// +// loop { +// cnt += 1; +// if cnt > 400 { +// cnt = 0; +// } +// +// let clr = hsv2rgb_u8((cnt as f32 / 400.0) * 360.0, 0.0, 1.0); +//// info!("[{}] clr : {}", cnt, clr); +// for i in 0..LEN { +// leds[i] = clr.into(); +// } +// +// ws.write(brightness(leds.iter().copied(), vbrightness)).unwrap(); +// delay.start(16.milliseconds()); +// let _ = nb::block!(delay.wait()); +// } +//} + +//use panic_halt as _; + +#[rtic::app(device = pico::hal::pac, peripherals = true)] +mod app { + use super::*; + + use defmt::*; + use defmt_rtt as _; + + use embedded_hal::digital::v2::OutputPin; + use embedded_time::duration::Extensions; + use pico::{ + hal::{ + self, + clocks::Clock, + clocks::init_clocks_and_plls, + watchdog::Watchdog, + sio::Sio, + pio::SM0, + timer::Timer + }, + + XOSC_CRYSTAL_FREQ, + }; + + use smart_leds::{brightness, SmartLedsWrite, RGB8}; + use ws2812_pio::Ws2812Driver; + use pico::hal::pio::PIOExt; + + const SCAN_TIME_US: u32 = 1000000; + + #[shared] + struct Shared { + timer: Timer, + alarm: hal::timer::Alarm0, + led: hal::gpio::Pin, + ws: Ws2812Driver, + } + + #[local] + struct Local {} + + #[init] + fn init(c: init::Context) -> (Shared, Local, init::Monotonics) { + let mut resets = c.device.RESETS; + let mut watchdog = Watchdog::new(c.device.WATCHDOG); + let clocks = init_clocks_and_plls( + XOSC_CRYSTAL_FREQ, + c.device.XOSC, + c.device.CLOCKS, + c.device.PLL_SYS, + c.device.PLL_USB, + &mut resets, + &mut watchdog, + ) + .ok() + .unwrap(); + + let sio = Sio::new(c.device.SIO); + let pins = pico::Pins::new( + c.device.IO_BANK0, + c.device.PADS_BANK0, + sio.gpio_bank0, + &mut resets, + ); + let mut led = pins.led.into_push_pull_output(); + led.set_low().unwrap(); + + let mut timer = Timer::new(c.device.TIMER, &mut resets); + let mut alarm = timer.alarm_0().unwrap(); + let _ = alarm.schedule(SCAN_TIME_US.microseconds()); + alarm.enable_interrupt(&mut timer); + + let (mut pio, sm0, _, _, _) = c.device.PIO0.split(&mut resets); + let ws = Ws2812Driver::new( + pins.gpio4.into_mode(), + &mut pio, + sm0, + clocks.peripheral_clock.freq(), + ); + + (Shared { timer, alarm, led, ws }, Local {}, init::Monotonics()) + } + + #[task( + binds = TIMER_IRQ_0, + priority = 1, + shared = [timer, alarm, ws], + local = [], + )] + fn timer_irq(mut c: timer_irq::Context) { + let clr : RGB8 = (255, 0, 255).into(); + + c.shared.ws.lock(|ws| + ws.write([clr].iter().copied()).unwrap()); + + let timer = c.shared.timer; + let alarm = c.shared.alarm; + (timer, alarm).lock(|t, a| { + a.clear_interrupt(t); + let _ = a.schedule(SCAN_TIME_US.microseconds()); + }); + } + + #[idle(local = [x: u32 = 0])] + fn idle(cx: idle::Context) -> ! { + // Locals in idle have lifetime 'static + let _x: &'static mut u32 = cx.local.x; + +// hprintln!("idle").unwrap(); + info!("Idle started!"); + +// debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + +// let timer = Timer::new(cx.device.TIMER, &mut pac.RESETS); +// let mut delay = timer.count_down(); + + loop { + cortex_m::asm::nop(); + +// delay.start(16.milliseconds()); +// let _ = nb::block!(delay.wait()); + } + } +} diff --git a/sd_card_spi/Cargo.toml b/sd_card_spi/Cargo.toml index b9d6324..c9ed919 100644 --- a/sd_card_spi/Cargo.toml +++ b/sd_card_spi/Cargo.toml @@ -20,7 +20,7 @@ panic-probe = { version = "0.2.0", features = ["print-defmt"] } rp2040-hal = { git = "https://github.com/rp-rs/rp-hal", branch="main", features=["rt"] } rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } -pico = { git = "https://github.com/rp-rs/rp-hal.git", branch="main" } +rp-pico = { git = "https://github.com/rp-rs/rp-hal.git", branch="main" } nb = "1.0" diff --git a/sd_card_spi/src/main.rs b/sd_card_spi/src/main.rs index 6b92797..6ef30ab 100644 --- a/sd_card_spi/src/main.rs +++ b/sd_card_spi/src/main.rs @@ -11,11 +11,12 @@ use embedded_hal::digital::v2::OutputPin; use panic_probe as _; use embedded_sdmmc; +use embedded_sdmmc::filesystem::Mode; -use rp2040_hal as rphal; - -use pico::hal::{ +use rp_pico::hal::{ pac, + gpio, + spi, clocks::{Clock, init_clocks_and_plls}, sio::Sio, watchdog::Watchdog, @@ -26,16 +27,10 @@ use pico::hal::{ #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; +#[derive(Default)] pub struct DummyTimesource { } -impl DummyTimesource { - pub fn new() -> Self { - Self { - } - } -} - impl embedded_sdmmc::TimeSource for DummyTimesource { fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { embedded_sdmmc::Timestamp { @@ -71,7 +66,7 @@ fn main() -> ! { .ok() .unwrap(); - let pins = pico::Pins::new( + let pins = rp_pico::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, @@ -83,11 +78,11 @@ fn main() -> ! { // let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); - let _spi_sclk = pins.gpio2.into_mode::(); - let _spi_mosi = pins.gpio3.into_mode::(); - let _spi_miso = pins.gpio4.into_mode::(); + let _spi_sclk = pins.gpio2.into_mode::(); + let _spi_mosi = pins.gpio3.into_mode::(); + let _spi_miso = pins.gpio4.into_mode::(); let spi_cs = pins.gpio5.into_push_pull_output(); - let spi = rphal::spi::Spi::<_, _, 8>::new(pac.SPI0); + let spi = spi::Spi::<_, _, 8>::new(pac.SPI0); // Exchange the uninitialised SPI driver for an initialised one let spi = spi.init( @@ -102,7 +97,7 @@ fn main() -> ! { info!("Aquire BlockDevice ok!"); let mut cont = - embedded_sdmmc::Controller::new(block, DummyTimesource::new()); + embedded_sdmmc::Controller::new(block, DummyTimesource::default()); info!("Init SD card..."); info!("OK!\nCard size..."); @@ -118,6 +113,7 @@ fn main() -> ! { match cont.open_root_dir(&v) { Ok(dir) => { info!("Root!"); + cont.iterate_dir(&v, &dir, |ent| { info!("/{}.{}", core::str::from_utf8(ent.name.base_name()).unwrap(), @@ -127,17 +123,18 @@ fn main() -> ! { let mut file = cont.open_file_in_dir( &mut v, &dir, "O.TST", - embedded_sdmmc::filesystem::Mode::ReadOnly).unwrap(); + Mode::ReadOnly).unwrap(); + let mut buf = [0u8; 32]; let nr = cont.read(&mut v, &mut file, &mut buf).unwrap(); - info!("READ {} bytes: {}", nr, buf); cont.close_file(&v, file).unwrap(); + info!("READ {} bytes: {}", nr, buf); + let mut file = cont.open_file_in_dir( &mut v, &dir, "O.TST", -// embedded_sdmmc::filesystem::Mode::ReadWriteCreateOrAppend).unwrap(); - embedded_sdmmc::filesystem::Mode::ReadWriteCreateOrTruncate).unwrap(); + Mode::ReadWriteCreateOrTruncate).unwrap(); cont.write(&mut v, &mut file, b"foobar123\n").unwrap(); cont.close_file(&v, file).unwrap(); },