Browse Source

First release of stm32f0xx-hal based on stm32f042-hal

Signed-off-by: Daniel Egger <daniel@eggers-club.de>
features/pwm
Daniel Egger 3 years ago
commit
3db793e9d6
  1. 8
      .cargo/config
  2. 5
      .gitignore
  3. 53
      Cargo.toml
  4. 33
      README.md
  5. 37
      examples/blinky.rs
  6. 46
      examples/blinky_delay.rs
  7. 86
      examples/flash_systick.rs
  8. 291
      examples/i2c_hal_ina260reader.rs
  9. 80
      examples/i2c_hal_ina260serial.rs
  10. 268
      examples/i2c_hal_ssd1306alphabeter.rs
  11. 116
      examples/led_hal_button_irq.rs
  12. 43
      examples/serial_echo.rs
  13. 66
      examples/spi_hal_apa102c.rs
  14. 11
      memory.x
  15. 5
      openocd.cfg
  16. 8
      openocd_program.sh
  17. 74
      src/delay.rs
  18. 497
      src/gpio.rs
  19. 233
      src/i2c.rs
  20. 32
      src/lib.rs
  21. 5
      src/prelude.rs
  22. 174
      src/rcc.rs
  23. 269
      src/serial.rs
  24. 170
      src/spi.rs
  25. 63
      src/time.rs
  26. 13
      tools/capture_example_bloat.sh

8
.cargo/config

@ -0,0 +1,8 @@
[target.thumbv6m-none-eabi]
runner = 'arm-none-eabi-gdb'
rustflags = [
"-C", "link-arg=-Tlink.x",
]
[build]
target = "thumbv6m-none-eabi"

5
.gitignore

@ -0,0 +1,5 @@
/target/
**/*.orig
**/*.rs.bk
Cargo.lock
*.txt

53
Cargo.toml

@ -0,0 +1,53 @@
[package]
authors = ["Daniel Egger <daniel@eggers-club.de>"]
categories = [
"embedded",
"hardware-support",
"no-std",
]
description = "Peripheral access API for STM32F0 series microcontrollers"
documentation = "https://docs.rs/stm32f0xx-hal"
keywords = [
"arm",
"cortex-m",
"stm32f0xx",
"hal",
]
license = "0BSD"
name = "stm32f0xx-hal"
readme = "README.md"
repository = "https://github.com/stm32-rs/stm32f0xx-hal"
version = "0.7.0"
[dependencies]
bare-metal = { version = "0.2.4", features = ["const-fn"] }
cortex-m = "0.5.8"
cortex-m-rt = "0.6.5"
nb = "0.1.1"
void = { version = "1.0.2", default-features = false }
stm32f0 = "0.4.0"
[dependencies.cast]
default-features = false
version = "0.2.2"
[dependencies.embedded-hal]
features = ["unproven"]
version = "0.2.2"
[dev-dependencies]
ina260 = "0.2.3"
numtoa = "0.2.3"
panic-halt = "0.2.0"
[features]
rt = ["stm32f0/rt"]
stm32f042 = ["stm32f0/stm32f0x2"]
[profile.dev]
debug = true
[profile.release]
debug = true
lto = true
opt-level = "s"

33
README.md

@ -0,0 +1,33 @@
stm32f0xx-hal
=============
_stm32f0xx-hal_ contains a hardware abstraction on top of the peripheral access
API for the STMicro STM32F0xx family of microcontrollers. It replaces the
[stm32f042-hal][] by a more ubiqitous version suitable for additional families.
Currently supported configuration are:
* stm32f042
The idea behind this crate is to gloss over the slight differences in the
various peripherals available on those MCUs so a HAL can be written for all
chips in that same family without having to cut and paste crates for every
single model.
Collaboration on this crate is highly welcome as are pull requests!
This crate relies on Adam Greigs fantastic [stm32f0][] crate to provide
appropriate register definitions and implements a partial set of the
[embedded-hal][] traits.
Some of the implementation was shamelessly adapted from the [stm32f103xx-hal][]
crate by Jorge Aparicio.
[stm32f0]: https://crates.io/crates/stm32f0
[stm32f042-hal]: https://github.com/therealprof/stm32f042-hal
[stm32f103xx-hal]: https://github.com/japaric/stm32f103xx-hal
[embedded-hal]: https://github.com/japaric/embedded-hal.git
License
-------
[0-clause BSD license](LICENSE-0BSD.txt).

37
examples/blinky.rs

@ -0,0 +1,37 @@
#![no_main]
#![no_std]
extern crate cortex_m_rt;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::prelude::*;
use hal::stm32;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
if let Some(p) = stm32::Peripherals::take() {
let gpioa = p.GPIOA.split();
/* (Re-)configure PA1 as output */
let mut led = gpioa.pa1.into_push_pull_output();
loop {
/* Turn PA1 on a million times in a row */
for _ in 0..1_000_000 {
led.set_high();
}
/* Then turn PA1 off a million times in a row */
for _ in 0..1_000_000 {
led.set_low();
}
}
}
loop {
continue;
}
}

