mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-01 22:28:37 +08:00
Merge branch 'bugfix/pwm_support_fractional_phase' into 'master'
bugfix(pwm): support fractional phase See merge request sdk/ESP8266_RTOS_SDK!1424
This commit is contained in:
@ -51,7 +51,7 @@ typedef struct {
|
|||||||
uint32_t step_01duty; // 0.1 of the duty value
|
uint32_t step_01duty; // 0.1 of the duty value
|
||||||
uint32_t step_001duty; // 0.01 of the duty value
|
uint32_t step_001duty; // 0.01 of the duty value
|
||||||
uint32_t gpio_num;//gpio pins
|
uint32_t gpio_num;//gpio pins
|
||||||
int16_t phase; //init phase
|
float phase; //init phase
|
||||||
int fade_time; // Time to duty by fade
|
int fade_time; // Time to duty by fade
|
||||||
} ledc_obj_t;
|
} ledc_obj_t;
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ static void ledc_task(void* pvParameters)
|
|||||||
|
|
||||||
esp_err_t ledc_fade_func_install(int intr_alloc_flags)
|
esp_err_t ledc_fade_func_install(int intr_alloc_flags)
|
||||||
{
|
{
|
||||||
int16_t ledc_phase[LEDC_CHANNEL_MAX] = {0};
|
float ledc_phase[LEDC_CHANNEL_MAX] = {0};
|
||||||
uint32_t ledc_duty[LEDC_CHANNEL_MAX] = {0};
|
uint32_t ledc_duty[LEDC_CHANNEL_MAX] = {0};
|
||||||
uint32_t ledc_gpio_num[LEDC_CHANNEL_MAX] = {0};
|
uint32_t ledc_gpio_num[LEDC_CHANNEL_MAX] = {0};
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ static const char *TAG = "pwm";
|
|||||||
#define AHEAD_TICKS3 2
|
#define AHEAD_TICKS3 2
|
||||||
#define MAX_TICKS 10000000ul
|
#define MAX_TICKS 10000000ul
|
||||||
|
|
||||||
#define PWM_VERSION "PWM v3.2"
|
#define PWM_VERSION "PWM v3.4"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t duty; /*!< pwm duty for each channel */
|
uint32_t duty; /*!< pwm duty for each channel */
|
||||||
int16_t phase; /*!< pwm phase for each channel */
|
float phase; /*!< pwm phase for each channel */
|
||||||
uint8_t io_num; /*!< pwm io_num for each channel */
|
uint8_t io_num; /*!< pwm io_num for each channel */
|
||||||
} pwm_info_t;
|
} pwm_info_t;
|
||||||
|
|
||||||
@ -113,13 +113,13 @@ static void pwm_phase_init(void)
|
|||||||
|
|
||||||
for (i = 0; i < pwm_obj->channel_num; i++) {
|
for (i = 0; i < pwm_obj->channel_num; i++) {
|
||||||
if (-180 < pwm_obj->pwm_info[i].phase && pwm_obj->pwm_info[i].phase < 0) {
|
if (-180 < pwm_obj->pwm_info[i].phase && pwm_obj->pwm_info[i].phase < 0) {
|
||||||
time_delay = 0 - ((0 - pwm_obj->pwm_info[i].phase) * pwm_obj->depth / 360);
|
time_delay = (int32_t)(0 - ((0 - pwm_obj->pwm_info[i].phase) * pwm_obj->depth / 360.0));
|
||||||
} else if (pwm_obj->pwm_info[i].phase == 0) {
|
} else if (pwm_obj->pwm_info[i].phase == 0) {
|
||||||
continue;
|
continue;
|
||||||
} else if (180 > pwm_obj->pwm_info[i].phase && pwm_obj->pwm_info[i].phase > 0) {
|
} else if (180 >= pwm_obj->pwm_info[i].phase && pwm_obj->pwm_info[i].phase > 0) {
|
||||||
time_delay = pwm_obj->pwm_info[i].phase * pwm_obj->depth / 360;
|
time_delay = (int32_t)(pwm_obj->pwm_info[i].phase * pwm_obj->depth / 360.0);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "channel[%d] phase error %d, valid ramge from (-180,180)\n", i, pwm_obj->pwm_info[i].phase);
|
ESP_LOGE(TAG, "channel[%d] phase error %f, valid ramge from (-180,180]\n", i, pwm_obj->pwm_info[i].phase);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +224,7 @@ esp_err_t pwm_set_period_duties(uint32_t period, uint32_t *duties)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t pwm_set_phase(uint8_t channel_num, int16_t phase)
|
esp_err_t pwm_set_phase(uint8_t channel_num, float phase)
|
||||||
{
|
{
|
||||||
PWM_CHECK(channel_num < pwm_obj->channel_num, "Channel num error", ESP_ERR_INVALID_ARG);
|
PWM_CHECK(channel_num < pwm_obj->channel_num, "Channel num error", ESP_ERR_INVALID_ARG);
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ esp_err_t pwm_set_phase(uint8_t channel_num, int16_t phase)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t pwm_set_phases(int16_t *phases)
|
esp_err_t pwm_set_phases(float *phases)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
PWM_CHECK(NULL != phases, "Pointer is empty", ESP_ERR_INVALID_ARG);
|
PWM_CHECK(NULL != phases, "Pointer is empty", ESP_ERR_INVALID_ARG);
|
||||||
@ -246,7 +246,7 @@ esp_err_t pwm_set_phases(int16_t *phases)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t pwm_get_phase(uint8_t channel_num, uint16_t *phase_p)
|
esp_err_t pwm_get_phase(uint8_t channel_num, float *phase_p)
|
||||||
{
|
{
|
||||||
PWM_CHECK(channel_num < pwm_obj->channel_num, "Channel num error", ESP_ERR_INVALID_ARG);
|
PWM_CHECK(channel_num < pwm_obj->channel_num, "Channel num error", ESP_ERR_INVALID_ARG);
|
||||||
PWM_CHECK(NULL != phase_p, "Pointer is empty", ESP_ERR_INVALID_ARG);
|
PWM_CHECK(NULL != phase_p, "Pointer is empty", ESP_ERR_INVALID_ARG);
|
||||||
@ -259,9 +259,7 @@ esp_err_t pwm_get_phase(uint8_t channel_num, uint16_t *phase_p)
|
|||||||
static void pwm_timer_enable(uint8_t enable)
|
static void pwm_timer_enable(uint8_t enable)
|
||||||
{
|
{
|
||||||
if (0 == enable) {
|
if (0 == enable) {
|
||||||
ENTER_CRITICAL();
|
|
||||||
REG_WRITE(WDEVTSF0TIMER_ENA, REG_READ(WDEVTSF0TIMER_ENA) & (~WDEV_TSF0TIMER_ENA));
|
REG_WRITE(WDEVTSF0TIMER_ENA, REG_READ(WDEVTSF0TIMER_ENA) & (~WDEV_TSF0TIMER_ENA));
|
||||||
EXIT_CRITICAL();
|
|
||||||
} else {
|
} else {
|
||||||
REG_WRITE(WDEVTSF0TIMER_ENA, WDEV_TSF0TIMER_ENA);
|
REG_WRITE(WDEVTSF0TIMER_ENA, WDEV_TSF0TIMER_ENA);
|
||||||
}
|
}
|
||||||
@ -310,14 +308,20 @@ static void IRAM_ATTR pwm_timer_intr_handler(void)
|
|||||||
pwm_obj->this_target = AHEAD_TICKS1 + AHEAD_TICKS3;
|
pwm_obj->this_target = AHEAD_TICKS1 + AHEAD_TICKS3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REG_WRITE(WDEVSLEEP0_CONF, REG_READ(WDEVSLEEP0_CONF) & (~WDEV_TSFUP0_ENA));
|
||||||
|
REG_WRITE(WDEVTSF0TIMER_ENA, REG_READ(WDEVTSF0TIMER_ENA) & (~WDEV_TSF0TIMER_ENA));
|
||||||
REG_WRITE(WDEVTSFSW0_LO, 0);
|
REG_WRITE(WDEVTSFSW0_LO, 0);
|
||||||
//WARNING, pwm_obj->this_target - AHEAD_TICKS1 should be bigger than 2
|
//WARNING, pwm_obj->this_target - AHEAD_TICKS1 should be bigger than 2
|
||||||
REG_WRITE(WDEVTSF0_TIMER_LO, pwm_obj->this_target - AHEAD_TICKS1);
|
REG_WRITE(WDEVTSF0_TIMER_LO, pwm_obj->this_target - AHEAD_TICKS1);
|
||||||
REG_WRITE(WDEVTSF0TIMER_ENA, WDEV_TSF0TIMER_ENA);
|
REG_WRITE(WDEVTSF0TIMER_ENA, WDEV_TSF0TIMER_ENA);
|
||||||
|
REG_WRITE(WDEVSLEEP0_CONF, REG_READ(WDEVSLEEP0_CONF) | WDEV_TSFUP0_ENA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwm_timer_start(uint32_t period)
|
static void pwm_timer_start(uint32_t period)
|
||||||
{
|
{
|
||||||
|
ENTER_CRITICAL();
|
||||||
|
REG_WRITE(WDEVSLEEP0_CONF, REG_READ(WDEVSLEEP0_CONF) & (~WDEV_TSFUP0_ENA));
|
||||||
|
REG_WRITE(WDEVTSF0TIMER_ENA, REG_READ(WDEVTSF0TIMER_ENA) & (~WDEV_TSF0TIMER_ENA));
|
||||||
// suspend all task to void timer interrupt missed
|
// suspend all task to void timer interrupt missed
|
||||||
// TODO, do we need lock interrupt here, I think interrupt context will not take 1ms long
|
// TODO, do we need lock interrupt here, I think interrupt context will not take 1ms long
|
||||||
// time low field to 0
|
// time low field to 0
|
||||||
@ -334,8 +338,11 @@ static void pwm_timer_start(uint32_t period)
|
|||||||
pwm_obj->this_target = US_TO_TICKS(period);
|
pwm_obj->this_target = US_TO_TICKS(period);
|
||||||
// WARNING: pwm_obj->this_target should bigger than AHEAD_TICKS1
|
// WARNING: pwm_obj->this_target should bigger than AHEAD_TICKS1
|
||||||
REG_WRITE(WDEVTSF0_TIMER_LO, pwm_obj->this_target - AHEAD_TICKS1);
|
REG_WRITE(WDEVTSF0_TIMER_LO, pwm_obj->this_target - AHEAD_TICKS1);
|
||||||
// enable timer
|
REG_WRITE(WDEVTSF0TIMER_ENA, WDEV_TSF0TIMER_ENA);
|
||||||
|
REG_WRITE(WDEVSLEEP0_CONF, REG_READ(WDEVSLEEP0_CONF) | WDEV_TSFUP0_ENA);
|
||||||
|
//enable timer
|
||||||
pwm_timer_enable(1);
|
pwm_timer_enable(1);
|
||||||
|
EXIT_CRITICAL();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pwm_timer_register(void (*handle)(void))
|
static void pwm_timer_register(void (*handle)(void))
|
||||||
@ -573,7 +580,9 @@ esp_err_t pwm_stop(uint32_t stop_level_mask)
|
|||||||
{
|
{
|
||||||
int16_t i = 0;
|
int16_t i = 0;
|
||||||
|
|
||||||
|
ENTER_CRITICAL();
|
||||||
pwm_timer_enable(0);
|
pwm_timer_enable(0);
|
||||||
|
EXIT_CRITICAL();
|
||||||
uint32_t level_set = REG_READ(PERIPHS_GPIO_BASEADDR + GPIO_OUT_ADDRESS);
|
uint32_t level_set = REG_READ(PERIPHS_GPIO_BASEADDR + GPIO_OUT_ADDRESS);
|
||||||
|
|
||||||
for (i = 0; i < pwm_obj->channel_num; i++) {
|
for (i = 0; i < pwm_obj->channel_num; i++) {
|
||||||
|
@ -145,13 +145,13 @@ esp_err_t pwm_set_duties(uint32_t *duties);
|
|||||||
*
|
*
|
||||||
* @param channel_num PWM channel number
|
* @param channel_num PWM channel number
|
||||||
* the channel_num cannot exceed the value initialized by pwm_init.
|
* the channel_num cannot exceed the value initialized by pwm_init.
|
||||||
* @param phase The phase of this PWM channel, the phase range is (-180 ~ 180).
|
* @param phase The phase of this PWM channel, the phase range is (-180 ~ 180].
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_ERR_INVALID_ARG Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t pwm_set_phase(uint8_t channel_num, int16_t phase);
|
esp_err_t pwm_set_phase(uint8_t channel_num, float phase);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the phase of all channels.
|
* @brief Set the phase of all channels.
|
||||||
@ -164,7 +164,7 @@ esp_err_t pwm_set_phase(uint8_t channel_num, int16_t phase);
|
|||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_ERR_INVALID_ARG Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t pwm_set_phases(int16_t *phases);
|
esp_err_t pwm_set_phases(float *phases);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the phase of a PWM channel.
|
* @brief Get the phase of a PWM channel.
|
||||||
@ -177,7 +177,7 @@ esp_err_t pwm_set_phases(int16_t *phases);
|
|||||||
* - ESP_OK Success
|
* - ESP_OK Success
|
||||||
* - ESP_ERR_INVALID_ARG Parameter error
|
* - ESP_ERR_INVALID_ARG Parameter error
|
||||||
*/
|
*/
|
||||||
esp_err_t pwm_get_phase(uint8_t channel_num, uint16_t *phase_p);
|
esp_err_t pwm_get_phase(uint8_t channel_num, float *phase_p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set PWM period and duty of each PWM channel.
|
* @brief Set PWM period and duty of each PWM channel.
|
||||||
|
@ -148,12 +148,14 @@
|
|||||||
|
|
||||||
#define WDEVTSF0_TIME_LO 0x3ff21004
|
#define WDEVTSF0_TIME_LO 0x3ff21004
|
||||||
#define WDEVTSF0_TIME_HI 0x3ff21008
|
#define WDEVTSF0_TIME_HI 0x3ff21008
|
||||||
|
#define WDEVSLEEP0_CONF 0x3ff21014
|
||||||
#define WDEVTSFSW0_LO 0x3ff21018
|
#define WDEVTSFSW0_LO 0x3ff21018
|
||||||
#define WDEVTSFSW0_HI 0x3ff2101C
|
#define WDEVTSFSW0_HI 0x3ff2101C
|
||||||
#define WDEVTSF0_TIMER_LO 0x3ff2109c
|
#define WDEVTSF0_TIMER_LO 0x3ff2109c
|
||||||
#define WDEVTSF0_TIMER_HI 0x3ff210a0
|
#define WDEVTSF0_TIMER_HI 0x3ff210a0
|
||||||
#define WDEVTSF0TIMER_ENA 0x3ff21098
|
#define WDEVTSF0TIMER_ENA 0x3ff21098
|
||||||
#define WDEV_TSF0TIMER_ENA BIT(31)
|
#define WDEV_TSF0TIMER_ENA BIT(31)
|
||||||
|
#define WDEV_TSFUP0_ENA BIT(31)
|
||||||
|
|
||||||
//Watch dog reg {{
|
//Watch dog reg {{
|
||||||
#define PERIPHS_WDT_BASEADDR 0x60000900
|
#define PERIPHS_WDT_BASEADDR 0x60000900
|
||||||
|
@ -49,14 +49,13 @@ uint32_t duties[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// phase table, delay = (phase[x]/360)*PERIOD
|
// phase table, delay = (phase[x]/360)*PERIOD
|
||||||
int16_t phase[4] = {
|
float phase[4] = {
|
||||||
0, 0, 90, -90,
|
0, 0, 90.0, -90.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
void app_main()
|
void app_main()
|
||||||
{
|
{
|
||||||
pwm_init(PWM_PERIOD, duties, 4, pin_num);
|
pwm_init(PWM_PERIOD, duties, 4, pin_num);
|
||||||
pwm_set_channel_invert(0x1 << 0);
|
|
||||||
pwm_set_phases(phase);
|
pwm_set_phases(phase);
|
||||||
pwm_start();
|
pwm_start();
|
||||||
int16_t count = 0;
|
int16_t count = 0;
|
||||||
|
Reference in New Issue
Block a user