Skip to content

Commit

Permalink
Merge pull request #17 from RossPorter506/master
Browse files Browse the repository at this point in the history
Add I2C, SPI, and ADC functionality, Take 2
  • Loading branch information
YuhanLiin authored Jan 20, 2025
2 parents d5542a1 + 1629c9b commit d3c45f8
Show file tree
Hide file tree
Showing 25 changed files with 2,749 additions and 249 deletions.
60 changes: 60 additions & 0 deletions examples/adc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#![no_main]
#![no_std]

use embedded_hal::digital::v2::*;
use msp430_rt::entry;
use msp430fr2x5x_hal::{
adc::{AdcConfig, ClockDivider, Predivider, Resolution, SampleTime, SamplingRate},
gpio::Batch,
pmm::Pmm,
watchdog::Wdt,
};
use nb::block;
use panic_msp430 as _;

// If pin 1.1 is between 1V and 2V, the LED on pin 1.0 should light up.
#[entry]
fn main() -> ! {
// Take peripherals and disable watchdog
let periph = msp430fr2355::Peripherals::take().unwrap();
let _wdt = Wdt::constrain(periph.WDT_A);

// Configure GPIO
let pmm = Pmm::new(periph.PMM);
let port1 = Batch::new(periph.P1).split(&pmm);
let mut led = port1.pin0.to_output();
let mut adc_pin = port1.pin1.to_alternate3();

// ADC setup
let mut adc = AdcConfig::new(
ClockDivider::_1,
Predivider::_1,
Resolution::_8BIT,
SamplingRate::_50KSPS,
SampleTime::_4,
)
.use_modclk()
.configure(periph.ADC);

loop {
// Get ADC voltage, assuming the ADC reference voltage is 3300mV
// It's infallible besides nb::WouldBlock, so it's safe to unwrap after block!()
// If you want a raw count use adc.read() instead.
let reading_mv = block!( adc.read_voltage_mv(&mut adc_pin, 3300) ).unwrap();

// Turn on LED if voltage between 1000 and 2000mV
if (1000..=2000).contains(&reading_mv) {
led.set_high().ok();
} else {
led.set_low().ok();
}
}
}

// The compiler will emit calls to the abort() compiler intrinsic if debug assertions are
// enabled (default for dev profile). MSP430 does not actually have meaningful abort() support
// so for now, we create our own in each application where debug assertions are present.
#[no_mangle]
extern "C" fn abort() -> ! {
panic!();
}
41 changes: 21 additions & 20 deletions examples/blinky.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,40 @@

use embedded_hal::digital::v2::*;
use msp430_rt::entry;
use msp430fr2x5x_hal::{gpio::Batch, pmm::Pmm, watchdog::Wdt};
use msp430fr2x5x_hal::{
clock::{ClockConfig, DcoclkFreqSel, MclkDiv, SmclkDiv},
fram::Fram,
gpio::Batch,
hal::blocking::delay::DelayMs,
pmm::Pmm,
watchdog::Wdt,
};
use panic_msp430 as _;

// Red onboard LED should blink at a steady period.
// Green onboard LED should go on when P2.3 button is pressed
#[entry]
fn main() -> ! {
// Take peripherals and disable watchdog
let periph = msp430fr2355::Peripherals::take().unwrap();
let _wdt = Wdt::constrain(periph.WDT_A);

// Configure GPIO
let pmm = Pmm::new(periph.PMM);
let p1 = Batch::new(periph.P1).split(&pmm);
let p2 = Batch::new(periph.P2)
.config_pin3(|p| p.pullup())
.split(&pmm);
let p6 = Batch::new(periph.P6)
.config_pin6(|p| p.to_output())
.split(&pmm);
let port1 = Batch::new(periph.P1).split(&pmm);
let mut p1_0 = port1.pin0.to_output();

let mut p1_0 = p1.pin0.to_output();
let p2_3 = p2.pin3;
let mut p6_6 = p6.pin6;
// Configure clocks to get accurate delay timing
let mut fram = Fram::new(periph.FRCTL);
let (_smclk, _aclk, mut delay) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_8MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_1)
.freeze(&mut fram);