46
examples/blinky_delay.rs

@ -0,0 +1,46 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::delay::Delay;
use hal::prelude::*;
use hal::stm32;
use cortex_m::peripheral::Peripherals;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
if let (Some(p), Some(cp)) = (stm32::Peripherals::take(), Peripherals::take()) {
let gpioa = p.GPIOA.split();
/* (Re-)configure PA1 as output */
let mut led = gpioa.pa1.into_push_pull_output();
/* Constrain clocking registers */
let mut rcc = p.RCC.constrain();
/* Configure clock to 8 MHz (i.e. the default) and freeze it */
let clocks = rcc.cfgr.sysclk(8.mhz()).freeze();
/* Get delay provider */
let mut delay = Delay::new(cp.SYST, clocks);
loop {
led.set_high();
delay.delay_ms(1_000_u16);
led.set_low();
delay.delay_ms(1_000_u16);
}
}
loop {
continue;
}
}

86
examples/flash_systick.rs

@ -0,0 +1,86 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::gpio::*;
use hal::prelude::*;
use hal::stm32;
use cortex_m::interrupt::Mutex;
use cortex_m::peripheral::syst::SystClkSource::Core;
use cortex_m::peripheral::Peripherals;
use cortex_m_rt::{entry, exception};
use core::cell::RefCell;
use core::ops::DerefMut;
static GPIO: Mutex<RefCell<Option<gpioa::PA1<Output<PushPull>>>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
if let (Some(p), Some(cp)) = (stm32::Peripherals::take(), Peripherals::take()) {
let gpioa = p.GPIOA.split();
let mut rcc = p.RCC.constrain();
let _ = rcc.cfgr.sysclk(48.mhz()).freeze();
let mut syst = cp.SYST;
/* (Re-)configure PA1 as output */
let mut led = gpioa.pa1.into_push_pull_output();
cortex_m::interrupt::free(move |cs| {
*GPIO.borrow(cs).borrow_mut() = Some(led);
});
/* Initialise SysTick counter with a defined value */
unsafe { syst.cvr.write(1) };
/* Set source for SysTick counter, here full operating frequency (== 8MHz) */
syst.set_clock_source(Core);
/* Set reload value, i.e. timer delay 48 MHz/4 Mcounts == 12Hz or 83ms */
syst.set_reload(4_000_000 - 1);
/* Start counter */
syst.enable_counter();
/* Start interrupt generation */
syst.enable_interrupt();
}
loop {
continue;
}
}
/* Define an exception, i.e. function to call when exception occurs. Here if our SysTick timer
* trips the flash function will be called and the specified stated passed in via argument */
//, flash, state: u8 = 1);
#[exception]
fn SysTick() -> ! {
static mut state: u8 = 1;
/* Enter critical section */
cortex_m::interrupt::free(|cs| {
if let Some(ref mut led) = *GPIO.borrow(cs).borrow_mut().deref_mut() {
/* Check state variable, keep LED off most of the time and turn it on every 10th tick */
if *state < 10 {
/* If set turn off the LED */
led.set_low();
/* And now increment state variable */
*state += 1;
} else {
/* If not set, turn on the LED */
led.set_high();
/* And set new state variable back to 0 */
*state = 0;
}
}
});
}

291
examples/i2c_hal_ina260reader.rs

