/*******************************************************************************
 * (c) Copyright 2008-2010 Actel Corporation
 *
 * CorePWM driver API.
 *
 * SVN $Revision: 3060 $
 * SVN $Date: 2010-09-27 15:33:07 +0530 (Mon, 27 Sep 2010) $
 */
/*=========================================================================*//**
  @mainpage CorePWM Bare Metal Driver.

  @section intro_sec Introduction
  The CorePWM hardware IP which includes up to 16 pulse width modulated (PWM)
  outputs and up to 16 tachometer inputs. The CorePWM bare metal software
  driver is designed for use in systems with no operating system.

  The CorePWM driver provides:
    - Functions to control the duty cycle of each independent PWM output. The
      duty cycle control functions are identical for both the General Purpose
      PWM and Low Ripple DAC modes of CorePWM.
    - A function to control the positive and negative edges of each independent
      PWM output. This function can only be used for CorePWM outputs configured
      as General Purpose PWM. This function is useful for controlling the phase
      between different PWM outputs.
    - A function to generate left, center or right aligned PWM output waveforms.
    - Functions to enable and disable synchronous update of the PWM output
       waveforms.
    - Functions to enable and disable pulse stretching of the PWM output waveforms.
    - Functions to configure and control the tachometer and measure the period of
      tachometer input signals.
    - Functions to control tachometer interrupts.

  @section driver_configuration Driver Configuration
  The CorePWM driver is configured through calls to the PWM_init() function for
  each CorePWM instance in the hardware design. The configuration parameters
  include the CorePWM hardware instance base address and other runtime
  parameters, such as the PWM clock prescale and period.
  No CorePWM hardware configuration parameters are used by the driver, apart
  from the CorePWM hardware instance base address. Hence, no additional
  configuration files are required to use the driver.

  Configured PWM Register Widths
  Each CorePWM instance in the hardware design is configured for the width of the
  APB data bus, by the APB_DWIDTH configuration parameter. This parameter also
  configures the width of CorePWM’s PRESCALE, PERIOD, PWMx_POSEDGE, PWMx_NEGEDGE
  and DACx_LEVELOUT registers. The CorePWM driver’s PWM_init(),
  PWM_set_duty_cycle(), PWM_set_edges() and PWM_generate_aligned_wave() functions
  write values to these registers via one or more of the parameters prescale,
  period, duty_cycle, pos_edge or neg_edge – all of type uint32_t. It is your
  responsibility to ensure that the values passed by these parameters are within
  the range 0 to (2^APB_DWIDTH - 1), where APB_DWIDTH is 8, 16 or 32 dependent
  upon your CorePWM hardware configuration, The return value from the
  PWM_get_duty_cycle() function is also within the range 0 to (2^APB_DWIDTH - 1).

  Note: Failure to keep the prescale, period, duty_cycle, pos_edge and neg_edge
        parameter values within the range 0 to (2^APB_DWIDTH - 1) will result
        in unintended CorePWM register settings.

  Fixed PWM Peroid or Prescale Register Values
  The prescale and period parameter values passed to the PWM_init() function may
  not have any effect if fixed values were selected for the PRESCALE and PERIOD
  registers in the hardware configuration of CorePWM. When fixed values are
  selected for these registers, the driver cannot overwrite the fixed values.

  Fixed PWM Positive or Negative Edge Register Values
  The pos_edge and neg_edge parameter values passed to the PWM_set_edges()
  function, and the duty_cycle parameter value passed to the PWM_set_duty_cycle()
  and PWM_generate_aligned_wave() functions, may not have the desired effect if
  fixed values were selected for the PWMx_POSEDGE (positive edge) or
  PWMx_NEGEDGE (negative edge) registers in the hardware configuration of
  CorePWM. When fixed values are selected for these registers, the driver cannot
  overwrite the fixed values.

  Synchronized Update of PWM Output Waveforms
  The configuration of the CorePWM instance in the hardware design must enable
  the shadow update register for each PWM channel that requires synchronous output
  waveform updates. The PWM_enable_synch_update() and PWM_disable_synch_update()
  functions will only affect PWM channels that have their shadow update registers
  enabled in hardware.

  @section theory_op Theory of Operation
  The CorePWM software driver is designed to allow the control of multiple
  instances of CorePWM. Each instance of CorePWM in the hardware design is
  associated with a single instance of the pwm_instance_t structure in the
  software.
  You need to allocate memory for one unique pwm_instance_t structure instance
  for each CorePWM hardware instance.The contents of these data structures are
  initialized during calls to function PWM_init(). A pointer to the structure
  is passed to subsequent driver functions in order to identify the CorePWM
  hardware instance you wish to perform the requested operation on.

  Note: Do not attempt to directly manipulate the content of pwm_instance_t
        structures. This structure is only intended to be modified by the driver
        function.

  Initialization
  The PWM granularity is configured through the PWM_init() function prescale
  parameter. The PWM granularity specifies the resolution of the PWM output
  waveforms for the targeted CorePWM instance. It is also sometimes called the
  PWM period count time base. It is defined by the following equation:
      PWM_GRANULARITY = SYS_CLOCK_PERIOD * ( prescale + 1 )
  Where SYS_CLOCK_PERIOD is the period of the system clock used to clock the
  CorePWM hardware instance and prescale is the value of the prescale parameter
  passed to function PWM_init().
  The PWM period is configured through the PWM_init() function period parameter.
  It specifies the period of the PWM output waveforms for the targeted CorePWM
  instance. The PWM period is defined by the following equation:
     PWM_PERIOD = PWM_GRANULARITY * ( period + 1 )

  Note: The prescale and period values passed to the PWM_init() function may not
        have any effect if fixed values were selected for the prescale and period
        in the hardware configuration of CorePWM.

  Note: The prescale and period parameters are not relevant to any PWM outputs
        that were configured for Low Ripple DAC mode in the hardware configuration
        of CorePWM. In this mode, their only role is in setting the interval between
        synchronized register updates when the shadow register is enabled for the
        PWM output.

  PWM Output Control
  The waveform for each PWM output is specified through calls to the
  PWM_set_duty_cycle() or PWM_set_edges() functions. Each PWM output is configured
  as either a General Purpose PWM output or a Low Ripple DAC output in the hardware
  configuration of CorePWM. In General Purpose PWM mode, either of the
  PWM_set_duty_cycle() or PWM_set_edges() functions may be used to specify the PWM
  output waveform. In Low Ripple DAC mode, only the PWM_set_duty_cycle() function
  may be used to specify the PWM output waveform. The duty cycle of the PWM can be
  read by calling PWM_get_duty_cyle().
  The waveform alignment of General Purpose PWM outputs can be set by calling
  PWM_generate_aligned_wave().
  The PWM_enable_synch_update() function is used to enable the synchronous update
  of a selected group of PWM channels. The PWM_disable_synch_update() is used to
  terminate the synchronous update cycle after at least one PWM period has elapsed.
  In synchronous mode the channel output waveforms are updated at the beginning of
  the PWM period, which is useful for motor control and can be used to keep a
  constant dead band space between channel waveforms. The configuration of the
  CorePWM instance in the hardware design must enable the shadow update register
  for each PWM channel that requires synchronous output waveform updates. When the
  shadow register is enabled, the PWM_set_duty_cycle(), PWM_set_edges() and
  PWM_generate_aligned_wave() functions set the new output waveform edge values in
  the channel’s shadow register instead of directly in the edge registers. Then, a
  call to the PWM_enable_synch_update() function updates the PWM channel’s output
  waveform at the beginning of the next PWM period. Finally, a call to the
  PWM_disable_synch_update() function completes the update cycle.

  Note: The PWM_enable_synch_update() and PWM_disable_synch_update() functions have
        no affect on any PWM channels that do not have their shadow update registers
        configured in hardware; these channels are always updated immediately,
        asynchronous to the PWM period.

  Note: The pos_edge and neg_edge values passed to the PWM_set_edges() function,
        and the duty_cycle value passed to the PWM_set_duty_cycle() and
        PWM_generate_aligned_wave() functions, may not have the desired effect if
        fixed values were selected for the positive or negative edge registers in
        the hardware configuration of CorePWM.

  A typical sequence of function calls for PWM outputs is:
  a call to function PWM_init() to initialize the CorePWM instance and pass it
  values for the prescale and period; a call to either PWM_set_duty_cycle() or
  PWM_set_edges() , or PWM_generate_aligned_wave() for each PWM output to specify
  the output waveform; a call to PWM_enable() to enable a PWM output; and a call to
  PWM_disable() to disable a PWM output.The function PWM_set_duty_cycle() and
  PWM_generate_aligned_wave() will also enable the PWM output if it is not already
  enabled.

  Tachometer Control
  CorePWM also provides a tachometer interface. During the hardware design, the
  CorePWM configuration mode should be set to either 1 - (PWM and TACH mode) or
  2 - (TACH only mode) which enables the tachometer interface. Each CorePWM hardware
  instance supports up to 16 tachometer inputs.
  The CorePWM tachometer is initialized through a call to the PWM_tach_init() function.
  The PWM_tach_init() function should be called before any other CorePWM driver
  tachometer functions to set up the tachometer prescale value, initialize the
  measurement mode and disable interrupts.
  The PWM_tach_set_mode() function is used to configure the tachometer input channels
  for continuous or one time measurement of the input signal period. The
  PWM_tach_clear_status() and PWM_tach_read_status() functions are used to clear and
  read the measurement status bits for the tachometer input channels. When the status
  bit indicates that a new input signal period measurement is available, the
  PWM_tach_read_value() function is used to read the measured signal period value.

  A typical sequence of function calls for measurement of a tachometer input signal is:
  a call to function PWM_init() to initialize the CorePWM instance and pass it values
  for the prescale and period; a call to PWM_tach_init() to initialize a tachometer
  input and pass it a tachometer prescale value; a call to PWM_tach_set_mode() to set
  the tachometer measurement mode; next a call to PWM_tach_enable_irq(), if interrupts
  are required; then a call to PWM_enable_stretch_pulse() to enable pulse stretching of
  the PWM output; a call to PWM_tach_clear_status() to trigger new measurement of the
  tachometer input signal period; a call to PWM_tach_read_status(), if interrupts are
  not used, to verify that input period value has been updated in the TACHPULSEDUR
  register; now a call to PWM_tach_read_value() to read the measured period of tachometer
  input signal; and finally a call to PWM_disable_stretch_pulse() to disable pulse
  stretching of the PWM output and resume a previously programmed PWM output waveform
  pattern.

  Interrupt Control
  Interrupts generated by CorePWM tachometer status changes are controlled using the
  following functions:
    - PWM_tach_enable_irq()
    - PWM_tach_disable_irq()
    - PWM_tach_clear_irq()
    - PWM_tach_get_irq_source()
  The PWM_tach_get_irq_source() function is used identify which CorePWM tachometer
  input channel has generated an interrupt, among all the tachometer input channels
  that have interrupts enabled.

 *//*=========================================================================*/
