diff --git a/apps/app_blink_tiva_c.rs b/apps/app_blink_tiva_c.rs index 37029455..61e45cb4 100644 --- a/apps/app_blink_tiva_c.rs +++ b/apps/app_blink_tiva_c.rs @@ -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"; } } } diff --git a/src/zinc/hal/tiva_c/io.rs b/src/zinc/hal/tiva_c/io.rs index 4588b007..cda47e0f 100644 --- a/src/zinc/hal/tiva_c/io.rs +++ b/src/zinc/hal/tiva_c/io.rs @@ -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: *const T) -> &'static T { + unsafe { + &*t + } +} diff --git a/src/zinc/hal/tiva_c/pin.rs b/src/zinc/hal/tiva_c/pin.rs index 5988aa42..6428beb7 100644 --- a/src/zinc/hal/tiva_c/pin.rs +++ b/src/zinc/hal/tiva_c/pin.rs @@ -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...). @@ -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, } @@ -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); @@ -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); } } @@ -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] @@ -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: *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; diff --git a/src/zinc/hal/tiva_c/timer.rs b/src/zinc/hal/tiva_c/timer.rs index 47016dc7..623aa431 100644 --- a/src/zinc/hal/tiva_c/timer.rs +++ b/src/zinc/hal/tiva_c/timer.rs @@ -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)] @@ -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 @@ -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); @@ -84,44 +85,35 @@ 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); } } @@ -129,32 +121,88 @@ 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; +}