@ -0,0 +1,291 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate embedded_hal;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
extern crate numtoa;
use hal::i2c::*;
use hal::prelude::*;
use hal::stm32;
use embedded_hal::blocking::i2c::Write;
use numtoa::NumToA;
use cortex_m_rt::entry;
const SSD1306_BYTE_CMD: u8 = 0x00;
const SSD1306_BYTE_DATA: u8 = 0x40;
const SSD1306_BYTE_CMD_SINGLE: u8 = 0x80;
const SSD1306_DISPLAY_RAM: u8 = 0xA4;
const SSD1306_DISPLAY_NORMAL: u8 = 0xA6;
const SSD1306_DISPLAY_OFF: u8 = 0xAE;
const SSD1306_DISPLAY_ON: u8 = 0xAF;
const SSD1306_MEMORY_ADDR_MODE: u8 = 0x20;
const SSD1306_COLUMN_RANGE: u8 = 0x21;
const SSD1306_PAGE_RANGE: u8 = 0x22;
const SSD1306_DISPLAY_START_LINE: u8 = 0x40;
const SSD1306_SCAN_MODE_NORMAL: u8 = 0xC0;
const SSD1306_DISPLAY_OFFSET: u8 = 0xD3;
const SSD1306_PIN_MAP: u8 = 0xDA;
const SSD1306_DISPLAY_CLK_DIV: u8 = 0xD5;
const SSD1306_CHARGE_PUMP: u8 = 0x8D;
#[entry]
fn main() -> ! {
if let Some(p) = stm32::Peripherals::take() {
let gpiof = p.GPIOF.split();
let mut rcc = p.RCC.constrain();
let _ = rcc.cfgr.freeze();
let scl = gpiof
.pf1
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
let sda = gpiof
.pf0
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
/* Setup I2C1 */
let mut i2c = I2c::i2c1(p.I2C1, (scl, sda), 10.khz());
/* Initialise SSD1306 display */
let _ = ssd1306_init(&mut i2c);
/* Print a welcome message on the display */
let _ = ssd1306_pos(&mut i2c, 0, 0);
/* Endless loop */
loop {
let _ = ssd1306_pos(&mut i2c, 0, 0);
let mut data = [0; 2];
let _ = i2c.write_read(0x40, &[0x00], &mut data);
let config = (u16::from(data[0]) << 8) | u16::from(data[1]);
let mut buffer = [0u8; 10];
let _ = ssd1306_print_bytes(&mut i2c, config.numtoa(10, &mut buffer));
let _ = ssd1306_pos(&mut i2c, 0, 1);
let mut data = [0; 2];
let _ = i2c.write_read(0x40, &[0x02], &mut data);
let mut voltage = ((u32::from(data[0]) << 8) | u32::from(data[1])) * 1250;
let _ = ssd1306_print_bytes(&mut i2c, voltage.numtoa(10, &mut buffer));
let _ = ssd1306_print_bytes(&mut i2c, b"uV ");
let _ = ssd1306_pos(&mut i2c, 0, 2);
let mut data = [0; 2];
let _ = i2c.write_read(0x40, &[0x01], &mut data);
voltage = ((u32::from(data[0]) << 8) | u32::from(data[1])) * 1250;
let _ = ssd1306_print_bytes(&mut i2c, voltage.numtoa(10, &mut buffer));
let _ = ssd1306_print_bytes(&mut i2c, b"uA ");
}
}
loop {
continue;
}
}
/// Print characters on the display with the embedded 7x7 font
fn ssd1306_print_bytes<I2C, E>(i2c: &mut I2C, bytes: &[u8]) -> Result<(), E>
where
I2C: Write<Error = E>,
{
/* A 7x7 font shamelessly borrowed from https://github.com/techninja/MarioChron/ */
const FONT_7X7: [u8; 672] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (space)
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, // !
0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, // "
0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x00, // $
0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00, // %
0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00, // &
0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, // '
0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x00, // )
0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00, // *
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // +
0x00, 0x50, 0x30, 0x00, 0x00, 0x00, 0x00, // ,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // -
0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // /
0x1C, 0x3E, 0x61, 0x41, 0x43, 0x3E, 0x1C, // 0
0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, // 1
0x62, 0x73, 0x79, 0x59, 0x5D, 0x4F, 0x46, // 2
0x20, 0x61, 0x49, 0x4D, 0x4F, 0x7B, 0x31, // 3
0x18, 0x1C, 0x16, 0x13, 0x7F, 0x7F, 0x10, // 4
0x27, 0x67, 0x45, 0x45, 0x45, 0x7D, 0x38, // 5
0x3C, 0x7E, 0x4B, 0x49, 0x49, 0x79, 0x30, // 6
0x03, 0x03, 0x71, 0x79, 0x0D, 0x07, 0x03, // 7
0x36, 0x7F, 0x49, 0x49, 0x49, 0x7F, 0x36, // 8
0x06, 0x4F, 0x49, 0x49, 0x69, 0x3F, 0x1E, // 9
0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, // :
0x00, 0x56, 0x36, 0x00, 0x00, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // <
0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, // =
0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, // >
0x02, 0x01, 0x51, 0x09, 0x06, 0x00, 0x00, // ?
0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, 0x00, // @
0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00, 0x00, // A
0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // B
0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, // C
0x7F, 0x7F, 0x41, 0x41, 0x63, 0x3E, 0x1C, // D
0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00, // E
0x7F, 0x09, 0x09, 0x01, 0x01, 0x00, 0x00, // F
0x3E, 0x41, 0x41, 0x51, 0x32, 0x00, 0x00, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, // H
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x00, // I
0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x00, // J
0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // K
0x7F, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, // L
0x7F, 0x02, 0x04, 0x02, 0x7F, 0x00, 0x00, // M
0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x00, // N
0x3E, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00, // P
0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x00, // Q
0x7F, 0x7F, 0x11, 0x31, 0x79, 0x6F, 0x4E, // R
0x46, 0x49, 0x49, 0x49, 0x31, 0x00, 0x00, // S
0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x00, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x00, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x00, // V
0x7F, 0x7F, 0x38, 0x1C, 0x38, 0x7F, 0x7F, // W
0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00, // X
0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00, // Y
0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, // [
0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // "\"
0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00, // ]
0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, // ^
0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, // _
0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, // `
0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00, // a
0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, 0x00, // b
0x38, 0x44, 0x44, 0x44, 0x20, 0x00, 0x00, // c
0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00, // d
0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // e
0x08, 0x7E, 0x09, 0x01, 0x02, 0x00, 0x00, // f
0x08, 0x14, 0x54, 0x54, 0x3C, 0x00, 0x00, // g
0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // h
0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x00, // i
0x20, 0x40, 0x44, 0x3D, 0x00, 0x00, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, // k
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, // l
0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, 0x00, // m
0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // n
0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, // o
0x7C, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, // p
0x08, 0x14, 0x14, 0x18, 0x7C, 0x00, 0x00, // q
0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x00, // r
0x48, 0x54, 0x54, 0x54, 0x20, 0x00, 0x00, // s
0x04, 0x3F, 0x44, 0x40, 0x20, 0x00, 0x00, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x00, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x00, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x00, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // x
0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00, 0x00, // y
0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, // z
0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, // {
0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, // |
0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, // }
0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, // ->
0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x00, // <-
];
for c in bytes {
/* Create an array with our I2C instruction and a blank column at the end */
let mut data: [u8; 9] = [SSD1306_BYTE_DATA, 0, 0, 0, 0, 0, 0, 0, 0];
/* Calculate our index into the character table above */
let index = (*c as usize - 0x20) * 7;
/* Populate the middle of the array with the data from the character array at the right
* index */
data[1..8].copy_from_slice(&FONT_7X7[index..index + 7]);
/* Write it out to the I2C bus */
i2c.write(0x3C, &data)?
}
Ok(())
}
/// Initialise display with some useful values
fn ssd1306_init<I2C, E>(i2c: &mut I2C) -> Result<(), E>
where
I2C: Write<Error = E>,
{
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_OFF])?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_CLK_DIV, 0x80],
)?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_SCAN_MODE_NORMAL])?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_OFFSET, 0x00, 0x00],
)?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_MEMORY_ADDR_MODE, 0x00],
)?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_START_LINE, 0x00],
)?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_CHARGE_PUMP, 0x14])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_PIN_MAP, 0x12])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_RAM])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_NORMAL])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_ON])?;
let data = [
SSD1306_BYTE_DATA,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
];
for _ in 0..128 {
i2c.write(0x3C, &data)?;
}
Ok(())
}
/// Position cursor at specified x, y block coordinate (multiple of 8)
fn ssd1306_pos<I2C, E>(i2c: &mut I2C, x: u8, y: u8) -> Result<(), E>
where
I2C: Write<Error = E>,
{
let data = [
SSD1306_BYTE_CMD,
SSD1306_COLUMN_RANGE,
x * 8,
0x7F,
SSD1306_PAGE_RANGE,
y,
0x07,
];
i2c.write(0x3C, &data)
}

