Remove the not implemented TIM lld files.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10421 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Theodore Ateba 2017-08-13 14:28:39 +00:00
parent a5d9d7e741
commit 1320b9c2e2
6 changed files with 0 additions and 1922 deletions

View File

@ -1,373 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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.
*/
/*
This driver is based on the work done by Matteo Serva available at
http://github.com/matteoserva/ChibiOS-AVR
*/
/**
* @file hal_gpt_lld.c
* @brief AVR GPT driver subsystem low level driver.
*
* @addtogroup GPT
* @{
*/
#include "hal.h"
#if HAL_USE_GPT || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define PRESCALER_SIZE_BASE 5
#define PRESCALER_SIZE_EXTENDED 7
// FIXME: could use better names here!
typedef struct {
volatile uint8_t *tccra;
volatile uint8_t *tccrb;
volatile uint8_t *ocr1;
volatile uint8_t *ocr2;
volatile uint8_t *tcnt1;
volatile uint8_t *tcnt2;
volatile uint8_t *tifr;
volatile uint8_t *timsk;
} timer_registers_t;
const timer_registers_t regs_table[] = {
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
{ &TCCR1A, &TCCR1B, &OCR1AH, &OCR1AL, &TCNT1H, &TCNT1L, &TIFR1, &TIMSK1 },
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
{ &TCCR2A, &TCCR2B, &OCR2A, &OCR2A, &TCNT2, &TCNT2, &TIFR2, &TIMSK2 },
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
{ &TCCR3A, &TCCR3B, &OCR3AH, &OCR3AL, &TCNT3H, &TCNT3L, &TIFR3, &TIMSK3 },
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
{ &TCCR4A, &TCCR4B, &OCR4AH, &OCR4AL, &TCNT4H, &TCNT4L, &TIFR4, &TIMSK4 },
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
{ &TCCR5A, &TCCR5B, &OCR5AH, &OCR5AL, &TCNT5H, &TCNT5L, &TIFR5, &TIMSK5 },
#endif
};
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
GPTDriver GPTD4;
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
GPTDriver GPTD5;
#endif
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
static uint16_t ratio_base[] = { 1024, 256, 64, 8, 1 };
static uint8_t clock_source_base[]= { 5, 4, 3, 2, 1 };
//static uint16_t ratio_extended[] = { 1024, 256, 128, 64, 32, 8, 1 };
//static uint8_t clock_source_extended[] = { 7, 6, 5, 4, 3, 2, 1 };
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static uint8_t prescaler(uint16_t freq, uint16_t *ratio, uint8_t n) {
uint8_t i;
for (i = 0; i < n; ++i) {
uint32_t result = F_CPU / ratio[i] / freq;
if (result > 256UL)
return i - 1;
if ((result * ratio[i] * freq) == F_CPU)
return i;
}
return -1; // TO check
}
static void gpt_lld_serve_interrupt(GPTDriver *gptp) {
gptp->counter++;
if (gptp->counter == gptp->period) {
gptp->counter = 0;
if (gptp->state == GPT_ONESHOT) {
gptp->state = GPT_READY; /* Back in GPT_READY state. */
gpt_lld_stop_timer(gptp); /* Timer automatically stopped. */
}
gptp->callback(gptp);
}
}
static void gpt_lld_dummy_callback(GPTDriver *gptp) {
}
static uint8_t getTimerIndex(GPTDriver *gptp) {
uint8_t index = 0;
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
if (gptp == &GPTD1) return index;
else index++;
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
if (gptp == &GPTD2) return index;
else index++;
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
if (gptp == &GPTD3) return index;
else index++;
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
if (gptp == &GPTD4) return index;
else index++;
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
if (gptp == &GPTD5) return index;
else index++;
#endif
return -1; // To check
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
/**
* @brief TIM1 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(TIMER1_COMPA_vect) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(TIMER2_COMPA_vect) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
/**
* @brief TIM3 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(TIMER3_COMPA_vect) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
/**
* @brief TIM4 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(TIMER4_COMPA_vect) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
/**
* @brief TIM2 interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(TIMER5_COMPA_vect) {
OSAL_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD5);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
gptObjectInit(&GPTD1);
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
gptObjectInit(&GPTD2);
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
gptObjectInit(&GPTD3);
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
gptObjectInit(&GPTD4);
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
gptObjectInit(&GPTD5);
#endif
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
uint8_t psc;
if (gptp->state == GPT_STOP) {
/* Clock activation.*/
}
/* Configuration.*/
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
if (gptp == &GPTD2) {
psc = prescaler(gptp->config->frequency, ratio_extended, PRESCALER_SIZE_EXTENDED);
gptp->clock_source = clock_source_extended[psc] & 0x07;
TCCR2A = (1 << WGM21) | (0 << WGM20);
TCCR2B = (0 << WGM22);
OCR2A = F_CPU / ratio_extended[psc] /gptp->config->frequency - 1;
return;
}
#endif
uint8_t i = getTimerIndex(gptp);
psc = prescaler(gptp->config->frequency, ratio_base, PRESCALER_SIZE_BASE);
gptp->clock_source = clock_source_base[psc] & 0x07;
*regs_table[i].tccra = (0 << WGM11) |
(0 << WGM10) |
(0 << COM1A1) |
(0 << COM1A0) |
(0 << COM1B1) |
(0 << COM1B0);
*regs_table[i].tccrb = (1 << WGM12);
*regs_table[i].ocr1 = 0;
*regs_table[i].ocr2 = F_CPU / ratio_base[psc] / gptp->config->frequency - 1;
}
/**
* @brief Deactivates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop(GPTDriver *gptp) {
/* nothing to be done */
if (gptp->state == GPT_READY) {
/* Clock de-activation.*/
}
gpt_lld_stop_timer(gptp);
}
/**
* @brief Starts the timer in continuous mode.
*
* @param[in] gptp pointer to the @p GPTDriver object
* @param[in] period period in ticks
*
* @notapi
*/
void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period) {
gptp->callback = gptp->config->callback;
gptp->period = period;
gptp->counter = 0;
uint8_t i = getTimerIndex(gptp);
*regs_table[i].tcnt1 = 0;
*regs_table[i].tcnt2 = 0;
*regs_table[i].tifr = (1 << OCF1A);
*regs_table[i].timsk = (1 << OCIE1A);
*regs_table[i].tccrb |= (gptp->clock_source << CS10);
}
/**
* @brief Stops the timer.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_stop_timer(GPTDriver *gptp) {
uint8_t i = getTimerIndex(gptp);
*regs_table[i].tccrb &= ~((7 << CS10) | (1 << OCIE1A));
*regs_table[i].tifr = (1 << OCF1A);
}
/**
* @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->callback = gpt_lld_dummy_callback;
gpt_lld_start_timer(gptp, interval);
//FIX
while (gptp->state != GPT_READY) {}
}
#endif /* HAL_USE_GPT */
/** @} */

