diff options
| author | Keith Packard <keithp@keithp.com> | 2016-04-02 22:41:06 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2016-04-02 22:41:06 -0700 | 
| commit | 097c156b13ae975c742f294b46429e8ff14c365b (patch) | |
| tree | 10394c19747917b479fe45afdaa72fec42d4da17 | |
| parent | 0f227683e29062224a612c4a2ab5c8b2fc166059 (diff) | |
altos/stmf0: Add pwm and exti drivers
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | src/stmf0/ao_exti_stm.c | 149 | ||||
| -rw-r--r-- | src/stmf0/ao_pwm.c | 214 | 
2 files changed, 363 insertions, 0 deletions
| diff --git a/src/stmf0/ao_exti_stm.c b/src/stmf0/ao_exti_stm.c new file mode 100644 index 00000000..906392e6 --- /dev/null +++ b/src/stmf0/ao_exti_stm.c @@ -0,0 +1,149 @@ +/* + * 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_exti.h> + +static void	(*ao_exti_callback[16])(void); + +uint32_t	ao_last_exti; + +static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) { +	uint16_t	pending = (ao_last_exti = stm_exti.pr) & mask; +	uint8_t		pin; +	static uint16_t	last_mask; +	static uint8_t	last_pin; + +	if (pending == last_mask) { +		stm_exti.pr = last_mask; +		(*ao_exti_callback[last_pin])(); +		return; +	} +	stm_exti.pr = pending; +	for (pin = first; pin <= last; pin++) +		if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) { +			last_mask = (1 << pin); +			last_pin = pin; +			(*ao_exti_callback[pin])(); +		} +} + +void stm_exti0_1_isr(void) { ao_exti_range_isr(0, 1, 0x0003); } +void stm_exti2_3_isr(void) { ao_exti_range_isr(2, 3, 0x000c); } +void stm_exti4_15_isr(void) { ao_exti_range_isr(4, 15, 0xfff0); } + +void +ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) { +	uint32_t	mask = 1 << pin; +	uint32_t	pupdr; +	uint8_t		irq; +	uint8_t		prio; + +	ao_exti_callback[pin] = callback; + +	/* configure gpio to interrupt routing */ +	stm_exticr_set(gpio, pin); + +	if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) { +		/* configure pin as input, setting selected pull-up/down mode */ +		stm_moder_set(gpio, pin, STM_MODER_INPUT); +		switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) { +		case 0: +		default: +			pupdr  = STM_PUPDR_NONE; +			break; +		case AO_EXTI_MODE_PULL_UP: +			pupdr = STM_PUPDR_PULL_UP; +			break; +		case AO_EXTI_MODE_PULL_DOWN: +			pupdr = STM_PUPDR_PULL_DOWN; +			break; +		} +		stm_pupdr_set(gpio, pin, pupdr); +	} + +	/* Set interrupt mask and rising/falling mode */ +	stm_exti.imr &= ~mask; +	if (mode & AO_EXTI_MODE_RISING) +		stm_exti.rtsr |= mask; +	else +		stm_exti.rtsr &= ~mask; +	if (mode & AO_EXTI_MODE_FALLING) +		stm_exti.ftsr |= mask; +	else +		stm_exti.ftsr &= ~mask; + +	if (pin <= 1) +		irq = STM_ISR_EXTI0_1_POS; +	else if (pin <= 3) +		irq = STM_ISR_EXTI2_3_POS; +	else +		irq = STM_ISR_EXTI4_15_POS; + +	/* Set priority */ +	prio = AO_STM_NVIC_MED_PRIORITY; +	if (mode & AO_EXTI_PRIORITY_LOW) +		prio = AO_STM_NVIC_LOW_PRIORITY; +	else if (mode & AO_EXTI_PRIORITY_HIGH) +		prio = AO_STM_NVIC_HIGH_PRIORITY; + +	stm_nvic_set_priority(irq, prio); +	stm_nvic_set_enable(irq); +} + +void +ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) { +	(void) gpio; + +	uint32_t	mask = 1 << pin; +	 +	if (mode & AO_EXTI_MODE_RISING) +		stm_exti.rtsr |= mask; +	else +		stm_exti.rtsr &= ~mask; +	if (mode & AO_EXTI_MODE_FALLING) +		stm_exti.ftsr |= mask; +	else +		stm_exti.ftsr &= ~mask; +} + +void +ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)()) { +	(void) gpio; +	ao_exti_callback[pin] = callback; +} + +void +ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) { +	uint32_t	mask = (1 << pin); +	(void) gpio; +	stm_exti.pr = mask; +	stm_exti.imr |= (1 << pin); +} + +void +ao_exti_disable(struct stm_gpio *gpio, uint8_t pin) { +	uint32_t	mask = (1 << pin); +	(void) gpio; +	stm_exti.imr &= ~mask; +	stm_exti.pr = mask; +} + +void +ao_exti_init(void) +{ +} diff --git a/src/stmf0/ao_pwm.c b/src/stmf0/ao_pwm.c new file mode 100644 index 00000000..c1e157f5 --- /dev/null +++ b/src/stmf0/ao_pwm.c @@ -0,0 +1,214 @@ +/* + * 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_pwm.h" + +static uint8_t	pwm_running; + +static uint16_t	pwm_value[NUM_PWM]; + +static void +ao_pwm_up(void) +{ +	if (pwm_running++ == 0) { +		struct stm_tim23	*tim = AO_PWM_TIMER; + +		tim->ccr1 = 0; +		tim->ccr2 = 0; +		tim->ccr3 = 0; +		tim->ccr4 = 0; +		tim->arr = PWM_MAX - 1;	/* turn on the timer */ +		tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) | +			    (0 << STM_TIM23_CR1_ARPE) | +			    (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) | +			    (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) | +			    (0 << STM_TIM23_CR1_OPM) | +			    (0 << STM_TIM23_CR1_URS) | +			    (0 << STM_TIM23_CR1_UDIS) | +			    (1 << STM_TIM23_CR1_CEN)); + +		/* Set the timer running */ +		tim->egr = (1 << STM_TIM23_EGR_UG); +	} +} + +static void +ao_pwm_down(void) +{ +	if (--pwm_running == 0) { +		struct stm_tim23	*tim = AO_PWM_TIMER; + +		tim->arr = 0; +		tim->cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) | +			    (0 << STM_TIM23_CR1_ARPE) | +			    (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) | +			    (STM_TIM23_CR1_DIR_UP << STM_TIM23_CR1_DIR) | +			    (0 << STM_TIM23_CR1_OPM) | +			    (0 << STM_TIM23_CR1_URS) | +			    (0 << STM_TIM23_CR1_UDIS) | +			    (0 << STM_TIM23_CR1_CEN)); + +		/* Stop the timer */ +		tim->egr = (1 << STM_TIM23_EGR_UG); +	} +} + +void +ao_pwm_set(uint8_t pwm, uint16_t value) +{ +	struct stm_tim23	*tim = AO_PWM_TIMER; +	uint8_t			ch = AO_PWM_0_CH; + +	if (value > PWM_MAX) +		value = PWM_MAX; +	if (value != 0) { +		if (pwm_value[pwm] == 0) +			ao_pwm_up(); +	} +#if NUM_PWM > 1 +	switch (pwm) { +	case 0: +		ch = AO_PWM_0_CH; +		break; +	case 1: +		ch = AO_PWM_0_CH; +		break; +#if NUM_PWM > 2 +	case 2: +		ch = AO_PWM_0_CH; +		break; +#endif +#if NUM_PWM > 3 +	case 3: +		ch = AO_PWM_0_CH; +		break; +#endif +	} +#endif + +	switch (ch) { +	case 1: +		tim->ccr1 = value; +		break; +	case 2: +		tim->ccr2 = value; +		break; +	case 3: +		tim->ccr3 = value; +		break; +	case 4: +		tim->ccr4 = value; +		break; +	} +	if (value == 0) { +		if (pwm_value[pwm] != 0) +			ao_pwm_down(); +	} +	pwm_value[pwm] = value; +} + +static void +ao_pwm_cmd(void) +{ +	uint8_t	ch; +	uint16_t val; + +	ao_cmd_decimal(); +	ch = ao_cmd_lex_u32; +	ao_cmd_decimal(); +	val = ao_cmd_lex_u32; +	if (ao_cmd_status != ao_cmd_success) +		return; + +	printf("Set channel %d to %d\n", ch, val); +	ao_pwm_set(ch, val); +} + +static const struct ao_cmds ao_pwm_cmds[] = { +	{ ao_pwm_cmd,	"P <ch> <val>\0Set PWM ch to val" }, +	{ 0, NULL }, +}; + +void +ao_pwm_init(void) +{ +	struct stm_tim23	*tim = AO_PWM_TIMER; + +	stm_rcc.apb1enr |= (1 << AO_PWM_TIMER_ENABLE); + +	tim->cr1 = 0; +	tim->psc = AO_PWM_TIMER_SCALE - 1; +	tim->cnt = 0; +	tim->ccer = ((1 << STM_TIM23_CCER_CC1E) | +		     (0 << STM_TIM23_CCER_CC1P) | +		     (1 << STM_TIM23_CCER_CC2E) | +		     (0 << STM_TIM23_CCER_CC2P) | +		     (1 << STM_TIM23_CCER_CC3E) | +		     (0 << STM_TIM23_CCER_CC3P) | +		     (1 << STM_TIM23_CCER_CC4E) | +		     (0 << STM_TIM23_CCER_CC4P)); + +	tim->ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | +		      (STM_TIM23_CCMR1_OC2M_PWM_MODE_1 << STM_TIM23_CCMR1_OC2M) | +		      (0 << STM_TIM23_CCMR1_OC2PE) | +		      (0 << STM_TIM23_CCMR1_OC2FE) | +		      (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + +		      (0 << STM_TIM23_CCMR1_OC1CE) | +		      (STM_TIM23_CCMR1_OC1M_PWM_MODE_1 << STM_TIM23_CCMR1_OC1M) | +		      (0 << STM_TIM23_CCMR1_OC1PE) | +		      (0 << STM_TIM23_CCMR1_OC1FE) | +		      (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + + +	tim->ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | +		      (STM_TIM23_CCMR2_OC4M_PWM_MODE_1 << STM_TIM23_CCMR2_OC4M) | +		      (0 << STM_TIM23_CCMR2_OC4PE) | +		      (0 << STM_TIM23_CCMR2_OC4FE) | +		      (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + +		      (0 << STM_TIM23_CCMR2_OC3CE) | +		      (STM_TIM23_CCMR2_OC3M_PWM_MODE_1 << STM_TIM23_CCMR2_OC3M) | +		      (0 << STM_TIM23_CCMR2_OC3PE) | +		      (0 << STM_TIM23_CCMR2_OC3FE) | +		      (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); +	tim->egr = 0; + +	tim->sr = 0; +	tim->dier = 0; +	tim->smcr = 0; +	tim->cr2 = ((0 << STM_TIM23_CR2_TI1S) | +		    (STM_TIM23_CR2_MMS_RESET<< STM_TIM23_CR2_MMS) | +		    (0 << STM_TIM23_CR2_CCDS)); + +	stm_afr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_AFR_AF1); +	stm_ospeedr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_OSPEEDR_MEDIUM); +#if NUM_PWM > 1 +	stm_afr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_AFR_AF1); +	stm_ospeedr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_OSPEEDR_MEDIUM); +#endif +#if NUM_PWM > 2 +	stm_afr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_AFR_AF1); +	stm_ospeedr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_OSPEEDR_MEDIUM); +#endif +#if NUM_PWM > 3 +	stm_afr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_AFR_AF1); +	stm_ospeedr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_OSPEEDR_MEDIUM); +#endif +	ao_cmd_register(&ao_pwm_cmds[0]); +} | 
