riscv/esp32c3: Add ESP32-C3 LEDC(PWM) driver
This commit is contained in:
parent
b5ee9b673c
commit
beed26b6bf
@ -178,6 +178,11 @@ config ESP32C3_SPI
|
||||
bool
|
||||
default n
|
||||
|
||||
config ESP32C3_LEDC
|
||||
bool "LEDC (PWM)"
|
||||
default n
|
||||
select PWM
|
||||
|
||||
config ESP32C3_GPIO_IRQ
|
||||
bool "GPIO pin interrupts"
|
||||
default n
|
||||
@ -418,6 +423,71 @@ config ESP32C3_FREERUN
|
||||
endmenu # Timer/counter Configuration
|
||||
endif # ESP32C3_TIMER
|
||||
|
||||
menu "LEDC configuration"
|
||||
depends on ESP32C3_LEDC
|
||||
|
||||
menuconfig ESP32C3_LEDC_TIM0
|
||||
bool "Timer 0"
|
||||
default n
|
||||
|
||||
if ESP32C3_LEDC_TIM0
|
||||
|
||||
config ESP32C3_LEDC_TIM0_CHANNELS
|
||||
int "Number of Timer 0 channels"
|
||||
default 2
|
||||
|
||||
endif # ESP32C3_LEDC_TIM0
|
||||
|
||||
menuconfig ESP32C3_LEDC_TIM1
|
||||
bool "Timer 1"
|
||||
default n
|
||||
|
||||
if ESP32C3_LEDC_TIM1
|
||||
|
||||
config ESP32C3_LEDC_TIM1_CHANNELS
|
||||
int "Number of Timer 1 channels"
|
||||
default 2
|
||||
|
||||
endif # ESP32C3_LEDC_TIM1
|
||||
|
||||
menuconfig ESP32C3_LEDC_TIM2
|
||||
bool "Timer 2"
|
||||
default n
|
||||
|
||||
if ESP32C3_LEDC_TIM2
|
||||
|
||||
config ESP32C3_LEDC_TIM2_CHANNELS
|
||||
int "Number of Timer 2 channels"
|
||||
default 2
|
||||
|
||||
endif # ESP32C3_LEDC_TIM2
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL0_PIN
|
||||
int "Channel 0 pin"
|
||||
default 2
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL1_PIN
|
||||
int "Channel 1 pin"
|
||||
default 3
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL2_PIN
|
||||
int "Channel 2 pin"
|
||||
default 4
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL3_PIN
|
||||
int "Channel 3 pin"
|
||||
default 5
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL4_PIN
|
||||
int "Channel 4 pin"
|
||||
default 6
|
||||
|
||||
config ESP32C3_LEDC_CHANNEL5_PIN
|
||||
int "Channel 5 pin"
|
||||
default 7
|
||||
|
||||
endmenu # LEDC configuration
|
||||
|
||||
menu "Wi-Fi configuration"
|
||||
depends on ESP32C3_WIRELESS
|
||||
|
||||
|
@ -121,6 +121,10 @@ endif
|
||||
|
||||
CHIP_CSRCS += esp32c3_rtc.c
|
||||
|
||||
ifeq ($(CONFIG_ESP32C3_LEDC),y)
|
||||
CHIP_CSRCS += esp32c3_ledc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ESP32C3_WIRELESS),y)
|
||||
WIRELESS_DRV_UNPACK = esp-wireless-drivers-3rdparty
|
||||
WIRELESS_DRV_ID = 2b53111
|
||||
|
776
arch/risc-v/src/esp32c3/esp32c3_ledc.c
Normal file
776
arch/risc-v/src/esp32c3/esp32c3_ledc.c
Normal file
@ -0,0 +1,776 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/esp32c3/esp32c3_ledc.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "esp32c3.h"
|
||||
#include "esp32c3_clockconfig.h"
|
||||
#include "esp32c3_gpio.h"
|
||||
#include "esp32c3_ledc.h"
|
||||
|
||||
#include "riscv_arch.h"
|
||||
#include "hardware/esp32c3_ledc.h"
|
||||
#include "hardware/esp32c3_system.h"
|
||||
#include "hardware/esp32c3_gpio_sigmap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* LEDC total timers */
|
||||
|
||||
#define LEDC_TIMERS (3)
|
||||
|
||||
/* LEDC total channels */
|
||||
|
||||
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
|
||||
# define LEDC_CHANNELS (6)
|
||||
#else
|
||||
# define LEDC_CHANNELS (3)
|
||||
#endif
|
||||
|
||||
/* LEDC timer0 channels and offset */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM0
|
||||
# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
|
||||
# define LEDC_TIM0_CHANS CONFIG_ESP32C3_LEDC_TIM0_CHANNELS
|
||||
# else
|
||||
# define LEDC_TIM0_CHANS (1)
|
||||
# endif
|
||||
# define LEDC_TIM0_CHANS_OFF (0)
|
||||
#endif
|
||||
|
||||
/* LEDC timer1 channels and offset */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM1
|
||||
# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
|
||||
# define LEDC_TIM1_CHANS CONFIG_ESP32C3_LEDC_TIM1_CHANNELS
|
||||
# else
|
||||
# define LEDC_TIM1_CHANS (1)
|
||||
# endif
|
||||
# define LEDC_TIM1_CHANS_OFF (LEDC_TIM0_CHANS_OFF + LEDC_TIM0_CHANS)
|
||||
#endif
|
||||
|
||||
/* LEDC timer2 channels and offset */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM2
|
||||
# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
|
||||
# define LEDC_TIM2_CHANS CONFIG_ESP32C3_LEDC_TIM2_CHANNELS
|
||||
# else
|
||||
# define LEDC_TIM2_CHANS (1)
|
||||
# endif
|
||||
|
||||
# define LEDC_TIM2_CHANS_OFF (LEDC_TIM1_CHANS_OFF + LEDC_TIM1_CHANS)
|
||||
#endif
|
||||
|
||||
/* LEDC clock resource */
|
||||
|
||||
#define LEDC_CLK_RES (1) /* APB clock */
|
||||
|
||||
/* LEDC timer max reload */
|
||||
|
||||
#define LEDC_RELOAD_MAX (16384) /* 2^14 */
|
||||
|
||||
/* LEDC timer max clock divider parameter */
|
||||
|
||||
#define LEDC_CLKDIV_MAX (1024) /* 2^10 */
|
||||
|
||||
/* LEDC timer registers mapping */
|
||||
|
||||
#define LEDC_TIMER_REG(r, n) ((r) + (n) * (LEDC_TIMER1_CONF_REG - \
|
||||
LEDC_TIMER2_CONF_REG))
|
||||
|
||||
/* LEDC timer channel registers mapping */
|
||||
|
||||
#define LEDC_CHAN_REG(r, n) ((r) + (n) * (LEDC_CH0_CONF0_REG - \
|
||||
LEDC_CH1_CONF0_REG))
|
||||
|
||||
#define SET_TIMER_BITS(t, r, b) setbits(b, LEDC_TIMER_REG(r, (t)->num));
|
||||
#define SET_TIMER_REG(t, r, v) putreg32(v, LEDC_TIMER_REG(r, (t)->num));
|
||||
|
||||
#define SET_CHAN_BITS(c, r, b) setbits(b, LEDC_CHAN_REG(r, (c)->num));
|
||||
#define SET_CHAN_REG(c, r, v) putreg32(v, LEDC_CHAN_REG(r, (c)->num));
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* LEDC timer channel configuration */
|
||||
|
||||
struct esp32c3_ledc_chan_s
|
||||
{
|
||||
const uint8_t num; /* Timer channel ID */
|
||||
const uint8_t pin; /* Timer channel GPIO pin number */
|
||||
|
||||
uint16_t duty; /* Timer channel current duty */
|
||||
};
|
||||
|
||||
/* This structure represents the state of one LEDC timer */
|
||||
|
||||
struct esp32c3_ledc_s
|
||||
{
|
||||
const struct pwm_ops_s *ops; /* PWM operations */
|
||||
|
||||
const uint8_t num; /* Timer ID */
|
||||
|
||||
const uint8_t channels; /* Timer channels number */
|
||||
struct esp32c3_ledc_chan_s *chans; /* Timer channels pointer */
|
||||
|
||||
uint32_t frequency; /* Timer current frequency */
|
||||
uint32_t reload; /* Timer current reload */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_setup(struct pwm_lowerhalf_s *dev);
|
||||
static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
|
||||
static int pwm_start(struct pwm_lowerhalf_s *dev,
|
||||
const struct pwm_info_s *info);
|
||||
static int pwm_stop(struct pwm_lowerhalf_s *dev);
|
||||
static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* LEDC PWM operations */
|
||||
|
||||
static const struct pwm_ops_s g_pwmops =
|
||||
{
|
||||
.setup = pwm_setup,
|
||||
.shutdown = pwm_shutdown,
|
||||
.start = pwm_start,
|
||||
.stop = pwm_stop,
|
||||
.ioctl = pwm_ioctl
|
||||
};
|
||||
|
||||
/* LEDC channels table */
|
||||
|
||||
static struct esp32c3_ledc_chan_s g_ledc_chans[LEDC_CHANNELS] =
|
||||
{
|
||||
{
|
||||
.num = 0,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL0_PIN
|
||||
},
|
||||
|
||||
{
|
||||
.num = 1,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL1_PIN
|
||||
},
|
||||
|
||||
{
|
||||
.num = 2,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL2_PIN
|
||||
},
|
||||
|
||||
#if LEDC_CHANNELS > 3
|
||||
{
|
||||
.num = 3,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL3_PIN
|
||||
},
|
||||
|
||||
{
|
||||
.num = 4,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL4_PIN
|
||||
},
|
||||
|
||||
{
|
||||
.num = 5,
|
||||
.pin = CONFIG_ESP32C3_LEDC_CHANNEL5_PIN
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/* LEDC timer0 private data */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM0
|
||||
static struct esp32c3_ledc_s g_pwm0dev =
|
||||
{
|
||||
.ops = &g_pwmops,
|
||||
.num = 0,
|
||||
.channels = LEDC_TIM0_CHANS,
|
||||
.chans = &g_ledc_chans[LEDC_TIM0_CHANS_OFF]
|
||||
};
|
||||
#endif /* CONFIG_ESP32C3_LEDC_TIM0 */
|
||||
|
||||
/* LEDC timer1 private data */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM1
|
||||
static struct esp32c3_ledc_s g_pwm1dev =
|
||||
{
|
||||
.ops = &g_pwmops,
|
||||
.num = 1,
|
||||
.channels = LEDC_TIM1_CHANS,
|
||||
.chans = &g_ledc_chans[LEDC_TIM1_CHANS_OFF]
|
||||
};
|
||||
#endif /* CONFIG_ESP32C3_LEDC_TIM1 */
|
||||
|
||||
/* LEDC timer2 private data */
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM2
|
||||
static struct esp32c3_ledc_s g_pwm2dev =
|
||||
{
|
||||
.ops = &g_pwmops,
|
||||
.num = 2,
|
||||
.channels = LEDC_TIM2_CHANS,
|
||||
.chans = &g_ledc_chans[LEDC_TIM2_CHANS_OFF]
|
||||
};
|
||||
#endif /* CONFIG_ESP32C3_LEDC_TIM2 */
|
||||
|
||||
/* Clock reference count */
|
||||
|
||||
static uint32_t g_clk_ref;
|
||||
|
||||
/****************************************************************************
|
||||
* Private functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ledc_enable_clk
|
||||
*
|
||||
* Description:
|
||||
* Enable LEDC clock.
|
||||
*
|
||||
* Input Parameters:
|
||||
* NOne
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ledc_enable_clk(void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (!g_clk_ref)
|
||||
{
|
||||
setbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
|
||||
resetbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
|
||||
|
||||
putreg32(LEDC_CLK_RES, LEDC_CONF_REG);
|
||||
|
||||
pwminfo("Enable ledc clock\n");
|
||||
}
|
||||
|
||||
g_clk_ref++;
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ledc_disable_clk
|
||||
*
|
||||
* Description:
|
||||
* Disable LEDC clock.
|
||||
*
|
||||
* Input Parameters:
|
||||
* NOne
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ledc_disable_clk(void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
g_clk_ref--;
|
||||
|
||||
if (!g_clk_ref)
|
||||
{
|
||||
pwminfo("Disable ledc clock\n");
|
||||
|
||||
setbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
|
||||
resetbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: setup_timer
|
||||
*
|
||||
* Description:
|
||||
* Setup LEDC timer frequency and reload.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the LEDC timer state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void setup_timer(struct esp32c3_ledc_s *priv)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
uint32_t reload;
|
||||
uint32_t prescaler;
|
||||
uint32_t shift = 1;
|
||||
uint64_t pwmclk = esp32c3_clk_apb_freq();
|
||||
|
||||
/* Reset timer */
|
||||
|
||||
SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
|
||||
|
||||
/* Calculate optimal values for the timer prescaler and for the timer
|
||||
* modulo register. If' frequency' is the desired frequency, then
|
||||
*
|
||||
* tpmclk = pwmclk / presc
|
||||
* frequency = tpmclk / reload
|
||||
*
|
||||
* ==>
|
||||
*
|
||||
* reload = pwmclk / presc / frequency
|
||||
*
|
||||
* In ESP32-C3, there are 4 clock resources for PWM:
|
||||
*
|
||||
* 1. APB clock (80 MHz)
|
||||
* 2. RTC clock (8 MHz)
|
||||
* 3. XTAL clock (depends on hardware, generally is 40 MHz)
|
||||
* 4. REF clock (this is APB clock divided, generally is 1 MHz)
|
||||
*
|
||||
* We mostly use APB clock generally.
|
||||
*
|
||||
* There are many solutions to this, but the best solution will be the one
|
||||
* that has the largest reload value and the smallest prescaler value.
|
||||
* That is the solution that should give us the most accuracy in the timer
|
||||
* control. Subject to:
|
||||
*
|
||||
* 2 <= presc <= 2^14(16,384)
|
||||
* 1 <= clkdiv <= 2^10
|
||||
*
|
||||
* clkdiv has 8-bit decimal precision, so
|
||||
* clkdiv = pwmclk * 256 / 16384 / frequency would be optimal.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* pwmclk = 80 MHz
|
||||
* frequency = 100 Hz
|
||||
*
|
||||
* presc = 80,000,000 * 256 / 16,384 / 100
|
||||
* = 12,500
|
||||
* timclk = 80,000,000 / (12,500 / 256)
|
||||
* = 1,638,400
|
||||
* counter = 1,638,400 / 100
|
||||
* = 16,384
|
||||
* = 2^14
|
||||
* shift = 14
|
||||
*/
|
||||
|
||||
reload = (pwmclk * 256 / priv->frequency + LEDC_CLKDIV_MAX) /
|
||||
LEDC_CLKDIV_MAX;
|
||||
if (reload == 0)
|
||||
{
|
||||
reload = 1;
|
||||
}
|
||||
else if (reload > LEDC_RELOAD_MAX)
|
||||
{
|
||||
reload = LEDC_RELOAD_MAX;
|
||||
}
|
||||
|
||||
for (int c = 2; c <= LEDC_RELOAD_MAX; c *= 2)
|
||||
{
|
||||
if (c * 2 > reload)
|
||||
{
|
||||
reload = c;
|
||||
break;
|
||||
}
|
||||
|
||||
shift++;
|
||||
}
|
||||
|
||||
prescaler = pwmclk * 256 / reload / priv->frequency;
|
||||
|
||||
pwminfo("PWM timer%" PRIu8 " frequency=%0.4f reload=%" PRIu32 " shift=%" \
|
||||
PRIu32 " prescaler=%0.4f\n",
|
||||
priv->num, (float)pwmclk / reload / ((float)prescaler / 256),
|
||||
reload, shift, (float)prescaler / 256);
|
||||
|
||||
/* Store reload for channel duty */
|
||||
|
||||
priv->reload = reload;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Set timer clock divide and reload */
|
||||
|
||||
regval = (shift << LEDC_TIMER0_DUTY_RES_S) |
|
||||
(prescaler << LEDC_CLK_DIV_TIMER0_S);
|
||||
SET_TIMER_REG(priv, LEDC_TIMER0_CONF_REG, regval);
|
||||
|
||||
/* Update clock divide and reload to hardware */
|
||||
|
||||
SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PARA_UP);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: setup_channel
|
||||
*
|
||||
* Description:
|
||||
* Setup LEDC timer channel duty.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the LEDC timer state structure
|
||||
* cn - Timer channel number
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void setup_channel(struct esp32c3_ledc_s *priv, int cn)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
struct esp32c3_ledc_chan_s *chan = &priv->chans[cn];
|
||||
|
||||
/* Duty cycle:
|
||||
*
|
||||
* duty cycle = duty / 65536 * reload (fractional value)
|
||||
*/
|
||||
|
||||
regval = b16toi(chan->duty * priv->reload + b16HALF);
|
||||
|
||||
pwminfo("channel=%" PRIu8 " duty=%" PRIu16 "(%0.4f) regval=%" PRIu32 \
|
||||
" reload=%" PRIu32 "\n",
|
||||
chan->num, chan->duty, (float)chan->duty / UINT16_MAX,
|
||||
regval, priv->reload);
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Reset config 0 & 1 registers */
|
||||
|
||||
SET_CHAN_REG(chan, LEDC_CH0_CONF0_REG, 0);
|
||||
SET_CHAN_REG(chan, LEDC_CH0_CONF1_REG, 0);
|
||||
|
||||
/* Set pulse phase 0 */
|
||||
|
||||
SET_CHAN_REG(chan, LEDC_CH0_HPOINT_REG, 0);
|
||||
|
||||
/* Duty register uses bits [18:4] */
|
||||
|
||||
SET_CHAN_REG(chan, LEDC_CH0_DUTY_REG, regval << 4);
|
||||
|
||||
/* Start GPIO output */
|
||||
|
||||
SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_SIG_OUT_EN_CH0);
|
||||
|
||||
/* Start Duty counter */
|
||||
|
||||
SET_CHAN_BITS(chan, LEDC_CH0_CONF1_REG, LEDC_DUTY_START_CH0);
|
||||
|
||||
/* Update duty and phase to hardware */
|
||||
|
||||
SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_PARA_UP_CH0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_setup
|
||||
*
|
||||
* Description:
|
||||
* This method is called when the driver is opened. The lower half driver
|
||||
* should configure and initialize the device so that it is ready for use.
|
||||
* It should not, however, output pulses until the start method is called.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A reference to the lower half PWM driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_setup(struct pwm_lowerhalf_s *dev)
|
||||
{
|
||||
struct esp32c3_ledc_s *priv = (struct esp32c3_ledc_s *)dev;
|
||||
|
||||
pwminfo("PWM timer%d\n", priv->num);
|
||||
|
||||
ledc_enable_clk();
|
||||
|
||||
/* Setup channel GPIO pins */
|
||||
|
||||
for (int i = 0; i < priv->channels; i++)
|
||||
{
|
||||
pwminfo("channel%d --> pin%d\n", priv->chans[i].num,
|
||||
priv->chans[i].pin);
|
||||
|
||||
esp32c3_configgpio(priv->chans[i].pin, OUTPUT | PULLUP);
|
||||
esp32c3_gpio_matrix_out(priv->chans[i].pin,
|
||||
LEDC_LS_SIG_OUT0_IDX + priv->chans[i].num,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_shutdown
|
||||
*
|
||||
* Description:
|
||||
* This method is called when the driver is closed. The lower half driver
|
||||
* stop pulsed output, free any resources, disable the timer hardware, and
|
||||
* put the system into the lowest possible power usage state
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A reference to the lower half PWM driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_shutdown(struct pwm_lowerhalf_s *dev)
|
||||
{
|
||||
struct esp32c3_ledc_s *priv = (struct esp32c3_ledc_s *)dev;
|
||||
#ifdef CONFIG_PWM_NCHANNELS
|
||||
int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
|
||||
#else
|
||||
int channels = 1;
|
||||
#endif
|
||||
|
||||
/* Stop timer */
|
||||
|
||||
pwm_stop(dev);
|
||||
|
||||
/* Clear timer and channel configuration */
|
||||
|
||||
priv->frequency = 0;
|
||||
priv->reload = 0;
|
||||
for (int i = 0; i < channels; i++)
|
||||
{
|
||||
priv->chans[i].duty = 0;
|
||||
}
|
||||
|
||||
ledc_disable_clk();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_start
|
||||
*
|
||||
* Description:
|
||||
* (Re-)initialize the timer resources and start the pulsed output
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A reference to the lower half PWM driver state structure
|
||||
* info - A reference to the characteristics of the pulsed output
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_start(struct pwm_lowerhalf_s *dev,
|
||||
const struct pwm_info_s *info)
|
||||
{
|
||||
struct esp32c3_ledc_s *priv = (struct esp32c3_ledc_s *)dev;
|
||||
#ifdef CONFIG_PWM_NCHANNELS
|
||||
int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
|
||||
#else
|
||||
int channels = 1;
|
||||
#endif
|
||||
|
||||
pwminfo("PWM timer%d\n", priv->num);
|
||||
|
||||
/* Update timer with given PWM timer frequency */
|
||||
|
||||
if (priv->frequency != info->frequency)
|
||||
{
|
||||
priv->frequency = info->frequency;
|
||||
setup_timer(priv);
|
||||
}
|
||||
|
||||
/* Update timer with given PWM channel duty */
|
||||
|
||||
for (int i = 0; i < channels; i++)
|
||||
{
|
||||
if (priv->chans[i].duty != info[i].duty)
|
||||
{
|
||||
priv->chans[i].duty = info[i].duty;
|
||||
setup_channel(priv, i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_stop
|
||||
*
|
||||
* Description:
|
||||
* Stop the pulsed output and reset the timer resources.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A reference to the lower half PWM driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_stop(struct pwm_lowerhalf_s *dev)
|
||||
{
|
||||
irqstate_t flags;
|
||||
struct esp32c3_ledc_s *priv = (struct esp32c3_ledc_s *)dev;
|
||||
|
||||
pwminfo("PWM timer%d\n", priv->num);
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Stop timer */
|
||||
|
||||
SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PAUSE);
|
||||
|
||||
/* Reset timer */
|
||||
|
||||
SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
|
||||
|
||||
leave_critical_section(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pwm_ioctl
|
||||
*
|
||||
* Description:
|
||||
* Lower-half logic may support platform-specific ioctl commands
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A reference to the lower half PWM driver state structure
|
||||
* cmd - The ioctl command
|
||||
* arg - The argument accompanying the ioctl command
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_PWM_INFO
|
||||
struct esp32c3_ledc_s *priv = (struct esp32c3_ledc_s *)dev;
|
||||
|
||||
pwminfo("PWM timer%d\n", priv->num);
|
||||
#endif
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32c3_ledc_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize one LEDC timer for use with the upper_level PWM driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* timer - A number identifying the timer use.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a pointer to the ESP32-C3 LEDC lower half PWM driver is
|
||||
* returned. NULL is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct pwm_lowerhalf_s *esp32c3_ledc_init(int timer)
|
||||
{
|
||||
struct esp32c3_ledc_s *lower = NULL;
|
||||
|
||||
pwminfo("TIM%u\n", timer);
|
||||
|
||||
switch (timer)
|
||||
{
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM0
|
||||
case 0:
|
||||
{
|
||||
lower = &g_pwm0dev;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM1
|
||||
case 1:
|
||||
{
|
||||
lower = &g_pwm1dev;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM2
|
||||
case 2:
|
||||
{
|
||||
lower = &g_pwm2dev;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM3
|
||||
case 3:
|
||||
{
|
||||
lower = &g_pwm3dev;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
pwmerr("ERROR: No such timer configured %d\n", timer);
|
||||
lower = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (struct pwm_lowerhalf_s *)lower;
|
||||
}
|
52
arch/risc-v/src/esp32c3/esp32c3_ledc.h
Normal file
52
arch/risc-v/src/esp32c3/esp32c3_ledc.h
Normal file
@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/esp32c3/esp32c3_ledc.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_RISCV_SRC_ESP32C3_ESP32C3_LEDC_H
|
||||
#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_LEDC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/timers/pwm.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32c3_ledc_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize one LEDC timer for use with the upper_level PWM driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* timer - A number identifying the timer use.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a pointer to the ESP32-C3 LEDC lower half PWM driver is
|
||||
* returned. NULL is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct pwm_lowerhalf_s *esp32c3_ledc_init(int timer);
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_LEDC_H */
|
2742
arch/risc-v/src/esp32c3/hardware/esp32c3_ledc.h
Normal file
2742
arch/risc-v/src/esp32c3/hardware/esp32c3_ledc.h
Normal file
File diff suppressed because it is too large
Load Diff
47
boards/risc-v/esp32c3/esp32c3-devkit/configs/pwm/defconfig
Normal file
47
boards/risc-v/esp32c3/esp32c3-devkit/configs/pwm/defconfig
Normal file
@ -0,0 +1,47 @@
|
||||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_NSH_ARGCAT is not set
|
||||
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
|
||||
# CONFIG_NSH_CMDPARMS is not set
|
||||
CONFIG_ARCH="risc-v"
|
||||
CONFIG_ARCH_BOARD="esp32c3-devkit"
|
||||
CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
|
||||
CONFIG_ARCH_CHIP="esp32c3"
|
||||
CONFIG_ARCH_CHIP_ESP32C3=y
|
||||
CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=1536
|
||||
CONFIG_ARCH_RISCV=y
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=15000
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEV_ZERO=y
|
||||
CONFIG_ESP32C3_LEDC=y
|
||||
CONFIG_ESP32C3_LEDC_TIM0=y
|
||||
CONFIG_EXAMPLES_PWM=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=2048
|
||||
CONFIG_INTELHEX_BINARY=y
|
||||
CONFIG_LIBC_PERROR_STDOUT=y
|
||||
CONFIG_LIBC_STRERROR=y
|
||||
CONFIG_MAX_TASKS=8
|
||||
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
|
||||
CONFIG_NSH_ARCHINIT=y
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=512
|
||||
CONFIG_NSH_READLINE=y
|
||||
CONFIG_NSH_STRERROR=y
|
||||
CONFIG_PREALLOC_TIMERS=0
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_START_DAY=29
|
||||
CONFIG_START_MONTH=11
|
||||
CONFIG_START_YEAR=2019
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_UART0_SERIAL_CONSOLE=y
|
||||
CONFIG_USER_ENTRYPOINT="nsh_main"
|
@ -66,6 +66,10 @@ ifeq ($(CONFIG_ONESHOT),y)
|
||||
CSRCS += esp32c3_oneshot.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PWM),y)
|
||||
CSRCS += esp32c3_ledc.c
|
||||
endif
|
||||
|
||||
SCRIPTIN = $(SCRIPTDIR)$(DELIM)esp32c3.template.ld
|
||||
SCRIPTOUT = $(SCRIPTDIR)$(DELIM)esp32c3_out.ld
|
||||
|
||||
|
@ -181,5 +181,17 @@ int board_bmp180_initialize(int devno, int busno);
|
||||
int esp32c3_spiflash_init(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32c3_ledc_setup
|
||||
*
|
||||
* Description:
|
||||
* Initialize LEDC PWM and register the PWM device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC
|
||||
int esp32c3_pwm_setup(void);
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __BOARDS_RISCV_ESP32C3_ESP32C3_DEVKIT_SRC_ESP32C3_DEVKIT_H */
|
||||
|
@ -283,6 +283,14 @@ int esp32c3_bringup(void)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC
|
||||
ret = esp32c3_pwm_setup();
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: esp32c3_pwm_setup() failed: %d\n", ret);
|
||||
}
|
||||
#endif /* CONFIG_ESP32C3_LEDC */
|
||||
|
||||
/* If we got here then perhaps not all initialization was successful, but
|
||||
* at least enough succeeded to bring-up NSH with perhaps reduced
|
||||
* capabilities.
|
||||
|
116
boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_ledc.c
Normal file
116
boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_ledc.c
Normal file
@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
* boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_ledc.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/board.h>
|
||||
#include <nuttx/timers/pwm.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "esp32c3_ledc.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32c3_pwm_setup
|
||||
*
|
||||
* Description:
|
||||
* Initialize LEDC PWM and register the PWM device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32c3_pwm_setup(void)
|
||||
{
|
||||
int ret;
|
||||
struct pwm_lowerhalf_s *pwm;
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM0
|
||||
pwm = esp32c3_ledc_init(0);
|
||||
if (!pwm)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 0 lower half\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Register the PWM driver at "/dev/pwm0" */
|
||||
|
||||
ret = pwm_register("/dev/pwm0", pwm);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM1
|
||||
pwm = esp32c3_ledc_init(1);
|
||||
if (!pwm)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 1 lower half\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Register the PWM driver at "/dev/pwm1" */
|
||||
|
||||
ret = pwm_register("/dev/pwm1", pwm);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP32C3_LEDC_TIM2
|
||||
pwm = esp32c3_ledc_init(2);
|
||||
if (!pwm)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 2 lower half\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Register the PWM driver at "/dev/pwm2" */
|
||||
|
||||
ret = pwm_register("/dev/pwm2", pwm);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: pwm_register failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user