Closed gin66 closed 5 months ago
Thank you. I've taken a look into your FastAccelStepper, I may need to use it some day. You're right, I'm not familiar with gpio_iomux_in function. I tried to find some documentation but it is rather scarce. If I understand correctly it establishes an internal connection to another GPIO and the result would be similar to using a wire? Do you have an idea which one of the signals from gpio_sig_map.h (https://github.com/pycom/esp-idf-2.0/blob/master/components/esp32/include/soc/gpio_sig_map.h) should I use?
Bojan
Quite good documentation is here from page 45: (https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf)
Eventually it is even easier:
4.2.3 Simple GPIO Input
The GPIO_IN_REG/GPIO_IN1_REG register holds the input values of each GPIO pad.
The input value of any GPIO pin can be read at any time without configuring the
GPIO Matrix for a particular peripheral signal. However, it is necessary to enable
the input in the IO_MUX by setting the FUN_IE bit in the IO_MUX_x_REG register
corresponding to pad X, as mentioned in Section 4.2.2.
The respective macro for setting FUN_IE seems to be: `
I'm still having difficulties getting it to work with Arduino. If I PIN_INPUT_ENABLE weather in setup () or in loop () the result is the same - ESP32 reboots with:
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
The code I used for testing:
#include <WiFi.h>
#include <soc/gpio_sig_map.h>
void setup () {
Serial.begin (115200);
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
PIN_INPUT_ENABLE (2);
// start PWM on built-in LED
ledcSetup (0, 1000, 10);
ledcAttachPin (2, 0); // built-in LED
ledcWrite (0, 307); // 1/3 duty cycle
}
void loop () {
delay (1000);
Serial.printf ("%i\n", digitalRead (2)); // expected: 1/3 of 1 and 2/3 of 0 on built-in LED
}
Do you have any ideas?
Try this:
#include <soc/gpio_sig_map.h>
#include <soc/io_mux_reg.h>
#define LED 2
void setup () {
Serial.begin (115200);
// start PWM on built-in LED
ledcSetup (0, 12, 10);
ledcAttachPin (LED, 0); // built-in LED
ledcWrite (0, 307); // 1/3 duty cycle
PIN_INPUT_ENABLE (GPIO_PIN_MUX_REG[2]);
}
void loop () {
delay(10);
Serial.printf("%i", digitalRead(LED));
// Serial.printf ("%i\n", gpio_input_get()); // This reads all 32 port bits at once
}
Two more comments:
Indeed. There are some combinations that just don't work well. For example 1000 Hz PWM and 10 ms sampling. It is strange though why 1200 Hz with 12 ms sampling works.
On the other hand oscilloscope normally does not use "delay" but rather "delayMicroseconds" at higher frequencies which I believe is not RTOS but an Arduino function so it doesn't have to do much with interrupters and everything works just fine. I'll include your solution to the Oscilloscope. Thank you.
"For example 1000 Hz PWM and 10 ms sampling." => 1000 Hz = 1ms, which is 1/10th with 10ms
"It is strange though why 1200 Hz with 12 ms sampling works." => 1200Hz = 0.833ms, which 1:14.4=5:72 of 12ms. So not strange at all
Hi gin66.
I'm sorry to bother you again with the same topic. PIN_INPUT_ENABLE (GPIO_PIN_MUX_REG[...]) worked very well with IDF 4.x. After the upgrade to IDF 5.x I've been struggling for days to get it working, with no success. Although the code compiles without any problems, digitalRead only returns 0 if GPIO is not configured in INPUT mode (if it is configured as OUTPUT or PWM for example). Can you help me with this, please?
Sorry, but the IDF5 gives me headaches, too, so I only can give you link to migration guide.
My lib is absolutely broken with IDF5 and porting mcpwm/pcnt/rmt drivers is close to a new development….for the EXACT same hardware. And your experience tells me, that there is chance, that this is not even possible anymore….on the EXACT same hardware.
Thank you for your information. I hope we'll find something out.
This is just a partial success:
Using gpio_get_level (gpio_pin) instead of digitalRead (gpio_pin) helps reading pins configured as OUTPUT, but doesn't help with PWM signals at all.
I tried writing a modified version of gpio_get_level function that basically returns (_gpio_hal.dev->out >> gpio_num) & 0x1, instead original one that returns (_gpio_hal.dev->in>> gpio_num) & 0x1, but this didn't help either.
I guess I'll go with this for now, until a better solution is found.
This seems to be a full solution. Basically, instead of using PIN_INPUT_ENABLE (GPIO_PIN_MUX_REG[... we can now use gpio_hal_input_enable (...
Here is a whole test script:
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
void setup () {
Serial.begin (115200);
#define PWM_PIN 16
// generate PWM signal on PWM_PIN ...
ledcAttach (PWM_PIN, 1000, 10);
ledcWrite (PWM_PIN, 307); // 307 out of 1024 (10 bit resolution) = 1/3
// ... or just set the output value of PWM_PIN
// pinMode (PWM_PIN, OUTPUT);
// digitalWrite (PWM_PIN, HIGH);
// enable input on PWM_PIN
static gpio_hal_context_t _gpio_hal = {
.dev = GPIO_HAL_GET_HW (GPIO_PORT_0)
};
gpio_hal_input_enable (&_gpio_hal, PWM_PIN);
// test reading PWM_PIN
for (int i = 0; i < 100; i ++) {
delayMicroseconds (111);
Serial.println (gpio_get_level ((gpio_num_t) PWM_PIN));
}
}
void loop () {
}
great News! Thanks for figuring out and sharing the solution. So I can make use of this in my lib, too.
Nice project and thanks for sharing. In regard to this comment of yours:
I do not know how to digitalRead PWM signals directly from GPIOs that output them. Any useful idea would be greatly appreciated.
In my project FastAccelStepper, the mcpwm are used to output stepper signals. Those pulses are read back from the pin and fed into the pcnt modules. Perhaps similar approach works for your issue. The relevant code is:
The key is
gpio_iomux_in()
. Via github search could not see, that you use this function. Perhaps new to you and a direction towards a solution. even though, no turn-key solution.