#ifndef CORE_PWM_H_
#define CORE_PWM_H_

#include "cpu_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/*-------------------------------------------------------------------------*//**
  Definition for tachometer measurement mode.
  CorePWM allows the tachometer input measurement mode to be configured. The
  following constants are used as an argument to the PWM_tach_set_mode()
  function to specify the tachometer input measurement mode.
 */
#define TACH_CONTINUOUS  0
#define TACH_ONE_SHOT    1

/*-------------------------------------------------------------------------*//**
  PWM identifiers. The identifiers defined in this enumeration are used to
  identify individual PWM outputs. They are used as argument to most CorePWM
  driver functions to identify the PWM controlled by a function call.
 */
typedef enum {
    PWM_1 = 1,
    PWM_2,
    PWM_3,
    PWM_4,
    PWM_5,
    PWM_6,
    PWM_7,
    PWM_8,
    PWM_9,
    PWM_10,
    PWM_11,
    PWM_12,
    PWM_13,
    PWM_14,
    PWM_15,
    PWM_16
} pwm_id_t;

/*-------------------------------------------------------------------------*//**
  The pwm_tach_id_t type is used to identify individual CorePWM tachometer
  inputs. The inputs are used as an argument to most CorePWM driver functions
  to identify the PWM tachometer input controlled by a function call.
 */
