172 lines
4.9 KiB
Rust
172 lines
4.9 KiB
Rust
//! Blinks an LED
|
|
//!
|
|
//! This assumes that a LED is connected to pc13 as is the case on the blue pill board.
|
|
//!
|
|
//! Note: Without additional hardware, PC13 should not be used to drive an LED, see page 5.1.2 of
|
|
//! the reference manaual for an explanation. This is not an issue on the blue pill.
|
|
|
|
#![deny(unsafe_code)]
|
|
#![deny(warnings)]
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
extern crate panic_halt;
|
|
extern crate cortex_m_semihosting;
|
|
|
|
use nb::block;
|
|
|
|
use stm32f1xx_hal::{
|
|
prelude::*,
|
|
pac,
|
|
timer::Timer,
|
|
serial::Serial,
|
|
};
|
|
use cortex_m_rt::entry;
|
|
//use cortex_m_semihosting::hprintln;
|
|
use stm32f1xx_hal::adc;
|
|
|
|
extern crate byteorder;
|
|
use byteorder::{ByteOrder, LittleEndian};
|
|
|
|
struct RangeConverter {
|
|
// Input specifics
|
|
left: u16,
|
|
center: u16,
|
|
right: u16,
|
|
deadzone: u16,
|
|
|
|
// Output range
|
|
min: i16,
|
|
max: i16,
|
|
}
|
|
|
|
impl RangeConverter {
|
|
fn convert(&self, value: u16) -> i16 {
|
|
if value <= self.left {
|
|
return self.min
|
|
}
|
|
if value >= self.right {
|
|
return self.max
|
|
}
|
|
|
|
let cd: u16 = if value > self.center {
|
|
value - self.center
|
|
} else {
|
|
self.center - value
|
|
};
|
|
|
|
if cd <= self.deadzone {
|
|
return 0;
|
|
}
|
|
|
|
// Value outside of deadzone.
|
|
let cv: i16 = (cd - self.deadzone) as i16;
|
|
if value > self.center {
|
|
let md: i32 = ((self.right - self.center) - self.deadzone) as i32;
|
|
let val: i32 = (self.max as i32) * (cv as i32) / md;
|
|
return val as i16;
|
|
} else {
|
|
let md: i32 = ((self.center - self.left) - self.deadzone) as i32;
|
|
let val: i32 = (self.min as i32) * (cv as i32) / md;
|
|
return val as i16;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
// Get access to the core peripherals from the cortex-m crate
|
|
let cp = cortex_m::Peripherals::take().unwrap();
|
|
// Get access to the device specific peripherals from the peripheral access crate
|
|
let dp = pac::Peripherals::take().unwrap();
|
|
|
|
// Take ownership over the raw flash and rcc devices and convert them into the corresponding
|
|
// HAL structs
|
|
let mut flash = dp.FLASH.constrain();
|
|
let mut rcc = dp.RCC.constrain();
|
|
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
|
|
|
|
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
|
|
// `clocks`
|
|
let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);
|
|
//hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
|
|
|
|
// Acquire the GPIOC peripheral
|
|
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
|
|
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
|
|
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
|
|
|
|
// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function
|
|
// in order to configure the port. For pins 0-7, crl should be passed instead.
|
|
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
|
|
// Configure the syst timer to trigger an update every second
|
|
let mut timer = Timer::syst(cp.SYST, 30.hz(), clocks);
|
|
|
|
let mut adc1 = adc::Adc::adc1(dp.ADC1, &mut rcc.apb2);
|
|
|
|
let mut ch0 = gpiob.pb0.into_analog(&mut gpiob.crl);
|
|
let mut ch1 = gpiob.pb1.into_analog(&mut gpiob.crl);
|
|
let mut ch2 = gpioa.pa0.into_analog(&mut gpioa.crl);
|
|
|
|
let fire = gpioc.pc14.into_pull_up_input(&mut gpioc.crh);
|
|
let tx = gpioa.pa2.into_alternate_push_pull(&mut gpioa.crl);
|
|
let rx = gpioa.pa3;
|
|
let serial = Serial::usart2(
|
|
dp.USART2,
|
|
(tx, rx),
|
|
&mut afio.mapr,
|
|
19_200.bps(),
|
|
clocks,
|
|
&mut rcc.apb1,
|
|
);
|
|
let (mut tx, mut _rx) = serial.split();
|
|
|
|
let rcx = RangeConverter{
|
|
left: 2064,
|
|
center: 3026,
|
|
right: 4096,
|
|
deadzone: 300,
|
|
|
|
min: -1000,
|
|
max: 1000,
|
|
};
|
|
let rcy = RangeConverter{
|
|
left: 2250,
|
|
center: 3000,
|
|
right: 4096,
|
|
deadzone: 100,
|
|
|
|
min: -1000,
|
|
max: 1000,
|
|
};
|
|
|
|
// Wait for the timer to trigger an update and change the state of the LED
|
|
loop {
|
|
block!(timer.wait()).unwrap();
|
|
led.set_high();
|
|
block!(timer.wait()).unwrap();
|
|
led.set_low();
|
|
|
|
let data0: u16 = adc1.read(&mut ch0).unwrap();
|
|
let data1: u16 = adc1.read(&mut ch1).unwrap();
|
|
let _data2: u16 = adc1.read(&mut ch2).unwrap();
|
|
|
|
let x: i16 = -rcx.convert(data0);
|
|
let y: i16 = rcy.convert(data1);
|
|
|
|
let mut bufx = [0, 0];
|
|
let mut bufy = [0, 0];
|
|
if fire.is_low() {
|
|
LittleEndian::write_i16(&mut bufx, x);
|
|
LittleEndian::write_i16(&mut bufy, y);
|
|
} else {
|
|
LittleEndian::write_i16(&mut bufx, 0);
|
|
LittleEndian::write_i16(&mut bufy, 0);
|
|
};
|
|
block!(tx.write(bufx[0])).ok();
|
|
block!(tx.write(bufx[1])).ok();
|
|
block!(tx.write(bufy[0])).ok();
|
|
block!(tx.write(bufy[1])).ok();
|
|
}
|
|
}
|