git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6136 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2013-08-11 14:09:37 +00:00
parent 130f205cc9
commit 094e7be39a
7 changed files with 3933 additions and 0 deletions

View File

@ -0,0 +1,763 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file STM32/gpt_lld.c
* @brief STM32 GPT subsystem low level driver source.
*
* @addtogroup GPT
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPTD1 driver identifier.
* @note The driver GPTD1 allocates the complex timer TIM1 when enabled.
*/
#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPTD2 driver identifier.
* @note The driver GPTD2 allocates the timer TIM2 when enabled.
*/
#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPTD3 driver identifier.
* @note The driver GPTD3 allocates the timer TIM3 when enabled.
*/
#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPTD4 driver identifier.
* @note The driver GPTD4 allocates the timer TIM4 when enabled.
*/
#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
/**
* @brief GPTD5 driver identifier.
* @note The driver GPTD5 allocates the timer TIM5 when enabled.
*/
#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__)
GPTDriver GPTD5;
#endif
/**
* @brief GPTD6 driver identifier.
* @note The driver GPTD6 allocates the timer TIM6 when enabled.
*/
#if STM32_GPT_USE_TIM6 || defined(__DOXYGEN__)
GPTDriver GPTD6;
#endif
/**
* @brief GPTD7 driver identifier.
* @note The driver GPTD7 allocates the timer TIM7 when enabled.
*/
#if STM32_GPT_USE_TIM7 || defined(__DOXYGEN__)
GPTDriver GPTD7;
#endif
/**
* @brief GPTD8 driver identifier.
* @note The driver GPTD8 allocates the timer TIM8 when enabled.
*/
#if STM32_GPT_USE_TIM8 || defined(__DOXYGEN__)
GPTDriver GPTD8;
#endif
/**
* @brief GPTD9 driver identifier.
* @note The driver GPTD9 allocates the timer TIM9 when enabled.
*/
#if STM32_GPT_USE_TIM9 || defined(__DOXYGEN__)
GPTDriver GPTD9;
#endif
/**
* @brief GPTD11 driver identifier.
* @note The driver GPTD11 allocates the timer TIM11 when enabled.
*/
#if STM32_GPT_USE_TIM11 || defined(__DOXYGEN__)
GPTDriver GPTD11;
#endif
/**
* @brief GPTD12 driver identifier.
* @note The driver GPTD12 allocates the timer TIM12 when enabled.
*/
#if STM32_GPT_USE_TIM12 || defined(__DOXYGEN__)
GPTDriver GPTD12;
#endif
/**
* @brief GPTD14 driver identifier.
* @note The driver GPTD14 allocates the timer TIM14 when enabled.
*/
#if STM32_GPT_USE_TIM14 || defined(__DOXYGEN__)
GPTDriver GPTD14;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] gptp pointer to a @p GPTDriver object
*/
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->tim->SR = 0;
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->config->callback(gptp);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if STM32_GPT_USE_TIM1
#if !defined(STM32_TIM1_UP_HANDLER)
#error "STM32_TIM1_UP_HANDLER not defined"
#endif
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM1 */
#if STM32_GPT_USE_TIM2
#if !defined(STM32_TIM2_HANDLER)
#error "STM32_TIM2_HANDLER not defined"
#endif
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM2_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM2 */
#if STM32_GPT_USE_TIM3
#if !defined(STM32_TIM3_HANDLER)
#error "STM32_TIM3_HANDLER not defined"
#endif
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM3_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM3 */
#if STM32_GPT_USE_TIM4
#if !defined(STM32_TIM4_HANDLER)
#error "STM32_TIM4_HANDLER not defined"
#endif
/**
* @brief TIM4 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM4_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM4 */
#if STM32_GPT_USE_TIM5
#if !defined(STM32_TIM5_HANDLER)
#error "STM32_TIM5_HANDLER not defined"
#endif
/**
* @brief TIM5 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM5_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD5);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM5 */
#if STM32_GPT_USE_TIM6
#if !defined(STM32_TIM6_HANDLER)
#error "STM32_TIM6_HANDLER not defined"
#endif
/**
* @brief TIM6 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM6_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD6);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM6 */
#if STM32_GPT_USE_TIM7
#if !defined(STM32_TIM7_HANDLER)
#error "STM32_TIM7_HANDLER not defined"
#endif
/**
* @brief TIM7 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM7_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD7);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM7 */
#if STM32_GPT_USE_TIM8
#if !defined(STM32_TIM8_UP_HANDLER)
#error "STM32_TIM8_UP_HANDLER not defined"
#endif
/**
* @brief TIM8 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD8);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM8 */
#if STM32_GPT_USE_TIM9
#if !defined(STM32_TIM9_HANDLER)
#error "STM32_TIM9_HANDLER not defined"
#endif
/**
* @brief TIM9 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM9_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD9);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM9 */
#if STM32_GPT_USE_TIM11
#if !defined(STM32_TIM11_HANDLER)
#error "STM32_TIM11_HANDLER not defined"
#endif
/**
* @brief TIM11 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM11_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD11);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM11 */
#if STM32_GPT_USE_TIM12
#if !defined(STM32_TIM12_HANDLER)
#error "STM32_TIM12_HANDLER not defined"
#endif
/**
* @brief TIM12 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM12_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD12);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM12 */
#if STM32_GPT_USE_TIM14
#if !defined(STM32_TIM14_HANDLER)
#error "STM32_TIM14_HANDLER not defined"
#endif
/**
* @brief TIM14 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM14_HANDLER) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD14);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_GPT_USE_TIM14 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if STM32_GPT_USE_TIM1
/* Driver initialization.*/
GPTD1.tim = STM32_TIM1;
gptObjectInit(&GPTD1);
#endif
#if STM32_GPT_USE_TIM2
/* Driver initialization.*/
GPTD2.tim = STM32_TIM2;
gptObjectInit(&GPTD2);
#endif
#if STM32_GPT_USE_TIM3
/* Driver initialization.*/
GPTD3.tim = STM32_TIM3;
gptObjectInit(&GPTD3);
#endif
#if STM32_GPT_USE_TIM4
/* Driver initialization.*/
GPTD4.tim = STM32_TIM4;
gptObjectInit(&GPTD4);
#endif
#if STM32_GPT_USE_TIM5
/* Driver initialization.*/
GPTD5.tim = STM32_TIM5;
gptObjectInit(&GPTD5);
#endif
#if STM32_GPT_USE_TIM6
/* Driver initialization.*/
GPTD6.tim = STM32_TIM6;
gptObjectInit(&GPTD6);
#endif
#if STM32_GPT_USE_TIM7
/* Driver initialization.*/
GPTD7.tim = STM32_TIM7;
gptObjectInit(&GPTD7);
#endif
#if STM32_GPT_USE_TIM8
/* Driver initialization.*/
GPTD8.tim = STM32_TIM8;
gptObjectInit(&GPTD8);
#endif
#if STM32_GPT_USE_TIM9
/* Driver initialization.*/
GPTD9.tim = STM32_TIM9;
gptObjectInit(&GPTD9);
#endif
#if STM32_GPT_USE_TIM11
/* Driver initialization.*/
GPTD11.tim = STM32_TIM11;
gptObjectInit(&GPTD11);
#endif
#if STM32_GPT_USE_TIM12
/* Driver initialization.*/
GPTD12.tim = STM32_TIM12;
gptObjectInit(&GPTD12);
#endif
#if STM32_GPT_USE_TIM14
/* Driver initialization.*/
GPTD14.tim = STM32_TIM14;
gptObjectInit(&GPTD14);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint16_t psc;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
#if STM32_GPT_USE_TIM1
if (&GPTD1 == gptp) {
rccEnableTIM1(FALSE);
rccResetTIM1();
nvicEnableVector(STM32_TIM1_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM1_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_GPT_USE_TIM2
if (&GPTD2 == gptp) {
rccEnableTIM2(FALSE);
rccResetTIM2();
nvicEnableVector(STM32_TIM2_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM2_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM3
if (&GPTD3 == gptp) {
rccEnableTIM3(FALSE);
rccResetTIM3();
nvicEnableVector(STM32_TIM3_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM3_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM4
if (&GPTD4 == gptp) {
rccEnableTIM4(FALSE);
rccResetTIM4();
nvicEnableVector(STM32_TIM4_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM4_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM5
if (&GPTD5 == gptp) {
rccEnableTIM5(FALSE);
rccResetTIM5();
nvicEnableVector(STM32_TIM5_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM5_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM6
if (&GPTD6 == gptp) {
rccEnableTIM6(FALSE);
rccResetTIM6();
nvicEnableVector(STM32_TIM6_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM6_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM7
if (&GPTD7 == gptp) {
rccEnableTIM7(FALSE);
rccResetTIM7();
nvicEnableVector(STM32_TIM7_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM7_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM8
if (&GPTD8 == gptp) {
rccEnableTIM8(FALSE);
rccResetTIM8();
nvicEnableVector(STM32_TIM8_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM8_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_GPT_USE_TIM9
if (&GPTD9 == gptp) {
rccEnableTIM9(FALSE);
rccResetTIM9();
nvicEnableVector(STM32_TIM9_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM9_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_GPT_USE_TIM11
if (&GPTD11 == gptp) {
rccEnableTIM11(FALSE);
rccResetTIM11();
nvicEnableVector(STM32_TIM11_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM11_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_GPT_USE_TIM12
if (&GPTD12 == gptp) {
rccEnableTIM12(FALSE);
rccResetTIM12();
nvicEnableVector(STM32_TIM12_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM12_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_GPT_USE_TIM14
if (&GPTD14 == gptp) {
rccEnableTIM14(FALSE);
rccResetTIM14();
nvicEnableVector(STM32_TIM14_NUMBER,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM14_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
}
#endif
}
/* Prescaler value calculation.*/
psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1);
chDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock,
"gpt_lld_start(), #1", "invalid frequency");
/* Timer configuration.*/
gptp->tim->CR1 = 0; /* Initially stopped. */
gptp->tim->CR2 = STM32_TIM_CR2_CCDS; /* DMA on UE (if any). */
gptp->tim->PSC = psc; /* Prescaler value. */
gptp->tim->DIER = 0;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
if (gptp->state == GPT_READY) {
gptp->tim->CR1 = 0; /* Timer disabled. */
gptp->tim->DIER = 0; /* All IRQs disabled. */
gptp->tim->SR = 0; /* Clear eventual pending IRQs. */
#if STM32_GPT_USE_TIM1
if (&GPTD1 == gptp) {
nvicDisableVector(STM32_TIM1_UP_NUMBER);
rccDisableTIM1(FALSE);
}
#endif
#if STM32_GPT_USE_TIM2
if (&GPTD2 == gptp) {
nvicDisableVector(STM32_TIM2_NUMBER);
rccDisableTIM2(FALSE);
}
#endif
#if STM32_GPT_USE_TIM3
if (&GPTD3 == gptp) {
nvicDisableVector(STM32_TIM3_NUMBER);
rccDisableTIM3(FALSE);
}
#endif
#if STM32_GPT_USE_TIM4
if (&GPTD4 == gptp) {
nvicDisableVector(STM32_TIM4_NUMBER);
rccDisableTIM4(FALSE);
}
#endif
#if STM32_GPT_USE_TIM5
if (&GPTD5 == gptp) {
nvicDisableVector(STM32_TIM5_NUMBER);
rccDisableTIM5(FALSE);
}
#endif
#if STM32_GPT_USE_TIM6
if (&GPTD6 == gptp) {
nvicDisableVector(STM32_TIM6_NUMBER);
rccDisableTIM6(FALSE);
}
#endif
#if STM32_GPT_USE_TIM7
if (&GPTD7 == gptp) {
nvicDisableVector(STM32_TIM7_NUMBER);
rccDisableTIM7(FALSE);
}
#endif
#if STM32_GPT_USE_TIM8
if (&GPTD8 == gptp) {
nvicDisableVector(STM32_TIM8_UP_NUMBER);
rccDisableTIM8(FALSE);
}
#endif
#if STM32_GPT_USE_TIM9
if (&GPTD9 == gptp) {
nvicDisableVector(STM32_TIM9_NUMBER);
rccDisableTIM9(FALSE);
}
#endif
#if STM32_GPT_USE_TIM11
if (&GPTD11 == gptp) {
nvicDisableVector(STM32_TIM11_NUMBER);
rccDisableTIM11(FALSE);
}
#endif
#if STM32_GPT_USE_TIM12
if (&GPTD12 == gptp) {
nvicDisableVector(STM32_TIM12_NUMBER);
rccDisableTIM12(FALSE);
}
#endif
#if STM32_GPT_USE_TIM14
if (&GPTD14 == gptp) {
nvicDisableVector(STM32_TIM14_NUMBER);
rccDisableTIM14(FALSE);
}
#endif
}
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tim->ARR = interval - 1; /* Time constant. */
gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
gptp->tim->CNT = 0; /* Reset counter. */
/* NOTE: After generating the UG event it takes several clock cycles before
SR bit 0 goes to 1. This is because the clearing of CNT has been inserted
before the clearing of SR, to give it some time.*/
gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
gptp->tim->DIER = STM32_TIM_DIER_UIE; /* Update Event IRQ enabled. */
gptp->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
gptp->tim->CR1 = 0; /* Initially stopped. */
gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
gptp->tim->DIER = 0; /* Interrupts disabled. */
}
/**
* @brief Starts the timer in one shot mode and waits for completion.
* @details This function specifically polls the timer waiting for completion
* in order to not have extra delays caused by interrupt servicing,
* this function is only recommended for short delays.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] interval time interval in ticks
*
* @notapi
*/
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) {
gptp->tim->ARR = interval - 1; /* Time constant. */
gptp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
gptp->tim->CR1 = STM32_TIM_CR1_OPM | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
while (!(gptp->tim->SR & STM32_TIM_SR_UIF))
;
}
#endif /* HAL_USE_GPT */
/** @} */

View File

@ -0,0 +1,506 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file STM32/gpt_lld.h
* @brief STM32 GPT subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef _GPT_LLD_H_
#define _GPT_LLD_H_
#include "stm32_tim.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief GPTD1 driver enable switch.
* @details If set to @p TRUE the support for GPTD1 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM1) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM1 FALSE
#endif
/**
* @brief GPTD2 driver enable switch.
* @details If set to @p TRUE the support for GPTD2 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM2) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM2 FALSE
#endif
/**
* @brief GPTD3 driver enable switch.
* @details If set to @p TRUE the support for GPTD3 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM3) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM3 FALSE
#endif
/**
* @brief GPTD4 driver enable switch.
* @details If set to @p TRUE the support for GPTD4 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM4) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM4 FALSE
#endif
/**
* @brief GPTD5 driver enable switch.
* @details If set to @p TRUE the support for GPTD5 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM5) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM5 FALSE
#endif
/**
* @brief GPTD6 driver enable switch.
* @details If set to @p TRUE the support for GPTD6 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM6) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM6 FALSE
#endif
/**
* @brief GPTD7 driver enable switch.
* @details If set to @p TRUE the support for GPTD7 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM7) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM7 FALSE
#endif
/**
* @brief GPTD8 driver enable switch.
* @details If set to @p TRUE the support for GPTD8 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM8) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM8 FALSE
#endif
/**
* @brief GPTD9 driver enable switch.
* @details If set to @p TRUE the support for GPTD9 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM9) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM9 FALSE
#endif
/**
* @brief GPTD11 driver enable switch.
* @details If set to @p TRUE the support for GPTD11 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM11) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM11 FALSE
#endif
/**
* @brief GPTD12 driver enable switch.
* @details If set to @p TRUE the support for GPTD12 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM12) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM12 FALSE
#endif
/**
* @brief GPTD14 driver enable switch.
* @details If set to @p TRUE the support for GPTD14 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_GPT_USE_TIM14) || defined(__DOXYGEN__)
#define STM32_GPT_USE_TIM14 FALSE
#endif
/**
* @brief GPTD1 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM1_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD2 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM2_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD3 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM3_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD4 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM4_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD5 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM5_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD6 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM6_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM6_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD7 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM7_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM7_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD8 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM8_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD9 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM9_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD11 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM11_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM11_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD12 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM12_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM12_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD14 interrupt priority level setting.
*/
#if !defined(STM32_GPT_TIM14_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM14_IRQ_PRIORITY 7
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if STM32_GPT_USE_TIM1 && !STM32_HAS_TIM1
#error "TIM1 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM2 && !STM32_HAS_TIM2
#error "TIM2 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM3 && !STM32_HAS_TIM3
#error "TIM3 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM4 && !STM32_HAS_TIM4
#error "TIM4 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM5 && !STM32_HAS_TIM5
#error "TIM5 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM6 && !STM32_HAS_TIM6
#error "TIM6 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM7 && !STM32_HAS_TIM7
#error "TIM7 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM8 && !STM32_HAS_TIM8
#error "TIM8 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM9 && !STM32_HAS_TIM9
#error "TIM9 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM11 && !STM32_HAS_TIM11
#error "TIM11 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM12 && !STM32_HAS_TIM12
#error "TIM12 not present in the selected device"
#endif
#if STM32_GPT_USE_TIM14 && !STM32_HAS_TIM14
#error "TIM14 not present in the selected device"
#endif
#if !STM32_GPT_USE_TIM1 && !STM32_GPT_USE_TIM2 && \
!STM32_GPT_USE_TIM3 && !STM32_GPT_USE_TIM4 && \
!STM32_GPT_USE_TIM5 && !STM32_GPT_USE_TIM6 && \
!STM32_GPT_USE_TIM7 && !STM32_GPT_USE_TIM8 && \
!STM32_GPT_USE_TIM9 && !STM32_GPT_USE_TIM11 && \
!STM32_GPT_USE_TIM12 && !STM32_GPT_USE_TIM14
#error "GPT driver activated but no TIM peripheral assigned"
#endif
#if STM32_GPT_USE_TIM1 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM1"
#endif
#if STM32_GPT_USE_TIM2 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM2"
#endif
#if STM32_GPT_USE_TIM3 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM3"
#endif
#if STM32_GPT_USE_TIM4 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM4_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM4"
#endif
#if STM32_GPT_USE_TIM5 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM5_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM5"
#endif
#if STM32_GPT_USE_TIM6 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM6_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM6"
#endif
#if STM32_GPT_USE_TIM7 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM7_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM7"
#endif
#if STM32_GPT_USE_TIM8 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM8_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM8"
#endif
#if STM32_GPT_USE_TIM9 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM9_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM9"
#endif
#if STM32_GPT_USE_TIM11 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM11_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM11"
#endif
#if STM32_GPT_USE_TIM12 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM12_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM12"
#endif
#if STM32_GPT_USE_TIM14 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_GPT_TIM14_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM14"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief GPT frequency type.
*/
typedef uint32_t gptfreq_t;
/**
* @brief GPT counter type.
*/
typedef uint16_t gptcnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
gptfreq_t frequency;
/**
* @brief Timer callback pointer.
* @note This callback is invoked on GPT counter events.
*/
gptcallback_t callback;
/* End of the mandatory fields.*/
} GPTConfig;
/**
* @brief Structure representing a GPT driver.
*/
struct GPTDriver {
/**
* @brief Driver state.
*/
gptstate_t state;
/**
* @brief Current configuration data.
*/
const GPTConfig *config;
#if defined(GPT_DRIVER_EXT_FIELDS)
GPT_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the TIMx registers block.
*/
stm32_tim_t *tim;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Changes the interval of GPT peripheral.
* @details This function changes the interval of a running GPT unit.
* @pre The GPT unit must have been activated using @p gptStart().
* @pre The GPT unit must have been running in continuous mode using
* @p gptStartContinuous().
* @post The GPT unit interval is changed to the new value.
* @note The function has effect at the next cycle start.
*
* @param[in] gptp pointer to a @p GPTDriver object
* @param[in] interval new cycle time in timer ticks
* @notapi
*/
#define gpt_lld_change_interval(gptp, interval) \
((gptp)->tim->ARR = (uint16_t)((interval) - 1))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if STM32_GPT_USE_TIM1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if STM32_GPT_USE_TIM2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if STM32_GPT_USE_TIM3 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if STM32_GPT_USE_TIM4 && !defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#if STM32_GPT_USE_TIM5 && !defined(__DOXYGEN__)
extern GPTDriver GPTD5;
#endif
#if STM32_GPT_USE_TIM6 && !defined(__DOXYGEN__)
extern GPTDriver GPTD6;
#endif
#if STM32_GPT_USE_TIM7 && !defined(__DOXYGEN__)
extern GPTDriver GPTD7;
#endif
#if STM32_GPT_USE_TIM8 && !defined(__DOXYGEN__)
extern GPTDriver GPTD8;
#endif
#if STM32_GPT_USE_TIM9 && !defined(__DOXYGEN__)
extern GPTDriver GPTD9;
#endif
#if STM32_GPT_USE_TIM11 && !defined(__DOXYGEN__)
extern GPTDriver GPTD11;
#endif
#if STM32_GPT_USE_TIM12 && !defined(__DOXYGEN__)
extern GPTDriver GPTD12;
#endif
#if STM32_GPT_USE_TIM14 && !defined(__DOXYGEN__)
extern GPTDriver GPTD14;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void gpt_lld_init(void);
void gpt_lld_start(GPTDriver *gptp);
void gpt_lld_stop(GPTDriver *gptp);
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period);
void gpt_lld_stop_timer(GPTDriver *gptp);
void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_GPT */
#endif /* _GPT_LLD_H_ */
/** @} */

View File

@ -0,0 +1,641 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/*
Concepts and parts of this file have been contributed by Fabio Utzig and
Xo Wang.
*/
/**
* @file STM32/icu_lld.c
* @brief STM32 ICU subsystem low level driver header.
*
* @addtogroup ICU
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_ICU || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief ICUD1 driver identifier.
* @note The driver ICUD1 allocates the complex timer TIM1 when enabled.
*/
#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__)
ICUDriver ICUD1;
#endif
/**
* @brief ICUD2 driver identifier.
* @note The driver ICUD1 allocates the timer TIM2 when enabled.
*/
#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__)
ICUDriver ICUD2;
#endif
/**
* @brief ICUD3 driver identifier.
* @note The driver ICUD1 allocates the timer TIM3 when enabled.
*/
#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__)
ICUDriver ICUD3;
#endif
/**
* @brief ICUD4 driver identifier.
* @note The driver ICUD4 allocates the timer TIM4 when enabled.
*/
#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__)
ICUDriver ICUD4;
#endif
/**
* @brief ICUD5 driver identifier.
* @note The driver ICUD5 allocates the timer TIM5 when enabled.
*/
#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__)
ICUDriver ICUD5;
#endif
/**
* @brief ICUD8 driver identifier.
* @note The driver ICUD8 allocates the timer TIM8 when enabled.
*/
#if STM32_ICU_USE_TIM8 || defined(__DOXYGEN__)
ICUDriver ICUD8;
#endif
/**
* @brief ICUD9 driver identifier.
* @note The driver ICUD9 allocates the timer TIM9 when enabled.
*/
#if STM32_ICU_USE_TIM9 || defined(__DOXYGEN__)
ICUDriver ICUD9;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
*
* @param[in] icup pointer to the @p ICUDriver object
*/
static void icu_lld_serve_interrupt(ICUDriver *icup) {
uint16_t sr;
sr = icup->tim->SR;
sr &= icup->tim->DIER;
icup->tim->SR = ~sr;
if (icup->config->channel == ICU_CHANNEL_1) {
if ((sr & STM32_TIM_SR_CC1IF) != 0)
_icu_isr_invoke_period_cb(icup);
if ((sr & STM32_TIM_SR_CC2IF) != 0)
_icu_isr_invoke_width_cb(icup);
} else {
if ((sr & STM32_TIM_SR_CC1IF) != 0)
_icu_isr_invoke_width_cb(icup);
if ((sr & STM32_TIM_SR_CC2IF) != 0)
_icu_isr_invoke_period_cb(icup);
}
if ((sr & STM32_TIM_SR_UIF) != 0)
_icu_isr_invoke_overflow_cb(icup);
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if STM32_ICU_USE_TIM1
#if !defined(STM32_TIM1_UP_HANDLER)
#error "STM32_TIM1_UP_HANDLER not defined"
#endif
/**
* @brief TIM1 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD1);
CH_IRQ_EPILOGUE();
}
#if !defined(STM32_TIM1_CC_HANDLER)
#error "STM32_TIM1_CC_HANDLER not defined"
#endif
/**
* @brief TIM1 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD1);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM1 */
#if STM32_ICU_USE_TIM2
#if !defined(STM32_TIM2_HANDLER)
#error "STM32_TIM2_HANDLER not defined"
#endif
/**
* @brief TIM2 interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM2_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD2);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM2 */
#if STM32_ICU_USE_TIM3
#if !defined(STM32_TIM3_HANDLER)
#error "STM32_TIM3_HANDLER not defined"
#endif
/**
* @brief TIM3 interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM3_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD3);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM3 */
#if STM32_ICU_USE_TIM4
#if !defined(STM32_TIM4_HANDLER)
#error "STM32_TIM4_HANDLER not defined"
#endif
/**
* @brief TIM4 interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM4_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD4);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM4 */
#if STM32_ICU_USE_TIM5
#if !defined(STM32_TIM5_HANDLER)
#error "STM32_TIM5_HANDLER not defined"
#endif
/**
* @brief TIM5 interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM5_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD5);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM5 */
#if STM32_ICU_USE_TIM8
#if !defined(STM32_TIM8_UP_HANDLER)
#error "STM32_TIM8_UP_HANDLER not defined"
#endif
/**
* @brief TIM8 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD8);
CH_IRQ_EPILOGUE();
}
#if !defined(STM32_TIM8_CC_HANDLER)
#error "STM32_TIM8_CC_HANDLER not defined"
#endif
/**
* @brief TIM8 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD8);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM8 */
#if STM32_ICU_USE_TIM9
#if !defined(STM32_TIM9_HANDLER)
#error "STM32_TIM9_HANDLER not defined"
#endif
/**
* @brief TIM9 interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM9_HANDLER) {
CH_IRQ_PROLOGUE();
icu_lld_serve_interrupt(&ICUD9);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_ICU_USE_TIM9 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ICU driver initialization.
*
* @notapi
*/
void icu_lld_init(void) {
#if STM32_ICU_USE_TIM1
/* Driver initialization.*/
icuObjectInit(&ICUD1);
ICUD1.tim = STM32_TIM1;
#endif
#if STM32_ICU_USE_TIM2
/* Driver initialization.*/
icuObjectInit(&ICUD2);
ICUD2.tim = STM32_TIM2;
#endif
#if STM32_ICU_USE_TIM3
/* Driver initialization.*/
icuObjectInit(&ICUD3);
ICUD3.tim = STM32_TIM3;
#endif
#if STM32_ICU_USE_TIM4
/* Driver initialization.*/
icuObjectInit(&ICUD4);
ICUD4.tim = STM32_TIM4;
#endif
#if STM32_ICU_USE_TIM5
/* Driver initialization.*/
icuObjectInit(&ICUD5);
ICUD5.tim = STM32_TIM5;
#endif
#if STM32_ICU_USE_TIM8
/* Driver initialization.*/
icuObjectInit(&ICUD8);
ICUD8.tim = STM32_TIM8;
#endif
#if STM32_ICU_USE_TIM9
/* Driver initialization.*/
icuObjectInit(&ICUD9);
ICUD9.tim = STM32_TIM9;
#endif
}
/**
* @brief Configures and activates the ICU peripheral.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_start(ICUDriver *icup) {
uint32_t psc;
chDbgAssert((icup->config->channel == ICU_CHANNEL_1) ||
(icup->config->channel == ICU_CHANNEL_2),
"icu_lld_start(), #1", "invalid input");
if (icup->state == ICU_STOP) {
/* Clock activation and timer reset.*/
#if STM32_ICU_USE_TIM1
if (&ICUD1 == icup) {
rccEnableTIM1(FALSE);
rccResetTIM1();
nvicEnableVector(STM32_TIM1_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
nvicEnableVector(STM32_TIM1_CC_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK2;
}
#endif
#if STM32_ICU_USE_TIM2
if (&ICUD2 == icup) {
rccEnableTIM2(FALSE);
rccResetTIM2();
nvicEnableVector(STM32_TIM2_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM2_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM3
if (&ICUD3 == icup) {
rccEnableTIM3(FALSE);
rccResetTIM3();
nvicEnableVector(STM32_TIM3_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM3_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM4
if (&ICUD4 == icup) {
rccEnableTIM4(FALSE);
rccResetTIM4();
nvicEnableVector(STM32_TIM4_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM4_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM5
if (&ICUD5 == icup) {
rccEnableTIM5(FALSE);
rccResetTIM5();
nvicEnableVector(STM32_TIM5_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM5_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM8
if (&ICUD8 == icup) {
rccEnableTIM8(FALSE);
rccResetTIM8();
nvicEnableVector(STM32_TIM8_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY));
nvicEnableVector(STM32_TIM8_CC_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK2;
}
#endif
#if STM32_ICU_USE_TIM9
if (&ICUD9 == icup) {
rccEnableTIM9(FALSE);
rccResetTIM9();
nvicEnableVector(STM32_TIM9_NUMBER,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM9_IRQ_PRIORITY));
icup->clock = STM32_TIMCLK1;
}
#endif
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
icup->tim->CR1 = 0; /* Timer disabled. */
icup->tim->DIER = 0; /* All IRQs disabled. */
icup->tim->SR = 0; /* Clear eventual pending IRQs. */
icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */
icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */
icup->tim->CNT = 0; /* Counter reset to zero. */
}
/* Timer configuration.*/
psc = (icup->clock / icup->config->frequency) - 1;
chDbgAssert((psc <= 0xFFFF) &&
((psc + 1) * icup->config->frequency) == icup->clock,
"icu_lld_start(), #1", "invalid frequency");
icup->tim->PSC = (uint16_t)psc;
icup->tim->ARR = 0xFFFF;
if (icup->config->channel == ICU_CHANNEL_1) {
/* Selected input 1.
CCMR1_CC1S = 01 = CH1 Input on TI1.
CCMR1_CC2S = 10 = CH2 Input on TI1.*/
icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(1) | STM32_TIM_CCMR1_CC2S(2);
/* SMCR_TS = 101, input is TI1FP1.
SMCR_SMS = 100, reset on rising edge.*/
icup->tim->SMCR = STM32_TIM_SMCR_TS(5) | STM32_TIM_SMCR_SMS(4);
/* The CCER settings depend on the selected trigger mode.
ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
icup->tim->CCER = STM32_TIM_CCER_CC1E |
STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P;
else
icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P |
STM32_TIM_CCER_CC2E;
/* Direct pointers to the capture registers in order to make reading
data faster from within callbacks.*/
icup->wccrp = &icup->tim->CCR[1];
icup->pccrp = &icup->tim->CCR[0];
} else {
/* Selected input 2.
CCMR1_CC1S = 10 = CH1 Input on TI2.
CCMR1_CC2S = 01 = CH2 Input on TI2.*/
icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(2) | STM32_TIM_CCMR1_CC2S(1);
/* SMCR_TS = 110, input is TI2FP2.
SMCR_SMS = 100, reset on rising edge.*/
icup->tim->SMCR = STM32_TIM_SMCR_TS(6) | STM32_TIM_SMCR_SMS(4);
/* The CCER settings depend on the selected trigger mode.
ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P |
STM32_TIM_CCER_CC2E;
else
icup->tim->CCER = STM32_TIM_CCER_CC1E |
STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P;
/* Direct pointers to the capture registers in order to make reading
data faster from within callbacks.*/
icup->wccrp = &icup->tim->CCR[0];
icup->pccrp = &icup->tim->CCR[1];
}
}
/**
* @brief Deactivates the ICU peripheral.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_stop(ICUDriver *icup) {
if (icup->state == ICU_READY) {
/* Clock deactivation.*/
icup->tim->CR1 = 0; /* Timer disabled. */
icup->tim->DIER = 0; /* All IRQs disabled. */
icup->tim->SR = 0; /* Clear eventual pending IRQs. */
#if STM32_ICU_USE_TIM1
if (&ICUD1 == icup) {
nvicDisableVector(STM32_TIM1_UP_NUMBER);
nvicDisableVector(STM32_TIM1_CC_NUMBER);
rccDisableTIM1(FALSE);
}
#endif
#if STM32_ICU_USE_TIM2
if (&ICUD2 == icup) {
nvicDisableVector(STM32_TIM2_NUMBER);
rccDisableTIM2(FALSE);
}
#endif
#if STM32_ICU_USE_TIM3
if (&ICUD3 == icup) {
nvicDisableVector(STM32_TIM3_NUMBER);
rccDisableTIM3(FALSE);
}
#endif
#if STM32_ICU_USE_TIM4
if (&ICUD4 == icup) {
nvicDisableVector(STM32_TIM4_NUMBER);
rccDisableTIM4(FALSE);
}
#endif
#if STM32_ICU_USE_TIM5
if (&ICUD5 == icup) {
nvicDisableVector(STM32_TIM5_NUMBER);
rccDisableTIM5(FALSE);
}
#endif
#if STM32_ICU_USE_TIM8
if (&ICUD8 == icup) {
nvicDisableVector(STM32_TIM8_UP_NUMBER);
nvicDisableVector(STM32_TIM8_CC_NUMBER);
rccDisableTIM8(FALSE);
}
#endif
#if STM32_ICU_USE_TIM9
if (&ICUD9 == icup) {
nvicDisableVector(STM32_TIM9_NUMBER);
rccDisableTIM9(FALSE);
}
#endif
}
}
/**
* @brief Enables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_enable(ICUDriver *icup) {
icup->tim->SR = 0; /* Clear pending IRQs (if any). */
if (icup->config->channel == ICU_CHANNEL_1) {
if (icup->config->period_cb != NULL)
icup->tim->DIER |= STM32_TIM_DIER_CC1IE;
if (icup->config->width_cb != NULL)
icup->tim->DIER |= STM32_TIM_DIER_CC2IE;
} else {
if (icup->config->width_cb != NULL)
icup->tim->DIER |= STM32_TIM_DIER_CC1IE;
if (icup->config->period_cb != NULL)
icup->tim->DIER |= STM32_TIM_DIER_CC2IE;
}
if (icup->config->overflow_cb != NULL)
icup->tim->DIER |= STM32_TIM_DIER_UIE;
icup->tim->CR1 = STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
}
/**
* @brief Disables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_disable(ICUDriver *icup) {
icup->tim->CR1 = 0; /* Initially stopped. */
icup->tim->SR = 0; /* Clear pending IRQs (if any). */
icup->tim->DIER = 0; /* Interrupts disabled. */
}
#endif /* HAL_USE_ICU */
/** @} */

View File

@ -0,0 +1,406 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file STM32/icu_lld.h
* @brief STM32 ICU subsystem low level driver header.
*
* @addtogroup ICU
* @{
*/
#ifndef _ICU_LLD_H_
#define _ICU_LLD_H_
#include "stm32_tim.h"
#if HAL_USE_ICU || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ICUD1 driver enable switch.
* @details If set to @p TRUE the support for ICUD1 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM1) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM1 FALSE
#endif
/**
* @brief ICUD2 driver enable switch.
* @details If set to @p TRUE the support for ICUD2 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM2) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM2 FALSE
#endif
/**
* @brief ICUD3 driver enable switch.
* @details If set to @p TRUE the support for ICUD3 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM3) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM3 FALSE
#endif
/**
* @brief ICUD4 driver enable switch.
* @details If set to @p TRUE the support for ICUD4 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM4) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM4 FALSE
#endif
/**
* @brief ICUD5 driver enable switch.
* @details If set to @p TRUE the support for ICUD5 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM5) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM5 FALSE
#endif
/**
* @brief ICUD8 driver enable switch.
* @details If set to @p TRUE the support for ICUD8 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM8) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM8 FALSE
#endif
/**
* @brief ICUD9 driver enable switch.
* @details If set to @p TRUE the support for ICUD9 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ICU_USE_TIM9) || defined(__DOXYGEN__)
#define STM32_ICU_USE_TIM9 FALSE
#endif
/**
* @brief ICUD1 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM1_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD2 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM2_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD3 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM3_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD4 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM4_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD5 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM5_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD8 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM8_IRQ_PRIORITY 7
#endif
/**
* @brief ICUD9 interrupt priority level setting.
*/
#if !defined(STM32_ICU_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM9_IRQ_PRIORITY 7
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if STM32_ICU_USE_TIM1 && !STM32_HAS_TIM1
#error "TIM1 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM2 && !STM32_HAS_TIM2
#error "TIM2 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM3 && !STM32_HAS_TIM3
#error "TIM3 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM4 && !STM32_HAS_TIM4
#error "TIM4 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM5 && !STM32_HAS_TIM5
#error "TIM5 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM8 && !STM32_HAS_TIM8
#error "TIM8 not present in the selected device"
#endif
#if STM32_ICU_USE_TIM9 && !STM32_HAS_TIM9
#error "TIM9 not present in the selected device"
#endif
#if !STM32_ICU_USE_TIM1 && !STM32_ICU_USE_TIM2 && \
!STM32_ICU_USE_TIM3 && !STM32_ICU_USE_TIM4 && \
!STM32_ICU_USE_TIM5 && !STM32_ICU_USE_TIM8 && \
!STM32_ICU_USE_TIM9
#error "ICU driver activated but no TIM peripheral assigned"
#endif
#if STM32_ICU_USE_TIM1 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM1"
#endif
#if STM32_ICU_USE_TIM2 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM2"
#endif
#if STM32_ICU_USE_TIM3 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM3"
#endif
#if STM32_ICU_USE_TIM4 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM4_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM4"
#endif
#if STM32_ICU_USE_TIM5 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM5_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM5"
#endif
#if STM32_ICU_USE_TIM8 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM8_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM8"
#endif
#if STM32_ICU_USE_TIM9 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ICU_TIM9_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM9"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief ICU driver mode.
*/
typedef enum {
ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
} icumode_t;
/**
* @brief ICU frequency type.
*/
typedef uint32_t icufreq_t;
/**
* @brief ICU channel type.
*/
typedef enum {
ICU_CHANNEL_1 = 0, /**< Use TIMxCH1. */
ICU_CHANNEL_2 = 1, /**< Use TIMxCH2. */
} icuchannel_t;
/**
* @brief ICU counter type.
*/
typedef uint16_t icucnt_t;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief Driver mode.
*/
icumode_t mode;
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
icufreq_t frequency;
/**
* @brief Callback for pulse width measurement.
*/
icucallback_t width_cb;
/**
* @brief Callback for cycle period measurement.
*/
icucallback_t period_cb;
/**
* @brief Callback for timer overflow.
*/
icucallback_t overflow_cb;
/* End of the mandatory fields.*/
/**
* @brief Timer input channel to be used.
* @note Only inputs TIMx 1 and 2 are supported.
*/
icuchannel_t channel;
} ICUConfig;
/**
* @brief Structure representing an ICU driver.
*/
struct ICUDriver {
/**
* @brief Driver state.
*/
icustate_t state;
/**
* @brief Current configuration data.
*/
const ICUConfig *config;
#if defined(ICU_DRIVER_EXT_FIELDS)
ICU_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the TIMx registers block.
*/
stm32_tim_t *tim;
/**
* @brief CCR register used for width capture.
*/
volatile uint32_t *wccrp;
/**
* @brief CCR register used for period capture.
*/
volatile uint32_t *pccrp;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the width of the latest pulse.
* @details The pulse width is defined as number of ticks between the start
* edge and the stop edge.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @notapi
*/
#define icu_lld_get_width(icup) (*((icup)->wccrp) + 1)
/**
* @brief Returns the width of the latest cycle.
* @details The cycle width is defined as number of ticks between a start
* edge and the next start edge.
*
* @param[in] icup pointer to the @p ICUDriver object
* @return The number of ticks.
*
* @notapi
*/
#define icu_lld_get_period(icup) (*((icup)->pccrp) + 1)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if STM32_ICU_USE_TIM1 && !defined(__DOXYGEN__)
extern ICUDriver ICUD1;
#endif
#if STM32_ICU_USE_TIM2 && !defined(__DOXYGEN__)
extern ICUDriver ICUD2;
#endif
#if STM32_ICU_USE_TIM3 && !defined(__DOXYGEN__)
extern ICUDriver ICUD3;
#endif
#if STM32_ICU_USE_TIM4 && !defined(__DOXYGEN__)
extern ICUDriver ICUD4;
#endif
#if STM32_ICU_USE_TIM5 && !defined(__DOXYGEN__)
extern ICUDriver ICUD5;
#endif
#if STM32_ICU_USE_TIM8 && !defined(__DOXYGEN__)
extern ICUDriver ICUD8;
#endif
#if STM32_ICU_USE_TIM9 && !defined(__DOXYGEN__)
extern ICUDriver ICUD9;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void icu_lld_init(void);
void icu_lld_start(ICUDriver *icup);
void icu_lld_stop(ICUDriver *icup);
void icu_lld_enable(ICUDriver *icup);
void icu_lld_disable(ICUDriver *icup);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ICU */
#endif /* _ICU_LLD_H_ */
/** @} */

View File

@ -0,0 +1,705 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file STM32/pwm_lld.c
* @brief STM32 PWM subsystem low level driver header.
*
* @addtogroup PWM
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief PWMD1 driver identifier.
* @note The driver PWMD1 allocates the complex timer TIM1 when enabled.
*/
#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__)
PWMDriver PWMD1;
#endif
/**
* @brief PWMD2 driver identifier.
* @note The driver PWMD2 allocates the timer TIM2 when enabled.
*/
#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__)
PWMDriver PWMD2;
#endif
/**
* @brief PWMD3 driver identifier.
* @note The driver PWMD3 allocates the timer TIM3 when enabled.
*/
#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__)
PWMDriver PWMD3;
#endif
/**
* @brief PWMD4 driver identifier.
* @note The driver PWMD4 allocates the timer TIM4 when enabled.
*/
#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__)
PWMDriver PWMD4;
#endif
/**
* @brief PWMD5 driver identifier.
* @note The driver PWMD5 allocates the timer TIM5 when enabled.
*/
#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__)
PWMDriver PWMD5;
#endif
/**
* @brief PWMD8 driver identifier.
* @note The driver PWMD8 allocates the timer TIM8 when enabled.
*/
#if STM32_PWM_USE_TIM8 || defined(__DOXYGEN__)
PWMDriver PWMD8;
#endif
/**
* @brief PWMD9 driver identifier.
* @note The driver PWMD9 allocates the timer TIM9 when enabled.
*/
#if STM32_PWM_USE_TIM9 || defined(__DOXYGEN__)
PWMDriver PWMD9;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
#if STM32_PWM_USE_TIM2 || STM32_PWM_USE_TIM3 || STM32_PWM_USE_TIM4 || \
STM32_PWM_USE_TIM5 || STM32_PWM_USE_TIM9 || defined(__DOXYGEN__)
/**
* @brief Common TIM2...TIM5,TIM9 IRQ handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*/
static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
uint16_t sr;
sr = pwmp->tim->SR;
sr &= pwmp->tim->DIER;
pwmp->tim->SR = ~sr;
if ((sr & STM32_TIM_SR_CC1IF) != 0)
pwmp->config->channels[0].callback(pwmp);
if ((sr & STM32_TIM_SR_CC2IF) != 0)
pwmp->config->channels[1].callback(pwmp);
if ((sr & STM32_TIM_SR_CC3IF) != 0)
pwmp->config->channels[2].callback(pwmp);
if ((sr & STM32_TIM_SR_CC4IF) != 0)
pwmp->config->channels[3].callback(pwmp);
if ((sr & STM32_TIM_SR_UIF) != 0)
pwmp->config->callback(pwmp);
}
#endif /* STM32_PWM_USE_TIM2 || ... || STM32_PWM_USE_TIM5 */
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if STM32_PWM_USE_TIM1
#if !defined(STM32_TIM1_UP_HANDLER)
#error "STM32_TIM1_UP_HANDLER not defined"
#endif
/**
* @brief TIM1 update interrupt handler.
* @note It is assumed that this interrupt is only activated if the callback
* pointer is not equal to @p NULL in order to not perform an extra
* check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM1_UP_HANDLER) {
CH_IRQ_PROLOGUE();
STM32_TIM1->SR = ~STM32_TIM_SR_UIF;
PWMD1.config->callback(&PWMD1);
CH_IRQ_EPILOGUE();
}
#if !defined(STM32_TIM1_CC_HANDLER)
#error "STM32_TIM1_CC_HANDLER not defined"
#endif
/**
* @brief TIM1 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM1_CC_HANDLER) {
uint16_t sr;
CH_IRQ_PROLOGUE();
sr = STM32_TIM1->SR & STM32_TIM1->DIER;
STM32_TIM1->SR = ~(STM32_TIM_SR_CC1IF | STM32_TIM_SR_CC2IF |
STM32_TIM_SR_CC3IF | STM32_TIM_SR_CC4IF);
if ((sr & STM32_TIM_SR_CC1IF) != 0)
PWMD1.config->channels[0].callback(&PWMD1);
if ((sr & STM32_TIM_SR_CC2IF) != 0)
PWMD1.config->channels[1].callback(&PWMD1);
if ((sr & STM32_TIM_SR_CC3IF) != 0)
PWMD1.config->channels[2].callback(&PWMD1);
if ((sr & STM32_TIM_SR_CC4IF) != 0)
PWMD1.config->channels[3].callback(&PWMD1);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM1 */
#if STM32_PWM_USE_TIM2
#if !defined(STM32_TIM2_HANDLER)
#error "STM32_TIM2_HANDLER not defined"
#endif
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM2_HANDLER) {
CH_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD2);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM2 */
#if STM32_PWM_USE_TIM3
#if !defined(STM32_TIM3_HANDLER)
#error "STM32_TIM3_HANDLER not defined"
#endif
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM3_HANDLER) {
CH_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD3);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM3 */
#if STM32_PWM_USE_TIM4
#if !defined(STM32_TIM4_HANDLER)
#error "STM32_TIM4_HANDLER not defined"
#endif
/**
* @brief TIM4 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM4_HANDLER) {
CH_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD4);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM4 */
#if STM32_PWM_USE_TIM5
#if !defined(STM32_TIM5_HANDLER)
#error "STM32_TIM5_HANDLER not defined"
#endif
/**
* @brief TIM5 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM5_HANDLER) {
CH_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD5);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM5 */
#if STM32_PWM_USE_TIM8
#if !defined(STM32_TIM8_UP_HANDLER)
#error "STM32_TIM8_UP_HANDLER not defined"
#endif
/**
* @brief TIM8 update interrupt handler.
* @note It is assumed that this interrupt is only activated if the callback
* pointer is not equal to @p NULL in order to not perform an extra
* check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM8_UP_HANDLER) {
CH_IRQ_PROLOGUE();
STM32_TIM8->SR = ~TIM_SR_UIF;
PWMD8.config->callback(&PWMD8);
CH_IRQ_EPILOGUE();
}
#if !defined(STM32_TIM8_CC_HANDLER)
#error "STM32_TIM8_CC_HANDLER not defined"
#endif
/**
* @brief TIM8 compare interrupt handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM8_CC_HANDLER) {
uint16_t sr;
CH_IRQ_PROLOGUE();
sr = STM32_TIM8->SR & STM32_TIM8->DIER;
STM32_TIM8->SR = ~(STM32_TIM_SR_CC1IF | STM32_TIM_SR_CC2IF |
STM32_TIM_SR_CC3IF | STM32_TIM_SR_CC4IF);
if ((sr & STM32_TIM_SR_CC1IF) != 0)
PWMD8.config->channels[0].callback(&PWMD8);
if ((sr & STM32_TIM_SR_CC2IF) != 0)
PWMD8.config->channels[1].callback(&PWMD8);
if ((sr & STM32_TIM_SR_CC3IF) != 0)
PWMD8.config->channels[2].callback(&PWMD8);
if ((sr & STM32_TIM_SR_CC4IF) != 0)
PWMD8.config->channels[3].callback(&PWMD8);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM8 */
#if STM32_PWM_USE_TIM9
#if !defined(STM32_TIM9_HANDLER)
#error "STM32_TIM9_HANDLER not defined"
#endif
/**
* @brief TIM9 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_TIM9_HANDLER) {
CH_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD9);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_PWM_USE_TIM9 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level PWM driver initialization.
*
* @notapi
*/
void pwm_lld_init(void) {
#if STM32_PWM_USE_TIM1
/* Driver initialization.*/
pwmObjectInit(&PWMD1);
PWMD1.tim = STM32_TIM1;
#endif
#if STM32_PWM_USE_TIM2
/* Driver initialization.*/
pwmObjectInit(&PWMD2);
PWMD2.tim = STM32_TIM2;
#endif
#if STM32_PWM_USE_TIM3
/* Driver initialization.*/
pwmObjectInit(&PWMD3);
PWMD3.tim = STM32_TIM3;
#endif
#if STM32_PWM_USE_TIM4
/* Driver initialization.*/
pwmObjectInit(&PWMD4);
PWMD4.tim = STM32_TIM4;
#endif
#if STM32_PWM_USE_TIM5
/* Driver initialization.*/
pwmObjectInit(&PWMD5);
PWMD5.tim = STM32_TIM5;
#endif
#if STM32_PWM_USE_TIM8
/* Driver initialization.*/
pwmObjectInit(&PWMD8);
PWMD8.tim = STM32_TIM8;
#endif
#if STM32_PWM_USE_TIM9
/* Driver initialization.*/
pwmObjectInit(&PWMD9);
PWMD9.tim = STM32_TIM9;
#endif
}
/**
* @brief Configures and activates the PWM peripheral.
* @note Starting a driver that is already in the @p PWM_READY state
* disables all the active channels.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp) {
uint32_t psc;
uint16_t ccer;
if (pwmp->state == PWM_STOP) {
/* Clock activation and timer reset.*/
#if STM32_PWM_USE_TIM1
if (&PWMD1 == pwmp) {
rccEnableTIM1(FALSE);
rccResetTIM1();
nvicEnableVector(STM32_TIM1_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
nvicEnableVector(STM32_TIM1_CC_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_PWM_USE_TIM2
if (&PWMD2 == pwmp) {
rccEnableTIM2(FALSE);
rccResetTIM2();
nvicEnableVector(STM32_TIM2_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM2_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM3
if (&PWMD3 == pwmp) {
rccEnableTIM3(FALSE);
rccResetTIM3();
nvicEnableVector(STM32_TIM3_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM3_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM4
if (&PWMD4 == pwmp) {
rccEnableTIM4(FALSE);
rccResetTIM4();
nvicEnableVector(STM32_TIM4_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM4_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM5
if (&PWMD5 == pwmp) {
rccEnableTIM5(FALSE);
rccResetTIM5();
nvicEnableVector(STM32_TIM5_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM5_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM8
if (&PWMD8 == pwmp) {
rccEnableTIM8(FALSE);
rccResetTIM8();
nvicEnableVector(STM32_TIM8_UP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY));
nvicEnableVector(STM32_TIM8_CC_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_PWM_USE_TIM9
if (&PWMD9 == pwmp) {
rccEnableTIM9(FALSE);
rccResetTIM9();
nvicEnableVector(STM32_TIM9_NUMBER,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM9_IRQ_PRIORITY));
pwmp->clock = STM32_TIMCLK1;
}
#endif
/* All channels configured in PWM1 mode with preload enabled and will
stay that way until the driver is stopped.*/
pwmp->tim->CCMR1 = STM32_TIM_CCMR1_OC1M(6) | STM32_TIM_CCMR1_OC1PE |
STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE;
pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE |
STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE;
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
pwmp->tim->CR1 = 0; /* Timer disabled. */
pwmp->tim->DIER = 0; /* All IRQs disabled. */
pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */
pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */
pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */
pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */
pwmp->tim->CNT = 0; /* Counter reset to zero. */
}
/* Timer configuration.*/
psc = (pwmp->clock / pwmp->config->frequency) - 1;
chDbgAssert((psc <= 0xFFFF) &&
((psc + 1) * pwmp->config->frequency) == pwmp->clock,
"pwm_lld_start(), #1", "invalid frequency");
pwmp->tim->PSC = (uint16_t)psc;
pwmp->tim->ARR = (uint16_t)(pwmp->period - 1);
pwmp->tim->CR2 = pwmp->config->cr2;
/* Output enables and polarities setup.*/
ccer = 0;
switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC1P;
case PWM_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC1E;
default:
;
}
switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC2P;
case PWM_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC2E;
default:
;
}
switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC3P;
case PWM_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC3E;
default:
;
}
switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC4P;
case PWM_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC4E;
default:
;
}
#if STM32_PWM_USE_ADVANCED
#if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8
if (&PWMD1 == pwmp) {
#endif
#if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8
if (&PWMD8 == pwmp) {
#endif
#if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8
if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp)) {
#endif
switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC1NP;
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC1NE;
default:
;
}
switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC2NP;
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC2NE;
default:
;
}
switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
ccer |= STM32_TIM_CCER_CC3NP;
case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
ccer |= STM32_TIM_CCER_CC3NE;
default:
;
}
}
#endif /* STM32_PWM_USE_ADVANCED*/
pwmp->tim->CCER = ccer;
pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */
pwmp->tim->DIER = pwmp->config->callback == NULL ? 0 : STM32_TIM_DIER_UIE;
pwmp->tim->SR = 0; /* Clear pending IRQs. */
#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8
#if STM32_PWM_USE_ADVANCED
pwmp->tim->BDTR = pwmp->config->bdtr | STM32_TIM_BDTR_MOE;
#else
pwmp->tim->BDTR = STM32_TIM_BDTR_MOE;
#endif
#endif
/* Timer configured and started.*/
pwmp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN;
}
/**
* @brief Deactivates the PWM peripheral.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_stop(PWMDriver *pwmp) {
/* If in ready state then disables the PWM clock.*/
if (pwmp->state == PWM_READY) {
pwmp->tim->CR1 = 0; /* Timer disabled. */
pwmp->tim->DIER = 0; /* All IRQs disabled. */
pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
#if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8
pwmp->tim->BDTR = 0;
#endif
#if STM32_PWM_USE_TIM1
if (&PWMD1 == pwmp) {
nvicDisableVector(STM32_TIM1_UP_NUMBER);
nvicDisableVector(STM32_TIM1_CC_NUMBER);
rccDisableTIM1(FALSE);
}
#endif
#if STM32_PWM_USE_TIM2
if (&PWMD2 == pwmp) {
nvicDisableVector(STM32_TIM2_NUMBER);
rccDisableTIM2(FALSE);
}
#endif
#if STM32_PWM_USE_TIM3
if (&PWMD3 == pwmp) {
nvicDisableVector(STM32_TIM3_NUMBER);
rccDisableTIM3(FALSE);
}
#endif
#if STM32_PWM_USE_TIM4
if (&PWMD4 == pwmp) {
nvicDisableVector(STM32_TIM4_NUMBER);
rccDisableTIM4(FALSE);
}
#endif
#if STM32_PWM_USE_TIM5
if (&PWMD5 == pwmp) {
nvicDisableVector(STM32_TIM5_NUMBER);
rccDisableTIM5(FALSE);
}
#endif
#if STM32_PWM_USE_TIM8
if (&PWMD8 == pwmp) {
nvicDisableVector(STM32_TIM8_UP_NUMBER);
nvicDisableVector(STM32_TIM8_CC_NUMBER);
rccDisableTIM8(FALSE);
}
#endif
#if STM32_PWM_USE_TIM9
if (&PWMD9 == pwmp) {
nvicDisableVector(STM32_TIM9_NUMBER);
rccDisableTIM9(FALSE);
}
#endif
}
}
/**
* @brief Enables a PWM channel.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is active using the specified configuration.
* @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @notapi
*/
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
pwmp->tim->CCR[channel] = width; /* New duty cycle. */
/* If there is a callback defined for the channel then the associated
interrupt must be enabled.*/
if (pwmp->config->channels[channel].callback != NULL) {
uint32_t dier = pwmp->tim->DIER;
/* If the IRQ is not already enabled care must be taken to clear it,
it is probably already pending because the timer is running.*/
if ((dier & (2 << channel)) == 0) {
pwmp->tim->DIER = dier | (2 << channel);
pwmp->tim->SR = ~(2 << channel);
}
}
}
/**
* @brief Disables a PWM channel.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is disabled and its output line returned to the
* idle state.
* @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
*
* @notapi
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
pwmp->tim->CCR[channel] = 0;
pwmp->tim->DIER &= ~(2 << channel);
}
#endif /* HAL_USE_PWM */
/** @} */

View File

@ -0,0 +1,474 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file STM32/pwm_lld.h
* @brief STM32 PWM subsystem low level driver header.
*
* @addtogroup PWM
* @{
*/
#ifndef _PWM_LLD_H_
#define _PWM_LLD_H_
#include "stm32_tim.h"
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Number of PWM channels per PWM driver.
*/
#define PWM_CHANNELS 4
/**
* @brief Complementary output modes mask.
* @note This is an STM32-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_MASK 0xF0
/**
* @brief Complementary output not driven.
* @note This is an STM32-specific setting.
*/
#define PWM_COMPLEMENTARY_OUTPUT_DISABLED 0x00
/**
* @brief Complementary output, active is logic level one.
* @note This is an STM32-specific setting.
* @note This setting is only available if the configuration option
* @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
* timers TIM1 and TIM8.
*/
#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH 0x10
/**
* @brief Complementary output, active is logic level zero.
* @note This is an STM32-specific setting.
* @note This setting is only available if the configuration option
* @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
* timers TIM1 and TIM8.
*/
#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief If advanced timer features switch.
* @details If set to @p TRUE the advanced features for TIM1 and TIM8 are
* enabled.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_ADVANCED) || defined(__DOXYGEN__)
#define STM32_PWM_USE_ADVANCED FALSE
#endif
/**
* @brief PWMD1 driver enable switch.
* @details If set to @p TRUE the support for PWMD1 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM1) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM1 FALSE
#endif
/**
* @brief PWMD2 driver enable switch.
* @details If set to @p TRUE the support for PWMD2 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM2) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM2 FALSE
#endif
/**
* @brief PWMD3 driver enable switch.
* @details If set to @p TRUE the support for PWMD3 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM3) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM3 FALSE
#endif
/**
* @brief PWMD4 driver enable switch.
* @details If set to @p TRUE the support for PWMD4 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM4) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM4 FALSE
#endif
/**
* @brief PWMD5 driver enable switch.
* @details If set to @p TRUE the support for PWMD5 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM5) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM5 FALSE
#endif
/**
* @brief PWMD8 driver enable switch.
* @details If set to @p TRUE the support for PWMD8 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM8) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM8 FALSE
#endif
/**
* @brief PWMD9 driver enable switch.
* @details If set to @p TRUE the support for PWMD9 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM9) || defined(__DOXYGEN__)
#define STM32_PWM_USE_TIM9 FALSE
#endif
/**
* @brief PWMD1 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM1_IRQ_PRIORITY 7
#endif
/**
* @brief PWMD2 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM2_IRQ_PRIORITY 7
#endif
/**
* @brief PWMD3 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM3_IRQ_PRIORITY 7
#endif
/**
* @brief PWMD4 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM4_IRQ_PRIORITY 7
#endif
/**
* @brief PWMD5 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM5_IRQ_PRIORITY 7
#endif
/**
* @brief PWMD8 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM8_IRQ_PRIORITY 7
#endif
/** @} */
/**
* @brief PWMD9 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM9_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM9_IRQ_PRIORITY 7
#endif
/** @} */
/*===========================================================================*/
/* Configuration checks. */
/*===========================================================================*/
#if STM32_PWM_USE_TIM1 && !STM32_HAS_TIM1
#error "TIM1 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM2 && !STM32_HAS_TIM2
#error "TIM2 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM3 && !STM32_HAS_TIM3
#error "TIM3 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM4 && !STM32_HAS_TIM4
#error "TIM4 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM5 && !STM32_HAS_TIM5
#error "TIM5 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM8 && !STM32_HAS_TIM8
#error "TIM8 not present in the selected device"
#endif
#if STM32_PWM_USE_TIM9 && !STM32_HAS_TIM9
#error "TIM9 not present in the selected device"
#endif
#if !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM2 && \
!STM32_PWM_USE_TIM3 && !STM32_PWM_USE_TIM4 && \
!STM32_PWM_USE_TIM5 && !STM32_PWM_USE_TIM8 && \
!STM32_PWM_USE_TIM9
#error "PWM driver activated but no TIM peripheral assigned"
#endif
#if STM32_PWM_USE_ADVANCED && !STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8
#error "advanced mode selected but no advanced timer assigned"
#endif
#if STM32_PWM_USE_TIM1 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM1"
#endif
#if STM32_PWM_USE_TIM2 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM2"
#endif
#if STM32_PWM_USE_TIM3 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM3"
#endif
#if STM32_PWM_USE_TIM4 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM4_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM4"
#endif
#if STM32_PWM_USE_TIM5 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM5_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM5"
#endif
#if STM32_PWM_USE_TIM8 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM8_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM8"
#endif
#if STM32_PWM_USE_TIM9 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_PWM_TIM9_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIM9"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief PWM mode type.
*/
typedef uint32_t pwmmode_t;
/**
* @brief PWM channel type.
*/
typedef uint8_t pwmchannel_t;
/**
* @brief PWM counter type.
*/
typedef uint16_t pwmcnt_t;
/**
* @brief PWM driver channel configuration structure.
*/
typedef struct {
/**
* @brief Channel active logic level.
*/
pwmmode_t mode;
/**
* @brief Channel callback pointer.
* @note This callback is invoked on the channel compare event. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/* End of the mandatory fields.*/
} PWMChannelConfig;
/**
* @brief PWM driver configuration structure.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
uint32_t frequency;
/**
* @brief PWM period in ticks.
* @note The low level can use assertions in order to catch invalid
* period specifications.
*/
pwmcnt_t period;
/**
* @brief Periodic callback pointer.
* @note This callback is invoked on PWM counter reset. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/**
* @brief Channels configurations.
*/
PWMChannelConfig channels[PWM_CHANNELS];
/* End of the mandatory fields.*/
/**
* @brief TIM CR2 register initialization data.
* @note The value of this field should normally be equal to zero.
*/
uint16_t cr2;
#if STM32_PWM_USE_ADVANCED || defined(__DOXYGEN__)
/**
* @brief TIM BDTR (break & dead-time) register initialization data.
* @note The value of this field should normally be equal to zero.
*/ \
uint16_t bdtr;
#endif
} PWMConfig;
/**
* @brief Structure representing a PWM driver.
*/
struct PWMDriver {
/**
* @brief Driver state.
*/
pwmstate_t state;
/**
* @brief Current driver configuration data.
*/
const PWMConfig *config;
/**
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Timer base clock.
*/
uint32_t clock;
/**
* @brief Pointer to the TIMx registers block.
*/
stm32_tim_t *tim;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Changes the period the PWM peripheral.
* @details This function changes the period of a PWM unit that has already
* been activated using @p pwmStart().
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The PWM unit period is changed to the new value.
* @note The function has effect at the next cycle start.
* @note If a period is specified that is shorter than the pulse width
* programmed in one of the channels then the behavior is not
* guaranteed.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] period new cycle time in ticks
*
* @notapi
*/
#define pwm_lld_change_period(pwmp, period) \
((pwmp)->tim->ARR = (uint16_t)((period) - 1))
/**
* @brief Returns a PWM channel status.
* @pre The PWM unit must have been activated using @p pwmStart().
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
*
* @notapi
*/
#define pwm_lld_is_channel_enabled(pwmp, channel) \
(((pwmp)->tim->CCR[channel] != 0) || \
(((pwmp)->tim->DIER & (2 << channel)) != 0))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if STM32_PWM_USE_TIM1 && !defined(__DOXYGEN__)
extern PWMDriver PWMD1;
#endif
#if STM32_PWM_USE_TIM2 && !defined(__DOXYGEN__)
extern PWMDriver PWMD2;
#endif
#if STM32_PWM_USE_TIM3 && !defined(__DOXYGEN__)
extern PWMDriver PWMD3;
#endif
#if STM32_PWM_USE_TIM4 && !defined(__DOXYGEN__)
extern PWMDriver PWMD4;
#endif
#if STM32_PWM_USE_TIM5 && !defined(__DOXYGEN__)
extern PWMDriver PWMD5;
#endif
#if STM32_PWM_USE_TIM8 && !defined(__DOXYGEN__)
extern PWMDriver PWMD8;
#endif
#if STM32_PWM_USE_TIM9 && !defined(__DOXYGEN__)
extern PWMDriver PWMD9;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void pwm_lld_init(void);
void pwm_lld_start(PWMDriver *pwmp);
void pwm_lld_stop(PWMDriver *pwmp);
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PWM */
#endif /* _PWM_LLD_H_ */
/** @} */

View File

@ -0,0 +1,438 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
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.
*/
/**
* @file stm32_timh
* @brief STM32 TIM registers layout header.
* @note This file requires definitions from the ST STM32 header file.
*
* @addtogroup STM32_TIM
* @{
*/
#ifndef _STM32_TIM_H_
#define _STM32_TIM_H_
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name TIM_CR1 register
* @{
*/
#define STM32_TIM_CR1_CEN (1U << 0)
#define STM32_TIM_CR1_UDIS (1U << 1)
#define STM32_TIM_CR1_URS (1U << 2)
#define STM32_TIM_CR1_OPM (1U << 3)
#define STM32_TIM_CR1_DIR (1U << 4)
#define STM32_TIM_CR1_CMS_MASK (3U << 4)
#define STM32_TIM_CR1_CMS(n) ((n) << 5)
#define STM32_TIM_CR1_ARPE (1U << 7)
#define STM32_TIM_CR1_CKD_MASK (3U << 8)
#define STM32_TIM_CR1_CKD(n) ((n) << 8)
#define STM32_TIM_CR1_UIFREMAP (1U << 11)
/** @} */
/**
* @name TIM_CR2 register
* @{
*/
#define STM32_TIM_CR2_CCPC (1U << 0)
#define STM32_TIM_CR2_CCUS (1U << 2)
#define STM32_TIM_CR2_CCDS (1U << 3)
#define STM32_TIM_CR2_MMS_MASK (7U << 4)
#define STM32_TIM_CR2_MMS(n) ((n) << 4)
#define STM32_TIM_CR2_TI1S (1U << 7)
#define STM32_TIM_CR2_OIS1 (1U << 8)
#define STM32_TIM_CR2_OIS1N (1U << 9)
#define STM32_TIM_CR2_OIS2 (1U << 10)
#define STM32_TIM_CR2_OIS2N (1U << 11)
#define STM32_TIM_CR2_OIS3 (1U << 12)
#define STM32_TIM_CR2_OIS3N (1U << 13)
#define STM32_TIM_CR2_OIS4 (1U << 14)
#define STM32_TIM_CR2_OIS5 (1U << 16)
#define STM32_TIM_CR2_OIS6 (1U << 17)
#define STM32_TIM_CR2_MMS2_MASK (15U << 20)
#define STM32_TIM_CR2_MMS2(n) ((n) << 20)
/** @} */
/**
* @name TIM_SMCR register
* @{
*/
#define STM32_TIM_SMCR_SMS_MASK 0x00010007
#define STM32_TIM_SMCR_SMS(n) ((((n) & 7) << 0) | \
(((n) & 8) << 16))
#define STM32_TIM_SMCR_OCCS (1U << 3)
#define STM32_TIM_SMCR_TS_MASK (7U << 4)
#define STM32_TIM_SMCR_TS(n) ((n) << 4)
#define STM32_TIM_SMCR_MSM (1U << 7)
#define STM32_TIM_SMCR_ETF_MASK (15U << 8)
#define STM32_TIM_SMCR_ETF(n) ((n) << 8)
#define STM32_TIM_SMCR_ETPS_MASK (3U << 12)
#define STM32_TIM_SMCR_ETPS(n) ((n) << 12)
#define STM32_TIM_SMCR_ECE (1U << 14)
#define STM32_TIM_SMCR_ETP (1U << 15)
/** @} */
/**
* @name TIM_DIER register
* @{
*/
#define STM32_TIM_DIER_UIE (1U << 0)
#define STM32_TIM_DIER_CC1IE (1U << 1)
#define STM32_TIM_DIER_CC2IE (1U << 2)
#define STM32_TIM_DIER_CC3IE (1U << 3)
#define STM32_TIM_DIER_CC4IE (1U << 4)
#define STM32_TIM_DIER_COMIE (1U << 5)
#define STM32_TIM_DIER_TIE (1U << 6)
#define STM32_TIM_DIER_BIE (1U << 7)
#define STM32_TIM_DIER_UDE (1U << 8)
#define STM32_TIM_DIER_CC1DE (1U << 9)
#define STM32_TIM_DIER_CC2DE (1U << 10)
#define STM32_TIM_DIER_CC3DE (1U << 11)
#define STM32_TIM_DIER_CC4DE (1U << 12)
#define STM32_TIM_DIER_COMDE (1U << 13)
#define STM32_TIM_DIER_TDE (1U << 14)
/** @} */
/**
* @name TIM_SR register
* @{
*/
#define STM32_TIM_SR_UIF (1U << 0)
#define STM32_TIM_SR_CC1IF (1U << 1)
#define STM32_TIM_SR_CC2IF (1U << 2)
#define STM32_TIM_SR_CC3IF (1U << 3)
#define STM32_TIM_SR_CC4IF (1U << 4)
#define STM32_TIM_SR_COMIF (1U << 5)
#define STM32_TIM_SR_TIF (1U << 6)
#define STM32_TIM_SR_BIF (1U << 7)
#define STM32_TIM_SR_B2IF (1U << 8)
#define STM32_TIM_SR_CC1OF (1U << 9)
#define STM32_TIM_SR_CC2OF (1U << 10)
#define STM32_TIM_SR_CC3OF (1U << 11)
#define STM32_TIM_SR_CC4OF (1U << 12)
#define STM32_TIM_SR_CC5IF (1U << 16)
#define STM32_TIM_SR_CC6IF (1U << 17)
/** @} */
/**
* @name TIM_EGR register
* @{
*/
#define STM32_TIM_EGR_UG (1U << 0)
#define STM32_TIM_EGR_CC1G (1U << 1)
#define STM32_TIM_EGR_CC2G (1U << 2)
#define STM32_TIM_EGR_CC3G (1U << 3)
#define STM32_TIM_EGR_CC4G (1U << 4)
#define STM32_TIM_EGR_COMG (1U << 5)
#define STM32_TIM_EGR_TG (1U << 6)
#define STM32_TIM_EGR_BG (1U << 7)
#define STM32_TIM_EGR_B2G (1U << 8)
/** @} */
/**
* @name TIM_CCMR1 register (output)
* @{
*/
#define STM32_TIM_CCMR1_CC1S_MASK (3U << 0)
#define STM32_TIM_CCMR1_CC1S(n) ((n) << 0)
#define STM32_TIM_CCMR1_OC1FE (1U << 2)
#define STM32_TIM_CCMR1_OC1PE (1U << 3)
#define STM32_TIM_CCMR1_OC1M_MASK 0x00010070
#define STM32_TIM_CCMR1_OC1M(n) ((((n) & 3) << 4) | \
(((n) & 4) << 16))
#define STM32_TIM_CCMR1_OC1CE (1U << 7)
#define STM32_TIM_CCMR1_CC2S_MASK (3U << 8)
#define STM32_TIM_CCMR1_CC2S(n) ((n) << 8)
#define STM32_TIM_CCMR1_OC2FE (1U << 10)
#define STM32_TIM_CCMR1_OC2PE (1U << 11)
#define STM32_TIM_CCMR1_OC2M_MASK 0x01007000
#define STM32_TIM_CCMR1_OC2M(n) ((((n) & 3) << 8) | \
(((n) & 4) << 24))
#define STM32_TIM_CCMR1_OC2CE (1U << 15)
/** @} */
/**
* @name CCMR1 register (input)
* @{
*/
#define STM32_TIM_CCMR1_IC1PSC_MASK (3U << 2)
#define STM32_TIM_CCMR1_IC1PSC(n) ((n) << 2)
#define STM32_TIM_CCMR1_IC1F_MASK (15U << 4)
#define STM32_TIM_CCMR1_IC1F(n) ((n) << 4)
#define STM32_TIM_CCMR1_IC2PSC_MASK (3U << 10)
#define STM32_TIM_CCMR1_IC2PSC(n) ((n) << 10)
#define STM32_TIM_CCMR1_IC2F_MASK (15U << 12)
#define STM32_TIM_CCMR1_IC2F(n) ((n) << 12)
/** @} */
/**
* @name TIM_CCMR2 register (output)
* @{
*/
#define STM32_TIM_CCMR2_CC3S_MASK (3U << 0)
#define STM32_TIM_CCMR2_CC3S(n) ((n) << 0)
#define STM32_TIM_CCMR2_OC3FE (1U << 2)
#define STM32_TIM_CCMR2_OC3PE (1U << 3)
#define STM32_TIM_CCMR2_OC3M_MASK 0x00010070
#define STM32_TIM_CCMR2_OC3M(n) ((((n) & 3) << 4) | \
(((n) & 4) << 16))
#define STM32_TIM_CCMR2_OC3CE (1U << 7)
#define STM32_TIM_CCMR2_CC4S_MASK (3U << 8)
#define STM32_TIM_CCMR2_CC4S(n) ((n) << 8)
#define STM32_TIM_CCMR2_OC4FE (1U << 10)
#define STM32_TIM_CCMR2_OC4PE (1U << 11)
#define STM32_TIM_CCMR2_OC4M_MASK 0x01007000
#define STM32_TIM_CCMR2_OC4M(n) ((((n) & 3) << 8) | \
(((n) & 4) << 24))
#define STM32_TIM_CCMR2_OC4CE (1U << 15)
/** @} */
/**
* @name TIM_CCMR2 register (input)
* @{
*/
#define STM32_TIM_CCMR2_IC3PSC_MASK (3U << 2)
#define STM32_TIM_CCMR2_IC3PSC(n) ((n) << 2)
#define STM32_TIM_CCMR2_IC3F_MASK (15U << 4)
#define STM32_TIM_CCMR2_IC3F(n) ((n) << 4)
#define STM32_TIM_CCMR2_IC4PSC_MASK (3U << 10)
#define STM32_TIM_CCMR2_IC4PSC(n) ((n) << 10)
#define STM32_TIM_CCMR2_IC4F_MASK (15U << 12)
#define STM32_TIM_CCMR2_IC4F(n) ((n) << 12)
/** @} */
/**
* @name TIM_CCER register
* @{
*/
#define STM32_TIM_CCER_CC1E (1U << 0)
#define STM32_TIM_CCER_CC1P (1U << 1)
#define STM32_TIM_CCER_CC1NE (1U << 2)
#define STM32_TIM_CCER_CC1NP (1U << 3)
#define STM32_TIM_CCER_CC2E (1U << 4)
#define STM32_TIM_CCER_CC2P (1U << 5)
#define STM32_TIM_CCER_CC2NE (1U << 6)
#define STM32_TIM_CCER_CC2NP (1U << 7)
#define STM32_TIM_CCER_CC3E (1U << 8)
#define STM32_TIM_CCER_CC3P (1U << 9)
#define STM32_TIM_CCER_CC3NE (1U << 10)
#define STM32_TIM_CCER_CC3NP (1U << 11)
#define STM32_TIM_CCER_CC4E (1U << 12)
#define STM32_TIM_CCER_CC4P (1U << 13)
#define STM32_TIM_CCER_CC4NP (1U << 15)
#define STM32_TIM_CCER_CC5E (1U << 16)
#define STM32_TIM_CCER_CC5P (1U << 17)
#define STM32_TIM_CCER_CC6E (1U << 20)
#define STM32_TIM_CCER_CC6P (1U << 21)
/** @} */
/**
* @name TIM_CNT register
* @{
*/
#define STM32_TIM_CNT_UIFCPY (1U << 31)
/** @} */
/**
* @name TIM_BDTR register
* @{
*/
#define STM32_TIM_BDTR_DTG_MASK (255U << 0)
#define STM32_TIM_BDTR_DTG(n) ((n) << 0)
#define STM32_TIM_BDTR_LOCK_MASK (3U << 8)
#define STM32_TIM_BDTR_LOCK(n) ((n) << 8)
#define STM32_TIM_BDTR_OSSI (1U << 10)
#define STM32_TIM_BDTR_OSSR (1U << 11)
#define STM32_TIM_BDTR_BKE (1U << 12)
#define STM32_TIM_BDTR_BKP (1U << 13)
#define STM32_TIM_BDTR_AOE (1U << 14)
#define STM32_TIM_BDTR_MOE (1U << 15)
#define STM32_TIM_BDTR_BKF_MASK (15U << 16)
#define STM32_TIM_BDTR_BKF(n) ((n) << 16)
#define STM32_TIM_BDTR_BK2F_MASK (15U << 20)
#define STM32_TIM_BDTR_BK2F(n) ((n) << 20)
#define STM32_TIM_BDTR_BK2E (1U << 24)
#define STM32_TIM_BDTR_BK2P (1U << 25)
/** @} */
/**
* @name TIM_DCR register
* @{
*/
#define STM32_TIM_DCR_DBA_MASK (31U << 0)
#define STM32_TIM_DCR_DBA(n) ((n) << 0)
#define STM32_TIM_DCR_DBL_MASK (31U << 8)
#define STM32_TIM_DCR_DBL(b) ((n) << 8)
/** @} */
/**
* @name TIM16_OR register
* @{
*/
#define STM32_TIM16_OR_TI1_RMP_MASK (3U << 6)
#define STM32_TIM16_OR_TI1_RMP(n) ((n) << 6)
/** @} */
/**
* @name TIM_OR register
* @{
*/
#define STM32_TIM_OR_ETR_RMP_MASK (15U << 0)
#define STM32_TIM_OR_ETR_RMP(n) ((n) << 0)
/** @} */
/**
* @name TIM_CCMR3 register
* @{
*/
#define STM32_TIM_CCMR3_OC5FE (1U << 2)
#define STM32_TIM_CCMR3_OC5PE (1U << 3)
#define STM32_TIM_CCMR3_OC5M_MASK 0x00010070
#define STM32_TIM_CCMR3_OC5M(n) ((((n) & 3) << 4) | \
(((n) & 4) << 16))
#define STM32_TIM_CCMR3_OC5CE (1U << 7)
#define STM32_TIM_CCMR3_OC6FE (1U << 10)
#define STM32_TIM_CCMR3_OC6PE (1U << 11)
#define STM32_TIM_CCMR3_OC6M_MASK 0x01007000
#define STM32_TIM_CCMR3_OC6M(n) ((((n) & 3) << 8) | \
(((n) & 4) << 24))
#define STM32_TIM_CCMR3_OC6CE (1U << 15)
/** @} */
/**
* @name TIM units references
* @{
*/
#define STM32_TIM1 ((stm32_tim_t *)TIM1_BASE)
#define STM32_TIM2 ((stm32_tim_t *)TIM2_BASE)
#define STM32_TIM3 ((stm32_tim_t *)TIM3_BASE)
#define STM32_TIM4 ((stm32_tim_t *)TIM4_BASE)
#define STM32_TIM5 ((stm32_tim_t *)TIM5_BASE)
#define STM32_TIM6 ((stm32_tim_t *)TIM6_BASE)
#define STM32_TIM7 ((stm32_tim_t *)TIM7_BASE)
#define STM32_TIM8 ((stm32_tim_t *)TIM8_BASE)
#define STM32_TIM9 ((stm32_tim_t *)TIM9_BASE)
#define STM32_TIM10 ((stm32_tim_t *)TIM10_BASE)
#define STM32_TIM11 ((stm32_tim_t *)TIM11_BASE)
#define STM32_TIM12 ((stm32_tim_t *)TIM12_BASE)
#define STM32_TIM13 ((stm32_tim_t *)TIM13_BASE)
#define STM32_TIM14 ((stm32_tim_t *)TIM14_BASE)
#define STM32_TIM15 ((stm32_tim_t *)TIM15_BASE)
#define STM32_TIM16 ((stm32_tim_t *)TIM16_BASE)
#define STM32_TIM17 ((stm32_tim_t *)TIM17_BASE)
#define STM32_TIM18 ((stm32_tim_t *)TIM18_BASE)
#define STM32_TIM19 ((stm32_tim_t *)TIM19_BASE)
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief STM32 TIM registers block.
* @note This is the most general known form, not all timers have
* necessarily all registers and bits.
*/
typedef struct {
volatile uint32_t CR1;
volatile uint32_t CR2;
volatile uint32_t SMCR;
volatile uint32_t DIER;
volatile uint32_t SR;
volatile uint32_t EGR;
volatile uint32_t CCMR1;
volatile uint32_t CCMR2;
volatile uint32_t CCER;
volatile uint32_t CNT;
volatile uint32_t PSC;
volatile uint32_t ARR;
volatile uint32_t RCR;
volatile uint32_t CCR[4];
volatile uint32_t BDTR;
volatile uint32_t DCR;
volatile uint32_t DMAR;
volatile uint32_t OR;
volatile uint32_t CCMR3;
volatile uint32_t CCR5;
volatile uint32_t CCR6;
} stm32_tim_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#endif /* _STM32_TIM_H_ */
/** @} */