typedef enum {
    PWM_TACH_INVALID = 0,
    PWM_TACH_1,
    PWM_TACH_2,
    PWM_TACH_3,
    PWM_TACH_4,
    PWM_TACH_5,
    PWM_TACH_6,
    PWM_TACH_7,
    PWM_TACH_8,
    PWM_TACH_9,
    PWM_TACH_10,
    PWM_TACH_11,
    PWM_TACH_12,
    PWM_TACH_13,
    PWM_TACH_14,
    PWM_TACH_15,
    PWM_TACH_16
} pwm_tach_id_t;

/*-------------------------------------------------------------------------*//**
  The pwm_wave_align_t type is used to align the duty cycle of the PWM output
  waveform within the period of the PWM output waveform. A value of this type
  is used as an argument to the PWM_generate_aligned_wave() function.

  Note: The duty cycle corresponds to the number of period ticks for which
        the PWM output will remain high.
 */
typedef enum {
    PWM_LEFT_ALIGN,
    PWM_CENTER_ALIGN,
    PWM_RIGHT_ALIGN
} pwm_wave_align_t;

/*-------------------------------------------------------------------------*//**
  The pwm_tach_prescale_t type is used to select the PCLK prescale divisor for
  the CorePWM tachometer. A value of this type is used as an argument to the
  PWM_tach_init() function.
 */
