Nut/OS  4.10.3
API Reference
ostimer.c
Go to the documentation of this file.
00001 
00036 /*
00037  * $Log: ostimer.c,v $
00038  *
00039  */
00040 
00041 #include <cfg/os.h>
00042 #include <cfg/clock.h>
00043 #include <arch/avr32.h>
00044 #include <dev/irqreg.h>
00045 #include <sys/timer.h>
00046 
00047 #include <arch/avr32/ihndlr.h>
00048 
00049 #include <avr32/io.h>
00050 
00051 
00056 
00057 #ifndef NUT_TICK_FREQ
00058 #define NUT_TICK_FREQ   1000UL
00059 #endif
00060 
00061 IRQ_HANDLER sig_sysCompare = {
00062 #ifdef NUT_PERFMON
00063     0,                          /* Interrupt counter, ir_count. */
00064 #endif
00065     NULL,                       /* Passed argument, ir_arg. */
00066     NULL,                       /* Handler subroutine, ir_handler. */
00067     NULL                        /* Interrupt control, ir_ctl. */
00068 };
00069 
00070 
00078 static u_int AVR32GetPllClock(int pll)
00079 {
00080     u_int rc;
00081     u_int osc = 0;
00082 
00083     if (AVR32_PM.PLL[pll].pllosc)
00084         osc = 0;
00085     else
00086         osc = OSC0_VAL;
00087 
00088     /*
00089      * The main oscillator clock frequency is specified by the
00090      * configuration. It's usually equal to the on-board crystal.
00091      */
00092     rc = osc;
00093 
00094     if (AVR32_PM.PLL[pll].pllen) {
00095         u_int divider = AVR32_PM.PLL[pll].plldiv;
00096         u_int multiplier = AVR32_PM.PLL[pll].pllmul;
00097 
00098         if (divider)
00099             rc *= (multiplier + 1) / divider;
00100         else
00101             rc *= 2 * (multiplier + 1);
00102 
00103         if (AVR32_PM.PLL[pll].pllopt)
00104             rc /= 2;
00105     }
00106     return rc;
00107 }
00108 
00114 static uint32_t Avr32GetProcessorClock(void)
00115 {
00116     u_int rc = 0;
00117     u_int mckr = AVR32_PM.mcctrl;
00118 
00119     /* Determine the clock source. */
00120     switch (mckr & AVR32_PM_MCCTRL_MCSEL_MASK) {
00121     case AVR32_PM_MCCTRL_MCSEL_OSC0:
00122         /* OSC0 clock selected */
00123         rc = OSC0_VAL;
00124         break;
00125     case AVR32_PM_MCCTRL_MCSEL_SLOW:
00126         /* Slow clock selected. */
00127         rc = AVR32_PM_RCOSC_FREQUENCY;
00128         break;
00129     case AVR32_PM_MCCTRL_MCSEL_PLL0:
00130         /* PLL0 clock selected. */
00131         rc = AVR32GetPllClock(0);
00132         break;
00133     }
00134 
00135     /* Handle pre-scaling. */
00136     if (AVR32_PM.cksel & AVR32_PM_CKSEL_CPUDIV_MASK) {
00137         int cpusel = (AVR32_PM.cksel & AVR32_PM_CKSEL_CPUSEL_MASK) >> AVR32_PM_CKSEL_CPUSEL_OFFSET;
00138         /* CPUDIV = 1: CPU Clock equals main clock divided by 2^(CPUSEL+1). */
00139         rc /= _BV(cpusel + 1);
00140     }
00141 
00142     return rc;
00143 }
00144 
00145 
00149 static SIGNAL(SystemCompareIrqEntry)
00150 {
00151     IRQ_ENTRY();
00152     uint32_t compare;
00153     compare = Get_system_register(AVR32_COMPARE);
00154     Set_system_register(AVR32_COMPARE, 0);
00155     if (sig_sysCompare.ir_handler) {
00156         (sig_sysCompare.ir_handler) (sig_sysCompare.ir_arg);
00157     }
00158 #if __AVR32_AP7000__ || __AT32AP7000__ || __AVR32_UC3A0512ES__ || __AVR32_UC3A1512ES__
00159     /* AP7000 and UC3 prior to rev H doesn't clear COUNT on compare match, so we need to
00160        offset COMPARE */
00161     compare += NutGetCpuClock() / NUT_TICK_FREQ;
00162     if (!compare)               // Avoid disabling compare.
00163         ++compare;
00164 #endif
00165     Set_system_register(AVR32_COMPARE, compare);
00166     IRQ_EXIT();
00167 }
00168 
00180 void NutRegisterTimer(void (*handler) (void *))
00181 {
00182     /* Set compare value for the specified tick frequency. */
00183     Set_system_register(AVR32_COMPARE, NutGetCpuClock() / NUT_TICK_FREQ + Get_system_register(AVR32_COUNT));
00184 
00185     sig_sysCompare.ir_handler = handler;
00186 
00187     register_interrupt(SystemCompareIrqEntry, AVR32_CORE_COMPARE_IRQ, AVR32_INTC_INT0);
00188 }
00189 
00199 uint32_t NutArchClockGet(int idx)
00200 {
00201     uint32_t rc = AVR32_PM_PBA_MAX_FREQ;
00202 
00203     if (idx == NUT_HWCLK_CPU || idx == NUT_HWCLK_PERIPHERAL_HSB) {
00204         rc = Avr32GetProcessorClock();
00205     } else if (idx == NUT_HWCLK_PERIPHERAL_A) {
00206         /* Get PBA Clock */
00207         rc = Avr32GetProcessorClock();
00208 
00209         if (AVR32_PM.CKSEL.pbadiv) {
00210             rc /= _BV(AVR32_PM.CKSEL.pbasel + 1);
00211         }
00212     } else if (idx == NUT_HWCLK_PERIPHERAL_B) {
00213         /* Get PBB Clock */
00214         rc = Avr32GetProcessorClock();
00215 
00216         if (AVR32_PM.CKSEL.pbbdiv) {
00217             rc /= _BV(AVR32_PM.CKSEL.pbbsel + 1);
00218         }
00219     } else if (idx == NUT_HWCLK_SLOW_CLOCK) {
00220         /* Can be changed using the RCCR register 
00221            but there is no information on the datasheet yet
00222            on how to do so. Therefore we don't know how to calculate
00223            non-default values yet. */
00224 #if defined( __AVR32_AP7000__ )
00225         rc = 32768;             // AP7000 has no constant for slow clock, but this is the same as XIN32, which should be 32768hz
00226 #else
00227         rc = AVR32_PM_RCOSC_FREQUENCY;
00228 #endif
00229     }
00230 
00231     return rc;
00232 }
00233 
00234 
00240 uint32_t NutGetTickClock(void)
00241 {
00242     return NUT_TICK_FREQ;
00243 }
00244 
00248 uint32_t NutTimerMillisToTicks(uint32_t ms)
00249 {
00250 #if (NUT_TICK_FREQ % 1000)
00251     if (ms >= 0x3E8000UL)
00252         return (ms / 1000UL) * NUT_TICK_FREQ;
00253     return (ms * NUT_TICK_FREQ + 999UL) / 1000UL;
00254 #else
00255     return ms * (NUT_TICK_FREQ / 1000UL);
00256 #endif
00257 }
00258