blob: 60b033d1aaa69422c578877f3ca657e91e988135 [file] [log] [blame]
/**
* \file
*
* \brief AST driver for SAM.
*
* Copyright (C) 2012-2013 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 AST_H_INCLUDED
#define AST_H_INCLUDED
/**
* \defgroup group_sam_drivers_ast AST - Asynchronous Timer
*
* Driver for the AST (Asynchronous Timer).
* Provides functions for configuring and operating the AST in the calendar or
* timer/counter modes.
*
* \{
*/
#include "compiler.h"
/// @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond */
/** Timeout to prevent code hang in clock initialization */
#define AST_POLL_TIMEOUT 10000
/** \name Predefined PSEL Values
*/
/* @{ */
/**
* The PSEL value to set the AST source clock (after the prescaler) to 1 Hz,
* when using an external 32-kHz crystal.
*/
#define AST_PSEL_32KHZ_1HZ 14
/**
* The PSEL value to set the AST source clock (after the prescaler)
* to 1.76 Hz when using the internal RC oscillator (~ 115 kHz)
*/
#define AST_PSEL_RC_1_76HZ 15
/* @} */
/* Description for Calendar Field.*/
struct ast_calv {
uint32_t sec : 6;
uint32_t min : 6;
uint32_t hour : 5;
uint32_t day : 5;
uint32_t month : 4;
uint32_t year : 6;
};
/* Input when initializing AST in calendar mode.*/
struct ast_calendar {
union {
uint32_t field;
struct ast_calv FIELD;
};
};
typedef enum ast_mode {
AST_COUNTER_MODE = 0,
AST_CALENDAR_MODE = 1,
} ast_mode_t;
typedef enum ast_oscillator_type {
AST_OSC_RC = 0,
AST_OSC_32KHZ = 1,
AST_OSC_PB = 2,
AST_OSC_GCLK = 3,
AST_OSC_1KHZ = 4,
} ast_oscillator_type_t;
#define AST_INTERRUPT_SOURCE_NUM 5
typedef enum ast_interrupt_source {
AST_INTERRUPT_ALARM = 0,
AST_INTERRUPT_PER,
AST_INTERRUPT_OVF,
AST_INTERRUPT_READY,
AST_INTERRUPT_CLKREADY,
} ast_interrupt_source_t;
typedef enum ast_wakeup_source {
AST_WAKEUP_ALARM = 0,
AST_WAKEUP_PER,
AST_WAKEUP_OVF,
} ast_wakeup_source_t;
typedef enum ast_event_source {
AST_EVENT_ALARM = 0,
AST_EVENT_PER,
AST_EVENT_OVF,
} ast_event_source_t;
struct ast_config {
/*
* Mode: Calendar mode:
* \ref AST_CALENDAR_MODE or
* \ref Counter mode: AST_COUNTER_MODE.
*/
ast_mode_t mode;
/* Oscillator type */
ast_oscillator_type_t osc_type;
/* Prescaler Value. */
uint8_t psel;
/* Initial counter Value. */
uint32_t counter;
/* Initial calendar Value. */
struct ast_calendar calendar;
};
typedef void (*ast_callback_t)(void);
bool ast_is_enabled(Ast *ast);
void ast_enable(Ast *ast);
void ast_disable(Ast *ast);
uint32_t ast_set_config(Ast *ast, struct ast_config *ast_conf);
void ast_set_callback(Ast *ast, ast_interrupt_source_t source,
ast_callback_t callback, uint8_t irq_line, uint8_t irq_level);
uint32_t ast_configure_digital_tuner(Ast *ast, uint32_t input_freq,
uint32_t tuned_freq);
void ast_init_digital_tuner(Ast *ast, bool add, uint8_t value,
uint8_t exp);
void ast_disable_digital_tuner(Ast *ast);
void ast_write_calendar_value(Ast *ast, struct ast_calendar ast_calendar);
struct ast_calendar ast_read_calendar_value(Ast *ast);
void ast_write_counter_value(Ast *ast, uint32_t ast_counter);
void ast_enable_counter_clear_on_alarm(Ast *ast, uint8_t alarm_channel);
void ast_clear_prescalar(Ast *ast);
/**
* \brief This function returns the AST current counter value.
*
* \param ast Base address of the AST.
*
* \return The AST current counter value.
*/
static inline uint32_t ast_read_counter_value(Ast *ast)
{
return ast->AST_CV;
}
/**
* \brief Check the busy status of AST clock
*
* \param ast Base address of the AST.
*
* \return 1 If AST clock is busy, else it will return 0.
*/
static inline bool ast_is_clkbusy(Ast *ast)
{
return (ast->AST_SR & AST_SR_CLKBUSY) != 0;
}
/**
* \brief Check the busy status of AST.
*
* \param ast Base address of the AST.
*
* \return 1 If AST is busy, else it will return 0.
*/
static inline bool ast_is_busy(Ast *ast)
{
return (ast->AST_SR & AST_SR_BUSY) != 0;
}
/**
* \brief Get status of AST.
*
* \param ast Base address of the AST (i.e. Ast).
*
* \return status of AST.
*/
static inline uint32_t ast_read_status(Ast *ast)
{
return ast->AST_SR;
}
/**
* \brief This function return the AST interrupts mask value.
*
* \param ast Base address of the AST.
*
* \return Interrupt mask value
*/
static inline uint32_t ast_read_interrupt_mask(Ast *ast)
{
return ast->AST_IMR;
}
void ast_write_alarm0_value(Ast *ast, uint32_t alarm_value);
void ast_write_periodic0_value(Ast *ast, uint32_t pir);
void ast_enable_interrupt(Ast *ast, ast_interrupt_source_t source);
void ast_disable_interrupt(Ast *ast, ast_interrupt_source_t source);
void ast_clear_interrupt_flag(Ast *ast, ast_interrupt_source_t source);
void ast_enable_wakeup(Ast *ast, ast_wakeup_source_t source);
void ast_disable_wakeup(Ast *ast, ast_wakeup_source_t source);
void ast_enable_event(Ast *ast, ast_event_source_t source);
void ast_disable_event(Ast *ast, ast_event_source_t source);
/// @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond */
/**
* \}
*/
/**
* \page sam_ast_quick_start Quick Start Guide for the AST driver
*
* This is the quick start guide for the \ref group_sam_drivers_ast, with
* step-by-step instructions on how to configure and use the driver for
* a specific use case.The code examples can be copied into e.g the main
* application loop or any other function that will need to control the
* AST module.
*
* \section ast_qs_use_cases Use cases
* - \ref ast_basic
*
* \section ast_basic AST basic usage
*
* This use case will demonstrate how to initialize the AST module to
* calendar or counter mode.
*
*
* \section ast_basic_setup Setup steps
*
* \subsection ast_basic_prereq Prerequisites
*
* This module requires the following service
* - \ref clk_group
*
* \subsection ast_basic_setup_code
*
* Add this to the main loop or a setup function:
* \code
* osc_priv_enable_osc32();
* \endcode
*
* \subsection ast_basic_setup_workflow
*
* -# Enable the AST module
* - \code ast_enable(AST); \endcode
* -# Initialize the AST to counter mode
* - \code
* struct ast_config ast_conf;
* ast_conf.mode = AST_COUNTER_MODE;
* ast_conf.osc_type = AST_OSC_32KHZ;
* ast_conf.psel = AST_PSEL_32KHZ_1HZ;
* ast_conf.counter = 0;
* ast_set_config(AST, &ast_conf)
* \endcode
* -# Or initialize the AST to calendar mode
* - \code
* struct ast_calendar calendar;
* struct ast_config ast_conf;
* calendar.FIELD.sec = 0;
* calendar.FIELD.min = 15;
* calendar.FIELD.hour = 12;
* calendar.FIELD.day = 20;
* calendar.FIELD.month = 9;
* calendar.FIELD.year = 12;
* struct ast_config ast_conf;
* ast_conf.mode = AST_CALENDAR_MODE;
* ast_conf.osc_type = AST_OSC_32KHZ;
* ast_conf.psel = AST_PSEL_32KHZ_1HZ;
* ast_conf.calendar = calendar;
* ast_set_config(AST, &ast_conf)
* \endcode
* - \note We need to set the clock after prescaler to 1HZ.
*
*
* \section ast_basic_usage Usage steps
*
* \subsection ast_basic_usage_code
*
* We can get the calendar value by
* \code
* calendar = ast_read_calendar_value(AST);
* \endcode
* Or we can get the counter value by
* \code
* ast_counter = ast_read_counter_value(AST);
* \endcode
*
* We can set the alarm interrupt by
* \code
* ast_write_alarm0_value(AST, calendar.field + 1);
* ast_set_callback(AST, ast_interrupt_alarm, ast_alarm_callback,
* AST_ALARM_IRQn, 1);
* \endcode
* And we can set the periodic interrupt by
* \code
* ast_write_periodic0_value(AST, AST_PSEL_32KHZ_1HZ - 4);
* ast_set_callback(AST, ast_interrupt_per, ast_per_callback,
* AST_PER_IRQn, 1);
* \endcode
*/
#endif /* AST_H_INCLUDED */