altos/lpc: Add fast timer
authorKeith Packard <keithp@keithp.com>
Fri, 25 Mar 2016 01:28:16 +0000 (19:28 -0600)
committerKeith Packard <keithp@keithp.com>
Sat, 26 Mar 2016 23:07:20 +0000 (16:07 -0700)
This offers a faster timer callback for higher-precision operation

Signed-off-by: Keith Packard <keithp@keithp.com>
src/lpc/ao_fast_timer_lpc.c [new file with mode: 0644]
src/lpc/ao_timer_lpc.c
src/lpc/lpc.h
src/lpc/registers.ld

diff --git a/src/lpc/ao_fast_timer_lpc.c b/src/lpc/ao_fast_timer_lpc.c
new file mode 100644 (file)
index 0000000..c4f26fc
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_fast_timer.h>
+
+static void (*ao_fast_timer_callback[AO_FAST_TIMER_MAX])(void);
+static uint8_t ao_fast_timer_count;
+static uint8_t ao_fast_timer_users;
+
+static void
+ao_fast_timer_enable(void)
+{
+       lpc_ct16b0.tcr = ((1 << LPC_CT16B_TCR_CEN) |
+                         (1 << LPC_CT16B_TCR_CRST));
+}
+
+static void
+ao_fast_timer_disable(void)
+{
+       lpc_ct16b0.tcr = ((0 << LPC_CT16B_TCR_CEN) |
+                         (0 << LPC_CT16B_TCR_CRST));
+}
+
+void
+ao_fast_timer_on(void (*callback)(void))
+{
+       ao_fast_timer_callback[ao_fast_timer_count] = callback;
+       if (!ao_fast_timer_count++)
+               ao_fast_timer_enable();
+}
+
+void
+ao_fast_timer_off(void (*callback)(void))
+{
+       uint8_t n;
+
+       for (n = 0; n < ao_fast_timer_count; n++)
+               if (ao_fast_timer_callback[n] == callback) {
+                       for (; n < ao_fast_timer_count-1; n++) {
+                               ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
+                       }
+                       if (!--ao_fast_timer_count)
+                               ao_fast_timer_disable();
+                       break;
+               }
+}
+
+void lpc_ct16b0_isr(void)
+{
+       uint32_t        v = lpc_ct16b0.ir;
+       int             i;
+
+       lpc_ct16b0.ir = v;
+       if (v & (1 << LPC_CT16B_IR_MR0INT)) {
+               for (i = 0; i < ao_fast_timer_count; i++)
+                       (*ao_fast_timer_callback[i])();
+       }
+}
+
+#ifndef FAST_TIMER_FREQ
+#define FAST_TIMER_FREQ        10000
+#endif
+
+#define TIMER_FAST     (AO_LPC_SYSCLK / FAST_TIMER_FREQ)
+
+void
+ao_fast_timer_init(void)
+{
+       if (!ao_fast_timer_users) {
+
+               lpc_nvic_set_enable(LPC_ISR_CT16B0_POS);
+               lpc_nvic_set_priority(LPC_ISR_CT16B0_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
+               /* Turn on 16-bit timer CT16B0 */
+
+               lpc_scb.sysahbclkctrl |= 1 << LPC_SCB_SYSAHBCLKCTRL_CT16B0;
+
+               /* Disable timer */
+               lpc_ct16b0.tcr = 0;
+
+               /* scale factor 1 */
+               lpc_ct16b0.pr = 0;
+               lpc_ct16b0.pc = 0;
+
+               lpc_ct16b0.mcr = ((1 << LPC_CT16B_MCR_MR0I) |
+                                 (1 << LPC_CT16B_MCR_MR0R));
+
+               lpc_ct16b0.mr[0] = TIMER_FAST;
+
+               ao_fast_timer_disable();
+       }
+       if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
+               ao_panic(AO_PANIC_FAST_TIMER);
+       ao_fast_timer_users++;
+}
+
index 44fb410e7f522b642d1a68f965f46681690a3d74..623559ebe14c4c69127a62c381d8a1161085a945 100644 (file)
@@ -99,7 +99,7 @@ ao_clock_init(void)
                                 (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY) |
                                 (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO) |
                                 (1 << LPC_SCB_SYSAHBCLKCTRL_IOCON));
-                                
+
        /* Enable the brown-out detection at the highest voltage to
         * make sure the flash part remains happy
         */
@@ -112,21 +112,21 @@ ao_clock_init(void)
        /* Turn the IRC clock back on */
        lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD);
        ao_clock_delay();
-       
+
        /* Switch to the IRC clock */
        lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL;
        lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
        lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
        while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
                ;
-       
+
        /* Switch USB to the main clock */
        lpc_scb.usbclksel = (LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK << LPC_SCB_USBCLKSEL_SEL);
        lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA);
        lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA);
        while (!(lpc_scb.usbclkuen & (1 << LPC_SCB_USBCLKUEN_ENA)))
                ;
