commit 5976f6e92cf330e5597cf07913f70786bdeaabee
parent 6b1a3bda0c8db9f7bb0d256df9db5f4f356465f8
Author: Bradley Gannon <bradley@bradleygannon.com>
Date: Tue, 10 Feb 2026 22:23:04 -0500
Move polled logic into interrupts and tune symbol timer
Diffstat:
| M | src/main.rs | | | 144 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
1 file changed, 87 insertions(+), 57 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -2,42 +2,97 @@
#![no_main]
#![feature(abi_avr_interrupt)]
-use core::{
- ptr::{read_volatile, write_volatile},
- sync::atomic::{AtomicU16, Ordering},
-};
+use core::cell::RefCell;
+use arduino_hal::{
+ hal::port::{PD2, PD3, PD4, PD5, PD6},
+ port::{mode::Output, Pin},
+};
+use avr_device::interrupt::{self, Mutex};
use embedded_hal::digital::OutputPin;
-use heapless::Vec;
use panic_halt as _;
-static COUNTER: AtomicU16 = AtomicU16::new(0);
-static INCREMENT: AtomicU16 = AtomicU16::new(0);
static SINE_TABLE: [u8; 32] = [
16, 19, 22, 24, 27, 29, 30, 31, 31, 31, 30, 29, 27, 24, 22, 19, 16, 12, 9, 7, 4, 2, 1, 0, 0, 0,
1, 2, 4, 7, 9, 12,
];
-static mut UPDATE_DAC: bool = false;
-static mut NEXT_SYMBOL: bool = false;
+
+// ASCII letter B with three idle bits, one start bit, eight data bits, and one stop bit (8N1)
+static MESSAGE: [bool; 13] = [
+ true, true, true, false, false, true, false, false, false, false, true, false, true,
+];
+
+static SENDER: Mutex<RefCell<Sender>> = Mutex::new(RefCell::new(Sender {
+ counter: 0,
+ increment: 0,
+ message_index: 0,
+ dac_0: None,
+ dac_1: None,
+ dac_2: None,
+ dac_3: None,
+ dac_4: None,
+}));
const MARK_INCREMENT: u16 = 2100;
const SPACE_INCREMENT: u16 = 3838;
+struct Sender {
+ counter: u16,
+ increment: u16,
+ message_index: usize,
+ dac_0: Option<Pin<Output, PD2>>,
+ dac_1: Option<Pin<Output, PD3>>,
+ dac_2: Option<Pin<Output, PD4>>,
+ dac_3: Option<Pin<Output, PD5>>,
+ dac_4: Option<Pin<Output, PD6>>,
+}
+
#[avr_device::interrupt(atmega328p)]
fn TIMER0_COMPA() {
- let old_counter = COUNTER.load(Ordering::SeqCst);
- let new_counter = old_counter.wrapping_add(INCREMENT.load(Ordering::SeqCst));
- let old_index = old_counter >> 11;
- let new_index = new_counter >> 11;
- if new_index != old_index {
- unsafe { UPDATE_DAC = true };
- }
- COUNTER.store(new_counter, Ordering::SeqCst);
+ interrupt::free(|cs| {
+ let mut sender = SENDER.borrow(cs).borrow_mut();
+ sender.counter = sender.counter.wrapping_add(sender.increment);
+ let sine_index = ((sender.counter >> 11) as usize).clamp(0, SINE_TABLE.len());
+ if let Some(sine_value) = SINE_TABLE.get(sine_index) {
+ let _ = sender
+ .dac_0
+ .as_mut()
+ .unwrap()
+ .set_state((sine_value & 0b10000 != 0).into());
+ let _ = sender
+ .dac_1
+ .as_mut()
+ .unwrap()
+ .set_state((sine_value & 0b01000 != 0).into());
+ let _ = sender
+ .dac_2
+ .as_mut()
+ .unwrap()
+ .set_state((sine_value & 0b00100 != 0).into());
+ let _ = sender
+ .dac_3
+ .as_mut()
+ .unwrap()
+ .set_state((sine_value & 0b00010 != 0).into());
+ let _ = sender
+ .dac_4
+ .as_mut()
+ .unwrap()
+ .set_state((sine_value & 0b00001 != 0).into());
+ }
+ });
}
#[avr_device::interrupt(atmega328p)]
fn TIMER1_COMPA() {
- unsafe { NEXT_SYMBOL = true };
+ interrupt::free(|cs| {
+ let mut sender = SENDER.borrow(cs).borrow_mut();
+ match MESSAGE.get(sender.message_index).unwrap() {
+ true => sender.increment = MARK_INCREMENT,
+ false => sender.increment = SPACE_INCREMENT,
+ }
+ sender.message_index = (sender.message_index + 1) % MESSAGE.len();
+ });
}
#[arduino_hal::entry]
@@ -49,6 +104,15 @@ fn main() -> ! {
let mut _serial = arduino_hal::default_serial!(dp, pins, 57600);
+ interrupt::free(|cs| {
+ let mut sender = SENDER.borrow(cs).borrow_mut();
+ sender.dac_0 = Some(pins.d2.into_output());
+ sender.dac_1 = Some(pins.d3.into_output());
+ sender.dac_2 = Some(pins.d4.into_output());
+ sender.dac_3 = Some(pins.d5.into_output());
+ sender.dac_4 = Some(pins.d6.into_output());
+ });
+
let dac_timer = dp.TC0;
dac_timer.tccr0a().write(|w| w.wgm0().ctc());
dac_timer.tccr0b().write(|w| w.cs0().prescale_8());
@@ -56,48 +120,14 @@ fn main() -> ! {
dac_timer.ocr0a().write(|w| w.set(52));
dac_timer.timsk0().write(|w| w.ocie0a().set_bit());
- let mut dac_0 = pins.d2.into_output();
- let mut dac_1 = pins.d3.into_output();
- let mut dac_2 = pins.d4.into_output();
- let mut dac_3 = pins.d5.into_output();
- let mut dac_4 = pins.d6.into_output();
- let mut led = pins.d13.into_output();
-
let symbol_timer = dp.TC1;
symbol_timer
.tccr1b()
- .write(|w| w.wgm1().set(0b01).cs1().prescale_256());
- // 52 * 256 = 13_312 cycles; at 16 MHz this gives a period of 832 µs (about 1202 Hz)
- symbol_timer.ocr1a().write(|w| w.set(52));
+ .write(|w| w.wgm1().set(0b01).cs1().direct());
+ // this should theoretically be 13_333 cycles, but in practice we have to go a little faster to
+ // account for overhead; this value seems to work well
+ symbol_timer.ocr1a().write(|w| w.set(12_750));
symbol_timer.timsk1().write(|w| w.ocie1a().set_bit());
- // ASCII letter B with three idle bits, one start bit, eight data bits, and one stop bit (8N1)
- let message: Vec<bool, 13> = Vec::from_array([
- true, true, true, false, false, true, false, false, false, false, true, false, true,
- ]);
- let mut message_index = 0;
-
- loop {
- if unsafe { read_volatile(&raw const UPDATE_DAC) } {
- let sine_index =
- ((COUNTER.load(Ordering::SeqCst) >> 11) as usize).clamp(0, SINE_TABLE.len());
- if let Some(sine_value) = SINE_TABLE.get(sine_index) {
- let _ = dac_0.set_state((sine_value & 0b10000 != 0).into());
- let _ = dac_1.set_state((sine_value & 0b01000 != 0).into());
- let _ = dac_2.set_state((sine_value & 0b00100 != 0).into());
- let _ = dac_3.set_state((sine_value & 0b00010 != 0).into());
- let _ = dac_4.set_state((sine_value & 0b00001 != 0).into());
- }
- led.toggle();
- unsafe { write_volatile(&raw mut UPDATE_DAC, false) };
- }
- if unsafe { read_volatile(&raw const NEXT_SYMBOL) } {
- match message.get(message_index).unwrap() {
- true => INCREMENT.store(MARK_INCREMENT, Ordering::SeqCst),
- false => INCREMENT.store(SPACE_INCREMENT, Ordering::SeqCst),
- }
- message_index = (message_index + 1) % message.len();
- unsafe { write_volatile(&raw mut NEXT_SYMBOL, false) };
- }
- }
+ loop {}
}