View File

@ -1,221 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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.
*/
/*
This driver is based on the work done by Matteo Serva available at
http://github.com/matteoserva/ChibiOS-AVR
*/
/**
* @file hal_gpt_lld.h
* @brief AVR GPT driver subsystem low level driver header.
*
* @addtogroup GPT
* @{
*/
#ifndef HAL_GPT_LLD_H
#define HAL_GPT_LLD_H
#if HAL_USE_GPT || defined(__DOXYGEN__)
#include "avr_timers.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief GPT1 driver enable switch.
* @details If set to @p TRUE the support for GPT1 is included.
* @note The default is @p FALSE.
*/
#if !defined(AVR_GPT_USE_TIM1)
#define AVR_GPT_USE_TIM1 FALSE
#endif
/**
* @brief GPT2 driver enable switch.
* @details If set to @p TRUE the support for GPT2 is included.
* @note The default is @p FALSE.
*/
#if !defined(AVR_GPT_USE_TIM2)
#define AVR_GPT_USE_TIM2 FALSE
#endif
/**
* @brief GPT3 driver enable switch.
* @details If set to @p TRUE the support for GPT3 is included.
* @note The default is @p FALSE.
*/
#if !defined(AVR_GPT_USE_TIM3)
#define AVR_GPT_USE_TIM3 FALSE
#endif
/**
* @brief GPT4 driver enable switch.
* @details If set to @p TRUE the support for GPT4 is included.
* @note The default is @p FALSE.
*/
#if !defined(AVR_GPT_USE_TIM4)
#define AVR_GPT_USE_TIM4 FALSE
#endif
/**
* @brief GPT5 driver enable switch.
* @details If set to @p TRUE the support for GPT5 is included.
* @note The default is @p FALSE.
*/
#if !defined(AVR_GPT_USE_TIM5)
#define AVR_GPT_USE_TIM5 FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* 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.
*/
volatile 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 input clock from prescaler
*/
uint8_t clock_source;
/**
* @brief Lenght of the period in clock ticks
*/
gptcnt_t period;
/**
* @brief Current clock tick.
*/
gptcnt_t counter;
/**
* @brief Function called from the interrupt service routine
*/
gptcallback_t callback;
};
/*===========================================================================*/
/* 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
*/
// FIXME: placeholder to enable compile, should be implemented!
#define gpt_lld_change_interval(gptp, interval)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if AVR_GPT_USE_TIM1 || defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if AVR_GPT_USE_TIM3 || defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if AVR_GPT_USE_TIM4 || defined(__DOXYGEN__)
extern GPTDriver GPTD4;
#endif
#if AVR_GPT_USE_TIM5 || defined(__DOXYGEN__)
extern GPTDriver GPTD5;
#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 interval);
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 /* HAL_GPT_LLD_H */
/** @} */