-       
+
        /* Find a PLL post divider ratio that gets the FCCO in range */
        for (p = 0; p < 4; p++)
                if (AO_LPC_CLKOUT << (1 + p) >= AO_LPC_FCCO_MIN)
@@ -163,12 +163,12 @@ ao_clock_init(void)
        lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
        while (!(lpc_scb.syspllclkuen & (1 << LPC_SCB_SYSPLLCLKUEN_ENA)))
                ;
-       
+
        /* Turn on the PLL */
        lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
 
        /* Wait for it to lock */
-       
+
        for (i = 0; i < 20000; i++)
                if (lpc_scb.syspllstat & (1 << LPC_SCB_SYSPLLSTAT_LOCK))
                        break;
@@ -199,7 +199,7 @@ ao_clock_init(void)
        lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
        while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
                ;
-       
+
        /* Power down everything we don't need */
        lpc_scb.pdruncfg = ((1 << LPC_SCB_PDRUNCFG_IRCOUT_PD) |
                            (1 << LPC_SCB_PDRUNCFG_IRC_PD) |
index 9408ceab1ab7d76ab71037f3c009f7b3ab53d716..40d412d01f90b6fabed6fc57e4aa44e1fc348d4c 100644 (file)
@@ -411,7 +411,7 @@ struct lpc_scb {
        vuint32_t       mainclksel;     /* 0x70 */
        vuint32_t       mainclkuen;
        vuint32_t       sysahbclkdiv;
-       uint32_t        r7c;            
+       uint32_t        r7c;
 
        vuint32_t       sysahbclkctrl;  /* 0x80 */
        uint32_t        r84[3];
@@ -429,14 +429,14 @@ struct lpc_scb {
        uint32_t        rcc;
 
        uint32_t        rd0[4];
-       
+
        vuint32_t       clkoutsel;      /* 0xe0 */
        vuint32_t       clkoutuen;
        vuint32_t       clkoutdiv;
        uint32_t        rec;
-       
+
        uint32_t        rf0[4];         /* 0xf0 */
-       
+
        vuint32_t       pioporcap0;     /* 0x100 */
        vuint32_t       pioporcap1;
        uint32_t        r102[2];
@@ -445,7 +445,7 @@ struct lpc_scb {
        uint32_t        r120[4];        /* 0x120 */
        uint32_t        r130[4];        /* 0x130 */
        uint32_t        r140[4];        /* 0x140 */
-       
+
        vuint32_t       bodctrl;        /* 0x150 */
        vuint32_t       systckcal;
        uint32_t        r158[2];
@@ -479,7 +479,7 @@ struct lpc_scb {
        uint32_t        r240[12 * 4];   /* 0x240 */
 
        uint32_t        r300[15 * 4];   /* 0x300 */
-                            
+
        uint32_t        r3f0;           /* 0x3f0 */
        vuint32_t       device_id;
 };
@@ -680,7 +680,7 @@ struct lpc_gpio {
        vuint32_t       word[0x40];     /* 0x1000 */
 
        uint8_t         r1100[0x2000 - 0x1100];
-       
+
        vuint32_t       dir[2];         /* 0x2000 */
 
        uint8_t         r2008[0x2080 - 0x2008];
@@ -1032,7 +1032,7 @@ lpc_nvic_enabled(int irq) {
        return (lpc_nvic.iser >> irq) & 1;
 }
 
-       
+
 static inline void
 lpc_nvic_set_pending(int irq) {
        lpc_nvic.ispr = (1 << irq);
@@ -1201,18 +1201,118 @@ extern struct lpc_adc lpc_adc;
 #define LPC_ADC_STAT_OVERRUN   8
 #define LPC_ADC_STAT_ADINT     16
 
+struct lpc_ct16b {
+       vuint32_t       ir;     /* 0x00 */
+       vuint32_t       tcr;
+       vuint32_t       tc;
+       vuint32_t       pr;
+
+       vuint32_t       pc;     /* 0x10 */
+       vuint32_t       mcr;
+       vuint32_t       mr[4];  /* 0x18 */
+       vuint32_t       ccr;    /* 0x28 */
+       vuint32_t       cr0;
+
+       vuint32_t       cr1_0;  /* 0x30 (only for ct16b0 */
+       vuint32_t       cr1_1;  /* 0x34 (only for ct16b1 */
+       uint32_t        r38;
+       vuint32_t       emr;
+
+       uint8_t         r40[0x70 - 0x40];
+
+       vuint32_t       ctcr;   /* 0x70 */
+       vuint32_t       pwmc;
+};
+
+extern struct lpc_ct16b        lpc_ct16b0, lpc_ct16b1;
+
+#define lpc_ct16b0     (*(struct lpc_ct16b *) 0x4000c000)
+#define lpc_ct16b1     (*(struct lpc_ct16b *) 0x40010000)
+
+#define LPC_CT16B_IR_MR0INT    0
+#define LPC_CT16B_IR_MR1INT    1
+#define LPC_CT16B_IR_MR2INT    2
+#define LPC_CT16B_IR_MR3INT    3
+#define LPC_CT16B_IR_CR0INT    4
+#define LPC_CT16B0_IR_CR1INT   6
+#define LPC_CT16B1_IR_CR1INT   5
+
+#define LPC_CT16B_TCR_CEN      0
+#define LPC_CT16B_TCR_CRST     1
+
+#define LPC_CT16B_MCR_MR0I     0
+#define LPC_CT16B_MCR_MR0R     1
+#define LPC_CT16B_MCR_MR0S     2
+#define LPC_CT16B_MCR_MR1I     3
+#define LPC_CT16B_MCR_MR1R     4
+#define LPC_CT16B_MCR_MR1S     5
+#define LPC_CT16B_MCR_MR2I     6
+#define LPC_CT16B_MCR_MR2R     7
+#define LPC_CT16B_MCR_MR2S     8
+#define LPC_CT16B_MCR_MR3I     9
+#define LPC_CT16B_MCR_MR3R     10
+#define LPC_CT16B_MCR_MR3S     11
+
+#define LPC_CT16B_CCR_CAP0RE   0
+#define LPC_CT16B_CCR_CAP0FE   1
+#define LPC_CT16B_CCR_CAP0I    2
+#define LPC_CT16B0_CCR_CAP1RE  6
+#define LPC_CT16B0_CCR_CAP1FE  7
+#define LPC_CT16B0_CCR_CAP1I   8
+#define LPC_CT16B1_CCR_CAP1RE  3
+#define LPC_CT16B1_CCR_CAP1FE  4
+#define LPC_CT16B1_CCR_CAP1I   5
+
+#define LPC_CT16B_EMR_EM0      0
+#define LPC_CT16B_EMR_EM1      1
+#define LPC_CT16B_EMR_EM2      2
+#define LPC_CT16B_EMR_EM3      3
+#define LPC_CT16B_EMR_EMC0     4
+#define LPC_CT16B_EMR_EMC1     6
+#define LPC_CT16B_EMR_EMC2     8
+#define LPC_CT16B_EMR_EMC3     10
+
+#define LPC_CT16B_EMR_EMC_NOTHING      0
+#define LPC_CT16B_EMR_EMC_CLEAR                1
+#define LPC_CT16B_EMR_EMC_SET          2
+#define LPC_CT16B_EMR_EMC_TOGGLE       3
+
+#define LPC_CT16B_CCR_CTM      0
+#define  LPC_CT16B_CCR_CTM_TIMER               0
+#define  LPC_CT16B_CCR_CTM_COUNTER_RISING      1
+#define  LPC_CT16B_CCR_CTM_COUNTER_FALLING     2
+#define  LPC_CT16B_CCR_CTM_COUNTER_BOTH                3
+#define LPC_CT16B_CCR_CIS      2
+#define  LPC_CT16B_CCR_CIS_CAP0                        0
+#define  LPC_CT16B0_CCR_CIS_CAP1               2
+#define  LPC_CT16B1_CCR_CIS_CAP1               1
+#define LPC_CT16B_CCR_ENCC     4
+#define LPC_CT16B_CCR_SELCC    5
+#define  LPC_CT16B_CCR_SELCC_RISING_CAP0       0
+#define  LPC_CT16B_CCR_SELCC_FALLING_CAP0      1
+#define  LPC_CT16B0_CCR_SELCC_RISING_CAP1      4
+#define  LPC_CT16B0_CCR_SELCC_FALLING_CAP1     5
+#define  LPC_CT16B1_CCR_SELCC_RISING_CAP1      2
+#define  LPC_CT16B1_CCR_SELCC_FALLING_CAP1     3
+#define LPC_CT16B_CCR_
+
+#define LPC_CT16B_PWMC_PWMEN0  0
+#define LPC_CT16B_PWMC_PWMEN1  1
+#define LPC_CT16B_PWMC_PWMEN2  2
+#define LPC_CT16B_PWMC_PWMEN3  3
+
 struct lpc_ct32b {
        vuint32_t       ir;     /* 0x00 */
        vuint32_t       tcr;
        vuint32_t       tc;
        vuint32_t       pr;
-       
+
        vuint32_t       pc;     /* 0x10 */
        vuint32_t       mcr;
        vuint32_t       mr[4];  /* 0x18 */
        vuint32_t       ccr;    /* 0x28 */
        vuint32_t       cr0;
-       
+
        vuint32_t       cr1_0;  /* 0x30 (only for ct32b0 */
        vuint32_t       cr1_1;  /* 0x34 (only for ct32b1 */
        uint32_t        r38;
index a523c39c9afb1910f6d844b0ef3d81005e3da336..61dd9e7076c0dca5130badee0868fcd2a3e4fe1e 100644 (file)
@@ -1,6 +1,8 @@
 lpc_usb_sram   = 0x20004000;
 lpc_usb_endpoint = 0x20004700;
 lpc_usart      = 0x40008000;
+lpc_ct16b0     = 0x4000c000;
+lpc_ct16b1     = 0x40010000;
 lpc_ct32b0     = 0x40014000;
 lpc_ct32b1     = 0x40018000;
 lpc_adc                = 0x4001c000;