board/cpu: added pwm driver for stm32f4discovery

dev/timer
Hauke Petersen 9 years ago committed by Hauke Petersen
parent 60886c240f
commit cc6ee1dc05

@ -148,33 +148,40 @@
* @name PWM configuration
* @{
*/
#define PWM_NUMOF (0U) /* TODO !!!!!!! */
#define PWM_0_EN 0
#define PWM_1_EN 0
#define PWM_NUMOF (2U)
#define PWM_0_EN 1
#define PWM_1_EN 1
#define PWM_MAX_CHANNELS 4
/* PWM 0 device configuration */
#define PWM_0_DEV TIM1
#define PWM_0_CHANNELS 4
#define PWM_0_CLK (168000000U)
#define PWM_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_TIM1EN)
#define PWM_0_CLKDIS() (RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN)
/* PWM 0 pin configuration */
#define PWM_0_PORT
#define PWM_0_PINS
#define PWM_0_PORT_CLKEN()
#define PWM_0_CH1_AFCFG()
#define PWM_0_CH2_AFCFG()
#define PWM_0_CH3_AFCFG()
#define PWM_0_CH4_AFCFG()
#define PWM_0_PORT GPIOE
#define PWM_0_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN)
#define PWM_0_PIN_CH0 9
#define PWM_0_PIN_CH1 11
#define PWM_0_PIN_CH2 13
#define PWM_0_PIN_CH3 14
#define PWM_0_PIN_AF 1
/* PWM 1 device configuration */
#define PWM_1_DEV TIM3
#define PWM_1_CHANNELS 4
#define PWM_1_CHANNELS 3
#define PWM_1_CLK (84000000U)
#define PWM_1_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_TIM3EN)
#define PWM_1_CLKDIS() (RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN)
/* PWM 1 pin configuration */
#define PWM_1_PORT
#define PWM_1_PINS
#define PWM_1_PORT_CLKEN()
#define PWM_1_CH1_AFCFG()
#define PWM_1_CH2_AFCFG()
#define PWM_1_CH3_AFCFG()
#define PWM_1_CH4_AFCFG()
#define PWM_1_PORT GPIOB
#define PWM_1_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN)
#define PWM_1_PIN_CH0 4
#define PWM_1_PIN_CH1 5
#define PWM_1_PIN_CH2 0
#define PWM_1_PIN_CH3 1
#define PWM_1_PIN_AF 2
/** @} */

@ -0,0 +1,242 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_stm32f4
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Hauke Petersen <mail@haukepetersen.de>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "cpu.h"
#include "periph/pwm.h"
#include "periph_conf.h"
/* ignore file in case no PWM devices are defined */
#if PWM_NUMOF
int pwm_init(pwm_t dev, pwm_mode_t mode, unsigned int frequency, unsigned int resolution)
{
TIM_TypeDef *tim = NULL;
GPIO_TypeDef *port = NULL;
uint32_t pins[PWM_MAX_CHANNELS];
uint32_t af = 0;
int channels = 0;
uint32_t pwm_clk = 0;
pwm_poweron(dev);
switch (dev) {
#if PWM_0_EN
case PWM_0:
tim = PWM_0_DEV;
port = PWM_0_PORT;
pins[0] = PWM_0_PIN_CH0;
pins[1] = PWM_0_PIN_CH1;
pins[2] = PWM_0_PIN_CH2;
pins[3] = PWM_0_PIN_CH3;
af = PWM_0_PIN_AF;
channels = PWM_0_CHANNELS;
pwm_clk = PWM_0_CLK;
PWM_0_PORT_CLKEN();
break;
#endif
#if PWM_1_EN
case PWM_1:
tim = PWM_1_DEV;
port = PWM_1_PORT;
pins[0] = PWM_1_PIN_CH0;
pins[1] = PWM_1_PIN_CH1;
pins[2] = PWM_1_PIN_CH2;
pins[3] = PWM_1_PIN_CH3;
af = PWM_1_PIN_AF;
channels = PWM_1_CHANNELS;
pwm_clk = PWM_1_CLK;
PWM_1_PORT_CLKEN();
break;
#endif
}
/* setup pins: alternate function */
for (int i = 0; i < channels; i++) {
port->MODER &= ~(3 << (pins[i] * 2));
port->MODER |= (2 << (pins[i] * 2));
if (pins[i] < 8) {
port->AFR[0] &= ~(0xf << (pins[i] * 4));
port->AFR[0] |= (af << (pins[i] * 4));
} else {
port->AFR[1] &= ~(0xf << ((pins[i] - 8) * 4));
port->AFR[1] |= (af << ((pins[i] - 8) * 4));
}
}
/* reset timer configuration registers */
tim->CR1 = 0;
tim->CR2 = 0;
tim->CCMR1 = 0;
tim->CCMR2 = 0;
/* set c/c register to initial 0 */
tim->CCR1 = 0;
tim->CCR2 = 0;
tim->CCR3 = 0;
tim->CCR4 = 0;
/* set prescale and auto-reload registers to matching values for resolution and frequency */
if (resolution > 0xffff || (resolution * frequency) > pwm_clk) {
return -2;
}
tim->PSC = (pwm_clk / (resolution * frequency)) - 1;
tim->ARR = resolution - 1;
/* set PWM mode */
switch (mode) {
case PWM_LEFT:
tim->CCMR1 |= (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 |
TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2);
tim->CCMR2 |= (TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 |
TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2);
break;
case PWM_RIGHT:
tim->CCMR1 |= (TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 |
TIM_CCMR1_OC2M_0 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2);
tim->CCMR2 |= (TIM_CCMR2_OC3M_0 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 |
TIM_CCMR2_OC4M_0 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2);
break;
case PWM_CENTER:
tim->CR1 |= (TIM_CR1_CMS_0 | TIM_CR1_CMS_1);
break;
}
/* enable output on PWM pins */
tim->CCER = (TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E);
/* enable PWM outputs */
tim->BDTR = TIM_BDTR_MOE;
/* enable timer ergo the PWM generation */
pwm_start(dev);
return 0;
}
int pwm_set(pwm_t dev, int channel, unsigned int value)
{
TIM_TypeDef *tim = NULL;
switch (dev) {
#if PWM_0_EN
case PWM_0:
tim = PWM_0_DEV;
break;
#endif
#if PWM_1_EN
case PWM_1:
tim = PWM_1_DEV;
break;
#endif
}
/* norm value to maximum possible value */
if (value > 0xffff) {
value = 0xffff;
}
switch (channel) {
case 0:
tim->CCR1 = value;
break;
case 1:
tim->CCR2 = value;
break;
case 2:
tim->CCR3 = value;
break;
case 3:
tim->CCR4 = value;
break;
default:
return -1;
}
return 0;
}
void pwm_start(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_DEV->CR1 |= TIM_CR1_CEN;
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_DEV->CR1 |= TIM_CR1_CEN;
break;
#endif
}
}
void pwm_stop(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_DEV->CR1 &= ~(TIM_CR1_CEN);
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_DEV->CR1 &= ~(TIM_CR1_CEN);
break;
#endif
}
}
void pwm_poweron(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_CLKEN();
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_CLKEN();
break;
#endif
}
}
void pwm_poweroff(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_CLKDIS();
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_CLKDIS();
break;
#endif
}
}
#endif /* PWM_NUMOF */
Loading…
Cancel
Save