loop {
// `toggle()` returns a `Result` because of embedded_hal, but the result is always `Ok` with MSP430 GPIO.
// Rust complains about unused Results, so we 'use' the Result by calling .ok()
p1_0.toggle().ok();

for _ in 0..5000 {
if p2_3.is_high().unwrap() {
p6_6.set_low().ok();
} else {
p6_6.set_high().ok();
}
}
delay.delay_ms(500);
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> ! {
.config_pin0(|p| p.to_output())
.split(&pmm);

let (smclk, aclk) = ClockConfig::new(periph.CS)
let (smclk, aclk, _delay) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_1MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_1)
.aclk_vloclk()
Expand Down
87 changes: 42 additions & 45 deletions examples/capture_intr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![no_std]
#![feature(abi_msp430_interrupt)]

// This example also demonstrates how to write panic-free code using panic_never.

use core::cell::UnsafeCell;
use critical_section::with;
use embedded_hal::digital::v2::ToggleableOutputPin;
Expand All @@ -27,6 +29,7 @@ use panic_msp430 as _;
#[cfg(not(debug_assertions))]
use panic_never as _;

// We use UnsafeCell as a panic-free version of RefCell. If you aren't using `panic_never` then RefCell is more ergonomic.
static CAPTURE: Mutex<UnsafeCell<Option<Capture<msp430fr2355::TB0, CCR1>>>> =
Mutex::new(UnsafeCell::new(None));
static VECTOR: Mutex<UnsafeCell<Option<TBxIV<msp430fr2355::TB0>>>> =
Expand All @@ -38,38 +41,37 @@ static RED_LED: Mutex<UnsafeCell<Option<Pin<P1, Pin0, Output>>>> =
// so sometimes inputs are missed.
#[entry]
fn main() -> ! {
if let Some(periph) = msp430fr2355::Peripherals::take() {
let mut fram = Fram::new(periph.FRCTL);
Wdt::constrain(periph.WDT_A);

let pmm = Pmm::new(periph.PMM);
let p1 = Batch::new(periph.P1)
.config_pin0(|p| p.to_output())
.split(&pmm);
let red_led = p1.pin0;

with(|cs| unsafe { *RED_LED.borrow(cs).get() = Some(red_led) });

let (_smclk, aclk) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_1MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_1)
.aclk_vloclk()
.freeze(&mut fram);

let captures = CaptureParts3::config(periph.TB0, TimerConfig::aclk(&aclk))
.config_cap1_input_A(p1.pin6.to_alternate2())
.config_cap1_trigger(CapTrigger::FallingEdge)
.commit();
let mut capture = captures.cap1;
let vectors = captures.tbxiv;

setup_capture(&mut capture);
with(|cs| {
unsafe { *CAPTURE.borrow(cs).get() = Some(capture) }
unsafe { *VECTOR.borrow(cs).get() = Some(vectors) }
});
unsafe { enable() };
}
let Some(periph) = msp430fr2355::Peripherals::take() else { loop {} };
let mut fram = Fram::new(periph.FRCTL);
Wdt::constrain(periph.WDT_A);

let pmm = Pmm::new(periph.PMM);
let p1 = Batch::new(periph.P1)
.config_pin0(|p| p.to_output())
.split(&pmm);
let red_led = p1.pin0;

with(|cs| unsafe { *RED_LED.borrow(cs).get() = Some(red_led) });

let (_smclk, aclk, _delay) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_1MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_1)
.aclk_vloclk()
.freeze(&mut fram);

let captures = CaptureParts3::config(periph.TB0, TimerConfig::aclk(&aclk))
.config_cap1_input_A(p1.pin6.to_alternate2())
.config_cap1_trigger(CapTrigger::FallingEdge)
.commit();
let mut capture = captures.cap1;
let vectors = captures.tbxiv;

setup_capture(&mut capture);
with(|cs| {
unsafe { *CAPTURE.borrow(cs).get() = Some(capture) }
unsafe { *VECTOR.borrow(cs).get() = Some(vectors) }
});
unsafe { enable() };