80
examples/i2c_hal_ina260serial.rs

@ -0,0 +1,80 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate embedded_hal;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
extern crate ina260;
extern crate numtoa;
use hal::i2c::*;
use hal::prelude::*;
use hal::serial::*;
use hal::stm32;
use numtoa::NumToA;
use ina260::*;
use core::fmt::Write;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
if let Some(p) = stm32::Peripherals::take() {
let gpiof = p.GPIOF.split();
let gpioa = p.GPIOA.split();
let mut clocks = p.RCC.constrain().cfgr.freeze();
/* Initialise serial pins */
let tx = gpioa.pa9.into_alternate_af1();
let rx = gpioa.pa10.into_alternate_af1();
/* Setup serial port */
let serial = Serial::usart1(p.USART1, (tx, rx), 115_200.bps(), clocks);
let (mut tx, mut _rx) = serial.split();
/* Initialise I2C pins */
let scl = gpiof
.pf1
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
let sda = gpiof
.pf0
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
/* Setup I2C1 */
let mut i2c = I2c::i2c1(p.I2C1, (scl, sda), 1.khz());
let mut ina260 = INA260::new(i2c, 0x40).unwrap();
/* Endless loop */
loop {
let mut buffer = [0u8; 10];
/* Read and print voltage */
let voltage = ina260.voltage().unwrap();
let _ = tx.write_str(unsafe {
core::str::from_utf8_unchecked(voltage.numtoa(10, &mut buffer))
});
let _ = tx.write_str("uV\n\r");
/* Read and print current */
let current = ina260.current().unwrap();
let _ = tx.write_str(unsafe {
core::str::from_utf8_unchecked(current.numtoa(10, &mut buffer))
});
let _ = tx.write_str("uA\n\r");
}
}
loop {
continue;
}
}

268
examples/i2c_hal_ssd1306alphabeter.rs

