espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.51k stars 7.39k forks source link

how to run timer / capture with max possible speed ( 40MHz or 20MHz )? #5102

Closed Pepito-design closed 3 years ago

Pepito-design commented 3 years ago

I want to measure the distance between 2 signals with very high precision. Idea is to use the capture functionality of MCPWM. First I'm trying to set the clock prescaler to 2. Expected is half of the crystal frequency. I add debug info ( Serial output ) .... it seems to be correct .... better as expected. Then I start the pwm config stuff. And here it sucks in my program. if ( ESP_OK != mcpwm_set_pin(MCPWM_UNIT_0, &pin_config)) { Serial.println(" ERROR: mcpwm_set_pin problem"); } I expect, in case something is going wrong, the error message .... but the chip is hanging .... no message, red led is on .... no reaction at all. If I comment the line with mcpwm_set_pin ... it works as expected ( but pin mode isn't set ). Can see all debug messages. The program is not finished, it's only the setup to do the final work, to debug and very the settings. mcpwm_get_frequency tells me ... is running with 15Hz .... first assumption was data type error, but it isn't. Up to 1MHz it works fine .... Duty cycle should be 50.0% to make the max speed possible. But mcpwm_get_duty tells me it's 0.0%. I expect I made some mistakes ... or one really big one. I'm giving up at the moment .... need help. Or is a better, more straight forward way possible to measure the distance between 2 signals in number of clocks? The frequency of the signals is up to some 10 kHz, the distance between 0 and huge value ( < 0xFF FF FF FF ) . Think ESP32 is a good choice for that. Next time I have to control a 180V 5A DC motor ( PWM based ). Hope I learned all the tricky things around the mcpwm units up front ..... ;-) Thanks for help. Program is compiling, possible to upload, watch the Serial output. It's hanging here if ( ESP_OK != mcpwm_set_pin(MCPWM_UNIT_0, &pin_config)) as long this line is active.

Pepito

Hardware:

Board: ESP32 Dev Module Core Installation version: 1.0.6 IDE name: Arduino IDE Flash Frequency: 40Mhz PSRAM enabled: no Upload Speed: 921600 Computer OS: Tumbleweed / Suse

Description:

1.) hanging at: if ( ESP_OK != mcpwm_set_pin(MCPWM_UNIT_0, &pin_config)) 2.) frequency is 15Hz .... expected is 20MHz 3.) duty cycle is 0% .... expected is 50%

Sketch:

include

include

include "esp_attr.h"

include "soc/mcpwm_struct.h"

include "driver/mcpwm.h"

include "driver/timer.h"

define ALPHA 52.0 // Winkel Pickup <-- OT anpassen!

define MCPWM_EN_CAPTURE 1

define CAP0_INT_EN BIT(27) //Capture 0 interrupt bit

define CAP1_INT_EN BIT(28) //Capture 1 interrupt bit

define GPIO_CAP0_IN 23 //Set GPIO 23 as CAP0 Pick-UP

define GPIO_CAP1_IN 25 //Set GPIO 25 as CAP1 Ignition

define TIMER_DIVIDER 2 // Hardware timer clock divider

define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds

typedef struct { timer_group_t timer_group; timer_idx_t timer_idx; int alarm_interval; bool auto_reload; } example_timer_info_t;

typedef struct { uint32_t capture_signal_P; uint32_t capture_signal_Z; mcpwm_capture_signal_t sel_cap_signal; } capture;

uint32_t current_cap_value = NULL; uint32_t previous_cap_value = NULL; static mcpwm_dev_t *MCPWM[1] = {&MCPWM0};

xQueueHandle cap_queue; float Zuendwinkel ;

