Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
1 result

Target

Select target project
  • Frappe/e7020e_2021
  • rognda-6/e7020e_2021
  • Klomega/e7020e_2021
  • pln/e7020e_2021
  • CarlOsterberg/e7020e_2021
  • jonjac-6/e7020e_2021
  • deux-babiri-futari/e7020e_2021
  • samgra-7/e7020e_2021
  • JosefUtbult/e7020e_2021
  • edwkll-7/e7020e_2021
10 results
Select Git revision
  • master
1 result
Show changes
Commits on Source (6)
Showing
with 707 additions and 165 deletions
......@@ -19,7 +19,7 @@
"runToMain": true,
"svdFile": "${workspaceRoot}/.vscode/STM32F401.svd",
"configFiles": [
"interface/stlink-v2-1.cfg",
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"preRestartCommands": [
......@@ -44,6 +44,41 @@
"executable": "./target/thumbv7em-none-eabihf/debug/examples/${fileBasenameNoExtension}",
"cpu": "cortex-m4",
},
{
"type": "cortex-debug",
"request": "launch",
"name": "Cortex Debug 48Mhz",
"servertype": "openocd",
"cwd": "${workspaceRoot}",
"preLaunchTask": "cargo build --example",
"runToMain": true,
"svdFile": "${workspaceRoot}/.vscode/STM32F401.svd",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"preRestartCommands": [
"load",
],
"postLaunchCommands": [
"monitor arm semihosting enable"
],
"swoConfig": {
"enabled": true,
"cpuFrequency": 48000000,
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{
"type": "console",
"label": "ITM",
"port": 0
}
]
},
"executable": "./target/thumbv7em-none-eabihf/debug/examples/${fileBasenameNoExtension}",
"cpu": "cortex-m4",
},
{
"type": "cortex-debug",
"request": "launch",
......@@ -54,7 +89,7 @@
"runToMain": true,
"svdFile": "${workspaceRoot}/.vscode/STM32F401.svd",
"configFiles": [
"interface/stlink-v2-1.cfg",
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"preRestartCommands": [
......@@ -78,6 +113,41 @@
},
"executable": "./target/thumbv7em-none-eabihf/release/examples/${fileBasenameNoExtension}",
"cpu": "cortex-m4",
},
{
"type": "cortex-debug",
"request": "launch",
"name": "Cortex Release 48Mhz",
"servertype": "openocd",
"cwd": "${workspaceRoot}",
"preLaunchTask": "cargo build --example --release",
"runToMain": true,
"svdFile": "${workspaceRoot}/.vscode/STM32F401.svd",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"preRestartCommands": [
"load",
],
"postLaunchCommands": [
"monitor arm semihosting enable"
],
"swoConfig": {
"enabled": true,
"cpuFrequency": 48000000,
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{
"type": "console",
"label": "ITM",
"port": 0
}
]
},
"executable": "./target/thumbv7em-none-eabihf/release/examples/${fileBasenameNoExtension}",
"cpu": "cortex-m4",
}
]
}.
\ No newline at end of file
# Changelog
## 2021-03-19
- `examples/itm_rtic_hello_48MHz.rs`, example to trace ITM, when processor runs at 48MHz, useful to debug USB applications.
- `.vscode/launch.json`, added 48MHz itm tracing profiles. (Now consistenly using `stlink.cfg`.)
## 2021-03-18
- `examples/usb-mouse.rs`, a very small example using external hid library.
## 2021-03-07
- examples/rtic_bare7.rs, using embedded HAL.
- examples/rtic_bare8.rs, serial communication, bad design.
- examples/rtic_bare9.rs, serial communication, good design.
- `examples/rtic_bare7.rs`, using embedded HAL.
- `examples/rtic_bare8.rs`, serial communication, bad design.
- `examples/rtic_bare9.rs`, serial communication, good design.
## 2021-03-05
- examples/rtic_bare6.rs, setup and validate the clock tree.
- `examples/rtic_bare6.rs`, setup and validate the clock tree.
## 2021-02-28
- examples/rtic_bare2.rs, raw timer access.
- examples/rtic_bare3.rs, timing abstractions.
- examples/rtic_bare4.rs, a simple bare metal peripheral access API.
- examples/rtic_bare5.rs, write your own C-like peripheral access API.
- `examples/rtic_bare2.rs`, raw timer access.
- `examples/rtic_bare3.rs`, timing abstractions.
- `examples/rtic_bare4.rs`, a simple bare metal peripheral access API.
- `examples/rtic_bare5.rs`, write your own C-like peripheral access API.
## 2021-02-26
- examples/bare1.rs, bare metal 101!
- `examples/bare1.rs`, bare metal 101!
## 2021-02-23
- examples/rtic_blinky.rs, added instructions to terminal based debugging
- `examples/rtic_blinky.rs`, added instructions to terminal based debugging
## 2021-02-22
- memory.x, reduced flash size to 128k to match light-weight target
- Cargo.toml, updated dependencies to latest stm32f4xx-hal/pac
- `memory.x`, reduced flash size to 128k to match light-weight target
- `Cargo.toml`, updated dependencies to latest `stm32f4xx-hal/pac`
Some experiments (wip):
- examples/rtt_rtic_i2c.rs, spi emulation over i2c
- src/pwm3389e, driver using emulated spi
- `examples/rtt_rtic_i2c.rs`, spi emulation over i2c
- `src/pwm3389e`, driver using emulated spi
## 2021-02-16
- rtt_rtic_usb_mouse updated
- `rtt_rtic_usb_mouse` updated
Notice, requires release build
## 2021-02-15
......
......@@ -7,9 +7,11 @@ version = "0.1.0"
[dependencies]
cortex-m = { version = "0.7.1", features = ["linker-plugin-lto"] }
# cortex-m = { version = "0.7.1" }
cortex-m-rt = "0.6.13"
cortex-m-semihosting = "0.3.7"
cortex-m-rtic = "0.5.5"
# embedded-hal = { version = "0.2.4", features = ["unproven"] }
embedded-hal = "0.2.4"
usb-device = "0.2.7"
......@@ -17,7 +19,7 @@ usb-device = "0.2.7"
panic-halt = "0.2.0"
# Uncomment for the itm panic examples.
#panic-itm = "0.4.2"
panic-itm = "0.4.2"
# Uncomment for the rtt-timing examples.
panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
......@@ -26,18 +28,18 @@ panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
panic-semihosting = "0.5.6"
# Tracing
rtt-target = { version = "0.3.0", features = ["cortex-m"] }
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
nb = "1.0.0"
usbd-hid = "0.5.0"
micromath = "1.1.0"
[dependencies.stm32f4]
version = "0.13.0"
features = ["stm32f411", "rt"]
# Uncomment for the allocator example.
# alloc-cortex-m = "0.4.0"
[dependencies.stm32f4xx-hal]
version = "0.8.3"
version = "0.9.0"
features = ["rt", "stm32f411", "usb_fs"]
# Enable to use the latest git version
# gitgit = "https://github.com/stm32-rs/stm32f4xx-hal"
......@@ -45,28 +47,19 @@ features = ["rt", "stm32f411", "usb_fs"]
# path = "../stm32f4xx-hal"
# this lets you use `cargo fix`!
[[bin]]
name = "app"
test = false
bench = false
# [[bin]]
# name = "app"
# # test = false
# bench = false
[profile.dev]
incremental = false
codegen-units = 1
overflow-checks = false
[profile.release]
incremental = false
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
# [features]
# nightly = ["cortex-m/inline-asm"]
# # this lets you use `cargo fix`!
# [[bin]]
# name = "app"
# test = false
# bench = false
......@@ -197,9 +197,9 @@ D+ used for re-enumeration. You don't need to connect the V+ from the USB cable,
- If this does not work you can try to erase the flash memory (the program running on the STM32F401/F11).
``` shell
> st-util erase
st-flash 1.6.1
2021-01-11T16:02:14 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages.
> st-flash erase
st-flash 1.7.0
2021-06-23T14:07:35 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages.
Mass erasing.......
```
......
......@@ -9,6 +9,10 @@ use stm32f4;
const APP: () = {
#[init]
fn init(cx: init::Context) {
// Set up the system clock.
let rcc = ctx.device.RCC.constrain();
let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
let mut p = cx.core;
let stim = &mut p.ITM.stim[0];
for a in 0..=10 {
......
// itm_rtic_hello_48Mhz
//
// Use the vscode 48Mhz launch profiles
#![no_main]
#![no_std]
use cortex_m::iprintln;
use panic_halt as _;
use stm32f4xx_hal::prelude::*;
#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
const APP: () = {
#[init]
fn init(ctx: init::Context) {
// Set up the system clock.
let rcc = ctx.device.RCC.constrain();
let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
let mut p = ctx.core;
let stim = &mut p.ITM.stim[0];
for a in 0..=10 {
iprintln!(stim, "RTIC Hello, world!! {}", a);
}
}
};
......@@ -86,15 +86,15 @@ const APP: () = {
device.SPI2,
(sck, miso, mosi),
MODE_3,
stm32f4xx_hal::time::KiloHertz(2000).into(),
stm32f4xx_hal::time::KiloHertz(200).into(),
clocks,
);
let mut delay = DwtDelay::new(&mut core.DWT, clocks);
let delay = DwtDelay::new(&mut core.DWT, clocks);
let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
// set in burst mode
pmw3389.write_register(Register::MotionBurst, 0x00);
pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
// semantically, the monotonic timer is frozen at time "zero" during `init`
// NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
......@@ -111,8 +111,10 @@ const APP: () = {
static mut COUNTER: u32 = 0;
static mut POS_X: i64 = 0;
// run each ms
*COUNTER += 1;
if *COUNTER == 1000 / RATIO {
if *COUNTER == 1000 {
// run each s
cx.spawn.trace(*POS_X).unwrap();
*COUNTER = 0;
}
......@@ -121,9 +123,7 @@ const APP: () = {
*POS_X += x as i64;
// task should run each second N ms (16_000 cycles at 16MHz)
cx.schedule
.poll(cx.scheduled + (RATIO * 16_000).cycles())
.unwrap();
cx.schedule.poll(cx.scheduled + 16_000.cycles()).unwrap();
}
#[task(priority = 1)]
......
......@@ -9,6 +9,7 @@
#![no_main]
#![no_std]
use cortex_m_semihosting::hprintln;
use panic_semihosting as _;
use stm32f4;
......@@ -18,6 +19,7 @@ const APP: () = {
#[inline(never)] // avoid inlining of this function/task
#[no_mangle] // to strip hash from symbols (easier to read)
fn init(_cx: init::Context) {
hprintln!("hello");
let mut x = core::u32::MAX - 1;
loop {
// cortex_m::asm::bkpt();
......
......@@ -17,7 +17,7 @@ use stm32f4xx_hal::{
gpio::{gpioa::PA5, Output, PushPull},
prelude::*,
};
;
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
const OFFSET: u32 = 8_000_000;
......
//! examples/rtt-pwm-sine.rs
//! cargo run --examples rtt-pwm-sine --release
// #![deny(unsafe_code)]
// #![deny(warnings)]
#![no_main]
#![no_std]
use cortex_m::{asm, peripheral::DWT};
use panic_rtt_target as _;
use rtic::cyccnt::{Instant, U32Ext as _};
use rtt_target::{rprint, rprintln, rtt_init_print};
use core::f32::consts::PI;
use micromath::F32Ext;
use stm32f4xx_hal::{
bb,
dwt::Dwt,
gpio::Speed,
gpio::{
gpiob::{PB10, PB4},
gpioc::{PC2, PC3},
Alternate, Output, PushPull,
},
prelude::*,
pwm,
rcc::Clocks,
spi::Spi,
stm32,
};
use embedded_hal::spi::MODE_3;
use panic_rtt_target as _;
use app::{
pmw3389::{self, Register},
DwtDelay,
};
type PMW3389T = pmw3389::Pmw3389<
Spi<
stm32f4xx_hal::stm32::SPI2,
(
PB10<Alternate<stm32f4xx_hal::gpio::AF5>>,
PC2<Alternate<stm32f4xx_hal::gpio::AF5>>,
PC3<Alternate<stm32f4xx_hal::gpio::AF5>>,
),
>,
PB4<Output<PushPull>>,
>;
include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs"));
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = {
struct Resources {
// late resources
TIM1: stm32::TIM1,
pmw3389: PMW3389T,
}
#[init(schedule = [pwm_out, poll])]
fn init(mut cx: init::Context) -> init::LateResources {
rtt_init_print!();
rprintln!("init");
let device = cx.device;
let mut core = cx.core;
// Initialize (enable) the monotonic timer (CYCCNT)
core.DCB.enable_trace();
core.DWT.enable_cycle_counter();
let rcc = device.RCC.constrain();
// Set up the system clock. 96 MHz?
let clocks = rcc.cfgr.sysclk(96.mhz()).pclk1(24.mhz()).freeze();
// Configure SPI
// spi2
// sck - pb10, (yellow)
// miso - pc2, (red)
// mosi - pc3, (orange)
// ncs - pb4, (long yellow)
// motion - (brown)
//
// +5, (white)
// gnd, (black)
cortex_m::asm::dsb(); // chip errata
let gpiob = device.GPIOB.split();
cortex_m::asm::dsb(); // chip errata
let gpioc = device.GPIOC.split();
cortex_m::asm::dsb(); // chip errata
let sck = gpiob.pb10.into_alternate_af5().set_speed(Speed::VeryHigh);
let miso = gpioc.pc2.into_alternate_af5().set_speed(Speed::High);
let mosi = gpioc.pc3.into_alternate_af5().set_speed(Speed::High);
let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High);
let spi = Spi::spi2(
device.SPI2,
(sck, miso, mosi),
MODE_3,
stm32f4xx_hal::time::KiloHertz(2000).into(),
clocks,
);
let delay = DwtDelay::new(&mut core.DWT, clocks);
let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
// // set in burst mode
// pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
// setup TIM1 as PWM (for implementing an 8 bit DA)
let gpioa = device.GPIOA.split();
cortex_m::asm::dsb(); // chip errata
// we set the pins to VeryHigh to get the sharpest waveform possible
// (rise and fall times should have similar characteristics)
let _channels = (
gpioa.pa8.into_alternate_af1().set_speed(Speed::VeryHigh),
gpioa.pa9.into_alternate_af1().set_speed(Speed::VeryHigh),
);
// Setup PWM RAW
let tim1 = device.TIM1;
// Here we need unsafe as we are "stealing" the RCC peripheral
// At this point it has been contrained into SysConf and used to set clocks
let rcc = unsafe { &(*stm32::RCC::ptr()) };
rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
rcc.apb2rstr.modify(|_, w| w.tim1rst().set_bit());
rcc.apb2rstr.modify(|_, w| w.tim1rst().clear_bit());
// Setup chanel 1 and 2 as pwm_mode1
tim1.ccmr1_output()
.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1());
tim1.ccmr1_output()
.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1());
// The reference manual is a bit ambiguous about when enabling this bit is really
// necessary, but since we MUST enable the pre-load for the output channels then we
// might as well enable for the auto-reload too
tim1.cr1.modify(|_, w| w.arpe().set_bit());
let clk = clocks.pclk2().0 * if clocks.ppre2() == 1 { 1 } else { 2 };
// check the actual clock setup
rprintln!("clk {}", clk);
// we want maximum performance, thus we set the prescaler to 0
let pre = 0;
rprintln!("pre {}", pre);
tim1.psc.write(|w| w.psc().bits(pre));
// we want 8 bits of resolution
// so our ARR = 2^8 - 1 = 256 - 1 = 255
let arr = 255;
rprintln!("arr {}", arr);
tim1.arr.write(|w| unsafe { w.bits(arr) });
// Trigger update event to load the registers
tim1.cr1.modify(|_, w| w.urs().set_bit());
tim1.egr.write(|w| w.ug().set_bit());
tim1.cr1.modify(|_, w| w.urs().clear_bit());
// Set main output enable of all Output Compare (OC) registers
tim1.bdtr.modify(|_, w| w.moe().set_bit());
// Set output enable for channels 1 and 2
tim1.ccer.write(|w| w.cc1e().set_bit().cc2e().set_bit());
// Setup the timer
tim1.cr1.write(|w| {
w.cms()
.bits(0b00) // edge aligned mode
.dir() // counter used as up-counter
.clear_bit()
.opm() // one pulse mode
.clear_bit()
.cen() // enable counter
.set_bit()
});
// Set main output enable of all Output Compare (OC) registers
tim1.bdtr.modify(|_, w| w.moe().set_bit());
// Set duty cycle of Channels
tim1.ccr1.write(|w| unsafe { w.ccr().bits(128) });
tim1.ccr2.write(|w| unsafe { w.ccr().bits(128) });
// Set preload for the CCx
tim1.cr2.write(|w| w.ccpc().set_bit());
// Enable update events
tim1.dier.write(|w| w.uie().enabled());
tim1.sr.modify(|_, w| w.uif().clear());
// just to check that we actually get update events
while tim1.sr.read().uif().is_clear() {
rprint!("-");
}
rprintln!("here");
tim1.sr.modify(|_, w| w.uif().clear());
cx.schedule.pwm_out(cx.start + PWM_CYCLES.cycles()).ok();
cx.schedule.poll(cx.start + POLL_CYCLES.cycles()).ok();
// pass on late resources
init::LateResources {
TIM1: tim1,
pmw3389,
}
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
rprintln!("idle");
// panic!("panic");
loop {
asm::nop()
}
}
#[task(priority = 1)]
fn trace(_cx: trace::Context, pos_x: i64, pos_y: i64) {
static mut OLD_POS_X: i64 = 0;
static mut OLD_POS_Y: i64 = 0;
rprintln!(
"@{:?}, pos_x {:010}, diff {:010}, pos_y {:010}, diff {:010} ",
Instant::now(),
pos_x,
pos_x.wrapping_sub(*OLD_POS_X),
pos_y,
pos_y.wrapping_sub(*OLD_POS_Y),
);
*OLD_POS_X = pos_x;
*OLD_POS_Y = pos_y;
}
#[task(priority = 2, resources = [pmw3389], schedule = [poll], spawn = [trace])]
fn poll(cx: poll::Context) {
static mut COUNTER: u32 = 0;
static mut POS_X: i64 = 0;
static mut POS_Y: i64 = 0;
// run each ms
*COUNTER += 1;
if *COUNTER == 1000 {
// run each s
cx.spawn.trace(*POS_X, *POS_Y).unwrap();
*COUNTER = 0;
}
let pmw3389 = cx.resources.pmw3389;
//write 0x01 to Motion register and read from it to freeze the motion values and make them available
pmw3389.write_register(Register::Motion, 0x01).unwrap();
let _ = pmw3389.read_register(Register::Motion).unwrap();
let xl: u8 = pmw3389.read_register(Register::DeltaXL).unwrap();
let xh: u8 = pmw3389.read_register(Register::DeltaXH).unwrap();
let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
// let (x, _y) = cx.resources.pmw3389.read_status().unwrap();
*POS_X += (((xl as u16) | ((xh as u16) << 8)) as i16) as i64;
*POS_Y += (((yl as u16) | ((yh as u16) << 8)) as i16) as i64;
// task should run each second N ms (96_000 cycles at 96MHz)
cx.schedule
.poll(cx.scheduled + POLL_CYCLES.cycles())
.unwrap();
}
#[task(priority = 3, resources = [TIM1], schedule = [pwm_out])]
fn pwm_out(cx: pwm_out::Context) {
static mut INDEX: u16 = 0;
static mut LEFT: u16 = 0;
static mut RIGHT: u16 = 0;
// static mut FLOAT: u16 = 0;
let tim1 = cx.resources.TIM1;
tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
// tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) });
cx.schedule
.pwm_out(cx.scheduled + PWM_CYCLES.cycles())
.unwrap();
*INDEX = (*INDEX).wrapping_add(1_000);
// let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0;
// *FLOAT = (128.0 + f.sin() * 128.0) as u16;
*LEFT = SINE_BUF[*INDEX as usize] as u16;
*RIGHT = SINE_BUF[*INDEX as usize] as u16;
// if cx.scheduled.elapsed() > 1500.cycles() {
// panic!("task overrun");
// }
}
extern "C" {
fn EXTI0();
fn EXTI1();
fn EXTI2();
}
};
// We aim for a sampling rate of 48kHz, assuming that the input filter of the
// sound card used to sample the generated signal has an appropriate input filter
const PWM_CYCLES: u32 = 2000; // 96_000_000 / 2_000 = 48_000 Hz
const POLL_CYCLES: u32 = 96_000; // 96_000_000 / 96_000 = 1_000 Hz
......@@ -6,14 +6,17 @@
#![no_main]
#![no_std]
use core::f32::consts::PI;
// use core::f32::consts::PI;
use cortex_m::{asm, peripheral::DWT};
// use panic_halt as _;
use panic_rtt_target as _;
use rtic::cyccnt::{Instant, U32Ext as _};
use rtt_target::{rprint, rprintln, rtt_init_print};
use stm32f4xx_hal::{bb, dma, gpio::Speed, prelude::*, pwm, stm32};
use core::f32::consts::PI;
use micromath::F32Ext;
use stm32f4xx_hal::{bb, gpio::Speed, prelude::*, pwm, stm32};
include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs"));
......@@ -153,19 +156,23 @@ const APP: () = {
static mut INDEX: u16 = 0;
static mut LEFT: u16 = 0;
static mut RIGHT: u16 = 0;
static mut FLOAT: u16 = 0;
let tim1 = cx.resources.TIM1;
tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
// tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) });
*INDEX = (*INDEX).wrapping_add(10_000);
let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0;
*FLOAT = (128.0 + f.sin() * 128.0) as u16;
cx.schedule.pwm_out(cx.scheduled + PERIOD.cycles()).ok();
*LEFT = SINE_BUF[*INDEX as usize] as u16;
*RIGHT = SINE_BUF[*INDEX as usize] as u16;
if cx.scheduled.elapsed() > 300.cycles() {
if cx.scheduled.elapsed() > 500.cycles() {
panic!("task overrun");
}
}
......
......@@ -47,7 +47,7 @@ const APP: () = {
// Setup PWM RAW
let tim1 = dp.TIM1;
// Here we need unsafe as we are "stealing" the RCC peripheral
// At this point it has been contrained into SysConf and used to set clocks
// At this point it has been constrained into SysConf and used to set clocks
let rcc = unsafe { &(*stm32::RCC::ptr()) };
rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
......
//! examples/rtt_timing.rs
//! cargo run --examples rtt-timing
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
......
......@@ -6,7 +6,6 @@
#![no_std]
use cortex_m::{asm::delay, delay};
// use panic_halt as _;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
......@@ -21,15 +20,36 @@ use stm32f4xx_hal::{
stm32::I2C1,
};
use rtic::cyccnt::{Instant, U32Ext as _};
use app::{
pmw3389e::{self, Register},
DwtDelay,
};
#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
const OFFSET: u32 = 8_000_000 / 10;
const LOG_OFFSET: u32 = 8_000_000;
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = {
#[init]
fn init(cx: init::Context) {
struct Resources {
pmw3389: pmw3389e::Pmw3389e<
SC18IS602::SH18IS602<
I2c<
I2C1,
(
PB8<AlternateOD<stm32f4xx_hal::gpio::AF4>>,
PB9<AlternateOD<stm32f4xx_hal::gpio::AF4>>,
),
>,
>,
SC18IS602::Error,
>,
#[init((0, 0))]
pos: (i64, i64),
}
#[init(schedule = [poll, log])]
fn init(cx: init::Context) -> init::LateResources {
rtt_init_print!();
rprintln!("init");
let dp = cx.device;
......@@ -41,6 +61,7 @@ const APP: () = {
// Initialize (enable) the monotonic timer (CYCCNT)
cp.DCB.enable_trace();
cp.DWT.enable_cycle_counter();
// Set up I2C.
let gpiob = dp.GPIOB.split();
......@@ -52,54 +73,17 @@ const APP: () = {
use embedded_hal::spi::MODE_3;
use SC18IS602::{Order, Speed, SH18IS602};
let mut spi_emu =
SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true);
let spi_emu = SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true);
rprintln!("spi_emu initialized");
// reset SPI transfer
spi_emu.set_low().ok();
cortex_m::asm::delay(1_000_000);
spi_emu.set_high().ok();
cortex_m::asm::delay(1_000_000);
rprintln!("set to gpio management");
// try split transaction
rprintln!("try split transaction");
// the write part
spi_emu.set_low().unwrap();
let mut req = [0x00];
spi_emu.transfer(&mut req).unwrap();
rprintln!("id request {:02x?}", req);
cortex_m::asm::delay(1_000);
// the read part
let mut req = [00];
spi_emu.transfer(&mut req).unwrap();
rprintln!("id resp {:02x?}", req);
spi_emu.set_high().unwrap();
rprintln!("try split transaction");
// the write part
spi_emu.set_low().unwrap();
let mut req = [0x01];
spi_emu.transfer(&mut req).unwrap();
rprintln!("version request {:02x?}", req);
cortex_m::asm::delay(1_000);
// the read part
let mut req = [00];
spi_emu.transfer(&mut req).unwrap();
rprintln!("version resp {:02x?}", req);
spi_emu.set_high().unwrap();
let delay = DwtDelay::new(&mut cp.DWT, clocks);
let pmw3389 = pmw3389e::Pmw3389e::new(spi_emu, delay).unwrap();
rprintln!("success");
cx.schedule.poll(cx.start + OFFSET.cycles()).unwrap();
cx.schedule.log(cx.start + LOG_OFFSET.cycles()).unwrap();
init::LateResources { pmw3389 }
}
#[idle]
......@@ -109,6 +93,52 @@ const APP: () = {
continue;
}
}
#[task(priority = 2, resources = [pmw3389, pos], schedule = [poll])]
fn poll(cx: poll::Context) {
// rprintln!("poll @ {:?}", Instant::now());
// static mut X: i64 = 0;
// static mut Y: i64 = 0;
cx.schedule.poll(cx.scheduled + OFFSET.cycles()).unwrap();
let pmw3389 = cx.resources.pmw3389;
pmw3389.write_register(Register::Motion, 0x01).unwrap();
let motion = pmw3389.read_register(Register::Motion).unwrap();
let xl = pmw3389.read_register(Register::DeltaXL).unwrap();
let xh = pmw3389.read_register(Register::DeltaXH).unwrap();
let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
let x = (xl as u16 + (xh as u16) << 8) as i16;
let y = (yl as u16 + (yh as u16) << 8) as i16;
cx.resources.pos.0 += x as i64;
cx.resources.pos.1 += y as i64;
// let surface = motion & 0x08;
// let motion_detect = motion & 0x80;
// rprintln!(
// "motion {}, surface {}, (x, y) {:?}",
// motion_detect,
// surface,
// (x, y),
// );
}
#[task(priority = 1, resources = [pos], schedule = [log])]
fn log(mut cx: log::Context) {
cx.schedule.log(cx.scheduled + LOG_OFFSET.cycles()).unwrap();
cx.resources.pos.lock(|pos| rprintln!("(x, y) {:?}", pos));
}
extern "C" {
fn EXTI0();
fn EXTI1();
}
};
// SC18IS602
......@@ -222,8 +252,12 @@ mod SC18IS602 {
| (mode.phase as u8) << 2
| speed as u8;
rprintln!("configuring i2c->spi bridge");
device.i2c.write(addr, &mut [SpiConfigure.id(), cfg]).ok();
rprintln!("spi bridge configured");
if gpio {
device.set_ss0_gpio();
} else {
......@@ -258,8 +292,6 @@ mod SC18IS602 {
}
}
// impl<I2C> Default for SH18IS602<I2C> where I2C: i2c::Write + i2c::Read {}
impl<I2C> Transfer<u8> for SH18IS602<I2C>
where
I2C: i2c::Write + i2c::Read,
......@@ -290,12 +322,10 @@ mod SC18IS602 {
// A short delay is needed
// For improved performance use write if result is not needed
cortex_m::asm::delay(1000);
cortex_m::asm::delay(1_000);
self.i2c.read(self.addr, words).map_err(|_| panic!()).ok();
// rprintln!("transfer_read {:02x?}", words);
Ok(words)
}
}
......@@ -310,12 +340,13 @@ mod SC18IS602 {
if !self.gpio {
Err(Error::NotConfigured)
} else {
rprintln!("set low");
// rprintln!("set low");
// cortex_m::asm::delay(10_000);
self.i2c
.write(self.addr, &[Function::GpioWrite.id(), 0x0])
.map_err(|_| panic!())
.ok();
cortex_m::asm::delay(100_000);
// cortex_m::asm::delay(20_000);
Ok(())
}
}
......@@ -324,7 +355,8 @@ mod SC18IS602 {
if !self.gpio {
Err(Error::NotConfigured)
} else {
rprintln!("set_high");
// rprintln!("set_high");
// cortex_m::asm::delay(10_000);
self.i2c
.write(self.addr, &[Function::GpioWrite.id(), 0x1])
.map_err(|_| panic!())
......
......@@ -324,6 +324,7 @@ fn usb_poll<B: bus::UsbBus>(
usb_dev: &mut UsbDevice<'static, B>,
hid: &mut HIDClass<'static, B>,
) {
//
if !usb_dev.poll(&mut [hid]) {
return;
}
......
// > cargo run usb-mouse
// or
// > cargo run usb-mouse --release
#![no_main]
#![no_std]
use stm32f4xx_hal::{
gpio::{gpioc::PC13, Input, PullUp},
otg_fs::{UsbBus, UsbBusType, USB},
prelude::*,
rcc::Clocks,
};
use usb_device::{bus::UsbBusAllocator, prelude::*};
use usbd_hid::{
descriptor::{generator_prelude::*, MouseReport},
hid_class::HIDClass,
};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
const APP: () = {
struct Resources {
btn: PC13<Input<PullUp>>,
hid: HIDClass<'static, UsbBusType>,
usb_dev: UsbDevice<'static, UsbBus<USB>>,
}
#[init]
fn init(ctx: init::Context) -> init::LateResources {
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
rtt_init_print!();
rprintln!("init");
// Set up the system clock.
let rcc = ctx.device.RCC.constrain();
let clocks: Clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
let hclk = clocks.hclk();
let gpioc = ctx.device.GPIOC.split();
let btn = gpioc.pc13.into_pull_up_input();
let gpioa = ctx.device.GPIOA.split();
let usb = USB {
usb_global: ctx.device.OTG_FS_GLOBAL,
usb_device: ctx.device.OTG_FS_DEVICE,
usb_pwrclk: ctx.device.OTG_FS_PWRCLK,
pin_dm: gpioa.pa11.into_alternate_af10(),
pin_dp: gpioa.pa12.into_alternate_af10(),
hclk,
};
USB_BUS.replace(UsbBus::new(usb, EP_MEMORY));
let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), MouseReport::desc(), 1);
let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000))
.manufacturer("E70011E")
.product("Mouse")
.serial_number("1.0")
.device_class(0)
.build();
init::LateResources { btn, hid, usb_dev }
}
#[task(binds=OTG_FS, resources = [btn, hid, usb_dev])]
fn on_usb(ctx: on_usb::Context) {
static mut COUNTER: u16 = 0;
static mut FIRST: bool = true;
if *FIRST {
rprintln!("on_usb");
*FIRST = false;
}
// destruct the context
let (btn, usb_dev, hid) = (ctx.resources.btn, ctx.resources.usb_dev, ctx.resources.hid);
let report = MouseReport {
x: match *COUNTER {
// reached after 100ms
100 => {
rprintln!("10");
10
}
// reached after 199ms
199 => {
rprintln!("-10");
-10
}
_ => 0,
},
y: 0,
buttons: btn.is_low().unwrap().into(), // (into takes a bool into an integer)
wheel: 0,
};
// wraps around after 200ms
*COUNTER = (*COUNTER + 1) % 200;
// push the report
hid.push_input(&report).ok();
// update the usb device state
if usb_dev.poll(&mut [hid]) {
return;
}
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
rprintln!("idle");
loop {
cortex_m::asm::nop();
}
}
};
......@@ -24,7 +24,7 @@ monitor arm semihosting enable
# # send captured ITM to the file itm.fifo
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
# # 8000000 must match the core clock frequency
monitor tpiu config internal itm.txt uart off 16000000
monitor tpiu config internal itm.txt uart off 48000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 8000000 must match the core clock frequency
......
#![no_std]
#![no_main]
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
use cortex_m::asm;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
asm::nop(); // To not have main optimize to abort in release mode, remove when you add code
loop {
// your code goes here
}
}
......@@ -6,7 +6,7 @@ use crate::DwtDelay;
use embedded_hal::blocking::spi::{Transfer, Write};
use embedded_hal::digital::v2::OutputPin;
use rtt_target::{rprint, rprintln};
use rtt_target::rprintln;
#[allow(dead_code)]
#[derive(Clone, Copy)]
......@@ -116,23 +116,6 @@ where
rprintln!("reset");
// shutdown
// adns_write_reg(Shutdown, 0xb6); // Shutdown first
// delay(300);
// adns_com_begin(); // drop and raise ncs to reset spi port
// delayMicroseconds(40);
// adns_com_end();
// delayMicroseconds(40);
// pmw3389.write_register(Register::Shutdown, 0xb6)?;
// pmw3389.delay.delay_ms(300);
// pmw3389.com_begin();
// pmw3389.delay.delay_us(40);
// pmw3389.com_end();
// pmw3389.delay.delay_us(40);
// force reset
pmw3389.write_register(Register::PowerUpReset, 0x5a)?;
......@@ -220,7 +203,7 @@ where
}
/// Read status
pub fn read_status(&mut self) -> Result<((i16, i16)), E> {
pub fn read_status(&mut self) -> Result<(i16, i16), E> {
self.com_begin();
self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
......@@ -340,7 +323,7 @@ where
// // set initial CPI resolution
// // adns_write_reg(Config1, 0x15);
let cpi: u16 = 16000;
let cpi: u16 = 1600;
self.write_register(Register::ResolutionL, cpi as u8)?;
self.write_register(Register::ResolutionH, (cpi >> 8) as u8)?;
......
......@@ -146,16 +146,16 @@ where
pmw3389.upload_firmware()?;
// pmw3389.delay.delay_ms(1000);
pmw3389.delay.delay_ms(1000);
// rprintln!("Optical Chip Initialized");
rprintln!("Optical Chip Initialized");
// // read product id
// let id = pmw3389.product_id()?;
// rprintln!("product_id 0x{:x}", id);
// read product id
let id = pmw3389.product_id()?;
rprintln!("product_id 0x{:x}", id);
// let srom_id = pmw3389.read_register(Register::SROMId)?;
// rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
let srom_id = pmw3389.read_register(Register::SROMId)?;
rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
// // loop {
// // pmw3389.write_register(Register::Motion, 0x01)?;
......@@ -384,7 +384,7 @@ where
// // adns_write_reg(Config1, 0x15);
// self.write_register(Register::ResolutionL, 0x15)?;
self.write_register(Register::ResolutionL, 0x5)?;
self.write_register(Register::ResolutionL, 0x15)?;
// self.write_register(Register::ResolutionH, 0x15)?;
self.write_register(Register::ResolutionH, 0x00)?;
......