commit 45eebb1b18359e69f4396608f202cb0482c8bb72 Author: Astro Date: Mon Apr 22 00:14:32 2019 +0200 PoC diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..d9430b4 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,12 @@ +[target.thumbv7m-none-eabi] +runner = "gdb -q -x openocd.gdb" +rustflags = [ + "-C", "link-arg=-Tlink.x", +] + +[build] +# Pick ONE of these compilation targets +# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ +target = "thumbv7m-none-eabi" # Cortex-M3 +# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) +# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..de33e90 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +categories = ["embedded", "no-std"] +name = "pentatube" +license = "GPL-3.0-only" +authors = ["Astro "] +version = "0.0.0" +edition = "2018" + +[badges] +maintenance = { status = "experimental" } + +[package.metadata.docs.rs] +features = [] +default-target = "thumbv7m-none-eabi" + +[dependencies] +panic-abort = "0.3.1" +bare-metal = "0.2" +cortex-m = "0.5" +cortex-m-rt = { version = "0.6", features = ["device"] } +cortex-m-log = { version = "0.4", features = ["log-integration"] } +stm32f1 = { version = "0.6", features = ["rt", "stm32f103"] } +embedded-hal = "0.2.2" +stm32f1xx-hal = { git = "https://github.com/stm32-rs/stm32f1xx-hal", features = ["rt", "stm32f103"] } +#stm32f1xx-hal = { path = "../stm32f4xx-hal", features = ["rt", "stm32f429"] } + +[features] +default = [] + +[profile.release] +codegen-units = 1 +incremental = false +debug = true +opt-level = "s" +lto = true diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..98f603e --- /dev/null +++ b/build.rs @@ -0,0 +1,18 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put the linker script somewhere the linker can find it + 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()); + + // Only re-run the build script when memory.x is changed, + // instead of when any part of the source code changes. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..811e299 --- /dev/null +++ b/default.nix @@ -0,0 +1,50 @@ +{ # Use master branch of the overlay by default + mozillaOverlay ? import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz), + rustManifest ? builtins.fetchurl "https://static.rust-lang.org/dist/channel-rust-nightly.toml" +}: + +let + pkgs = import { overlays = [ mozillaOverlay ]; }; +in +with pkgs; +let + targets = [ + "x86_64-unknown-linux-gnu" + "thumbv6m-none-eabi" + "thumbv7m-none-eabi" + "thumbv7em-none-eabi" + "thumbv7em-none-eabihf" + ]; + rust = + rustChannelOfTargets "nightly" null targets; + rustPlatform = recurseIntoAttrs (makeRustPlatform { + rustc = rust; + cargo = rust; + }); + + openocd = + stdenv.mkDerivation { + name = "openocd-stlink-blackpill"; + buildInputs = [ + pkgs.openocd + makeWrapper + ]; + src = ./src; + noBuild = true; + installPhase = + let + openOcdFlags = [ + "-f" "${pkgs.openocd}/share/openocd/scripts/interface/stlink-v2-1.cfg" + "-f" "${pkgs.openocd}/share/openocd/scripts/target/stm32f1x.cfg" + "-c" "init" + ]; + in '' + mkdir -p $out/bin + + makeWrapper ${pkgs.openocd}/bin/openocd $out/bin/openocd-stlink-blackpill \ + --add-flags "${lib.escapeShellArgs openOcdFlags}" + ''; + }; +in { + inherit pkgs rustPlatform openocd; +} diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..71f245d --- /dev/null +++ b/memory.x @@ -0,0 +1,6 @@ +/* Linker script for the STM32F103C8T6 */ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} diff --git a/openocd.gdb b/openocd.gdb new file mode 100644 index 0000000..0ee4c97 --- /dev/null +++ b/openocd.gdb @@ -0,0 +1,10 @@ +target remote :3333 + +# print demangled symbols by default +set print asm-demangle on + +monitor arm semihosting enable + +load +continue +#step diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..af8f508 --- /dev/null +++ b/shell.nix @@ -0,0 +1,23 @@ +let + project = import ./default.nix {}; +in +with project.pkgs; +stdenv.mkDerivation { + name = "project-env"; + buildInputs = with project.rustPlatform.rust; [ + rustc cargo gdb project.openocd + ]; + + # Set Environment Variables + RUST_BACKTRACE = 1; + + shellHook = '' + echo "Starting openocd…" + ${project.openocd}/bin/openocd-stlink-blackpill -c "reset init" & + + # Let openocd output scroll by + sleep 1 + + echo "Run 'cargo run --release'" + ''; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7531302 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,131 @@ +#![no_std] +#![no_main] +// #![deny(warnings, unused)] + +#[allow(unused_extern_crates)] +extern crate panic_abort; + +// use cortex_m::asm::{wfi, nop}; +use cortex_m_rt::entry; +use embedded_hal::{ + digital::OutputPin, + spi::MODE_0, + blocking::spi::Write as SpiWrite, +// watchdog::{WatchdogEnable, Watchdog}, +}; +use stm32f1xx_hal::{ + flash::FlashExt, + rcc::RccExt, + gpio::GpioExt, + afio::AfioExt, + time::U32Ext, + spi::Spi, + stm32::{CorePeripherals, Peripherals}, +}; + + +pub struct PwmGraphics { + t: u8, +} + +impl PwmGraphics { + pub fn new() -> Self { + PwmGraphics { t: 0 } + } + + pub fn generate_frame(&mut self, rgb: &[[u8; 3]; 8]) -> [u8; 3] { + let mut bgr = [0u8; 3]; + + for i in 0..bgr.len() { + for x in 0..rgb.len() { + if self.t < rgb[x][i] { + bgr[2 - i] |= 1 << x; + } + } + } + + self.t += 1; + bgr + } +} + +/// Initialization and main loop +#[entry] +fn main() -> ! { + let mut cp = CorePeripherals::take().unwrap(); + cp.SCB.enable_icache(); + cp.SCB.enable_dcache(&mut cp.CPUID); + + let dp = Peripherals::take().unwrap(); + let mut flash = dp.FLASH.constrain(); + let mut rcc = dp.RCC.constrain(); + let clocks = rcc.cfgr + .use_hse(8.mhz()) + .sysclk(72.mhz()) + .hclk(72.mhz()) + .pclk1(36.mhz()) + .pclk2(72.mhz()) + .freeze(&mut flash.acr); + + // let mut wd = IndependentWatchdog::new(dp.IWDG); + // wd.start(1000u32.ms()); + // wd.feed(); + + let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); + let mut gpiob = dp.GPIOB.split(&mut rcc.apb2); + + let mut led = gpiob.pb12.into_push_pull_output(&mut gpiob.crh); + + // (srclk) violet, nucleo: D13 + let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl); + // not connected + let miso = gpioa.pa6.into_floating_input(&mut gpioa.crl); + // (serin) blue, nucleo: D11 + let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl); + let pins = (sck, miso, mosi); + let mut parts = dp.AFIO.constrain(&mut rcc.apb2); + let mut spi = Spi::spi1(dp.SPI1, pins, &mut parts.mapr, MODE_0, 36u32.mhz(), clocks, &mut rcc.apb2); + + // (rclk) brown, nucleo: D8 + let mut rclk = gpioa.pa4.into_push_pull_output(&mut gpioa.crl); + // (srclr) green, nucleo: D9 + let mut srclr = gpioa.pa3.into_push_pull_output(&mut gpioa.crl); + + // timer::setup(cp.SYST, clocks); + + srclr.set_high(); + rclk.set_low(); + let mut pg = PwmGraphics::new(); + let mut t = 0usize; + loop { + let mut frame = [[0u8; 3]; 8]; + for x in 0..frame.len() { + frame[x][0] = (t >> 10) as u8; + frame[x][1] = ((t >> 10) + (x << 1)) as u8; + frame[x][2] = ((t >> 9) - (x << 2)) as u8; + } + let data = pg.generate_frame(&frame); + spi.write(&data) + .unwrap(); + + rclk.set_high(); + // for _ in 0..200 { + // nop(); + // } + rclk.set_low(); + + t += 1; + if (t / 1_000) % 2 == 0 { + led.set_high(); + } else { + led.set_low(); + } + // // for _ in 0..100000 { + // // nop(); + // // } + + // // Update watchdog + // wd.feed(); + + } +}