typedef enum pwm_tach_prescale {
    TACH_PRESCALE_PCLK_DIV_1     = 0x0000,
    TACH_PRESCALE_PCLK_DIV_2     = 0x0001,
    TACH_PRESCALE_PCLK_DIV_4     = 0x0002,
    TACH_PRESCALE_PCLK_DIV_8     = 0x0003,
    TACH_PRESCALE_PCLK_DIV_16    = 0x0004,
    TACH_PRESCALE_PCLK_DIV_32    = 0x0005,
    TACH_PRESCALE_PCLK_DIV_64    = 0x0006,
    TACH_PRESCALE_PCLK_DIV_128   = 0x0007,
    TACH_PRESCALE_PCLK_DIV_256   = 0x0008,
    TACH_PRESCALE_PCLK_DIV_512   = 0x0009,
    TACH_PRESCALE_PCLK_DIV_1024  = 0x000A,
    TACH_PRESCALE_PCLK_DIV_2048  = 0x000B
} pwm_tach_prescale_t;

/*-------------------------------------------------------------------------*//**
  This structure is used to identify the various CorePWM hardware instances in
  your system. Your application software should declare one instance of this
  structure for each instance of CorePWM in your system. The function PWM_init()
  Initializes this structure. A pointer to an initialized instance of the
  structure should be passed as the first parameter to the CorePWM driver
  functions, to identify which CorePWM hardware instance should perform the
  requested operation.
 */
typedef struct pwm_instance
{
    addr_t  address;
} pwm_instance_t;

/*-------------------------------------------------------------------------*//**
  The PWM_init() function initializes a CorePWM hardware instance and the
  data structure associated with the CorePWM hardware instance. It disables
  all PWM outputs and sets the prescale and period value for the PWM. This
  function should be called before any other CorePWM driver functions.

  @param pwm_inst
    Pointer to a PWM_instance_t structure holding all relevant data associated
    with the target CorePWM hardware instance. This pointer will be used to
    identify the target CorePWM hardware instance in subsequent calls to the
    CorePWM functions.

  @param base_addr
    The base_address parameter is the base address in the processor's memory map
    for the registers of the CorePWM hardware instance being initialized.

  @param prescale
    The prescale parameter is used to specify the PWM period count time base.
    It specifies the PWM granularity.
    The value of this parameter should be between 0 and (2^APB_DWIDTH - 1) where
    APB_DWIDTH is the value selected for the APB_DWIDTH in the instantiation of
    the CorePWM DirectCore hardware instance.
      PWM_GRANULARITY = system_clock_period * (prescale + 1)

  @param period
    The period parameter specifies the period of the PWM cycles.
    The value of this parameter should be between 1 and (2^APB_DWIDTH - 1) where
    APB_DWIDTH is the value selected for the APB_DWIDTH in the instantiation of
    the CorePWM DirectCore hardware instance.
       PWM_PERIOD = PWM_GRANULARITY * (period + 1)

  @return          none.

  Example:
  @code
   #define COREPWM_BASE_ADDR  0xC0000000
   #define PWM_PRESCALE       0
   #define PWM_PERIOD         10

   pwm_instance_t the_pwm;

   void system_init( void )
   {
        PWM_init( &the_pwm, COREPWM_BASE_ADDR, PWM_PRESCALE, PWM_PERIOD ) ;
   }
  @endcode
 */
void PWM_init
(
    pwm_instance_t * pwm_inst,
    addr_t base_addr,
    uint32_t prescale,
    uint32_t period
);
/*-------------------------------------------------------------------------*//**
  The PWM_enable() function enables the specified PWM output.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @return
    none.

  Example :
  The following call will enable PWM 1.
  @code
    PWM_enable(&the_pwm, PWM_1);
  @endcode
 */
void PWM_enable
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_disable() function disables the specified PWM output.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @return
    none.

  Example:
  The following call will disable PWM 1.
  @code
    PWM_disable(&the_pwm, PWM_1);
  @endcode
 */
void PWM_disable
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_enable_synch_update() function enables synchronous update of PWM
  outputs. In synchronous mode, a selected group of PWM outputs are updated
  at the beginning of the PWM period, which is useful for motor control and
  can be used to keep a constant dead band space between output waveforms.
  Configuration updates for all of the selected PWM outputs are synchronized
  to the beginning of the PWM period, allowing precise updates and maintaining
  phase alignments between outputs.

  Note: The configuration of the CorePWM instance in the hardware design must
        enable the shadow update register for each PWM channel that requires
        synchronous output waveform updates. This function has no affect on any
        PWM channel that does not have its shadow update register configured in
        hardware.

  Note: The PWM_set_duty_cycle(), PWM_set_edges() or PWM_generate_aligned_wave()
        functions must be called to set the new output waveform edge values in
        the channel’s shadow register before using a call to the
        PWM_enable_synch_update() function to enable the update.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @return
    none.

  Example:
  Enable synchronous update of the duty cycle for the PWM 1 and PWM 2 outputs.
  @code
    uint32_t duty_cycle = 2;
    PWM_set_duty_cycle( &the_pwm, PWM_1, duty_cycle );
    PWM_set_duty_cycle( &the_pwm, PWM_2, duty_cycle );
    PWM_enable_synch_update( &the_pwm );
    wait_more_than_one_period();
    PWM_disable_synch_update( &the_pwm );
  @endcode
 */