static void example_tg_timer_init(timer_group_t group, timer_idx_t timer, bool auto_reload, int timer_interval_sec) { / Select and initialize basic parameters of the timer / timer_config_t timer_config; timer_config.divider = TIMER_DIVIDER; timer_config.counter_dir = TIMER_COUNT_UP; timer_config.counter_en = TIMER_PAUSE; timer_config.alarm_en = TIMER_ALARM_EN; timer_config.auto_reload = auto_reload; // default clock source is APB

timer_init( group, timer, &timer_config);

/* Timer's counter will initially start from value below.
   Also, if auto_reload is set, this value will be automatically reload on alarm */

timer_set_counter_value(group, timer, 0);

/* Configure the alarm value and the interrupt on alarm. */
//timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
//timer_enable_intr(group, timer);

example_timer_info_t timer_info; timer_info.timer_group = group; timer_info.timer_idx = timer; timer_info.auto_reload = auto_reload; timer_info.alarm_interval = timer_interval_sec; // timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info, 0);

timer_start(group, timer); }

static void disp_captured_signal(void arg) { capture evt; float Drehzahl; int32_t OT; xQueueReceive(cap_queue, &evt, portMAX_DELAY); if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) { // OT = P + P x (ALPHA/360°) ALPHA = Offset Pick-UP redundant, wird nicht benoetigt // Drehzahl = 60sec / ( P x 25nsec ) // OT = evt.capture_signal_P + (( ALPHA / 360.0 ) evt.capture_signal_P)); Drehzahl = 60.0 / ((float)evt.capture_signal_P 0.000000025); Serial.print(" P = "); Serial.print(evt.capture_signal_P, DEC); // eingefangener Wert vom Timer Serial.print("Drehzahl = "); Serial.println(Drehzahl,3); // 3 Stellen hinterm Komma // Serial.print(" OT = "); // Serial.println(OT,DEC); } if ((evt.sel_cap_signal == MCPWM_SELECT_CAP1)) { // gamma = ( ALPHA - ( Z 360 / P ) Zuendwinkel = ALPHA - ( (float) evt.capture_signal_Z * 360.0 / (float) previous_cap_value[0] ); Serial.print(" Z = "); Serial.print(evt.capture_signal_Z); Serial.print(" Zuendwinkel = "); Serial.println(Zuendwinkel,3); } }

static void IRAM_ATTR isr_handler(void *arg) // static void isr_handler(void) { uint32_t mcpwm_intr_status; capture evt; mcpwm_intr_status = MCPWM[MCPWM_UNIT_0]->int_st.val; //Read interrupt status //calculate the interval in the ISR, //so that the interval will be always correct even when cap_queue is not handled in time and overflow. if (mcpwm_intr_status & CAP0_INT_EN) { //Check for interrupt on rising edge on CAP0 signal // mcpwm_start(MCPWM_UNIT_0, MCPWM_SELECT_CAP1); // Auf Zuendimpuls warten current_cap_value[0] = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0); //get capture signal counter value evt.capture_signal_P = (current_cap_value[0] - previous_cap_value[0]) ; previous_cap_value[0] = current_cap_value[0]; evt.sel_cap_signal = MCPWM_SELECT_CAP0; xQueueSendFromISR(cap_queue, &evt, NULL); } if (mcpwm_intr_status & CAP1_INT_EN) { //Check for interrupt on rising edge on CAP1 signal Zuendimpuls gekommen // mcpwm_stop(MCPWM_UNIT_0, MCPWM_SELECT_CAP1); current_cap_value[1] = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP1); //get capture signal counter value evt.capture_signal_Z = abs((current_cap_value[1] - previous_cap_value[0])) ; // Differenz Z - P evt.sel_cap_signal = MCPWM_SELECT_CAP1; xQueueSendFromISR(cap_queue, &evt, NULL); } MCPWM[MCPWM_UNIT_0]->int_clr.val = mcpwm_intr_status; }

static void mcpwm_example_gpio_initialize(void) { printf("initializing mcpwm gpio...\n"); mcpwm_pin_config_t pin_config; pin_config.mcpwm_cap0_in_num = GPIO_CAP0_IN; pin_config.mcpwm_cap1_in_num = GPIO_CAP1_IN;

if ( ESP_OK != mcpwm_set_pin(MCPWM_UNIT_0, &pin_config))
 {
  Serial.println(" ERROR: mcpwm_set_pin problem");
 }

gpio_pulldown_en((gpio_num_t) GPIO_CAP0_IN);    //Enable pull down on CAP0   signal
gpio_pulldown_en((gpio_num_t) GPIO_CAP1_IN);    //Enable pull down on CAP1   signal

if ( ESP_OK != mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_POS_EDGE, 0))  //capture signal on rising edge, prescale = 0 
 {
  Serial.println(" ERROR: MCPWM_UNIT_0, MCPWM_SELECT_CAP0 enable geht nicht");
 }
if ( ESP_OK != mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE, 0))  //capture signal on rising edge, prescale = 0 
 {
  Serial.println(" ERROR: MCPWM_UNIT_0, MCPWM_SELECT_CAP1 enable geht nicht");
 }
 //enable interrupt, so each this a rising edge occurs interrupt is triggered
