-
|
Hi there, I'm new to embedded systems, so please feel free to correct me on anything I've gotten wrong. I'm working on a project that will use a baremetal attiny85, and I found this library and wanted to try and move from the previous arduino code to rust, as I'm more familiar with Rust than C, and I wanted to challenge myself. I coded more or less the basics of what I need to have the MCU do on an arduino nano using the avr-hal library, and I would like to 'migrate' it over to the attiny85. I know this is not going to be anywhere near a one-to-one move, so I'm expecting a nearly full rewrite. I have several attiny85s that I've been programming fairly well using the arduino suite of things, and specifically an Arduino Uno as the programmer for the ATTiny, setup as an ISP. I would really like to keep using this method of programming since this is the only method I have available currently, but I'm not opposed to getting more hardware to make the transition easier. I did a decent amount of research and found people saying the documentation for baremetal chips is not that mature yet, but I'm absolutely open to contributing where I can once I get things working. My biggest struggle currently is figuring out which modules to use and how to setup ravedude for programming the ATTiny as I mentioned previously. Any guidance would be really helpful, I've been at this for a little while with basically no progress. Thank you in advance for any help or criticisms! For reference, here's the code I wrote for the Nano (like I said, very basic, and not adapted to the ATTiny): #![no_std]
#![no_main]
#![feature(abi_avr_interrupt)]
use arduino_hal::prelude::*;
use avr_device::atmega328p::tc1::tccr1b::CS1_A;
use avr_device::atmega328p::TC1;
use core::mem;
use panic_halt as _;
use ufmt::{uWrite, uwriteln};
use core::sync::atomic::{AtomicBool, Ordering};
struct InterruptState {
// blinker: Pin<Output>,
}
struct SpeedState {
value: u8,
}
impl SpeedState {
fn increment(&mut self) {
if self.value < 3 {
self.value += 1;
}
}
fn decrement(&mut self) {
if self.value > 0 {
self.value -= 1;
}
}
fn get(&self) -> u8 {
self.value
}
}
static mut INTERRUPT_STATE: mem::MaybeUninit<InterruptState> = mem::MaybeUninit::uninit();
static PRINT_TICK: AtomicBool = AtomicBool::new(false);
#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);
let input_hold = pins.d2.into_pull_up_input();
let input_up = pins.d3.into_pull_up_input();
let input_down = pins.d4.into_pull_up_input();
let mut speed_state: SpeedState = SpeedState { value: 0 };
let mut count: u32 = 0;
let mut serial = arduino_hal::default_serial!(dp, pins, 115200);
ufmt::uwriteln!(&mut serial, "#########################").unwrap_infallible();
ufmt::uwriteln!(&mut serial, "Serial Interface Started.").unwrap_infallible();
ufmt::uwriteln!(&mut serial, "#########################").unwrap_infallible();
let _led = pins.d13.into_output();
let mut last_button_states = (false, false, false);
unsafe {
INTERRUPT_STATE = mem::MaybeUninit::new(InterruptState {
});
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
let tmr1: TC1 = dp.TC1;
unsafe {
avr_device::interrupt::enable();
}
loop {
let button_states = (input_hold.is_low(), input_up.is_low(), input_down.is_low());
if button_states.0 != last_button_states.0 {
if button_states.0 {
rig_timer(&tmr1, &mut serial);
ufmt::uwriteln!(&mut serial, "Button Pressed").unwrap_infallible();
} else {
end_timer(&tmr1);
count = 0;
ufmt::uwriteln!(&mut serial, "Button Released").unwrap_infallible();
}
}
if PRINT_TICK.load(Ordering::Acquire) {
count += 1;
PRINT_TICK.store(false, Ordering::Release);
}
if count >= 2 {
if button_states.1 && button_states.1 != last_button_states.1 {
speed_state.increment();
ufmt::uwriteln!(&mut serial, "Speed State: {}", speed_state.get()).unwrap_infallible();
}
if button_states.2 && button_states.2 != last_button_states.2 {
speed_state.decrement();
ufmt::uwriteln!(&mut serial, "Speed State: {}", speed_state.get()).unwrap_infallible();
}
}
last_button_states = button_states;
}
}
pub const fn calc_overflow(clock_hz: u32, target_hz: u32, prescale: u32) -> u32 {
clock_hz / target_hz / prescale - 1
}
pub fn end_timer(tmr1: &TC1) {
tmr1.timsk1().write(|w| w.ocie1a().clear_bit());
}
pub fn rig_timer<W: uWrite<Error = ::core::convert::Infallible>>(tmr1: &TC1, serial: &mut W) {
use arduino_hal::clock::Clock;
const ARDUINO_NANO_CLOCK_FREQUENCY_HZ: u32 = arduino_hal::DefaultClock::FREQ;
const CLOCK_SOURCE: CS1_A = CS1_A::PRESCALE_256;
let clock_divisor: u32 = match CLOCK_SOURCE {
CS1_A::DIRECT => 1,
CS1_A::PRESCALE_8 => 8,
CS1_A::PRESCALE_64 => 64,
CS1_A::PRESCALE_256 => 256,
CS1_A::PRESCALE_1024 => 1024,
CS1_A::NO_CLOCK | CS1_A::EXT_FALLING | CS1_A::EXT_RISING => {
uwriteln!(serial, "uhoh, code tried to set the clock source to something other than a static prescaler {}", CLOCK_SOURCE as usize)
.unwrap_infallible();
1
}
};
let ticks = calc_overflow(ARDUINO_NANO_CLOCK_FREQUENCY_HZ, 1, clock_divisor) as u16;
tmr1.tccr1a().write(|w| w.wgm1().set(0b00));
tmr1.tccr1b().write(|w| {
w.cs1()
//.prescale_256()
.variant(CLOCK_SOURCE)
.wgm1()
.set(0b01)
});
tmr1.ocr1a().write(|w| w.set(ticks));
tmr1.timsk1().write(|w| w.ocie1a().set_bit()); // enable this specific interrupt
}
#[avr_device::interrupt(atmega328p)]
fn TIMER1_COMPA() {
unsafe {
let _ = &mut *INTERRUPT_STATE.as_mut_ptr();
};
PRINT_TICK.store(true, Ordering::Release);
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
|
Alright, I ended up figuring it out. Needed to use the "arduino_as_isp" programmer in Ravedude.toml and importing attiny_hal instead of arduino_hal. |
Beta Was this translation helpful? Give feedback.
Alright, I ended up figuring it out. Needed to use the "arduino_as_isp" programmer in Ravedude.toml and importing attiny_hal instead of arduino_hal.