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

557 lines
14 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_pwm.c
*
* Project:
* --------
* KL520
*
* Description:
* ------------
* This is PWMTIMER driver
*
* Author:
* -------
* Albert Chen
**
******************************************************************************/
/******************************************************************************
Head Block of The File
******************************************************************************/
// Sec 0: Comment block of the file
// Sec 1: Include File
#include "base.h"
#include "io.h"
#include "Driver_Common.h"
#include "regbase.h"
#include "kdrv_pwm.h"
#include "kdrv_pinmux.h"
#include "kdrv_cmsis_core.h"
//#include "kmdw_console.h"
//#define PWM_DBG
#ifdef PWM_DBG
#define pwm_msg(fmt, ...) info_msg("[KDRV_PWM] " fmt, ##__VA_ARGS__)
#else
#define pwm_msg(fmt, ...)
#endif
#define MAX_PWM_TIMER 6
#define HZ 100 /// how many tick each sec
#define MAX_TIMER 7
#define TIMER_INTSTAT 0x0
#define TIMER_CR 0x0
#define TIMER_LOAD 0x4
#define TIMER_COMPARE 0x8
#define TIMER_CNTO 0xc
/******************************************************************************
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 struct
{
uint32_t TmSrc: 1; /* bit 0 */
uint32_t TmStart: 1;
uint32_t TmUpdate: 1;
uint32_t TmOutInv: 1;
uint32_t TmAutoLoad:1;
uint32_t TmIntEn: 1;
uint32_t TmIntMode: 1;
uint32_t TmDmaEn: 1;
uint32_t TmPwmEn: 1; /* bit 8 */
uint32_t Reserved: 15; /* bit 9~23 */
uint32_t TmDeadZone:8; /* bit 24~31 */
}kdrv_pwmtimer_control;
typedef struct
{
uint32_t IntNum; /* interrupt number */
uint32_t Tick; /* Tick Per Second */
uint32_t Running; /* Is timer running */
}kdrv_pwmtimer_struct;
typedef void (*timer_isr)(void);
/******************************************************************************
Declaration of Global Variables & Functions
******************************************************************************/
// Sec 6: declaration of global variable
// Sec 7: declaration of global function prototype
/******************************************************************************
Declaration of static Global Variables & Functions
******************************************************************************/
// Sec 8: declaration of static global variable
kdrv_pwmtimer_control *timer_control[MAX_TIMER+1];
uint32_t *CNTBBase_tmp;
uint32_t *CMPBBase_tmp;
static kdrv_pwmtimer_struct ftimer[MAX_TIMER+1];
static uint32_t TimerBase[MAX_TIMER+1] ={0, PWM_FTPWMTMR010_PA_BASE+0x10, PWM_FTPWMTMR010_PA_BASE+0x20,PWM_FTPWMTMR010_PA_BASE+0x30,PWM_FTPWMTMR010_PA_BASE+0x40,PWM_FTPWMTMR010_PA_BASE+0x50,PWM_FTPWMTMR010_PA_BASE+0x60,PWM_FTPWMTMR010_PA_BASE+0x70};
static uint32_t CNTBBase[MAX_TIMER+1] ={0, PWM_FTPWMTMR010_PA_BASE+0x14, PWM_FTPWMTMR010_PA_BASE+0x24,PWM_FTPWMTMR010_PA_BASE+0x34,PWM_FTPWMTMR010_PA_BASE+0x44,PWM_FTPWMTMR010_PA_BASE+0x54,PWM_FTPWMTMR010_PA_BASE+0x64,PWM_FTPWMTMR010_PA_BASE+0x74};
static uint32_t CMPBBase[MAX_TIMER+1] ={0, PWM_FTPWMTMR010_PA_BASE+0x18, PWM_FTPWMTMR010_PA_BASE+0x28,PWM_FTPWMTMR010_PA_BASE+0x38,PWM_FTPWMTMR010_PA_BASE+0x48,PWM_FTPWMTMR010_PA_BASE+0x58,PWM_FTPWMTMR010_PA_BASE+0x68,PWM_FTPWMTMR010_PA_BASE+0x78};
uint32_t t1_tick = 0, t2_tick = 0, t3_tick = 0, t4_tick = 0, t5_tick = 0, t6_tick = 0;
// Sec 9: declaration of static function prototype
static void kdrv_pwmtimer_resetall(void);
static void kdrv_pwmtimer_autoreloadvalue(pwmtimer timer, uint32_t value);
static kdrv_status_t kdrv_pwmtimer_int_clear(pwmtimer timer);
/******************************************************************************
// Sec 10: C Functions
******************************************************************************/
static kdrv_status_t _set_timer_clk_source(pwmtimer timer,uint32_t clk)
{
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
timer_control[timer]->TmSrc = clk;
return KDRV_STATUS_OK;
}
static kdrv_status_t _set_timer_tick(uint32_t timer,uint32_t clk_tick)
{
volatile kdrv_pwmtimer_struct *ctimer = &ftimer[timer];
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
ctimer->Tick = clk_tick;
return KDRV_STATUS_OK;
}
static void _print_pwm_reg(pwmtimer timer)
{
#ifdef PWM_DBG
uint32_t val = 0;
val = inw(TimerBase[timer]);
pwm_msg("T%d_CTRL = 0x%4x", timer, val);
val = inw(CNTBBase[timer]);
pwm_msg("T%d_CNTB = 0x%4x", timer, val);
val = inw(CMPBBase[timer]);
pwm_msg("T%d_CMPB = 0x%4x", timer, val);
val = inw(CMPBBase[timer] + 0x4);
pwm_msg("T%d_CNTO = 0x%4x", timer, val);
#endif
}
static void PWMTimer1_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER1);
++t1_tick;
}
static void PWMTimer2_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER2);
++t2_tick;
}
static void PWMTimer3_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER3);
++t3_tick;
}
static void PWMTimer4_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER4);
++t4_tick;
}
static void PWMTimer5_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER5);
++t5_tick;
}
static void PWMTimer6_IRQHandler(void)
{
kdrv_pwmtimer_int_clear(PWMTIMER6);
++t6_tick;
}
static kdrv_status_t kdrv_pwmtimer_disable(pwmtimer timer)
{
kdrv_pwmtimer_struct *ctimer=&ftimer[timer];
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
timer_control[timer]->TmStart = 0;
timer_control[timer]->TmUpdate = 0;
timer_control[timer]->TmOutInv = 0;
timer_control[timer]->TmDmaEn = 0;
timer_control[timer]->TmIntEn = 0;
timer_control[timer]->TmDeadZone= 0;
timer_control[timer]->TmSrc = 0;
timer_control[timer]->TmAutoLoad= 0;
ctimer->Running = false;
return KDRV_STATUS_OK;
}
static void kdrv_pwmtimer_resetall(void)
{
uint32_t i;
for (i = 1; i <= MAX_TIMER; i++)
kdrv_pwmtimer_disable((pwmtimer)i);
}
static void kdrv_pwmtimer_autoreloadvalue(pwmtimer timer, uint32_t value)
{
outw(TimerBase[timer] + TIMER_LOAD, value);
}
static kdrv_status_t kdrv_pwmtimer_autoreloadenable(pwmtimer timer)
{
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
timer_control[timer]->TmAutoLoad = 1;
return KDRV_STATUS_OK;
}
static kdrv_status_t kdrv_pwmtimer_int_enable(pwmtimer timer)
{
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
timer_control[timer]->TmIntEn = 1;
return KDRV_STATUS_OK;
}
static kdrv_status_t kdrv_pwmtimer_ioctrl(timeriotype iotype, pwmtimer timer, uint32_t tick)
{
switch(iotype)
{
case IO_TIMER_RESETALL:
kdrv_pwmtimer_resetall();
break;
case IO_TIMER_SETTICK:
return _set_timer_tick(timer,tick);
case IO_TIMER_SETCLKSRC:
return _set_timer_clk_source(timer,tick);
default:
return KDRV_STATUS_ERROR;
}
return KDRV_STATUS_OK;
}
static kdrv_status_t kdrv_pwmtimer_int_clear(pwmtimer timer)
{
int value;
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_INVALID_TIMER_ID;
value = 1<<(timer-1);
outw(PWM_FTPWMTMR010_PA_BASE + TIMER_INTSTAT, value);
return KDRV_STATUS_OK;
}
static kdrv_status_t kdrv_pwmtimer_enable(pwmtimer timer)
{
kdrv_pwmtimer_struct *ctimer=&ftimer[timer];
if ((timer == 0) || (timer > MAX_TIMER))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
if(ctimer->Running == true)
return KDRV_STATUS_TIMER_ID_IN_USED;
timer_control[timer]->TmUpdate = 1;
timer_control[timer]->TmStart = 1;
ctimer->Running = true;
return KDRV_STATUS_OK;
}
uint32_t kdrv_current_t1_tick(void)
{
return t1_tick;
}
uint32_t kdrv_current_t2_tick(void)
{
return t2_tick;
}
uint32_t kdrv_current_t3_tick(void)
{
return t3_tick;
}
uint32_t kdrv_current_t4_tick(void)
{
return t4_tick;
}
uint32_t kdrv_current_t5_tick(void)
{
return t5_tick;
}
uint32_t kdrv_current_t6_tick(void)
{
return t6_tick;
}
kdrv_status_t kdrv_pwmtimer_initialize(pwmtimer timer, uint32_t tick)
{
kdrv_pwmtimer_struct *ctimer = &ftimer[timer];
uint32_t timer_irq;
timer_isr isr;
if (timer == 0 || timer > MAX_TIMER)
return KDRV_STATUS_TIMER_INVALID_TIMER_ID;
switch(timer)
{
case PWMTIMER1:
t1_tick = 0;
timer_irq = PWM_FTPWMTMR010_1_IRQ;
isr = PWMTimer1_IRQHandler;
break;
case PWMTIMER2:
t2_tick = 0;
timer_irq = PWM_FTPWMTMR010_2_IRQ;
isr = PWMTimer2_IRQHandler;
break;
case PWMTIMER3:
t3_tick = 0;
timer_irq = PWM_FTPWMTMR010_3_IRQ;
isr = PWMTimer3_IRQHandler;
break;
case PWMTIMER4:
t4_tick = 0;
timer_irq = PWM_FTPWMTMR010_4_IRQ;
isr = PWMTimer4_IRQHandler;
break;
case PWMTIMER5:
t5_tick = 0;
timer_irq = PWM_FTPWMTMR010_5_IRQ;
isr = PWMTimer5_IRQHandler;
break;
case PWMTIMER6:
t6_tick = 0;
timer_irq = PWM_FTPWMTMR010_6_IRQ;
isr = PWMTimer6_IRQHandler;
break;
default:
return KDRV_STATUS_TIMER_INVALID_TIMER_ID;
}
timer_control[timer]=(kdrv_pwmtimer_control *)(TimerBase[timer]);
kdrv_pwmtimer_close(timer);
if(kdrv_pwmtimer_ioctrl(IO_TIMER_SETTICK,timer,tick))
return KDRV_STATUS_ERROR;
kdrv_pwmtimer_autoreloadvalue(timer,ctimer->Tick);
kdrv_pwmtimer_autoreloadenable(timer);
kdrv_pwmtimer_int_clear(timer);
if (kdrv_pwmtimer_int_enable(timer))
return KDRV_STATUS_ERROR;
NVIC_SetVector((IRQn_Type)timer_irq, (uint32_t)isr);
NVIC_EnableIRQ((IRQn_Type)timer_irq);
if(kdrv_pwmtimer_enable(timer))
return KDRV_STATUS_ERROR;
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_pwmtimer_close(pwmtimer timer)
{
uint32_t timer_irq;
if (timer == 0 || timer > MAX_TIMER)
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
if(kdrv_pwmtimer_disable(timer))
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE; /* Stop the timer first */
switch(timer)
{
case PWMTIMER1:
timer_irq = PWM_FTPWMTMR010_1_IRQ;
break;
case PWMTIMER2:
timer_irq = PWM_FTPWMTMR010_2_IRQ;
break;
case PWMTIMER3:
timer_irq = PWM_FTPWMTMR010_3_IRQ;
break;
case PWMTIMER4:
timer_irq = PWM_FTPWMTMR010_4_IRQ;
break;
case PWMTIMER5:
timer_irq = PWM_FTPWMTMR010_5_IRQ;
break;
case PWMTIMER6:
timer_irq = PWM_FTPWMTMR010_6_IRQ;
break;
default:
return KDRV_STATUS_ERROR;
}
NVIC_DisableIRQ((IRQn_Type)timer_irq);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_pwmtimer_tick_reset(pwmtimer timer)
{
if ((timer == 0) || (timer > MAX_PWM_TIMER))
{
return KDRV_STATUS_TIMER_ID_NOT_AVAILABLE;
}
switch(timer)
{
case PWMTIMER1:
t1_tick = 0;
break;
case PWMTIMER2:
t2_tick = 0;
break;
case PWMTIMER3:
t3_tick = 0;
break;
case PWMTIMER4:
t4_tick = 0;
break;
case PWMTIMER5:
t5_tick = 0;
break;
case PWMTIMER6:
t6_tick = 0;
break;
default:
return KDRV_STATUS_ERROR;
}
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_pwmtimer_delay_ms(uint32_t msec)
{
uint32_t tick_end;
kdrv_status_t ret;
ret = kdrv_pwmtimer_initialize(PWMTIMER1, PWMTMR_1MSEC_PERIOD);
if(ret != KDRV_STATUS_OK)
return ret;
tick_end = kdrv_current_t1_tick() + msec;
do {
__WFI();
} while (tick_end > kdrv_current_t1_tick());
ret = kdrv_pwmtimer_close(PWMTIMER1);
return ret;
}
// Start of PWM function
kdrv_status_t kdrv_pwm_config(pwmtimer timer, pwmpolarity polarity, uint32_t duty, uint32_t period, bool ns2clkcnt)
{
uint32_t ClkCnt;
uint32_t ratio_period = 0;
uint32_t ratio_duty = 0;
CNTBBase_tmp = (uint32_t *)CNTBBase[timer];
CMPBBase_tmp = (uint32_t *)CMPBBase[timer];
if (timer == 0 || timer > MAX_TIMER)
return KDRV_STATUS_TIMER_INVALID_TIMER_ID;
if(duty == 0 || period == 0)
return KDRV_STATUS_ERROR;
_print_pwm_reg(timer);
if(ns2clkcnt)
{
ratio_period = 1000000000/period;
ClkCnt = APB_CLK / ratio_period;
*CNTBBase_tmp = ClkCnt ;
ratio_duty = 1000000000/duty;
ClkCnt = APB_CLK / ratio_duty;
*CMPBBase_tmp = ClkCnt ;
}
else
{
*CNTBBase_tmp = period;
*CMPBBase_tmp = duty;
}
timer_control[timer]=(kdrv_pwmtimer_control *)(TimerBase[timer]);
timer_control[timer]->TmUpdate = 1;
timer_control[timer]->TmOutInv = polarity;
timer_control[timer]->TmAutoLoad = 1;
timer_control[timer]->TmStart = 1;
_print_pwm_reg(timer);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_pwm_enable(pwmtimer timer)
{
timer_control[timer]->TmPwmEn = 1;
_print_pwm_reg(timer);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_pwm_disable(pwmtimer timer)
{
if(1 != timer_control[timer]->TmPwmEn)
{
pwm_msg("pwm%d is not enable!", timer);
return KDRV_STATUS_TIMER_ID_NOT_IN_USED;
}
timer_control[timer]->TmPwmEn = 0;
_print_pwm_reg(timer);
return KDRV_STATUS_OK;
}
// End of PWM function