Issue with MCPWM Prescaler

jmcornil
Posts: 9
Joined: Mon Feb 10, 2020 1:42 pm

Issue with MCPWM Prescaler

Postby jmcornil » Mon Feb 10, 2020 5:44 pm

Hello everybody and thank you for reading my post.

I am beginning to play with MCPWM and I would change on the fly some values such as the prescaler which are in MCPWM_CLK_CFG_REG and in MCPWM_TIMER0_CFG0_REG. For the moment I have no oscillo and I test with leds.
  • For the prescaler in MCPWM_CLK_CFG_REG register, I see a change when I modify its value.
  • But for the one in MCPWM_TIMER0_CFG0_REG, it seems to me that there is no change when I modify its value. what am I doing wrong in the following program ?
Other question : if in the following program I replace
pwm_config.frequency = 20;
by
pwm_config.frequency = 10;
without executing the lines 92-101, I see a strange value in the MCPWM_TIMER0_PERIOD part of the PWM_TIMER0_CFG0_REG :
I find there 34464 = 0x86A0 when the right value would be 100000 = 0x186A0.
Obviously it is impossible to put this value into the 16 bits provided and it looks like the extra digit was cut.

Thank you very much for any clue

Best regards

J.M. CORNIL


Code: Select all

#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_attr.h"
#include "soc/rtc.h"
#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"


#define GPIO_PWM0A_OUT 17   //Set GPIO 17 as PWM0A
#define GPIO_PWM0B_OUT 21   //Set GPIO 21 as PWM0B

static void mcpwm_example_gpio_initialize(void)
{
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
}

		// general prescaler
		uint8_t get_MCPWM_CLK_CFG_REG(){ 
			return *((uint32_t *) MCPWM_CLK_CFG_REG(0)) & 0xFF;
			}		
			
		void set_MCPWM_CLK_CFG_REG(uint8_t val){
			 *((uint32_t *) MCPWM_CLK_CFG_REG(0)) = (MCPWM_CLK_CFG_REG(0) & 0xFFFFFF00) | val ;
			 }
			 
		// Timer0 prescaler
		uint8_t get_MCPWM_TIMER0_PRESCALE(){ 
			return *((uint32_t *) MCPWM_TIMER0_CFG0_REG(0)) & 0xFF;
			}

		void set_MCPWM_TIMER0_PRESCALE(uint8_t val){ 
			uint32_t* p = (uint32_t *) MCPWM_TIMER0_CFG0_REG(0);
			*p = (*p & 0xFFFFFF00) | val;
			}
    
    // Timer0 period
		uint16_t get_MCPWM_TIMER0_PERIOD(){ 
			return ((*((uint32_t *) MCPWM_TIMER0_CFG0_REG(0))) >>8) & 0xFFFF;
			}

		void set_MCPWM_TIMER0_PERIOD(uint16_t val){ 
			uint32_t* p = (uint32_t *) MCPWM_TIMER0_CFG0_REG(0);
			*p = (*p & 0xFF0000FF) | (val<<8);
			}

    // A cmpr register
		uint16_t get_MCPWM_GEN0_TSTMP_A_REG(){ 
			return (*(uint32_t *)MCPWM_GEN0_TSTMP_A_REG(0)) & 0xFFFF;
			}

		void set_MCPWM_GEN0_TSTMP_A_REG(uint16_t val){ 
			uint32_t* p = (uint32_t *)MCPWM_GEN0_TSTMP_A_REG(0);
			*p = (*p & 0xFFFF0000) | val;
			}

    // B cmpr register
		uint16_t get_MCPWM_GEN0_TSTMP_B_REG(){ 
			return (*(uint32_t *)MCPWM_GEN0_TSTMP_B_REG(0)) & 0xFFFF;
			}

		void set_MCPWM_GEN0_TSTMP_B_REG(uint16_t val){ 
			uint32_t* p = (uint32_t *)MCPWM_GEN0_TSTMP_B_REG(0);
			*p = (*p & 0xFFFF0000) | val;
			}			
		void timer_Start(){
			uint32_t* p = (uint32_t *) MCPWM_TIMER0_CFG1_REG(0);
			*p = (*p & ~0b111) | 0b10;
			}
		void timer_Stop(){
			uint32_t* p = (uint32_t *) MCPWM_TIMER0_CFG1_REG(0);
			*p = *p & ~0b111;
			}

