2025-12-17 15:55:25 +08:00

801 lines
26 KiB
C

/* Copyright (c) 2020 Kneron, Inc. All Rights Reserved.
*
* The information contained herein is property of Kneron, Inc.
* Terms and conditions of usage are described in detail in Kneron
* STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information.
* NO WARRANTY of ANY KIND is provided. This heading must NOT be removed
* from the file.
*/
/******************************************************************************
* Filename:
* ---------
* kdrv_timer.c
*
* Project:
* --------
* KL520
*
* Description:
* ------------
* This is TIMER driver
*
* Author:
* -------
* Albert Chen
**
******************************************************************************/
/******************************************************************************
Head Block of The File
******************************************************************************/
// Sec 0: Comment block of the file
// Sec 1: Include File
#include "kdrv_timer.h"
#include "kdrv_cmsis_core.h"
#include "regbase.h"
#include "io.h"
#include <string.h>
// Sec 2: Constant Definitions, Imported Symbols, miscellaneous
#define TIMER_DGB
#define PERF_ISR_CNT 99
#define FLAGS_TIMER_M1_DONE_EVENT BIT0
#define FLAGS_TIMER_M2_DONE_EVENT BIT1
#define FLAGS_TIMER_OF_DONE_EVENT BIT2
#define FLAGS_TIMER_ALL_EVENTS ( FLAGS_TIMER_M1_DONE_EVENT | FLAGS_TIMER_M2_DONE_EVENT | FLAGS_TIMER_OF_DONE_EVENT)
#define TM_PER_IP 3
#define TM_REG_OFS 3
#define TM_ENABLE 0x01
#define TM_CLK 0x02
#define TM_OFENABLE 0x04
#define TM_INT_MASK_M1 0x01
#define TM_INT_MASK_M2 0x02
#define TM_INT_MASK_OF 0x04
#define TM_TMCR 0x30
#define TM_TMINTSTAT 0x34
#define TM_TMINTMASK 0x38
#define TM_ID_1 0
#define TM_ID_2 1
#define TM_ID_3 2
#define TM_DOWN 0
#define TM_UP 1
/******************************************************************************
Declaration of External Variables & Functions
******************************************************************************/
// Sec 3: declaration of external variable
// Sec 4: declaration of external function prototype
/******************************************************************************
Declaration of data structure
******************************************************************************/
// Sec 5: structure, uniou, enum, linked list
typedef enum {
TIMER_ID_0,
TIMER_ID_1,
TIMER_ID_2,
TIMER_ID_3,
TIMER_ID_4,
TIMER_ID_5,
TIMER_ID_MAX,
TIMER_ID_INIT=0xFF
}TIMER_ID;
typedef struct {
uint32_t in_use;
timer_cb_fr_isr_t cb;
void * user_arg;
osThreadId_t tid;
uint32_t* ptmid;
uint32_t perf_in_use;
uint32_t perf_cnt;
uint32_t perf_last_instant;
}kdp_timer_t;
typedef volatile union U_regTIMER
{
struct
{
uint32_t Tm1Counter; //Timer1 counter
uint32_t Tm1Load; //Timer1 auto reload value
uint32_t Tm1Match1; //Timer1 match value 1
uint32_t Tm1Match2; //Timer1 match value 2
uint32_t Tm2Counter; //Timer2 counter
uint32_t Tm2Load; //Timer2 auto reload value
uint32_t Tm2Match1; //Timer2 match value 1
uint32_t Tm2Match2; //Timer2 match value 2
uint32_t Tm3Counter; //Timer3 counter
uint32_t Tm3Load; //Timer3 auto reload value
uint32_t Tm3Match1; //Timer3 match value 1
uint32_t Tm3Match2; //Timer3 match value 2
uint32_t TmCR; //Timer1, Timer2, Timer3 control registers
uint32_t IntrState; //Interrupt state of FTTMR010
uint32_t IntrMask; //Interrupt mask of FTTMR010
uint32_t TmRevision; //Revision number of FTTMR010
}dw; //double word
struct
{
uint32_t Tm1Counter :32; //Timer 1 counter
uint32_t Tm1Load :32; //Timer 1 load
uint32_t Tm1Match1 :32; //Timer 1 match level 1
uint32_t Tm1Match2 :32; //Timer 1 match level 2
uint32_t Tm2Counter :32; //Timer 2 counter
uint32_t Tm2Load :32; //Timer 2 load
uint32_t Tm2Match1 :32; //Timer 2 match level 1
uint32_t Tm2Match2 :32; //Timer 2 match level 2
uint32_t Tm3Counter :32; //Timer 3 counter
uint32_t Tm3Load :32; //Timer 3 load
uint32_t Tm3Match1 :32; //Timer 3 match level 1
uint32_t Tm3Match2 :32; //Timer 3 match level 2
uint32_t Tm1En :1; //Timer 1 enable 0: disable / 1: enable
uint32_t Tm1Clock :1; //Timer 1 clock source 0: PCLK / 1: EXT1CLK
uint32_t Tm1OfEn :1; //Timer 1 overflow interrupt enable bit 0: disable / 1: enable
uint32_t Tm2En :1; //Timer 2 enable 0: disable / 1: enable
uint32_t Tm2Clock :1; //Timer 2 clock source 0: PCLK / 1: EXT2CLK
uint32_t Tm2OfEn :1; //Timer 2 overflow interrupt enable bit 0: disable / 1: enable
uint32_t Tm3En :1; //Timer 3 enable 0: disable / 1: enable
uint32_t Tm3Clock :1; //Timer 3 clock source 0: PCLK / 1: EXT3CLK
uint32_t Tm3OfEn :1; //Timer 3 overflow interrupt enable bit 0: disable / 1: enable
uint32_t Tm1UpDown :1; //Timer 1 up or down count 0: down count / 1: up count
uint32_t Tm2UpDown :1; //Timer 2 up or down count 0: down count / 1: up count
uint32_t Tm3UpDown :1; //Timer 3 up or down count 0: down count / 1: up count
uint32_t Reserve0 :20;
uint32_t STm1Match1 :1; //Timer 1 match 1 interrupt status
uint32_t STm1Match2 :1; //Timer 1 match 2 interrupt status
uint32_t STm1Overflow :1; //Timer 1 overflow interrupt status
uint32_t STm2Match1 :1; //Timer 2 match 1 interrupt status
uint32_t STm2Match2 :1; //Timer 2 match 2 interrupt status
uint32_t STm2Overflow :1; //Timer 2 overflow interrupt status
uint32_t STm3Match1 :1; //Timer 3 match 1 interrupt status
uint32_t STm3Match2 :1; //Timer 3 match 2 interrupt status
uint32_t STm3Overflow :1; //Timer 3 overflow interrupt status
uint32_t Reserve1 :23;
uint32_t MTm1Match1 :1; //Timer 1 match 1 interrupt mask 0: no effect/ 1: masked
uint32_t MTm1Match2 :1; //Timer 1 match 2 interrupt mask 0: no effect/ 1: masked
uint32_t MTm1Overflow :1; //Timer 1 overflow interrupt mask 0: no effect/ 1: masked
uint32_t MTm2Match1 :1; //Timer 2 match 1 interrupt mask 0: no effect/ 1: masked
uint32_t MTm2Match2 :1; //Timer 2 match 2 interrupt mask 0: no effect/ 1: masked
uint32_t MTm2Overflow :1; //Timer 2 overflow interrupt mask 0: no effect/ 1: masked
uint32_t MTm3Match1 :1; //Timer 3 match 1 interrupt mask 0: no effect/ 1: masked
uint32_t MTm3Match2 :1; //Timer 3 match 2 interrupt mask 0: no effect/ 1: masked
uint32_t MTm3Overflow :1; //Timer 3 overflow interrupt mask 0: no effect/ 1: masked
uint32_t Reserve2 :23;
}bf; //bit-field
}U_regTIMER;
#define REGTIMER_0 ((U_regTIMER*) TMR_FTPWMTMR010_0_PA_BASE)
#define REGTIMER_1 ((U_regTIMER*) TMR_FTPWMTMR010_1_PA_BASE)
/******************************************************************************
Declaration of Global Variables & Functions
******************************************************************************/
// Sec 6: declaration of global variable
volatile uint32_t timer_used_mask;
volatile uint32_t timer_wakeup;
// Sec 7: declaration of global function prototype
/******************************************************************************
Declaration of static Global Variables & Functions
******************************************************************************/
// Sec 8: declaration of static global variable
volatile kdp_timer_t timer[TIMER_ID_MAX];
#ifdef TIMER_DGB
uint32_t ErrCnt[2];
#endif
uint32_t TCnt[2];
uint32_t perftimerid;
uint32_t timer_inited = 0;
// Sec 9: declaration of static function prototype
static kdrv_status_t kdrv_timer_closelight(uint32_t* TimerId);
/******************************************************************************
// Sec 10: C Functions
******************************************************************************/
static void read_set_bit(volatile uint32_t addr, uint32_t bit)
{
uint32_t tmp;
tmp = inw(addr);
tmp |= (1<<bit);
outw(addr, tmp);
}
static void read_clear_bit(volatile uint32_t addr, uint32_t bit)
{
uint32_t tmp;
tmp = inw(addr);
tmp &= ~(1<<bit);
outw(addr, tmp);
}
static void kdrv_timer_ip_init()
{
U_regTIMER* Timer_Reg;
int i;
for(i = 0 ; i < 2 ; i++)
{
Timer_Reg = (i == 0)? REGTIMER_0: REGTIMER_1;
Timer_Reg->dw.Tm1Counter = 0;
Timer_Reg->dw.Tm1Load = 0;
Timer_Reg->dw.Tm1Match1 = 0;
Timer_Reg->dw.Tm1Match2 = 0;
Timer_Reg->dw.Tm2Counter = 0;
Timer_Reg->dw.Tm2Load = 0;
Timer_Reg->dw.Tm2Match1 = 0;
Timer_Reg->dw.Tm2Match2 = 0;
Timer_Reg->dw.Tm3Counter = 0;
Timer_Reg->dw.Tm3Load = 0;
Timer_Reg->dw.Tm3Match1 = 0;
Timer_Reg->dw.Tm3Match2 = 0;
Timer_Reg->dw.TmCR = 0;
Timer_Reg->dw.IntrState = 0;
Timer_Reg->dw.IntrMask = 0;
}
}
uint32_t kdrv_timer_get_bit(uint32_t mask)
{
uint32_t Idtmp = 0;
if(mask != 0)
{
do{
mask = mask>>1;
Idtmp++;
}while(mask);
return Idtmp-1;
}
return 0;
}
kdrv_status_t kdrv_timer_intclear(uint32_t TimerId, uint32_t IntId)
{
U_regTIMER* Timer_Reg;
uint32_t value, ofs;
ofs = (TM_REG_OFS * (TimerId % TM_PER_IP)); //bit field offset 0/3/6 for TMCR/INTRSTATE/INTRMASK
value = 1<<(IntId + ofs);
Timer_Reg = (TimerId < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
Timer_Reg->dw.IntrState = value;
return KDRV_STATUS_OK;
}
void kdrv_timer_irqhandler0(void)
{
uint32_t mask, n_bit, timerid, intid,timer_isr_stat;
timer_isr_stat = REGTIMER_0->dw.IntrState;
timer_isr_stat &= ~(REGTIMER_0->dw.IntrMask);
#ifdef TIMER_DGB
if(timer_isr_stat == 0 )
{
ErrCnt[0]++;
}
#endif
while(timer_isr_stat)
{
mask = (timer_isr_stat) & (((timer_isr_stat) - 1)^(timer_isr_stat));
n_bit = kdrv_timer_get_bit(mask);
timerid = (n_bit / 3);
intid = (n_bit % 3);
kdrv_timer_intclear(timerid, intid);
if(timer[timerid].perf_in_use == 1)
{
timer[timerid].perf_cnt++;
}
else if(timer[timerid].cb != NULL)
{
timer[timerid].cb((cb_event_t)intid, timer[timerid].user_arg);
}
else if(timer[timerid].tid != 0)
{
kdrv_timer_closelight(timer[timerid].ptmid);
osThreadFlagsSet(timer[timerid].tid, FLAGS_TIMER_OF_DONE_EVENT);
TCnt[0]++;
}
else
{
kdrv_timer_closelight(timer[timerid].ptmid);
}
timer_isr_stat &= ~mask;
}
timer_wakeup = 1;
}
void kdrv_timer_irqhandler1(void)
{
uint32_t mask, n_bit, timerid, intid,timer_isr_stat;
timer_isr_stat = REGTIMER_1->dw.IntrState;
timer_isr_stat &= ~(REGTIMER_1->dw.IntrMask);
#ifdef TIMER_DGB
if( timer_isr_stat == 0)
{
ErrCnt[1]++;
}
#endif
while(timer_isr_stat)
{
mask = (timer_isr_stat) & (((timer_isr_stat) - 1)^(timer_isr_stat));
n_bit = kdrv_timer_get_bit(mask);
timerid = (n_bit / 3)+ TM_PER_IP;
intid = (n_bit % 3);
kdrv_timer_intclear(timerid, intid);
if(timer[timerid].perf_in_use == 1)
{
timer[timerid].perf_cnt++;
}
else if(timer[timerid].cb != NULL)
{
timer[timerid].cb((cb_event_t)intid, timer[timerid].user_arg);
}
else if(timer[timerid].tid != 0)
{
kdrv_timer_closelight(timer[timerid].ptmid);
osThreadFlagsSet(timer[timerid].tid, FLAGS_TIMER_OF_DONE_EVENT);
TCnt[1]++;
}
else
{
kdrv_timer_closelight(timer[timerid].ptmid);
}
timer_isr_stat &= ~mask;
}
timer_wakeup = 1;
}
kdrv_status_t kdrv_timer_register(uint32_t* TimerId, timer_cb_fr_isr_t cb_event, void *arg)
{
if (timer[*TimerId].in_use)
{
return KDRV_STATUS_TIMER_ID_IN_USED;
}
timer[*TimerId].in_use = 1;
timer[*TimerId].cb = cb_event;
timer[*TimerId].user_arg = arg;
timer[*TimerId].ptmid = TimerId;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_unregister(uint32_t* TimerId)
{
uint32_t TimerID = *TimerId;
timer[TimerID].in_use = 0;
timer[TimerID].cb = NULL;
timer[TimerID].user_arg = NULL;
timer[TimerID].tid = NULL;
timer[TimerID].ptmid = NULL;
timer[TimerID].perf_in_use = 0;
timer[TimerID].perf_cnt = 0;
timer[TimerID].perf_last_instant = 0;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_open(uint32_t* TimerId, timer_cb_fr_isr_t cb_event, void *arg)
{
uint32_t free_mask=0;
kdrv_status_t ret = KDRV_STATUS_OK;
free_mask = (~timer_used_mask) &(((~timer_used_mask) - 1)^(~timer_used_mask));
if(free_mask > 0x3F)
{
*TimerId = TIMER_ID_INIT;
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
}
*TimerId = kdrv_timer_get_bit(free_mask);
ret = kdrv_timer_register(TimerId, cb_event, arg);
if(ret == KDRV_STATUS_OK)
timer_used_mask |= free_mask;
return ret;
}
static kdrv_status_t kdrv_timer_closelight(uint32_t* TimerId)
{
uint32_t TimerID = *TimerId;
U_regTIMER* Timer_Reg;
if(timer[TimerID].in_use == 0)
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
Timer_Reg = (TimerID < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
switch(TimerID%TM_PER_IP)
{
case TM_ID_1:
Timer_Reg->bf.Tm1En = 0;
Timer_Reg->bf.Tm1UpDown = 0;
Timer_Reg->bf.Tm1OfEn = 0;
Timer_Reg->bf.MTm1Match1 = 1;
Timer_Reg->bf.MTm1Match2 = 1;
Timer_Reg->bf.MTm1Overflow = 1;
break;
case TM_ID_2:
Timer_Reg->bf.Tm2En = 0;
Timer_Reg->bf.Tm2UpDown = 0;
Timer_Reg->bf.Tm2OfEn = 0;
Timer_Reg->bf.MTm2Match1 = 1;
Timer_Reg->bf.MTm2Match2 = 1;
Timer_Reg->bf.MTm2Overflow = 1;
break;
case TM_ID_3:
Timer_Reg->bf.Tm3En = 0;
Timer_Reg->bf.Tm3UpDown = 0;
Timer_Reg->bf.Tm3OfEn = 0;
Timer_Reg->bf.MTm3Match1 = 1;
Timer_Reg->bf.MTm3Match2 = 1;
Timer_Reg->bf.MTm3Overflow = 1;
break;
default:
break;
}
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_close(uint32_t* TimerId)
{
uint32_t TimerID = *TimerId;
uint32_t used_mask = (1<<*TimerId);
U_regTIMER* Timer_Reg;
if (TimerID >= TIMER_ID_MAX)
return KDRV_STATUS_TIMER_INVALID_TIMER_ID;
if (timer[TimerID].in_use == 0)
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
Timer_Reg = (TimerID < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
switch(TimerID%TM_PER_IP)
{
case TM_ID_1:
Timer_Reg->bf.Tm1En = 0;
Timer_Reg->bf.Tm1UpDown = 0;
Timer_Reg->bf.Tm1OfEn = 0;
Timer_Reg->bf.MTm1Match1 = 1;
Timer_Reg->bf.MTm1Match2 = 1;
Timer_Reg->bf.MTm1Overflow = 1;
break;
case TM_ID_2:
Timer_Reg->bf.Tm2En = 0;
Timer_Reg->bf.Tm2UpDown = 0;
Timer_Reg->bf.Tm2OfEn = 0;
Timer_Reg->bf.MTm2Match1 = 1;
Timer_Reg->bf.MTm2Match2 = 1;
Timer_Reg->bf.MTm2Overflow = 1;
break;
case TM_ID_3:
Timer_Reg->bf.Tm3En = 0;
Timer_Reg->bf.Tm3UpDown = 0;
Timer_Reg->bf.Tm3OfEn = 0;
Timer_Reg->bf.MTm3Match1 = 1;
Timer_Reg->bf.MTm3Match2 = 1;
Timer_Reg->bf.MTm3Overflow = 1;
break;
default:
break;
}
kdrv_timer_unregister(TimerId);
timer_used_mask = timer_used_mask & ~(used_mask);
*TimerId = TIMER_ID_INIT;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_set(uint32_t* TimerId, uint32_t Intval, timer_stat_t State)
{
uint32_t load = Intval*100;
uint32_t TimerID = *TimerId;
uint32_t bit;
uint32_t ofs;
U_regTIMER* Timer_Reg;
if(timer[TimerID].in_use == 0)
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
ofs = (TM_REG_OFS * (TimerID % TM_PER_IP)); //bit field offset 0/3/6 for TMCR/INTRSTATE/INTRMASK
Timer_Reg = (TimerID < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
if(State == TIMER_PAUSE)
{
bit = kdrv_timer_get_bit((TM_ENABLE) << ofs);
read_clear_bit((uint32_t)&Timer_Reg->dw.TmCR, bit);
return KDRV_STATUS_OK;
}
switch(TimerID % TM_PER_IP)
{
case TM_ID_1:
Timer_Reg->dw.Tm1Counter = load;
Timer_Reg->dw.Tm1Load = 0;
Timer_Reg->dw.Tm1Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm1Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm1OfEn = 1;
Timer_Reg->bf.Tm1Clock = 0;
Timer_Reg->bf.Tm1UpDown = 0;
Timer_Reg->bf.MTm1Match1 = 1;
Timer_Reg->bf.MTm1Match2 = 1;
Timer_Reg->bf.MTm1Overflow = 0;
break;
case TM_ID_2:
Timer_Reg->dw.Tm2Counter = load;
Timer_Reg->dw.Tm2Load = 0;
Timer_Reg->dw.Tm2Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm2Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm2OfEn = 1;
Timer_Reg->bf.Tm2Clock = 0;
Timer_Reg->bf.Tm2UpDown = 0;
Timer_Reg->bf.MTm2Match1 = 1;
Timer_Reg->bf.MTm2Match2 = 1;
Timer_Reg->bf.MTm2Overflow = 0;
break;
case TM_ID_3:
Timer_Reg->dw.Tm3Counter = load;
Timer_Reg->dw.Tm3Load = 0;
Timer_Reg->dw.Tm3Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm3Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm3OfEn = 1;
Timer_Reg->bf.Tm3Clock = 0;
Timer_Reg->bf.Tm3UpDown = 0;
Timer_Reg->bf.MTm3Match1 = 1;
Timer_Reg->bf.MTm3Match2 = 1;
Timer_Reg->bf.MTm3Overflow = 0;
break;
default:
break;
}
if(State == TIMER_START)
{
Timer_Reg->dw.TmCR |= ((TM_ENABLE) << ofs);
if(timer[TimerID].cb == NULL)
{
timer[TimerID].tid = osThreadGetId();
if(timer[TimerID].tid != NULL)
osThreadFlagsWait(FLAGS_TIMER_OF_DONE_EVENT, osFlagsWaitAny, osWaitForever);
else
{
timer_wakeup = 0;
do
{
__WFE();
} while (timer_wakeup == 0);
}
kdrv_timer_close(TimerId);
}
}
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_perf_open(uint32_t* TimerId)
{
uint32_t free_mask=0;
kdrv_status_t ret = KDRV_STATUS_OK;
uint32_t Used_mask = timer_used_mask;
free_mask = (~Used_mask) &(((~Used_mask) - 1)^(~Used_mask));
if(free_mask == BIT0 || free_mask == BIT3)
{
Used_mask |= free_mask;
free_mask = (~Used_mask) &(((~Used_mask) - 1)^(~Used_mask));
}
if(free_mask > 0x3F)
{
*TimerId = TIMER_ID_INIT;
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
}
*TimerId = kdrv_timer_get_bit(free_mask);
ret = kdrv_timer_register(TimerId, NULL, NULL);
if(ret == KDRV_STATUS_OK)
timer_used_mask |= free_mask;
return ret;
}
kdrv_status_t kdrv_timer_perf_set(uint32_t* TimerId)
{
uint32_t TimerID = *TimerId;
U_regTIMER* Timer_Reg;
if(timer[TimerID].in_use == 0)
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
if(timer[TimerID].perf_in_use == 1)
return KDRV_STATUS_ERROR;
timer[TimerID].perf_in_use = 1;
timer[TimerID].perf_cnt = 0;
Timer_Reg = (TimerID < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
switch(TimerID % TM_PER_IP)
{
case TM_ID_1:
Timer_Reg->dw.Tm1Counter = 0;
Timer_Reg->dw.Tm1Load = 0;
Timer_Reg->dw.Tm1Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm1Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm1OfEn = 1;
Timer_Reg->bf.Tm1Clock = 0;
Timer_Reg->bf.Tm1UpDown = TM_UP;
Timer_Reg->bf.MTm1Match1 = 1;
Timer_Reg->bf.MTm1Match2 = 1;
Timer_Reg->bf.MTm1Overflow = 0;
Timer_Reg->bf.Tm1En = 1;
break;
case TM_ID_2:
Timer_Reg->dw.Tm2Counter = 0;
Timer_Reg->dw.Tm2Load = 0;
Timer_Reg->dw.Tm2Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm2Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm2OfEn = 1;
Timer_Reg->bf.Tm2Clock = 0;
Timer_Reg->bf.Tm2UpDown = TM_UP;
Timer_Reg->bf.MTm2Match1 = 1;
Timer_Reg->bf.MTm2Match2 = 1;
Timer_Reg->bf.MTm2Overflow = 0;
Timer_Reg->bf.Tm2En = 1;
break;
case TM_ID_3:
Timer_Reg->dw.Tm3Counter = 0;
Timer_Reg->dw.Tm3Load = 0;
Timer_Reg->dw.Tm3Match1 = 0xFFFFFFFF;
Timer_Reg->dw.Tm3Match2 = 0xFFFFFFFF;
Timer_Reg->bf.Tm3OfEn = 1;
Timer_Reg->bf.Tm3Clock = 0;
Timer_Reg->bf.Tm3UpDown = TM_UP;
Timer_Reg->bf.MTm3Match1 = 1;
Timer_Reg->bf.MTm3Match2 = 1;
Timer_Reg->bf.MTm3Overflow = 0;
Timer_Reg->bf.Tm3En = 1;
break;
default:
break;
}
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_perf_get_instant(uint32_t* TimerId, uint32_t* instant, uint32_t* time)
{
uint32_t ctime;
uint32_t TimerID = *TimerId;
U_regTIMER* Timer_Reg;
Timer_Reg = (*TimerId < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
if(timer[*TimerId].perf_in_use == 0)
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
if(timer[*TimerId].perf_cnt >= PERF_ISR_CNT)
timer[*TimerId].perf_cnt = PERF_ISR_CNT;// avoid overflow;
switch(TimerID % TM_PER_IP)
{
case TM_ID_1:
ctime = Timer_Reg->dw.Tm1Counter/100;
break;
case TM_ID_2:
ctime = Timer_Reg->dw.Tm2Counter/100;
break;
case TM_ID_3:
ctime = Timer_Reg->dw.Tm3Counter/100;
break;
default:
break;
}
if(ctime < timer[*TimerId].perf_last_instant)
*instant = ctime + (42949672 - timer[*TimerId].perf_last_instant);
else
*instant = ctime - timer[*TimerId].perf_last_instant;
timer[*TimerId].perf_last_instant = ctime;
*time = ctime;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_perf_reset(uint32_t* TimerId)
{
uint32_t TimerID = *TimerId;
U_regTIMER* Timer_Reg;
Timer_Reg = (*TimerId < TM_PER_IP)? REGTIMER_0: REGTIMER_1;
if(timer[*TimerId].perf_in_use == 0)
return KDRV_STATUS_ERROR;
timer[*TimerId].perf_cnt = 0;
switch(TimerID % TM_PER_IP)
{
case TM_ID_1:
Timer_Reg->dw.Tm1Counter = 0;
break;
case TM_ID_2:
Timer_Reg->dw.Tm2Counter = 0;
break;
case TM_ID_3:
Timer_Reg->dw.Tm3Counter = 0;
break;
default:
break;
}
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_initialize(void)
{
if(timer_inited == 1)
return KDRV_STATUS_ERROR;
timer_inited = 1;
timer_used_mask = 0;
read_set_bit(SCU_FTSCU100_PA_BASE + 0x60, 15);
read_set_bit(SCU_FTSCU100_PA_BASE + 0x60, 16);
kdrv_timer_ip_init();
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_0_1_IRQ, (uint32_t)kdrv_timer_irqhandler0);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_0_1_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_0_1_IRQ);
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_0_2_IRQ, (uint32_t)kdrv_timer_irqhandler0);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_0_2_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_0_2_IRQ);
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_0_3_IRQ, (uint32_t)kdrv_timer_irqhandler0);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_0_3_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_0_3_IRQ);
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_1_1_IRQ, (uint32_t)kdrv_timer_irqhandler1);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_1_1_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_1_1_IRQ);
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_1_2_IRQ, (uint32_t)kdrv_timer_irqhandler1);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_1_2_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_1_2_IRQ);
NVIC_SetVector((IRQn_Type)TMR_FTTMR010_1_3_IRQ, (uint32_t)kdrv_timer_irqhandler1);
NVIC_ClearPendingIRQ((IRQn_Type)TMR_FTTMR010_1_3_IRQ);
NVIC_EnableIRQ((IRQn_Type)TMR_FTTMR010_1_3_IRQ);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_uninitialize(void)
{
read_clear_bit(SCU_FTSCU100_PA_BASE + 0x60, 15);
read_clear_bit(SCU_FTSCU100_PA_BASE + 0x60, 16);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_0_1_IRQ);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_0_2_IRQ);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_0_3_IRQ);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_1_1_IRQ);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_1_2_IRQ);
NVIC_DisableIRQ((IRQn_Type)TMR_FTTMR010_1_3_IRQ);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_timer_delay_ms(uint32_t msec)
{
uint32_t timerid;
kdrv_timer_initialize();
kdrv_timer_open(&timerid, NULL, NULL);
return kdrv_timer_set(&timerid, (msec*1000), TIMER_START);
}
kdrv_status_t kdrv_timer_delay_us(uint32_t usec)
{
uint32_t timerid;
kdrv_timer_initialize();
kdrv_timer_open(&timerid, NULL, NULL);
return kdrv_timer_set(&timerid, (usec), TIMER_START);
}
kdrv_status_t kdrv_timer_perf_measure_start(void)
{
kdrv_timer_initialize();
kdrv_timer_perf_open(&perftimerid);
kdrv_timer_perf_reset(&perftimerid);
return kdrv_timer_perf_set(&perftimerid);
}
kdrv_status_t kdrv_timer_perf_measure_get(uint32_t *instant, uint32_t *time)
{
return kdrv_timer_perf_get_instant(&perftimerid, instant, time);
}