loop {}
}
Expand All @@ -81,20 +83,15 @@ fn setup_capture<T: CapCmp<C>, C>(capture: &mut Capture<T, C>) {
#[interrupt]
fn TIMER0_B1() {
with(|cs| {
if let Some(vector) = unsafe { &mut *VECTOR.borrow(cs).get() }.as_mut() {
if let Some(capture) = unsafe { &mut *CAPTURE.borrow(cs).get() }.as_mut() {
match vector.interrupt_vector() {
CaptureVector::Capture1(cap) => {
if cap.interrupt_capture(capture).is_ok() {
if let Some(led) = unsafe { &mut *RED_LED.borrow(cs).get() }.as_mut() {
led.toggle().void_unwrap();
}
}
}
_ => {}
};
let Some(vector) = unsafe { &mut *VECTOR.borrow(cs).get() }.as_mut() else { return; };
let Some(capture) = unsafe { &mut *CAPTURE.borrow(cs).get() }.as_mut() else { return; };
let Some(led) = unsafe { &mut *RED_LED.borrow(cs).get() }.as_mut() else { return; };

if let CaptureVector::Capture1(cap) = vector.interrupt_vector() {
if cap.interrupt_capture(capture).is_ok() {
led.toggle().void_unwrap();
}
}
};
});
}

Expand Down
2 changes: 1 addition & 1 deletion examples/clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() -> ! {
.split(&pmm);
let mut p1_0 = p1.pin0;

let (smclk, _aclk) = ClockConfig::new(periph.CS)
let (smclk, _aclk, _delay) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_8MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_1)
.aclk_vloclk()
Expand Down
2 changes: 1 addition & 1 deletion examples/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn main() -> ! {
let mut fram = Fram::new(periph.FRCTL);
let _wdt = Wdt::constrain(periph.WDT_A);

let (_smclk, aclk) = ClockConfig::new(periph.CS)
let (_smclk, aclk, _delay) = ClockConfig::new(periph.CS)
.mclk_dcoclk(DcoclkFreqSel::_1MHz, MclkDiv::_1)
.smclk_on(SmclkDiv::_2)
.aclk_refoclk()
Expand Down
41 changes: 41 additions & 0 deletions examples/gpio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#![no_main]
#![no_std]

use embedded_hal::digital::v2::*;
use msp430_rt::entry;
use msp430fr2x5x_hal::{gpio::Batch, pmm::Pmm, watchdog::Wdt};
use panic_msp430 as _;

// Green onboard LED should go on when P2.3 button is pressed
#[entry]
fn main() -> ! {
let periph = msp430fr2355::Peripherals::take().unwrap();
let _wdt = Wdt::constrain(periph.WDT_A);

let pmm = Pmm::new(periph.PMM);
let p2 = Batch::new(periph.P2)
.config_pin3(|p| p.pullup())
.split(&pmm);
let p6 = Batch::new(periph.P6)
.config_pin6(|p| p.to_output())
.split(&pmm);

let p2_3 = p2.pin3;
let mut p6_6 = p6.pin6;

loop {
if p2_3.is_high().unwrap() {
p6_6.set_low().ok();
} else {
p6_6.set_high().ok();
}
}
}

// The compiler will emit calls to the abort() compiler intrinsic if debug assertions are
// enabled (default for dev profile). MSP430 does not actually have meaningful abort() support
// so for now, we create our own in each application where debug assertions are present.
#[no_mangle]
extern "C" fn abort() -> ! {
panic!();
}
26 changes: 10 additions & 16 deletions examples/gpio_interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static P2IV: Mutex<RefCell<Option<PxIV<P2>>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let periph = msp430fr2355::Peripherals::take().unwrap();
let (_smclk, aclk) = ClockConfig::new(periph.CS)
let (_smclk, aclk, _delay) = ClockConfig::new(periph.CS)
.mclk_refoclk(MclkDiv::_1)
// 32 KHz SMCLK
.smclk_on(SmclkDiv::_2)
Expand All @@ -53,8 +53,8 @@ fn main() -> ! {
let mut green_led = p6.pin6;
let p2iv = p2.pxiv;

with(|cs| *RED_LED.borrow(cs).borrow_mut() = Some(red_led));
with(|cs| *P2IV.borrow(cs).borrow_mut() = Some(p2iv));
with(|cs| RED_LED.borrow_ref_mut(cs).replace(red_led));
with(|cs| P2IV.borrow_ref_mut(cs).replace(p2iv));

wdt.set_aclk(&aclk)
.enable_interrupts()
Expand All @@ -74,25 +74,19 @@ fn main() -> ! {
#[interrupt]
fn PORT2() {
with(|cs| {
RED_LED.borrow(cs).borrow_mut().as_mut().map(|red_led| {
match P2IV
.borrow(cs)
.borrow_mut()
.as_mut()
.unwrap()
.get_interrupt_vector()
{
GpioVector::Pin7Isr => red_led.toggle().ok(),
_ => panic!(),
}
})
let Some(ref mut red_led) = *RED_LED.borrow_ref_mut(cs) else { return; };
let Some(ref mut p2iv) = *P2IV.borrow_ref_mut(cs) else { return; };

if let GpioVector::Pin7Isr = p2iv.get_interrupt_vector() {
red_led.toggle().ok();
}
});
}

#[interrupt]
fn WDT() {
with(|cs| {
RED_LED.borrow(cs).borrow_mut().as_mut().map(|red_led| {
RED_LED.borrow_ref_mut(cs).as_mut().map(|red_led| {
red_led.toggle().ok();
})
});
Expand Down
Loading

0 comments on commit d3c45f8

Please sign in to comment.