@ -0,0 +1,268 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate embedded_hal;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::i2c::*;
use hal::prelude::*;
use hal::stm32;
use cortex_m_rt::entry;
use embedded_hal::blocking::i2c::Write;
const SSD1306_BYTE_CMD: u8 = 0x00;
const SSD1306_BYTE_DATA: u8 = 0x40;
const SSD1306_BYTE_CMD_SINGLE: u8 = 0x80;
const SSD1306_DISPLAY_RAM: u8 = 0xA4;
const SSD1306_DISPLAY_NORMAL: u8 = 0xA6;
const SSD1306_DISPLAY_OFF: u8 = 0xAE;
const SSD1306_DISPLAY_ON: u8 = 0xAF;
const SSD1306_MEMORY_ADDR_MODE: u8 = 0x20;
const SSD1306_COLUMN_RANGE: u8 = 0x21;
const SSD1306_PAGE_RANGE: u8 = 0x22;
const SSD1306_DISPLAY_START_LINE: u8 = 0x40;
const SSD1306_SCAN_MODE_NORMAL: u8 = 0xC0;
const SSD1306_DISPLAY_OFFSET: u8 = 0xD3;
const SSD1306_PIN_MAP: u8 = 0xDA;
const SSD1306_DISPLAY_CLK_DIV: u8 = 0xD5;
const SSD1306_CHARGE_PUMP: u8 = 0x8D;
#[entry]
fn main() -> ! {
if let Some(p) = stm32::Peripherals::take() {
let gpiof = p.GPIOF.split();
let mut rcc = p.RCC.constrain();
let _ = rcc.cfgr.freeze();
let scl = gpiof
.pf1
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
let sda = gpiof
.pf0
.into_alternate_af1()
.internal_pull_up(true)
.set_open_drain();
/* Setup I2C1 */
let mut i2c = I2c::i2c1(p.I2C1, (scl, sda), 400.khz());
/* Initialise SSD1306 display */
let _ = ssd1306_init(&mut i2c);
/* Print a welcome message on the display */
let _ = ssd1306_pos(&mut i2c, 0, 0);
/* Endless loop */
loop {
for c in 97..123 {
let _ = ssd1306_print_bytes(&mut i2c, &[c]);
}
for c in 65..91 {
let _ = ssd1306_print_bytes(&mut i2c, &[c]);
}
}
}
loop {
continue;
}
}
/// Print characters on the display with the embedded 7x7 font
fn ssd1306_print_bytes<I2C, E>(i2c: &mut I2C, bytes: &[u8]) -> Result<(), E>
where
I2C: Write<Error = E>,
{
/* A 7x7 font shamelessly borrowed from https://github.com/techninja/MarioChron/ */
const FONT_7X7: [u8; 672] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (space)
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, // !
0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, // "
0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x00, // $
0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00, // %
0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00, // &
0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, // '
0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x00, // )
0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00, // *
0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // +
0x00, 0x50, 0x30, 0x00, 0x00, 0x00, 0x00, // ,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // -
0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // /
0x1C, 0x3E, 0x61, 0x41, 0x43, 0x3E, 0x1C, // 0
0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, // 1
0x62, 0x73, 0x79, 0x59, 0x5D, 0x4F, 0x46, // 2
0x20, 0x61, 0x49, 0x4D, 0x4F, 0x7B, 0x31, // 3
0x18, 0x1C, 0x16, 0x13, 0x7F, 0x7F, 0x10, // 4
0x27, 0x67, 0x45, 0x45, 0x45, 0x7D, 0x38, // 5
0x3C, 0x7E, 0x4B, 0x49, 0x49, 0x79, 0x30, // 6
0x03, 0x03, 0x71, 0x79, 0x0D, 0x07, 0x03, // 7
0x36, 0x7F, 0x49, 0x49, 0x49, 0x7F, 0x36, // 8
0x06, 0x4F, 0x49, 0x49, 0x69, 0x3F, 0x1E, // 9
0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, // :
0x00, 0x56, 0x36, 0x00, 0x00, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // <
0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, // =
0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, // >
0x02, 0x01, 0x51, 0x09, 0x06, 0x00, 0x00, // ?
0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, 0x00, // @
0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00, 0x00, // A
0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // B
0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, // C
0x7F, 0x7F, 0x41, 0x41, 0x63, 0x3E, 0x1C, // D
0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00, // E
0x7F, 0x09, 0x09, 0x01, 0x01, 0x00, 0x00, // F
0x3E, 0x41, 0x41, 0x51, 0x32, 0x00, 0x00, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00, // H
0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x00, // I
0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x00, // J
0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // K
0x7F, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, // L
0x7F, 0x02, 0x04, 0x02, 0x7F, 0x00, 0x00, // M
0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x00, // N
0x3E, 0x7F, 0x41, 0x41, 0x41, 0x7F, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00, // P
0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x00, // Q
0x7F, 0x7F, 0x11, 0x31, 0x79, 0x6F, 0x4E, // R
0x46, 0x49, 0x49, 0x49, 0x31, 0x00, 0x00, // S
0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x00, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x00, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x00, // V
0x7F, 0x7F, 0x38, 0x1C, 0x38, 0x7F, 0x7F, // W
0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00, // X
0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00, // Y
0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, // [
0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // "\"
0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00, // ]
0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, // ^
0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, // _
0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, // `
0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00, // a
0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, 0x00, // b
0x38, 0x44, 0x44, 0x44, 0x20, 0x00, 0x00, // c
0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00, // d
0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // e
0x08, 0x7E, 0x09, 0x01, 0x02, 0x00, 0x00, // f
0x08, 0x14, 0x54, 0x54, 0x3C, 0x00, 0x00, // g
0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // h
0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, 0x00, // i
0x20, 0x40, 0x44, 0x3D, 0x00, 0x00, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, // k
0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, // l
0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, 0x00, // m
0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // n
0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, // o
0x7C, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, // p
0x08, 0x14, 0x14, 0x18, 0x7C, 0x00, 0x00, // q
0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, 0x00, // r
0x48, 0x54, 0x54, 0x54, 0x20, 0x00, 0x00, // s
0x04, 0x3F, 0x44, 0x40, 0x20, 0x00, 0x00, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, 0x00, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x00, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x00, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, // x
0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00, 0x00, // y
0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00, // z
0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, // {
0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, // |
0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, // }
0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, // ->
0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00, 0x00, // <-
];
for c in bytes {
/* Create an array with our I2C instruction and a blank column at the end */
let mut data: [u8; 9] = [SSD1306_BYTE_DATA, 0, 0, 0, 0, 0, 0, 0, 0];
/* Calculate our index into the character table above */
let index = (*c as usize - 0x20) * 7;
/* Populate the middle of the array with the data from the character array at the right
* index */
data[1..8].copy_from_slice(&FONT_7X7[index..index + 7]);
/* Write it out to the I2C bus */
i2c.write(0x3C, &data)?
}
Ok(())
}
/// Initialise display with some useful values
fn ssd1306_init<I2C, E>(i2c: &mut I2C) -> Result<(), E>
where
I2C: Write<Error = E>,
{
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_OFF])?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_CLK_DIV, 0x80],
)?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_SCAN_MODE_NORMAL])?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_OFFSET, 0x00, 0x00],
)?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_MEMORY_ADDR_MODE, 0x00],
)?;
i2c.write(
0x3C,
&[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_START_LINE, 0x00],
)?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_CHARGE_PUMP, 0x14])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_PIN_MAP, 0x12])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_RAM])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_NORMAL])?;
i2c.write(0x3C, &[SSD1306_BYTE_CMD_SINGLE, SSD1306_DISPLAY_ON])?;
let data = [
SSD1306_BYTE_DATA,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
];
for _ in 0..128 {
i2c.write(0x3C, &data)?;
}
Ok(())
}
/// Position cursor at specified x, y block coordinate (multiple of 8)
fn ssd1306_pos<I2C, E>(i2c: &mut I2C, x: u8, y: u8) -> Result<(), E>
where
I2C: Write<Error = E>,
{
let data = [
SSD1306_BYTE_CMD,
SSD1306_COLUMN_RANGE,
x * 8,
0x7F,
SSD1306_PAGE_RANGE,
y,
0x07,
];
i2c.write(0x3C, &data)
}