View File

@ -1,335 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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 hal_icu_lld.c
* @brief AVR ICU driver subsystem low level driver source.
*
* @addtogroup ICU
* @{
*/
#include "hal.h"
#if HAL_USE_ICU || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
typedef struct {
volatile uint8_t *tccra;
volatile uint8_t *tccrb;
volatile uint16_t *tcnt;
volatile uint8_t *timsk;
} icu_registers_t;
static icu_registers_t regs_table[]=
{
#if AVR_ICU_USE_TIM1 || defined(__DOXYGEN__)
{&TCCR1A, &TCCR1B, &TCNT1, &TIMSK1},
#endif
#if AVR_ICU_USE_TIM3 || defined(__DOXYGEN__)
{&TCCR3A, &TCCR3B, &TCNT3, &TIMSK3},
#endif
#if AVR_ICU_USE_TIM4 || defined(__DOXYGEN__)
{&TCCR4A, &TCCR4B, &TCNT4, &TIMSK4},
#endif
#if AVR_ICU_USE_TIM5 || defined(__DOXYGEN__)
{&TCCR5A, &TCCR5B, &TCNT5, &TIMSK5},
#endif
};
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief ICU1 driver identifier.
*/
#if AVR_ICU_USE_TIM1 || defined(__DOXYGEN__)
ICUDriver ICUD1;
#endif
/**
* @brief ICU3 driver identifier.
*/
#if AVR_ICU_USE_TIM3 || defined(__DOXYGEN__)
ICUDriver ICUD3;
#endif
/**
* @brief ICU4 driver identifier.
*/
#if AVR_ICU_USE_TIM4 || defined(__DOXYGEN__)
ICUDriver ICUD4;
#endif
/**
* @brief ICU5 driver identifier.
*/
#if AVR_ICU_USE_TIM5 || defined(__DOXYGEN__)
ICUDriver ICUD5;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static inline void handle_capture_isr(ICUDriver *icup,
volatile uint16_t *icr,
volatile uint8_t *tccrb,
volatile uint16_t *tcnt)
{
uint16_t value = *icr;
uint8_t rising = (*tccrb & (1 << ICES1)) ? 1 : 0;
*tccrb ^= (1 << ICES1);
if ((icup->config->mode == ICU_INPUT_ACTIVE_HIGH && rising) ||
(icup->config->mode == ICU_INPUT_ACTIVE_LOW && !rising)) {
icup->width = value;
if (icup->config->width_cb != NULL)
icup->config->width_cb(icup);
} else {
icup->period = value;
if (icup->config->period_cb != NULL)
icup->config->period_cb(icup);
/* Reset counter at the end of every cycle */
*tcnt = 0;
}
}
static uint8_t index(ICUDriver *icup)
{
uint8_t index = 0;
#if AVR_ICU_USE_TIM1 || defined(__DOXYGEN__)
if (icup == &ICUD1) return index;
else index++;
#endif
#if AVR_ICU_USE_TIM3 || defined(__DOXYGEN__)
if (icup == &ICUD3) return index;
else index++;
#endif
#if AVR_ICU_USE_TIM4 || defined(__DOXYGEN__)
if (icup == &ICUD4) return index;
else index++;
#endif
#if AVR_ICU_USE_TIM5 || defined(__DOXYGEN__)
if (icup == &ICUD5) return index;
else index++;
#endif
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if AVR_ICU_USE_TIM1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER1_CAPT_vect)
{
OSAL_IRQ_PROLOGUE();
handle_capture_isr(&ICUD1, &ICR1, &TCCR1B, &TCNT1);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER1_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
ICUD1.config->overflow_cb(&ICUD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_ICU_USE_TIM3 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER3_CAPT_vect)
{
OSAL_IRQ_PROLOGUE();
handle_capture_isr(&ICUD3, &ICR3, &TCCR3B, &TCNT3);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER3_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
ICUD3.config->overflow_cb(&ICUD3);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_ICU_USE_TIM4 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER4_CAPT_vect)
{
OSAL_IRQ_PROLOGUE();
handle_capture_isr(&ICUD4, &ICR4, &TCCR4B, &TCNT4);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER4_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
ICUD4.config->overflow_cb(&ICUD4);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_ICU_USE_TIM5 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER5_CAPT_vect)
{
OSAL_IRQ_PROLOGUE();
handle_capture_isr(&ICUD5, &ICR5, &TCCR5B, &TCNT5);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER5_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
ICUD5.config->overflow_cb(&ICUD5);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ICU driver initialization.
*
* @notapi
*/
void icu_lld_init(void) {
#if AVR_ICU_USE_TIM1
icuObjectInit(&ICUD1);
#endif
#if AVR_ICU_USE_TIM3
icuObjectInit(&ICUD3);
#endif
#if AVR_ICU_USE_TIM4
icuObjectInit(&ICUD4);
#endif
#if AVR_ICU_USE_TIM5
icuObjectInit(&ICUD5);
#endif
}
/**
* @brief Configures and activates the ICU peripheral.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_start(ICUDriver *icup) {
if (icup->state == ICU_STOP) {
uint8_t i = index(icup);
/* Normal waveform generation (counts from 0 to 0xFFFF) */
*regs_table[i].tccra &= ~((1 << WGM11) | (1 << WGM10));
*regs_table[i].tccrb &= ~((1 << WGM13) | (1 << WGM12));
/* Enable noise canceler, set prescale to CLK/1024 */
*regs_table[i].tccrb |= (1 << ICNC1) | (1 << CS12) | (1 << CS10);
if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
*regs_table[i].tccrb |= (1 << ICES1);
else
*regs_table[i].tccrb &= ~(1 << ICES1);
}
}
/**
* @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) {
/* Resets the peripheral.*/
/* Disables the peripheral.*/
#if AVR_ICU_USE_TIM1
if (&ICUD1 == icup) {
}
#endif /* AVR_ICU_USE_TIM1 */
}
}
/**
* @brief Enables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_enable(ICUDriver *icup) {
uint8_t i = index(icup);
icup->width = icup->period = 0;
*regs_table[i].tcnt = 0;
*regs_table[i].timsk |= (1 << ICIE1);
if (icup->config->overflow_cb != NULL)
*regs_table[i].timsk |= (1 << TOIE1);
}
/**
* @brief Disables the input capture.
*
* @param[in] icup pointer to the @p ICUDriver object
*
* @notapi
*/
void icu_lld_disable(ICUDriver *icup) {
uint8_t i = index(icup);
*regs_table[i].timsk &= ~((1 << ICIE1) | (1 << TOIE1));
}
/**
* @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
*/
icucnt_t icu_lld_get_width(ICUDriver *icup) {
return icup->width;
}
/**
* @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
*/
icucnt_t icu_lld_get_period(ICUDriver *icup) {
return icup->period;
}
#endif /* HAL_USE_ICU */
/** @} */

