diff options
| -rw-r--r-- | src/lpc/ao_fast_timer_lpc.c | 110 | ||||
| -rw-r--r-- | src/lpc/ao_timer_lpc.c | 14 | ||||
| -rw-r--r-- | src/lpc/lpc.h | 120 | ||||
| -rw-r--r-- | src/lpc/registers.ld | 2 | 
4 files changed, 229 insertions, 17 deletions
| diff --git a/src/lpc/ao_fast_timer_lpc.c b/src/lpc/ao_fast_timer_lpc.c new file mode 100644 index 00000000..c4f26fc4 --- /dev/null +++ b/src/lpc/ao_fast_timer_lpc.c @@ -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++; +} + diff --git a/src/lpc/ao_timer_lpc.c b/src/lpc/ao_timer_lpc.c index 44fb410e..623559eb 100644 --- a/src/lpc/ao_timer_lpc.c +++ b/src/lpc/ao_timer_lpc.c @@ -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) | diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h index 9408ceab..40d412d0 100644 --- a/src/lpc/lpc.h +++ b/src/lpc/lpc.h @@ -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; diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld index a523c39c..61dd9e70 100644 --- a/src/lpc/registers.ld +++ b/src/lpc/registers.ld @@ -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; | 
