240 lines
6.8 KiB
C
240 lines
6.8 KiB
C
/*
|
|
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* o Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* o 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.
|
|
*
|
|
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
|
*/
|
|
|
|
/*!
|
|
* @file gpt.c
|
|
* @brief GPT driver source file.
|
|
*
|
|
* @ingroup diag_timer
|
|
*/
|
|
|
|
#include "sdk.h"
|
|
#include "gpt.h"
|
|
|
|
#include "imx_timer.h"
|
|
#include "registers/regsgpt.h"
|
|
#include "interrupt.h"
|
|
#include "ccm_pll.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Code
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline void gpt_clear_all_events(void)
|
|
{
|
|
HW_GPT_SR_WR(kGPTAllEvents);
|
|
}
|
|
|
|
uint32_t gpt_get_rollover_event(void)
|
|
{
|
|
// clear it if found set
|
|
if (HW_GPT_SR.B.ROV)
|
|
{
|
|
HW_GPT_SR_WR(BM_GPT_SR_ROV);
|
|
return kGPTRollover;
|
|
}
|
|
|
|
// return the read value before the bit was cleared
|
|
return 0;
|
|
}
|
|
|
|
uint32_t gpt_get_capture_event(uint8_t flag, uint32_t * capture_val)
|
|
{
|
|
// get the capture status bit
|
|
flag &= kGPTInputCapture1 | kGPTInputCapture2;
|
|
uint32_t status_register = HW_GPT_SR_RD() & flag;
|
|
|
|
// Read the captured timer value.
|
|
if (capture_val)
|
|
{
|
|
if (status_register == kGPTInputCapture1)
|
|
{
|
|
*(uint32_t *) capture_val = HW_GPT_ICR1.B.CAPT;
|
|
}
|
|
else if (status_register == kGPTInputCapture2)
|
|
{
|
|
*(uint32_t *) capture_val = HW_GPT_ICR2.B.CAPT;
|
|
}
|
|
}
|
|
|
|
// Clear the flag.
|
|
HW_GPT_SR_WR(status_register);
|
|
|
|
// return the read value before the bit was cleared
|
|
return status_register;
|
|
}
|
|
|
|
void gpt_set_capture_event(uint8_t cap_input, uint8_t cap_input_mode)
|
|
{
|
|
// set the new input mode
|
|
switch (cap_input)
|
|
{
|
|
case kGPTInputCapture1:
|
|
HW_GPT_CR.B.IM1 = cap_input_mode;
|
|
break;
|
|
|
|
case kGPTInputCapture2:
|
|
HW_GPT_CR.B.IM2 = cap_input_mode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32_t gpt_get_compare_event(uint8_t flag)
|
|
{
|
|
// get the active compare flags
|
|
flag &= kGPTOutputCompare1 | kGPTOutputCompare2 | kGPTOutputCompare3;
|
|
uint32_t status_register = HW_GPT_SR_RD() & flag;
|
|
|
|
// clear flags which are active
|
|
if (status_register)
|
|
{
|
|
HW_GPT_SR_WR(status_register);
|
|
}
|
|
|
|
// return the read value before the flags were cleared
|
|
return status_register;
|
|
}
|
|
|
|
void gpt_set_compare_event(uint8_t cmp_output, uint8_t cmp_output_mode, uint32_t cmp_value)
|
|
{
|
|
// set the value to compare with
|
|
switch (cmp_output)
|
|
{
|
|
case kGPTOutputCompare1:
|
|
BW_GPT_CR_OM1(cmp_output_mode);
|
|
HW_GPT_OCR1_WR(cmp_value);
|
|
break;
|
|
|
|
case kGPTOutputCompare2:
|
|
BW_GPT_CR_OM2(cmp_output_mode);
|
|
HW_GPT_OCR2_WR(cmp_value);
|
|
break;
|
|
|
|
case kGPTOutputCompare3:
|
|
BW_GPT_CR_OM3(cmp_output_mode);
|
|
HW_GPT_OCR3_WR(cmp_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void gpt_counter_disable(void)
|
|
{
|
|
// disable the counter
|
|
HW_GPT_CR.B.EN = 0;
|
|
|
|
// ensure to leave the counter in a proper state by disabling the interrupt sources
|
|
HW_GPT_IR_WR(0);
|
|
|
|
// and by clearing possible remaining events
|
|
gpt_clear_all_events();
|
|
}
|
|
|
|
void gpt_counter_enable(uint32_t irq_mode)
|
|
{
|
|
// ensure to start the counter in a proper state by clearing possible remaining events
|
|
gpt_clear_all_events();
|
|
|
|
// enable the interrupts or clear the register for polling
|
|
HW_GPT_IR_WR(irq_mode & kGPTAllEvents);
|
|
|
|
// finally, enable the counter
|
|
HW_GPT_CR.B.EN = 1;
|
|
}
|
|
|
|
void gpt_setup_interrupt(void (*irq_subroutine)(void), bool enableIt)
|
|
{
|
|
uint32_t irq_id = IMX_INT_GPT;
|
|
|
|
if (enableIt)
|
|
{
|
|
// register the IRQ sub-routine
|
|
register_interrupt_routine(irq_id, irq_subroutine);
|
|
|
|
// enable the IRQ
|
|
enable_interrupt(irq_id, CPU_0, 0);
|
|
}
|
|
else
|
|
{
|
|
// disable the IRQ
|
|
disable_interrupt(irq_id, CPU_0);
|
|
}
|
|
}
|
|
|
|
void gpt_init(uint32_t clock_src, uint32_t prescaler, uint32_t counter_mode, uint32_t low_power_mode)
|
|
{
|
|
uint32_t control_reg_tmp = 0;
|
|
uint32_t base = GPT_BASE_ADDR;
|
|
|
|
// enable the source clocks to the GPT port
|
|
clock_gating_config(base, CLOCK_ON);
|
|
|
|
// start with a known state by disabling and reseting the module
|
|
HW_GPT_CR_WR(BM_GPT_CR_SWR);
|
|
|
|
// wait for the reset to complete
|
|
while (HW_GPT_CR.B.SWR != 0) ;
|
|
|
|
// set the reference source clock for the counter
|
|
if (clock_src == CLKSRC_CKIL)
|
|
{
|
|
// CKIL source is 0x4 for GPT but 0x3 for EPIT
|
|
clock_src++;
|
|
}
|
|
control_reg_tmp |= BF_GPT_CR_CLKSRC(clock_src);
|
|
|
|
// the prescaler can be changed at any time, and
|
|
// this affects the output clock immediately
|
|
HW_GPT_PR_WR(BF_GPT_PR_PRESCALER(prescaler - 1));
|
|
|
|
// set the counter mode
|
|
control_reg_tmp |= BF_GPT_CR_FRR(counter_mode);
|
|
|
|
// set behavior for low power mode
|
|
if (low_power_mode & WAIT_MODE_EN)
|
|
{
|
|
control_reg_tmp |= BM_GPT_CR_WAITEN;
|
|
}
|
|
if (low_power_mode & STOP_MODE_EN)
|
|
{
|
|
control_reg_tmp |= BM_GPT_CR_STOPEN;
|
|
}
|
|
|
|
// specify from where the counter starts to count when enabled
|
|
// this code makes it start from 0
|
|
control_reg_tmp |= BM_GPT_CR_ENMOD;
|
|
|
|
// finally write the control register
|
|
HW_GPT_CR_WR(control_reg_tmp);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// EOF
|
|
////////////////////////////////////////////////////////////////////////////////
|