Compare commits
1 Commits
master
...
features/p
Author | SHA1 | Date |
---|---|---|
![]() |
70eceec773 | 4 years ago |
44 changed files with 1571 additions and 4610 deletions
@ -1,8 +0,0 @@
|
||||
required_approvals = 1 |
||||
block_labels = ["wip"] |
||||
delete_merged_branches = true |
||||
status = [ |
||||
"Rustfmt", |
||||
"ci (stable)", |
||||
"ci (1.39.0, stable)", |
||||
] |
@ -1,33 +0,0 @@
|
||||
on: |
||||
push: |
||||
branches: [ staging, trying, master ] |
||||
pull_request: |
||||
|
||||
name: Continuous integration |
||||
|
||||
jobs: |
||||
ci: |
||||
runs-on: ubuntu-latest |
||||
strategy: |
||||
matrix: |
||||
rust: |
||||
- stable |
||||
- 1.39.0 # MSRV |
||||
include: |
||||
- rust: nightly |
||||
experimental: true |
||||
|
||||
steps: |
||||
- uses: actions/checkout@v2 |
||||
- uses: actions-rs/toolchain@v1 |
||||
with: |
||||
profile: minimal |
||||
toolchain: ${{ matrix.rust }} |
||||
target: thumbv6m-none-eabi |
||||
override: true |
||||
|
||||
- name: Regular build |
||||
run: python tools/check.py |
||||
|
||||
- name: Size check |
||||
run: python tools/check.py size_check |
@ -1,21 +0,0 @@
|
||||
on: |
||||
push: |
||||
branches: [ staging, trying, master ] |
||||
pull_request: |
||||
|
||||
name: Clippy check |
||||
jobs: |
||||
clippy_check: |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/checkout@v1 |
||||
- run: rustup component add clippy |
||||
- uses: actions-rs/toolchain@v1 |
||||
with: |
||||
toolchain: stable |
||||
target: thumbv6m-none-eabi |
||||
override: true |
||||
- uses: actions-rs/clippy-check@v1 |
||||
with: |
||||
token: ${{ secrets.GITHUB_TOKEN }} |
||||
args: --features=stm32f072 --target thumbv6m-none-eabi |
@ -1,23 +0,0 @@
|
||||
on: |
||||
push: |
||||
branches: [ staging, trying, master ] |
||||
pull_request: |
||||
|
||||
name: Code formatting check |
||||
|
||||
jobs: |
||||
fmt: |
||||
name: Rustfmt |
||||
runs-on: ubuntu-latest |
||||
steps: |
||||
- uses: actions/checkout@v2 |
||||
- uses: actions-rs/toolchain@v1 |
||||
with: |
||||
profile: minimal |
||||
toolchain: stable |
||||
override: true |
||||
- run: rustup component add rustfmt |
||||
- uses: actions-rs/cargo@v1 |
||||
with: |
||||
command: fmt |
||||
args: --all -- --check |
@ -0,0 +1,21 @@
|
||||
language: rust |
||||
rust: |
||||
- stable |
||||
- nightly |
||||
cache: cargo |
||||
env: |
||||
- MCU=stm32f042 |
||||
- MCU=stm32f030 |
||||
- MCU=stm32f030x6 |
||||
- MCU=stm32f030x8 |
||||
- MCU=stm32f030xc |
||||
- MCU=stm32f070 |
||||
- MCU=stm32f070x6 |
||||
- MCU=stm32f070xb |
||||
matrix: |
||||
allow_failures: |
||||
- rust: nightly |
||||
fast_finish: true |
||||
script: |
||||
- rustup target add thumbv6m-none-eabi |
||||
- cargo build --features=$MCU --examples --release |
@ -1,74 +1,41 @@
|
||||
stm32f0xx-hal |
||||
============= |
||||
|
||||
[](https://github.com/stm32-rs/stm32f0xx-hal) |
||||
[](https://crates.io/crates/stm32f0xx-hal) |
||||
[](https://docs.rs/stm32f0xx-hal/) |
||||
|
||||
[_stm32f0xx-hal_](https://github.com/stm32-rs/stm32f0xx-hal) contains a hardware abstraction on top of the peripheral access API for the STMicro STM32F0xx family of microcontrollers. |
||||
|
||||
This crate replaces the [stm32f042-hal](https://github.com/therealprof/stm32f042-hal) by a more ubiquitous version suitable for additional families. 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. |
||||
|
||||
This crate relies on Adam Greig's fantastic [stm32f0](https://crates.io/crates/stm32f0) crate to provide appropriate register definitions, and implements a partial set of the [embedded-hal](https://github.com/rust-embedded/embedded-hal) traits. Some of the implementation was shamelessly adapted from the [stm32f103xx-hal](https://github.com/japaric/stm32f103xx-hal) crate by Jorge Aparicio. |
||||
|
||||
Collaboration on this crate is highly welcome, as are pull requests! |
||||
|
||||
|
||||
Supported Configurations |
||||
------------------------ |
||||
|
||||
* __stm32f030__ (stm32f030x4, stm32f030x6, stm32f030x8, stm32f030xc) |
||||
* __stm32f031__ |
||||
* __stm32f038__ |
||||
* __stm32f042__ |
||||
* __stm32f048__ |
||||
* __stm32f051__ |
||||
* __stm32f058__ |
||||
* __stm32f070__ (stm32f070x6, stm32f070xb) |
||||
* __stm32f071__ |
||||
* __stm32f072__ |
||||
* __stm32f078__ |
||||
* __stm32f091__ |
||||
* __stm32f098__ |
||||
|
||||
|
||||
Getting Started |
||||
--------------- |
||||
The `examples` folder contains several example programs. To compile them, one must specify the target device as cargo feature: |
||||
``` |
||||
$ cargo build --features=stm32f030 |
||||
``` |
||||
|
||||
To use stm32f0xx-hal as a dependency in a standalone project the target device feature must be specified in the `Cargo.toml` file: |
||||
``` |
||||
[dependencies] |
||||
cortex-m = "0.6.0" |
||||
cortex-m-rt = "0.6.8" |
||||
stm32f0xx-hal = {version = "0.16", features = ["stm32f030"]} |
||||
``` |
||||
|
||||
If you are unfamiliar with embedded development using Rust, there are a number of fantastic resources available to help. |
||||
|
||||
- [Embedded Rust Documentation](https://docs.rust-embedded.org/) |
||||
- [The Embedded Rust Book](https://docs.rust-embedded.org/book/) |
||||
- [Rust Embedded FAQ](https://docs.rust-embedded.org/faq.html) |
||||
- [rust-embedded/awesome-embedded-rust](https://github.com/rust-embedded/awesome-embedded-rust) |
||||
|
||||
|
||||
Minimum supported Rust version |
||||
------------------------------ |
||||
|
||||
The minimum supported Rust version at the moment is **1.39.0**. Older versions |
||||
**may** compile, especially when some features are not used in your |
||||
application. |
||||
|
||||
Changelog |
||||
--------- |
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md). |
||||
|
||||
_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: |
||||
* stm32f030 |
||||
* stm32f030x4 |
||||
* stm32f030x6 |
||||
* stm32f030x8 |
||||
* stm32f030xc |
||||
* stm32f042 |
||||
* stm32f070 |
||||
* stm32f070x6 |
||||
* stm32f070xb |
||||
|
||||
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, see [LICENSE-0BSD.txt](LICENSE-0BSD.txt) for more details. |
||||
[0-clause BSD license](LICENSE-0BSD.txt). |
||||
|
@ -1,89 +0,0 @@
|
||||
#![no_main] |
||||
#![no_std] |
||||
|
||||
use panic_halt as _; |
||||
|
||||
use stm32f0xx_hal as hal; |
||||
|
||||
use crate::hal::{pac, prelude::*}; |
||||
|
||||
use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource::Core}; |
||||
use cortex_m_rt::{entry, exception}; |
||||
|
||||
use core::{cell::RefCell, fmt::Write}; |
||||
|
||||
struct Shared { |
||||
adc: hal::adc::Adc, |
||||
tx: hal::serial::Tx<pac::USART1>, |
||||
} |
||||
|
||||
static SHARED: Mutex<RefCell<Option<Shared>>> = Mutex::new(RefCell::new(None)); |
||||
|
||||
#[entry] |
||||
fn main() -> ! { |
||||
if let (Some(p), Some(cp)) = ( |
||||
hal::pac::Peripherals::take(), |
||||
cortex_m::peripheral::Peripherals::take(), |
||||
) { |
||||
cortex_m::interrupt::free(move |cs| { |
||||
let mut flash = p.FLASH; |
||||
let mut rcc = p.RCC.configure().sysclk(8.mhz()).freeze(&mut flash); |
||||
|
||||
let gpioa = p.GPIOA.split(&mut rcc); |
||||
|
||||
let mut syst = cp.SYST; |
||||
|
||||
// Set source for SysTick counter, here full operating frequency (== 8MHz)
|
||||
syst.set_clock_source(Core); |
||||
|
||||
// Set reload value, i.e. timer delay 8 MHz/counts
|
||||
syst.set_reload(8_000_000 - 1); |
||||
|
||||
// Start SysTick counter
|
||||
syst.enable_counter(); |
||||
|
||||
// Start SysTick interrupt generation
|
||||
syst.enable_interrupt(); |
||||
|
||||
// USART1 at PA9 (TX) and PA10(RX)
|
||||
let tx = gpioa.pa9.into_alternate_af1(cs); |
||||
let rx = gpioa.pa10.into_alternate_af1(cs); |
||||
|
||||
// Initialiase UART
|
||||
let (mut tx, _) = |
||||
hal::serial::Serial::usart1(p.USART1, (tx, rx), 115_200.bps(), &mut rcc).split(); |
||||
|
||||
// Initialise ADC
|
||||
let adc = hal::adc::Adc::new(p.ADC, &mut rcc); |
||||
|
||||
// Output a friendly greeting
|
||||
tx.write_str("\n\rThis ADC example will read various values using the ADC and print them out to the serial terminal\r\n").ok(); |
||||
|
||||
// Move all components under Mutex supervision
|
||||
*SHARED.borrow(cs).borrow_mut() = Some(Shared { adc, tx }); |
||||
}); |
||||
} |
||||
|
||||
loop { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
#[exception] |
||||
fn SysTick() { |
||||
use core::ops::DerefMut; |
||||
|
||||
// Enter critical section
|
||||
cortex_m::interrupt::free(|cs| { |
||||
// Get access to the Mutex protected shared data
|
||||
if let Some(ref mut shared) = SHARED.borrow(cs).borrow_mut().deref_mut() { |
||||
// Read temperature data from internal sensor using ADC
|
||||
let t = hal::adc::VTemp::read(&mut shared.adc, None); |
||||
writeln!(shared.tx, "Temperature {}.{}C\r", t / 100, t % 100).ok(); |
||||
|
||||
// Read volatage reference data from internal sensor using ADC
|
||||
let t = hal::adc::VRef::read_vdda(&mut shared.adc); |
||||
writeln!(shared.tx, "Vdda {}mV\r", t).ok(); |
||||
} |
||||
}); |
||||
} |
@ -1,98 +0,0 @@
|
||||
#![no_main] |
||||
#![no_std] |
||||
|
||||
use panic_halt as _; |
||||
|
||||
use stm32f0xx_hal as hal; |
||||
|
||||
use crate::hal::{ |
||||
gpio::*, |
||||
pac::{interrupt, Interrupt, Peripherals, TIM7}, |
||||
prelude::*, |
||||
time::Hertz, |
||||
timers::*, |
||||
}; |
||||
|
||||
use cortex_m_rt::entry; |
||||
|
||||
use core::cell::RefCell; |
||||
use cortex_m::{interrupt::Mutex, peripheral::Peripherals as c_m_Peripherals}; |
||||
|
||||
// A type definition for the GPIO pin to be used for our LED
|
||||
type LEDPIN = gpioa::PA5<Output<PushPull>>; |
||||
|
||||
// Make LED pin globally available
|
||||
static GLED: Mutex<RefCell<Option<LEDPIN>>> = Mutex::new(RefCell::new(None)); |
||||
|
||||
// Make timer interrupt registers globally available
|
||||
static GINT: Mutex<RefCell<Option<Timer<TIM7>>>> = Mutex::new(RefCell::new(None)); |
||||
|
||||
// Define an interupt handler, i.e. function to call when interrupt occurs. Here if our external
|
||||
// interrupt trips when the timer timed out
|
||||
#[interrupt] |
||||
fn TIM7() { |
||||
static mut LED: Option<LEDPIN> = None; |
||||
static mut INT: Option<Timer<TIM7>> = None; |
||||
|
||||
let led = LED.get_or_insert_with(|| { |
||||
cortex_m::interrupt::free(|cs| { |
||||
// Move LED pin here, leaving a None in its place
|
||||
GLED.borrow(cs).replace(None).unwrap() |
||||
}) |
||||
}); |
||||
|
||||
let int = INT.get_or_insert_with(|| { |
||||
cortex_m::interrupt::free(|cs| { |
||||
// Move LED pin here, leaving a None in its place
|
||||
GINT.borrow(cs).replace(None).unwrap() |
||||
}) |
||||
}); |
||||
|
||||
led.toggle().ok(); |
||||
int.wait().ok(); |
||||
} |
||||
|
||||
#[entry] |
||||
fn main() -> ! { |
||||
if let (Some(mut p), Some(cp)) = (Peripherals::take(), c_m_Peripherals::take()) { |
||||
cortex_m::interrupt::free(move |cs| { |
||||
let mut rcc = p |
||||
.RCC |
||||
.configure() |
||||
.hsi48() |
||||
.enable_crs(p.CRS) |
||||
.sysclk(48.mhz()) |
||||
.pclk(24.mhz()) |
||||
.freeze(&mut p.FLASH); |
||||
|
||||
let gpioa = p.GPIOA.split(&mut rcc); |
||||
|
||||
// (Re-)configure PA5 as output
|
||||
let led = gpioa.pa5.into_push_pull_output(cs); |
||||
|
||||
// Move the pin into our global storage
|
||||
*GLED.borrow(cs).borrow_mut() = Some(led); |
||||
|
||||
// Set up a timer expiring after 1s
|
||||
let mut timer = Timer::tim7(p.TIM7, Hertz(1), &mut rcc); |
||||
|
||||
// Generate an interrupt when the timer expires
|
||||
timer.listen(Event::TimeOut); |
||||
|
||||
// Move the timer into our global storage
|
||||
*GINT.borrow(cs).borrow_mut() = Some(timer); |
||||
|
||||
// Enable TIM7 IRQ, set prio 1 and clear any pending IRQs
|
||||
let mut nvic = cp.NVIC; |
||||
unsafe { |
||||
nvic.set_priority(Interrupt::TIM7, 1); |
||||
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM7); |
||||
} |
||||
cortex_m::peripheral::NVIC::unpend(Interrupt::TIM7); |
||||
}); |
||||
} |
||||
|
||||
loop { |
||||
continue; |
||||
} |
||||
} |
@ -1,61 +0,0 @@
|
||||
#![deny(unused_imports)] |
||||
#![no_main] |
||||
#![no_std] |
||||
|
||||
use cortex_m; |
||||
use cortex_m_rt as rt; |
||||
use panic_halt as _; |
||||
|
||||
use stm32f0xx_hal as hal; |
||||
|
||||
use crate::hal::dac::*; |
||||
use crate::hal::pac; |
||||
use crate::hal::prelude::*; |
||||
|
||||
use rt::entry; |
||||
|
||||
enum Direction { |
||||
Upcounting, |
||||
Downcounting, |
||||
} |
||||
|
||||
#[entry] |
||||
fn main() -> ! { |
||||
if let (Some(mut dp), Some(_cp)) = (pac::Peripherals::take(), cortex_m::Peripherals::take()) { |
||||
let mut rcc = dp.RCC.configure().sysclk(8.mhz()).freeze(&mut dp.FLASH); |
||||
let gpioa = dp.GPIOA.split(&mut rcc); |
||||
|
||||
let pa4 = cortex_m::interrupt::free(move |cs| gpioa.pa4.into_analog(cs)); |
||||
|
||||
let mut dac = dac(dp.DAC, pa4, &mut rcc); |
||||
|
||||
dac.enable(); |
||||
|
||||
let mut dir = Direction::Upcounting; |
||||
let mut val = 0; |
||||
|
||||
dac.set_value(2058); |
||||
cortex_m::asm::bkpt(); |
||||
|
||||
dac.set_value(4095); |
||||
cortex_m::asm::bkpt(); |
||||
|
||||
loop { |
||||
dac.set_value(val); |
||||
match val { |
||||
0 => dir = Direction::Upcounting, |
||||
4095 => dir = Direction::Downcounting, |
||||
_ => (), |
||||
}; |
||||
|
||||
match dir { |
||||
Direction::Upcounting => val += 1, |
||||
Direction::Downcounting => val -= 1, |
||||
} |
||||
} |
||||
} |
||||
|
||||
loop { |
||||
continue; |
||||
} |
||||
} |
@ -1,96 +0,0 @@
|
||||
#![no_main] |
||||
#![no_std] |
||||
|
||||
use panic_halt as _; |
||||
|
||||
use stm32f0xx_hal as hal; |
||||
|
||||
use crate::hal::{gpio::*, pac, prelude::*}; |
||||
|
||||
use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource::Core, Peripherals}; |
||||
use cortex_m_rt::{entry, exception}; |
||||
|
||||
use core::cell::RefCell; |
||||
use core::mem::swap; |
||||
|
||||
// A type definition for the GPIO pin to be used for our LED
|
||||
type LEDPIN = gpiob::PB3<Output<PushPull>>; |
||||
|
||||
// Mutex protected structure for our shared GPIO pin
|
||||
static GPIO: Mutex<RefCell<Option<LEDPIN>>> = Mutex::new(RefCell::new(None)); |
||||
|
||||
#[entry] |
||||
fn main() -> ! { |
||||
if let (Some(mut p), Some(cp)) = (pac::Peripherals::take(), Peripherals::take()) { |
||||
cortex_m::interrupt::free(move |cs| { |
||||
let mut rcc = p.RCC.configure().sysclk(48.mhz()).freeze(&mut p.FLASH); |
||||
|
||||
// Get access to individual pins in the GPIO port
|
||||
let gpioa = p.GPIOB.split(&mut rcc); |
||||
|
||||
// (Re-)configure the pin connected to our LED as output
|
||||
let led = gpioa.pb3.into_push_pull_output(cs); |
||||
|
||||
// Transfer GPIO into a shared structure
|
||||
swap(&mut Some(led), &mut GPIO.borrow(cs).borrow_mut()); |
||||
|
||||
let mut syst = cp.SYST; |
||||
|
||||
// Initialise SysTick counter with a defined value
|
||||
unsafe { syst.cvr.write(1) }; |
||||
|
||||
// Set source for SysTick counter, here full operating frequency (== 48MHz)
|
||||
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 counting
|
||||
syst.enable_counter(); |
||||
|
||||
// Enable interrupt generation
|
||||
syst.enable_interrupt(); |
||||
}); |
||||
} |
||||
|
||||
loop { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
// Define an exception handler, i.e. function to call when exception occurs. Here, if our SysTick
|
||||
// timer generates an exception the following handler will be called
|
||||
#[exception] |
||||
fn SysTick() { |
||||
// Our moved LED pin
|
||||
static mut LED: Option<LEDPIN> = None; |
||||
|
||||
// Exception handler state variable
|
||||
static mut STATE: u8 = 1; |
||||
|
||||
// If LED pin was moved into the exception handler, just use it
|
||||
if let Some(led) = LED { |
||||
// Check state variable, keep LED off most of the time and turn it on every 10th tick
|
||||
if *STATE < 10 { |
||||
// Turn off the LED
|
||||
led.set_low().ok(); |
||||
|
||||
// And now increment state variable
|
||||
*STATE += 1; |
||||
} else { |
||||
// Turn on the LED
|
||||
led.set_high().ok(); |
||||
|
||||
// And set new state variable back to 0
|
||||
*STATE = 0; |
||||
} |
||||
} |
||||
// Otherwise move it out of the Mutex protected shared region into our exception handler
|
||||
else { |
||||
// Enter critical section
|
||||
cortex_m::interrupt::free(|cs| { |
||||
// Swap globally stored data with SysTick private data
|
||||
swap(LED, &mut GPIO.borrow(cs).borrow_mut()); |
||||
}); |
||||
} |
||||
} |
@ -1,48 +0,0 @@
|
||||
#![no_main] |
||||
#![no_std] |
||||
|
||||
use panic_halt as _; |
||||
|
||||
use stm32f0xx_hal as hal; |
||||
|
||||
use crate::hal::{i2c::I2c, pac, prelude::*}; |
||||
|
||||
use cortex_m_rt::entry; |
||||
|
||||
/* Example meant for stm32f030xc MCUs with i2c devices connected on PB7 and PB8 */ |
||||
|
||||
#[entry] |
||||
fn main() -> ! { |
||||
if let Some(p) = pac::Peripherals::take() { |
||||
cortex_m::interrupt::free(move |cs| { |
||||
let mut flash = p.FLASH; |
||||
let mut rcc = p.RCC.configure().freeze(&mut flash); |
||||
|
||||
let gpiob = p.GPIOB.split(&mut rcc); |
||||
|
||||
// Configure pins for I2C
|
||||
let sda = gpiob.pb7.into_alternate_af1(cs); |
||||
let scl = gpiob.pb8.into_alternate_af1(cs); |
||||
|
||||
// Configure I2C with 100kHz rate
|
||||
let mut i2c = I2c::i2c1(p.I2C1, (scl, sda), 100.khz(), &mut rcc); |
||||
|
||||
let mut _devices = 0; |
||||
// I2C addresses are 7-bit wide, covering the 0-127 range
|
||||
|