rt-thread/bsp/loongson/ls1cdev/libraries/ls1c_timer.c

302 lines
8.5 KiB
C
Raw Normal View History

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* first version
*/
// Ӳ<><D3B2><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>Դ<EFBFBD><D4B4>
#include <ls1c.h>
#include "ls1c_public.h"
#include "ls1c_pin.h"
#include "ls1c_clock.h"
#include "ls1c_regs.h"
#include "ls1c_pwm.h"
#include "ls1c_timer.h"
// <20><>ʱ<EFBFBD><CAB1><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD><EFBFBD>(CNTR<54><52>HRC<52><43>LRC)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
#define TIMER_COUNTER_MAX (0xffffff)
/*
* <EFBFBD><EFBFBD>ȡָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ļĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
* @timer Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
* @ret <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
*/
unsigned int timer_get_reg_base(ls1c_timer_t timer)
{
unsigned int reg_base = 0;
switch (timer)
{
case TIMER_PWM0:
reg_base = LS1C_REG_BASE_PWM0;
break;
case TIMER_PWM1:
reg_base = LS1C_REG_BASE_PWM1;
break;
case TIMER_PWM2:
reg_base = LS1C_REG_BASE_PWM2;
break;
case TIMER_PWM3:
reg_base = LS1C_REG_BASE_PWM3;
break;
}
return reg_base;
}
/*
* <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ʱ
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
*/
void timer_init(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
unsigned long timer_clk = 0; // Ӳ<><D3B2><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
unsigned long tmp;
unsigned int ctrl = 0; // <20><><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD><EFBFBD>еĿ<D0B5><C4BF><EFBFBD><EFBFBD><EFBFBD>Ϣ
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return ;
}
/*
* <EFBFBD>Ѷ<EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ = <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> * <EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD>λns) / 1000000000
* <EFBFBD><EFBFBD>о1c<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ΪAPBʱ<EFBFBD>ӣ<EFBFBD><EFBFBD>126Mhz<EFBFBD><EFBFBD>
* Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD>Ż<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD>ø<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
timer_clk = clk_get_apb_rate();
tmp = (timer_clk / 1000000) * (timer_info->time_ns / 1000); // <20><>1000000000<30><30><EFBFBD><EFBFBD>Ϊ1000000<30><30>1000
tmp = MIN(tmp, TIMER_COUNTER_MAX);
// <20><><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD><EFBFBD><EFBFBD>Ϣ
ctrl = (1 << LS1C_PWM_INT_LRC_EN)
| (0 << LS1C_PWM_INT_HRC_EN)
| (0 << LS1C_PWM_CNTR_RST)
| (0 << LS1C_PWM_INT_SR)
| (1 << LS1C_PWM_INTEN)
| (1 << LS1C_PWM_SINGLE)
| (1 << LS1C_PWM_OE)
| (1 << LS1C_PWM_CNT_EN);
// <20><><EFBFBD>ø<EFBFBD><C3B8><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
timer_reg_base = timer_get_reg_base(timer_info->timer); // <20><>ȡ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
reg_write_32(0, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_HRC));
reg_write_32(tmp--, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_LRC));
reg_write_32(0, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CNTR));
reg_write_32(ctrl, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
return ;
}
/*
* <EFBFBD>ж<EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>ʱ(ʵ<EFBFBD>ֶ<EFBFBD>ʱ)
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
* @ret TRUE or FALSE
*/
BOOL timer_is_time_out(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
unsigned int ctrl; // <20><><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD><EFBFBD><EFBFBD>ֵ
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return FALSE;
}
// <20><>ȡ<EFBFBD><C8A1><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD>
timer_reg_base = timer_get_reg_base(timer_info->timer);
ctrl = reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
// <20>ж<EFBFBD><D0B6>ж<EFBFBD>״̬λ
if (ctrl & (1 << LS1C_PWM_INT_SR))
{
return TRUE;
}
else
{
return FALSE;
}
}
/*
* ֹͣ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
*/
void timer_stop(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0;
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return ;
}
timer_reg_base = timer_get_reg_base(timer_info->timer);
reg_write_32(0, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
return ;
}
/*
* <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>ʱ<EFBFBD><EFBFBD>(ʵ<EFBFBD>ּ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λns
* @timer_info Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
* @ret ʱ<EFBFBD><EFBFBD><EFBFBD>λns
*/
unsigned long timer_get_time_ns(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0;
unsigned int cntr = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD>CNTR<54><52>ֵ
unsigned long time_ns = 0; // ʱ<><EFBFBD><E4A3AC>λns
unsigned long timer_clk = 0; // <20><>ʱ<EFBFBD><CAB1>ʱ<EFBFBD><CAB1>
// <20><>ȡ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>CNTR<54><52>ֵ
timer_reg_base = timer_get_reg_base(timer_info->timer);
cntr = reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CNTR));
/*
* <EFBFBD><EFBFBD>CNTRֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊʱ<EFBFBD><EFBFBD><EFBFBD>λus
* ʱ<EFBFBD><EFBFBD> = (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵCNTR * 1000000000) / <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD>
* Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD>Ż<EFBFBD><EFBFBD><EFBFBD>ʽΪ ʱ<EFBFBD><EFBFBD> = (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵCNTR * 1000) / (<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD> / 1000000)
*/
timer_clk = clk_get_apb_rate();
time_ns = (cntr * 1000 ) / (timer_clk /1000000);
// printf("[%s] time_us=%lu, cntr=%d, timer_clk=%d\n", __FUNCTION__, time_ns, cntr, timer_clk);
return time_ns;
}
/*
* <EFBFBD><EFBFBD>ӡtimer<EFBFBD><EFBFBD><EFBFBD>ؼĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
* @timer_info Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>
*/
void timer_print_regs(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0;
timer_reg_base = timer_get_reg_base(timer_info->timer);
printf("CNTR=0x%x, HRC=0x%x, LRC=0x%x, CTRL=0x%x\n",
reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CNTR)),
reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_HRC)),
reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_LRC)),
reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL)));
return ;
}
/*
* <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD>
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
*/
void timer_int_clr(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
unsigned int ctrl ;
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return ;
}
timer_reg_base = timer_get_reg_base(timer_info->timer); // <20><>ȡ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
ctrl = reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
ctrl = ctrl | (1<<LS1C_PWM_INT_SR) ;
reg_write_32(ctrl , (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
ctrl = ctrl & (~(1<<LS1C_PWM_INT_SR)) ;
reg_write_32(ctrl , (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
return ;
}
/*
* <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
*/
void timer_cnt_clr(timer_info_t *timer_info)
{
unsigned int timer_reg_base = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
unsigned int ctrl ;
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return ;
}
timer_reg_base = timer_get_reg_base(timer_info->timer); // <20><>ȡ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
ctrl = reg_read_32((volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
ctrl = ctrl | (1<<LS1C_PWM_CNTR_RST);
reg_write_32(ctrl , (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
ctrl = ctrl & (~(1<<LS1C_PWM_CNTR_RST)) ;
reg_write_32(ctrl , (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
return ;
}
/*
* <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD>ж϶<EFBFBD>ʱ
* @timer_info <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
* @hrc <EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD> lrc <EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD> Ϊ1<EFBFBD>򿪣<EFBFBD>Ϊ0<EFBFBD>ر<EFBFBD>
*/
void timer_int_init(timer_info_t *timer_info, int hrc, int lrc)
{
unsigned int timer_reg_base = 0; // <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
unsigned long timer_clk = 0; // Ӳ<><D3B2><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
unsigned long h_value, l_value;
unsigned int ctrl = 0; // <20><><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD><EFBFBD>еĿ<D0B5><C4BF><EFBFBD><EFBFBD><EFBFBD>Ϣ
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD>
if (NULL == timer_info)
{
return ;
}
/*
* <EFBFBD>Ѷ<EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ = <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> * <EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD>λns) / 1000000000
* <EFBFBD><EFBFBD>о1c<EFBFBD>Ķ<EFBFBD>ʱ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>ΪAPBʱ<EFBFBD>ӣ<EFBFBD><EFBFBD>126Mhz<EFBFBD><EFBFBD>
* Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD>Ż<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>Ҳ<EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><EFBFBD>ø<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
timer_clk = clk_get_apb_rate();
l_value = (timer_clk / 1000000) * (timer_info->time_ns / 1000); // <20><>1000000000<30><30><EFBFBD><EFBFBD>Ϊ1000000<30><30>1000
l_value = MIN(l_value, TIMER_COUNTER_MAX);
h_value = (timer_clk / 1000000) * (timer_info->time_h_ns / 1000); // <20><>1000000000<30><30><EFBFBD><EFBFBD>Ϊ1000000<30><30>1000
h_value = MIN(h_value, l_value);
// <20><><EFBFBD>ƼĴ<C6BC><C4B4><EFBFBD><EFBFBD><EFBFBD>Ϣ
ctrl = (lrc << LS1C_PWM_INT_LRC_EN)
| (hrc << LS1C_PWM_INT_HRC_EN)
| (0 << LS1C_PWM_CNTR_RST)
| (0 << LS1C_PWM_INT_SR)
| (1 << LS1C_PWM_INTEN)
| (1 << LS1C_PWM_SINGLE)
| (1 << LS1C_PWM_OE)
| (1 << LS1C_PWM_CNT_EN);
// <20><><EFBFBD>ø<EFBFBD><C3B8><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
timer_reg_base = timer_get_reg_base(timer_info->timer); // <20><>ȡ<EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
reg_write_32(0, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_HRC));
reg_write_32(l_value--, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_LRC));
reg_write_32(h_value--, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_HRC));
reg_write_32(0, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CNTR));
reg_write_32(ctrl, (volatile unsigned int *)(timer_reg_base + LS1C_PWM_CTRL));
return ;
}