adjust root folder
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief PWM service for XMEGA.
|
||||
*
|
||||
* Copyright (c) 2012 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asf.h>
|
||||
|
||||
/**
|
||||
* \brief Calculate TC settings from PWM frequency
|
||||
*
|
||||
* This function will find the correct TC settings (clock prescaler and
|
||||
* period) which will give the wanted PWM frequency.
|
||||
*
|
||||
* \note Since we want to be able to run the PWM at all duty-cycles ranging
|
||||
* from 0-100%, we require a period of at least 100 to achieve this. Thus, the
|
||||
* highest possible PWM frequency is CPU frequency / 100.
|
||||
*
|
||||
* \param config Pointer to PWM configuration.
|
||||
* \param freq_hz Wanted PWM frequency in Hz.
|
||||
*/
|
||||
void pwm_set_frequency(struct pwm_config *config, uint16_t freq_hz)
|
||||
{
|
||||
uint32_t cpu_hz = sysclk_get_cpu_hz();
|
||||
uint16_t smallest_div;
|
||||
uint16_t dividor;
|
||||
|
||||
/* Avoid division by zero. */
|
||||
Assert(freq_hz != 0);
|
||||
|
||||
/* Calculate the smallest divider for the requested frequency
|
||||
related to the CPU frequency */
|
||||
smallest_div = cpu_hz / freq_hz / 0xFFFF;
|
||||
if (smallest_div < 1) {
|
||||
dividor = 1;
|
||||
config->clk_sel = PWM_CLK_DIV1;
|
||||
} else if (smallest_div < 2) {
|
||||
dividor = 2;
|
||||
config->clk_sel = PWM_CLK_DIV2;
|
||||
} else if (smallest_div < 4) {
|
||||
dividor = 4;
|
||||
config->clk_sel = PWM_CLK_DIV4;
|
||||
} else if (smallest_div < 8) {
|
||||
dividor = 8;
|
||||
config->clk_sel = PWM_CLK_DIV8;
|
||||
} else if (smallest_div < 64) {
|
||||
dividor = 64;
|
||||
config->clk_sel = PWM_CLK_DIV64;
|
||||
} else if (smallest_div < 256) {
|
||||
dividor = 256;
|
||||
config->clk_sel = PWM_CLK_DIV256;
|
||||
} else {
|
||||
dividor = 1024;
|
||||
config->clk_sel = PWM_CLK_DIV1024;
|
||||
}
|
||||
|
||||
/* Calculate the period from the just found divider */
|
||||
config->period = cpu_hz / dividor / freq_hz;
|
||||
|
||||
/* Make sure our period is at least 100 ticks so we are able to provide
|
||||
a full range (0-100% duty cycle */
|
||||
if (config->period < 100) {
|
||||
/* The period is too short. */
|
||||
config->clk_sel = PWM_CLK_OFF;
|
||||
config->period = 0;
|
||||
Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize PWM configuration struct and set correct I/O pin to output
|
||||
*
|
||||
* \param config Pointer to PWM configuration struct.
|
||||
* \param tc \ref pwm_tc_t "TC" to use for this PWM.
|
||||
* \param channel \ref pwm_channel_t "CC channel" to use for this PWM.
|
||||
* \param freq_hz Frequency to use for this PWM.
|
||||
*/
|
||||
void pwm_init(struct pwm_config *config, enum pwm_tc_t tc,
|
||||
enum pwm_channel_t channel, uint16_t freq_hz)
|
||||
{
|
||||
/* Number of channels for this TC */
|
||||
uint8_t num_chan = 0;
|
||||
UNUSED(num_chan);
|
||||
|
||||
/* Set TC and correct I/O pin to output */
|
||||
switch (tc) {
|
||||
#if defined(TCC0)
|
||||
case PWM_TCC0:
|
||||
config->tc = &TCC0;
|
||||
PORTC.DIR |= (1 << (channel-1));
|
||||
num_chan = 4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(TCC1)
|
||||
case PWM_TCC1:
|
||||
config->tc = &TCC1;
|
||||
PORTC.DIR |= (1 << (channel+3));
|
||||
num_chan = 2;
|
||||
break;
|
||||
#endif
|
||||
#if defined(TCD0)
|
||||
case PWM_TCD0:
|
||||
config->tc = &TCD0;
|
||||
PORTD.DIR |= (1 << (channel-1));
|
||||
num_chan = 4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(TCD1)
|
||||
case PWM_TCD1:
|
||||
config->tc = &TCD1;
|
||||
PORTD.DIR |= (1 << (channel+3));
|
||||
num_chan = 2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCE0)
|
||||
case PWM_TCE0:
|
||||
config->tc = &TCE0;
|
||||
PORTE.DIR |= (1 << (channel-1));
|
||||
num_chan = 4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(TCE1)
|
||||
case PWM_TCE1:
|
||||
config->tc = &TCE1;
|
||||
PORTE.DIR |= (1 << (channel+3));
|
||||
num_chan = 2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCF0)
|
||||
case PWM_TCF0:
|
||||
config->tc = &TCF0;
|
||||
PORTF.DIR |= (1 << (channel-1));
|
||||
num_chan = 4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(TCF1)
|
||||
case PWM_TCF1:
|
||||
config->tc = &TCF1;
|
||||
PORTF.DIR |= (1 << (channel+3));
|
||||
num_chan = 2;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make sure we are not given a channel number larger
|
||||
than this TC can handle */
|
||||
Assert(channel <= num_chan);
|
||||
config->channel = channel;
|
||||
|
||||
/* Set the correct cc_mask */
|
||||
switch (channel) {
|
||||
case PWM_CH_A:
|
||||
config->cc_mask = TC_CCAEN;
|
||||
break;
|
||||
case PWM_CH_B:
|
||||
config->cc_mask = TC_CCBEN;
|
||||
break;
|
||||
case PWM_CH_C:
|
||||
config->cc_mask = TC_CCCEN;
|
||||
break;
|
||||
case PWM_CH_D:
|
||||
config->cc_mask = TC_CCDEN;
|
||||
break;
|
||||
default:
|
||||
Assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable peripheral clock for this TC */
|
||||
tc_enable(config->tc);
|
||||
|
||||
/* Set this TC's waveform generator in single slope mode */
|
||||
tc_set_wgm(config->tc, TC_WG_SS);
|
||||
|
||||
/* Default values (disable TC and set minimum period)*/
|
||||
config->period = 0;
|
||||
config->clk_sel = PWM_CLK_OFF;
|
||||
tc_write_clock_source(config->tc, PWM_CLK_OFF);
|
||||
|
||||
/* Set the PWM frequency */
|
||||
pwm_set_frequency(config, freq_hz);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start a PWM channel
|
||||
*
|
||||
* This function enables a channel with a given duty cycle.
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
* \param duty_cycle_scale Duty cycle as a value between 0 and 100.
|
||||
*/
|
||||
void pwm_start(struct pwm_config *config, uint8_t duty_cycle_scale)
|
||||
{
|
||||
/* Set given duty cycle */
|
||||
pwm_set_duty_cycle_percent(config, duty_cycle_scale);
|
||||
/* Set correct TC period */
|
||||
tc_write_period(config->tc, config->period);
|
||||
/* Enable CC channel for this TC */
|
||||
tc_enable_cc_channels(config->tc, config->cc_mask);
|
||||
/* Enable TC by setting correct clock prescaler */
|
||||
tc_write_clock_source(config->tc, config->clk_sel);
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief PWM service for XMEGA.
|
||||
*
|
||||
* Copyright (c) 2012 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PWM_H
|
||||
#define PWM_H
|
||||
|
||||
#include "tc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup pwm_group XMEGA Pulse Width Modulation (PWM) service
|
||||
*
|
||||
* See \ref pwm_quickstart.
|
||||
*
|
||||
* This is a service for single slope wave form generation on the XMEGA.
|
||||
* It provides functions for enabling, disabling and configuring the TC modules
|
||||
* in single slope PWM mode.
|
||||
*
|
||||
* The API uses a \ref pwm_config "structure" which contain the configuration.
|
||||
* This structure must be set up before the PWM can be started.
|
||||
*
|
||||
* \section dependencies Dependencies
|
||||
* This driver depends on the following modules:
|
||||
* - \ref tc_group to set up TC in PWM mode.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief PWM compare channel index
|
||||
*/
|
||||
enum pwm_channel_t {
|
||||
/** Channel A. PWM output on pin 0 */
|
||||
PWM_CH_A = 1,
|
||||
/** Channel B. PWM output on pin 1 */
|
||||
PWM_CH_B = 2,
|
||||
/** Channel C. PWM output on pin 2 */
|
||||
PWM_CH_C = 3,
|
||||
/** Channel D. PWM output on pin 3 */
|
||||
PWM_CH_D = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Valid timer/counters to use
|
||||
* \note Not all timer/counters are available on all devices.
|
||||
* Please refer to the datasheet for more information on what
|
||||
* timer/counters are available for the device you are using.
|
||||
*/
|
||||
enum pwm_tc_t {
|
||||
/** PWM on port C, pin 0, 1, 2 or 3 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCC0,
|
||||
/** PWM on port C, pin 4 or 5 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCC1,
|
||||
/** PWM on port D, pin 0, 1, 2 or 3 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCD0,
|
||||
/** PWM on port D, pin 4 or 5 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCD1,
|
||||
/** PWM on port E, pin 0, 1, 2 or 3 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCE0,
|
||||
/** PWM on port E, pin 4 or 5 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCE1,
|
||||
/** PWM on port F, pin 0, 1, 2 or 3 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCF0,
|
||||
/** PWM on port F, pin 4 or 5 (depending on
|
||||
\ref pwm_channel_t "channel") */
|
||||
PWM_TCF1,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Valid clock source indexes
|
||||
*/
|
||||
enum pwm_clk_sel {
|
||||
PWM_CLK_OFF = TC_CLKSEL_OFF_gc,
|
||||
PWM_CLK_DIV1 = TC_CLKSEL_DIV1_gc,
|
||||
PWM_CLK_DIV2 = TC_CLKSEL_DIV2_gc,
|
||||
PWM_CLK_DIV4 = TC_CLKSEL_DIV4_gc,
|
||||
PWM_CLK_DIV8 = TC_CLKSEL_DIV8_gc,
|
||||
PWM_CLK_DIV64 = TC_CLKSEL_DIV64_gc,
|
||||
PWM_CLK_DIV256 = TC_CLKSEL_DIV256_gc,
|
||||
PWM_CLK_DIV1024 = TC_CLKSEL_DIV1024_gc,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief PWM configuration
|
||||
*/
|
||||
struct pwm_config {
|
||||
void *tc;
|
||||
enum pwm_channel_t channel;
|
||||
enum tc_cc_channel_mask_enable_t cc_mask;
|
||||
enum pwm_clk_sel clk_sel;
|
||||
uint16_t period;
|
||||
};
|
||||
|
||||
/** \brief Interrupt callback type */
|
||||
typedef void (*pwm_callback_t) (void);
|
||||
|
||||
void pwm_init(struct pwm_config *config, enum pwm_tc_t tc,
|
||||
enum pwm_channel_t channel, uint16_t freq_hz);
|
||||
void pwm_set_frequency(struct pwm_config *config, uint16_t freq_hz);
|
||||
void pwm_start(struct pwm_config *config, uint8_t duty_cycle_scale);
|
||||
|
||||
/**
|
||||
* \brief Function to set PWM duty cycle
|
||||
*
|
||||
* The duty cycle can be set on a scale between 0-100%. This value
|
||||
* will be used to update the CCx register for the selected PWM channel.
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
* \param duty_cycle_scale Duty cycle as a value between 0 and 100.
|
||||
*/
|
||||
static inline void pwm_set_duty_cycle_percent(struct pwm_config *config,
|
||||
uint8_t duty_cycle_scale)
|
||||
{
|
||||
Assert( duty_cycle_scale <= 100 );
|
||||
tc_write_cc_buffer(config->tc, config->channel,
|
||||
(uint16_t)(((uint32_t)config->period *
|
||||
(uint32_t)duty_cycle_scale) / 100));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Function that stops the PWM timer
|
||||
*
|
||||
* The PWM timer is stopped by writing the prescaler register to "clock off"
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
*/
|
||||
static inline void pwm_stop(struct pwm_config *config)
|
||||
{
|
||||
tc_write_clock_source(config->tc, TC_CLKSEL_OFF_gc);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable the PWM timer
|
||||
*
|
||||
* This function disables the peripheral clock for the timer and shut down
|
||||
* module when unused in order to save power.
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
*/
|
||||
static inline void pwm_disable(struct pwm_config *config)
|
||||
{
|
||||
pwm_stop(config);
|
||||
tc_disable(config->tc);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Function that resets the PWM timer
|
||||
*
|
||||
* This function reset the CNT register for the selected timer used for PWM
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
*/
|
||||
static inline void pwm_timer_reset(struct pwm_config *config)
|
||||
{
|
||||
tc_write_count(config->tc, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Callback function for timer overflow interrupts
|
||||
*
|
||||
* This function enables T/C overflow interrupts (low level interrupts)
|
||||
* and defines the callback function for the overflow ISR interrupt routine.
|
||||
*
|
||||
* \param *config Pointer to the PWM configuration struct
|
||||
* \param callback Callback function
|
||||
*/
|
||||
static inline void pwm_overflow_int_callback(struct pwm_config *config,
|
||||
pwm_callback_t callback)
|
||||
{
|
||||
tc_set_overflow_interrupt_level(config->tc, TC_INT_LVL_LO);
|
||||
tc_set_overflow_interrupt_callback(config->tc, callback);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \page pwm_quickstart Quickstart guide for AVR XMEGA PWM service
|
||||
*
|
||||
* This is the quickstart guide for the \ref pwm_group,
|
||||
* with step-by-step instructions on how to configure and use the service in a
|
||||
* selection of use cases.
|
||||
*
|
||||
* The use cases contain several code fragments. The code fragments in the
|
||||
* steps for setup can be copied into a custom initialization function, while
|
||||
* the steps for usage can be copied into, e.g., the main application function.
|
||||
*
|
||||
* \section basic_use_case Basic use case
|
||||
* In the most basic use case, we configure one PWM channel in non-interrupt
|
||||
* mode.
|
||||
*
|
||||
* \section pwm_basic_use_case_setup Setup steps
|
||||
* \subsection pwm_basic_use_case_setup_code Example code
|
||||
* Add to application C-file:
|
||||
* \code
|
||||
* struct pwm_config pwm_cfg;
|
||||
*
|
||||
* sysclk_init();
|
||||
* pwm_init(&pwm_cfg, PWM_TCE0, PWM_CH_A, 500);
|
||||
* \endcode
|
||||
*
|
||||
* \subsection pwm_basic_use_case_setup_flow Workflow
|
||||
* -# Ensure that \ref conf_clock.h is present for the driver.
|
||||
* \note This file is only for the driver and should not be included by the
|
||||
* user.
|
||||
* -# Define config struct for PWM module:
|
||||
* \code struct pwm_config pwm_cfg; \endcode
|
||||
* -# Initialize sysclock module:
|
||||
* \code sysclk_init();\endcode
|
||||
* -# Initialize config struct and set up PWM with frequency of 500 Hz.\n
|
||||
* \code pwm_init(&pwm_cfg, PWM_TCE0, PWM_CH_A, 500); \endcode
|
||||
* \note Since the timer/counter \ref PWM_TCE0 and channel \ref PWM_CH_A
|
||||
* is used, the PWM will be output on port E, pin 0.
|
||||
* See \ref pwm_tc_t and \ref pwm_channel_t for more information
|
||||
* on what port/pin is used for different timer/counters.
|
||||
|
||||
* \attention This step must not be skipped or the initial content of the
|
||||
* structs will be unpredictable, possibly causing misconfiguration.
|
||||
*
|
||||
* \section pwm_basic_use_case_usage Usage steps
|
||||
* \subsection pwm_basic_use_case_usage_code Example code
|
||||
* Add to, e.g., main loop in application C-file:
|
||||
* \code pwm_start(&pwm_config, 50); \endcode
|
||||
*
|
||||
* \subsection pwm_basic_use_case_usage_flow Workflow
|
||||
* -# Start PWM with 50% duty cycle:
|
||||
* \code pwm_start(&pwm_config, 50); \endcode
|
||||
*
|
||||
* \section pwm_use_cases Advanced use cases
|
||||
* For more advanced use of the PWM service, see the following use cases:
|
||||
* - \subpage pwm_use_case_1 : PWM with interrupt
|
||||
*/
|
||||
/**
|
||||
* \page pwm_use_case_1 Use case #1
|
||||
* In this use case the PWM module is configured with overflow interrupt.
|
||||
*
|
||||
* \section pwm_use_case_1_setup Setup steps
|
||||
* \subsection pwm_use_case_1_setup_code Example code
|
||||
*
|
||||
* Add to application C-file:
|
||||
* \code
|
||||
* struct pwm_config pwm_cfg;
|
||||
*
|
||||
* void my_callback(void)
|
||||
* {
|
||||
* do_something();
|
||||
* }
|
||||
|
||||
* void pwm_init(void)
|
||||
* {
|
||||
* pmic_init();
|
||||
* sysclk_init();
|
||||
*
|
||||
* cpu_irq_enable();
|
||||
*
|
||||
* pwm_init(&pwm_cfg, PWM_TCE0, PWM_CH_A, 75);
|
||||
* pwm_overflow_int_callback(&pwm_cfg, my_callback);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \subsection pwm_use_case_1_setup_flow Workflow
|
||||
* -# Define config struct for PWM module:
|
||||
* \code struct pwm_config pwm_cfg; \endcode
|
||||
* -# Define a callback function in the application which does whatever task
|
||||
* you want it to do:
|
||||
* \code
|
||||
* void my_callback(void)
|
||||
* {
|
||||
* do_something();
|
||||
* }
|
||||
* \endcode
|
||||
* -# Initialize interrupt controller module:
|
||||
* \code pmic_init();\endcode
|
||||
* -# Initialize sysclock module:
|
||||
* \code sysclk_init();\endcode
|
||||
* -# Enable global interrupts:
|
||||
* \code cpu_irq_enable();\endcode
|
||||
* -# Initialize config struct and set up PWM with frequency of 75 Hz:
|
||||
* \code pwm_init(&pwm_cfg, PWM_TCE0, PWM_CH_A, 75); \endcode
|
||||
* \note Since the timer/counter \ref PWM_TCE0 and channel \ref PWM_CH_A
|
||||
* is used, the PWM will be output on port E, pin 0.
|
||||
* See \ref pwm_tc_t and \ref pwm_channel_t for more information
|
||||
* on what port/pin is used for different timer/counters.
|
||||
* \attention This step must not be skipped or the initial content of the
|
||||
* structs will be unpredictable, possibly causing misconfiguration.
|
||||
* -# Set callback function on PWM TC channel overflow:
|
||||
* \code pwm_overflow_int_callback(&pwm_cfg, my_callback); \endcode
|
||||
*
|
||||
* \section pwm_use_case_1_usage Usage steps
|
||||
* \subsection pwm_use_case_1_usage_code Example code
|
||||
* Add to, e.g., main loop in application C-file:
|
||||
* \code pwm_start(&pwm_cfg, 50); \endcode
|
||||
*
|
||||
* \subsection pwm_basic_use_case_usage_flow Workflow
|
||||
* -# Start PWM with 50% duty cycle:
|
||||
* \code pwm_start(&pwm_cfg, 50); \endcode
|
||||
*
|
||||
*/
|
||||
|
||||
#endif /* PWM_H */
|
||||
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* \file timeout.c
|
||||
*
|
||||
* \brief Timeout service for XMEGA
|
||||
*
|
||||
* Copyright (C) 2011-2012 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
#include <asf.h>
|
||||
#include <conf_timeout.h>
|
||||
|
||||
/* Check if RTC32 is defined, otherwise use RTC as default */
|
||||
#if defined(CLOCK_SOURCE_RTC32)
|
||||
#include <rtc32.h>
|
||||
#else
|
||||
#include <rtc.h>
|
||||
#endif
|
||||
|
||||
/** \brief Timeout timekeeping data */
|
||||
struct timeout_struct {
|
||||
/**
|
||||
* Current count-down value. Counts down for every tick.
|
||||
* Will be considered as expired when it reaches 0, and
|
||||
* may then be reloaded with period.
|
||||
*/
|
||||
uint16_t count;
|
||||
|
||||
/**
|
||||
* Period between expires. Used to reload count.
|
||||
* If 0, the count won't be reloaded.
|
||||
*/
|
||||
uint16_t period;
|
||||
};
|
||||
|
||||
/** Array of configurable timeout timekeeping data */
|
||||
static struct timeout_struct timeout_array[TIMEOUT_COUNT];
|
||||
|
||||
/** Bitmask of active timeouts */
|
||||
static uint8_t timeout_active;
|
||||
|
||||
/** Bitmask of expired timeouts */
|
||||
static uint8_t timeout_expired;
|
||||
|
||||
/**
|
||||
* \brief Callback function for RTC compare interrupt handler
|
||||
*
|
||||
* The function executes when the RTC compare interrupt occurs and loop
|
||||
* through all timeout channels. The timeout_array[channel_index] which
|
||||
* contains the remaining ticks before timeout is decremented and the timeout
|
||||
* active/expired masks are updated.
|
||||
*/
|
||||
static void tick_handler(uint32_t time)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* Loop through all timeout channels */
|
||||
for (i = 0; i < TIMEOUT_COUNT; i++) {
|
||||
/* Skip processing on current channel if not active */
|
||||
if (!(timeout_active & (1 << i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Decrement current channel with one tick */
|
||||
timeout_array[i].count--;
|
||||
|
||||
/* Skip further processing on current channel if not expired */
|
||||
if (timeout_array[i].count) {
|
||||
continue;
|
||||
} else {
|
||||
/* Update expired bit mask with current channel */
|
||||
timeout_expired |= 1 << i;
|
||||
|
||||
/* If Periodic timer, reset timeout counter to period
|
||||
* time */
|
||||
if (timeout_array[i].period) {
|
||||
timeout_array[i].count
|
||||
= timeout_array[i].period;
|
||||
}
|
||||
/* If not periodic timeout, set current channel to
|
||||
* in-active */
|
||||
else {
|
||||
timeout_active &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Reset RTC before next tick */
|
||||
rtc_set_time(0);
|
||||
rtc_set_alarm(TIMEOUT_COMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize timeout
|
||||
*
|
||||
* Initializes timeout counter for desired tick rate and starts it. The device
|
||||
* interrupt controller should be initialized prior to calling this function,
|
||||
* and global interrupts must be enabled.
|
||||
*
|
||||
* \note If the service is configured to use the asynchronous RTC32 module,
|
||||
* there are restrictions on the timeout period that can be used - see
|
||||
* to \ref rtc32_min_alarm_time for details.
|
||||
*/
|
||||
void timeout_init(void)
|
||||
{
|
||||
rtc_init();
|
||||
rtc_set_callback(tick_handler);
|
||||
rtc_set_time(0);
|
||||
rtc_set_alarm(TIMEOUT_COMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start periodic timeout with a specific start timeout
|
||||
*
|
||||
* \param id \ref timeout_id_t
|
||||
* \param period Time period in number of ticks
|
||||
* \param offset Time to first timeout in number of ticks
|
||||
*/
|
||||
void timeout_start_offset(timeout_id_t id, uint16_t period, uint16_t offset)
|
||||
{
|
||||
/* Check that ID within the TIMEOUT_COUNT range */
|
||||
if (id < TIMEOUT_COUNT) {
|
||||
/* Disable interrupts before tweaking the bitmasks */
|
||||
irqflags_t flags;
|
||||
flags = cpu_irq_save();
|
||||
|
||||
/* Update timeout struct with offset and period */
|
||||
timeout_array[id].count = offset;
|
||||
timeout_array[id].period = period;
|
||||
|
||||
/* Set current timeout channel bitmasks to active and not
|
||||
* expired */
|
||||
timeout_active |= 1 << id;
|
||||
timeout_expired &= ~(1 << id);
|
||||
|
||||
/* Restore interrupts */
|
||||
cpu_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start singleshot timeout
|
||||
*
|
||||
* \param id \ref timeout_id_t
|
||||
* \param timeout Timeout in number of ticks
|
||||
*/
|
||||
void timeout_start_singleshot(timeout_id_t id, uint16_t timeout)
|
||||
{
|
||||
timeout_start_offset(id, 0, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start periodic timeout
|
||||
*
|
||||
* \param id \ref timeout_id_t
|
||||
* \param period Time period in number of ticks
|
||||
*/
|
||||
void timeout_start_periodic(timeout_id_t id, uint16_t period)
|
||||
{
|
||||
timeout_start_offset(id, period, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Test and clear expired flag for running timeout
|
||||
*
|
||||
* \param id \ref timeout_id_t
|
||||
* \retval true Timer have expired; clearing expired flag
|
||||
* \retval false Timer still running
|
||||
*/
|
||||
bool timeout_test_and_clear_expired(timeout_id_t id)
|
||||
{
|
||||
/* Check that ID within the TIMEOUT_COUNT range */
|
||||
if (id < TIMEOUT_COUNT) {
|
||||
irqflags_t flags;
|
||||
|
||||
/* Check if timeout has expired */
|
||||
if (timeout_expired & (1 << id)) {
|
||||
flags = cpu_irq_save();
|
||||
timeout_expired &= ~(1 << id);
|
||||
cpu_irq_restore(flags);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Stop running timeout
|
||||
*
|
||||
* \param id \ref timeout_id_t
|
||||
*/
|
||||
void timeout_stop(timeout_id_t id)
|
||||
{
|
||||
irqflags_t flags;
|
||||
flags = cpu_irq_save();
|
||||
timeout_active &= ~(1 << id);
|
||||
cpu_irq_restore(flags);
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
/**
|
||||
* \file timeout.h
|
||||
*
|
||||
* \brief Timeout service for XMEGA
|
||||
*
|
||||
* Copyright (C) 2011-2012 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
#ifndef TIMEOUT_H
|
||||
#define TIMEOUT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <compiler.h>
|
||||
#include <asf.h>
|
||||
#include "conf_timeout.h"
|
||||
|
||||
/**
|
||||
* \defgroup timeout_group Timeout service XMEGA
|
||||
*
|
||||
* See \ref timeout_quickstart.
|
||||
*
|
||||
* The timeout service uses the asynchronous RTC/RTC32 in order to have a
|
||||
* system tick. Typical tick rate is 1-1000Hz. Clock sources available:
|
||||
* - Internal 32kHz ULP oscillator
|
||||
* - Internal 32kHz calibrated RC oscillator
|
||||
* - External 32kHz crystal oscillator
|
||||
* - External clock (Not available on all devices)
|
||||
*
|
||||
* The timeout service is configurable to a number of independent timeout
|
||||
* channels, each with different delay setup in a number of ticks. Both
|
||||
* singleshot and periodic timeouts are supported.
|
||||
*
|
||||
* As this service provides a software layer on top of the RTC/RTC32 module it
|
||||
* will have some performance penalty, so for high performance it would be
|
||||
* recommended to implement a more specific use by implementing your own
|
||||
* interrupt handler based on this as a reference.
|
||||
*
|
||||
* \section timeout_configuration Configuration
|
||||
* Configuration is done in the config file : conf_timeout.h
|
||||
*
|
||||
* Configuration defines:
|
||||
* - \ref TIMEOUT_CLOCK_SOURCE_HZ : Frequency of clock source, used in
|
||||
* calculation of tick rate
|
||||
*
|
||||
* - \ref TIMEOUT_COUNT : Number of independent timeout channels
|
||||
* (Max 8 channels)
|
||||
*
|
||||
* - \ref TIMEOUT_TICK_HZ : Desired tick rate in Hz
|
||||
*
|
||||
* - \ref CLOCK_SOURCE_RTC32 Used to disable the RTC module (default)
|
||||
* and use the RTC32 module found in ATxmegaA3B
|
||||
* and ATxmegaA3BU.
|
||||
*
|
||||
* \section tc_timeout_interface Interface
|
||||
* The timeout internal setup needs to be configured and this is done by the
|
||||
* function tc_timeout_init().
|
||||
*
|
||||
* There are different functions for starting a timer:
|
||||
* - \ref timeout_start_singleshot() : Start a singleshot timeout.
|
||||
* - \ref timeout_start_periodic() : Start a periodic timeout.
|
||||
* - \ref timeout_start_offset() : Start a periodic timeout with a specific
|
||||
* start offset.
|
||||
*
|
||||
* Polling for timer status can be done with
|
||||
* \ref timeout_test_and_clear_expired(), and this will also clear the
|
||||
* expired flag in case of periodic timer.
|
||||
*
|
||||
* A running timer can be stopped with \ref timeout_stop().
|
||||
*
|
||||
* Common to all the function arguments are a timeout identifier, this is a
|
||||
* number starting from 0 to identify the timeout channel. Maximum of this
|
||||
* parameter is controlled by the configuration \ref TIMEOUT_COUNT.
|
||||
*
|
||||
* The start timeout functions uses timeout values represented in number of
|
||||
* ticks.
|
||||
*
|
||||
* \subsection tc_timeout_usage Usage
|
||||
* First of all, the include file is needed:
|
||||
* \code #include "timeout.h" \endcode
|
||||
*
|
||||
* Then the timeout internals need to be set up by calling:
|
||||
* \code timeout_init(); \endcode
|
||||
*
|
||||
* For simple usage starting a singleshot timeout for timeout id 0 and a timeout
|
||||
* value of 100 ticks:
|
||||
* \code
|
||||
* tc_timeout_start_singleshot(0, 100);
|
||||
* while (!timeout_test_and_clear_expired(0));
|
||||
* // do whats needed after timeout has expired
|
||||
* \endcode
|
||||
*
|
||||
* \section tc_timeout_accuracy Accuracy
|
||||
* Since this is a timeout layer on top of a system tick; the trigger time of a
|
||||
* timeout is fully depending on this system tick. This means that you might
|
||||
* not know when the next tick will count down your timeout, and this inaccuracy
|
||||
* can be from 0 to 1 system tick.
|
||||
*
|
||||
* E.g.: If you want a timeout of 1 system tick and use 1 as your timeout
|
||||
* value, this might trigger immediately. So, if you have a requirement to wait
|
||||
* at least 1 system tick, it would be recommended to use the requested value
|
||||
* + 1.
|
||||
*
|
||||
* However, if you know the system tick has passed or are using periodic timeout
|
||||
* you can be confident in the timing.
|
||||
*/
|
||||
|
||||
|
||||
// Test for missing configurations
|
||||
#if !defined(TIMEOUT_CLOCK_SOURCE_HZ)
|
||||
# error "configuration define missing: TIMEOUT_CLOCK_SOURCE_HZ"
|
||||
#endif
|
||||
|
||||
#if !defined(TIMEOUT_TICK_HZ)
|
||||
# error "configuration define missing: TIMEOUT_TICK_HZ"
|
||||
#endif
|
||||
|
||||
#if !defined(TIMEOUT_COUNT)
|
||||
# error "configuration define missing: TIMEOUT_COUNT"
|
||||
#endif
|
||||
|
||||
// Check if timeout count is within allowed range
|
||||
#if (TIMEOUT_COUNT > 8)
|
||||
# error "TIMEOUT_COUNT outside allowed range"
|
||||
#endif
|
||||
|
||||
|
||||
// Calculate tick rate
|
||||
#define TIMEOUT_COMP TIMEOUT_CLOCK_SOURCE_HZ / TIMEOUT_TICK_HZ
|
||||
|
||||
/**
|
||||
* \brief Timeout identifier
|
||||
*
|
||||
* Index for timeout channel to use. Limited by max value configured with \ref
|
||||
* TIMEOUT_COUNT.
|
||||
*/
|
||||
typedef uint8_t timeout_id_t;
|
||||
|
||||
// API functions
|
||||
void timeout_init(void);
|
||||
void timeout_start_singleshot(timeout_id_t id, uint16_t timeout);
|
||||
void timeout_start_periodic(timeout_id_t id, uint16_t period);
|
||||
void timeout_start_offset(timeout_id_t id, uint16_t period,
|
||||
uint16_t start_offset);
|
||||
bool timeout_test_and_clear_expired(timeout_id_t id);
|
||||
void timeout_stop(timeout_id_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \page timeout_quickstart Quick start guide for Timeout service
|
||||
*
|
||||
* This is the quick start guide for the \ref timeout_group, with
|
||||
* step-by-step instructions on how to configure and use the driver in a
|
||||
* selection of use cases.
|
||||
*
|
||||
* The use cases contain several code fragments. The code fragments in the
|
||||
* steps for setup can be copied into a custom initialization function, while
|
||||
* the steps for usage can be copied into, e.g., the main application function.
|
||||
*
|
||||
* \section timeout_use_cases Timeout use cases
|
||||
* - \ref timeout_basic_use_case
|
||||
* - \subpage timeout_use_case_1
|
||||
*
|
||||
* \section timeout_basic_use_case Basic use case - Toggle LEDs with periodic timeout
|
||||
* In this use case, two periodic timeouts are used to toggle two leds.
|
||||
*
|
||||
* \section timeout_basic_use_case_setup Setup steps
|
||||
*
|
||||
* \subsection timeout_basic_use_case_setup_prereq Prerequisites
|
||||
* For the setup code of this use case to work, the following must
|
||||
* be added to the project:
|
||||
* -# \ref sysclk_group
|
||||
* -# \ref pmic_group
|
||||
* -# \ref gpio_group
|
||||
* -# \ref rtc_group
|
||||
* -# Configuration info for the timeout service must be added to the
|
||||
* conf_timeout.h file (located in the config folder):
|
||||
* \code
|
||||
* #define TIMEOUT_CLOCK_SOURCE_HZ 1024
|
||||
* #define TIMEOUT_COUNT 8
|
||||
* #define TIMEOUT_TICK_HZ 4
|
||||
* \endcode
|
||||
* -# Configuration info for the RTC driver must be added to the
|
||||
* conf_rtc.h file (located in the config folder):
|
||||
* \code
|
||||
* #define CONFIG_RTC_PRESCALER RTC_PRESCALER_DIV1_gc
|
||||
* #define CONFIG_RTC_CLOCK_SOURCE CLK_RTCSRC_ULP_gc
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_basic_use_case_setup_code Example code
|
||||
* The following must be added to the project:
|
||||
* \code
|
||||
* #define TIMEOUT_0 0
|
||||
* #define TIMEOUT_1 1
|
||||
* \endcode
|
||||
*
|
||||
* Add to application initialization:
|
||||
* \code
|
||||
* sysclk_init();
|
||||
* pmic_init();
|
||||
* timeout_init();
|
||||
* timeout_start_periodic(TIMEOUT_0, 1);
|
||||
* timeout_start_periodic(TIMEOUT_1, 2);
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_basic_use_case_setup_flow Workflow
|
||||
* -# Initialize system clock:
|
||||
* - \code sysclk_init(); \endcode
|
||||
* -# Initialize the PMIC driver:
|
||||
* - \code pmic_init(); \endcode
|
||||
* -# Initialize timeout service:
|
||||
* - \code timout_init(); \endcode
|
||||
* -# Start timeout channel 0 with a period of 1 tick:
|
||||
* - \code timeout_start_periodic(TIMEOUT_0, 1); \endcode
|
||||
* -# Start timeout channel 1 with a period of 2 ticks:
|
||||
* - \code timeout_start_periodic(TIMEOUT_1, 2); \endcode
|
||||
*
|
||||
* \section timeout_basic_use_case_usage Usage steps
|
||||
*
|
||||
* \subsection timeout_basic_use_case_usage_code Example code
|
||||
* Add to application C-file:
|
||||
* \code
|
||||
* while (1) {
|
||||
* if (timeout_test_and_clear_expired(TIMEOUT_0)) {
|
||||
* gpio_toggle_pin(LED0_GPIO);
|
||||
* }
|
||||
* if (timeout_test_and_clear_expired(TIMEOUT_1)) {
|
||||
* gpio_toggle_pin(LED1_GPIO);
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_basic_use_case_usage_flow Workflow
|
||||
* -# Check if timeout on channel 0 has expired, and toggle led if it has:
|
||||
* - \code
|
||||
* if (timeout_test_and_clear_expired(TIMEOUT_0)) {
|
||||
* gpio_toggle_pin(LED0_GPIO);
|
||||
* }
|
||||
* \endcode
|
||||
* -# Check if timeout on channel 1 has expired, and toggle led if it has:
|
||||
* - \code
|
||||
* if (timeout_test_and_clear_expired(TIMEOUT_1)) {
|
||||
* gpio_toggle_pin(LED1_GPIO);
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page timeout_use_case_1 Debounce filter on a button
|
||||
*
|
||||
* In this use case, a simple debounce filter on a button will be set up.
|
||||
*
|
||||
* \section timeout_use_case_1_setup Setup steps
|
||||
*
|
||||
* \subsection timeout_use_case_1_setup_prereq Prerequisites
|
||||
* For the setup code of this use case to work, the following must
|
||||
* be added to the project:
|
||||
* -# \ref sysclk_group
|
||||
* -# \ref pmic_group
|
||||
* -# \ref gpio_group
|
||||
* -# \ref rtc_group
|
||||
* -# Configuration info for the timeout service must be added to the
|
||||
* conf_timeout.h file (located in the config folder):
|
||||
* \code
|
||||
* #define TIMEOUT_CLOCK_SOURCE_HZ 1024
|
||||
* #define TIMEOUT_COUNT 1
|
||||
* #define TIMEOUT_TICK_HZ 100
|
||||
* \endcode
|
||||
* -# Configuration info for the RTC driver must be added to the
|
||||
* conf_rtc.h file (located in the config folder):
|
||||
* \code
|
||||
* #define CONFIG_RTC_PRESCALER RTC_PRESCALER_DIV1_gc
|
||||
* #define CONFIG_RTC_CLOCK_SOURCE CLK_RTCSRC_ULP_gc
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_use_case_1_setup_code Example code
|
||||
* The following must be added to the project:
|
||||
* \code
|
||||
* #define DEBOUNCE_TIMEOUT 0
|
||||
* #define DEBOUNCE_TICKS (50 * TIMEOUT_TICK_HZ / 1000)
|
||||
* \endcode
|
||||
*
|
||||
* Add to application initialization:
|
||||
* \code
|
||||
* sysclk_init();
|
||||
* pmic_init();
|
||||
* timeout_init();
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_use_case_1_setup_flow Workflow
|
||||
* -# Initialize system clock:
|
||||
* - \code sysclk_init(); \endcode
|
||||
* -# Initialize the PMIC driver:
|
||||
* - \code pmic_init(); \endcode
|
||||
* -# Initialize timeout service:
|
||||
* - \code timout_init(); \endcode
|
||||
*
|
||||
* \subsection timeout_use_case_1_usage_code Example code
|
||||
* Add to application C-file:
|
||||
* \code
|
||||
* bool button_pressed;
|
||||
* bool button_previous_state_pressed = false;
|
||||
* while (1) {
|
||||
* button_pressed = gpio_pin_is_low(GPIO_PUSH_BUTTON_0);
|
||||
* if (button_previous_state_pressed != button_pressed) {
|
||||
* timeout_start_singleshot(DEBOUNCE_TIMEOUT, DEBOUNCE_TICKS);
|
||||
* button_previous_state_pressed = button_pressed;
|
||||
* }
|
||||
*
|
||||
* if (timeout_test_and_clear_expired(DEBOUNCE_TIMEOUT)) {
|
||||
* if (button_pressed) {
|
||||
* gpio_toggle_pin(LED0_GPIO);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \subsection timeout_use_case_1_usage_flow Workflow
|
||||
* -# Create a variable to hold state of push button:
|
||||
* - \code bool button_pressed; \endcode
|
||||
* -# Create a variable to hold previous state of push button:
|
||||
* - \code bool button_previous_state_pressed; \endcode
|
||||
* -# Get button state:
|
||||
* - \code button_pressed = gpio_pin_is_low(GPIO_PUSH_BUTTON_0); \endcode
|
||||
* -# Check if button state has changed since last iteration:
|
||||
* - \code if (button_previous_state_pressed != button_pressed) \endcode
|
||||
* -# Start debounce timeout:
|
||||
* - \code
|
||||
* timeout_start_singleshot(DEBOUNCE_TIMEOUT, DEBOUNCE_TICKS);
|
||||
* \endcode
|
||||
* -# Set previous state of button:
|
||||
* - \code button_previous_state_pressed = button_pressed; \endcode
|
||||
* -# Check if debounce timeout has expired:
|
||||
* - \code if (timeout_test_and_clear_expired(DEBOUNCE_TIMEOUT)) \endcode
|
||||
* -# Check if button is pressed down:
|
||||
* - \code if (button_pressed) \endcode
|
||||
* -# Toggle led:
|
||||
* - \code gpio_toggle_pin(LED0_GPIO); \endcode
|
||||
*/
|
||||
|
||||
#endif /* TIMEOUT_H */
|
||||
Reference in New Issue
Block a user