Skip to content
This repository has been archived by the owner on Jul 6, 2019. It is now read-only.

Commit

Permalink
Port Timer code to ioregs
Browse files Browse the repository at this point in the history
  • Loading branch information
simias committed Oct 25, 2014
1 parent af521ce commit 8f9b316
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 123 deletions.
9 changes: 3 additions & 6 deletions apps/app_blink_tiva_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ platformtree!(
}

gpio {
PortA {
led1@1 { direction = "out"; }
}
PortF {

led2@2 { direction = "out"; }
PortF {
led1@1 { direction = "out"; }
led2@2 { direction = "out"; }
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/zinc/hal/tiva_c/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ impl Reg {
}
}
}

/// Hack to get a static 'ioreg' reference from a raw pointer to the register
/// base
pub fn get_reg_ref<T>(t: *const T) -> &'static T {
unsafe {
&*t
}
}
62 changes: 13 additions & 49 deletions src/zinc/hal/tiva_c/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use hal::pin::{GPIO, GPIODirection, In, Out, GPIOLevel, High, Low};
use hal::tiva_c::sysctl;
use hal::tiva_c::io::Reg;
use hal::tiva_c::io;

/// The pins are accessed through ports. Each port has 8 pins and are identified
/// by a letter (PortA, PortB, etc...).
Expand All @@ -20,8 +20,8 @@ pub enum PortID {

/// Structure describing a single HW pin
pub struct Pin {
/// Base address for the port containing the pin
regs: &'static reg::PORT,
/// Timer register interface
regs: &'static reg::Port,
/// Pin index in the port
index: uint,
}
Expand All @@ -45,7 +45,7 @@ impl Pin {

periph.ensure_enabled();

let pin = Pin { regs: reg::get_ref(regs), index: pin_index as uint };
let pin = Pin { regs: io::get_reg_ref(regs), index: pin_index as uint };

pin.configure(dir, function);

Expand All @@ -69,13 +69,7 @@ impl Pin {
f => {
self.regs.afsel.set_afsel(self.index, reg::PERIPHERAL);

// let pctl_offset = (self.index as uint) * 4;

// let mut reg = pctl.read32();
// reg &= !(0xf << pctl_offset);
// reg |= (f as u32) << pctl_offset;

// pctl.write32(reg);
self.regs.pctl.set_pctl(self.index, f as u32);
}
}

Expand Down Expand Up @@ -131,12 +125,10 @@ impl GPIO for Pin {

pub mod reg {
//! Pin registers definition
use util::volatile_cell::VolatileCell;
use core::ops::Drop;
use core::intrinsics::transmute;

ioregs!(PORT = {
ioregs!(Port = {
0x3FC => reg32 data {
//! Pin value
0..7 => data[8]
Expand Down Expand Up @@ -200,42 +192,14 @@ pub mod reg {

0x52C => reg32 pctl {
//! Pin function selection when afsel is set for the pin.
0..31 => pctl
0..31 => pctl[8]
}
})

pub const PORT_A: *const PORT = 0x40004000 as *const PORT;
pub const PORT_B: *const PORT = 0x40005000 as *const PORT;
pub const PORT_C: *const PORT = 0x40006000 as *const PORT;
pub const PORT_D: *const PORT = 0x40007000 as *const PORT;
pub const PORT_E: *const PORT = 0x40024000 as *const PORT;
pub const PORT_F: *const PORT = 0x40025000 as *const PORT;

/// Hack to get a reference to one of the register definitions above
pub fn get_ref<T>(t: *const T) -> &'static T {
unsafe {
&*t
}
}
pub const PORT_A: *const Port = 0x40004000 as *const Port;
pub const PORT_B: *const Port = 0x40005000 as *const Port;
pub const PORT_C: *const Port = 0x40006000 as *const Port;
pub const PORT_D: *const Port = 0x40007000 as *const Port;
pub const PORT_E: *const Port = 0x40024000 as *const Port;
pub const PORT_F: *const Port = 0x40025000 as *const Port;
}

static PORT_A_BASE: u32 = 0x40004000;
static PORT_B_BASE: u32 = 0x40005000;
static PORT_C_BASE: u32 = 0x40006000;
static PORT_D_BASE: u32 = 0x40007000;
static PORT_E_BASE: u32 = 0x40024000;
static PORT_F_BASE: u32 = 0x40025000;

// Register offsets from port base
static DATA : u32 = 0x000;
static DIR : u32 = 0x400;
static AFSEL : u32 = 0x420;
static DR2R : u32 = 0x500;
static DR4R : u32 = 0x504;
static DR8R : u32 = 0x508;
static ODR : u32 = 0x50C;
static PUR : u32 = 0x510;
static PDR : u32 = 0x514;
static SLR : u32 = 0x518;
static DEN : u32 = 0x51C;
static PCTL : u32 = 0x52C;
184 changes: 116 additions & 68 deletions src/zinc/hal/tiva_c/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use hal::tiva_c::sysctl;
use hal::tiva_c::io::Reg;
use hal::timer;
use hal::tiva_c::io;

/// There are 6 standard 16/32bit timers and 6 "wide" 32/64bit timers
#[allow(missing_doc)]
Expand Down Expand Up @@ -43,8 +44,8 @@ pub enum Mode {

/// Structure describing a single timer counter (both 16/32bit and 32/64bit)
pub struct Timer {
/// Base address for this counter
base : u32,
/// Timer register interface
regs : &'static reg::Timer,
/// True if the counter is wide 32/64bit
wide : bool,
/// Current timer mode
Expand All @@ -56,24 +57,24 @@ impl Timer {
pub fn new(id: TimerId,
mode: Mode,
prescale: u16) -> Timer {
let (periph, base, wide) = match id {
Timer0 => (sysctl::periph::timer::TIMER_0, TIMER_0_BASE, false),
Timer1 => (sysctl::periph::timer::TIMER_1, TIMER_1_BASE, false),
Timer2 => (sysctl::periph::timer::TIMER_2, TIMER_2_BASE, false),
Timer3 => (sysctl::periph::timer::TIMER_3, TIMER_3_BASE, false),
Timer4 => (sysctl::periph::timer::TIMER_4, TIMER_4_BASE, false),
Timer5 => (sysctl::periph::timer::TIMER_5, TIMER_5_BASE, false),
TimerW0 => (sysctl::periph::timer::TIMER_W_0, TIMER_W_0_BASE, true),
TimerW1 => (sysctl::periph::timer::TIMER_W_1, TIMER_W_1_BASE, true),
TimerW2 => (sysctl::periph::timer::TIMER_W_2, TIMER_W_2_BASE, true),
TimerW3 => (sysctl::periph::timer::TIMER_W_3, TIMER_W_3_BASE, true),
TimerW4 => (sysctl::periph::timer::TIMER_W_4, TIMER_W_4_BASE, true),
TimerW5 => (sysctl::periph::timer::TIMER_W_5, TIMER_W_5_BASE, true),
let (periph, regs, wide) = match id {
Timer0 => (sysctl::periph::timer::TIMER_0, reg::TIMER_0, false),
Timer1 => (sysctl::periph::timer::TIMER_1, reg::TIMER_1, false),
Timer2 => (sysctl::periph::timer::TIMER_2, reg::TIMER_2, false),
Timer3 => (sysctl::periph::timer::TIMER_3, reg::TIMER_3, false),
Timer4 => (sysctl::periph::timer::TIMER_4, reg::TIMER_4, false),
Timer5 => (sysctl::periph::timer::TIMER_5, reg::TIMER_5, false),
TimerW0 => (sysctl::periph::timer::TIMER_W_0, reg::TIMER_W_0, true),
TimerW1 => (sysctl::periph::timer::TIMER_W_1, reg::TIMER_W_1, true),
TimerW2 => (sysctl::periph::timer::TIMER_W_2, reg::TIMER_W_2, true),
TimerW3 => (sysctl::periph::timer::TIMER_W_3, reg::TIMER_W_3, true),
TimerW4 => (sysctl::periph::timer::TIMER_W_4, reg::TIMER_W_4, true),
TimerW5 => (sysctl::periph::timer::TIMER_W_5, reg::TIMER_W_5, true),
};

periph.ensure_enabled();

let timer = Timer { base: base, wide: wide, mode: mode};
let timer = Timer { regs: io::get_reg_ref(regs), wide: wide, mode: mode};

timer.configure(prescale);

Expand All @@ -84,77 +85,124 @@ impl Timer {
/// XXX Only Periodic and OneShot modes are implemented so far
pub fn configure(&self, prescale: u16) {

let ctl = Reg::new(self.base + CTL);

// Make sure the timer is disabled before making changes.
ctl.bitband_write(0, false);

let cfg = Reg::new(self.base + CFG);
self.regs.ctl.set_taen(false);

// Configure the timer as half-width so that we can use the prescaler
cfg.write32(0x4);

let amr = Reg::new(self.base + AMR);

// Configure TAMR
let mut amr_val = match self.mode {
OneShot => 0x1,
Periodic => 0x2,
_ => { return; /* Not implemented! */ },
};

// We need to count down in order for the prescaler to work as a
// prescaler. If we count up it becomes a timer extension (i.e. it becomes
// the MSBs of the counter).
amr_val |= 0 << 4;

amr.write32(amr_val);
self.regs.cfg.set_cfg(reg::HalfWidth);

self.regs.amr
.set_mr(match self.mode {
OneShot => reg::OneShot,
Periodic => reg::Periodic,
_ => { return; /* Not implemented! */ },
})
// We need to count down in order for the prescaler to work as a
// prescaler. If we count up it becomes a timer extension (i.e. it becomes
// the MSBs of the counter).
.set_cdir(reg::Down);

// Set maximum timeout value to overflow as late as possible
let tailr = Reg::new(self.base + TAILR);

tailr.write32(0xffffffff);
self.regs.tailr.set_tailr(0xffffffff);

// Set prescale value
let apr = Reg::new(self.base + APR);
if !self.wide && prescale > 0xffff {
return; /* prescale is too wide for this timer */
}

apr.write32(prescale as u32);
self.regs.apr.set_psr(prescale as u32);

// Timer is now configured, we can enable it
ctl.bitband_write(0, true);
self.regs.ctl.set_taen(true);
}
}

impl timer::Timer for Timer {
/// Retrieve the current timer value
#[inline(always)]
fn get_counter(&self) -> u32 {
let tav = Reg::new(self.base + TAV);

// We count down, however the trait code expects that the counter increases,
// so we just complement the value to get an increasing counter.
!tav.read32()
!self.regs.tav.v()
}
}

static TIMER_0_BASE: u32 = 0x40030000;
static TIMER_1_BASE: u32 = 0x40031000;
static TIMER_2_BASE: u32 = 0x40032000;
static TIMER_3_BASE: u32 = 0x40033000;
static TIMER_4_BASE: u32 = 0x40034000;
static TIMER_5_BASE: u32 = 0x40035000;

static TIMER_W_0_BASE: u32 = 0x40036000;
static TIMER_W_1_BASE: u32 = 0x40037000;
static TIMER_W_2_BASE: u32 = 0x4003C000;
static TIMER_W_3_BASE: u32 = 0x4003D000;
static TIMER_W_4_BASE: u32 = 0x4003E000;
static TIMER_W_5_BASE: u32 = 0x4003F000;

// Register offsets from timer base
static CFG : u32 = 0x000;
static AMR : u32 = 0x004;
static CTL : u32 = 0x00C;
static TAILR : u32 = 0x028;
static APR : u32 = 0x038;
static TAV : u32 = 0x050;
pub mod reg {
//! Timer registers definition
use util::volatile_cell::VolatileCell;
use core::ops::Drop;

ioregs!(Timer = {
0x00 => reg32 cfg {
//! Timer configuration
0..2 => cfg {
0 => FullWidth,
1 => Rtc,
4 => HalfWidth,
},
}
0x04 => reg32 amr {
//! Timer A mode
0..1 => mr { //! mode
1 => OneShot,
2 => Periodic,
3 => Capture,
},
2 => cmr, //= capture mode
3 => ams, //= alternate mode select
4 => cdir { //! Count direction
0 => Down,
1 => Up,
},
5 => mie, //= match interrupt enable
6 => wot, //= wait on trigger
7 => snaps, //= snap-shot mode
8 => ild, //= interval load write
9 => pwmie, //= PWM interrupt enable
10 => rsu, //= match register update
11 => plo, //= PWM legacy operation
}
0x0C => reg32 ctl {
0 => taen, //= Timer A enable
1 => tastall, //= Timer A stall enable
2..3 => taevent { //! Timer A event mode
0 => PosEdge,
1 => NegEdge,
3 => AnyEdge,
},
4 => rtcen, //= RTC stall enable
5 => taote, //= Timer B output trigger enable
6 => tapwml, //= Timer B PWM output level

8 => tben, //= Timer B enable
9 => tbstall, //= Timer B stall enable
10..11 => tbevent, //= Timer B event mode
13 => tbote, //= Timer B output trigger enable
14 => tbpwml, //= Timer B PWM output level
}
0x28 => reg32 tailr {
0..31 => tailr, //= Timer A interval load
}
0x38 => reg32 apr {
0..15 => psr, //= Timer A prescale value
//= Only 8bit for 16/32bit timers
}
0x50 => reg32 tav {
0..31 => v, // Timer A counter value
}
})

pub const TIMER_0: *const Timer = 0x40030000 as *const Timer;
pub const TIMER_1: *const Timer = 0x40031000 as *const Timer;
pub const TIMER_2: *const Timer = 0x40032000 as *const Timer;
pub const TIMER_3: *const Timer = 0x40033000 as *const Timer;
pub const TIMER_4: *const Timer = 0x40034000 as *const Timer;
pub const TIMER_5: *const Timer = 0x40035000 as *const Timer;

pub const TIMER_W_0: *const Timer = 0x40036000 as *const Timer;
pub const TIMER_W_1: *const Timer = 0x40037000 as *const Timer;
pub const TIMER_W_2: *const Timer = 0x4003C000 as *const Timer;
pub const TIMER_W_3: *const Timer = 0x4003D000 as *const Timer;
pub const TIMER_W_4: *const Timer = 0x4003E000 as *const Timer;
pub const TIMER_W_5: *const Timer = 0x4003F000 as *const Timer;
}

0 comments on commit 8f9b316

Please sign in to comment.