void PWM_enable_synch_update
(
    pwm_instance_t * pwm_inst
);

/*-------------------------------------------------------------------------*//**
  The PWM_disable_synch_update() function disables synchronous update of PWM
  outputs. The PWM_disable_synch_update() is used to terminate a synchronous
  update cycle after at least one PWM period has elapsed.

  Note: The configuration of the CorePWM instance in the hardware design must
        enable the shadow update register for each PWM channel that requires
        synchronous output waveform updates. This function has no affect on
        any PWM channel that does not have its shadow update register
        configured in hardware.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @return
    none.

  Example:
  The call to PWM_disable_synch_update() below will disable synchronous
  update of PWM outputs.
  @code
    PWM_enable_synch_update( &the_pwm );
    wait_more_than_one_period();
    PWM_disable_synch_update(&the_pwm);
  @endcode
 */
void PWM_disable_synch_update
(
    pwm_instance_t * pwm_inst
);

/*-------------------------------------------------------------------------*//**
  The PWM_set_duty_cycle() function is used for setting the duty cycle of a
  PWM output.

  Note: It will also enable the PWM output if it is not already enabled.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @param duty_cycle
    The duty_cycle parameter specifies the PWM output duty cycle.
    In General Purpose PWM mode:
       This parameter corresponds to the number of period ticks for which
       the PWM output will remain high. The value of this parameter should be
       between 0 and the value of the period selected for the call to PWM_init().

    In Low Ripple DAC mode:
       This parameter corresponds to the average density duty cycle. The value
       of this parameter should be between 0 and (2^APB_DWIDTH - 1) where
       APB_DWIDTH  is the value selected for the APB_DWIDTH in the instantiation
       of the CorePWM DirectCore hardware instance. This sets the average
       density of the PWM output high pulses to between 0% and 100% in proportion
       to the duty_cycle value as a percentage of the (2^APB_DWIDTH - 1) value.

       Note: The only role that prescale and period play in Low Ripple DAC mode is
             to set the point when synchronized register updates will take place,
             if the shadow register is enabled for a PWM output.

  @return
    none.

  Example:
  The following example sets the duty cycle of PWM 1 to the value 2.
  @code
    uint32_t duty_cycle = 2;
    PWM_set_duty_cycle( &the_pwm, PWM_1, duty_cycle );

  @endcode
 */
void PWM_set_duty_cycle
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id,
    uint32_t duty_cycle
);

/*-------------------------------------------------------------------------*//**
  The PWM_set_edges() function is used to configure the positive and negative
  edge of the specified PWM output. The PWM output waveform is controlled by
  specifying the value of period counter at which the output will rise and fall.

  Note: The PWM_set_edges() function does not enable the PWM output. You must
        call the PWM_enable() function to enable the PWM output, either before
        or after calling the PWM_set_edges() function.

  Note: If you specify the same value for both the positive edge and the
        negative edge, this will set the PWM output waveform to toggle mode
        (50% duty cycle). The PWM output waveform will toggle high or low in
        each succeeding PWM period when the period counter reaches the edge
        value set by this function.

  Note: The PWM_get_duty_cycle() function will return the value 0 when it is
        called after using the PWM_set_edges() function to set the PWM output
        waveform to toggle mode (50% duty cycle). A return value of 0 from the
        PWM_get_duty_cycle() function normally means a 0% duty cycle, therefore
        you must be alert to this exception if you use the PWM_set_edges()
        function to manipulate the PWM output waveform edges.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify
    the target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @param pos_edge
    The pos_edge parameter specifies the value of the period counter at which
    the PWM output identified by pwm_id will rise from low to high. The value
    of this parameter should be between 0 and the value of the period selected
    for the call to PWM_init().

  @param neg_edge
    The neg_edge parameter specifies the value of the period counter at which
    the PWM output identified by pwm_id will fall from high to low. The value
    of this parameter should be between 0 and the value of the period selected
    for the call to PWM_init().

  @return
    none.

  Example:
  The following example sets the positive and negative edges of PWM 1 to 0
  and 2 respectively.
  @code
    uint32_t pos_edge = 0;
    uint32_t neg_edge = 2;
    PWM_set_edges( &the_pwm, PWM_1, pos_edge, neg_edge );

  @endcode
 */
void PWM_set_edges
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id,
    uint32_t pos_edge,
    uint32_t neg_edge
);

