rt-thread-official/bsp/ck802/libraries/common/pwm/ck_pwm.c

316 lines
8.8 KiB
C

/*
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************************************************
* @file ck_pwm.c
* @brief CSI Source File for PWM Driver
* @version V1.0
* @date 02. June 2017
******************************************************************************/
#include "ck_pwm.h"
#include "drv_pwm.h"
#include "soc.h"
#define ERR_PWM(errno) (CSI_DRV_ERRNO_PWM_BASE | errno)
#define PWM_NULL_PARAM_CHK(para) \
do { \
if (para == NULL) { \
return ERR_PWM(EDRV_PARAMETER); \
} \
} while (0)
typedef struct {
uint32_t base;
uint32_t irq;
uint32_t ch_num;
} ck_pwm_priv_t;
static ck_pwm_priv_t pwm_instance[CONFIG_PWM_NUM];
int32_t __attribute__((weak)) target_pwm_init(pin_t pwm_pin, uint32_t *ch_num, uint32_t *base, uint32_t *irq)
{
return -1;
}
/**
\brief Initialize PWM Interface. 1. Initializes the resources needed for the PWM interface 2.registers event callback function
\param[in] pwm pin of gpio
\return handle pwm handle to operate.
*/
pwm_handle_t drv_pwm_initialize(pin_t pwm_pin)
{
uint32_t base = 0u;
uint32_t irq = 0u;
uint32_t ch_num = 0u;
int32_t idx = target_pwm_init(pwm_pin, &ch_num, &base, &irq);
if (idx < 0 || idx >= CONFIG_PWM_NUM) {
return NULL;
}
ck_pwm_priv_t *pwm_priv = &pwm_instance[idx];
pwm_priv->base = base;
pwm_priv->irq = irq;
pwm_priv->ch_num = ch_num;
return pwm_priv;
}
/**
\brief De-initialize PWM Interface. stops operation and releases the software resources used by the interface
\param[in] handle pwm handle to operate.
\return \ref execution_status
*/
int32_t drv_pwm_uninitialize(pwm_handle_t handle)
{
PWM_NULL_PARAM_CHK(handle);
return 0;
}
/**
\brief config pwm mode.
\param[in] handle pwm handle to operate.
\param[in] sysclk configured system clock.
\param[in] period_us the PWM period in us
\param[in] duty the PMW duty. ( 0 - 10000 represents 0% - 100% ,other values are invalid)
\return \ref execution_status
*/
int32_t drv_pwm_config(pwm_handle_t handle, uint32_t sysclk, uint32_t period_us, uint32_t duty)
{
if (handle == NULL || duty > 10000) {
return ERR_PWM(EDRV_PARAMETER);
}
ck_pwm_priv_t *pwm_priv = handle;
uint32_t chn = pwm_priv->ch_num;
uint32_t counter = (sysclk / 1000000 * period_us);
if (counter >= 0xffff) {
return ERR_PWM(EDRV_PARAMETER);
}
uint32_t data_width;
data_width = (uint32_t)((counter * duty / 10000));
ck_pwm_reg_t *addr = (ck_pwm_reg_t *)(pwm_priv->base);
uint32_t ctl_tmp = addr->PWMCTL;
uint32_t temp;
if (chn == CKENUM_PWM_CH0 || chn == CKENUM_PWM_CH1) {
ctl_tmp &= 0xfffffffe;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP;
temp = addr->PWM01LOAD;
temp &= 0xffff0000;
addr->PWM01LOAD = temp | counter;
temp = addr->PWM0CMP;
if (chn == CKENUM_PWM_CH0) {
temp &= 0xffff0000;
addr->PWM0CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM0CMP = temp | data_width << 16;
}
}
if (chn == CKENUM_PWM_CH2 || chn == CKENUM_PWM_CH3) {
ctl_tmp &= 0xfffffffd;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP << 1;
temp = addr->PWM01LOAD;
temp &= 0x0000ffff;
addr->PWM01LOAD = temp | counter << 16 ;
temp = addr->PWM1CMP;
if (chn == CKENUM_PWM_CH2) {
temp &= 0xffff0000;
addr->PWM1CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM1CMP = temp | data_width << 16;
}
}
if (chn == CKENUM_PWM_CH4 || chn == CKENUM_PWM_CH5) {
ctl_tmp &= 0xfffffffb;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP << 2;
temp = addr->PWM23LOAD;
temp &= 0xffff0000;
addr->PWM23LOAD = temp | counter;
temp = addr->PWM2CMP;
if (chn == CKENUM_PWM_CH4) {
temp &= 0xffff0000;
addr->PWM2CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM2CMP = temp | data_width << 16;
}
}
if (chn == CKENUM_PWM_CH6 || chn == CKENUM_PWM_CH7) {
ctl_tmp &= 0xfffffff7;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP << 3;
temp = addr->PWM23LOAD;
temp &= 0x0000ffff;
addr->PWM23LOAD = temp | counter << 16 ;
temp = addr->PWM3CMP;
if (chn == CKENUM_PWM_CH6) {
temp &= 0xffff0000;
addr->PWM3CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM3CMP = temp | data_width << 16;
}
}
if (chn == CKENUM_PWM_CH8 || chn == CKENUM_PWM_CH9) {
ctl_tmp &= 0xffffffef;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP << 4;
temp = addr->PWM45LOAD;
temp &= 0xffff0000;
addr->PWM45LOAD = temp | counter ;
temp = addr->PWM4CMP;
if (chn == CKENUM_PWM_CH8) {
temp &= 0xffff0000;
addr->PWM4CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM4CMP = temp | data_width << 16;
}
}
if (chn == CKENUM_PWM_CH10 || chn == CKENUM_PWM_CH11) {
ctl_tmp &= 0xffffffdf;
addr->PWMCTL = ctl_tmp | (uint32_t)CKENUM_PWM_COUNT_UP << 5;
temp = addr->PWM45LOAD;
temp &= 0x0000ffff;
addr->PWM45LOAD = temp | counter << 16 ;
temp = addr->PWM5CMP;
if (chn == CKENUM_PWM_CH10) {
temp &= 0xffff0000;
addr->PWM5CMP = temp | data_width;
} else {
temp &= 0x0000ffff;
addr->PWM5CMP = temp | data_width << 16;
}
}
return 0;
}
/**
\brief start generate pwm signal.
\param[in] handle pwm handle to operate.
\param[in] pwm channel number.
\return \ref execution_status
*/
int32_t drv_pwm_start(pwm_handle_t handle)
{
PWM_NULL_PARAM_CHK(handle);
ck_pwm_priv_t *pwm_priv = handle;
ck_pwm_reg_t *addr = (ck_pwm_reg_t *)(pwm_priv->base);
uint32_t chn = pwm_priv->ch_num;
if (chn == CKENUM_PWM_CH0 || chn == CKENUM_PWM_CH1) {
addr->PWMCFG |= 0x00000003; /* PWM0 output enable */
}
if (chn == CKENUM_PWM_CH2 || chn == CKENUM_PWM_CH3) {
addr->PWMCFG |= 0x0000000C; /* PWM1 output enable */
}
if (chn == CKENUM_PWM_CH4 || chn == CKENUM_PWM_CH5) {
addr->PWMCFG |= 0x00000030; /* PWM2 output enable */
}
if (chn == CKENUM_PWM_CH6 || chn == CKENUM_PWM_CH7) {
addr->PWMCFG |= 0x000000C0; /* PWM3 output enable */
}
if (chn == CKENUM_PWM_CH8 || chn == CKENUM_PWM_CH9) {
addr->PWMCFG |= 0x00000300; /* PWM4 output enable */
}
if (chn == CKENUM_PWM_CH10 || chn == CKENUM_PWM_CH11) {
addr->PWMCFG |= 0x00000C00; /* PWM5 output enable */
}
return 0;
}
/**
\brief Stop generate pwm signal.
\param[in] handle pwm handle to operate.
\return \ref execution_status
*/
int32_t drv_pwm_stop(pwm_handle_t handle)
{
PWM_NULL_PARAM_CHK(handle);
ck_pwm_priv_t *pwm_priv = handle;
ck_pwm_reg_t *addr = (ck_pwm_reg_t *)(pwm_priv->base);
uint32_t chn = pwm_priv->ch_num;
if (chn == CKENUM_PWM_CH0 || chn == CKENUM_PWM_CH1) {
addr->PWMCFG &= ~0x00000003; /* PWM0 output disable */
}
if (chn == CKENUM_PWM_CH2 || chn == CKENUM_PWM_CH3) {
addr->PWMCFG &= ~0x0000000C; /* PWM1 output disable */
}
if (chn == CKENUM_PWM_CH4 || chn == CKENUM_PWM_CH5) {
addr->PWMCFG &= ~0x00000030; /* PWM2 output disable */
}
if (chn == CKENUM_PWM_CH6 || chn == CKENUM_PWM_CH7) {
addr->PWMCFG &= ~0x000000C0; /* PWM3 output disable */
}
if (chn == CKENUM_PWM_CH8 || chn == CKENUM_PWM_CH9) {
addr->PWMCFG &= ~0x00000300; /* PWM4 output disable */
}
if (chn == CKENUM_PWM_CH10 || chn == CKENUM_PWM_CH11) {
addr->PWMCFG &= ~0x00000C00; /* PWM5 output disable */
}
return 0;
}