void app_main(void)
{
    //1. mcpwm gpio initialization
    mcpwm_example_gpio_initialize();

    //2. initial mcpwm configuration
    mcpwm_config_t pwm_config;
    pwm_config.frequency = 20;    // frequency 
    pwm_config.cmpr_a = 50.0;     // duty cycle of PWMxA = 50.0%
    pwm_config.cmpr_b = 50.0;     // duty cycle of PWMxb = 50.0%
    pwm_config.counter_mode = MCPWM_UP_COUNTER;
    pwm_config.duty_mode = MCPWM_DUTY_MODE_1;
    mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A & PWM0B with above settings

		// Then I try playing with the two prescaler
		timer_Stop();
		// For this one I see that it operates on the result
		set_MCPWM_CLK_CFG_REG(255);
		// But for the following, I don't see any change, whatever the value
		set_MCPWM_TIMER0_PRESCALE(4); 
		set_MCPWM_TIMER0_PERIOD(60000);
		set_MCPWM_GEN0_TSTMP_B_REG(50000);
		set_MCPWM_GEN0_TSTMP_A_REG(50000);
		timer_Start();
		
		printf("MCPWM_CLK_CFG_REG adr = %d \r\n",get_MCPWM_CLK_CFG_REG());
		printf("MCPWM_TIMER0_CFG0_REG  presc = %d  period = %d \r\n",get_MCPWM_TIMER0_PRESCALE(),get_MCPWM_TIMER0_PERIOD());
		printf("MCPWM_GEN0_TSTMP_A_REG val = %d \r\n",get_MCPWM_GEN0_TSTMP_A_REG());
		printf("MCPWM_GEN0_TSTMP_B_REG val = %d \r\n",get_MCPWM_GEN0_TSTMP_B_REG());

}


Last edited by jmcornil on Tue Feb 11, 2020 7:42 pm, edited 1 time in total.

jmcornil
Posts: 9
Joined: Mon Feb 10, 2020 1:42 pm

Re: Issue with MCPWM Prescaler

Postby jmcornil » Tue Feb 11, 2020 5:53 pm

Hello

Since yesterday I have found the LL layer for ESP32 MCPWM register operations
(in the file components/soc/esp32/include/hal/mcpwm_ll.h).

I find that it provides an efficient method to initialize the MCPWM
(only one timer and one operator for the moment).
And so, I can choose freely my two prescaler (not only 15->16 and 9->10).
I put a sample program below (much shorter than the program of ysterday !)

Hope it will be helpful.

Code: Select all

#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_attr.h"
#include "soc/rtc.h"
#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"
#include "hal/mcpwm_hal.h"
#include "driver/gpio.h"

#define GPIO_PWM0A_OUT 17   //Set GPIO 17 as PWM0A
#define GPIO_PWM0B_OUT 21   //Set GPIO 21 as PWM0B
//#define GPIO_PWM1A_OUT 18   //Set GPIO 18 as PWM1A
//#define GPIO_PWM1B_OUT 22   //Set GPIO 22 as PWM1B
//#define GPIO_PWM2A_OUT 19   //Set GPIO 19 as PWM2A
//#define GPIO_PWM2B_OUT 23   //Set GPIO 23 as PWM2B

void app_main(void)
{
    // MCPWM GPIO initialization
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);

		// MCPWM Initialisation
		// First The clock prescale
		mcpwm_ll_set_clock_prescale(&MCPWM0, 31);
		// Then Timer0 initialisation
		mcpwm_ll_timer_set_prescale(&MCPWM0, MCPWM_TIMER_0, 39);
		mcpwm_ll_timer_set_count_mode(&MCPWM0, MCPWM_TIMER_0, 1);
		mcpwm_ll_timer_set_period(&MCPWM0, MCPWM_TIMER_0, 50000);
		mcpwm_ll_operator_select_timer(&MCPWM0, 0,MCPWM_TIMER_0);
		// Now Operator 0 initialisation
		mcpwm_ll_operator_set_compare(&MCPWM0, 0, MCPWM0A, 25000);
		mcpwm_ll_operator_set_compare(&MCPWM0, 0, MCPWM0B, 25000);
		mcpwm_ll_gen_set_zero_action(&MCPWM0, 0,  MCPWM_GEN_A, MCPWM_ACTION_FORCE_HIGH);
		mcpwm_ll_gen_set_cmp_action( &MCPWM0, 0,  MCPWM_GEN_A, MCPWM0A, MCPWM_ACTION_FORCE_LOW,MCPWM_ACTION_NO_CHANGE);
		mcpwm_ll_gen_set_zero_action(&MCPWM0, 0,  MCPWM_GEN_B, MCPWM_ACTION_FORCE_LOW);
		mcpwm_ll_gen_set_cmp_action( &MCPWM0, 0,  MCPWM_GEN_B, MCPWM0B, MCPWM_ACTION_FORCE_HIGH,MCPWM_ACTION_NO_CHANGE);
		
		// Timer start
		mcpwm_ll_timer_start(&MCPWM0,MCPWM_TIMER_0);
  
		while(1){}

}



Who is online

Users browsing this forum: No registered users and 19 guests