Commit 0f654513 authored by Damien's avatar Damien
Browse files

Implement simple servo control using PWM.

parent 8b3a7c22
......@@ -62,6 +62,7 @@ SRC_STM = \
stm32f4xx_dma.c \
stm32f4xx_exti.c \
stm32f4xx_gpio.c \
stm32f4xx_tim.c \
stm_misc.c \
usb_core.c \
usb_dcd.c \
......
......@@ -88,7 +88,7 @@ int lcd_line;
int lcd_column;
int lcd_next_line;
void lcd_init() {
void lcd_init(void) {
// set the outputs high
PYB_LCD_PORT->BSRRL = PYB_LCD_CS1_PIN;
PYB_LCD_PORT->BSRRL = PYB_LCD_RST_PIN;
......
void lcd_init();
void lcd_init(void);
void lcd_print_str(const char *str);
void lcd_print_strn(const char *str, unsigned int len);
......@@ -9,7 +9,7 @@
#define PYB_LED_G1_PIN (GPIO_Pin_4)
#define PYB_LED_G2_PIN (GPIO_Pin_5)
void led_init() {
void led_init(void) {
// set the output high (so LED is off)
PYB_LED_R_PORT->BSRRL = PYB_LED_R1_PIN;
PYB_LED_R_PORT->BSRRL = PYB_LED_R2_PIN;
......
......@@ -5,6 +5,6 @@ typedef enum {
PYB_LED_G2 = 3,
} pyb_led_t;
void led_init();
void led_init(void);
void led_state(pyb_led_t led, int state);
void led_toggle(pyb_led_t led);
/**
******************************************************************************
* @file stm32f4xx_tim.c
* @author MCD Application Team
* @version V1.1.0
* @date 11-January-2013
* @brief This file provides firmware functions to manage the following
* functionalities of the TIM peripheral:
* + TimeBase management
* + Output Compare management
* + Input Capture management
* + Advanced-control timers (TIM1 and TIM8) specific features
* + Interrupts, DMA and flags management
* + Clocks management
* + Synchronization management
* + Specific interface management
* + Specific remapping management
*
@verbatim
===============================================================================
##### How to use this driver #####
===============================================================================
[..]
This driver provides functions to configure and program the TIM
of all STM32F4xx devices.
These functions are split in 9 groups:
(#) TIM TimeBase management: this group includes all needed functions
to configure the TM Timebase unit:
(++) Set/Get Prescaler
(++) Set/Get Autoreload
(++) Counter modes configuration
(++) Set Clock division
(++) Select the One Pulse mode
(++) Update Request Configuration
(++) Update Disable Configuration
(++) Auto-Preload Configuration
(++) Enable/Disable the counter
(#) TIM Output Compare management: this group includes all needed
functions to configure the Capture/Compare unit used in Output
compare mode:
(++) Configure each channel, independently, in Output Compare mode
(++) Select the output compare modes
(++) Select the Polarities of each channel
(++) Set/Get the Capture/Compare register values
(++) Select the Output Compare Fast mode
(++) Select the Output Compare Forced mode
(++) Output Compare-Preload Configuration
(++) Clear Output Compare Reference
(++) Select the OCREF Clear signal
(++) Enable/Disable the Capture/Compare Channels
(#) TIM Input Capture management: this group includes all needed
functions to configure the Capture/Compare unit used in
Input Capture mode:
(++) Configure each channel in input capture mode
(++) Configure Channel1/2 in PWM Input mode
(++) Set the Input Capture Prescaler
(++) Get the Capture/Compare values
(#) Advanced-control timers (TIM1 and TIM8) specific features
(++) Configures the Break input, dead time, Lock level, the OSSI,
the OSSR State and the AOE(automatic output enable)
(++) Enable/Disable the TIM peripheral Main Outputs
(++) Select the Commutation event
(++) Set/Reset the Capture Compare Preload Control bit
(#) TIM interrupts, DMA and flags management
(++) Enable/Disable interrupt sources
(++) Get flags status
(++) Clear flags/ Pending bits
(++) Enable/Disable DMA requests
(++) Configure DMA burst mode
(++) Select CaptureCompare DMA request
(#) TIM clocks management: this group includes all needed functions
to configure the clock controller unit:
(++) Select internal/External clock
(++) Select the external clock mode: ETR(Mode1/Mode2), TIx or ITRx
(#) TIM synchronization management: this group includes all needed
functions to configure the Synchronization unit:
(++) Select Input Trigger
(++) Select Output Trigger
(++) Select Master Slave Mode
(++) ETR Configuration when used as external trigger
(#) TIM specific interface management, this group includes all
needed functions to use the specific TIM interface:
(++) Encoder Interface Configuration
(++) Select Hall Sensor
(#) TIM specific remapping management includes the Remapping
configuration of specific timers
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_conf.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_rcc.h"
/** @addtogroup STM32F4xx_StdPeriph_Driver
* @{
*/
/** @defgroup TIM
* @brief TIM driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* ---------------------- TIM registers bit mask ------------------------ */
#define SMCR_ETR_MASK ((uint16_t)0x00FF)
#define CCMR_OFFSET ((uint16_t)0x0018)
#define CCER_CCE_SET ((uint16_t)0x0001)
#define CCER_CCNE_SET ((uint16_t)0x0004)
#define CCMR_OC13M_MASK ((uint16_t)0xFF8F)
#define CCMR_OC24M_MASK ((uint16_t)0x8FFF)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void TI1_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
uint16_t TIM_ICFilter);
static void TI2_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
uint16_t TIM_ICFilter);
static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
uint16_t TIM_ICFilter);
static void TI4_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
uint16_t TIM_ICFilter);
/* Private functions ---------------------------------------------------------*/
/** @defgroup TIM_Private_Functions
* @{
*/
/** @defgroup TIM_Group1 TimeBase management functions
* @brief TimeBase management functions
*
@verbatim
===============================================================================
##### TimeBase management functions #####
===============================================================================
##### TIM Driver: how to use it in Timing(Time base) Mode #####
===============================================================================
[..]
To use the Timer in Timing(Time base) mode, the following steps are mandatory:
(#) Enable TIM clock using RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function
(#) Fill the TIM_TimeBaseInitStruct with the desired parameters.
(#) Call TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStruct) to configure the Time Base unit
with the corresponding configuration
(#) Enable the NVIC if you need to generate the update interrupt.
(#) Enable the corresponding interrupt using the function TIM_ITConfig(TIMx, TIM_IT_Update)
(#) Call the TIM_Cmd(ENABLE) function to enable the TIM counter.
-@- All other functions can be used separately to modify, if needed,
a specific feature of the Timer.
@endverbatim
* @{
*/
/**
* @brief Deinitializes the TIMx peripheral registers to their default reset values.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @retval None
*/
void TIM_DeInit(TIM_TypeDef* TIMx)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
if (TIMx == TIM1)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE);
}
else if (TIMx == TIM2)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);
}
else if (TIMx == TIM3)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);
}
else if (TIMx == TIM4)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);
}
else if (TIMx == TIM5)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, DISABLE);
}
else if (TIMx == TIM6)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE);
}
else if (TIMx == TIM7)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
}
else if (TIMx == TIM8)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE);
}
else if (TIMx == TIM9)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, DISABLE);
}
else if (TIMx == TIM10)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, DISABLE);
}
else if (TIMx == TIM11)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, DISABLE);
}
else if (TIMx == TIM12)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, DISABLE);
}
else if (TIMx == TIM13)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, DISABLE);
}
else
{
if (TIMx == TIM14)
{
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, DISABLE);
}
}
}
/**
* @brief Initializes the TIMx Time Base Unit peripheral according to
* the specified parameters in the TIM_TimeBaseInitStruct.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef structure
* that contains the configuration information for the specified TIM peripheral.
* @retval None
*/
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
uint16_t tmpcr1 = 0;
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));
tmpcr1 = TIMx->CR1;
if((TIMx == TIM1) || (TIMx == TIM8)||
(TIMx == TIM2) || (TIMx == TIM3)||
(TIMx == TIM4) || (TIMx == TIM5))
{
/* Select the Counter Mode */
tmpcr1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS));
tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
}
if((TIMx != TIM6) && (TIMx != TIM7))
{
/* Set the clock division */
tmpcr1 &= (uint16_t)(~TIM_CR1_CKD);
tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
}
TIMx->CR1 = tmpcr1;
/* Set the Autoreload value */
TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
/* Set the Prescaler value */
TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
if ((TIMx == TIM1) || (TIMx == TIM8))
{
/* Set the Repetition Counter value */
TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
}
/* Generate an update event to reload the Prescaler
and the repetition counter(only for TIM1 and TIM8) value immediatly */
TIMx->EGR = TIM_PSCReloadMode_Immediate;
}
/**
* @brief Fills each TIM_TimeBaseInitStruct member with its default value.
* @param TIM_TimeBaseInitStruct : pointer to a TIM_TimeBaseInitTypeDef
* structure which will be initialized.
* @retval None
*/
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
/* Set the default configuration */
TIM_TimeBaseInitStruct->TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseInitStruct->TIM_Prescaler = 0x0000;
TIM_TimeBaseInitStruct->TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct->TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct->TIM_RepetitionCounter = 0x0000;
}
/**
* @brief Configures the TIMx Prescaler.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param Prescaler: specifies the Prescaler Register value
* @param TIM_PSCReloadMode: specifies the TIM Prescaler Reload mode
* This parameter can be one of the following values:
* @arg TIM_PSCReloadMode_Update: The Prescaler is loaded at the update event.
* @arg TIM_PSCReloadMode_Immediate: The Prescaler is loaded immediatly.
* @retval None
*/
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_TIM_PRESCALER_RELOAD(TIM_PSCReloadMode));
/* Set the Prescaler value */
TIMx->PSC = Prescaler;
/* Set or reset the UG Bit */
TIMx->EGR = TIM_PSCReloadMode;
}
/**
* @brief Specifies the TIMx Counter Mode to be used.
* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
* @param TIM_CounterMode: specifies the Counter Mode to be used
* This parameter can be one of the following values:
* @arg TIM_CounterMode_Up: TIM Up Counting Mode
* @arg TIM_CounterMode_Down: TIM Down Counting Mode
* @arg TIM_CounterMode_CenterAligned1: TIM Center Aligned Mode1
* @arg TIM_CounterMode_CenterAligned2: TIM Center Aligned Mode2
* @arg TIM_CounterMode_CenterAligned3: TIM Center Aligned Mode3
* @retval None
*/
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)
{
uint16_t tmpcr1 = 0;
/* Check the parameters */
assert_param(IS_TIM_LIST3_PERIPH(TIMx));
assert_param(IS_TIM_COUNTER_MODE(TIM_CounterMode));
tmpcr1 = TIMx->CR1;
/* Reset the CMS and DIR Bits */
tmpcr1 &= (uint16_t)~(TIM_CR1_DIR | TIM_CR1_CMS);
/* Set the Counter Mode */
tmpcr1 |= TIM_CounterMode;
/* Write to TIMx CR1 register */
TIMx->CR1 = tmpcr1;
}
/**
* @brief Sets the TIMx Counter Register value
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param Counter: specifies the Counter register new value.
* @retval None
*/
void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
/* Set the Counter Register value */
TIMx->CNT = Counter;
}
/**
* @brief Sets the TIMx Autoreload Register value
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param Autoreload: specifies the Autoreload register new value.
* @retval None
*/
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint32_t Autoreload)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
/* Set the Autoreload Register value */
TIMx->ARR = Autoreload;
}
/**
* @brief Gets the TIMx Counter value.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @retval Counter Register value
*/
uint32_t TIM_GetCounter(TIM_TypeDef* TIMx)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
/* Get the Counter Register value */
return TIMx->CNT;
}
/**
* @brief Gets the TIMx Prescaler value.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @retval Prescaler Register value.
*/
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
/* Get the Prescaler Register value */
return TIMx->PSC;
}
/**
* @brief Enables or Disables the TIMx Update event.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param NewState: new state of the TIMx UDIS bit
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Set the Update Disable Bit */
TIMx->CR1 |= TIM_CR1_UDIS;
}
else
{
/* Reset the Update Disable Bit */
TIMx->CR1 &= (uint16_t)~TIM_CR1_UDIS;
}
}
/**
* @brief Configures the TIMx Update Request Interrupt source.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param TIM_UpdateSource: specifies the Update source.
* This parameter can be one of the following values:
* @arg TIM_UpdateSource_Global: Source of update is the counter
* overflow/underflow or the setting of UG bit, or an update
* generation through the slave mode controller.
* @arg TIM_UpdateSource_Regular: Source of update is counter overflow/underflow.
* @retval None
*/
void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_TIM_UPDATE_SOURCE(TIM_UpdateSource));
if (TIM_UpdateSource != TIM_UpdateSource_Global)
{
/* Set the URS Bit */
TIMx->CR1 |= TIM_CR1_URS;
}
else
{
/* Reset the URS Bit */
TIMx->CR1 &= (uint16_t)~TIM_CR1_URS;
}
}
/**
* @brief Enables or disables TIMx peripheral Preload register on ARR.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param NewState: new state of the TIMx peripheral Preload register
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Set the ARR Preload Bit */
TIMx->CR1 |= TIM_CR1_ARPE;
}
else
{
/* Reset the ARR Preload Bit */
TIMx->CR1 &= (uint16_t)~TIM_CR1_ARPE;
}
}
/**
* @brief Selects the TIMx's One Pulse Mode.
* @param TIMx: where x can be 1 to 14 to select the TIM peripheral.
* @param TIM_OPMode: specifies the OPM Mode to be used.
* This parameter can be one of the following values:
* @arg TIM_OPMode_Single
* @arg TIM_OPMode_Repetitive
* @retval None
*/
void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
assert_param(IS_TIM_OPM_MODE(TIM_OPMode));
/* Reset the OPM Bit */
TIMx->CR1 &= (uint16_t)~TIM_CR1_OPM;
/* Configure the OPM Mode */
TIMx->CR1 |= TIM_OPMode;
}
/**
* @brief Sets the TIMx Clock Division value.
* @param TIMx: where x can be 1 to 14 except 6 and 7, to select the TIM peripheral.
* @param TIM_CKD: specifies the clock division value.
* This parameter can be one of the following value:
* @arg TIM_CKD_DIV1: TDTS = Tck_tim
* @arg TIM_CKD_DIV2: TDTS = 2*Tck_tim
* @arg TIM_CKD_DIV4: TDTS = 4*Tck_tim
* @retval None
*/
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD)
{
/* Check the parameters */
assert_param(IS_TIM_LIST1_PERIPH(TIMx));
assert_param(IS_TIM_CKD_DIV(TIM_CKD));
/* Reset the CKD Bits */
TIMx->CR1 &= (uint16_t)(~TIM_CR1_CKD);
/* Set the CKD value */
TIMx->CR1 |= TIM_CKD;
}
/**
* @brief Enables or disables the specified TIM peripheral.
* @param TIMx: where x can be 1 to 14 to select the TIMx peripheral.
* @param NewState: new state of the TIMx peripheral.