std1.0.0-beta-7 SafeC docs

Source hal/timer.h

View in the repository

// SafeC Standard Library — Timer HAL
// Hardware timer control. Freestanding-safe.
//
// Timer<C> is generic over the timer block, a compile-time chip type:
//   TimerGeneric  reference layout: CTRL +0x00 (bit 0 enable), PRESCALER
//                 +0x04, PERIOD +0x08, COUNT +0x0C, STATUS +0x10 (bit 0 flag)
//   Stm32F4Tim    STM32 general-purpose timer (TIM2-TIM5 style): PSC, ARR,
//                 CNT, update flag (UIF)
#pragma once

namespace std {

// What a timer block type provides; Timer<C> requires it.
trait TimerChip {
    void         init(unsigned long base, unsigned int prescaler) const;
    void         set_period(unsigned long base, unsigned int period) const;
    void         run(unsigned long base, int on) const;
    unsigned int count(unsigned long base) const;
    int          flag(unsigned long base) const;
    void         clear_flag(unsigned long base) const;
}

struct TimerGeneric {
    int          unused_;
    void         init(unsigned long base, unsigned int prescaler) const;
    void         set_period(unsigned long base, unsigned int period) const;
    void         run(unsigned long base, int on) const;
    unsigned int count(unsigned long base) const;
    int          flag(unsigned long base) const;
    void         clear_flag(unsigned long base) const;
};
struct Stm32F4Tim {
    int          unused_;
    void         init(unsigned long base, unsigned int prescaler) const;
    void         set_period(unsigned long base, unsigned int period) const;
    void         run(unsigned long base, int on) const;
    unsigned int count(unsigned long base) const;
    int          flag(unsigned long base) const;
    void         clear_flag(unsigned long base) const;
};

generic<C: TimerChip>
struct Timer {
    &volatile unsigned int base; // MMIO base address
    unsigned int prescaler;  // clock divider
    C            chip;

    // Initialize a hardware timer at `base` with the given prescaler (STM32: the
    // counter runs at clock / (prescaler + 1)). The chip type comes from the target.
    static struct Timer<C> new(&volatile unsigned int base, unsigned int prescaler);

    // Set the auto-reload (period) value.
    void         set_period(unsigned int period);
    // Start the timer.
    void         start();
    // Stop the timer.
    void         stop();
    // Read the current counter value.
    unsigned int read() const;
    // Clear the interrupt/overflow flag.
    void         clear_flag();
    // Check if the overflow/compare flag is set. Returns 1 if set.
    int          flag_set() const;
    unsigned long addr_() const;
};

generic<C: TimerChip>
struct Timer<C> Timer::new(&volatile unsigned int base, unsigned int prescaler) {
    struct Timer<C> t;
    t.base = base;
    t.prescaler = prescaler;
    t.chip.init(t.addr_(), prescaler);
    return t;
}

generic<C: TimerChip>
unsigned long Timer::addr_() const { unsafe { return (unsigned long)self.base; } }
generic<C: TimerChip>
void Timer::set_period(unsigned int period) { self.chip.set_period(self.addr_(), period); }
generic<C: TimerChip>
void Timer::start() { self.chip.run(self.addr_(), 1); }
generic<C: TimerChip>
void Timer::stop() { self.chip.run(self.addr_(), 0); }
generic<C: TimerChip>
unsigned int Timer::read() const { return self.chip.count(self.addr_()); }
generic<C: TimerChip>
void Timer::clear_flag() { self.chip.clear_flag(self.addr_()); }
generic<C: TimerChip>
int Timer::flag_set() const { return self.chip.flag(self.addr_()); }

} // namespace std