Added template for film scanner firmware
This commit is contained in:
230
firmware/Cargo.lock
generated
230
firmware/Cargo.lock
generated
@@ -1,230 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jerk_control"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.123"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
|
||||
|
||||
[[package]]
|
||||
name = "motion-tester"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jerk_control",
|
||||
"structopt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -1,2 +1,2 @@
|
||||
[workspace]
|
||||
members = [ "jerk_control", "motion-tester" ]
|
||||
members = [ "jerk_control", "motion-tester", "film-scanner-fw" ]
|
||||
|
||||
89
firmware/film-scanner-fw/Cargo.toml
Normal file
89
firmware/film-scanner-fw/Cargo.toml
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
[package]
|
||||
name = "film-scanner-fw"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
cortex-m = "0.7.3"
|
||||
cortex-m-rt = "0.7.0"
|
||||
cortex-m-rtic = "1.0.0"
|
||||
embedded-hal = { version = "0.2.5", features=["unproven"] }
|
||||
embedded-time = "0.12.0"
|
||||
|
||||
# jnc
|
||||
usb-device = "0.2.8"
|
||||
usbd-serial = "0.1.1"
|
||||
usbd-hid = "0.5.1"
|
||||
futures = { version = "0.3", default-features = false, optional = true }
|
||||
|
||||
defmt = "0.3.0"
|
||||
defmt-rtt = "0.3.1"
|
||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
||||
|
||||
# We're using a Pico by default on this template
|
||||
rp-pico = "0.2.0"
|
||||
|
||||
# but you can use any BSP. Uncomment this to use the pro_micro_rp2040 BSP instead
|
||||
# sparkfun-pro-micro-rp2040 = "0.1.0"
|
||||
|
||||
# If you're not going to use a Board Support Package you'll need these:
|
||||
rp2040-hal = { version="0.4.0", features=["rt"] }
|
||||
|
||||
rp2040-boot2 = {version="0.2.0", optional = true }
|
||||
|
||||
# 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
|
||||
31
firmware/film-scanner-fw/build.rs
Normal file
31
firmware/film-scanner-fw/build.rs
Normal file
@@ -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");
|
||||
}
|
||||
15
firmware/film-scanner-fw/memory.x
Normal file
15
firmware/film-scanner-fw/memory.x
Normal file
@@ -0,0 +1,15 @@
|
||||
MEMORY {
|
||||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
}
|
||||
|
||||
EXTERN(BOOT2_FIRMWARE)
|
||||
|
||||
SECTIONS {
|
||||
/* ### Boot loader */
|
||||
.boot2 ORIGIN(BOOT2) :
|
||||
{
|
||||
KEEP(*(.boot2));
|
||||
} > BOOT2
|
||||
} INSERT BEFORE .text;
|
||||
42
firmware/film-scanner-fw/src/fmt.rs
Normal file
42
firmware/film-scanner-fw/src/fmt.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
// NOTE: This file came from:
|
||||
// https://github.com/Nashenas88/dactyl-manuform-kb2040-rs/blob/main/src/fmt.rs
|
||||
|
||||
//! Formatting module for helping with logging over a serial connection. This
|
||||
//! is useful on the kb2040 since there are no debugging pins exposed on the
|
||||
//! board.
|
||||
|
||||
use core::fmt;
|
||||
|
||||
pub(crate) struct Wrapper<'a> {
|
||||
buf: &'a mut [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> Wrapper<'a> {
|
||||
pub(crate) fn new(buf: &'a mut [u8]) -> Self {
|
||||
Wrapper { buf, offset: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Write for Wrapper<'a> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
let bytes = s.as_bytes();
|
||||
|
||||
// Skip over already-copied data.
|
||||
let remainder = &mut self.buf[self.offset..];
|
||||
// Check if there is space remaining (return error instead of panicking).
|
||||
if remainder.len() < bytes.len() {
|
||||
return Err(core::fmt::Error);
|
||||
}
|
||||
|
||||
// Make the two slices the same length.
|
||||
let remainder = &mut remainder[..bytes.len()];
|
||||
// Copy.
|
||||
remainder.copy_from_slice(bytes);
|
||||
|
||||
// Update offset to avoid overwriting.
|
||||
self.offset += bytes.len();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
523
firmware/film-scanner-fw/src/main.rs
Normal file
523
firmware/film-scanner-fw/src/main.rs
Normal file
@@ -0,0 +1,523 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use panic_probe as _;
|
||||
|
||||
mod fmt;
|
||||
|
||||
#[rtic::app(device = rp_pico::hal::pac, peripherals = true)]
|
||||
mod app {
|
||||
|
||||
use crate::fmt::Wrapper;
|
||||
use core::fmt::Write;
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_time::duration::Extensions;
|
||||
|
||||
use rp_pico::hal;
|
||||
use rp_pico::pac;
|
||||
use rp_pico::XOSC_CRYSTAL_FREQ;
|
||||
|
||||
// USB Device support
|
||||
use usb_device::{class_prelude::*, prelude::*};
|
||||
// USB Communications Class Device support
|
||||
use usbd_serial::SerialPort;
|
||||
|
||||
// Blinck time 5 seconds
|
||||
const SCAN_TIME_US: u32 = 5000000; // 200000; // 5000000; // 1000000; // 200000;
|
||||
|
||||
// IMPORTANT: The USB-Serial with RTIC github project example that I'm following.
|
||||
// I tried to use the Pico board examples of USB-Serial (without interrupts
|
||||
// and with interrupts with success, but when using with RTIC I could not make
|
||||
// it work when merged with the RTIC example.) So I asked some questions
|
||||
// in the in Matrix chat and received links to examples of there github
|
||||
// project where it was working, then a used and adapted some parts there
|
||||
// in this project template.
|
||||
// This were the kind folks that helped me in the Matrix chat, the 3 projects
|
||||
// that they suggest me to study are good examples of programs made with RTIC
|
||||
// and USB and should be studied.
|
||||
//
|
||||
// Paul Daniel Faria
|
||||
// https://github.com/Nashenas88/dactyl-manuform-kb2040-rs/blob/main/src/main.rs#L80
|
||||
//
|
||||
// see also:
|
||||
// korken89
|
||||
// https://github.com/korken89/pico-probe/tree/master/src
|
||||
//
|
||||
// see also:
|
||||
// Mathias
|
||||
// https://github.com/mgottschlag/rp2040-usb-sound-card/blob/b8078b57361c1b08755e5ab5f9992c56457ec18b/src/main.rs#L188
|
||||
//
|
||||
//
|
||||
// Global Static variable, has to be written inside unsafe blocks.
|
||||
// A reference can be obtained with as_ref() method.
|
||||
|
||||
pub struct Counter {
|
||||
counter: u32,
|
||||
enable: bool,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Self {
|
||||
Counter {
|
||||
counter: 0_u32,
|
||||
enable: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> u32 {
|
||||
self.counter
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.counter = 0_u32;
|
||||
}
|
||||
|
||||
fn increment(&mut self) {
|
||||
self.counter += 1_u32;
|
||||
}
|
||||
|
||||
fn enable(&mut self, state: bool) {
|
||||
self.enable = state;
|
||||
}
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {
|
||||
timer: hal::Timer,
|
||||
alarm: hal::timer::Alarm0,
|
||||
led: hal::gpio::Pin<hal::gpio::pin::bank0::Gpio25, hal::gpio::PushPullOutput>,
|
||||
led_blink_enable: bool,
|
||||
|
||||
serial: SerialPort<'static, hal::usb::UsbBus>,
|
||||
usb_dev: usb_device::device::UsbDevice<'static, hal::usb::UsbBus>,
|
||||
|
||||
counter: Counter,
|
||||
}
|
||||
|
||||
#[local]
|
||||
struct Local {}
|
||||
|
||||
#[init(local = [usb_bus: Option<usb_device::bus::UsbBusAllocator<hal::usb::UsbBus>> = None])]
|
||||
fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
|
||||
//*******
|
||||
// Initialization of the system clock.
|
||||
|
||||
let mut resets = c.device.RESETS;
|
||||
let mut watchdog = hal::watchdog::Watchdog::new(c.device.WATCHDOG);
|
||||
|
||||
// Configure the clocks - The default is to generate a 125 MHz system clock
|
||||
let clocks = hal::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();
|
||||
|
||||
//*******
|
||||
// Initialization of the USB and Serial and USB Device ID.
|
||||
|
||||
// USB
|
||||
//
|
||||
// Set up the USB driver
|
||||
// The bus that is used to manage the device and class below.
|
||||
let usb_bus: &'static _ =
|
||||
c.local
|
||||
.usb_bus
|
||||
.insert(UsbBusAllocator::new(hal::usb::UsbBus::new(
|
||||
c.device.USBCTRL_REGS,
|
||||
c.device.USBCTRL_DPRAM,
|
||||
clocks.usb_clock,
|
||||
true,
|
||||
&mut resets,
|
||||
)));
|
||||
|
||||
// Set up the USB Communications Class Device driver.
|
||||
let serial = SerialPort::new(usb_bus);
|
||||
|
||||
// Create a USB device with a fake VID and PID
|
||||
let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("Fake company")
|
||||
.product("Serial port")
|
||||
.serial_number("TEST")
|
||||
.device_class(2) // from: https://www.usb.org/defined-class-codes
|
||||
.build();
|
||||
|
||||
//*******
|
||||
// Initialization of the LED GPIO and the timer.
|
||||
|
||||
let sio = hal::Sio::new(c.device.SIO);
|
||||
let pins = rp_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 = hal::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);
|
||||
|
||||
// Enable led_blink.
|
||||
let led_blink_enable = true;
|
||||
|
||||
// Reset the counter
|
||||
let counter = Counter::new();
|
||||
|
||||
//********
|
||||
// Return the Shared variables struct, the Local variables struct and the XPTO Monitonics
|
||||
// (Note: Read again the RTIC book in the section of Monotonics timers)
|
||||
(
|
||||
Shared {
|
||||
timer,
|
||||
alarm,
|
||||
led,
|
||||
led_blink_enable,
|
||||
|
||||
serial,
|
||||
usb_dev,
|
||||
|
||||
counter,
|
||||
},
|
||||
Local {},
|
||||
init::Monotonics(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Task that blinks the rp-pico onboard LED and that send a message "LED ON!" and "LED OFF!" do USB-Serial.
|
||||
#[task(
|
||||
binds = TIMER_IRQ_0,
|
||||
priority = 1,
|
||||
shared = [timer, alarm, led, led_blink_enable, serial, counter],
|
||||
local = [tog: bool = true],
|
||||
)]
|
||||
fn timer_irq(mut cx: timer_irq::Context) {
|
||||
let mut buf = [0u8; 64];
|
||||
|
||||
let led = cx.shared.led;
|
||||
let led_blink_enable = cx.shared.led_blink_enable;
|
||||
let counter = cx.shared.counter;
|
||||
|
||||
let tog = cx.local.tog;
|
||||
|
||||
// Blinks the LED ON / OFF.
|
||||
(led, led_blink_enable, counter).lock(|led_a, led_blink_enable_a, counter_a| {
|
||||
let led_state_str: &str;
|
||||
if *led_blink_enable_a {
|
||||
if *tog {
|
||||
led_a.set_high().unwrap();
|
||||
led_state_str = "ON ";
|
||||
} else {
|
||||
led_a.set_low().unwrap();
|
||||
led_state_str = "OFF";
|
||||
}
|
||||
let _ = writeln!(
|
||||
Wrapper::new(&mut buf),
|
||||
"LED {}! counter = {}",
|
||||
led_state_str,
|
||||
counter_a.get()
|
||||
);
|
||||
}
|
||||
if counter_a.enable {
|
||||
counter_a.increment();
|
||||
}
|
||||
|
||||
if *led_blink_enable_a {
|
||||
*tog = !*tog;
|
||||
}
|
||||
});
|
||||
|
||||
// Clears the timer interrupt and Set's the new delta_time in the future.
|
||||
let mut timer = cx.shared.timer;
|
||||
let mut alarm = cx.shared.alarm;
|
||||
(alarm).lock(|a| {
|
||||
(timer).lock(|timer_a| {
|
||||
a.clear_interrupt(timer_a);
|
||||
let _ = a.schedule(SCAN_TIME_US.microseconds());
|
||||
});
|
||||
});
|
||||
|
||||
// Write the message "blabla! 2" do USB-Serial.
|
||||
cx.shared.serial.lock(|s| {
|
||||
write_serial(s, unsafe { core::str::from_utf8_unchecked(&buf) }, false);
|
||||
});
|
||||
|
||||
/*
|
||||
// Write the message "blabla! 2" do USB-Serial.
|
||||
c.shared.serial.lock(|s| {
|
||||
let mut buf = [0u8; 64];
|
||||
let _ = writeln!(Wrapper::new(&mut buf), "blabla! {}", 2); /*"{:?}"*/
|
||||
write_serial(s, unsafe { core::str::from_utf8_unchecked(&buf) }, false);
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/// Usb interrupt handler. Runs every time the host requests new data.
|
||||
#[task(binds = USBCTRL_IRQ, priority = 3, shared = [led, led_blink_enable, serial, usb_dev, counter])]
|
||||
fn usb_rx(cx: usb_rx::Context) {
|
||||
let led = cx.shared.led;
|
||||
let led_blink_enable = cx.shared.led_blink_enable;
|
||||
|
||||
let usb_dev = cx.shared.usb_dev;
|
||||
let serial = cx.shared.serial;
|
||||
let counter = cx.shared.counter;
|
||||
|
||||
(led, led_blink_enable, usb_dev, serial, counter).lock(
|
||||
|led_a, led_blink_enable_a, usb_dev_a, serial_a, counter_a| {
|
||||
// Check for new data
|
||||
if usb_dev_a.poll(&mut [serial_a]) {
|
||||
let mut buf = [0u8; 64];
|
||||
match serial_a.read(&mut buf) {
|
||||
Err(_e) => {
|
||||
// Do nothing
|
||||
// let _ = serial_a.write(b"Error.");
|
||||
// let _ = serial_a.flush();
|
||||
}
|
||||
Ok(0) => {
|
||||
// Do nothing
|
||||
let _ = serial_a.write(b"Didn't received data.");
|
||||
let _ = serial_a.flush();
|
||||
}
|
||||
Ok(_count) => {
|
||||
match_usb_serial_buf(
|
||||
&buf,
|
||||
led_a,
|
||||
led_blink_enable_a,
|
||||
serial_a,
|
||||
counter_a,
|
||||
);
|
||||
|
||||
/*
|
||||
// Code to echo the characters in Upper Case.
|
||||
|
||||
// Convert to upper case
|
||||
buf.iter_mut().take(count).for_each(|b| {
|
||||
b.make_ascii_uppercase();
|
||||
});
|
||||
if count > 0 {
|
||||
let _ = serial_a.write(b"Received data! ");
|
||||
let _ = serial_a.flush();
|
||||
}
|
||||
|
||||
// Send back to the host
|
||||
let mut wr_ptr = &buf[..count];
|
||||
while !wr_ptr.is_empty() {
|
||||
match serial_a.write(wr_ptr) {
|
||||
Ok(len) => {
|
||||
wr_ptr = &wr_ptr[len..];
|
||||
// if wr_ptr.len() == 0 {
|
||||
// let _ = serial_a.write(b"");
|
||||
let _ = serial_a.flush();
|
||||
// }
|
||||
}
|
||||
// On error, just drop unwritten data.
|
||||
// One possible error is Err(WouldBlock), meaning the USB
|
||||
// write buffer is full.
|
||||
Err(_) => break,
|
||||
};
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Task with least priority that only runs when nothing else is running.
|
||||
#[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();
|
||||
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
|
||||
/* New Tasks */
|
||||
|
||||
/// This function come from the github with USB-Serial example (see link above).
|
||||
///
|
||||
/// Helper function to ensure all data is written across the serial interface.
|
||||
fn write_serial(serial: &mut SerialPort<'static, hal::usb::UsbBus>, buf: &str, block: bool) {
|
||||
let write_ptr = buf.as_bytes();
|
||||
|
||||
// Because the buffer is of constant size and initialized to zero (0) we here
|
||||
// add a test to determine the size that's really occupied by the str that we
|
||||
// wan't to send. From index zero to first byte that is as the zero byte value.
|
||||
let mut index = 0;
|
||||
while index < write_ptr.len() && write_ptr[index] != 0 {
|
||||
index += 1;
|
||||
}
|
||||
let mut write_ptr = &write_ptr[0..index];
|
||||
|
||||
while !write_ptr.is_empty() {
|
||||
match serial.write(write_ptr) {
|
||||
Ok(len) => write_ptr = &write_ptr[len..],
|
||||
// Meaning the USB write buffer is full
|
||||
Err(UsbError::WouldBlock) => {
|
||||
if !block {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// On error, just drop unwritten data.
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
// let _ = serial.write("\n".as_bytes());
|
||||
let _ = serial.flush();
|
||||
}
|
||||
|
||||
fn match_usb_serial_buf(
|
||||
buf: &[u8; 64],
|
||||
led: &mut hal::gpio::Pin<hal::gpio::pin::bank0::Gpio25, hal::gpio::PushPullOutput>,
|
||||
led_blink_enable: &mut bool,
|
||||
serial: &mut SerialPort<'static, hal::usb::UsbBus>,
|
||||
counter: &mut Counter,
|
||||
) {
|
||||
let _buf_len = buf.len();
|
||||
match buf[0] {
|
||||
// Print Menu
|
||||
b'M' | b'm' => {
|
||||
write_serial(serial, "M - Print Menu\n", false);
|
||||
print_menu(serial);
|
||||
}
|
||||
// 0 - Reset counter
|
||||
b'0' => {
|
||||
write_serial(serial, "M - Print Menu\n", false);
|
||||
counter.reset();
|
||||
}
|
||||
// 1 - Increment counter
|
||||
b'1' => {
|
||||
write_serial(serial, "1 - Increment counter\n", false);
|
||||
counter.increment();
|
||||
}
|
||||
// 2 - Start continues counter
|
||||
b'2' => {
|
||||
write_serial(serial, "2 - Start continues counter\n", false);
|
||||
counter.enable(true);
|
||||
}
|
||||
// 3 - Stop continues counter
|
||||
b'3' => {
|
||||
write_serial(serial, "3 - Stop continues counter\n", false);
|
||||
counter.enable(false);
|
||||
}
|
||||
// 4 - Get switch and LED state
|
||||
b'4' => {
|
||||
write_serial(serial, "4 - Get switch and LED state\n", false);
|
||||
|
||||
// GPIO 25 onboard LED, we are going to read the bit 8 of the gpio_status register.
|
||||
// OUTFROMPERI - output signal from selected peripheral, before register
|
||||
// override is applied.
|
||||
// See pag 272 of the Pico Datasets:
|
||||
// https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#_gpio_functions
|
||||
|
||||
let led_status_reg =
|
||||
unsafe { (*pac::IO_BANK0::ptr()).gpio[25].gpio_status.read().bits() };
|
||||
|
||||
// Reserved bit.
|
||||
// let sio_pin_value = unsafe { (*pac::SIO::ptr()).gpio_out.read().bits() };
|
||||
|
||||
let (led_bool, led_status) = if ((led_status_reg & 1 << 8) >> 8) == 1_u32 {
|
||||
(true, "ON")
|
||||
} else {
|
||||
(false, "OFF")
|
||||
};
|
||||
|
||||
let mut buf = [0u8; 64];
|
||||
let _ = writeln!(
|
||||
Wrapper::new(&mut buf),
|
||||
"LED Status {:b}, {} LED {}",
|
||||
led_status_reg,
|
||||
led_bool,
|
||||
led_status
|
||||
);
|
||||
write_serial(
|
||||
serial,
|
||||
unsafe { core::str::from_utf8_unchecked(&buf) },
|
||||
false,
|
||||
);
|
||||
|
||||
// unsafe { (*pac::TIMER::ptr()).timerawh.read().bits() };
|
||||
}
|
||||
// 5 - Set LED on
|
||||
b'5' => {
|
||||
write_serial(serial, "5 - Set LED on\n", false);
|
||||
*led_blink_enable = false;
|
||||
let _ = led.set_high();
|
||||
}
|
||||
// 6 - Set LED off
|
||||
b'6' => {
|
||||
write_serial(serial, "6 - Set LED off\n", false);
|
||||
*led_blink_enable = false;
|
||||
let _ = led.set_low();
|
||||
}
|
||||
// 7 - Set LED blink enable
|
||||
b'7' => {
|
||||
write_serial(serial, "7 - Set LED blink enable\n", false);
|
||||
*led_blink_enable = true;
|
||||
}
|
||||
b'8' => {
|
||||
write_serial(serial, "8 - Display data rate\n", false);
|
||||
|
||||
let data_rate = serial.line_coding().data_rate();
|
||||
let mut buf = [0u8; 64];
|
||||
let _ = writeln!(Wrapper::new(&mut buf), "Data rate: {} bit/s", data_rate);
|
||||
write_serial(
|
||||
serial,
|
||||
unsafe { core::str::from_utf8_unchecked(&buf) },
|
||||
false,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
write_serial(
|
||||
serial,
|
||||
unsafe { core::str::from_utf8_unchecked(buf) },
|
||||
false,
|
||||
);
|
||||
write_serial(serial, "Invalid option!\n", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_menu(serial: &mut SerialPort<'static, hal::usb::UsbBus>) {
|
||||
let mut _buf = [0u8; 273];
|
||||
|
||||
// Create the Menu.
|
||||
let menu_str = "*****************
|
||||
* Menu:
|
||||
*
|
||||
* M / m - Print menu
|
||||
* 0 - Reset counter
|
||||
* 1 - Increment counter
|
||||
* 2 - Start continues counter
|
||||
* 3 - Stop continues counter
|
||||
* 4 - Get switch and LED state
|
||||
* 5 - Set LED on
|
||||
* 6 - Set LED off
|
||||
* 7 - Set LED blink enable
|
||||
* 8 - Display data rate
|
||||
*****************
|
||||
Enter option: ";
|
||||
|
||||
write_serial(serial, menu_str, true);
|
||||
|
||||
// Send out the data to USB-Serial.
|
||||
// let _ = serial.write(menu_str);
|
||||
|
||||
// let _ = writeln!(Wrapper::new(&mut buf), &menu_str);
|
||||
// write_serial(serial, unsafe { core::str::from_utf8_unchecked(menu_str) });
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.stdenv
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
tio
|
||||
stdenv
|
||||
elf2uf2-rs
|
||||
probe-run
|
||||
# keep this line if you use bash
|
||||
pkgs.bashInteractive
|
||||
bashInteractive
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user