MCPWM[MCPWM_UNIT_0]->int_ena.val = CAP0_INT_EN | CAP1_INT_EN;  //Enable interrupt on  CAP0, CAP1 signal
if ( ESP_OK != mcpwm_isr_register(MCPWM_UNIT_0, isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL))  //Set ISR Handler
 {
  Serial.println(" ERROR: mcpwm_isr_register nicht moeglich");
 }

}

void setup() { uint32_t frequenz; float duty; timer_config_t timer_config_in_use; uint8_t tmp[4]; timerBegin(0, 2, true); Serial.begin(115200); Serial.println("Configuring Timer 0"); example_tg_timer_init(TIMER_GROUP_0, TIMER_0, true, 10000000); timer_get_config(TIMER_GROUP_0, TIMER_0, &timer_config_in_use); Serial.println("Timer_0 configuration:"); Serial.print (" Divider = "); Serial.println(timer_config_in_use.divider); Serial.print ("auto reload = "); Serial.println(timer_config_in_use.auto_reload); Serial.print ("counter_dir = "); Serial.println(timer_config_in_use.counter_dir); Serial.print (" intr_type = "); Serial.println(timer_config_in_use.intr_type); Serial.print (" counter_en = "); Serial.println(timer_config_in_use.counter_en); Serial.print (" alarm_en = "); Serial.println(timer_config_in_use.alarm_en); delay(100); mcpwm_example_gpio_initialize(); Serial.println("Configuring Initial Parameters of mcpwm..."); mcpwm_config_t pwm_config; pwm_config.frequency = 20000000; //frequenz 20MHz .... better 40MHz 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_COUNTER_MAX; pwm_config.duty_mode = MCPWM_DUTY_MODE_1; if ( ESP_OK != mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config)) //Configure PWM0A with above settings { Serial.println(" ERROR: MCPWM_INIT Timer 0 geht nicht"); } if ( ESP_OK != mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0)) // Timer starten { Serial.println(" ERROR: MCPWM_UNIT_0, MCPWM_TIMER_0 startet nicht"); } else {

Serial.println(" MCPWM_UNIT_0, MCPWM_TIMER_0 gestartet");
if ( ESP_OK != mcpwm_set_frequency(MCPWM_UNIT_0, MCPWM_TIMER_0, 20000000)) // resundant
 {
  Serial.println(" ERROR: mcpwm_set_frequency geht nicht");
 }
Serial.print(" Laeuft mit ");
frequenz = mcpwm_get_frequency(MCPWM_UNIT_0, MCPWM_TIMER_0);
    tmp[0] = frequenz >> 24;
    tmp[1] = frequenz >> 16;
    tmp[2] = frequenz >> 8;
    tmp[3] = frequenz;

// sprintf( tmp, "%u",frequenz); Serial.print(tmp[0],HEX); Serial.print(tmp[1],HEX); Serial.print(tmp[2],HEX); Serial.print(tmp[3],HEX); Serial.print(" "); Serial.print(frequenz); Serial.println("Hz"); duty = mcpwm_get_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A); Serial.print(duty); Serial.println("%"); } }

void loop() { //unsigned int number = mcpwm_capture_signal_get_value(MCPWM_UNIT_0,MCPWM_SELECT_CAP0); // get value

}

Debug Messages:

Der Sketch verwendet 285654 Bytes (21%) des Programmspeicherplatzes. Das Maximum sind 1310720 Bytes. Globale Variablen verwenden 13724 Bytes (4%) des dynamischen Speichers, 313956 Bytes für lokale Variablen verbleiben. Das Maximum sind 327680 Bytes. esptool.py v3.0-dev Serial port /dev/ttyUSB0 Connecting.... Chip is ESP32-D0WDQ6 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: 08:3a:f2:a9:64:b0 Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Changed. Configuring flash size... Auto-detected Flash size: 4MB Compressed 8192 bytes to 47... Writing at 0x0000e000... (100 %) Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 33070.0 kbit/s)... Hash of data verified. Compressed 18656 bytes to 12053... Writing at 0x00001000... (100 %) Wrote 18656 bytes (12053 compressed) at 0x00001000 in 0.1 seconds (effective 1062.0 kbit/s)... Hash of data verified. Compressed 285776 bytes to 132636... Writing at 0x00010000... (11 %) Writing at 0x00014000... (22 %) Writing at 0x00018000... (33 %) Writing at 0x0001c000... (44 %) Writing at 0x00020000... (55 %) Writing at 0x00024000... (66 %) Writing at 0x00028000... (77 %) Writing at 0x0002c000... (88 %) Writing at 0x00030000... (100 %) Wrote 285776 bytes (132636 compressed) at 0x00010000 in 2.3 seconds (effective 1002.2 kbit/s)... Hash of data verified. Compressed 3072 bytes to 127... Writing at 0x00008000... (100 %) Wrote 3072 bytes (127 compressed) at 0x00008000 in 0.0 seconds (effective 8542.2 kbit/s)... Hash of data verified.

