arduino-tnc

git clone https://git.bradleygannon.com/arduino-tnc.git
Log | Files | Refs

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:
Msrc/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 {} }