/*-------------------------------------------------------------------------*//**
  The PWM_get_duty_cycle() function returns the current duty cycle of the
  specified PWM output. The duty cycle corresponds to the number of period
  ticks during which the output remains high and should be between 0 and the
  value of the period selected for the call to PWM_init().

  Note: Duty Cycle (in %) can be calculated as follows:
        Duty Cycle (%) = ( (returned duty cycle value) / (period +1) )*100

  Note: The PWM_get_duty_cycle() function is intended to return the duty cycle
        previously set through calls to the PWM_set_duty_cycle() or
        PWM_generate_aligned_wave() functions.

  Note: A returned duty cycle value of 0 normally means a 0% duty cycle. However,
        the PWM_get_duty_cycle() function will also return the value 0 when it
        is called after using the PWM_set_edges() function to set the PWM output
        waveform to toggle mode. In this case a return value of 0 does not mean
        a 0% duty cycle; rather it means that the PWM output waveform is in
        toggle mode. Refer to the description of the PWM_set_edges() function
        for a description of toggle mode. You must be alert to this exception if
        you use the PWM_set_edges() function to manipulate the PWM output
        waveform edges.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @return
    This function returns the duty cycle of the PWM output as a 32 bit unsigned
    integer. The duty cycle is the number of period ticks during which the
    output is high.

    Note: A returned duty cycle value of 0 normally means the PWM output is
          constantly low, however it may also indicate that the PWM output
          waveform is set to toggle mode (50% duty cycle). Refer to the note
          in the function description.

  Example:
  Read and assigns current duty cycle value to a variable.
  @code
    uint32_t duty_cycle ;
    duty_cycle = PWM_get_duty_cycle( &the_pwm, PWM_1 );

  @endcode
 */
uint32_t PWM_get_duty_cycle
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_generate_aligned_wave() function is used to align the duty_cycle of
  the PWM output waveform within the period of the PWM output waveform.
  Three PWM output waveform alignment options are supported:
    Left Aligned Waveform
    Center Aligned Waveform
    Right Aligned Waveform
  The PWM_generate_aligned_wave() function sets the appropriate positive edge
  and negative edge values to achieve the specified alignment for the PWM output
  waveform.
  Note: It will also enable the PWM output if it is not already enabled.

  The diagram below shows the possible waveform alignments:
  Assume PWM Prescale = 0, so that PWM Period granularity = clock period.
  Each dash & hyphen in this diagram represents one clock period.
  PWM Period = 13. Duty_cycle = 4.


       |<-------- Period ------> |
        _ _ _ _                     _ _ _ _
       |       |                   |       |
  _ _ _|       |_ _ _ _ _ _ _ _ _ _|       |_ _ _
       0       4                   0
       |-- |---|
           V
      Duty Cycle
        _ _ _ _                     _ _ _ _
       |       |                   |       |    --> Left Aligned Waveform
  _ _ _|       |_ _ _ _ _ _ _ _ _ _|       |_ _ _
       0       4                   0
       |           _ _ _ _         |
       |          |       |        |            --> Center Aligned Waveform
  _ _ _|_ _ _ _ _ |       |_ _ _ _ |_ _ _ _ _ _ _
       0          5       9        0
                            _ _ _ _|
                           |       |            --> Right Aligned Waveform
  _ _ _ _ _ _ _ _ _ _ _ _ _|       |_ _ _ _ _ _ _
       0                   10      0

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @param duty_cycle
    The duty_cycle parameter specifies the PWM output duty cycle. The duty
    cycle corresponds to the number of period ticks for which the PWM output
    will remain high. The value of this parameter should be between 0 and
    the value of the period selected for the call to PWM_init().

  @param alignment_type
    The alignment_type parameter specifies required alignment for the PWM
    output waveform. Allowed values of type pwm_wave_align_t are:
      PWM_LEFT_ALIGN
      PWM_CENTER_ALIGN
      PWM_RIGHT_ALIGN

  @return
    none.

  Example:
  The following example sets up PWM channels 1, 2 and 3 to generate left, center
  and right aligned output waveforms respectively.
  @code
    PWM_generate_aligned_wave(&the_pwm, PWM_1, duty_cycle, LEFT_ALIGN);
    PWM_generate_aligned_wave(&the_pwm, PWM_2, duty_cycle, CENTER_ALIGN);
    PWM_generate_aligned_wave(&the_pwm, PWM_3, duty_cycle, RIGHT_ALIGN);
  @endcode
 */
void PWM_generate_aligned_wave
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id,
    uint32_t duty_cycle,
    pwm_wave_align_t alignment_type
);