Leaving... Hard resetting via RTS pin... Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here ets Jun 8 2016 00:22:57 00:51:29.340 -> 00:51:29.340 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) 00:51:29.340 -> configsip: 0, SPIWP:0xee 00:51:29.340 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 00:51:29.340 -> mode:DIO, clock div:1 00:51:29.340 -> load:0x3fff0018,len:4 00:51:29.340 -> load:0x3fff001c,len:1216 00:51:29.340 -> ho 0 tail 12 room 4 00:51:29.340 -> load:0x40078000,len:10944 00:51:29.340 -> load:0x40080400,len:6388 00:51:29.340 -> entry 0x400806b4 00:51:29.439 -> E (132) psram: PSRAM ID read error: 0xffffffff 00:51:29.473 -> Configuring Timer 0 00:51:29.473 -> Timer_0 configuration: 00:51:29.473 -> Divider = 2 00:51:29.473 -> auto reload = 1 00:51:29.473 -> counter_dir = 1 00:51:29.473 -> intr_type = 0 00:51:29.473 -> counter_en = 1 00:51:29.473 -> alarm_en = 0 00:51:29.572 -> initializing mcpwm gpio... 00:51:29.572 -> E (241) MCPWM: /home/runner/work/e Hanging forever .... reset works .... end up always here

lbernstone commented 3 years ago

This forum is for issues with the code here, not issues with your code. MCPWM is bound by the same restrictions as LED PWM. https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html#supported-range-of-frequency-and-duty-resolutions

Pepito-design commented 3 years ago

Understand. But why is it hanging here? If it fails, the function generates specific return value. if ( ESP_OK != mcpwm_set_pin(MCPWM_UNIT_0, &pin_config)) { Serial.println(" ERROR: mcpwm_set_pin problem"); } So the error message should appear. It's hanging inside mcpwm_set_pin ... and that's not my code ;-) Thanks for help and have a good day Pepito

stale[bot] commented 3 years ago

[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.