Compare commits
6 Commits
main
...
savanni/pi
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | e8aa2432d3 | |
Savanni D'Gerinel | d3eeb02d2f | |
Savanni D'Gerinel | d76fd8cc39 | |
Savanni D'Gerinel | 93b84ee72d | |
Savanni D'Gerinel | 506a13e802 | |
Savanni D'Gerinel | 98ceab9833 |
File diff suppressed because it is too large
Load Diff
|
@ -30,5 +30,5 @@ members = [
|
||||||
"sgf",
|
"sgf",
|
||||||
"timezone-testing",
|
"timezone-testing",
|
||||||
"tree",
|
"tree",
|
||||||
"visions/server",
|
"visions/server", "pi-usb-serial", "tft"
|
||||||
]
|
, "serial-comm", "pi-led-pwm"]
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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());
|
||||||
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ static HEAP: Heap = Heap::empty();
|
||||||
|
|
||||||
const LIGHT_SCALE: I16F16 = I16F16::lit("256.0");
|
const LIGHT_SCALE: I16F16 = I16F16::lit("256.0");
|
||||||
const DASHBOARD_BRIGHTESS: u8 = 1;
|
const DASHBOARD_BRIGHTESS: u8 = 1;
|
||||||
const BODY_BRIGHTNESS: u8 = 8;
|
const BODY_BRIGHTNESS: u8 = 16;
|
||||||
|
|
||||||
struct DebouncedButton<P: PinId> {
|
struct DebouncedButton<P: PinId> {
|
||||||
debounce: Instant,
|
debounce: Instant,
|
||||||
|
|
|
@ -292,6 +292,35 @@ impl Animation for Blinker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum FlowDirection {
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Water {
|
||||||
|
transition: Fade,
|
||||||
|
flow_direction: FlowDirection,
|
||||||
|
transition_size: u8,
|
||||||
|
splash: u8,
|
||||||
|
splash_zone: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Water {
|
||||||
|
fn new(
|
||||||
|
starting_dashboard: DashboardPattern,
|
||||||
|
starting_body: BodyPattern,
|
||||||
|
time: Instant,
|
||||||
|
) {
|
||||||
|
Self {
|
||||||
|
transition: Fade::new(starting_dashboard, starting_body, WATER_DASHBOARD, WATER_BODY, DEFAULT_FRAMES),
|
||||||
|
flow_direction: FlowDirection::Forward,
|
||||||
|
transition_size: 4,
|
||||||
|
splash: 2,
|
||||||
|
splash_zone: 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Brake,
|
Brake,
|
||||||
|
@ -336,7 +365,7 @@ impl Pattern {
|
||||||
|
|
||||||
fn body(&self) -> BodyPattern {
|
fn body(&self) -> BodyPattern {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Water => OFF_BODY,
|
Pattern::Water => WATER_BODY,
|
||||||
Pattern::GayPride => PRIDE_BODY,
|
Pattern::GayPride => PRIDE_BODY,
|
||||||
Pattern::TransPride => TRANS_PRIDE_BODY,
|
Pattern::TransPride => TRANS_PRIDE_BODY,
|
||||||
}
|
}
|
||||||
|
@ -384,6 +413,13 @@ impl App {
|
||||||
|
|
||||||
fn update_animation(&mut self, time: Instant) {
|
fn update_animation(&mut self, time: Instant) {
|
||||||
match self.state {
|
match self.state {
|
||||||
|
State::Pattern(Pattern::Water) => {
|
||||||
|
self.current_animation = Box::new(Water::new(
|
||||||
|
self.dashboard_lights.clone(),
|
||||||
|
self.lights.clone(),
|
||||||
|
time,
|
||||||
|
));
|
||||||
|
}
|
||||||
State::Pattern(ref pattern) => {
|
State::Pattern(ref pattern) => {
|
||||||
self.current_animation = Box::new(Fade::new(
|
self.current_animation = Box::new(Fade::new(
|
||||||
self.dashboard_lights.clone(),
|
self.dashboard_lights.clone(),
|
||||||
|
|
|
@ -97,8 +97,83 @@ pub const OFF_BODY: BodyPattern = [RGB_OFF; 60];
|
||||||
pub const DEFAULT_FRAMES: U16F0 = U16F0::lit("30");
|
pub const DEFAULT_FRAMES: U16F0 = U16F0::lit("30");
|
||||||
|
|
||||||
pub const WATER_DASHBOARD: DashboardPattern = [WATER_1, WATER_2, WATER_3];
|
pub const WATER_DASHBOARD: DashboardPattern = [WATER_1, WATER_2, WATER_3];
|
||||||
|
pub const WATER_BODY: BodyPattern = [
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
|
||||||
pub const WATER_BODY: BodyPattern = [RGB_OFF; 60];
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
|
||||||
|
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
WATER_3,
|
||||||
|
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
WATER_2,
|
||||||
|
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
WATER_1,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const FIRE_DASHBOARD: DashboardPattern = [RGB_OFF; 3];
|
||||||
|
pub const FIRE_BODY: BodyPattern = [RGB_OFF; 60];
|
||||||
|
|
||||||
|
pub const EARTH_DASHBOARD: DashboardPattern = [RGB_OFF; 3];
|
||||||
|
pub const EARTH_BODY: BodyPattern = [RGB_OFF; 60];
|
||||||
|
|
||||||
|
pub const AIR_DASHBOARD: DashboardPattern = [RGB_OFF; 3];
|
||||||
|
pub const AIR_BODY: BodyPattern = [RGB_OFF; 60];
|
||||||
|
|
||||||
pub const PRIDE_DASHBOARD: DashboardPattern = [PRIDE_RED, PRIDE_GREEN, PRIDE_INDIGO];
|
pub const PRIDE_DASHBOARD: DashboardPattern = [PRIDE_RED, PRIDE_GREEN, PRIDE_INDIGO];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
target = "thumbv6m-none-eabi"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "elf2uf2-rs -d"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "pi-led-pwm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m-rt = "0.7.3"
|
||||||
|
embassy-embedded-hal = "0.2.0"
|
||||||
|
embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "integrated-timers"] }
|
||||||
|
embassy-rp = { version = "0.2.0", features = ["time-driver", "critical-section-impl"] }
|
||||||
|
embassy-time = "0.3.2"
|
||||||
|
panic-probe = "0.3.2"
|
|
@ -0,0 +1,26 @@
|
||||||
|
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");
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
MEMORY {
|
||||||
|
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||||
|
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||||
|
/*
|
||||||
|
* RAM consists of 4 banks, SRAM0-SRAM3, with a striped mapping.
|
||||||
|
* This is usually good for performance, as it distributes load on
|
||||||
|
* those banks evenly.
|
||||||
|
*/
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||||
|
/*
|
||||||
|
* RAM banks 4 and 5 use a direct mapping. They can be used to have
|
||||||
|
* memory areas dedicated for some specific job, improving predictability
|
||||||
|
* of access times.
|
||||||
|
* Example: Separate stacks for core0 and core1.
|
||||||
|
*/
|
||||||
|
SRAM4 : ORIGIN = 0x20040000, LENGTH = 4k
|
||||||
|
SRAM5 : ORIGIN = 0x20041000, LENGTH = 4k
|
||||||
|
|
||||||
|
/* SRAM banks 0-3 can also be accessed directly. However, those ranges
|
||||||
|
alias with the RAM mapping, above. So don't use them at the same time!
|
||||||
|
SRAM0 : ORIGIN = 0x21000000, LENGTH = 64k
|
||||||
|
SRAM1 : ORIGIN = 0x21010000, LENGTH = 64k
|
||||||
|
SRAM2 : ORIGIN = 0x21020000, LENGTH = 64k
|
||||||
|
SRAM3 : ORIGIN = 0x21030000, LENGTH = 64k
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN(BOOT2_FIRMWARE)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
/* ### Boot loader */
|
||||||
|
.boot2 ORIGIN(BOOT2) :
|
||||||
|
{
|
||||||
|
KEEP(*(.boot2));
|
||||||
|
} > BOOT2
|
||||||
|
} INSERT BEFORE .text;
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::pwm::Pwm;
|
||||||
|
use embassy_time::Timer;
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
struct RgBreathing {
|
||||||
|
val: u16,
|
||||||
|
change: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RgBreathing {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
|
let mut config_gb = embassy_rp::pwm::Config::default();
|
||||||
|
config_gb.top = 256;
|
||||||
|
config_gb.compare_a = 256;
|
||||||
|
config_gb.compare_b = 256;
|
||||||
|
let mut pwm_gb = Pwm::new_output_ab(p.PWM_SLICE1,
|
||||||
|
p.PIN_2,
|
||||||
|
p.PIN_3,
|
||||||
|
config_gb.clone());
|
||||||
|
|
||||||
|
let mut config_r = embassy_rp::pwm::Config::default();
|
||||||
|
config_r.top = 256;
|
||||||
|
config_r.compare_a = 256;
|
||||||
|
let mut pwm_r = Pwm::new_output_a(p.PWM_SLICE2,
|
||||||
|
p.PIN_4,
|
||||||
|
config_r.clone());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
Timer::after_secs(1).await;
|
||||||
|
/*
|
||||||
|
config_gb.compare_a = config_gb.compare_a.rotate_left(1);
|
||||||
|
config_gb.compare_b = config_gb.compare_b.rotate_left(2);
|
||||||
|
pwm_gb.set_config(&config_gb);
|
||||||
|
|
||||||
|
config_r.compare_a = config_r.compare_a.rotate_left(3);
|
||||||
|
pwm_r.set_config(&config_r);
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
target = "thumbv6m-none-eabi"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "elf2uf2-rs -d"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "pi-usb-serial"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[dependencies]
|
||||||
|
embassy-embedded-hal = { version = "0.1.0", features = ["defmt"] }
|
||||||
|
embassy-sync = { version = "0.6.0", features = ["defmt"] }
|
||||||
|
embassy-executor = { version = "0.5.0", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
|
embassy-time = { version = "0.3.1", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
|
embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
|
||||||
|
embassy-usb = { version = "0.3.0" }
|
||||||
|
|
||||||
|
defmt = "0.3"
|
||||||
|
defmt-rtt = "0.4"
|
||||||
|
|
||||||
|
cortex-m-rt = "0.7.0"
|
||||||
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
|
portable-atomic = { version = "1.5", features = ["critical-section"] }
|
||||||
|
static_cell = "2"
|
|
@ -0,0 +1,26 @@
|
||||||
|
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");
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
MEMORY {
|
||||||
|
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||||
|
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||||
|
/*
|
||||||
|
* RAM consists of 4 banks, SRAM0-SRAM3, with a striped mapping.
|
||||||
|
* This is usually good for performance, as it distributes load on
|
||||||
|
* those banks evenly.
|
||||||
|
*/
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||||
|
/*
|
||||||
|
* RAM banks 4 and 5 use a direct mapping. They can be used to have
|
||||||
|
* memory areas dedicated for some specific job, improving predictability
|
||||||
|
* of access times.
|
||||||
|
* Example: Separate stacks for core0 and core1.
|
||||||
|
*/
|
||||||
|
SRAM4 : ORIGIN = 0x20040000, LENGTH = 4k
|
||||||
|
SRAM5 : ORIGIN = 0x20041000, LENGTH = 4k
|
||||||
|
|
||||||
|
/* SRAM banks 0-3 can also be accessed directly. However, those ranges
|
||||||
|
alias with the RAM mapping, above. So don't use them at the same time!
|
||||||
|
SRAM0 : ORIGIN = 0x21000000, LENGTH = 64k
|
||||||
|
SRAM1 : ORIGIN = 0x21010000, LENGTH = 64k
|
||||||
|
SRAM2 : ORIGIN = 0x21020000, LENGTH = 64k
|
||||||
|
SRAM3 : ORIGIN = 0x21030000, LENGTH = 64k
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN(BOOT2_FIRMWARE)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
/* ### Boot loader */
|
||||||
|
.boot2 ORIGIN(BOOT2) :
|
||||||
|
{
|
||||||
|
KEEP(*(.boot2));
|
||||||
|
} > BOOT2
|
||||||
|
} INSERT BEFORE .text;
|
|
@ -0,0 +1,112 @@
|
||||||
|
//! This example test the RP Pico on board LED.
|
||||||
|
//!
|
||||||
|
//! It does not work with the RP Pico W board. See wifi_blinky.rs.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use embassy_usb::{Builder, Config, class::cdc_acm::{CdcAcmClass, State}, UsbDevice, driver::EndpointError};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::{bind_interrupts, gpio, peripherals::USB, usb::{Driver, Instance, InterruptHandler}};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
use gpio::{Level, Output};
|
||||||
|
use defmt::{info, panic, unwrap};
|
||||||
|
use defmt_rtt as _;
|
||||||
|
use panic_probe as _;
|
||||||
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBCTRL_IRQ => InterruptHandler<USB>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn usb_task(mut usb: UsbDevice<'static, Driver<'static, USB>>) {
|
||||||
|
usb.run().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
let mut led = Output::new(p.PIN_15, Level::Low);
|
||||||
|
|
||||||
|
let driver = embassy_rp::usb::Driver::new(p.USB, Irqs);
|
||||||
|
let mut config = Config::new(0x9988, 0x8899);
|
||||||
|
config.manufacturer = Some("Savanni");
|
||||||
|
config.product = Some("USB test device");
|
||||||
|
config.serial_number = Some("abcdefg");
|
||||||
|
config.max_power = 100;
|
||||||
|
config.max_packet_size_0 = 64;
|
||||||
|
|
||||||
|
let mut builder = {
|
||||||
|
static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
|
||||||
|
static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
|
||||||
|
static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new();
|
||||||
|
|
||||||
|
let mut builder = Builder::new(
|
||||||
|
driver,
|
||||||
|
config,
|
||||||
|
CONFIG_DESCRIPTOR.init([0; 256]),
|
||||||
|
BOS_DESCRIPTOR.init([0; 256]),
|
||||||
|
&mut [],
|
||||||
|
CONTROL_BUF.init([0; 64]),
|
||||||
|
);
|
||||||
|
builder
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut class = {
|
||||||
|
static STATE: StaticCell<State> = StaticCell::new();
|
||||||
|
let state = STATE.init(State::new());
|
||||||
|
CdcAcmClass::new(&mut builder, state, 64)
|
||||||
|
};
|
||||||
|
|
||||||
|
let usb = builder.build();
|
||||||
|
|
||||||
|
unwrap!(spawner.spawn(usb_task(usb)));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
class.wait_connection().await;
|
||||||
|
led.set_high();
|
||||||
|
info!("Connected");
|
||||||
|
// let _ = echo(&mut class).await;
|
||||||
|
let _ = primes(&mut class).await;
|
||||||
|
info!("Disconnected");
|
||||||
|
led.set_low();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Disconnected {}
|
||||||
|
|
||||||
|
impl From<EndpointError> for Disconnected {
|
||||||
|
fn from(val: EndpointError) -> Self {
|
||||||
|
match val {
|
||||||
|
EndpointError::BufferOverflow => {
|
||||||
|
panic!("Buffer overflow");
|
||||||
|
}
|
||||||
|
EndpointError::Disabled => Disconnected{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
let n = class.read_packet(&mut buf).await?;
|
||||||
|
buf[n] = b'\r';
|
||||||
|
buf[n+1] = b'\n';
|
||||||
|
let data = &buf[..n+2];
|
||||||
|
info!("data: {:x}", data);
|
||||||
|
class.write_packet(&data).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn primes<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
|
||||||
|
let PRIMES: [u8; 55] = [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251];
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
for idx in 0..PRIMES.len() {
|
||||||
|
buf[0] = PRIMES[idx];
|
||||||
|
class.write_packet(&buf).await?;
|
||||||
|
Timer::after_secs(1).await;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.77.0"
|
channel = "1.80.0"
|
||||||
targets = [ "wasm32-unknown-unknown", "thumbv6m-none-eabi" ]
|
targets = [ "wasm32-unknown-unknown", "thumbv6m-none-eabi" ]
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "serial-comm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
|
tokio-serial = "5.4.4"
|
|
@ -0,0 +1,22 @@
|
||||||
|
use tokio_serial::{DataBits, StopBits, Parity, SerialStream};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let mut port = SerialStream::open(&tokio_serial::new("/dev/ttyACM0", 115200).parity(Parity::None).stop_bits(StopBits::One).data_bits(DataBits::Eight)).expect("serial port to open");
|
||||||
|
|
||||||
|
/*
|
||||||
|
port.writable().await.expect("writeable to succeed");
|
||||||
|
let bytes = port.try_write(b"abcdefg").expect("write to succeed");
|
||||||
|
println!("{} bytes written", bytes);
|
||||||
|
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||||
|
*/
|
||||||
|
|
||||||
|
loop {
|
||||||
|
port.readable().await.expect("readable to succeed");
|
||||||
|
let mut buf: [u8; 64]= [0; 64];
|
||||||
|
if let Ok(_) = port.try_read(&mut buf) {
|
||||||
|
println!("{:?}", &buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
[build]
|
||||||
|
target = "thumbv6m-none-eabi"
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "elf2uf2-rs -d -s"
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "e-ink"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[dependencies]
|
||||||
|
embassy-embedded-hal = { version = "0.1.0", features = ["defmt"] }
|
||||||
|
embassy-sync = { version = "0.6.0", features = ["defmt"] }
|
||||||
|
embassy-executor = { version = "0.5.0", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
|
embassy-time = { version = "0.3.1", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
|
embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
|
||||||
|
|
||||||
|
defmt = "0.3"
|
||||||
|
defmt-rtt = "0.4"
|
||||||
|
|
||||||
|
cortex-m-rt = "0.7.0"
|
||||||
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
|
embedded-hal = "1.0.0"
|
|
@ -0,0 +1,26 @@
|
||||||
|
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");
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
MEMORY {
|
||||||
|
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||||
|
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||||
|
/*
|
||||||
|
* RAM consists of 4 banks, SRAM0-SRAM3, with a striped mapping.
|
||||||
|
* This is usually good for performance, as it distributes load on
|
||||||
|
* those banks evenly.
|
||||||
|
*/
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||||
|
/*
|
||||||
|
* RAM banks 4 and 5 use a direct mapping. They can be used to have
|
||||||
|
* memory areas dedicated for some specific job, improving predictability
|
||||||
|
* of access times.
|
||||||
|
* Example: Separate stacks for core0 and core1.
|
||||||
|
*/
|
||||||
|
SRAM4 : ORIGIN = 0x20040000, LENGTH = 4k
|
||||||
|
SRAM5 : ORIGIN = 0x20041000, LENGTH = 4k
|
||||||
|
|
||||||
|
/* SRAM banks 0-3 can also be accessed directly. However, those ranges
|
||||||
|
alias with the RAM mapping, above. So don't use them at the same time!
|
||||||
|
SRAM0 : ORIGIN = 0x21000000, LENGTH = 64k
|
||||||
|
SRAM1 : ORIGIN = 0x21010000, LENGTH = 64k
|
||||||
|
SRAM2 : ORIGIN = 0x21020000, LENGTH = 64k
|
||||||
|
SRAM3 : ORIGIN = 0x21030000, LENGTH = 64k
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
EXTERN(BOOT2_FIRMWARE)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
/* ### Boot loader */
|
||||||
|
.boot2 ORIGIN(BOOT2) :
|
||||||
|
{
|
||||||
|
KEEP(*(.boot2));
|
||||||
|
} > BOOT2
|
||||||
|
} INSERT BEFORE .text;
|
|
@ -0,0 +1,179 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::{spi, spi::Spi, gpio};
|
||||||
|
use embedded_hal::delay::DelayNs;
|
||||||
|
use embassy_time::Delay;
|
||||||
|
use gpio::{Level, Output};
|
||||||
|
use defmt::*;
|
||||||
|
use defmt_rtt as _;
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* width: 320
|
||||||
|
* height: 170
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn software_reset<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x01]);
|
||||||
|
timer.delay_ms(150);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sleep_out<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x11]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_mode<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x11]);
|
||||||
|
dcx.set_high();
|
||||||
|
let _ = spi.blocking_write(&[0x63]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_display<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x13]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_on<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x29]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_address_set<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
spi.blocking_write(&[0x36]);
|
||||||
|
dcx.set_high();
|
||||||
|
spi.blocking_write(&[0x08]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_set<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
let width: u16 = 320;
|
||||||
|
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x2a]);
|
||||||
|
dcx.set_high();
|
||||||
|
let _ = spi.blocking_write(&[0x0, 0x0, (width >> 8) as u8, (width & 0xff) as u8]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn row_set<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
let height: u16 = 170;
|
||||||
|
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x2b]);
|
||||||
|
dcx.set_high();
|
||||||
|
let _ = spi.blocking_write(&[0x0, 0x0, (height >> 8) as u8, (170 & 0xff) as u8]);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_image<T, M, R>(spi: &mut Spi<T, M>, timer: &mut Delay, dcx: &mut Output<R>)
|
||||||
|
where
|
||||||
|
T: embassy_rp::spi::Instance,
|
||||||
|
M: embassy_rp::spi::Mode,
|
||||||
|
R: embassy_rp::gpio::Pin,
|
||||||
|
{
|
||||||
|
dcx.set_low();
|
||||||
|
let _ = spi.blocking_write(&[0x2c]);
|
||||||
|
dcx.set_high();
|
||||||
|
let mut buf: [u8; 320 * 170 * 3] = [0; 320 * 170 * 3];
|
||||||
|
buf[0] = 0xff;
|
||||||
|
buf[2] = 0xff;
|
||||||
|
buf[3] = 0xff;
|
||||||
|
let _ = spi.blocking_write(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
let mut timer = Delay;
|
||||||
|
|
||||||
|
let mut tft_select = Output::new(p.PIN_10, Level::High); /* Pull low to activate the chip */
|
||||||
|
let mut tft_reset = Output::new(p.PIN_11, Level::Low);
|
||||||
|
timer.delay_ms(10);
|
||||||
|
tft_reset.set_high();
|
||||||
|
let mut dcx = Output::new(p.PIN_15, Level::Low); /* Low == Command, High == Data */
|
||||||
|
|
||||||
|
let mut spi_config = spi::Config::default();
|
||||||
|
spi_config.frequency = 2_000_000;
|
||||||
|
let mut spi = embassy_rp::spi::Spi::new_blocking(
|
||||||
|
p.SPI0,
|
||||||
|
p.PIN_2,
|
||||||
|
p.PIN_3,
|
||||||
|
p.PIN_4,
|
||||||
|
spi_config
|
||||||
|
);
|
||||||
|
|
||||||
|
tft_select.set_low();
|
||||||
|
|
||||||
|
|
||||||
|
/* Software reset, 150ms delay */
|
||||||
|
software_reset(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* 10 ms delay after each additonal command */
|
||||||
|
/* Sleep out */
|
||||||
|
sleep_out(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Color mode */
|
||||||
|
color_mode(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Memory access ctrl */
|
||||||
|
memory_address_set(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Column addr set */
|
||||||
|
column_set(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Row addr set */
|
||||||
|
row_set(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Normal Display on */
|
||||||
|
normal_display(&mut spi, &mut timer, &mut dcx);
|
||||||
|
/* Main screen on */
|
||||||
|
display_on(&mut spi, &mut timer, &mut dcx);
|
||||||
|
|
||||||
|
write_image(&mut spi, &mut timer, &mut dcx);
|
||||||
|
|
||||||
|
tft_select.set_high();
|
||||||
|
}
|
Loading…
Reference in New Issue