/*-------------------------------------------------------------------------*//**
  The PWM_enable_stretch_pulse() function is used to enable pulse stretching
  for the specified PWM output. To accurately measure the speed of 3-wire fans,
  it is necessary to turn on the fan periodically for long enough to get a
  complete measurement of the tachometer signal from the fan. This stretching
  of the PWM output pulse for a long duration is referred as PWM pulse
  stretching. When pulse stretching is enabled, the PWM output is set to high
  or low, dependent upon the configuration of the CorePWM instance in the
  hardware design. The PWM_disable_stretch_pulse() function must be used to
  disable PWM pulse stretching once the fan speed measurement is completed.

  Note: The configuration of the CorePWM instance in the hardware design must
        select the PWM output level – high or low – that is set when PWM pulse
        stretching is enabled. For example, to measure 3- wire fan speed, the
        CorePWM hardware configuration should select a high stretch level for
        the PWM output.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @return
    none.

  Example:
  The following function call enables the stretching of PWM output 1 pulse for
  tachometer input measurement.
  @code
    PWM_enable_stretch_pulse(&the_pwm, PWM_1);
  @endcode
 */
void PWM_enable_stretch_pulse
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_disable_stretch_pulse() function is used to disable pulse stretching
  for the specified PWM output. This function must be called once your
  application has completed the measurement of the tachometer input. When pulse
  stretching is disabled, the PWM output resumes generation of its previously
  programmed output waveform pattern.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_id
    The pwm_id parameter identifies the target PWM output.

  @return
    none.

  Example:
  The following function call disables the stretching of the PWM 1 output
  pulse after completing the tachometer input measurement.
  @code
    PWM_disable_stretch_pulse(&the_pwm, PWM_1);
  @endcode
 */