116
examples/led_hal_button_irq.rs

@ -0,0 +1,116 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;
#[macro_use]
extern crate stm32f0xx_hal as hal;
use hal::delay::Delay;
use hal::gpio::*;
use hal::prelude::*;
use cortex_m::interrupt::Mutex;
use cortex_m::peripheral::Peripherals as c_m_Peripherals;
use cortex_m_rt::entry;
pub use hal::stm32;
pub use hal::stm32::*;
use core::cell::RefCell;
use core::ops::DerefMut;
// Make our LED globally available
static LED: Mutex<RefCell<Option<gpiob::PB3<Output<PushPull>>>>> = Mutex::new(RefCell::new(None));
// Make our delay provider globally available
static DELAY: Mutex<RefCell<Option<Delay>>> = Mutex::new(RefCell::new(None));
// Make external interrupt registers globally available
static INT: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
if let (Some(p), Some(cp)) = (Peripherals::take(), c_m_Peripherals::take()) {
let gpiob = p.GPIOB.split();
let syscfg = p.SYSCFG_COMP;
let exti = p.EXTI;
// Enable clock for SYSCFG
let mut rcc = p.RCC;
rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit());
// Configure PB1 as input (button)
let _ = gpiob.pb1.into_pull_down_input();
// Configure PB3 as output (LED)
let mut led = gpiob.pb3.into_push_pull_output();
// Turn off LED
led.set_low();
// Configure clock to 8 MHz (i.e. the default) and freeze it
let clocks = rcc.constrain().cfgr.sysclk(8.mhz()).freeze();
// Initialise delay provider
let mut delay = Delay::new(cp.SYST, clocks);
// Enable external interrupt for PB1
syscfg
.syscfg_exticr1
.modify(|_, w| unsafe { w.exti1().bits(1) });
// Set interrupt request mask for line 1
exti.imr.modify(|_, w| w.mr1().set_bit());
// Set interrupt rising trigger for line 1
exti.rtsr.modify(|_, w| w.tr1().set_bit());
// Move control over LED and DELAY and EXTI into global mutexes
cortex_m::interrupt::free(move |cs| {
*LED.borrow(cs).borrow_mut() = Some(led);
*DELAY.borrow(cs).borrow_mut() = Some(delay);
*INT.borrow(cs).borrow_mut() = Some(exti);
});
// Enable EXTI IRQ, set prio 1 and clear any pending IRQs
let mut nvic = cp.NVIC;
nvic.enable(Interrupt::EXTI0_1);
unsafe { nvic.set_priority(Interrupt::EXTI0_1, 1) };
cortex_m::peripheral::NVIC::unpend(Interrupt::EXTI0_1);
}
loop {
continue;
}
}
/* Define an intterupt handler, i.e. function to call when exception occurs. Here if our external
* interrupt trips the flash function which will be called */
interrupt!(EXTI0_1, button_press);
fn button_press() {
// Enter critical section
cortex_m::interrupt::free(|cs| {
// Obtain all Mutex protected resources
if let (&mut Some(ref mut led), &mut Some(ref mut delay), &mut Some(ref mut exti)) = (
LED.borrow(cs).borrow_mut().deref_mut(),
DELAY.borrow(cs).borrow_mut().deref_mut(),
INT.borrow(cs).borrow_mut().deref_mut(),
) {
// Turn on LED
led.set_high();
// Wait a second
delay.delay_ms(1_000_u16);
// Turn off LED
led.set_low();
// Clear interrupt
exti.pr.modify(|_, w| w.pif1().set_bit());
}
});
}