View File

@ -1,195 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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 hal_icu_lld.h
* @brief AVR ICU driver subsystem low level driver header.
*
* @addtogroup ICU
* @{
*/
#ifndef HAL_ICU_LLD_H
#define HAL_ICU_LLD_H
#if HAL_USE_ICU || defined(__DOXYGEN__)
#include "avr_timers.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ICU driver enable switch.
* @details If set to @p TRUE the support for ICU1 is included.
*/
#if !defined(AVR_ICU_USE_TIM1) || defined(__DOXYGEN__)
#define AVR_ICU_USE_TIM1 FALSE
#endif
/**
* @brief ICU driver enable switch.
* @details If set to @p TRUE the support for ICU3 is included.
*/
#if !defined(AVR_ICU_USE_TIM3) || defined(__DOXYGEN__)
#define AVR_ICU_USE_TIM3 FALSE
#endif
/**
* @brief ICU driver enable switch.
* @details If set to @p TRUE the support for ICU4 is included.
*/
#if !defined(AVR_ICU_USE_TIM4) || defined(__DOXYGEN__)
#define AVR_ICU_USE_TIM4 FALSE
#endif
/**
* @brief ICU driver enable switch.
* @details If set to @p TRUE the support for ICU5 is included.
*/
#if !defined(AVR_ICU_USE_TIM5) || defined(__DOXYGEN__)
#define AVR_ICU_USE_TIM5 FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* 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 uint16_t icufreq_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.*/
} 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 Width value read by ISR.
*/
icucnt_t width;
/**
* @brief Period value read by ISR.
*/
icucnt_t period;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if AVR_ICU_USE_TIM1 && !defined(__DOXYGEN__)
extern ICUDriver ICUD1;
#endif
#if AVR_ICU_USE_TIM3 && !defined(__DOXYGEN__)
extern ICUDriver ICUD3;
#endif
#if AVR_ICU_USE_TIM4 && !defined(__DOXYGEN__)
extern ICUDriver ICUD4;
#endif
#if AVR_ICU_USE_TIM5 && !defined(__DOXYGEN__)
extern ICUDriver ICUD5;
#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);
icucnt_t icu_lld_get_width(ICUDriver *icup);
icucnt_t icu_lld_get_period(ICUDriver *icup);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ICU */
#endif /* HAL_ICU_LLD_H */
/** @} */

