Added interrupt and event generation handling functions to timer. Updated pwm 6step example to use those and commutate on button press using PWM ON scheme.

This commit is contained in:
Piotr Esden-Tempski 2011-01-31 13:28:54 -08:00
parent a0091f18c7
commit dd0018ffdf
3 changed files with 229 additions and 18 deletions

View File

@ -21,11 +21,74 @@
#include <libopencm3/stm32/nvic.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/exti.h>
#define FALLING 0
#define RISING 1
u16 exti_direction = FALLING;
void clock_setup(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
}
void gpio_setup(void)
{
/* Enable GPIOC clock. */
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
/*
* Set GPIO12 (PORTC) (led) to
* 'output alternate function push-pull'.
*/
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
}
void exti_setup(void)
{
/* Enable GPIOA clock. */
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
/* Enable AFIO clock. */
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
/* Enable EXTI0 interrupt */
nvic_enable_irq(NVIC_EXTI0_IRQ);
/* Set GPIO0 (in GPIO port A) to 'input open-drain'. */
gpio_set_mode(GPIOA, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO0);
/* configure EXTI subsystem */
exti_select_source(EXTI0, GPIOA);
exti_direction = FALLING;
exti_set_trigger(EXTI0, EXTI_TRIGGER_FALLING);
exti_enable_request(EXTI0);
}
void exti0_isr()
{
exti_reset_request(EXTI0);
if (exti_direction == FALLING) {
//gpio_toggle(GPIOA, GPIO12);
exti_direction = RISING;
exti_set_trigger(EXTI0, EXTI_TRIGGER_RISING);
} else {
//gpio_toggle(GPIOA, GPIO12);
timer_generate_event(TIM1, TIM_EGR_COMG);
exti_direction = FALLING;
exti_set_trigger(EXTI0, EXTI_TRIGGER_FALLING);
}
}
void tim_setup(void)
{
/* Enable TIM1 clock. */
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN);
@ -34,16 +97,6 @@ void clock_setup(void)
RCC_APB2ENR_IOPAEN |
RCC_APB2ENR_IOPBEN |
RCC_APB2ENR_AFIOEN);
}
void gpio_setup(void)
{
/*
* Set GPIO12 (PORTC) (led) to
* 'output alternate function push-pull'.
*/
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
/*
* Set TIM1 chanel output pins to
@ -65,11 +118,6 @@ void gpio_setup(void)
GPIO_TIM1_CH2N |
GPIO_TIM1_CH3N);
}
void tim_setup(void)
{
/* Enable TIM1 commutation interrupt. */
nvic_enable_irq(NVIC_TIM1_TRG_COM_IRQ);
@ -95,7 +143,7 @@ void tim_setup(void)
timer_set_period(TIM1, 72000000 / 32000);
/* Configure break and deadtime */
timer_set_deadtime(TIM1, 0);
timer_set_deadtime(TIM1, 10);
timer_set_enabled_off_state_in_idle_mode(TIM1);
timer_set_enabled_off_state_in_run_mode(TIM1);
timer_disable_break(TIM1);
@ -151,7 +199,7 @@ void tim_setup(void)
timer_set_oc_idle_state_set(TIM1, TIM_OC2N);
/* Set the capture compare value for OC1. */
timer_set_oc_value(TIM1, TIM_OC2, 200);
timer_set_oc_value(TIM1, TIM_OC2, 100);
/* Reenable outputs. */
timer_enable_oc_output(TIM1, TIM_OC2);
@ -178,7 +226,7 @@ void tim_setup(void)
timer_set_oc_idle_state_set(TIM1, TIM_OC3N);
/* Set the capture compare value for OC3. */
timer_set_oc_value(TIM1, TIM_OC3, 300);
timer_set_oc_value(TIM1, TIM_OC3, 100);
/* Reenable outputs. */
timer_enable_oc_output(TIM1, TIM_OC3);
@ -188,11 +236,155 @@ void tim_setup(void)
/* ARR reload enable */
timer_enable_preload(TIM1);
/* Enable preload of complementary channel configurations and update on COM event */
timer_enable_preload_complementry_enable_bits(TIM1);
/* Enable outputs in the break subsystem */
timer_enable_break_main_output(TIM1);
/* Counter enable */
timer_enable_counter(TIM1);
/* Enable commutation interrupt */
timer_enable_irq(TIM1, TIM_DIER_COMIE);
}
void tim1_trg_com_isr(void)
{
static int step = 0;
TIM1_SR &= ~TIM_SR_COMIF;
/* A simplified and inefficient implementation of PWM On
* scheme. Look at the implementation in Open-BLDC on
* http://open-bldc.org for the proper implementation. This
* one only serves as an example.
*
* Table of the pwm scheme zone configurations when driving:
* @verbatim
* | 1| 2| 3| 4| 5| 6|
* -+--+--+--+--+--+--+
* A|p+|++| |p-|--| |
* -+--+--+--+--+--+--+
* B| |p-|--| |p+|++|
* -+--+--+--+--+--+--+
* C|--| |p+|++| |p-|
* -+--+--+--+--+--+--+
* | | | | | | '- 360 Deg
* | | | | | '---- 300 Deg
* | | | | '------- 240 Deg
* | | | '---------- 180 Deg
* | | '------------- 120 Deg
* | '---------------- 60 Deg
* '------------------- 0 Deg
*
* Legend:
* p+: PWM on the high side
* p-: PWM on the low side
* --: Low side on
* ++: High side on
* : Floating/NC
* @endverbatim
*/
switch (step) {
case 0: /* A PWM HIGH, B OFF, C LOW */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_FROZEN);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_FORCE_LOW);
timer_enable_oc_output(TIM1, TIM_OC1);
timer_disable_oc_output(TIM1, TIM_OC1N);
timer_disable_oc_output(TIM1, TIM_OC2);
timer_disable_oc_output(TIM1, TIM_OC2N);
timer_enable_oc_output(TIM1, TIM_OC3);
timer_enable_oc_output(TIM1, TIM_OC3N);
step++;
break;
case 1: /* A HIGH, B PWM LOW, C OFF */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_FORCE_HIGH);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_FROZEN);
timer_enable_oc_output(TIM1, TIM_OC1);
timer_enable_oc_output(TIM1, TIM_OC1N);
timer_disable_oc_output(TIM1, TIM_OC2);
timer_enable_oc_output(TIM1, TIM_OC2N);
timer_disable_oc_output(TIM1, TIM_OC3);
timer_disable_oc_output(TIM1, TIM_OC3N);
step++;
break;
case 2: /* A OFF, B LOW, C PWM HIGH */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_FROZEN);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_FORCE_LOW);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
timer_disable_oc_output(TIM1, TIM_OC1);
timer_disable_oc_output(TIM1, TIM_OC1N);
timer_enable_oc_output(TIM1, TIM_OC2);
timer_enable_oc_output(TIM1, TIM_OC2N);
timer_enable_oc_output(TIM1, TIM_OC3);
timer_disable_oc_output(TIM1, TIM_OC3N);
step++;
break;
case 3: /* A PWM LOW, B OFF, C HIGH */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_FROZEN);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_FORCE_HIGH);
timer_disable_oc_output(TIM1, TIM_OC1);
timer_enable_oc_output(TIM1, TIM_OC1N);
timer_disable_oc_output(TIM1, TIM_OC2);
timer_disable_oc_output(TIM1, TIM_OC2N);
timer_enable_oc_output(TIM1, TIM_OC3);
timer_enable_oc_output(TIM1, TIM_OC3N);
step++;
break;
case 4: /* A LOW, B PWM HIGH, C OFF */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_FORCE_LOW);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_FROZEN);
timer_enable_oc_output(TIM1, TIM_OC1);
timer_enable_oc_output(TIM1, TIM_OC1N);
timer_enable_oc_output(TIM1, TIM_OC2);
timer_disable_oc_output(TIM1, TIM_OC2N);
timer_disable_oc_output(TIM1, TIM_OC3);
timer_disable_oc_output(TIM1, TIM_OC3N);
step++;
break;
case 5: /* A OFF, B HIGH, C PWM LOW */
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_FROZEN);
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_FORCE_HIGH);
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
timer_disable_oc_output(TIM1, TIM_OC1);
timer_disable_oc_output(TIM1, TIM_OC1N);
timer_enable_oc_output(TIM1, TIM_OC2);
timer_enable_oc_output(TIM1, TIM_OC2N);
timer_disable_oc_output(TIM1, TIM_OC3);
timer_enable_oc_output(TIM1, TIM_OC3N);
step=0;
break;
}
gpio_toggle(GPIOC, GPIO12);
}
int main(void)
@ -200,6 +392,7 @@ int main(void)
clock_setup();
gpio_setup();
tim_setup();
exti_setup();
while (1) {
__asm("nop");

View File

@ -852,6 +852,8 @@ enum tim_oc_mode {
};
/* --- TIM functions ------------------------------------------------------- */
void timer_enable_irq(u32 timer_peripheral, u32 irq);
void timer_disable_irq(u32 timer_peripheral, u32 irq);
void timer_set_mode(u32 timer_peripheral, u8 clock_div,
u8 alignment, u8 direction);
void timer_set_clock_division(u32 timer_peripheral, u32 clock_div);
@ -908,5 +910,6 @@ void timer_set_enabled_off_state_in_idle_mode(u32 timer_peripheral);
void timer_set_disabled_off_state_in_idle_mode(u32 timer_peripheral);
void timer_set_break_lock(u32 timer_peripheral, u32 lock);
void timer_set_deadtime(u32 timer_peripheral, u32 deadtime);
void timer_generate_event(u32 timer_peripheral, u32 event);
#endif

View File

@ -27,6 +27,16 @@
#include <libopencm3/stm32/timer.h>
void timer_enable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) |= irq;
}
void timer_disable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) &= ~irq;
}
void timer_set_mode(u32 timer_peripheral, u8 clock_div,
u8 alignment, u8 direction)
{
@ -829,3 +839,8 @@ void timer_set_deadtime(u32 timer_peripheral, u32 deadtime)
TIM_BDTR(timer_peripheral) |= deadtime;
}
}
void timer_generate_event(u32 timer_peripheral, u32 event)
{
TIM_EGR(timer_peripheral) |= event;
}