43
examples/serial_echo.rs

@ -0,0 +1,43 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::prelude::*;
use hal::stm32;
#[macro_use(block)]
extern crate nb;
use hal::serial::Serial;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
if let Some(p) = stm32::Peripherals::take() {
let gpioa = p.GPIOA.split();
let mut rcc = p.RCC.constrain();
let clocks = rcc.cfgr.sysclk(48.mhz()).freeze();
let tx = gpioa.pa9.into_alternate_af1();
let rx = gpioa.pa10.into_alternate_af1();
let serial = Serial::usart1(p.USART1, (tx, rx), 115_200.bps(), clocks);
let (mut tx, mut rx) = serial.split();
loop {
let received = block!(rx.read()).unwrap();
block!(tx.write(received)).ok();
}
}
loop {
continue;
}
}

66
examples/spi_hal_apa102c.rs

@ -0,0 +1,66 @@
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate panic_halt;
extern crate stm32f0xx_hal as hal;
use hal::prelude::*;
use hal::spi::Spi;
use hal::spi::{Mode, Phase, Polarity};
use hal::stm32;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
pub const MODE: Mode = Mode {
polarity: Polarity::IdleHigh,
phase: Phase::CaptureOnSecondTransition,
};
if let Some(p) = stm32::Peripherals::take() {
let mut rcc = p.RCC.constrain();
let clocks = rcc.cfgr.freeze();
let mut gpioa = p.GPIOA.split();
// Configure pins for SPI
let sck = gpioa.pa5.into_alternate_af0();
let miso = gpioa.pa6.into_alternate_af0();
let mosi = gpioa.pa7.into_alternate_af0();
// Configure SPI with 100kHz rate
let mut spi = Spi::spi1(p.SPI1, (sck, miso, mosi), MODE, 100_000.hz(), clocks);
// Cycle through colors on 16 chained APA102C LEDs
loop {
for r in 0..255 {
let _ = spi.write(&[0, 0, 0, 0]);
for _i in 0..16 {
let _ = spi.write(&[0b1110_0001, 0, 0, r]);
}
let _ = spi.write(&[0xFF, 0xFF, 0xFF, 0xFF]);
}
for b in 0..255 {
let _ = spi.write(&[0, 0, 0, 0]);
for _i in 0..16 {
let _ = spi.write(&[0b1110_0001, b, 0, 0]);
}
let _ = spi.write(&[0xFF, 0xFF, 0xFF, 0xFF]);
}
for g in 0..255 {
let _ = spi.write(&[0, 0, 0, 0]);
for _i in 0..16 {
let _ = spi.write(&[0b1110_0001, 0, g, 0]);
}
let _ = spi.write(&[0xFF, 0xFF, 0xFF, 0xFF]);
}
}
}
loop {
continue;
}
}

11
memory.x

@ -0,0 +1,11 @@
MEMORY
{
/* NOTE K = KiBi = 1024 bytes */
FLASH : ORIGIN = 0x08000000, LENGTH = 32K
RAM : ORIGIN = 0x20000000, LENGTH = 6K
}
/* This is where the call stack will be allocated. */
/* The stack is of the full descending type. */
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
_stack_start = ORIGIN(RAM) + LENGTH(RAM);

5
openocd.cfg

@ -0,0 +1,5 @@
source [find interface/cmsis-dap.cfg]
source [find target/stm32f0x.cfg]
init
flash probe 0

8
openocd_program.sh

