[bsp/cvitek]add pwm driver (#8571)

This commit is contained in:
flyingcys 2024-03-02 16:16:22 +08:00 committed by GitHub
parent 76202e2141
commit aa04a59805
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 548 additions and 2 deletions

View File

@ -40,9 +40,31 @@ menu "General Drivers Configuration"
default 32
endif
menuconfig BSP_USING_ADC
config BSP_USING_ADC
bool "Using ADC"
select RT_USING_ADC
default n
menuconfig BSP_USING_PWM
bool "Using PWM"
select RT_USING_PWM
default n
if BSP_USING_PWM
config BSP_USING_PWM0
bool "Enable PWM 0"
default n
config BSP_USING_PWM1
bool "Enable PWM 1"
default n
config BSP_USING_PWM2
bool "Enable PWM 2"
default n
config BSP_USING_PWM3
bool "Enable PWM 3"
default n
endif
endmenu

View File

@ -32,9 +32,33 @@ menu "General Drivers Configuration"
endif
menuconfig BSP_USING_ADC
config BSP_USING_ADC
bool "Using ADC"
select RT_USING_ADC
default n
menuconfig BSP_USING_PWM
bool "Using PWM"
select RT_USING_PWM
default n
if BSP_USING_PWM
config BSP_USING_PWM0
bool "Enable PWM 0"
default n
config BSP_USING_PWM1
bool "Enable PWM 1"
default n
config BSP_USING_PWM2
bool "Enable PWM 2"
default n
config BSP_USING_PWM3
bool "Enable PWM 3"
default n
endif
endmenu

View File

@ -18,6 +18,9 @@ if GetDepend('BSP_USING_I2C'):
if GetDepend('BSP_USING_ADC'):
src += ['drv_adc.c']
if GetDepend('BSP_USING_PWM'):
src += ['drv_pwm.c']
CPPPATH += [cwd + r'/cv1800b/pwm']
CPPDEFINES += ['-DCONFIG_64BIT']
group = DefineGroup('drivers', src, depend = [''], CPPDEFINES = CPPDEFINES, CPPPATH = CPPPATH)

View File

@ -0,0 +1,266 @@
#ifndef __CVI_PWM_H__
#define __CVI_PWM_H__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
#define CVI_PWM0_BASE 0x03060000
#define CVI_PWM1_BASE 0x03061000
#define CVI_PWM2_BASE 0x03062000
#define CVI_PWM3_BASE 0x03063000
typedef enum {
PWM_CHANNEL_0 = 0U,
PWM_CHANNEL_1,
PWM_CHANNEL_2,
PWM_CHANNEL_3,
PWM_CHANNEL_4,
PWM_CHANNEL_5,
PWM_CHANNEL_6,
PWM_CHANNEL_7,
PWM_CHANNEL_8,
PWM_CHANNEL_9,
PWM_CHANNEL_10,
PWM_CHANNEL_11,
PWM_CHANNEL_12,
PWM_CHANNEL_13,
PWM_CHANNEL_14,
PWM_CHANNEL_15,
PWM_CHANNEL_NUM
} cvi_pwm_channel_t;
struct cvi_pwm_regs_t {
uint32_t HLPERIOD0;
uint32_t PERIOD0;
uint32_t HLPERIOD1;
uint32_t PERIOD1;
uint32_t HLPERIOD2;
uint32_t PERIOD2;
uint32_t HLPERIOD3;
uint32_t PERIOD3;
uint32_t CAP_FREQNUM;
uint32_t CAP_FREQDATA;
uint32_t POLARITY;
uint32_t PWMSTART;
uint32_t PWMDONE;
uint32_t PWMUPDATE;
uint32_t PCOUNT0;
uint32_t PCOUNT1;
uint32_t PCOUNT2;
uint32_t PCOUNT3;
uint32_t PULSECOUNT0;
uint32_t PULSECOUNT1;
uint32_t PULSECOUNT2;
uint32_t PULSECOUNT3;
uint32_t SHIFTCOUNT0;
uint32_t SHIFTCOUNT1;
uint32_t SHIFTCOUNT2;
uint32_t SHIFTCOUNT3;
uint32_t SHIFTSTART;
uint32_t CAP_FREQEN;
uint32_t CAP_FREQDONE_NUM;
uint32_t PWM_OE;
};
static struct cvi_pwm_regs_t cv182x_pwm_reg = {
.HLPERIOD0 = 0x0,
.PERIOD0 = 0x4,
.HLPERIOD1 = 0x8,
.PERIOD1 = 0xc,
.HLPERIOD2 = 0x10,
.PERIOD2 = 0x14,
.HLPERIOD3 = 0x18,
.PERIOD3 = 0x1c,
.CAP_FREQNUM = 0x20,
.CAP_FREQDATA = 0x24,
.POLARITY = 0x40,
.PWMSTART = 0x44,
.PWMDONE = 0x48,
.PWMUPDATE = 0x4c,
.PCOUNT0 = 0x50,
.PCOUNT1 = 0x54,
.PCOUNT2 = 0x58,
.PCOUNT3 = 0x5c,
.PULSECOUNT0 = 0x60,
.PULSECOUNT1 = 0x64,
.PULSECOUNT2 = 0x68,
.PULSECOUNT3 = 0x6c,
.SHIFTCOUNT0 = 0x80,
.SHIFTCOUNT1 = 0x84,
.SHIFTCOUNT2 = 0x88,
.SHIFTCOUNT3 = 0x8c,
.SHIFTSTART = 0x90,
.CAP_FREQEN = 0x9c,
.CAP_FREQDONE_NUM = 0xC0,
.PWM_OE = 0xd0,
};
static struct cvi_pwm_regs_t *cvi_pwm_reg = &cv182x_pwm_reg;
#define PWM_HLPERIOD0(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD0))
#define PWM_PERIOD0(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD0))
#define PWM_HLPERIOD1(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD1))
#define PWM_PERIOD1(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD1))
#define PWM_HLPERIOD2(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD2))
#define PWM_PERIOD2(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD2))
#define PWM_HLPERIOD3(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD3))
#define PWM_PERIOD3(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD3))
#define PWM_HLPERIODX(reg_base, _ch_) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->HLPERIOD0 + (_ch_ << 3)))
#define PWM_PERIODX(reg_base, _ch_) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PERIOD0 * (1 + (_ch_ << 1))))
#define CAP_FREQNUM(reg_base, _ch_) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQNUM + _ch_ * 8))
#define CAP_FREQDATA(reg_base, _ch_) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQDATA + _ch_ * 8))
#define PWM_POLARITY(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->POLARITY))
#define PWM_PWMSTART(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMSTART))
#define PWM_PWMDONE(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMDONE))
#define PWM_PWMUPDATE(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWMUPDATE))
#define PWM_PCOUNT0(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT0))
#define PWM_PCOUNT1(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT1))
#define PWM_PCOUNT2(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT2))
#define PWM_PCOUNT3(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PCOUNT3))
#define PWM_PULSECOUNT0(reg_base) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT0))
#define PWM_PULSECOUNT1(reg_base) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT1))
#define PWM_PULSECOUNT2(reg_base) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT2))
#define PWM_PULSECOUNT3(reg_base) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->PULSECOUNT3))
#define PWM_SHIFTCOUNT0(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT0))
#define PWM_SHIFTCOUNT1(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT1))
#define PWM_SHIFTCOUNT2(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT2))
#define PWM_SHIFTCOUNT3(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTCOUNT3))
#define PWM_SHIFTSTART(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->SHIFTSTART))
#define CAP_FREQEN(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQEN))
#define CAP_FREQDONE_NUM(reg_base, _ch_) *((__IM uint32_t *)(reg_base + cvi_pwm_reg->CAP_FREQDONE_NUM + _ch_ * 4))
#define PWM_PWM_OE(reg_base) *((__IOM uint32_t *)(reg_base + cvi_pwm_reg->PWM_OE))
/*! PWM Configure Register, offset: 0x00 */
#define CVI_PWM_HIGH_PERIOD_Pos (0U)
#define CVI_PWM_HIGH_PERIOD_Msk (0xffffffff)
#define CVI_PWM_PERIOD_Pos (0U)
#define CVI_PWM_PERIOD_Msk (0xffffffff)
#define CVI_PWM_POLARITY_CH_Pos(_ch_) (_ch_)
#define CVI_PWM_POLARITY_CH_Msk(_ch_) (1U << CVI_PWM_POLARITY_CH_Pos(_ch_))
#define CVI_PWM_POLARITY_CH_HIGH(_ch_) CVI_PWM_POLARITY_CH_Msk(_ch_)
#define CVI_PWM_START_CH_Pos(_ch_) (_ch_)
#define CVI_PWM_START_CH_Msk(_ch_) (1U << CVI_PWM_START_CH_Pos(_ch_))
#define CVI_PWM_START_CH_EN(_ch_) CVI_PWM_START_CH_Msk(_ch_)
#define CVI_PWM_OUTPUT_CH_Pos(_ch_) (_ch_)
#define CVI_PWM_OUTPUT_CH_Msk(_ch_) (1U << CVI_PWM_OUTPUT_CH_Pos(_ch_))
#define CVI_PWM_OUTPUT_CH_EN(_ch_) CVI_PWM_OUTPUT_CH_Msk(_ch_)
#define CVI_CAP_FREQNUM_CH_Pos (0U)
#define CVI_CAP_FREQNUM_CH_Msk (0xffffffff)
#define CVI_CAP_FREQEN_Pos(_ch_) (_ch_)
#define CVI_CAP_FREQEN_Msk(_ch_) (1U << CVI_CAP_FREQEN_Pos(_ch_))
#define CVI_CAP_FREQEN(_ch_) CVI_CAP_FREQEN_Msk(_ch_)
#define CVI_CAP_FREQDONE_NUM_Poa (0U)
#define CVI_CAP_FREQDONE_NUM_Msk (0xffffffff)
#define CVI_CAP_FREQDATA_pos (0U)
#define CVI_CAP_FREQDATA_msk (0xffffffff)
static inline void cvi_pwm_set_high_period_ch(unsigned long reg_base, uint32_t ch, unsigned long long value)
{
PWM_HLPERIODX(reg_base, ch) = value;
}
static inline unsigned long long cvi_pwm_get_high_period_ch(unsigned long reg_base, uint32_t ch)
{
return PWM_HLPERIODX(reg_base, ch);
}
static inline void cvi_pwm_set_period_ch(unsigned long reg_base, uint32_t ch, unsigned long long value)
{
PWM_PERIODX(reg_base, ch) = value;
}
static inline unsigned long long cvi_pwm_get_period_ch(unsigned long reg_base, uint32_t ch)
{
return PWM_PERIODX(reg_base, ch);
}
static inline void cvi_pwm_set_polarity_high_ch(unsigned long reg_base, uint32_t ch)
{
PWM_POLARITY(reg_base) |= CVI_PWM_POLARITY_CH_HIGH(ch);
}
static inline void cvi_pwm_set_polarity_low_ch(unsigned long reg_base, uint32_t ch)
{
PWM_POLARITY(reg_base) &= ~CVI_PWM_POLARITY_CH_HIGH(ch);
}
static inline uint32_t cvi_pwm_get_polarity(unsigned long reg_base, uint32_t ch)
{
return (PWM_POLARITY(reg_base) & CVI_PWM_POLARITY_CH_Msk(ch));
}
static inline void cvi_pwm_start_en_ch(unsigned long reg_base, uint32_t ch)
{
PWM_PWMSTART(reg_base) |= CVI_PWM_START_CH_EN(ch);
}
static inline void cvi_pwm_start_dis_ch(unsigned long reg_base, uint32_t ch)
{
PWM_PWMSTART(reg_base) &= ~CVI_PWM_START_CH_EN(ch);
}
static inline void cvi_pwm_output_en_ch(unsigned long reg_base, uint32_t ch)
{
PWM_PWM_OE(reg_base) |= CVI_PWM_OUTPUT_CH_EN(ch);
}
static inline void cvi_pwm_input_en_ch(unsigned long reg_base, uint32_t ch)
{
PWM_PWM_OE(reg_base) &= ~CVI_PWM_OUTPUT_CH_EN(ch);
}
static inline void cvi_cap_set_freqnum_ch(unsigned long reg_base, uint32_t ch, uint32_t value)
{
CAP_FREQNUM(reg_base, ch) = value;
}
static inline void cvi_cap_freq_en_ch(unsigned long reg_base, uint32_t ch)
{
CAP_FREQEN(reg_base) |= CVI_CAP_FREQEN(ch);
}
static inline void cvi_cap_freq_dis_ch(unsigned long reg_base, uint32_t ch)
{
CAP_FREQEN(reg_base) &= ~CVI_CAP_FREQEN(ch);
}
static inline uint32_t cvi_cap_get_freq_done_num_ch(unsigned long reg_base, uint32_t ch)
{
return CAP_FREQDONE_NUM(reg_base, ch);
}
static inline uint32_t cvi_cap_get_freq_data_ch(unsigned long reg_base, uint32_t ch)
{
return CAP_FREQDATA(reg_base, ch);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024/02/19 flyingcys first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_pwm.h"
#ifdef BSP_USING_PWM
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define LOG_TAG "DRV.PWM"
struct cvi_pwm_dev
{
struct rt_device_pwm device;
const char *name;
rt_ubase_t reg_base;
};
static const uint64_t count_unit = 100000000; // 100M count per second
static const uint64_t NSEC_COUNT = 1000000000; // ns
static void cvi_pwm_set_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
{
unsigned long long duty_clk, period_clk;
cvi_pwm_set_polarity_low_ch(reg_base, (cfg->channel & PWM_MAX_CH));
duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
cvi_pwm_set_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
period_clk = (cfg->period * count_unit) / NSEC_COUNT;
cvi_pwm_set_period_ch(reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
cvi_pwm_output_en_ch(reg_base, cfg->channel & PWM_MAX_CH);
}
static void cvi_pwm_get_config(rt_ubase_t reg_base, struct rt_pwm_configuration *cfg)
{
unsigned long long duty_clk, period_clk;
duty_clk = cvi_pwm_get_high_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
cfg->pulse = duty_clk * NSEC_COUNT / count_unit;
period_clk = cvi_pwm_get_period_ch(reg_base, (cfg->channel & PWM_MAX_CH));
cfg->period = period_clk * NSEC_COUNT / count_unit;
}
static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
{
struct rt_pwm_configuration *cfg = (struct rt_pwm_configuration *)arg;
struct cvi_pwm_dev *pwm_dev = (struct cvi_pwm_dev *)device->parent.user_data;
unsigned long long duty_clk, period_clk;
const uint64_t count_unit = 100000000; // 100M count per second
const uint64_t NSEC_COUNT = 1000000000; // ns
if (cfg->channel > PWM_MAX_CH)
return -RT_EINVAL;
switch (cmd)
{
case PWM_CMD_ENABLE:
cvi_pwm_start_en_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
break;
case PWM_CMD_DISABLE:
cvi_pwm_start_dis_ch(pwm_dev->reg_base, cfg->channel & PWM_MAX_CH);
break;
case PWM_CMD_SET:
cvi_pwm_set_config(pwm_dev->reg_base, cfg);
break;
case PWM_CMD_GET:
cvi_pwm_get_config(pwm_dev->reg_base, cfg);
break;
case PWM_CMD_SET_PERIOD:
period_clk = (cfg->period * count_unit) / NSEC_COUNT;
cvi_pwm_set_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), period_clk);
break;
case PWM_CMD_SET_PULSE:
duty_clk = (cfg->pulse * count_unit) / NSEC_COUNT;
cvi_pwm_set_high_period_ch(pwm_dev->reg_base, (cfg->channel & PWM_MAX_CH), duty_clk);
break;
default:
LOG_D("cmd: %x channel: %d period: %d pulse: %d", cmd, cfg->channel, cfg->period, cfg->pulse);
break;
}
return RT_EOK;
}
const static struct rt_pwm_ops cvi_pwm_ops =
{
.control = &_pwm_control
};
static struct cvi_pwm_dev cvi_pwm[] =
{
#ifdef BSP_USING_PWM0
{
.name = "pwm0",
.reg_base = CVI_PWM0_BASE,
},
#endif
#ifdef BSP_USING_PWM1
{
.name = "pwm1",
.reg_base = CVI_PWM1_BASE,
},
#endif
#ifdef BSP_USING_PWM2
{
.name = "pwm2",
.reg_base = CVI_PWM2_BASE,
},
#endif
#ifdef BSP_USING_PWM3
{
.name = "pwm3",
.reg_base = CVI_PWM3_BASE,
},
#endif
};
int rt_hw_pwm_init(void)
{
int result = RT_EOK;
uint8_t i;
for (i = 0; i < sizeof(cvi_pwm) / sizeof(cvi_pwm[0]); i++)
{
result = rt_device_pwm_register(&cvi_pwm[i].device, cvi_pwm[i].name, &cvi_pwm_ops, &cvi_pwm[i]);
if (result != RT_EOK)
{
LOG_E("device %s register failed", cvi_pwm[i].name);
return -RT_ERROR;
}
}
return RT_EOK;
#if 0
#ifdef BSP_USING_PWM0
static struct cvi_pwm_dev cvi_pwm0;
cvi_pwm0.name = "pwm0";
cvi_pwm0.reg_base = CVI_PWM0_BASE;
result = rt_device_pwm_register(&cvi_pwm0.device, cvi_pwm0.name, &cvi_pwm_ops, &cvi_pwm0);
if (result != RT_EOK)
{
LOG_E("device %s register failed.", cvi_pwm0.name);
return result;
}
#endif
#ifdef BSP_USING_PWM1
static struct cvi_pwm_dev cvi_pwm1;
cvi_pwm1.name = "pwm1";
cvi_pwm1.reg_base = CVI_PWM1_BASE;
result = rt_device_pwm_register(&cvi_pwm1.device, cvi_pwm1.name, &cvi_pwm_ops, &cvi_pwm1);
if (result != RT_EOK)
{
LOG_E("device %s register failed.", cvi_pwm1.name);
return result;
}
#endif
#ifdef BSP_USING_PWM2
static struct cvi_pwm_dev cvi_pwm2;
cvi_pwm2.name = "pwm2";
cvi_pwm2.reg_base = CVI_PWM2_BASE;
result = rt_device_pwm_register(&cvi_pwm2.device, cvi_pwm2.name, &cvi_pwm_ops, &cvi_pwm2);
if (result != RT_EOK)
{
LOG_E("device %s register failed.", cvi_pwm2.name);
return result;
}
#endif
#ifdef BSP_USING_PWM3
static struct cvi_pwm_dev cvi_pwm3;
cvi_pwm3.name = "pwm3";
cvi_pwm3.reg_base = CVI_PWM3_BASE;
result = rt_device_pwm_register(&cvi_pwm3.device, cvi_pwm3.name, &cvi_pwm_ops, &cvi_pwm3);
if (result != RT_EOK)
{
LOG_E("device %s register failed.", cvi_pwm3.name);
return result;
}
#endif
return RT_EOK;
#endif
}
INIT_BOARD_EXPORT(rt_hw_pwm_init);
#endif /* BSP_USING_PWM */

19
bsp/cvitek/drivers/drv_pwm.h Executable file
View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024/02/19 flyingcys first version
*/
#ifndef __DRV_PWM_H__
#define __DRV_PWM_H__
#include "cvi_pwm.h"
#define PWM_MAX_CH 3
int rt_hw_pwm_init(void);
#endif /* __DRV_PWM_H__ */