diff options
-rw-r--r-- | src/ds3231.rs | 66 | ||||
-rw-r--r-- | src/main.rs | 544 | ||||
-rw-r--r-- | src/tim.rs | 16 |
3 files changed, 498 insertions, 128 deletions
diff --git a/src/ds3231.rs b/src/ds3231.rs index bd23fdd..fd96fed 100644 --- a/src/ds3231.rs +++ b/src/ds3231.rs @@ -2,6 +2,7 @@ use i2c::{I2C, TransDir, DutyType}; const DS3231_ADDR: u8 = 0b1101000; const DS3231_REG_SEC: u8 = 0x00; +const DS3231_REG_DATE: u8 = 0x04; const DS3231_REG_CTL: u8 = 0x0e; const DS3231_REG_TEMP: u8 = 0x11; @@ -24,15 +25,16 @@ pub struct Temp { pub quarter: u8 } -impl<'a> DS3231<'a> { - fn bcd2dec(bcd: u8) -> u8 { - (bcd >> 4) * 10 + (bcd & 0x0f) - } +fn bcd2dec(bcd: u8) -> u8 { + (bcd >> 4) * 10 + (bcd & 0x0f) +} + +fn dec2bcd(dec: u8) -> u8 { + ((dec / 10) << 4) | (dec % 10) +} - fn dec2bcd(dec: u8) -> u8 { - ((dec / 10) << 4) | (dec % 10) - } +impl<'a> DS3231<'a> { fn read_register(&self, start: u8, size: usize, buf: &mut [u8]){ let &DS3231(ref i2c) = self; i2c.conf_ack(true); /* enable ack */ @@ -69,16 +71,16 @@ impl<'a> DS3231<'a> { let hour = if am_enabled { (buf[2] & 0x0f) + ((buf[2] >> 4) & 1) * 10 } else { - DS3231::bcd2dec(buf[2]) + bcd2dec(buf[2]) }; let am = if am_enabled {(buf[2] >> 5) & 1 == 0} else {hour < 12}; - Date{second: DS3231::bcd2dec(buf[0]), - minute: DS3231::bcd2dec(buf[1]), + Date{second: bcd2dec(buf[0]), + minute: bcd2dec(buf[1]), hour, - day: DS3231::bcd2dec(buf[3]), - date: DS3231::bcd2dec(buf[4]), - month: DS3231::bcd2dec(buf[5]), - year: DS3231::bcd2dec(buf[6]), + day: bcd2dec(buf[3]), + date: bcd2dec(buf[4]), + month: bcd2dec(buf[5]), + year: bcd2dec(buf[6]), am, am_enabled} } @@ -88,16 +90,36 @@ impl<'a> DS3231<'a> { (1 << 6) | ((if date.am {0} else {1}) << 5) | ((date.hour / 10) << 4) | (date.hour % 10) } else { - DS3231::dec2bcd(date.hour) + dec2bcd(date.hour) }; - let buf: [u8; 7] = [DS3231::dec2bcd(date.second), - DS3231::dec2bcd(date.minute), + let buf: [u8; 7] = [dec2bcd(date.second), + dec2bcd(date.minute), hour, - DS3231::dec2bcd(date.day), - DS3231::dec2bcd(date.date), - DS3231::dec2bcd(date.month), - DS3231::dec2bcd(date.year)]; - self.write_register(DS3231_REG_SEC, 7, &buf); + dec2bcd(date.day), + dec2bcd(date.date), + dec2bcd(date.month), + dec2bcd(date.year)]; + self.write_register(DS3231_REG_SEC, buf.len(), &buf); + } + + pub fn write_time(&self, date: &Date) { + let hour = if date.am_enabled { + (1 << 6) | ((if date.am {0} else {1}) << 5) | + ((date.hour / 10) << 4) | (date.hour % 10) + } else { + dec2bcd(date.hour) + }; + let buf: [u8; 3] = [dec2bcd(date.second), + dec2bcd(date.minute), + hour]; + self.write_register(DS3231_REG_SEC, buf.len(), &buf); + } + + pub fn write_date(&self, date: &Date) { + let buf: [u8; 3] = [dec2bcd(date.date), + dec2bcd(date.month), + dec2bcd(date.year)]; + self.write_register(DS3231_REG_DATE, buf.len(), &buf); } pub fn write_control(&self) { diff --git a/src/main.rs b/src/main.rs index 9df73cf..673dd01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(asm)] +#![feature(const_fn)] #[macro_use] extern crate stm32f103xx; extern crate cortex_m; @@ -7,6 +8,7 @@ extern crate cortex_m; use stm32f103xx::{GPIOA, GPIOB, RCC, SYST, I2C1, EXTI, NVIC, Interrupt, AFIO, Peripherals}; use stm32f103xx::{gpioa}; use cortex_m::peripheral::SystClkSource; +use core::cell::{Cell, RefCell}; mod mutex; mod i2c; @@ -15,136 +17,502 @@ mod at24c; mod tim; const SYNC_PERIOD: u8 = 10; +const BLINK_PERIOD: u32 = 500; + +fn digits2bcds(digs: &[u8]) -> u32 { + let mut res: u32 = 0; + for d in digs.iter().rev() { + res = (res << 4) | (*d as u32); + } + res +} struct ShiftRegister<'a> { gpioa: &'a gpioa::RegisterBlock, width: u8, } -struct Clock { +#[derive(Copy, Clone)] +struct Time { sec: u8, min: u8, hr: u8, - reset: u8 } struct GlobalState { disp: Option<ShiftRegister<'static>>, i2c: Option<i2c::I2C<'static>>, - tim: Option<tim::Timer<'static>>, + btn1: Option<Button<'static>>, + //tim: Option<tim::Timer<'static>>, i2c_inited: bool, - buff: [u8; 6], - time: Clock, + sync_cnt: u8, + buff: RefCell<[u8; 6]>, + blinky: RefCell<[bool; 6]>, + blink_state: Cell<bool>, perip: Option<Peripherals<'static>>, - bs: bool + disp_on: bool, + pidx: usize, + panels: [&'static Panel; 2], +} + +struct Button<'a> { + state: Cell<bool>, + long: Cell<bool>, + timer: tim::Timer<'a> +} + +enum ButtonResult { + FALSE_ALARM, + SHORT_PRESS, + LONG_PRSSS +} + +impl<'a> Button<'a> { + fn new(timer: tim::Timer<'a>, thres: u32) -> Self { + /* in milliseconds */ + timer.init(thres * (8_000_000 / 1000)); + Button {state: Cell::new(false), + long: Cell::new(false), + timer} + } + + fn press(&self) { + if !self.state.get() { + self.state.set(true); + self.long.set(false); + self.timer.reset(); + self.timer.go(); + } + } + + fn release(&self) -> ButtonResult { + if self.state.get() { + self.timer.stop(); + self.state.set(false); + if self.long.get() { ButtonResult::LONG_PRSSS } + else { ButtonResult::SHORT_PRESS } + } else { ButtonResult::FALSE_ALARM } + } + + fn timeout(&self) { + self.timer.stop(); + self.long.set(true); + } +} + +trait Panel { + fn btn1_short(&self) -> bool {false} + fn btn1_long(&self) -> bool {false} + fn btn2_short(&self) -> bool {false} + fn btn2_long(&self) -> bool {false} + fn update_output(&self); +} + +#[derive(PartialEq, Clone, Copy)] +enum TimePanelState { + VIEW, + EDIT_HR, + EDIT_MIN, + EDIT_SEC +} + +struct TimePanel<'a> { + gs: &'a GlobalState, + state: Cell<TimePanelState>, + time: RefCell<Time>, + tmp: RefCell<Time> +} + +impl<'a> Panel for TimePanel<'a> { + fn btn1_short(&self) -> bool { + use TimePanelState::*; + { + let mut tmp = self.tmp.borrow_mut(); + match self.state.get() { + VIEW => return false, /* yield to the next panel */ + EDIT_HR => { + tmp.hr += 1; + if tmp.hr == 24 { tmp.hr = 0 }; + }, + EDIT_MIN => { + tmp.min += 1; + if tmp.min == 60 { tmp.min = 0 }; + }, + EDIT_SEC => { + tmp.sec += 1; + if tmp.sec == 60 { tmp.sec = 0 }; + }, + }; + } + self.update_output(); + true + } + + fn btn2_short(&self) -> bool { + use TimePanelState::*; + let s = match self.state.get() { + VIEW => { + let mut tmp = self.tmp.borrow_mut(); + let time = self.time.borrow(); + tmp.hr = time.hr; + tmp.min = time.min; + tmp.sec = time.sec; + EDIT_HR + }, + EDIT_HR => EDIT_MIN, + EDIT_MIN => EDIT_SEC, + EDIT_SEC => { + let tmp = self.tmp.borrow(); + ds3231::DS3231(self.gs.i2c.as_ref().unwrap()) + .write_time(&ds3231::Date{second: tmp.sec, + minute: tmp.min, + hour: tmp.hr, + day: 0, + date: 0, + month: 0, + year: 0, + am: false, + am_enabled: false}); + *self.time.borrow_mut() = *tmp; + VIEW + } + }; + self.state.set(s); + self.update_output(); + self.state.get() == VIEW + } + + fn update_output(&self) { + use TimePanelState::*; + let s = self.state.get(); + self.gs.update_blinky(match s { + VIEW => [false; 6], + EDIT_HR => [false, false, false, false, true, true], + EDIT_MIN => [false, false, true, true, false, false], + EDIT_SEC => [true, true, false, false, false, false] + }); + let time = self.time.borrow(); + let tmp = self.tmp.borrow(); + match s { + VIEW => self.gs.render3(time.hr, time.min, time.sec), + _ => self.gs.render3(tmp.hr, tmp.min, tmp.sec) + }; + self.gs.display(); + } +} + +impl<'a> TimePanel<'a> { + fn update_clock(&self, clk: Option<Time>) { + let mut time = self.time.borrow_mut(); + match clk { + Some(clk) => *time = clk, + None => time.tick() + } + if self.gs.pidx == 0 && self.state.get() == TimePanelState::VIEW { + self.gs.render3(time.hr, time.min, time.sec); + self.gs.display(); + } + } +} + +#[derive(Clone, Copy)] +struct Date { + yr: u8, + mon: u8, + day: u8 +} + +#[derive(PartialEq, Clone, Copy)] +enum DatePanelState { + VIEW, + EDIT_YR, + EDIT_MON, + EDIT_DAY +} + +struct DatePanel<'a> { + gs: &'a GlobalState, + state: Cell<DatePanelState>, + date: RefCell<Date>, + tmp: RefCell<Date> +} + +impl<'a> Panel for DatePanel<'a> { + fn btn1_short(&self) -> bool { + use DatePanelState::*; + { + let mut tmp = self.tmp.borrow_mut(); + match self.state.get() { + VIEW => return false, /* yield to the next panel */ + EDIT_YR => { + if tmp.yr == 255 { tmp.yr = 0 } + else { tmp.yr += 1 }; + }, + EDIT_MON => { + tmp.mon += 1; + if tmp.mon == 13 { tmp.mon = 1 }; + }, + EDIT_DAY => { + tmp.day += 1; + if tmp.day == 32 { tmp.day = 1 }; + }, + }; + } + self.update_output(); + true + } + + fn btn2_short(&self) -> bool { + use DatePanelState::*; + let s = match self.state.get() { + VIEW => { + let date = self.date.borrow(); + let mut tmp = self.tmp.borrow_mut(); + tmp.yr = date.yr; + tmp.mon = date.mon; + tmp.day = date.day; + EDIT_YR + }, + EDIT_YR => EDIT_MON, + EDIT_MON => EDIT_DAY, + EDIT_DAY => { + let tmp = self.tmp.borrow(); + ds3231::DS3231(self.gs.i2c.as_ref().unwrap()) + .write_date(&ds3231::Date{second: 0, + minute: 0, + hour: 0, + day: 0, + date: tmp.day, + month: tmp.mon, + year: tmp.yr, + am: false, + am_enabled: false}); + *self.date.borrow_mut() = *tmp; + VIEW + } + }; + self.state.set(s); + self.update_output(); + self.state.get() == VIEW + } + + fn update_output(&self) { + use DatePanelState::*; + let s = self.state.get(); + self.gs.update_blinky(match s{ + VIEW => [false; 6], + EDIT_YR => [false, false, false, false, true, true], + EDIT_MON => [false, false, true, true, false, false], + EDIT_DAY => [true, true, false, false, false, false] + }); + let date = self.date.borrow(); + let tmp = self.tmp.borrow(); + match s { + VIEW => self.gs.render3(date.yr, date.mon, date.day), + _ => self.gs.render3(tmp.yr, tmp.mon, tmp.day) + }; + self.gs.display(); + } +} + +impl<'a> DatePanel<'a> { + fn update_clock(&self, d: Option<Date>) { + let mut date = self.date.borrow_mut(); + match d { + Some(d) => *date = d, + None => () + } + if self.gs.pidx == 1 && self.state.get() == DatePanelState::VIEW { + self.gs.render3(date.yr, date.mon, date.day); + self.gs.display(); + } + } } +static mut TPANEL: TimePanel = TimePanel{state: Cell::new(TimePanelState::VIEW), + tmp: RefCell::new(Time{sec: 0, min: 0, hr: 0}), + time: RefCell::new(Time{sec: 0, min: 0, hr: 0}), + gs: unsafe{&GS}}; +static mut DPANEL: DatePanel = DatePanel{state: Cell::new(DatePanelState::VIEW), + tmp: RefCell::new(Date{yr: 0, mon: 1, day: 1}), + date: RefCell::new(Date{yr: 0, mon: 1, day: 1}), + gs: unsafe{&GS}}; + static mut GS: GlobalState = GlobalState{disp: None, i2c: None, - tim: None, + sync_cnt: 0, + btn1: None, i2c_inited: false, - buff: [0; 6], - time: Clock{sec: 0, min: 0, hr: 0, reset: 0}, + buff: RefCell::new([0; 6]), perip: None, - bs: false}; + disp_on: true, + blinky: RefCell::new([false; 6]), + blink_state: Cell::new(false), + pidx: 0, + panels: unsafe {[&TPANEL, &DPANEL]} + }; fn get_gs() -> &'static mut GlobalState { unsafe {&mut GS} } -fn digits2bcds(digs: &[u8]) -> u32 { - let mut res: u32 = 0; - for d in digs.iter().rev() { - res = (res << 4) | (*d as u32); +impl GlobalState { + + fn render3(&self, n1: u8, n2: u8, n3: u8) { + let mut buff = self.buff.borrow_mut(); + buff[1] = n3 / 10; buff[0] = n3 - buff[1] * 10; + buff[3] = n2 / 10; buff[2] = n2 - buff[3] * 10; + buff[5] = n1 / 10; buff[4] = n1 - buff[5] * 10; } - res -} -fn display() { - let gs = get_gs(); - gs.disp.as_ref().unwrap().output_bits(digits2bcds(&gs.buff[..])); -} + fn display(&self) { + let mut buff = *self.buff.borrow(); + let b = self.blink_state.get(); + let bs = self.blinky.borrow(); + if self.disp_on { + for (i, v) in buff.iter_mut().enumerate() { + if b && bs[i] { *v = 0xf; } + } + } else { + for i in buff.iter_mut() { *i = 0xf; } + } + self.disp.as_ref().unwrap().output_bits(digits2bcds(&buff[..])); + } -fn digits_countup() { - let gs = get_gs(); - let mut digits = &mut gs.buff; - gs.disp.as_ref().unwrap().output_bits(digits2bcds(&digits[..])); - let mut i = 0; - let mut carry = 1; - while carry > 0 && i < digits.len() { - digits[i] += carry; - carry = if digits[i] > 9 {digits[i] = 0; 1} else {0}; - i += 1; + fn update_blinky(&self, ns: [bool; 6]) { + let tim4 = self.perip.as_ref().unwrap().TIM4; + let timer = tim::Timer(tim4); + let en = timer.is_enabled(); + let flag = ns.iter().all(|x| !x); /* if nothing is blinking */ + *self.blinky.borrow_mut() = ns; + if en && flag { + self.blink_state.set(false); + timer.stop(); + } else if !en && !flag { + self.blink_state.set(false); + timer.reset(); + timer.go(); + } + } + + fn digits_countup(&self) { + self.display(); + let mut buff = *self.buff.borrow(); + let mut i = 0; + let mut carry = 1; + while carry > 0 && i < buff.len() { + buff[i] += carry; + carry = if buff[i] > 9 {buff[i] = 0; 1} else {0}; + i += 1; + } } -} -fn render_clock() { - let gs = get_gs(); - let mut digits = &mut gs.buff; - let time = &gs.time; - if gs.bs { - digits[1] = time.sec / 10; digits[0] = time.sec - digits[1] * 10; - digits[3] = time.min / 10; digits[2] = time.min - digits[3] * 10; - digits[5] = time.hr / 10; digits[4] = time.hr - digits[5] * 10; - } else { - for i in digits { - *i = 0xf; + + fn update_clock(&mut self) { + let mut clk = None; + let mut d = None; + if self.sync_cnt == 0 { + let rtc = ds3231::DS3231(self.i2c.as_ref().unwrap()); + let ds3231::Date{second: sec, + minute: min, + hour: hr, + date: day, + month: mon, + year: yr, ..} = rtc.read_fulldate(); + self.sync_cnt = SYNC_PERIOD; + clk = Some(Time{sec, min, hr}); + d = Some(Date{yr, mon, day}); + } else { + self.sync_cnt -= 1; + } + unsafe { + TPANEL.update_clock(clk); + DPANEL.update_clock(d); } } -} -fn update_clock() { - let gs = get_gs(); - let p = gs.perip.as_ref().unwrap(); - let rtc = ds3231::DS3231(gs.i2c.as_ref().unwrap()); - if !gs.i2c_inited {return} - if !gs.time.tick() { - let ds3231::Date{second: sec, - minute: min, - hour: hr, ..} = rtc.read_fulldate(); - gs.time = Clock{sec, min, hr, - reset: SYNC_PERIOD}; + + fn set_time(&mut self) { + let rtc = ds3231::DS3231(self.i2c.as_ref().unwrap()); + rtc.write_fulldate(&ds3231::Date{second: 30, + minute: 23, + hour: 18, + day: 2, + date: 10, + month: 10, + year: 17, + am: false, + am_enabled: false}); + /* + let rom = ROM.as_ref().unwrap(); + let mut buf: [u8; 64] = [23; 64]; + rom.write(23, 64, &buf); + let mut buf2: [u8; 80] = [0; 80]; + rom.read(20, 80, &mut buf2); + */ } - render_clock(); - display(); } fn systick_handler() { // digits_countup(); - update_clock(); + let gs = get_gs(); + if !gs.i2c_inited {return} + gs.update_clock(); } fn exti3_handler() { let gs = get_gs(); + let btn1 = gs.btn1.as_ref().unwrap(); let p = gs.perip.as_ref().unwrap(); p.EXTI.pr.write(|w| w.pr3().set_bit()); let x = p.GPIOA.idr.read().idr3().bit(); - if !x && !gs.bs { - gs.bs = true; - } else if x && gs.bs { - gs.bs = false; + if !x { + btn1.press(); + } else { + let gs = get_gs(); + match btn1.release() { + ButtonResult::FALSE_ALARM => (), + ButtonResult::SHORT_PRESS => { + if !gs.panels[gs.pidx].btn1_short() { + gs.pidx += 1; + if gs.pidx == gs.panels.len() { + gs.pidx = 0; + } + gs.panels[gs.pidx].update_output(); + } + }, + ButtonResult::LONG_PRSSS => { gs.panels[gs.pidx].btn2_short(); } + } + gs.display(); } - render_clock(); - display(); } fn tim2_handler() { let gs = get_gs(); let p = gs.perip.as_ref().unwrap(); p.TIM2.sr.modify(|_, w| w.uif().clear()); - gs.bs = !gs.bs; - render_clock(); - display(); + gs.btn1.as_ref().unwrap().timeout(); +} + +fn tim4_handler() { + let gs = get_gs(); + { + let p = gs.perip.as_ref().unwrap(); + p.TIM4.sr.modify(|_, w| w.uif().clear()); + } + gs.blink_state.set(!gs.blink_state.get()); + gs.display(); } exception!(SYS_TICK, systick_handler); interrupt!(EXTI3, exti3_handler); interrupt!(TIM2, tim2_handler); +interrupt!(TIM4, tim4_handler); impl<'a> ShiftRegister<'a> { fn new(gpioa: &'a gpioa::RegisterBlock, - width: u8) -> ShiftRegister<'a> { + width: u8) -> Self { let this = ShiftRegister{gpioa, width}; this } @@ -168,12 +536,8 @@ impl<'a> ShiftRegister<'a> { } } -impl Clock { - fn tick(&mut self) -> bool { - if self.reset == 0 { - return false; - } - +impl Time { + fn tick(&mut self) { self.sec += 1; if self.sec == 60 { self.min += 1; @@ -188,8 +552,6 @@ impl Clock { if self.hr == 24 { self.hr = 0; } - self.reset -= 1; - true } } @@ -209,7 +571,8 @@ fn init() { p.RCC.apb2enr.modify(|_, w| w.iopaen().enabled() .iopben().enabled() .afioen().enabled()); - p.RCC.apb1enr.modify(|_, w| w.tim2en().enabled()); + p.RCC.apb1enr.modify(|_, w| w.tim2en().enabled() + .tim4en().enabled()); /* GPIO */ /* enable PA0-2 for manipulating shift register */ @@ -235,6 +598,7 @@ fn init() { p.AFIO.exticr1.write(|w| unsafe { w.exti3().bits(0b0000) }); p.NVIC.enable(Interrupt::EXTI3); p.NVIC.enable(Interrupt::TIM2); + p.NVIC.enable(Interrupt::TIM4); p.EXTI.imr.write(|w| w.mr3().set_bit()); p.EXTI.rtsr.write(|w| w.tr3().set_bit()); p.EXTI.ftsr.write(|w| w.tr3().set_bit()); @@ -242,39 +606,18 @@ fn init() { gs.i2c = Some(i2c::I2C(p.I2C1)); gs.disp = Some(ShiftRegister::new(p.GPIOA, 24)); - gs.tim = Some(tim::Timer(p.TIM2)); gs.i2c.as_ref().unwrap().init(p.RCC, 0x01, 400_000, i2c::DutyType::DUTY1, true); - gs.tim.as_ref().unwrap().init(16_000_000); - gs.tim.as_ref().unwrap().go(); //i2c.init(0x01, 100_000, i2c::DutyType::DUTY1, false); gs.disp.as_ref().unwrap().output_bits(0); gs.i2c_inited = true; -} -fn set_clock() { - let gs = get_gs(); - let p = gs.perip.as_ref().unwrap(); - let rtc = ds3231::DS3231(gs.i2c.as_ref().unwrap()); - rtc.write_fulldate(&ds3231::Date{second: 30, - minute: 23, - hour: 18, - day: 2, - date: 10, - month: 10, - year: 17, - am: false, - am_enabled: false}); - /* - let rom = ROM.as_ref().unwrap(); - let mut buf: [u8; 64] = [23; 64]; - rom.write(23, 64, &buf); - let mut buf2: [u8; 80] = [0; 80]; - rom.read(20, 80, &mut buf2); - */ + gs.btn1 = Some(Button::new(tim::Timer(p.TIM2), 300)); + tim::Timer(p.TIM4).init(BLINK_PERIOD * (8_000_000 / 1000)); } fn main() { init(); + get_gs().update_clock(); //set_clock(); /* let x = mutex::Mutex::new(42); @@ -284,5 +627,4 @@ fn main() { let w = z; } */ - update_clock(); } @@ -1,4 +1,4 @@ -use stm32f103xx::{tim2, TIM2}; +use stm32f103xx::{tim1, tim2, TIM2}; pub struct Timer<'a> (pub &'a tim2::RegisterBlock); @@ -6,10 +6,12 @@ impl<'a> Timer<'a> { pub fn init(&self, timeout: u32) { let tim = self.0; self.set_timeout(timeout); - tim.cr1.write(|w| unsafe { - w.opm().continuous() - .cms().bits(0b00) - .dir().up()}); + tim.cr1.write(|w| w.opm().continuous()); + /* UEV to reload the psc and arr (without an interrupt) */ + tim.egr.write(|w| w.ug().set_bit()); + /* clear the interrupt flag caused by UG */ + tim.sr.modify(|_, w| w.uif().clear()); + /* finally enable the interrupt trigger */ tim.dier.modify(|_, w| w.uie().set_bit()); } @@ -20,6 +22,10 @@ impl<'a> Timer<'a> { self.0.arr.write(|w| w.arr().bits(arr)); } + pub fn is_enabled(&self) -> bool { + self.0.cr1.read().cen() == tim1::cr1::CENR::ENABLED + } + pub fn reset(&self) { self.0.cnt.write(|w| w.cnt().bits(0)); } |