@ -0,0 +1,8 @@
#!/bin/sh
if (( $# != 1 )); then
echo "Usage:"
echo "$0 <filename of firmware in ELF format>"
exit 1
fi
openocd -f openocd.cfg -c "program $1 verify reset exit"

74
src/delay.rs

@ -0,0 +1,74 @@
//! Delays
use cast::u32;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;
use hal::blocking::delay::{DelayMs, DelayUs};
use rcc::Clocks;
/// System timer (SysTick) as a delay provider
pub struct Delay {
clocks: Clocks,
syst: SYST,
}
impl Delay {
/// Configures the system timer (SysTick) as a delay provider
pub fn new(mut syst: SYST, clocks: Clocks) -> Self {
syst.set_clock_source(SystClkSource::Core);
Delay { syst, clocks }
}
/// Releases the system timer (SysTick) resource
pub fn free(self) -> SYST {
self.syst
}
}
impl DelayMs<u32> for Delay {
fn delay_ms(&mut self, ms: u32) {
self.delay_us(ms * 1_000);
}
}
impl DelayMs<u16> for Delay {
fn delay_ms(&mut self, ms: u16) {
self.delay_ms(u32(ms));
}
}
impl DelayMs<u8> for Delay {
fn delay_ms(&mut self, ms: u8) {
self.delay_ms(u32(ms));
}
}
impl DelayUs<u32> for Delay {
fn delay_us(&mut self, us: u32) {
let rvr = us * (self.clocks.sysclk().0 / 1_000_000);
assert!(rvr < (1 << 24));
self.syst.set_reload(rvr);
self.syst.clear_current();
self.syst.enable_counter();
while !self.syst.has_wrapped() {}
self.syst.disable_counter();
}
}
impl DelayUs<u16> for Delay {
fn delay_us(&mut self, us: u16) {
self.delay_us(u32(us))
}
}
impl DelayUs<u8> for Delay {
fn delay_us(&mut self, us: u8) {
self.delay_us(u32(us))
}
}

497
src/gpio.rs

@ -0,0 +1,497 @@
//! General Purpose Input / Output
use core::marker::PhantomData;
/// Extension trait to split a GPIO peripheral in independent pins and registers
pub trait GpioExt {
/// The parts to split the GPIO into
type Parts;
/// Splits the GPIO block into independent pins and registers
fn split(self) -> Self::Parts;
}
pub struct AF0;
pub struct AF1;
pub struct AF2;
pub struct AF3;
pub struct AF4;
pub struct AF5;
pub struct AF6;
pub struct AF7;
pub struct Alternate<MODE> {
_mode: PhantomData<MODE>,
}
/// Input mode (type state)
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
/// Floating input (type state)
pub struct Floating;
/// Pulled down input (type state)
pub struct PullDown;
/// Pulled up input (type state)
pub struct PullUp;
/// Open drain input or output (type state)
pub struct OpenDrain;
/// Output mode (type state)
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
/// Push pull output (type state)
pub struct PushPull;
macro_rules! gpio {
($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
]) => {
/// GPIO
pub mod $gpiox {
use core::marker::PhantomData;
use hal::digital::{InputPin, OutputPin, StatefulOutputPin};
use stm32::$GPIOX;
use stm32::RCC;
use super::{
Alternate, Floating, GpioExt, Input, OpenDrain, Output,
PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7,
};
/// GPIO parts
pub struct Parts {
$(
/// Pin
pub $pxi: $PXi<$MODE>,
)+
}
impl GpioExt for $GPIOX {
type Parts = Parts;
fn split(self) -> Parts {
// NOTE(unsafe) This executes only during initialisation
let rcc = unsafe { &(*RCC::ptr()) };
rcc.ahbenr.modify(|_, w| w.$iopxenr().set_bit());
Parts {
$(
$pxi: $PXi { _mode: PhantomData },
)+
}
}
}
/// Partially erased pin
pub struct $PXx<MODE> {
i: u8,
_mode: PhantomData<MODE>,
}
impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
fn is_set_high(&self) -> bool {
!self.is_set_low()
}
fn is_set_low(&self) -> bool {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
}
}
impl<MODE> OutputPin for $PXx<Output<MODE>> {
fn set_high(&mut self) {
// NOTE(unsafe) atomic write to a stateless register
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
}
fn set_low(&mut self) {
// NOTE(unsafe) atomic write to a stateless register
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
}
}
impl<MODE> InputPin for $PXx<Input<MODE>> {
fn is_high(&self) -> bool {
!self.is_low()
}
fn is_low(&self) -> bool {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
}
}
fn _set_alternate_mode (index:usize, mode: u32)
{
let offset = 2 * index;
let offset2 = 4 * index;
unsafe {
if offset2 < 32 {
&(*$GPIOX::ptr()).afrl.modify(|r, w| {
w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
});
} else
{
let offset2 = offset2 - 32;
&(*$GPIOX::ptr()).afrh.modify(|r, w| {
w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset