Skip to content
Permalink
feature/phasor
Go to file
 
 
Cannot retrieve contributors at this time
152 lines (115 sloc) 3.7 KB
// asf
#include "compiler.h"
#include "print_funcs.h"
#include "tc.h"
// libavr32
#include "conf_tc_irq.h"
#include "phasor.h"
#include "util.h"
static phasor_callback_t *_phasor_cb;
volatile static u16 _now;
volatile static bool _reset;
static u8 _ticks;
// -------------------------------------------------------------------------------
// functions (internal)
// -------------------------------------------------------------------------------
// initialize second tc channel
static void init_phasor_tc(void) {
volatile avr32_tc_t *tc = APP_TC;
// waveform options
static const tc_waveform_opt_t waveform_opt = {
.channel = PHASOR_TC_CHANNEL, // channel
.bswtrg = TC_EVT_EFFECT_NOOP, // software trigger action on TIOB
.beevt = TC_EVT_EFFECT_NOOP, // external event action
.bcpc = TC_EVT_EFFECT_NOOP, // rc compare action
.bcpb = TC_EVT_EFFECT_NOOP, // rb compare
.aswtrg = TC_EVT_EFFECT_NOOP, // soft trig on TIOA
.aeevt = TC_EVT_EFFECT_NOOP, // etc
.acpc = TC_EVT_EFFECT_NOOP,
.acpa = TC_EVT_EFFECT_NOOP,
// Waveform selection: Up mode with automatic trigger(reset) on RC compare.
.wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,
.enetrg = false, // external event trig
.eevt = 0, // extern event select
.eevtedg = TC_SEL_NO_EDGE, // extern event edge
.cpcdis = false, // counter disable when rc compare
.cpcstop = false, // counter stopped when rc compare
.burst = false,
.clki = false,
// Internal source clock 5, connected to fPBA / 128.
.tcclks = TC_CLOCK_SOURCE_TC5
};
// Options for enabling TC interrupts
static const tc_interrupt_t tc_interrupt = {
.etrgs = 0,
.ldrbs = 0,
.ldras = 0,
.cpcs = 1, // enable interrupt on RC compare alone
.cpbs = 0,
.cpas = 0,
.lovrs = 0,
.covfs = 0
};
// Initialize the timer/counter.
tc_init_waveform(tc, &waveform_opt);
// set a default rate
tc_write_rc(tc, PHASOR_TC_CHANNEL, (FPBA_HZ / 25600));
// configure the timer interrupt
tc_configure_interrupts(tc, PHASOR_TC_CHANNEL, &tc_interrupt);
}
__attribute__((__interrupt__))
static void irq_phasor(void) {
(*_phasor_cb)(_now, _reset);
if (_now == 0 && _reset) {
_reset = false;
}
_now++;
if (_now >= _ticks) {
_now = 0;
}
// clear interrupt flag by reading timer SR
tc_read_sr(APP_TC, PHASOR_TC_CHANNEL);
}
static void null_cb(u8 now, bool reset) {
}
// -----------------------------------------------------------------------------
// functions (external)
// -----------------------------------------------------------------------------
void init_phasor(void) {
phasor_set_callback(NULL);
init_phasor_tc();
INTC_register_interrupt(&irq_phasor, PHASOR_TC_IRQ, UI_IRQ_PRIORITY);
}
u16 phasor_setup(u16 hz, u8 ticks) {
_ticks = ticks < 1 ? 1 : ticks;
return phasor_set_frequency(hz);
}
int phasor_start(void) {
_now = 0;
_reset = false;
return tc_start(APP_TC, PHASOR_TC_CHANNEL);
}
int phasor_stop(void) {
return tc_stop(APP_TC, PHASOR_TC_CHANNEL);
}
void phasor_reset(void) {
cpu_irq_disable_level(APP_TC_IRQ_PRIORITY);
_now = 0;
_reset = true;
cpu_irq_enable_level(APP_TC_IRQ_PRIORITY);
}
u16 phasor_set_frequency(u16 hz) {
u16 rate, rc;
// limit range, 8Hz is about as slow as possible with a 16 bit
// counter; 4kHz is just a safety, depending on what happens in the
// phasor callback 4kHz might be too fast.
rate = uclip(hz, 8, 4000);
rc = FPBA_HZ / (128 * rate);
//print_dbg("\r\n phasor rc: ");
//print_dbg_ulong(rc);
tc_write_rc(APP_TC, PHASOR_TC_CHANNEL, rc);
return rate;
}
void phasor_set_callback(phasor_callback_t *cb) {
_phasor_cb = cb == NULL ? &null_cb : cb;
}