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:
Dong Heng
2020-09-22 11:07:55 +08:00
5 changed files with 31 additions and 21 deletions

View File

@ -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};

View File

@ -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++) {

View File

@ -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.

View File

@ -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

View File

@ -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;