View File

@ -1,565 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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.
*/
/*
This driver is based on the work done by Matteo Serva available at
http://github.com/matteoserva/ChibiOS-AVR
*/
/**
* @file hal_pwm_lld.c
* @brief AVR PWM driver subsystem low level driver.
*
* @addtogroup PWM
* @{
*/
#include "hal.h"
#if HAL_USE_PWM || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
typedef struct {
volatile uint8_t *tccra;
volatile uint8_t *tccrb;
volatile uint8_t *ocrah;
volatile uint8_t *ocral;
volatile uint8_t *ocrbh;
volatile uint8_t *ocrbl;
volatile uint8_t *ocrch;
volatile uint8_t *ocrcl;
volatile uint8_t *tifr;
volatile uint8_t *timsk;
} timer_registers_t;
static timer_registers_t regs_table[]=
{
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
#if defined(OCR1C)
{&TCCR1A, &TCCR1B, &OCR1AH, &OCR1AL, &OCR1BH, &OCR1BL, &OCR1CH, &OCR1CL, &TIFR1, &TIMSK1},
#else
{&TCCR1A, &TCCR1B, &OCR1AH, &OCR1AL, &OCR1BH, &OCR1BL, NULL, NULL, &TIFR1, &TIMSK1},
#endif
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
{&TCCR2A, &TCCR2B, &OCR2A, &OCR2A, &OCR2B, &OCR2B, NULL, NULL, &TIFR2, &TIMSK2},
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
{&TCCR3A, &TCCR3B, &OCR3AH, &OCR3AL, &OCR3BH, &OCR3BL, &OCR3CH, &OCR3CL, &TIFR3, &TIMSK3},
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
{&TCCR4A, &TCCR4B, &OCR4AH, &OCR4AL, &OCR4CH, &OCR4CL, &OCR4CH, &OCR4CL, &TIFR4, &TIMSK4},
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
{&TCCR5A, &TCCR5B, &OCR5AH, &OCR5AL, &OCR5BH, &OCR5BL, &OCR5CH, &OCR5CL, &TIFR5, &TIMSK5},
#endif
};
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief PWM driver identifiers.*/
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
PWMDriver PWMD1;
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
PWMDriver PWMD2;
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
PWMDriver PWMD3;
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
PWMDriver PWMD4;
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
PWMDriver PWMD5;
#endif
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static void config_channel(volatile uint8_t *tccra,
uint8_t com1,
uint8_t com0,
pwmmode_t mode)
{
*tccra &= ~((1 << com1) | (1 << com0));
if (mode == PWM_OUTPUT_ACTIVE_HIGH)
*tccra |= ((1 << com1) | (0 << com0)); /* non inverting mode */
else if (mode == PWM_OUTPUT_ACTIVE_LOW)
*tccra |= (1 << com1) | (1 << com0); /* inverting mode */
}
static uint8_t timer_index(PWMDriver *pwmp)
{
uint8_t index = 0;
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
if (pwmp == &PWMD1) return index;
else index++;
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
if (pwmp == &PWMD2) return index;
else index++;
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
if (pwmp == &PWMD3) return index;
else index++;
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
if (pwmp == &PWMD4) return index;
else index++;
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
if (pwmp == &PWMD5) return index;
else index++;
#endif
/* This is an error! */
return index;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*
* interrupt for compare1&2 and clock overflow. pwmd1 & pwmd2
*/
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER1_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD1.config->callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER1_COMPA_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD1.config->channels[0].callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER1_COMPB_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD1.config->channels[1].callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
#if PWM_CHANNELS > 2
OSAL_IRQ_HANDLER(TIMER1_COMPC_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD1.config->channels[2].callback(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
#endif
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER2_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD2.config->callback(&PWMD2);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER2_COMPA_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD2.config->channels[0].callback(&PWMD2);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER2_COMPB_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD2.config->channels[1].callback(&PWMD2);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER3_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD3.config->callback(&PWMD3);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER3_COMPA_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD3.config->channels[0].callback(&PWMD3);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER3_COMPB_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD3.config->channels[1].callback(&PWMD3);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER3_COMPC_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD3.config->channels[2].callback(&PWMD3);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER4_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD4.config->callback(&PWMD4);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER4_COMPA_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD4.config->channels[0].callback(&PWMD4);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER4_COMPB_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD4.config->channels[1].callback(&PWMD4);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER4_COMPC_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD4.config->channels[2].callback(&PWMD4);
OSAL_IRQ_EPILOGUE();
}
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(TIMER5_OVF_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD5.config->callback(&PWMD5);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER5_COMPA_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD5.config->channels[0].callback(&PWMD5);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER5_COMPB_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD5.config->channels[1].callback(&PWMD5);
OSAL_IRQ_EPILOGUE();
}
OSAL_IRQ_HANDLER(TIMER5_COMPC_vect)
{
OSAL_IRQ_PROLOGUE();
PWMD5.config->channels[2].callback(&PWMD5);
OSAL_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level PWM driver initialization.
*
* @notapi
*/
void pwm_lld_init(void)
{
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
pwmObjectInit(&PWMD1);
PWMD1.channels = PWM_CHANNELS;
TCCR1A = (1 << WGM11) | (1 << WGM10);
TCCR1B = (0 << WGM13) | (1 << WGM12);
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
pwmObjectInit(&PWMD2);
PWMD2.channels = PWM_CHANNELS;
TCCR2A = (1 << WGM21) | (1 << WGM20);
TCCR2B = (0 << WGM22);
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
pwmObjectInit(&PWMD3);
PWMD3.channels = PWM_CHANNELS;
TCCR3A = (1 << WGM31) | (1 << WGM30);
TCCR3B = (0 << WGM33) | (1 << WGM32);
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
pwmObjectInit(&PWMD4);
PWMD4.channels = PWM_CHANNELS;
TCCR4A = (1 << WGM41) | (1 << WGM40);
TCCR4B = (0 << WGM43) | (1 << WGM42);
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
pwmObjectInit(&PWMD5);
PWMD5.channels = PWM_CHANNELS;
TCCR5A = (1 << WGM51) | (1 << WGM50);
TCCR5B = (0 << WGM53) | (1 << WGM52);
#endif
}
/**
* @brief Configures and activates the PWM peripheral.
*
* @param[in] pwmp pointer to the @p PWMDriver object
*
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp)
{
if (pwmp->state == PWM_STOP) {
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
if (pwmp == &PWMD2) {
TCCR2B &= ~((1 << CS22) | (1 << CS21));
TCCR2B |= (1 << CS20);
if (pwmp->config->callback != NULL)
TIMSK2 |= (1 << TOIE2);
return;
}
#endif
uint8_t i = timer_index(pwmp);
/* TODO: support other prescaler options */
*regs_table[i].tccrb &= ~(1 << CS11);
*regs_table[i].tccrb |= (1 << CS12) | (1 << CS10);
if (pwmp->config->callback != NULL)
*regs_table[i].timsk = (1 << TOIE1);
}
}
/**
* @brief Deactivates the PWM peripheral.
*
* @param[in] pwmp pointer to the @p PWMDriver object
*
* @notapi
*/
void pwm_lld_stop(PWMDriver *pwmp)
{
uint8_t i = timer_index(pwmp);
*regs_table[i].tccrb &= ~((1 << CS12) | (1 << CS11) | (1 << CS10));
*regs_table[i].timsk = 0;
}
/**
* @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
*/
void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period)
{
}
/**
* @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 Depending on the hardware implementation this function has
* effect starting on the next cycle (recommended implementation)
* or immediately (fallback implementation).
*
* @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)
{
uint16_t val = width;
if (val > MAX_PWM_VALUE)
val = MAX_PWM_VALUE;
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
if (pwmp == &PWMD2) {
config_channel(&TCCR2A,
7 - 2*channel,
6 - 2*channel,
pwmp->config->channels[channel].mode);
TIMSK2 |= (1 << (channel + 1));
/* Timer 2 is 8 bit */
if (val > 0xFF)
val = 0xFF;
if (pwmp->config->channels[channel].callback) {
switch (channel) {
case 0: OCR2A = val; break;
case 1: OCR2B = val; break;
}
}
return;
}
#endif
uint8_t i = timer_index(pwmp);
config_channel(regs_table[i].tccra,
7 - 2*channel,
6 - 2*channel,
pwmp->config->channels[channel].mode);
volatile uint8_t *ocrh, *ocrl;
switch (channel) {
case 1:
ocrh = regs_table[i].ocrbh;
ocrl = regs_table[i].ocrbl;
break;
case 2:
ocrh = regs_table[i].ocrch;
ocrl = regs_table[i].ocrcl;
break;
default:
ocrh = regs_table[i].ocrah;
ocrl = regs_table[i].ocral;
}
*ocrh = val >> 8;
*ocrl = val & 0xFF;
*regs_table[i].tifr |= (1 << (channel + 1));
if (pwmp->config->channels[channel].callback != NULL)
*regs_table[i].timsk |= (1 << (channel + 1));
}
/**
* @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 Depending on the hardware implementation this function has
* effect starting on the next cycle (recommended implementation)
* or immediately (fallback implementation).
*
* @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)
{
uint8_t i = timer_index(pwmp);
config_channel(regs_table[i].tccra,
7 - 2*channel,
6 - 2*channel,
PWM_OUTPUT_DISABLED);
*regs_table[i].timsk &= ~(1 << (channel + 1));
}
/**
* @brief Enables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
uint8_t i = timer_index(pwmp);
*regs_table[i].timsk |= (1 << TOIE1);
}
/**
* @brief Disables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
uint8_t i = timer_index(pwmp);
*regs_table[i].timsk &= ~(1 << TOIE1);
}
/**
* @brief Enables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
uint8_t i = timer_index(pwmp);
*regs_table[i].timsk |= (1 << (channel + 1));
}
/**
* @brief Disables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel) {
uint8_t i = timer_index(pwmp);
*regs_table[i].timsk &= ~(1 << (channel + 1));
}
#endif /* HAL_USE_PWM */
/** @} */

