-
-
Save igrr/1515d369310479bbaf9239afeed4aac5 to your computer and use it in GitHub Desktop.
/* ESP32-S2 (beta) "dedicated GPIO" peripheral example */ | |
#include <stdio.h> | |
#include "sdkconfig.h" | |
#include "soc/system_reg.h" | |
#include "esp32s2beta/rom/gpio.h" | |
#include "soc/gpio_sig_map.h" | |
#include "driver/gpio.h" | |
/* The header file is not yet in IDF; however this is the only register we need. */ | |
#define DEDICATED_GPIO_OUT_CPU_EN_REG (DR_REG_DEDICATED_GPIO_BASE + 0x10) | |
void IRAM_ATTR app_main(void) | |
{ | |
/* enable the peripheral */ | |
REG_SET_BIT(DPORT_CPU_PERI_CLK_EN_REG, DPORT_CLK_EN_DEDICATED_GPIO); | |
REG_CLR_BIT(DPORT_CPU_PERI_RST_EN_REG, DPORT_RST_EN_DEDICATED_GPIO); | |
/* get the values of dedicated GPIO from the CPU, not peripheral registers */ | |
REG_WRITE(DEDICATED_GPIO_OUT_CPU_EN_REG, 0xff); | |
/* configure GPIOs as outputs and route "dedicated GPIO" signals to them */ | |
const int gpio_nums[] = {0, 1, 2, 3, 4, 5, 6, 7}; | |
int n_gpios = sizeof(gpio_nums)/sizeof(gpio_nums[0]); | |
for (int i = 0; i < n_gpios; ++i) { | |
int gpio_num = gpio_nums[i]; | |
gpio_config_t io_conf={ | |
.mode=GPIO_MODE_OUTPUT, | |
.pin_bit_mask=(1ULL<<gpio_num) | |
}; | |
ESP_ERROR_CHECK(gpio_config(&io_conf)); | |
gpio_matrix_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false, false); | |
} | |
uint32_t val = 0; | |
const uint32_t mask = 0xff; | |
const uint32_t zero = 0; | |
while(true) { | |
/* Set individual bits */ | |
__asm__ __volatile__ ("set_bit_gpio_out 0x1"); | |
__asm__ __volatile__ ("set_bit_gpio_out 0x2"); | |
__asm__ __volatile__ ("set_bit_gpio_out 0x4"); | |
__asm__ __volatile__ ("set_bit_gpio_out 0x8"); | |
__asm__ __volatile__ ("clr_bit_gpio_out 0x1"); | |
__asm__ __volatile__ ("clr_bit_gpio_out 0x2"); | |
__asm__ __volatile__ ("clr_bit_gpio_out 0x4"); | |
__asm__ __volatile__ ("clr_bit_gpio_out 0x8"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
/* write from a register with mask */ | |
__asm__ __volatile__ ("wr_mask_gpio_out %0, %1" : : "r"(val), "r"(mask)); | |
__asm__ __volatile__ ("wr_mask_gpio_out %0, %1" : : "r"(zero), "r"(mask)); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
/* can also set all the 8 bits (without masking) */ | |
__asm__ __volatile__ ("wur.gpio_out %0" : : "r"(val)); | |
__asm__ __volatile__ ("wur.gpio_out %0" : : "r"(zero)); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
__asm__ __volatile__ ("nop"); | |
val++; | |
} | |
} |
I found this screenshot of a logic analyzer trace produced by this example:
the pictured delay of 12.5 ns (1/80 MHz) corresponds to lines 43 and 44 of this code.
For the latest docs about this feature (on ESP32-S2), please check https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/dedic_gpio.html#manipulate-gpios-by-writing-assembly-code.
Thanks, that is good news!
thx for this exmaple, I was trying to use the bundle trick here
https://esp32.com/viewtopic.php?t=27963
with no luck
I saw your example but this line didnt work.
gpio_matrix_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false, false);
I think it changed to
gpio_iomux_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false);
dropping the last parm. but I'm ony able to make my GPIO go high, it will not go low.
#define HIGH(dedic_io_num) asm volatile ("ee.set_bit_gpio_out %0" : : "I"(dedic_io_num) : );
#define LOW(dedic_io_num) asm volatile ("ee.clr_bit_gpio_out %0" : : "I"(dedic_io_num) : );
Also could not use any of the enable the peripheral as those are undefined.
using the new way that also failed I tried this
#define HIGH(dedic_io_num) __asm__ __volatile__ ("ee.set_bit_gpio_out %0" : : "I"(dedic_io_num) : );
#define LOW(dedic_io_num) __asm__ __volatile__ ("ee.clr_bit_gpio_out %0" : : "I"(dedic_io_num) : );
// configure GPIO
const int bundleA_gpios[] = {0, 1, 2};
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
};
for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
// io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
// io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
//io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);
}
// Create bundleA, output only
dedic_gpio_bundle_handle_t bundleA = NULL;
dedic_gpio_bundle_config_t bundleA_config = {
.gpio_array = bundleA_gpios,
.array_size = sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]),
.flags = {
.out_en = 1,
},
};
while ( 1)
{
HIGH(2);
// _delay_us(10);
LOW(2);
}
You need to logical OR each bundleA_gpios[i] in io_conf.bit_mask:
io_conf.pin_bit_mask |= 1ULL << bundleA_gpios[i];
And after defining the bundleA_config you need to call:
ESP_ERROR_CHECK( dedic_gpio_new_bundle(&bundleA_config, &bundleA));
Then it should work.
What is the maximum GPIO toggle speed you can achieve this way? I need 20 MHz and the ESP32 can only achieve 10 MHz. Considering switching to an ESP32-S2 if this one can do it.