void PWM_disable_stretch_pulse
(
    pwm_instance_t * pwm_inst,
    pwm_id_t pwm_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_init() function is used to initialize the configuration of
  all of the CorePWM tachometer inputs. It sets the tachometer’s TACHPRESCALE
  register to the value specified by the tach_prescale parameter. It sets the
  tachometer measurement mode to continuous measurement for all tachometer
  inputs. It disables the interrupts for all tachometer inputs and clears any
  pending interrupts.

  Note: This function should be called before any other CorePWM driver
        tachometer functions.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param tach_prescale
    The tach_prescale value is used to select the PCLK prescale divisor for the
    CorePWM tachometer. This determines the period counter time base for
    tachometer measurements. Allowed values of type pwm_tach_prescale_t are:
       TACH_PRESCALE_PCLK_DIV_1
       TACH_PRESCALE_PCLK_DIV_2
       TACH_PRESCALE_PCLK_DIV_4
       TACH_PRESCALE_PCLK_DIV_8
       TACH_PRESCALE_PCLK_DIV_16
       TACH_PRESCALE_PCLK_DIV_32
       TACH_PRESCALE_PCLK_DIV_64
       TACH_PRESCALE_PCLK_DIV_128
       TACH_PRESCALE_PCLK_DIV_256
       TACH_PRESCALE_PCLK_DIV_512
       TACH_PRESCALE_PCLK_DIV_1024
       TACH_PRESCALE_PCLK_DIV_2048

  @return
    none.

  Example:
  The following call to PWM_tach_init() initializes the CorePWM tachometer and
  sets the PCLK prescale divisor to 8 for tachometer measurements.
  @code
    pwm_tach_prescale_t tach_prescale = TACH_PRESCALE_PCLK_DIV_8;
    PWM_tach_init(&the_pwm, tach_prescale);
  @endcode

 */
void PWM_tach_init
(
    pwm_instance_t *pwm_inst,
    pwm_tach_prescale_t tach_prescale
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_set_mode() function sets the measurement mode for the
  specified tachometer input. This function selects how frequently the
  tachometer input should be measured. There are two options for the measurement
  mode:
    Continuous measurement of tachometer input
    One time measurement of tachometer input

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @param pwm_tachmode
    The pwm_tachmode parameter is used to specify the tachometer input
    measurement mode. Allowed values for pwm_tachmode are:
      TACH_CONTINUOUS
      TACH_ONE_SHOT

  @return
    none.

  Example:
  The following example sets up tachometer input 1 for one time measurement.
  @code
    PWM_tach_set_mode(&the_pwm, PWM_TACH_1,TACH_ONE_SHOT);
  @endcode
 */
void PWM_tach_set_mode
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t  pwm_tach_id,
    uint16_t       pwm_tachmode
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_read_value() function reads the measured period of the
  tachometer input signal from the TACHPULSEDUR register corresponding to
  the specified tachometer input. The value returned is the number of timer
  ticks between two successive positive (or negative) edges of the tachometer
  input signal.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    It returns the number of timer ticks between two successive positive
    (or negative) edges of the tachometer input signal as a 16 bit unsigned
    integer.

  Example:
    Read and assign the value of the current period measurement for tachometer
    input 1 to a variable.
  @code
    uint16_t tach_input_value ;
    tach_input_value = PWM_tach_read_value(&the_pwm, PWM_TACH_1);
  @endcode
 */
uint16_t PWM_tach_read_value
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t    pwm_tach_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_clear_status() function is used to clear the tachometer
  status bit for the specified tachometer input. This allows the tachometer
  to take a new measurement of the input signal period and store it in the
  TACHPULSEDUR register corresponding to the specified tachometer input. This
  function is typically called when the user want to take a new reading of
  the tachometer input signal period.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    none.

  Example:
  The following call clears the status bit for tachometer input 1 to begin
  a new input period measurement.
  @code
     PWM_tach_clear_status(&the_pwm, PWM_TACH_1);
  @endcode
 */
void PWM_tach_clear_status
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t    pwm_tach_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_read_status() function returns the current status for the
  specified tachometer input. This function returns 1 if the tachometer input
  period measurement has been updated at least once since the status bit was
  cleared,otherwise it returns 0.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    It returns 1 if the tachometer input period measurement has been updated
    at least once since the status bit was cleared, otherwise it returns 0.

  Example:
  Read and assign the current status of tachometer input 1 to a variable.
  @code
    uint16_t tach_input_status ;
    tach_input_status = PWM_tach_read_status(&the_pwm, PWM_TACH_1);
  @endcode
 */
uint16_t PWM_tach_read_status
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t    pwm_tach_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_get_irq_source() function is used identify which tachometer
  input channel has generated an interrupt,among all the tachometer input
  channels with interrupts enabled.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @return
    It returns the pwm_tach_id_t identifier of the tachometer input generating
    the interrupt. It returns 0 if no tachometer input is generating an interrupt.

  Example:
  The following example returns the tachometer 1 identifier, PWM_TACH_1,
  when PWM_tach_get_irq_source() is called, after the tachometer input 1
  period measurement has been completed by CorePWM.
  @code
    pwm_tach_id_t tach_input_no ;
    PWM_tach_enable_irq( &the_pwm, PWM_TACH_1);
    PWM_tach_clear_status( &the_pwm, PWM_TACH_1);
    tach_input_no = PWM_tach_get_irq_source( &the_pwm );
  @endcode
 */
pwm_tach_id_t PWM_tach_get_irq_source
(
    pwm_instance_t * pwm_inst
);
/*-------------------------------------------------------------------------*//**
  The PWM_tach_enable_irq() function is used to enable interrupt generation
  for the specified tachometer input channel.

  Note: CorePWM asserts its interrupt output signal, when a tachometer input
        channel’s period measurement has been updated at least once since the
        channel’s interrupt was last cleared, if the channel is enabled for
        interrupt generation.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    none.

  Example:
  This call to PWM_tach_enable_irq() allows tachometer input 1 to generate an
  interrupt, when its input signal period measurement value is updated.
  @code
    PWM_tach_enable_irq(&the_pwm, PWM_TACH_1);
  @endcode
 */
void PWM_tach_enable_irq
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t  pwm_tach_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_disable_irq() function is used to disable interrupt generation
  for the specified tachometer input channel.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    none.

  Example:
  This call to PWM_tach_disable_irq() will prevent tachometer input 1 from
  generating an interrupt when its input signal period measurement value is
  updated.
  @code
    PWM_tach_disable_irq(&the_pwm, PWM_TACH_1);
  @endcode
 */
void PWM_tach_disable_irq
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t  pwm_tach_id
);

/*-------------------------------------------------------------------------*//**
  The PWM_tach_clear_irq() function is used to clear a pending interrupt
  generated by the specified tachometer input channel.

  Note: The PWM_tach_clear_irq() function  must be called as part of a PWM
        tachometer interrupt service routine (ISR) in order to prevent the
        same interrupt event retriggering a call to the PWM tachometer ISR.

  Note: Interrupts may also need to be cleared in the processor's interrupt
        controller.

  @param pwm_inst
    Pointer to a pwm_inst structure holding all relevant data associated with
    the target CorePWM hardware instance. This pointer is used to identify the
    target CorePWM hardware instance.

  @param pwm_tach_id
    The pwm_tach_id parameter identifies the target tachometer input.

  @return
    none.

  Example:
  This call to PWM_tach_clear_irq() will clear a pending interrupt from tachometer
  input 1.
  @code
    PWM_tach_clear_irq(&the_pwm, PWM_TACH_1);
  @endcode
 */
void PWM_tach_clear_irq
(
    pwm_instance_t * pwm_inst,
    pwm_tach_id_t  pwm_tach_id
);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /*CORE_PWM_H_*/