View File

@ -1,233 +0,0 @@
/*
ChibiOS - Copyright (C) 2006..2016 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.
*/
/*
This driver is based on the work done by Matteo Serva available at
http://github.com/matteoserva/ChibiOS-AVR
*/
/**
* @file hal_pwm_lld.h
* @brief AVR PWM driver subsystem low level driver header.
*
* @addtogroup PWM
* @{
*/
#ifndef HAL_PWM_LLD_H
#define HAL_PWM_LLD_H
#if HAL_USE_PWM || defined(__DOXYGEN__)
#include "avr_timers.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#if !defined(AVR_PWM_USE_TIM1)
#define AVR_PWM_USE_TIM1 FALSE
#endif
#if !defined(AVR_PWM_USE_TIM2)
#define AVR_PWM_USE_TIM2 FALSE
#endif
#if !defined(AVR_PWM_USE_TIM3)
#define AVR_PWM_USE_TIM3 FALSE
#endif
#if !defined(AVR_PWM_USE_TIM4)
#define AVR_PWM_USE_TIM4 FALSE
#endif
#if !defined(AVR_PWM_USE_TIM5)
#define AVR_PWM_USE_TIM5 FALSE
#endif
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief Number of PWM channels per PWM driver.
*/
#if !defined(PWM_CHANNELS) || defined(__DOXYGEN__)
#if defined(TIMER1_COMPC_vect)
#define PWM_CHANNELS 3
#else
#define PWM_CHANNELS 2
#endif
#endif
#define MAX_PWM_VALUE 0x3FF
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief PWM mode type.
*/
typedef uint8_t pwmmode_t;
/**
* @brief PWM channel type.
*/
typedef uint8_t pwmchannel_t;
/**
* @brief Type of a channels mask.
*/
typedef uint8_t pwmchnmsk_t;
/**
* @brief PWM counter type.
*/
typedef uint16_t pwmcnt_t;
/**
* @brief PWM driver channel configuration structure.
* @note Some architectures may not be able to support the channel mode
* or the callback, in this case the fields are ignored.
*/
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 Driver configuration structure.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
uint16_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.*/
} PWMConfig;
/**
* @brief Structure representing an PWM driver.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
struct PWMDriver {
/**
* @brief Driver state.
*/
pwmstate_t state;
/**
* @brief Current configuration data.
*/
const PWMConfig *config;
/**
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
/**
* @brief Mask of the enabled channels.
*/
pwmchnmsk_t enabled;
/**
* @brief Number of channels in this instance.
*/
pwmchannel_t channels;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if AVR_PWM_USE_TIM1 || defined(__DOXYGEN__)
extern PWMDriver PWMD1;
#endif
#if AVR_PWM_USE_TIM2 || defined(__DOXYGEN__)
extern PWMDriver PWMD2;
#endif
#if AVR_PWM_USE_TIM3 || defined(__DOXYGEN__)
extern PWMDriver PWMD3;
#endif
#if AVR_PWM_USE_TIM4 || defined(__DOXYGEN__)
extern PWMDriver PWMD4;
#endif
#if AVR_PWM_USE_TIM5 || defined(__DOXYGEN__)
extern PWMDriver PWMD5;
#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_change_period(PWMDriver *pwmp, pwmcnt_t period);
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_PWM */
#endif /* HAL_PWM_LLD_H */
/** @} */