Created
January 10, 2019 20:33
-
-
Save therealprof/643733e996b1c9eae66c39f6e2ce7173 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_main] | |
#![no_std] | |
use panic_halt; | |
use stm32f0xx_hal as hal; | |
use cortex_m_rt::entry; | |
use crate::hal::gpio::{gpiof::PF0, gpiof::PF1, Alternate, AF1}; | |
use crate::hal::i2c::*; | |
use crate::hal::prelude::*; | |
use crate::hal::serial::Serial; | |
use crate::hal::stm32::{self, interrupt, Interrupt::USART2}; | |
use core::cell::RefCell; | |
use core::fmt::Write; | |
use core::ops::{DerefMut, Deref}; | |
use cortex_m::{interrupt::Mutex, peripheral::Peripherals}; | |
// Make some peripherals globally available | |
struct MyShared { | |
i2c: hal::i2c::I2c<stm32::I2C1, PF1<Alternate<AF1>>, PF0<Alternate<AF1>>>, | |
rx: hal::serial::Rx<stm32::USART2>, | |
tx: hal::serial::Tx<stm32::USART2>, | |
} | |
use bare_metal::{CriticalSection}; | |
pub struct Shared<T> { | |
inner: Mutex<RefCell<Option<T>>>, | |
} | |
impl <T> Shared<T> { | |
/// Creates a new shared value | |
pub const fn new() -> Self { | |
Shared { | |
inner: Mutex::new(RefCell::new(None)), | |
} | |
} | |
pub fn load(&mut self, cs: &CriticalSection, value: T) -> Option<T> { | |
self.inner.borrow(cs).replace(Some(value)) | |
} | |
pub fn get<'a>(&'a self, cs: &'a CriticalSection) -> Option<core::cell::Ref<'a, T>> { | |
match self.inner.borrow(cs).try_borrow().ok() { | |
Some(inner) => match inner.deref() { | |
Some(_) => Some(core::cell::Ref::map(inner, |v| v.as_ref().unwrap())), | |
None => None, | |
} | |
None => None, | |
} | |
} | |
pub fn get_mut<'a>(&'a self, cs: &'a CriticalSection) -> Option<core::cell::RefMut<'a, T>> { | |
match self.inner.borrow(cs).try_borrow_mut().ok() { | |
Some(mut inner) => match inner.deref_mut() { | |
Some(_) => Some(core::cell::RefMut::map(inner, |v| v.as_mut().unwrap())), | |
None => None, | |
} | |
None => None, | |
} | |
} | |
} | |
static SHARED: Shared<MyShared> = Shared::new(); | |
#[entry] | |
fn main() -> ! { | |
if let (Some(mut p), Some(cp)) = (stm32::Peripherals::take(), Peripherals::take()) { | |
cortex_m::interrupt::free(|cs| { | |
// Configure clock to 8 MHz (i.e. the default) and freeze it | |
let rcc = p.RCC.configure().freeze(&mut p.FLASH); | |
let gpioa = p.GPIOA.split(&rcc); | |
let gpiof = p.GPIOF.split(&rcc); | |
let mut nvic = cp.NVIC; | |
let scl = gpiof | |
.pf1 | |
.into_alternate_af1(cs) | |
.internal_pull_up(cs, true) | |
.set_open_drain(cs); | |
let sda = gpiof | |
.pf0 | |
.into_alternate_af1(cs) | |
.internal_pull_up(cs, true) | |
.set_open_drain(cs); | |
// Setup I2C1 | |
let i2c = I2c::i2c1(p.I2C1, (scl, sda), 100.khz(), &rcc); | |
// USART2 at PA2 (TX) and PA15(RX) is connectet to ST-Link | |
let tx = gpioa.pa2.into_alternate_af1(cs); | |
let rx = gpioa.pa15.into_alternate_af1(cs); | |
// Set up our serial port for output | |
let mut serial = Serial::usart2(p.USART2, (tx, rx), 115_200.bps(), &rcc); | |
// Enable USART2 interrupt on received input | |
serial.listen(hal::serial::Event::Rxne); | |
let (mut tx, rx) = serial.split(); | |
// Enable USART2 interrupt and clear any pending interrupts | |
nvic.enable(USART2); | |
cortex_m::peripheral::NVIC::unpend(USART2); | |
// Print a welcome message | |
tx.write_str("\r\nWelcome to the I2C scanner. Enter any character to start scan.\r\n") | |
.ok(); | |
// Move all components under Mutex supervision | |
SHARED.load(cs, MyShared { i2c, rx, tx }); | |
}); | |
} | |
loop { | |
continue; | |
} | |
} | |
// The IRQ handler triggered by a received character in USART buffer, this will conduct our I2C | |
// scan when we receive anything | |
#[interrupt] | |
fn USART2() { | |
cortex_m::interrupt::free(|cs| { | |
// Obtain all Mutex protected resources | |
if let Some(mut shared) = SHARED.get_mut(cs) { | |
let tx = &mut shared.tx; | |
let rx = &mut shared.rx; | |
let i2c = &mut shared.i2c; | |
/* Read the character that triggered the interrupt from the USART */ | |
while rx.read().is_ok() {} | |
/* Output address schema for tried addresses */ | |
let _ = tx.write_str("\r\n"); | |
let _ = tx.write_str( | |
"0 1 2 3 4 5 6 7\r\n", | |
); | |
let _ = tx.write_str( | |
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF\r\n", | |
); | |
// Execute scanning once for each valid I2C address | |
for addr in 0..=0x7f { | |
let res = i2c.write(addr, &[0]); | |
// If we received a NACK there's no device on the attempted address | |
let _ = tx.write_str(match res { | |
Err(Error::NACK) => ".", | |
_ => "Y", | |
}); | |
} | |
let _ = tx.write_str( | |
"\r\n\r\nScan done.\r\n'Y' means a device was found on the I2C address above.\r\n'.' means no device found on that address.\r\nPlease enter any character to start a new scan.\r\n", | |
); | |
} | |
// Clear interrupt flag | |
cortex_m::peripheral::NVIC::unpend(USART2); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment